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.3.2
8 * @date 2019-11-08T19:06:45Z
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 });
13002
13003 var keycharm = createCommonjsModule(function (module, exports) {
13004 /**
13005 * Created by Alex on 11/6/2014.
13006 */
13007 // https://github.com/umdjs/umd/blob/master/returnExports.js#L40-L60
13008 // if the module has no dependencies, the above pattern can be simplified to
13009
13010 (function (root, factory) {
13011 {
13012 // Node. Does not work with strict CommonJS, but
13013 // only CommonJS-like environments that support module.exports,
13014 // like Node.
13015 module.exports = factory();
13016 }
13017 })(commonjsGlobal, function () {
13018 function keycharm(options) {
13019 var preventDefault = options && options.preventDefault || false;
13020 var container = options && options.container || window;
13021 var _exportFunctions = {};
13022 var _bound = {
13023 keydown: {},
13024 keyup: {}
13025 };
13026 var _keys = {};
13027 var i; // a - z
13028
13029 for (i = 97; i <= 122; i++) {
13030 _keys[String.fromCharCode(i)] = {
13031 code: 65 + (i - 97),
13032 shift: false
13033 };
13034 } // A - Z
13035
13036
13037 for (i = 65; i <= 90; i++) {
13038 _keys[String.fromCharCode(i)] = {
13039 code: i,
13040 shift: true
13041 };
13042 } // 0 - 9
13043
13044
13045 for (i = 0; i <= 9; i++) {
13046 _keys['' + i] = {
13047 code: 48 + i,
13048 shift: false
13049 };
13050 } // F1 - F12
13051
13052
13053 for (i = 1; i <= 12; i++) {
13054 _keys['F' + i] = {
13055 code: 111 + i,
13056 shift: false
13057 };
13058 } // num0 - num9
13059
13060
13061 for (i = 0; i <= 9; i++) {
13062 _keys['num' + i] = {
13063 code: 96 + i,
13064 shift: false
13065 };
13066 } // numpad misc
13067
13068
13069 _keys['num*'] = {
13070 code: 106,
13071 shift: false
13072 };
13073 _keys['num+'] = {
13074 code: 107,
13075 shift: false
13076 };
13077 _keys['num-'] = {
13078 code: 109,
13079 shift: false
13080 };
13081 _keys['num/'] = {
13082 code: 111,
13083 shift: false
13084 };
13085 _keys['num.'] = {
13086 code: 110,
13087 shift: false
13088 }; // arrows
13089
13090 _keys['left'] = {
13091 code: 37,
13092 shift: false
13093 };
13094 _keys['up'] = {
13095 code: 38,
13096 shift: false
13097 };
13098 _keys['right'] = {
13099 code: 39,
13100 shift: false
13101 };
13102 _keys['down'] = {
13103 code: 40,
13104 shift: false
13105 }; // extra keys
13106
13107 _keys['space'] = {
13108 code: 32,
13109 shift: false
13110 };
13111 _keys['enter'] = {
13112 code: 13,
13113 shift: false
13114 };
13115 _keys['shift'] = {
13116 code: 16,
13117 shift: undefined
13118 };
13119 _keys['esc'] = {
13120 code: 27,
13121 shift: false
13122 };
13123 _keys['backspace'] = {
13124 code: 8,
13125 shift: false
13126 };
13127 _keys['tab'] = {
13128 code: 9,
13129 shift: false
13130 };
13131 _keys['ctrl'] = {
13132 code: 17,
13133 shift: false
13134 };
13135 _keys['alt'] = {
13136 code: 18,
13137 shift: false
13138 };
13139 _keys['delete'] = {
13140 code: 46,
13141 shift: false
13142 };
13143 _keys['pageup'] = {
13144 code: 33,
13145 shift: false
13146 };
13147 _keys['pagedown'] = {
13148 code: 34,
13149 shift: false
13150 }; // symbols
13151
13152 _keys['='] = {
13153 code: 187,
13154 shift: false
13155 };
13156 _keys['-'] = {
13157 code: 189,
13158 shift: false
13159 };
13160 _keys[']'] = {
13161 code: 221,
13162 shift: false
13163 };
13164 _keys['['] = {
13165 code: 219,
13166 shift: false
13167 };
13168
13169 var down = function (event) {
13170 handleEvent(event, 'keydown');
13171 };
13172
13173 var up = function (event) {
13174 handleEvent(event, 'keyup');
13175 }; // handle the actualy bound key with the event
13176
13177
13178 var handleEvent = function (event, type) {
13179 if (_bound[type][event.keyCode] !== undefined) {
13180 var bound = _bound[type][event.keyCode];
13181
13182 for (var i = 0; i < bound.length; i++) {
13183 if (bound[i].shift === undefined) {
13184 bound[i].fn(event);
13185 } else if (bound[i].shift == true && event.shiftKey == true) {
13186 bound[i].fn(event);
13187 } else if (bound[i].shift == false && event.shiftKey == false) {
13188 bound[i].fn(event);
13189 }
13190 }
13191
13192 if (preventDefault == true) {
13193 event.preventDefault();
13194 }
13195 }
13196 }; // bind a key to a callback
13197
13198
13199 _exportFunctions.bind = function (key, callback, type) {
13200 if (type === undefined) {
13201 type = 'keydown';
13202 }
13203
13204 if (_keys[key] === undefined) {
13205 throw new Error("unsupported key: " + key);
13206 }
13207
13208 if (_bound[type][_keys[key].code] === undefined) {
13209 _bound[type][_keys[key].code] = [];
13210 }
13211
13212 _bound[type][_keys[key].code].push({
13213 fn: callback,
13214 shift: _keys[key].shift
13215 });
13216 }; // bind all keys to a call back (demo purposes)
13217
13218
13219 _exportFunctions.bindAll = function (callback, type) {
13220 if (type === undefined) {
13221 type = 'keydown';
13222 }
13223
13224 for (var key in _keys) {
13225 if (_keys.hasOwnProperty(key)) {
13226 _exportFunctions.bind(key, callback, type);
13227 }
13228 }
13229 }; // get the key label from an event
13230
13231
13232 _exportFunctions.getKey = function (event) {
13233 for (var key in _keys) {
13234 if (_keys.hasOwnProperty(key)) {
13235 if (event.shiftKey == true && _keys[key].shift == true && event.keyCode == _keys[key].code) {
13236 return key;
13237 } else if (event.shiftKey == false && _keys[key].shift == false && event.keyCode == _keys[key].code) {
13238 return key;
13239 } else if (event.keyCode == _keys[key].code && key == 'shift') {
13240 return key;
13241 }
13242 }
13243 }
13244
13245 return "unknown key, currently not supported";
13246 }; // unbind either a specific callback from a key or all of them (by leaving callback undefined)
13247
13248
13249 _exportFunctions.unbind = function (key, callback, type) {
13250 if (type === undefined) {
13251 type = 'keydown';
13252 }
13253
13254 if (_keys[key] === undefined) {
13255 throw new Error("unsupported key: " + key);
13256 }
13257
13258 if (callback !== undefined) {
13259 var newBindings = [];
13260 var bound = _bound[type][_keys[key].code];
13261
13262 if (bound !== undefined) {
13263 for (var i = 0; i < bound.length; i++) {
13264 if (!(bound[i].fn == callback && bound[i].shift == _keys[key].shift)) {
13265 newBindings.push(_bound[type][_keys[key].code][i]);
13266 }
13267 }
13268 }
13269
13270 _bound[type][_keys[key].code] = newBindings;
13271 } else {
13272 _bound[type][_keys[key].code] = [];
13273 }
13274 }; // reset all bound variables.
13275
13276
13277 _exportFunctions.reset = function () {
13278 _bound = {
13279 keydown: {},
13280 keyup: {}
13281 };
13282 }; // unbind all listeners and reset all variables.
13283
13284
13285 _exportFunctions.destroy = function () {
13286 _bound = {
13287 keydown: {},
13288 keyup: {}
13289 };
13290 container.removeEventListener('keydown', down, true);
13291 container.removeEventListener('keyup', up, true);
13292 }; // create listeners.
13293
13294
13295 container.addEventListener('keydown', down, true);
13296 container.addEventListener('keyup', up, true); // return the public functions.
13297
13298 return _exportFunctions;
13299 }
13300
13301 return keycharm;
13302 });
13303 });
13304
13305 var keycharm$1 = /*#__PURE__*/Object.freeze({
13306 __proto__: null,
13307 'default': keycharm,
13308 __moduleExports: keycharm
13309 });
13310
13311 /*! Hammer.JS - v2.0.15 - 2019-04-04
13312 * http://naver.github.io/egjs
13313 *
13314 * Forked By Naver egjs
13315 * Copyright (c) hammerjs
13316 * Licensed under the MIT license */
13317 function _extends() {
13318 _extends = Object.assign || function (target) {
13319 for (var i = 1; i < arguments.length; i++) {
13320 var source = arguments[i];
13321
13322 for (var key in source) {
13323 if (Object.prototype.hasOwnProperty.call(source, key)) {
13324 target[key] = source[key];
13325 }
13326 }
13327 }
13328
13329 return target;
13330 };
13331
13332 return _extends.apply(this, arguments);
13333 }
13334
13335 function _inheritsLoose(subClass, superClass) {
13336 subClass.prototype = Object.create(superClass.prototype);
13337 subClass.prototype.constructor = subClass;
13338 subClass.__proto__ = superClass;
13339 }
13340
13341 function _assertThisInitialized(self) {
13342 if (self === void 0) {
13343 throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
13344 }
13345
13346 return self;
13347 }
13348 /**
13349 * @private
13350 * extend object.
13351 * means that properties in dest will be overwritten by the ones in src.
13352 * @param {Object} target
13353 * @param {...Object} objects_to_assign
13354 * @returns {Object} target
13355 */
13356
13357
13358 var assign;
13359
13360 if (typeof Object.assign !== 'function') {
13361 assign = function assign(target) {
13362 if (target === undefined || target === null) {
13363 throw new TypeError('Cannot convert undefined or null to object');
13364 }
13365
13366 var output = Object(target);
13367
13368 for (var index = 1; index < arguments.length; index++) {
13369 var source = arguments[index];
13370
13371 if (source !== undefined && source !== null) {
13372 for (var nextKey in source) {
13373 if (source.hasOwnProperty(nextKey)) {
13374 output[nextKey] = source[nextKey];
13375 }
13376 }
13377 }
13378 }
13379
13380 return output;
13381 };
13382 } else {
13383 assign = Object.assign;
13384 }
13385
13386 var assign$1 = assign;
13387 var VENDOR_PREFIXES = ['', 'webkit', 'Moz', 'MS', 'ms', 'o'];
13388 var TEST_ELEMENT = typeof document === "undefined" ? {
13389 style: {}
13390 } : document.createElement('div');
13391 var TYPE_FUNCTION = 'function';
13392 var round = Math.round,
13393 abs$1 = Math.abs;
13394 var now = Date.now;
13395 /**
13396 * @private
13397 * get the prefixed property
13398 * @param {Object} obj
13399 * @param {String} property
13400 * @returns {String|Undefined} prefixed
13401 */
13402
13403 function prefixed(obj, property) {
13404 var prefix;
13405 var prop;
13406 var camelProp = property[0].toUpperCase() + property.slice(1);
13407 var i = 0;
13408
13409 while (i < VENDOR_PREFIXES.length) {
13410 prefix = VENDOR_PREFIXES[i];
13411 prop = prefix ? prefix + camelProp : property;
13412
13413 if (prop in obj) {
13414 return prop;
13415 }
13416
13417 i++;
13418 }
13419
13420 return undefined;
13421 }
13422 /* eslint-disable no-new-func, no-nested-ternary */
13423
13424
13425 var win;
13426
13427 if (typeof window === "undefined") {
13428 // window is undefined in node.js
13429 win = {};
13430 } else {
13431 win = window;
13432 }
13433
13434 var PREFIXED_TOUCH_ACTION = prefixed(TEST_ELEMENT.style, 'touchAction');
13435 var NATIVE_TOUCH_ACTION = PREFIXED_TOUCH_ACTION !== undefined;
13436
13437 function getTouchActionProps() {
13438 if (!NATIVE_TOUCH_ACTION) {
13439 return false;
13440 }
13441
13442 var touchMap = {};
13443 var cssSupports = win.CSS && win.CSS.supports;
13444 ['auto', 'manipulation', 'pan-y', 'pan-x', 'pan-x pan-y', 'none'].forEach(function (val) {
13445 // If css.supports is not supported but there is native touch-action assume it supports
13446 // all values. This is the case for IE 10 and 11.
13447 return touchMap[val] = cssSupports ? win.CSS.supports('touch-action', val) : true;
13448 });
13449 return touchMap;
13450 }
13451
13452 var TOUCH_ACTION_COMPUTE = 'compute';
13453 var TOUCH_ACTION_AUTO = 'auto';
13454 var TOUCH_ACTION_MANIPULATION = 'manipulation'; // not implemented
13455
13456 var TOUCH_ACTION_NONE = 'none';
13457 var TOUCH_ACTION_PAN_X = 'pan-x';
13458 var TOUCH_ACTION_PAN_Y = 'pan-y';
13459 var TOUCH_ACTION_MAP = getTouchActionProps();
13460 var MOBILE_REGEX = /mobile|tablet|ip(ad|hone|od)|android/i;
13461 var SUPPORT_TOUCH = 'ontouchstart' in win;
13462 var SUPPORT_POINTER_EVENTS = prefixed(win, 'PointerEvent') !== undefined;
13463 var SUPPORT_ONLY_TOUCH = SUPPORT_TOUCH && MOBILE_REGEX.test(navigator.userAgent);
13464 var INPUT_TYPE_TOUCH = 'touch';
13465 var INPUT_TYPE_PEN = 'pen';
13466 var INPUT_TYPE_MOUSE = 'mouse';
13467 var INPUT_TYPE_KINECT = 'kinect';
13468 var COMPUTE_INTERVAL = 25;
13469 var INPUT_START = 1;
13470 var INPUT_MOVE = 2;
13471 var INPUT_END = 4;
13472 var INPUT_CANCEL = 8;
13473 var DIRECTION_NONE = 1;
13474 var DIRECTION_LEFT = 2;
13475 var DIRECTION_RIGHT = 4;
13476 var DIRECTION_UP = 8;
13477 var DIRECTION_DOWN = 16;
13478 var DIRECTION_HORIZONTAL = DIRECTION_LEFT | DIRECTION_RIGHT;
13479 var DIRECTION_VERTICAL = DIRECTION_UP | DIRECTION_DOWN;
13480 var DIRECTION_ALL = DIRECTION_HORIZONTAL | DIRECTION_VERTICAL;
13481 var PROPS_XY = ['x', 'y'];
13482 var PROPS_CLIENT_XY = ['clientX', 'clientY'];
13483 /**
13484 * @private
13485 * walk objects and arrays
13486 * @param {Object} obj
13487 * @param {Function} iterator
13488 * @param {Object} context
13489 */
13490
13491 function each(obj, iterator, context) {
13492 var i;
13493
13494 if (!obj) {
13495 return;
13496 }
13497
13498 if (obj.forEach) {
13499 obj.forEach(iterator, context);
13500 } else if (obj.length !== undefined) {
13501 i = 0;
13502
13503 while (i < obj.length) {
13504 iterator.call(context, obj[i], i, obj);
13505 i++;
13506 }
13507 } else {
13508 for (i in obj) {
13509 obj.hasOwnProperty(i) && iterator.call(context, obj[i], i, obj);
13510 }
13511 }
13512 }
13513 /**
13514 * @private
13515 * let a boolean value also be a function that must return a boolean
13516 * this first item in args will be used as the context
13517 * @param {Boolean|Function} val
13518 * @param {Array} [args]
13519 * @returns {Boolean}
13520 */
13521
13522
13523 function boolOrFn(val, args) {
13524 if (typeof val === TYPE_FUNCTION) {
13525 return val.apply(args ? args[0] || undefined : undefined, args);
13526 }
13527
13528 return val;
13529 }
13530 /**
13531 * @private
13532 * small indexOf wrapper
13533 * @param {String} str
13534 * @param {String} find
13535 * @returns {Boolean} found
13536 */
13537
13538
13539 function inStr(str, find) {
13540 return str.indexOf(find) > -1;
13541 }
13542 /**
13543 * @private
13544 * when the touchActions are collected they are not a valid value, so we need to clean things up. *
13545 * @param {String} actions
13546 * @returns {*}
13547 */
13548
13549
13550 function cleanTouchActions(actions) {
13551 // none
13552 if (inStr(actions, TOUCH_ACTION_NONE)) {
13553 return TOUCH_ACTION_NONE;
13554 }
13555
13556 var hasPanX = inStr(actions, TOUCH_ACTION_PAN_X);
13557 var hasPanY = inStr(actions, TOUCH_ACTION_PAN_Y); // if both pan-x and pan-y are set (different recognizers
13558 // for different directions, e.g. horizontal pan but vertical swipe?)
13559 // we need none (as otherwise with pan-x pan-y combined none of these
13560 // recognizers will work, since the browser would handle all panning
13561
13562 if (hasPanX && hasPanY) {
13563 return TOUCH_ACTION_NONE;
13564 } // pan-x OR pan-y
13565
13566
13567 if (hasPanX || hasPanY) {
13568 return hasPanX ? TOUCH_ACTION_PAN_X : TOUCH_ACTION_PAN_Y;
13569 } // manipulation
13570
13571
13572 if (inStr(actions, TOUCH_ACTION_MANIPULATION)) {
13573 return TOUCH_ACTION_MANIPULATION;
13574 }
13575
13576 return TOUCH_ACTION_AUTO;
13577 }
13578 /**
13579 * @private
13580 * Touch Action
13581 * sets the touchAction property or uses the js alternative
13582 * @param {Manager} manager
13583 * @param {String} value
13584 * @constructor
13585 */
13586
13587
13588 var TouchAction =
13589 /*#__PURE__*/
13590 function () {
13591 function TouchAction(manager, value) {
13592 this.manager = manager;
13593 this.set(value);
13594 }
13595 /**
13596 * @private
13597 * set the touchAction value on the element or enable the polyfill
13598 * @param {String} value
13599 */
13600
13601
13602 var _proto = TouchAction.prototype;
13603
13604 _proto.set = function set(value) {
13605 // find out the touch-action by the event handlers
13606 if (value === TOUCH_ACTION_COMPUTE) {
13607 value = this.compute();
13608 }
13609
13610 if (NATIVE_TOUCH_ACTION && this.manager.element.style && TOUCH_ACTION_MAP[value]) {
13611 this.manager.element.style[PREFIXED_TOUCH_ACTION] = value;
13612 }
13613
13614 this.actions = value.toLowerCase().trim();
13615 };
13616 /**
13617 * @private
13618 * just re-set the touchAction value
13619 */
13620
13621
13622 _proto.update = function update() {
13623 this.set(this.manager.options.touchAction);
13624 };
13625 /**
13626 * @private
13627 * compute the value for the touchAction property based on the recognizer's settings
13628 * @returns {String} value
13629 */
13630
13631
13632 _proto.compute = function compute() {
13633 var actions = [];
13634 each(this.manager.recognizers, function (recognizer) {
13635 if (boolOrFn(recognizer.options.enable, [recognizer])) {
13636 actions = actions.concat(recognizer.getTouchAction());
13637 }
13638 });
13639 return cleanTouchActions(actions.join(' '));
13640 };
13641 /**
13642 * @private
13643 * this method is called on each input cycle and provides the preventing of the browser behavior
13644 * @param {Object} input
13645 */
13646
13647
13648 _proto.preventDefaults = function preventDefaults(input) {
13649 var srcEvent = input.srcEvent;
13650 var direction = input.offsetDirection; // if the touch action did prevented once this session
13651
13652 if (this.manager.session.prevented) {
13653 srcEvent.preventDefault();
13654 return;
13655 }
13656
13657 var actions = this.actions;
13658 var hasNone = inStr(actions, TOUCH_ACTION_NONE) && !TOUCH_ACTION_MAP[TOUCH_ACTION_NONE];
13659 var hasPanY = inStr(actions, TOUCH_ACTION_PAN_Y) && !TOUCH_ACTION_MAP[TOUCH_ACTION_PAN_Y];
13660 var hasPanX = inStr(actions, TOUCH_ACTION_PAN_X) && !TOUCH_ACTION_MAP[TOUCH_ACTION_PAN_X];
13661
13662 if (hasNone) {
13663 // do not prevent defaults if this is a tap gesture
13664 var isTapPointer = input.pointers.length === 1;
13665 var isTapMovement = input.distance < 2;
13666 var isTapTouchTime = input.deltaTime < 250;
13667
13668 if (isTapPointer && isTapMovement && isTapTouchTime) {
13669 return;
13670 }
13671 }
13672
13673 if (hasPanX && hasPanY) {
13674 // `pan-x pan-y` means browser handles all scrolling/panning, do not prevent
13675 return;
13676 }
13677
13678 if (hasNone || hasPanY && direction & DIRECTION_HORIZONTAL || hasPanX && direction & DIRECTION_VERTICAL) {
13679 return this.preventSrc(srcEvent);
13680 }
13681 };
13682 /**
13683 * @private
13684 * call preventDefault to prevent the browser's default behavior (scrolling in most cases)
13685 * @param {Object} srcEvent
13686 */
13687
13688
13689 _proto.preventSrc = function preventSrc(srcEvent) {
13690 this.manager.session.prevented = true;
13691 srcEvent.preventDefault();
13692 };
13693
13694 return TouchAction;
13695 }();
13696 /**
13697 * @private
13698 * find if a node is in the given parent
13699 * @method hasParent
13700 * @param {HTMLElement} node
13701 * @param {HTMLElement} parent
13702 * @return {Boolean} found
13703 */
13704
13705
13706 function hasParent$1(node, parent) {
13707 while (node) {
13708 if (node === parent) {
13709 return true;
13710 }
13711
13712 node = node.parentNode;
13713 }
13714
13715 return false;
13716 }
13717 /**
13718 * @private
13719 * get the center of all the pointers
13720 * @param {Array} pointers
13721 * @return {Object} center contains `x` and `y` properties
13722 */
13723
13724
13725 function getCenter(pointers) {
13726 var pointersLength = pointers.length; // no need to loop when only one touch
13727
13728 if (pointersLength === 1) {
13729 return {
13730 x: round(pointers[0].clientX),
13731 y: round(pointers[0].clientY)
13732 };
13733 }
13734
13735 var x = 0;
13736 var y = 0;
13737 var i = 0;
13738
13739 while (i < pointersLength) {
13740 x += pointers[i].clientX;
13741 y += pointers[i].clientY;
13742 i++;
13743 }
13744
13745 return {
13746 x: round(x / pointersLength),
13747 y: round(y / pointersLength)
13748 };
13749 }
13750 /**
13751 * @private
13752 * create a simple clone from the input used for storage of firstInput and firstMultiple
13753 * @param {Object} input
13754 * @returns {Object} clonedInputData
13755 */
13756
13757
13758 function simpleCloneInputData(input) {
13759 // make a simple copy of the pointers because we will get a reference if we don't
13760 // we only need clientXY for the calculations
13761 var pointers = [];
13762 var i = 0;
13763
13764 while (i < input.pointers.length) {
13765 pointers[i] = {
13766 clientX: round(input.pointers[i].clientX),
13767 clientY: round(input.pointers[i].clientY)
13768 };
13769 i++;
13770 }
13771
13772 return {
13773 timeStamp: now(),
13774 pointers: pointers,
13775 center: getCenter(pointers),
13776 deltaX: input.deltaX,
13777 deltaY: input.deltaY
13778 };
13779 }
13780 /**
13781 * @private
13782 * calculate the absolute distance between two points
13783 * @param {Object} p1 {x, y}
13784 * @param {Object} p2 {x, y}
13785 * @param {Array} [props] containing x and y keys
13786 * @return {Number} distance
13787 */
13788
13789
13790 function getDistance(p1, p2, props) {
13791 if (!props) {
13792 props = PROPS_XY;
13793 }
13794
13795 var x = p2[props[0]] - p1[props[0]];
13796 var y = p2[props[1]] - p1[props[1]];
13797 return Math.sqrt(x * x + y * y);
13798 }
13799 /**
13800 * @private
13801 * calculate the angle between two coordinates
13802 * @param {Object} p1
13803 * @param {Object} p2
13804 * @param {Array} [props] containing x and y keys
13805 * @return {Number} angle
13806 */
13807
13808
13809 function getAngle(p1, p2, props) {
13810 if (!props) {
13811 props = PROPS_XY;
13812 }
13813
13814 var x = p2[props[0]] - p1[props[0]];
13815 var y = p2[props[1]] - p1[props[1]];
13816 return Math.atan2(y, x) * 180 / Math.PI;
13817 }
13818 /**
13819 * @private
13820 * get the direction between two points
13821 * @param {Number} x
13822 * @param {Number} y
13823 * @return {Number} direction
13824 */
13825
13826
13827 function getDirection(x, y) {
13828 if (x === y) {
13829 return DIRECTION_NONE;
13830 }
13831
13832 if (abs$1(x) >= abs$1(y)) {
13833 return x < 0 ? DIRECTION_LEFT : DIRECTION_RIGHT;
13834 }
13835
13836 return y < 0 ? DIRECTION_UP : DIRECTION_DOWN;
13837 }
13838
13839 function computeDeltaXY(session, input) {
13840 var center = input.center; // let { offsetDelta:offset = {}, prevDelta = {}, prevInput = {} } = session;
13841 // jscs throwing error on defalut destructured values and without defaults tests fail
13842
13843 var offset = session.offsetDelta || {};
13844 var prevDelta = session.prevDelta || {};
13845 var prevInput = session.prevInput || {};
13846
13847 if (input.eventType === INPUT_START || prevInput.eventType === INPUT_END) {
13848 prevDelta = session.prevDelta = {
13849 x: prevInput.deltaX || 0,
13850 y: prevInput.deltaY || 0
13851 };
13852 offset = session.offsetDelta = {
13853 x: center.x,
13854 y: center.y
13855 };
13856 }
13857
13858 input.deltaX = prevDelta.x + (center.x - offset.x);
13859 input.deltaY = prevDelta.y + (center.y - offset.y);
13860 }
13861 /**
13862 * @private
13863 * calculate the velocity between two points. unit is in px per ms.
13864 * @param {Number} deltaTime
13865 * @param {Number} x
13866 * @param {Number} y
13867 * @return {Object} velocity `x` and `y`
13868 */
13869
13870
13871 function getVelocity(deltaTime, x, y) {
13872 return {
13873 x: x / deltaTime || 0,
13874 y: y / deltaTime || 0
13875 };
13876 }
13877 /**
13878 * @private
13879 * calculate the scale factor between two pointersets
13880 * no scale is 1, and goes down to 0 when pinched together, and bigger when pinched out
13881 * @param {Array} start array of pointers
13882 * @param {Array} end array of pointers
13883 * @return {Number} scale
13884 */
13885
13886
13887 function getScale(start, end) {
13888 return getDistance(end[0], end[1], PROPS_CLIENT_XY) / getDistance(start[0], start[1], PROPS_CLIENT_XY);
13889 }
13890 /**
13891 * @private
13892 * calculate the rotation degrees between two pointersets
13893 * @param {Array} start array of pointers
13894 * @param {Array} end array of pointers
13895 * @return {Number} rotation
13896 */
13897
13898
13899 function getRotation(start, end) {
13900 return getAngle(end[1], end[0], PROPS_CLIENT_XY) + getAngle(start[1], start[0], PROPS_CLIENT_XY);
13901 }
13902 /**
13903 * @private
13904 * velocity is calculated every x ms
13905 * @param {Object} session
13906 * @param {Object} input
13907 */
13908
13909
13910 function computeIntervalInputData(session, input) {
13911 var last = session.lastInterval || input;
13912 var deltaTime = input.timeStamp - last.timeStamp;
13913 var velocity;
13914 var velocityX;
13915 var velocityY;
13916 var direction;
13917
13918 if (input.eventType !== INPUT_CANCEL && (deltaTime > COMPUTE_INTERVAL || last.velocity === undefined)) {
13919 var deltaX = input.deltaX - last.deltaX;
13920 var deltaY = input.deltaY - last.deltaY;
13921 var v = getVelocity(deltaTime, deltaX, deltaY);
13922 velocityX = v.x;
13923 velocityY = v.y;
13924 velocity = abs$1(v.x) > abs$1(v.y) ? v.x : v.y;
13925 direction = getDirection(deltaX, deltaY);
13926 session.lastInterval = input;
13927 } else {
13928 // use latest velocity info if it doesn't overtake a minimum period
13929 velocity = last.velocity;
13930 velocityX = last.velocityX;
13931 velocityY = last.velocityY;
13932 direction = last.direction;
13933 }
13934
13935 input.velocity = velocity;
13936 input.velocityX = velocityX;
13937 input.velocityY = velocityY;
13938 input.direction = direction;
13939 }
13940 /**
13941 * @private
13942 * extend the data with some usable properties like scale, rotate, velocity etc
13943 * @param {Object} manager
13944 * @param {Object} input
13945 */
13946
13947
13948 function computeInputData(manager, input) {
13949 var session = manager.session;
13950 var pointers = input.pointers;
13951 var pointersLength = pointers.length; // store the first input to calculate the distance and direction
13952
13953 if (!session.firstInput) {
13954 session.firstInput = simpleCloneInputData(input);
13955 } // to compute scale and rotation we need to store the multiple touches
13956
13957
13958 if (pointersLength > 1 && !session.firstMultiple) {
13959 session.firstMultiple = simpleCloneInputData(input);
13960 } else if (pointersLength === 1) {
13961 session.firstMultiple = false;
13962 }
13963
13964 var firstInput = session.firstInput,
13965 firstMultiple = session.firstMultiple;
13966 var offsetCenter = firstMultiple ? firstMultiple.center : firstInput.center;
13967 var center = input.center = getCenter(pointers);
13968 input.timeStamp = now();
13969 input.deltaTime = input.timeStamp - firstInput.timeStamp;
13970 input.angle = getAngle(offsetCenter, center);
13971 input.distance = getDistance(offsetCenter, center);
13972 computeDeltaXY(session, input);
13973 input.offsetDirection = getDirection(input.deltaX, input.deltaY);
13974 var overallVelocity = getVelocity(input.deltaTime, input.deltaX, input.deltaY);
13975 input.overallVelocityX = overallVelocity.x;
13976 input.overallVelocityY = overallVelocity.y;
13977 input.overallVelocity = abs$1(overallVelocity.x) > abs$1(overallVelocity.y) ? overallVelocity.x : overallVelocity.y;
13978 input.scale = firstMultiple ? getScale(firstMultiple.pointers, pointers) : 1;
13979 input.rotation = firstMultiple ? getRotation(firstMultiple.pointers, pointers) : 0;
13980 input.maxPointers = !session.prevInput ? input.pointers.length : input.pointers.length > session.prevInput.maxPointers ? input.pointers.length : session.prevInput.maxPointers;
13981 computeIntervalInputData(session, input); // find the correct target
13982
13983 var target = manager.element;
13984
13985 if (hasParent$1(input.srcEvent.target, target)) {
13986 target = input.srcEvent.target;
13987 }
13988
13989 input.target = target;
13990 }
13991 /**
13992 * @private
13993 * handle input events
13994 * @param {Manager} manager
13995 * @param {String} eventType
13996 * @param {Object} input
13997 */
13998
13999
14000 function inputHandler(manager, eventType, input) {
14001 var pointersLen = input.pointers.length;
14002 var changedPointersLen = input.changedPointers.length;
14003 var isFirst = eventType & INPUT_START && pointersLen - changedPointersLen === 0;
14004 var isFinal = eventType & (INPUT_END | INPUT_CANCEL) && pointersLen - changedPointersLen === 0;
14005 input.isFirst = !!isFirst;
14006 input.isFinal = !!isFinal;
14007
14008 if (isFirst) {
14009 manager.session = {};
14010 } // source event is the normalized value of the domEvents
14011 // like 'touchstart, mouseup, pointerdown'
14012
14013
14014 input.eventType = eventType; // compute scale, rotation etc
14015
14016 computeInputData(manager, input); // emit secret event
14017
14018 manager.emit('hammer.input', input);
14019 manager.recognize(input);
14020 manager.session.prevInput = input;
14021 }
14022 /**
14023 * @private
14024 * split string on whitespace
14025 * @param {String} str
14026 * @returns {Array} words
14027 */
14028
14029
14030 function splitStr(str) {
14031 return str.trim().split(/\s+/g);
14032 }
14033 /**
14034 * @private
14035 * addEventListener with multiple events at once
14036 * @param {EventTarget} target
14037 * @param {String} types
14038 * @param {Function} handler
14039 */
14040
14041
14042 function addEventListeners(target, types, handler) {
14043 each(splitStr(types), function (type) {
14044 target.addEventListener(type, handler, false);
14045 });
14046 }
14047 /**
14048 * @private
14049 * removeEventListener with multiple events at once
14050 * @param {EventTarget} target
14051 * @param {String} types
14052 * @param {Function} handler
14053 */
14054
14055
14056 function removeEventListeners(target, types, handler) {
14057 each(splitStr(types), function (type) {
14058 target.removeEventListener(type, handler, false);
14059 });
14060 }
14061 /**
14062 * @private
14063 * get the window object of an element
14064 * @param {HTMLElement} element
14065 * @returns {DocumentView|Window}
14066 */
14067
14068
14069 function getWindowForElement(element) {
14070 var doc = element.ownerDocument || element;
14071 return doc.defaultView || doc.parentWindow || window;
14072 }
14073 /**
14074 * @private
14075 * create new input type manager
14076 * @param {Manager} manager
14077 * @param {Function} callback
14078 * @returns {Input}
14079 * @constructor
14080 */
14081
14082
14083 var Input =
14084 /*#__PURE__*/
14085 function () {
14086 function Input(manager, callback) {
14087 var self = this;
14088 this.manager = manager;
14089 this.callback = callback;
14090 this.element = manager.element;
14091 this.target = manager.options.inputTarget; // smaller wrapper around the handler, for the scope and the enabled state of the manager,
14092 // so when disabled the input events are completely bypassed.
14093
14094 this.domHandler = function (ev) {
14095 if (boolOrFn(manager.options.enable, [manager])) {
14096 self.handler(ev);
14097 }
14098 };
14099
14100 this.init();
14101 }
14102 /**
14103 * @private
14104 * should handle the inputEvent data and trigger the callback
14105 * @virtual
14106 */
14107
14108
14109 var _proto = Input.prototype;
14110
14111 _proto.handler = function handler() {};
14112 /**
14113 * @private
14114 * bind the events
14115 */
14116
14117
14118 _proto.init = function init() {
14119 this.evEl && addEventListeners(this.element, this.evEl, this.domHandler);
14120 this.evTarget && addEventListeners(this.target, this.evTarget, this.domHandler);
14121 this.evWin && addEventListeners(getWindowForElement(this.element), this.evWin, this.domHandler);
14122 };
14123 /**
14124 * @private
14125 * unbind the events
14126 */
14127
14128
14129 _proto.destroy = function destroy() {
14130 this.evEl && removeEventListeners(this.element, this.evEl, this.domHandler);
14131 this.evTarget && removeEventListeners(this.target, this.evTarget, this.domHandler);
14132 this.evWin && removeEventListeners(getWindowForElement(this.element), this.evWin, this.domHandler);
14133 };
14134
14135 return Input;
14136 }();
14137 /**
14138 * @private
14139 * find if a array contains the object using indexOf or a simple polyFill
14140 * @param {Array} src
14141 * @param {String} find
14142 * @param {String} [findByKey]
14143 * @return {Boolean|Number} false when not found, or the index
14144 */
14145
14146
14147 function inArray(src, find, findByKey) {
14148 if (src.indexOf && !findByKey) {
14149 return src.indexOf(find);
14150 } else {
14151 var i = 0;
14152
14153 while (i < src.length) {
14154 if (findByKey && src[i][findByKey] == find || !findByKey && src[i] === find) {
14155 // do not use === here, test fails
14156 return i;
14157 }
14158
14159 i++;
14160 }
14161
14162 return -1;
14163 }
14164 }
14165
14166 var POINTER_INPUT_MAP = {
14167 pointerdown: INPUT_START,
14168 pointermove: INPUT_MOVE,
14169 pointerup: INPUT_END,
14170 pointercancel: INPUT_CANCEL,
14171 pointerout: INPUT_CANCEL
14172 }; // in IE10 the pointer types is defined as an enum
14173
14174 var IE10_POINTER_TYPE_ENUM = {
14175 2: INPUT_TYPE_TOUCH,
14176 3: INPUT_TYPE_PEN,
14177 4: INPUT_TYPE_MOUSE,
14178 5: INPUT_TYPE_KINECT // see https://twitter.com/jacobrossi/status/480596438489890816
14179
14180 };
14181 var POINTER_ELEMENT_EVENTS = 'pointerdown';
14182 var POINTER_WINDOW_EVENTS = 'pointermove pointerup pointercancel'; // IE10 has prefixed support, and case-sensitive
14183
14184 if (win.MSPointerEvent && !win.PointerEvent) {
14185 POINTER_ELEMENT_EVENTS = 'MSPointerDown';
14186 POINTER_WINDOW_EVENTS = 'MSPointerMove MSPointerUp MSPointerCancel';
14187 }
14188 /**
14189 * @private
14190 * Pointer events input
14191 * @constructor
14192 * @extends Input
14193 */
14194
14195
14196 var PointerEventInput =
14197 /*#__PURE__*/
14198 function (_Input) {
14199 _inheritsLoose(PointerEventInput, _Input);
14200
14201 function PointerEventInput() {
14202 var _this;
14203
14204 var proto = PointerEventInput.prototype;
14205 proto.evEl = POINTER_ELEMENT_EVENTS;
14206 proto.evWin = POINTER_WINDOW_EVENTS;
14207 _this = _Input.apply(this, arguments) || this;
14208 _this.store = _this.manager.session.pointerEvents = [];
14209 return _this;
14210 }
14211 /**
14212 * @private
14213 * handle mouse events
14214 * @param {Object} ev
14215 */
14216
14217
14218 var _proto = PointerEventInput.prototype;
14219
14220 _proto.handler = function handler(ev) {
14221 var store = this.store;
14222 var removePointer = false;
14223 var eventTypeNormalized = ev.type.toLowerCase().replace('ms', '');
14224 var eventType = POINTER_INPUT_MAP[eventTypeNormalized];
14225 var pointerType = IE10_POINTER_TYPE_ENUM[ev.pointerType] || ev.pointerType;
14226 var isTouch = pointerType === INPUT_TYPE_TOUCH; // get index of the event in the store
14227
14228 var storeIndex = inArray(store, ev.pointerId, 'pointerId'); // start and mouse must be down
14229
14230 if (eventType & INPUT_START && (ev.button === 0 || isTouch)) {
14231 if (storeIndex < 0) {
14232 store.push(ev);
14233 storeIndex = store.length - 1;
14234 }
14235 } else if (eventType & (INPUT_END | INPUT_CANCEL)) {
14236 removePointer = true;
14237 } // it not found, so the pointer hasn't been down (so it's probably a hover)
14238
14239
14240 if (storeIndex < 0) {
14241 return;
14242 } // update the event in the store
14243
14244
14245 store[storeIndex] = ev;
14246 this.callback(this.manager, eventType, {
14247 pointers: store,
14248 changedPointers: [ev],
14249 pointerType: pointerType,
14250 srcEvent: ev
14251 });
14252
14253 if (removePointer) {
14254 // remove from the store
14255 store.splice(storeIndex, 1);
14256 }
14257 };
14258
14259 return PointerEventInput;
14260 }(Input);
14261 /**
14262 * @private
14263 * convert array-like objects to real arrays
14264 * @param {Object} obj
14265 * @returns {Array}
14266 */
14267
14268
14269 function toArray$1(obj) {
14270 return Array.prototype.slice.call(obj, 0);
14271 }
14272 /**
14273 * @private
14274 * unique array with objects based on a key (like 'id') or just by the array's value
14275 * @param {Array} src [{id:1},{id:2},{id:1}]
14276 * @param {String} [key]
14277 * @param {Boolean} [sort=False]
14278 * @returns {Array} [{id:1},{id:2}]
14279 */
14280
14281
14282 function uniqueArray(src, key, sort) {
14283 var results = [];
14284 var values = [];
14285 var i = 0;
14286
14287 while (i < src.length) {
14288 var val = key ? src[i][key] : src[i];
14289
14290 if (inArray(values, val) < 0) {
14291 results.push(src[i]);
14292 }
14293
14294 values[i] = val;
14295 i++;
14296 }
14297
14298 if (sort) {
14299 if (!key) {
14300 results = results.sort();
14301 } else {
14302 results = results.sort(function (a, b) {
14303 return a[key] > b[key];
14304 });
14305 }
14306 }
14307
14308 return results;
14309 }
14310
14311 var TOUCH_INPUT_MAP = {
14312 touchstart: INPUT_START,
14313 touchmove: INPUT_MOVE,
14314 touchend: INPUT_END,
14315 touchcancel: INPUT_CANCEL
14316 };
14317 var TOUCH_TARGET_EVENTS = 'touchstart touchmove touchend touchcancel';
14318 /**
14319 * @private
14320 * Multi-user touch events input
14321 * @constructor
14322 * @extends Input
14323 */
14324
14325 var TouchInput =
14326 /*#__PURE__*/
14327 function (_Input) {
14328 _inheritsLoose(TouchInput, _Input);
14329
14330 function TouchInput() {
14331 var _this;
14332
14333 TouchInput.prototype.evTarget = TOUCH_TARGET_EVENTS;
14334 _this = _Input.apply(this, arguments) || this;
14335 _this.targetIds = {}; // this.evTarget = TOUCH_TARGET_EVENTS;
14336
14337 return _this;
14338 }
14339
14340 var _proto = TouchInput.prototype;
14341
14342 _proto.handler = function handler(ev) {
14343 var type = TOUCH_INPUT_MAP[ev.type];
14344 var touches = getTouches.call(this, ev, type);
14345
14346 if (!touches) {
14347 return;
14348 }
14349
14350 this.callback(this.manager, type, {
14351 pointers: touches[0],
14352 changedPointers: touches[1],
14353 pointerType: INPUT_TYPE_TOUCH,
14354 srcEvent: ev
14355 });
14356 };
14357
14358 return TouchInput;
14359 }(Input);
14360
14361 function getTouches(ev, type) {
14362 var allTouches = toArray$1(ev.touches);
14363 var targetIds = this.targetIds; // when there is only one touch, the process can be simplified
14364
14365 if (type & (INPUT_START | INPUT_MOVE) && allTouches.length === 1) {
14366 targetIds[allTouches[0].identifier] = true;
14367 return [allTouches, allTouches];
14368 }
14369
14370 var i;
14371 var targetTouches;
14372 var changedTouches = toArray$1(ev.changedTouches);
14373 var changedTargetTouches = [];
14374 var target = this.target; // get target touches from touches
14375
14376 targetTouches = allTouches.filter(function (touch) {
14377 return hasParent$1(touch.target, target);
14378 }); // collect touches
14379
14380 if (type === INPUT_START) {
14381 i = 0;
14382
14383 while (i < targetTouches.length) {
14384 targetIds[targetTouches[i].identifier] = true;
14385 i++;
14386 }
14387 } // filter changed touches to only contain touches that exist in the collected target ids
14388
14389
14390 i = 0;
14391
14392 while (i < changedTouches.length) {
14393 if (targetIds[changedTouches[i].identifier]) {
14394 changedTargetTouches.push(changedTouches[i]);
14395 } // cleanup removed touches
14396
14397
14398 if (type & (INPUT_END | INPUT_CANCEL)) {
14399 delete targetIds[changedTouches[i].identifier];
14400 }
14401
14402 i++;
14403 }
14404
14405 if (!changedTargetTouches.length) {
14406 return;
14407 }
14408
14409 return [// merge targetTouches with changedTargetTouches so it contains ALL touches, including 'end' and 'cancel'
14410 uniqueArray(targetTouches.concat(changedTargetTouches), 'identifier', true), changedTargetTouches];
14411 }
14412
14413 var MOUSE_INPUT_MAP = {
14414 mousedown: INPUT_START,
14415 mousemove: INPUT_MOVE,
14416 mouseup: INPUT_END
14417 };
14418 var MOUSE_ELEMENT_EVENTS = 'mousedown';
14419 var MOUSE_WINDOW_EVENTS = 'mousemove mouseup';
14420 /**
14421 * @private
14422 * Mouse events input
14423 * @constructor
14424 * @extends Input
14425 */
14426
14427 var MouseInput =
14428 /*#__PURE__*/
14429 function (_Input) {
14430 _inheritsLoose(MouseInput, _Input);
14431
14432 function MouseInput() {
14433 var _this;
14434
14435 var proto = MouseInput.prototype;
14436 proto.evEl = MOUSE_ELEMENT_EVENTS;
14437 proto.evWin = MOUSE_WINDOW_EVENTS;
14438 _this = _Input.apply(this, arguments) || this;
14439 _this.pressed = false; // mousedown state
14440
14441 return _this;
14442 }
14443 /**
14444 * @private
14445 * handle mouse events
14446 * @param {Object} ev
14447 */
14448
14449
14450 var _proto = MouseInput.prototype;
14451
14452 _proto.handler = function handler(ev) {
14453 var eventType = MOUSE_INPUT_MAP[ev.type]; // on start we want to have the left mouse button down
14454
14455 if (eventType & INPUT_START && ev.button === 0) {
14456 this.pressed = true;
14457 }
14458
14459 if (eventType & INPUT_MOVE && ev.which !== 1) {
14460 eventType = INPUT_END;
14461 } // mouse must be down
14462
14463
14464 if (!this.pressed) {
14465 return;
14466 }
14467
14468 if (eventType & INPUT_END) {
14469 this.pressed = false;
14470 }
14471
14472 this.callback(this.manager, eventType, {
14473 pointers: [ev],
14474 changedPointers: [ev],
14475 pointerType: INPUT_TYPE_MOUSE,
14476 srcEvent: ev
14477 });
14478 };
14479
14480 return MouseInput;
14481 }(Input);
14482 /**
14483 * @private
14484 * Combined touch and mouse input
14485 *
14486 * Touch has a higher priority then mouse, and while touching no mouse events are allowed.
14487 * This because touch devices also emit mouse events while doing a touch.
14488 *
14489 * @constructor
14490 * @extends Input
14491 */
14492
14493
14494 var DEDUP_TIMEOUT = 2500;
14495 var DEDUP_DISTANCE = 25;
14496
14497 function setLastTouch(eventData) {
14498 var _eventData$changedPoi = eventData.changedPointers,
14499 touch = _eventData$changedPoi[0];
14500
14501 if (touch.identifier === this.primaryTouch) {
14502 var lastTouch = {
14503 x: touch.clientX,
14504 y: touch.clientY
14505 };
14506 var lts = this.lastTouches;
14507 this.lastTouches.push(lastTouch);
14508
14509 var removeLastTouch = function removeLastTouch() {
14510 var i = lts.indexOf(lastTouch);
14511
14512 if (i > -1) {
14513 lts.splice(i, 1);
14514 }
14515 };
14516
14517 setTimeout(removeLastTouch, DEDUP_TIMEOUT);
14518 }
14519 }
14520
14521 function recordTouches(eventType, eventData) {
14522 if (eventType & INPUT_START) {
14523 this.primaryTouch = eventData.changedPointers[0].identifier;
14524 setLastTouch.call(this, eventData);
14525 } else if (eventType & (INPUT_END | INPUT_CANCEL)) {
14526 setLastTouch.call(this, eventData);
14527 }
14528 }
14529
14530 function isSyntheticEvent(eventData) {
14531 var x = eventData.srcEvent.clientX;
14532 var y = eventData.srcEvent.clientY;
14533
14534 for (var i = 0; i < this.lastTouches.length; i++) {
14535 var t = this.lastTouches[i];
14536 var dx = Math.abs(x - t.x);
14537 var dy = Math.abs(y - t.y);
14538
14539 if (dx <= DEDUP_DISTANCE && dy <= DEDUP_DISTANCE) {
14540 return true;
14541 }
14542 }
14543
14544 return false;
14545 }
14546
14547 var TouchMouseInput =
14548 /*#__PURE__*/
14549 function () {
14550 var TouchMouseInput =
14551 /*#__PURE__*/
14552 function (_Input) {
14553 _inheritsLoose(TouchMouseInput, _Input);
14554
14555 function TouchMouseInput(_manager, callback) {
14556 var _this;
14557
14558 _this = _Input.call(this, _manager, callback) || this;
14559
14560 _this.handler = function (manager, inputEvent, inputData) {
14561 var isTouch = inputData.pointerType === INPUT_TYPE_TOUCH;
14562 var isMouse = inputData.pointerType === INPUT_TYPE_MOUSE;
14563
14564 if (isMouse && inputData.sourceCapabilities && inputData.sourceCapabilities.firesTouchEvents) {
14565 return;
14566 } // when we're in a touch event, record touches to de-dupe synthetic mouse event
14567
14568
14569 if (isTouch) {
14570 recordTouches.call(_assertThisInitialized(_assertThisInitialized(_this)), inputEvent, inputData);
14571 } else if (isMouse && isSyntheticEvent.call(_assertThisInitialized(_assertThisInitialized(_this)), inputData)) {
14572 return;
14573 }
14574
14575 _this.callback(manager, inputEvent, inputData);
14576 };
14577
14578 _this.touch = new TouchInput(_this.manager, _this.handler);
14579 _this.mouse = new MouseInput(_this.manager, _this.handler);
14580 _this.primaryTouch = null;
14581 _this.lastTouches = [];
14582 return _this;
14583 }
14584 /**
14585 * @private
14586 * handle mouse and touch events
14587 * @param {Hammer} manager
14588 * @param {String} inputEvent
14589 * @param {Object} inputData
14590 */
14591
14592
14593 var _proto = TouchMouseInput.prototype;
14594 /**
14595 * @private
14596 * remove the event listeners
14597 */
14598
14599 _proto.destroy = function destroy() {
14600 this.touch.destroy();
14601 this.mouse.destroy();
14602 };
14603
14604 return TouchMouseInput;
14605 }(Input);
14606
14607 return TouchMouseInput;
14608 }();
14609 /**
14610 * @private
14611 * create new input type manager
14612 * called by the Manager constructor
14613 * @param {Hammer} manager
14614 * @returns {Input}
14615 */
14616
14617
14618 function createInputInstance(manager) {
14619 var Type; // let inputClass = manager.options.inputClass;
14620
14621 var inputClass = manager.options.inputClass;
14622
14623 if (inputClass) {
14624 Type = inputClass;
14625 } else if (SUPPORT_POINTER_EVENTS) {
14626 Type = PointerEventInput;
14627 } else if (SUPPORT_ONLY_TOUCH) {
14628 Type = TouchInput;
14629 } else if (!SUPPORT_TOUCH) {
14630 Type = MouseInput;
14631 } else {
14632 Type = TouchMouseInput;
14633 }
14634
14635 return new Type(manager, inputHandler);
14636 }
14637 /**
14638 * @private
14639 * if the argument is an array, we want to execute the fn on each entry
14640 * if it aint an array we don't want to do a thing.
14641 * this is used by all the methods that accept a single and array argument.
14642 * @param {*|Array} arg
14643 * @param {String} fn
14644 * @param {Object} [context]
14645 * @returns {Boolean}
14646 */
14647
14648
14649 function invokeArrayArg(arg, fn, context) {
14650 if (Array.isArray(arg)) {
14651 each(arg, context[fn], context);
14652 return true;
14653 }
14654
14655 return false;
14656 }
14657
14658 var STATE_POSSIBLE = 1;
14659 var STATE_BEGAN = 2;
14660 var STATE_CHANGED = 4;
14661 var STATE_ENDED = 8;
14662 var STATE_RECOGNIZED = STATE_ENDED;
14663 var STATE_CANCELLED = 16;
14664 var STATE_FAILED = 32;
14665 /**
14666 * @private
14667 * get a unique id
14668 * @returns {number} uniqueId
14669 */
14670
14671 var _uniqueId = 1;
14672
14673 function uniqueId() {
14674 return _uniqueId++;
14675 }
14676 /**
14677 * @private
14678 * get a recognizer by name if it is bound to a manager
14679 * @param {Recognizer|String} otherRecognizer
14680 * @param {Recognizer} recognizer
14681 * @returns {Recognizer}
14682 */
14683
14684
14685 function getRecognizerByNameIfManager(otherRecognizer, recognizer) {
14686 var manager = recognizer.manager;
14687
14688 if (manager) {
14689 return manager.get(otherRecognizer);
14690 }
14691
14692 return otherRecognizer;
14693 }
14694 /**
14695 * @private
14696 * get a usable string, used as event postfix
14697 * @param {constant} state
14698 * @returns {String} state
14699 */
14700
14701
14702 function stateStr(state) {
14703 if (state & STATE_CANCELLED) {
14704 return 'cancel';
14705 } else if (state & STATE_ENDED) {
14706 return 'end';
14707 } else if (state & STATE_CHANGED) {
14708 return 'move';
14709 } else if (state & STATE_BEGAN) {
14710 return 'start';
14711 }
14712
14713 return '';
14714 }
14715 /**
14716 * @private
14717 * Recognizer flow explained; *
14718 * All recognizers have the initial state of POSSIBLE when a input session starts.
14719 * The definition of a input session is from the first input until the last input, with all it's movement in it. *
14720 * Example session for mouse-input: mousedown -> mousemove -> mouseup
14721 *
14722 * On each recognizing cycle (see Manager.recognize) the .recognize() method is executed
14723 * which determines with state it should be.
14724 *
14725 * If the recognizer has the state FAILED, CANCELLED or RECOGNIZED (equals ENDED), it is reset to
14726 * POSSIBLE to give it another change on the next cycle.
14727 *
14728 * Possible
14729 * |
14730 * +-----+---------------+
14731 * | |
14732 * +-----+-----+ |
14733 * | | |
14734 * Failed Cancelled |
14735 * +-------+------+
14736 * | |
14737 * Recognized Began
14738 * |
14739 * Changed
14740 * |
14741 * Ended/Recognized
14742 */
14743
14744 /**
14745 * @private
14746 * Recognizer
14747 * Every recognizer needs to extend from this class.
14748 * @constructor
14749 * @param {Object} options
14750 */
14751
14752
14753 var Recognizer =
14754 /*#__PURE__*/
14755 function () {
14756 function Recognizer(options) {
14757 if (options === void 0) {
14758 options = {};
14759 }
14760
14761 this.options = _extends({
14762 enable: true
14763 }, options);
14764 this.id = uniqueId();
14765 this.manager = null; // default is enable true
14766
14767 this.state = STATE_POSSIBLE;
14768 this.simultaneous = {};
14769 this.requireFail = [];
14770 }
14771 /**
14772 * @private
14773 * set options
14774 * @param {Object} options
14775 * @return {Recognizer}
14776 */
14777
14778
14779 var _proto = Recognizer.prototype;
14780
14781 _proto.set = function set(options) {
14782 assign$1(this.options, options); // also update the touchAction, in case something changed about the directions/enabled state
14783
14784 this.manager && this.manager.touchAction.update();
14785 return this;
14786 };
14787 /**
14788 * @private
14789 * recognize simultaneous with an other recognizer.
14790 * @param {Recognizer} otherRecognizer
14791 * @returns {Recognizer} this
14792 */
14793
14794
14795 _proto.recognizeWith = function recognizeWith(otherRecognizer) {
14796 if (invokeArrayArg(otherRecognizer, 'recognizeWith', this)) {
14797 return this;
14798 }
14799
14800 var simultaneous = this.simultaneous;
14801 otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this);
14802
14803 if (!simultaneous[otherRecognizer.id]) {
14804 simultaneous[otherRecognizer.id] = otherRecognizer;
14805 otherRecognizer.recognizeWith(this);
14806 }
14807
14808 return this;
14809 };
14810 /**
14811 * @private
14812 * drop the simultaneous link. it doesnt remove the link on the other recognizer.
14813 * @param {Recognizer} otherRecognizer
14814 * @returns {Recognizer} this
14815 */
14816
14817
14818 _proto.dropRecognizeWith = function dropRecognizeWith(otherRecognizer) {
14819 if (invokeArrayArg(otherRecognizer, 'dropRecognizeWith', this)) {
14820 return this;
14821 }
14822
14823 otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this);
14824 delete this.simultaneous[otherRecognizer.id];
14825 return this;
14826 };
14827 /**
14828 * @private
14829 * recognizer can only run when an other is failing
14830 * @param {Recognizer} otherRecognizer
14831 * @returns {Recognizer} this
14832 */
14833
14834
14835 _proto.requireFailure = function requireFailure(otherRecognizer) {
14836 if (invokeArrayArg(otherRecognizer, 'requireFailure', this)) {
14837 return this;
14838 }
14839
14840 var requireFail = this.requireFail;
14841 otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this);
14842
14843 if (inArray(requireFail, otherRecognizer) === -1) {
14844 requireFail.push(otherRecognizer);
14845 otherRecognizer.requireFailure(this);
14846 }
14847
14848 return this;
14849 };
14850 /**
14851 * @private
14852 * drop the requireFailure link. it does not remove the link on the other recognizer.
14853 * @param {Recognizer} otherRecognizer
14854 * @returns {Recognizer} this
14855 */
14856
14857
14858 _proto.dropRequireFailure = function dropRequireFailure(otherRecognizer) {
14859 if (invokeArrayArg(otherRecognizer, 'dropRequireFailure', this)) {
14860 return this;
14861 }
14862
14863 otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this);
14864 var index = inArray(this.requireFail, otherRecognizer);
14865
14866 if (index > -1) {
14867 this.requireFail.splice(index, 1);
14868 }
14869
14870 return this;
14871 };
14872 /**
14873 * @private
14874 * has require failures boolean
14875 * @returns {boolean}
14876 */
14877
14878
14879 _proto.hasRequireFailures = function hasRequireFailures() {
14880 return this.requireFail.length > 0;
14881 };
14882 /**
14883 * @private
14884 * if the recognizer can recognize simultaneous with an other recognizer
14885 * @param {Recognizer} otherRecognizer
14886 * @returns {Boolean}
14887 */
14888
14889
14890 _proto.canRecognizeWith = function canRecognizeWith(otherRecognizer) {
14891 return !!this.simultaneous[otherRecognizer.id];
14892 };
14893 /**
14894 * @private
14895 * You should use `tryEmit` instead of `emit` directly to check
14896 * that all the needed recognizers has failed before emitting.
14897 * @param {Object} input
14898 */
14899
14900
14901 _proto.emit = function emit(input) {
14902 var self = this;
14903 var state = this.state;
14904
14905 function emit(event) {
14906 self.manager.emit(event, input);
14907 } // 'panstart' and 'panmove'
14908
14909
14910 if (state < STATE_ENDED) {
14911 emit(self.options.event + stateStr(state));
14912 }
14913
14914 emit(self.options.event); // simple 'eventName' events
14915
14916 if (input.additionalEvent) {
14917 // additional event(panleft, panright, pinchin, pinchout...)
14918 emit(input.additionalEvent);
14919 } // panend and pancancel
14920
14921
14922 if (state >= STATE_ENDED) {
14923 emit(self.options.event + stateStr(state));
14924 }
14925 };
14926 /**
14927 * @private
14928 * Check that all the require failure recognizers has failed,
14929 * if true, it emits a gesture event,
14930 * otherwise, setup the state to FAILED.
14931 * @param {Object} input
14932 */
14933
14934
14935 _proto.tryEmit = function tryEmit(input) {
14936 if (this.canEmit()) {
14937 return this.emit(input);
14938 } // it's failing anyway
14939
14940
14941 this.state = STATE_FAILED;
14942 };
14943 /**
14944 * @private
14945 * can we emit?
14946 * @returns {boolean}
14947 */
14948
14949
14950 _proto.canEmit = function canEmit() {
14951 var i = 0;
14952
14953 while (i < this.requireFail.length) {
14954 if (!(this.requireFail[i].state & (STATE_FAILED | STATE_POSSIBLE))) {
14955 return false;
14956 }
14957
14958 i++;
14959 }
14960
14961 return true;
14962 };
14963 /**
14964 * @private
14965 * update the recognizer
14966 * @param {Object} inputData
14967 */
14968
14969
14970 _proto.recognize = function recognize(inputData) {
14971 // make a new copy of the inputData
14972 // so we can change the inputData without messing up the other recognizers
14973 var inputDataClone = assign$1({}, inputData); // is is enabled and allow recognizing?
14974
14975 if (!boolOrFn(this.options.enable, [this, inputDataClone])) {
14976 this.reset();
14977 this.state = STATE_FAILED;
14978 return;
14979 } // reset when we've reached the end
14980
14981
14982 if (this.state & (STATE_RECOGNIZED | STATE_CANCELLED | STATE_FAILED)) {
14983 this.state = STATE_POSSIBLE;
14984 }
14985
14986 this.state = this.process(inputDataClone); // the recognizer has recognized a gesture
14987 // so trigger an event
14988
14989 if (this.state & (STATE_BEGAN | STATE_CHANGED | STATE_ENDED | STATE_CANCELLED)) {
14990 this.tryEmit(inputDataClone);
14991 }
14992 };
14993 /**
14994 * @private
14995 * return the state of the recognizer
14996 * the actual recognizing happens in this method
14997 * @virtual
14998 * @param {Object} inputData
14999 * @returns {constant} STATE
15000 */
15001
15002 /* jshint ignore:start */
15003
15004
15005 _proto.process = function process(inputData) {};
15006 /* jshint ignore:end */
15007
15008 /**
15009 * @private
15010 * return the preferred touch-action
15011 * @virtual
15012 * @returns {Array}
15013 */
15014
15015
15016 _proto.getTouchAction = function getTouchAction() {};
15017 /**
15018 * @private
15019 * called when the gesture isn't allowed to recognize
15020 * like when another is being recognized or it is disabled
15021 * @virtual
15022 */
15023
15024
15025 _proto.reset = function reset() {};
15026
15027 return Recognizer;
15028 }();
15029
15030 var defaults = {
15031 /**
15032 * @private
15033 * set if DOM events are being triggered.
15034 * But this is slower and unused by simple implementations, so disabled by default.
15035 * @type {Boolean}
15036 * @default false
15037 */
15038 domEvents: false,
15039
15040 /**
15041 * @private
15042 * The value for the touchAction property/fallback.
15043 * When set to `compute` it will magically set the correct value based on the added recognizers.
15044 * @type {String}
15045 * @default compute
15046 */
15047 touchAction: TOUCH_ACTION_COMPUTE,
15048
15049 /**
15050 * @private
15051 * @type {Boolean}
15052 * @default true
15053 */
15054 enable: true,
15055
15056 /**
15057 * @private
15058 * EXPERIMENTAL FEATURE -- can be removed/changed
15059 * Change the parent input target element.
15060 * If Null, then it is being set the to main element.
15061 * @type {Null|EventTarget}
15062 * @default null
15063 */
15064 inputTarget: null,
15065
15066 /**
15067 * @private
15068 * force an input class
15069 * @type {Null|Function}
15070 * @default null
15071 */
15072 inputClass: null,
15073
15074 /**
15075 * @private
15076 * Default recognizer setup when calling `Hammer()`
15077 * When creating a new Manager these will be skipped.
15078 * @type {Array}
15079 */
15080 preset: [],
15081
15082 /**
15083 * @private
15084 * Some CSS properties can be used to improve the working of Hammer.
15085 * Add them to this method and they will be set when creating a new Manager.
15086 * @namespace
15087 */
15088 cssProps: {
15089 /**
15090 * @private
15091 * Disables text selection to improve the dragging gesture. Mainly for desktop browsers.
15092 * @type {String}
15093 * @default 'none'
15094 */
15095 userSelect: "none",
15096
15097 /**
15098 * @private
15099 * Disable the Windows Phone grippers when pressing an element.
15100 * @type {String}
15101 * @default 'none'
15102 */
15103 touchSelect: "none",
15104
15105 /**
15106 * @private
15107 * Disables the default callout shown when you touch and hold a touch target.
15108 * On iOS, when you touch and hold a touch target such as a link, Safari displays
15109 * a callout containing information about the link. This property allows you to disable that callout.
15110 * @type {String}
15111 * @default 'none'
15112 */
15113 touchCallout: "none",
15114
15115 /**
15116 * @private
15117 * Specifies whether zooming is enabled. Used by IE10>
15118 * @type {String}
15119 * @default 'none'
15120 */
15121 contentZooming: "none",
15122
15123 /**
15124 * @private
15125 * Specifies that an entire element should be draggable instead of its contents. Mainly for desktop browsers.
15126 * @type {String}
15127 * @default 'none'
15128 */
15129 userDrag: "none",
15130
15131 /**
15132 * @private
15133 * Overrides the highlight color shown when the user taps a link or a JavaScript
15134 * clickable element in iOS. This property obeys the alpha value, if specified.
15135 * @type {String}
15136 * @default 'rgba(0,0,0,0)'
15137 */
15138 tapHighlightColor: "rgba(0,0,0,0)"
15139 }
15140 };
15141 var STOP = 1;
15142 var FORCED_STOP = 2;
15143 /**
15144 * @private
15145 * add/remove the css properties as defined in manager.options.cssProps
15146 * @param {Manager} manager
15147 * @param {Boolean} add
15148 */
15149
15150 function toggleCssProps(manager, add) {
15151 var element = manager.element;
15152
15153 if (!element.style) {
15154 return;
15155 }
15156
15157 var prop;
15158 each(manager.options.cssProps, function (value, name) {
15159 prop = prefixed(element.style, name);
15160
15161 if (add) {
15162 manager.oldCssProps[prop] = element.style[prop];
15163 element.style[prop] = value;
15164 } else {
15165 element.style[prop] = manager.oldCssProps[prop] || "";
15166 }
15167 });
15168
15169 if (!add) {
15170 manager.oldCssProps = {};
15171 }
15172 }
15173 /**
15174 * @private
15175 * trigger dom event
15176 * @param {String} event
15177 * @param {Object} data
15178 */
15179
15180
15181 function triggerDomEvent(event, data) {
15182 var gestureEvent = document.createEvent("Event");
15183 gestureEvent.initEvent(event, true, true);
15184 gestureEvent.gesture = data;
15185 data.target.dispatchEvent(gestureEvent);
15186 }
15187 /**
15188 * @private
15189 * Manager
15190 * @param {HTMLElement} element
15191 * @param {Object} [options]
15192 * @constructor
15193 */
15194
15195
15196 var Manager =
15197 /*#__PURE__*/
15198 function () {
15199 function Manager(element, options) {
15200 var _this = this;
15201
15202 this.options = assign$1({}, defaults, options || {});
15203 this.options.inputTarget = this.options.inputTarget || element;
15204 this.handlers = {};
15205 this.session = {};
15206 this.recognizers = [];
15207 this.oldCssProps = {};
15208 this.element = element;
15209 this.input = createInputInstance(this);
15210 this.touchAction = new TouchAction(this, this.options.touchAction);
15211 toggleCssProps(this, true);
15212 each(this.options.recognizers, function (item) {
15213 var recognizer = _this.add(new item[0](item[1]));
15214
15215 item[2] && recognizer.recognizeWith(item[2]);
15216 item[3] && recognizer.requireFailure(item[3]);
15217 }, this);
15218 }
15219 /**
15220 * @private
15221 * set options
15222 * @param {Object} options
15223 * @returns {Manager}
15224 */
15225
15226
15227 var _proto = Manager.prototype;
15228
15229 _proto.set = function set(options) {
15230 assign$1(this.options, options); // Options that need a little more setup
15231
15232 if (options.touchAction) {
15233 this.touchAction.update();
15234 }
15235
15236 if (options.inputTarget) {
15237 // Clean up existing event listeners and reinitialize
15238 this.input.destroy();
15239 this.input.target = options.inputTarget;
15240 this.input.init();
15241 }
15242
15243 return this;
15244 };
15245 /**
15246 * @private
15247 * stop recognizing for this session.
15248 * This session will be discarded, when a new [input]start event is fired.
15249 * When forced, the recognizer cycle is stopped immediately.
15250 * @param {Boolean} [force]
15251 */
15252
15253
15254 _proto.stop = function stop(force) {
15255 this.session.stopped = force ? FORCED_STOP : STOP;
15256 };
15257 /**
15258 * @private
15259 * run the recognizers!
15260 * called by the inputHandler function on every movement of the pointers (touches)
15261 * it walks through all the recognizers and tries to detect the gesture that is being made
15262 * @param {Object} inputData
15263 */
15264
15265
15266 _proto.recognize = function recognize(inputData) {
15267 var session = this.session;
15268
15269 if (session.stopped) {
15270 return;
15271 } // run the touch-action polyfill
15272
15273
15274 this.touchAction.preventDefaults(inputData);
15275 var recognizer;
15276 var recognizers = this.recognizers; // this holds the recognizer that is being recognized.
15277 // so the recognizer's state needs to be BEGAN, CHANGED, ENDED or RECOGNIZED
15278 // if no recognizer is detecting a thing, it is set to `null`
15279
15280 var curRecognizer = session.curRecognizer; // reset when the last recognizer is recognized
15281 // or when we're in a new session
15282
15283 if (!curRecognizer || curRecognizer && curRecognizer.state & STATE_RECOGNIZED) {
15284 session.curRecognizer = null;
15285 curRecognizer = null;
15286 }
15287
15288 var i = 0;
15289
15290 while (i < recognizers.length) {
15291 recognizer = recognizers[i]; // find out if we are allowed try to recognize the input for this one.
15292 // 1. allow if the session is NOT forced stopped (see the .stop() method)
15293 // 2. allow if we still haven't recognized a gesture in this session, or the this recognizer is the one
15294 // that is being recognized.
15295 // 3. allow if the recognizer is allowed to run simultaneous with the current recognized recognizer.
15296 // this can be setup with the `recognizeWith()` method on the recognizer.
15297
15298 if (session.stopped !== FORCED_STOP && ( // 1
15299 !curRecognizer || recognizer === curRecognizer || // 2
15300 recognizer.canRecognizeWith(curRecognizer))) {
15301 // 3
15302 recognizer.recognize(inputData);
15303 } else {
15304 recognizer.reset();
15305 } // if the recognizer has been recognizing the input as a valid gesture, we want to store this one as the
15306 // current active recognizer. but only if we don't already have an active recognizer
15307
15308
15309 if (!curRecognizer && recognizer.state & (STATE_BEGAN | STATE_CHANGED | STATE_ENDED)) {
15310 session.curRecognizer = recognizer;
15311 curRecognizer = recognizer;
15312 }
15313
15314 i++;
15315 }
15316 };
15317 /**
15318 * @private
15319 * get a recognizer by its event name.
15320 * @param {Recognizer|String} recognizer
15321 * @returns {Recognizer|Null}
15322 */
15323
15324
15325 _proto.get = function get(recognizer) {
15326 if (recognizer instanceof Recognizer) {
15327 return recognizer;
15328 }
15329
15330 var recognizers = this.recognizers;
15331
15332 for (var i = 0; i < recognizers.length; i++) {
15333 if (recognizers[i].options.event === recognizer) {
15334 return recognizers[i];
15335 }
15336 }
15337
15338 return null;
15339 };
15340 /**
15341 * @private add a recognizer to the manager
15342 * existing recognizers with the same event name will be removed
15343 * @param {Recognizer} recognizer
15344 * @returns {Recognizer|Manager}
15345 */
15346
15347
15348 _proto.add = function add(recognizer) {
15349 if (invokeArrayArg(recognizer, "add", this)) {
15350 return this;
15351 } // remove existing
15352
15353
15354 var existing = this.get(recognizer.options.event);
15355
15356 if (existing) {
15357 this.remove(existing);
15358 }
15359
15360 this.recognizers.push(recognizer);
15361 recognizer.manager = this;
15362 this.touchAction.update();
15363 return recognizer;
15364 };
15365 /**
15366 * @private
15367 * remove a recognizer by name or instance
15368 * @param {Recognizer|String} recognizer
15369 * @returns {Manager}
15370 */
15371
15372
15373 _proto.remove = function remove(recognizer) {
15374 if (invokeArrayArg(recognizer, "remove", this)) {
15375 return this;
15376 }
15377
15378 var targetRecognizer = this.get(recognizer); // let's make sure this recognizer exists
15379
15380 if (recognizer) {
15381 var recognizers = this.recognizers;
15382 var index = inArray(recognizers, targetRecognizer);
15383
15384 if (index !== -1) {
15385 recognizers.splice(index, 1);
15386 this.touchAction.update();
15387 }
15388 }
15389
15390 return this;
15391 };
15392 /**
15393 * @private
15394 * bind event
15395 * @param {String} events
15396 * @param {Function} handler
15397 * @returns {EventEmitter} this
15398 */
15399
15400
15401 _proto.on = function on(events, handler) {
15402 if (events === undefined || handler === undefined) {
15403 return this;
15404 }
15405
15406 var handlers = this.handlers;
15407 each(splitStr(events), function (event) {
15408 handlers[event] = handlers[event] || [];
15409 handlers[event].push(handler);
15410 });
15411 return this;
15412 };
15413 /**
15414 * @private unbind event, leave emit blank to remove all handlers
15415 * @param {String} events
15416 * @param {Function} [handler]
15417 * @returns {EventEmitter} this
15418 */
15419
15420
15421 _proto.off = function off(events, handler) {
15422 if (events === undefined) {
15423 return this;
15424 }
15425
15426 var handlers = this.handlers;
15427 each(splitStr(events), function (event) {
15428 if (!handler) {
15429 delete handlers[event];
15430 } else {
15431 handlers[event] && handlers[event].splice(inArray(handlers[event], handler), 1);
15432 }
15433 });
15434 return this;
15435 };
15436 /**
15437 * @private emit event to the listeners
15438 * @param {String} event
15439 * @param {Object} data
15440 */
15441
15442
15443 _proto.emit = function emit(event, data) {
15444 // we also want to trigger dom events
15445 if (this.options.domEvents) {
15446 triggerDomEvent(event, data);
15447 } // no handlers, so skip it all
15448
15449
15450 var handlers = this.handlers[event] && this.handlers[event].slice();
15451
15452 if (!handlers || !handlers.length) {
15453 return;
15454 }
15455
15456 data.type = event;
15457
15458 data.preventDefault = function () {
15459 data.srcEvent.preventDefault();
15460 };
15461
15462 var i = 0;
15463
15464 while (i < handlers.length) {
15465 handlers[i](data);
15466 i++;
15467 }
15468 };
15469 /**
15470 * @private
15471 * destroy the manager and unbinds all events
15472 * it doesn't unbind dom events, that is the user own responsibility
15473 */
15474
15475
15476 _proto.destroy = function destroy() {
15477 this.element && toggleCssProps(this, false);
15478 this.handlers = {};
15479 this.session = {};
15480 this.input.destroy();
15481 this.element = null;
15482 };
15483
15484 return Manager;
15485 }();
15486
15487 var SINGLE_TOUCH_INPUT_MAP = {
15488 touchstart: INPUT_START,
15489 touchmove: INPUT_MOVE,
15490 touchend: INPUT_END,
15491 touchcancel: INPUT_CANCEL
15492 };
15493 var SINGLE_TOUCH_TARGET_EVENTS = 'touchstart';
15494 var SINGLE_TOUCH_WINDOW_EVENTS = 'touchstart touchmove touchend touchcancel';
15495 /**
15496 * @private
15497 * Touch events input
15498 * @constructor
15499 * @extends Input
15500 */
15501
15502 var SingleTouchInput =
15503 /*#__PURE__*/
15504 function (_Input) {
15505 _inheritsLoose(SingleTouchInput, _Input);
15506
15507 function SingleTouchInput() {
15508 var _this;
15509
15510 var proto = SingleTouchInput.prototype;
15511 proto.evTarget = SINGLE_TOUCH_TARGET_EVENTS;
15512 proto.evWin = SINGLE_TOUCH_WINDOW_EVENTS;
15513 _this = _Input.apply(this, arguments) || this;
15514 _this.started = false;
15515 return _this;
15516 }
15517
15518 var _proto = SingleTouchInput.prototype;
15519
15520 _proto.handler = function handler(ev) {
15521 var type = SINGLE_TOUCH_INPUT_MAP[ev.type]; // should we handle the touch events?
15522
15523 if (type === INPUT_START) {
15524 this.started = true;
15525 }
15526
15527 if (!this.started) {
15528 return;
15529 }
15530
15531 var touches = normalizeSingleTouches.call(this, ev, type); // when done, reset the started state
15532
15533 if (type & (INPUT_END | INPUT_CANCEL) && touches[0].length - touches[1].length === 0) {
15534 this.started = false;
15535 }
15536
15537 this.callback(this.manager, type, {
15538 pointers: touches[0],
15539 changedPointers: touches[1],
15540 pointerType: INPUT_TYPE_TOUCH,
15541 srcEvent: ev
15542 });
15543 };
15544
15545 return SingleTouchInput;
15546 }(Input);
15547
15548 function normalizeSingleTouches(ev, type) {
15549 var all = toArray$1(ev.touches);
15550 var changed = toArray$1(ev.changedTouches);
15551
15552 if (type & (INPUT_END | INPUT_CANCEL)) {
15553 all = uniqueArray(all.concat(changed), 'identifier', true);
15554 }
15555
15556 return [all, changed];
15557 }
15558 /**
15559 * @private
15560 * This recognizer is just used as a base for the simple attribute recognizers.
15561 * @constructor
15562 * @extends Recognizer
15563 */
15564
15565
15566 var AttrRecognizer =
15567 /*#__PURE__*/
15568 function (_Recognizer) {
15569 _inheritsLoose(AttrRecognizer, _Recognizer);
15570
15571 function AttrRecognizer(options) {
15572 if (options === void 0) {
15573 options = {};
15574 }
15575
15576 return _Recognizer.call(this, _extends({
15577 pointers: 1
15578 }, options)) || this;
15579 }
15580 /**
15581 * @private
15582 * Used to check if it the recognizer receives valid input, like input.distance > 10.
15583 * @memberof AttrRecognizer
15584 * @param {Object} input
15585 * @returns {Boolean} recognized
15586 */
15587
15588
15589 var _proto = AttrRecognizer.prototype;
15590
15591 _proto.attrTest = function attrTest(input) {
15592 var optionPointers = this.options.pointers;
15593 return optionPointers === 0 || input.pointers.length === optionPointers;
15594 };
15595 /**
15596 * @private
15597 * Process the input and return the state for the recognizer
15598 * @memberof AttrRecognizer
15599 * @param {Object} input
15600 * @returns {*} State
15601 */
15602
15603
15604 _proto.process = function process(input) {
15605 var state = this.state;
15606 var eventType = input.eventType;
15607 var isRecognized = state & (STATE_BEGAN | STATE_CHANGED);
15608 var isValid = this.attrTest(input); // on cancel input and we've recognized before, return STATE_CANCELLED
15609
15610 if (isRecognized && (eventType & INPUT_CANCEL || !isValid)) {
15611 return state | STATE_CANCELLED;
15612 } else if (isRecognized || isValid) {
15613 if (eventType & INPUT_END) {
15614 return state | STATE_ENDED;
15615 } else if (!(state & STATE_BEGAN)) {
15616 return STATE_BEGAN;
15617 }
15618
15619 return state | STATE_CHANGED;
15620 }
15621
15622 return STATE_FAILED;
15623 };
15624
15625 return AttrRecognizer;
15626 }(Recognizer);
15627 /**
15628 * @private
15629 * A tap is recognized when the pointer is doing a small tap/click. Multiple taps are recognized if they occur
15630 * between the given interval and position. The delay option can be used to recognize multi-taps without firing
15631 * a single tap.
15632 *
15633 * The eventData from the emitted event contains the property `tapCount`, which contains the amount of
15634 * multi-taps being recognized.
15635 * @constructor
15636 * @extends Recognizer
15637 */
15638
15639
15640 var TapRecognizer =
15641 /*#__PURE__*/
15642 function (_Recognizer) {
15643 _inheritsLoose(TapRecognizer, _Recognizer);
15644
15645 function TapRecognizer(options) {
15646 var _this;
15647
15648 if (options === void 0) {
15649 options = {};
15650 }
15651
15652 _this = _Recognizer.call(this, _extends({
15653 event: 'tap',
15654 pointers: 1,
15655 taps: 1,
15656 interval: 300,
15657 // max time between the multi-tap taps
15658 time: 250,
15659 // max time of the pointer to be down (like finger on the screen)
15660 threshold: 9,
15661 // a minimal movement is ok, but keep it low
15662 posThreshold: 10
15663 }, options)) || this; // previous time and center,
15664 // used for tap counting
15665
15666 _this.pTime = false;
15667 _this.pCenter = false;
15668 _this._timer = null;
15669 _this._input = null;
15670 _this.count = 0;
15671 return _this;
15672 }
15673
15674 var _proto = TapRecognizer.prototype;
15675
15676 _proto.getTouchAction = function getTouchAction() {
15677 return [TOUCH_ACTION_MANIPULATION];
15678 };
15679
15680 _proto.process = function process(input) {
15681 var _this2 = this;
15682
15683 var options = this.options;
15684 var validPointers = input.pointers.length === options.pointers;
15685 var validMovement = input.distance < options.threshold;
15686 var validTouchTime = input.deltaTime < options.time;
15687 this.reset();
15688
15689 if (input.eventType & INPUT_START && this.count === 0) {
15690 return this.failTimeout();
15691 } // we only allow little movement
15692 // and we've reached an end event, so a tap is possible
15693
15694
15695 if (validMovement && validTouchTime && validPointers) {
15696 if (input.eventType !== INPUT_END) {
15697 return this.failTimeout();
15698 }
15699
15700 var validInterval = this.pTime ? input.timeStamp - this.pTime < options.interval : true;
15701 var validMultiTap = !this.pCenter || getDistance(this.pCenter, input.center) < options.posThreshold;
15702 this.pTime = input.timeStamp;
15703 this.pCenter = input.center;
15704
15705 if (!validMultiTap || !validInterval) {
15706 this.count = 1;
15707 } else {
15708 this.count += 1;
15709 }
15710
15711 this._input = input; // if tap count matches we have recognized it,
15712 // else it has began recognizing...
15713
15714 var tapCount = this.count % options.taps;
15715
15716 if (tapCount === 0) {
15717 // no failing requirements, immediately trigger the tap event
15718 // or wait as long as the multitap interval to trigger
15719 if (!this.hasRequireFailures()) {
15720 return STATE_RECOGNIZED;
15721 } else {
15722 this._timer = setTimeout(function () {
15723 _this2.state = STATE_RECOGNIZED;
15724
15725 _this2.tryEmit();
15726 }, options.interval);
15727 return STATE_BEGAN;
15728 }
15729 }
15730 }
15731
15732 return STATE_FAILED;
15733 };
15734
15735 _proto.failTimeout = function failTimeout() {
15736 var _this3 = this;
15737
15738 this._timer = setTimeout(function () {
15739 _this3.state = STATE_FAILED;
15740 }, this.options.interval);
15741 return STATE_FAILED;
15742 };
15743
15744 _proto.reset = function reset() {
15745 clearTimeout(this._timer);
15746 };
15747
15748 _proto.emit = function emit() {
15749 if (this.state === STATE_RECOGNIZED) {
15750 this._input.tapCount = this.count;
15751 this.manager.emit(this.options.event, this._input);
15752 }
15753 };
15754
15755 return TapRecognizer;
15756 }(Recognizer);
15757 /**
15758 * @private
15759 * direction cons to string
15760 * @param {constant} direction
15761 * @returns {String}
15762 */
15763
15764
15765 function directionStr(direction) {
15766 if (direction === DIRECTION_DOWN) {
15767 return 'down';
15768 } else if (direction === DIRECTION_UP) {
15769 return 'up';
15770 } else if (direction === DIRECTION_LEFT) {
15771 return 'left';
15772 } else if (direction === DIRECTION_RIGHT) {
15773 return 'right';
15774 }
15775
15776 return '';
15777 }
15778 /**
15779 * @private
15780 * Pan
15781 * Recognized when the pointer is down and moved in the allowed direction.
15782 * @constructor
15783 * @extends AttrRecognizer
15784 */
15785
15786
15787 var PanRecognizer =
15788 /*#__PURE__*/
15789 function (_AttrRecognizer) {
15790 _inheritsLoose(PanRecognizer, _AttrRecognizer);
15791
15792 function PanRecognizer(options) {
15793 var _this;
15794
15795 if (options === void 0) {
15796 options = {};
15797 }
15798
15799 _this = _AttrRecognizer.call(this, _extends({
15800 event: 'pan',
15801 threshold: 10,
15802 pointers: 1,
15803 direction: DIRECTION_ALL
15804 }, options)) || this;
15805 _this.pX = null;
15806 _this.pY = null;
15807 return _this;
15808 }
15809
15810 var _proto = PanRecognizer.prototype;
15811
15812 _proto.getTouchAction = function getTouchAction() {
15813 var direction = this.options.direction;
15814 var actions = [];
15815
15816 if (direction & DIRECTION_HORIZONTAL) {
15817 actions.push(TOUCH_ACTION_PAN_Y);
15818 }
15819
15820 if (direction & DIRECTION_VERTICAL) {
15821 actions.push(TOUCH_ACTION_PAN_X);
15822 }
15823
15824 return actions;
15825 };
15826
15827 _proto.directionTest = function directionTest(input) {
15828 var options = this.options;
15829 var hasMoved = true;
15830 var distance = input.distance;
15831 var direction = input.direction;
15832 var x = input.deltaX;
15833 var y = input.deltaY; // lock to axis?
15834
15835 if (!(direction & options.direction)) {
15836 if (options.direction & DIRECTION_HORIZONTAL) {
15837 direction = x === 0 ? DIRECTION_NONE : x < 0 ? DIRECTION_LEFT : DIRECTION_RIGHT;
15838 hasMoved = x !== this.pX;
15839 distance = Math.abs(input.deltaX);
15840 } else {
15841 direction = y === 0 ? DIRECTION_NONE : y < 0 ? DIRECTION_UP : DIRECTION_DOWN;
15842 hasMoved = y !== this.pY;
15843 distance = Math.abs(input.deltaY);
15844 }
15845 }
15846
15847 input.direction = direction;
15848 return hasMoved && distance > options.threshold && direction & options.direction;
15849 };
15850
15851 _proto.attrTest = function attrTest(input) {
15852 return AttrRecognizer.prototype.attrTest.call(this, input) && ( // replace with a super call
15853 this.state & STATE_BEGAN || !(this.state & STATE_BEGAN) && this.directionTest(input));
15854 };
15855
15856 _proto.emit = function emit(input) {
15857 this.pX = input.deltaX;
15858 this.pY = input.deltaY;
15859 var direction = directionStr(input.direction);
15860
15861 if (direction) {
15862 input.additionalEvent = this.options.event + direction;
15863 }
15864
15865 _AttrRecognizer.prototype.emit.call(this, input);
15866 };
15867
15868 return PanRecognizer;
15869 }(AttrRecognizer);
15870 /**
15871 * @private
15872 * Swipe
15873 * Recognized when the pointer is moving fast (velocity), with enough distance in the allowed direction.
15874 * @constructor
15875 * @extends AttrRecognizer
15876 */
15877
15878
15879 var SwipeRecognizer =
15880 /*#__PURE__*/
15881 function (_AttrRecognizer) {
15882 _inheritsLoose(SwipeRecognizer, _AttrRecognizer);
15883
15884 function SwipeRecognizer(options) {
15885 if (options === void 0) {
15886 options = {};
15887 }
15888
15889 return _AttrRecognizer.call(this, _extends({
15890 event: 'swipe',
15891 threshold: 10,
15892 velocity: 0.3,
15893 direction: DIRECTION_HORIZONTAL | DIRECTION_VERTICAL,
15894 pointers: 1
15895 }, options)) || this;
15896 }
15897
15898 var _proto = SwipeRecognizer.prototype;
15899
15900 _proto.getTouchAction = function getTouchAction() {
15901 return PanRecognizer.prototype.getTouchAction.call(this);
15902 };
15903
15904 _proto.attrTest = function attrTest(input) {
15905 var direction = this.options.direction;
15906 var velocity;
15907
15908 if (direction & (DIRECTION_HORIZONTAL | DIRECTION_VERTICAL)) {
15909 velocity = input.overallVelocity;
15910 } else if (direction & DIRECTION_HORIZONTAL) {
15911 velocity = input.overallVelocityX;
15912 } else if (direction & DIRECTION_VERTICAL) {
15913 velocity = input.overallVelocityY;
15914 }
15915
15916 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;
15917 };
15918
15919 _proto.emit = function emit(input) {
15920 var direction = directionStr(input.offsetDirection);
15921
15922 if (direction) {
15923 this.manager.emit(this.options.event + direction, input);
15924 }
15925
15926 this.manager.emit(this.options.event, input);
15927 };
15928
15929 return SwipeRecognizer;
15930 }(AttrRecognizer);
15931 /**
15932 * @private
15933 * Pinch
15934 * Recognized when two or more pointers are moving toward (zoom-in) or away from each other (zoom-out).
15935 * @constructor
15936 * @extends AttrRecognizer
15937 */
15938
15939
15940 var PinchRecognizer =
15941 /*#__PURE__*/
15942 function (_AttrRecognizer) {
15943 _inheritsLoose(PinchRecognizer, _AttrRecognizer);
15944
15945 function PinchRecognizer(options) {
15946 if (options === void 0) {
15947 options = {};
15948 }
15949
15950 return _AttrRecognizer.call(this, _extends({
15951 event: 'pinch',
15952 threshold: 0,
15953 pointers: 2
15954 }, options)) || this;
15955 }
15956
15957 var _proto = PinchRecognizer.prototype;
15958
15959 _proto.getTouchAction = function getTouchAction() {
15960 return [TOUCH_ACTION_NONE];
15961 };
15962
15963 _proto.attrTest = function attrTest(input) {
15964 return _AttrRecognizer.prototype.attrTest.call(this, input) && (Math.abs(input.scale - 1) > this.options.threshold || this.state & STATE_BEGAN);
15965 };
15966
15967 _proto.emit = function emit(input) {
15968 if (input.scale !== 1) {
15969 var inOut = input.scale < 1 ? 'in' : 'out';
15970 input.additionalEvent = this.options.event + inOut;
15971 }
15972
15973 _AttrRecognizer.prototype.emit.call(this, input);
15974 };
15975
15976 return PinchRecognizer;
15977 }(AttrRecognizer);
15978 /**
15979 * @private
15980 * Rotate
15981 * Recognized when two or more pointer are moving in a circular motion.
15982 * @constructor
15983 * @extends AttrRecognizer
15984 */
15985
15986
15987 var RotateRecognizer =
15988 /*#__PURE__*/
15989 function (_AttrRecognizer) {
15990 _inheritsLoose(RotateRecognizer, _AttrRecognizer);
15991
15992 function RotateRecognizer(options) {
15993 if (options === void 0) {
15994 options = {};
15995 }
15996
15997 return _AttrRecognizer.call(this, _extends({
15998 event: 'rotate',
15999 threshold: 0,
16000 pointers: 2
16001 }, options)) || this;
16002 }
16003
16004 var _proto = RotateRecognizer.prototype;
16005
16006 _proto.getTouchAction = function getTouchAction() {
16007 return [TOUCH_ACTION_NONE];
16008 };
16009
16010 _proto.attrTest = function attrTest(input) {
16011 return _AttrRecognizer.prototype.attrTest.call(this, input) && (Math.abs(input.rotation) > this.options.threshold || this.state & STATE_BEGAN);
16012 };
16013
16014 return RotateRecognizer;
16015 }(AttrRecognizer);
16016 /**
16017 * @private
16018 * Press
16019 * Recognized when the pointer is down for x ms without any movement.
16020 * @constructor
16021 * @extends Recognizer
16022 */
16023
16024
16025 var PressRecognizer =
16026 /*#__PURE__*/
16027 function (_Recognizer) {
16028 _inheritsLoose(PressRecognizer, _Recognizer);
16029
16030 function PressRecognizer(options) {
16031 var _this;
16032
16033 if (options === void 0) {
16034 options = {};
16035 }
16036
16037 _this = _Recognizer.call(this, _extends({
16038 event: 'press',
16039 pointers: 1,
16040 time: 251,
16041 // minimal time of the pointer to be pressed
16042 threshold: 9
16043 }, options)) || this;
16044 _this._timer = null;
16045 _this._input = null;
16046 return _this;
16047 }
16048
16049 var _proto = PressRecognizer.prototype;
16050
16051 _proto.getTouchAction = function getTouchAction() {
16052 return [TOUCH_ACTION_AUTO];
16053 };
16054
16055 _proto.process = function process(input) {
16056 var _this2 = this;
16057
16058 var options = this.options;
16059 var validPointers = input.pointers.length === options.pointers;
16060 var validMovement = input.distance < options.threshold;
16061 var validTime = input.deltaTime > options.time;
16062 this._input = input; // we only allow little movement
16063 // and we've reached an end event, so a tap is possible
16064
16065 if (!validMovement || !validPointers || input.eventType & (INPUT_END | INPUT_CANCEL) && !validTime) {
16066 this.reset();
16067 } else if (input.eventType & INPUT_START) {
16068 this.reset();
16069 this._timer = setTimeout(function () {
16070 _this2.state = STATE_RECOGNIZED;
16071
16072 _this2.tryEmit();
16073 }, options.time);
16074 } else if (input.eventType & INPUT_END) {
16075 return STATE_RECOGNIZED;
16076 }
16077
16078 return STATE_FAILED;
16079 };
16080
16081 _proto.reset = function reset() {
16082 clearTimeout(this._timer);
16083 };
16084
16085 _proto.emit = function emit(input) {
16086 if (this.state !== STATE_RECOGNIZED) {
16087 return;
16088 }
16089
16090 if (input && input.eventType & INPUT_END) {
16091 this.manager.emit(this.options.event + "up", input);
16092 } else {
16093 this._input.timeStamp = now();
16094 this.manager.emit(this.options.event, this._input);
16095 }
16096 };
16097
16098 return PressRecognizer;
16099 }(Recognizer);
16100 /**
16101 * @private
16102 * wrap a method with a deprecation warning and stack trace
16103 * @param {Function} method
16104 * @param {String} name
16105 * @param {String} message
16106 * @returns {Function} A new function wrapping the supplied method.
16107 */
16108
16109
16110 function deprecate(method, name, message) {
16111 var deprecationMessage = "DEPRECATED METHOD: " + name + "\n" + message + " AT \n";
16112 return function () {
16113 var e = new Error('get-stack-trace');
16114 var stack = e && e.stack ? e.stack.replace(/^[^\(]+?[\n$]/gm, '').replace(/^\s+at\s+/gm, '').replace(/^Object.<anonymous>\s*\(/gm, '{anonymous}()@') : 'Unknown Stack Trace';
16115 var log = window.console && (window.console.warn || window.console.log);
16116
16117 if (log) {
16118 log.call(window.console, deprecationMessage, stack);
16119 }
16120
16121 return method.apply(this, arguments);
16122 };
16123 }
16124 /**
16125 * @private
16126 * extend object.
16127 * means that properties in dest will be overwritten by the ones in src.
16128 * @param {Object} dest
16129 * @param {Object} src
16130 * @param {Boolean} [merge=false]
16131 * @returns {Object} dest
16132 */
16133
16134
16135 var extend$1 = deprecate(function (dest, src, merge) {
16136 var keys = Object.keys(src);
16137 var i = 0;
16138
16139 while (i < keys.length) {
16140 if (!merge || merge && dest[keys[i]] === undefined) {
16141 dest[keys[i]] = src[keys[i]];
16142 }
16143
16144 i++;
16145 }
16146
16147 return dest;
16148 }, 'extend', 'Use `assign`.');
16149 /**
16150 * @private
16151 * merge the values from src in the dest.
16152 * means that properties that exist in dest will not be overwritten by src
16153 * @param {Object} dest
16154 * @param {Object} src
16155 * @returns {Object} dest
16156 */
16157
16158 var merge$1 = deprecate(function (dest, src) {
16159 return extend$1(dest, src, true);
16160 }, 'merge', 'Use `assign`.');
16161 /**
16162 * @private
16163 * simple class inheritance
16164 * @param {Function} child
16165 * @param {Function} base
16166 * @param {Object} [properties]
16167 */
16168
16169 function inherit(child, base, properties) {
16170 var baseP = base.prototype;
16171 var childP;
16172 childP = child.prototype = Object.create(baseP);
16173 childP.constructor = child;
16174 childP._super = baseP;
16175
16176 if (properties) {
16177 assign$1(childP, properties);
16178 }
16179 }
16180 /**
16181 * @private
16182 * simple function bind
16183 * @param {Function} fn
16184 * @param {Object} context
16185 * @returns {Function}
16186 */
16187
16188
16189 function bindFn(fn, context) {
16190 return function boundFn() {
16191 return fn.apply(context, arguments);
16192 };
16193 }
16194 /**
16195 * @private
16196 * Simple way to create a manager with a default set of recognizers.
16197 * @param {HTMLElement} element
16198 * @param {Object} [options]
16199 * @constructor
16200 */
16201
16202
16203 var Hammer =
16204 /*#__PURE__*/
16205 function () {
16206 var Hammer =
16207 /**
16208 * @private
16209 * @const {string}
16210 */
16211 function Hammer(element, options) {
16212 if (options === void 0) {
16213 options = {};
16214 }
16215
16216 return new Manager(element, _extends({
16217 recognizers: [// RecognizerClass, options, [recognizeWith, ...], [requireFailure, ...]
16218 [RotateRecognizer, {
16219 enable: false
16220 }], [PinchRecognizer, {
16221 enable: false
16222 }, ['rotate']], [SwipeRecognizer, {
16223 direction: DIRECTION_HORIZONTAL
16224 }], [PanRecognizer, {
16225 direction: DIRECTION_HORIZONTAL
16226 }, ['swipe']], [TapRecognizer], [TapRecognizer, {
16227 event: 'doubletap',
16228 taps: 2
16229 }, ['tap']], [PressRecognizer]]
16230 }, options));
16231 };
16232
16233 Hammer.VERSION = "2.0.15";
16234 Hammer.DIRECTION_ALL = DIRECTION_ALL;
16235 Hammer.DIRECTION_DOWN = DIRECTION_DOWN;
16236 Hammer.DIRECTION_LEFT = DIRECTION_LEFT;
16237 Hammer.DIRECTION_RIGHT = DIRECTION_RIGHT;
16238 Hammer.DIRECTION_UP = DIRECTION_UP;
16239 Hammer.DIRECTION_HORIZONTAL = DIRECTION_HORIZONTAL;
16240 Hammer.DIRECTION_VERTICAL = DIRECTION_VERTICAL;
16241 Hammer.DIRECTION_NONE = DIRECTION_NONE;
16242 Hammer.DIRECTION_DOWN = DIRECTION_DOWN;
16243 Hammer.INPUT_START = INPUT_START;
16244 Hammer.INPUT_MOVE = INPUT_MOVE;
16245 Hammer.INPUT_END = INPUT_END;
16246 Hammer.INPUT_CANCEL = INPUT_CANCEL;
16247 Hammer.STATE_POSSIBLE = STATE_POSSIBLE;
16248 Hammer.STATE_BEGAN = STATE_BEGAN;
16249 Hammer.STATE_CHANGED = STATE_CHANGED;
16250 Hammer.STATE_ENDED = STATE_ENDED;
16251 Hammer.STATE_RECOGNIZED = STATE_RECOGNIZED;
16252 Hammer.STATE_CANCELLED = STATE_CANCELLED;
16253 Hammer.STATE_FAILED = STATE_FAILED;
16254 Hammer.Manager = Manager;
16255 Hammer.Input = Input;
16256 Hammer.TouchAction = TouchAction;
16257 Hammer.TouchInput = TouchInput;
16258 Hammer.MouseInput = MouseInput;
16259 Hammer.PointerEventInput = PointerEventInput;
16260 Hammer.TouchMouseInput = TouchMouseInput;
16261 Hammer.SingleTouchInput = SingleTouchInput;
16262 Hammer.Recognizer = Recognizer;
16263 Hammer.AttrRecognizer = AttrRecognizer;
16264 Hammer.Tap = TapRecognizer;
16265 Hammer.Pan = PanRecognizer;
16266 Hammer.Swipe = SwipeRecognizer;
16267 Hammer.Pinch = PinchRecognizer;
16268 Hammer.Rotate = RotateRecognizer;
16269 Hammer.Press = PressRecognizer;
16270 Hammer.on = addEventListeners;
16271 Hammer.off = removeEventListeners;
16272 Hammer.each = each;
16273 Hammer.merge = merge$1;
16274 Hammer.extend = extend$1;
16275 Hammer.bindFn = bindFn;
16276 Hammer.assign = assign$1;
16277 Hammer.inherit = inherit;
16278 Hammer.bindFn = bindFn;
16279 Hammer.prefixed = prefixed;
16280 Hammer.toArray = toArray$1;
16281 Hammer.inArray = inArray;
16282 Hammer.uniqueArray = uniqueArray;
16283 Hammer.splitStr = splitStr;
16284 Hammer.boolOrFn = boolOrFn;
16285 Hammer.hasParent = hasParent$1;
16286 Hammer.addEventListeners = addEventListeners;
16287 Hammer.removeEventListeners = removeEventListeners;
16288 Hammer.defaults = defaults;
16289 return Hammer;
16290 }();
16291
16292 var hammer = createCommonjsModule(function (module) {
16293 /**
16294 * Setup a mock hammer.js object, for unit testing.
16295 *
16296 * Inspiration: https://github.com/uber/deck.gl/pull/658
16297 *
16298 * @returns {{on: noop, off: noop, destroy: noop, emit: noop, get: get}}
16299 */
16300 function hammerMock() {
16301 var noop = function noop() {};
16302
16303 return {
16304 on: noop,
16305 off: noop,
16306 destroy: noop,
16307 emit: noop,
16308 get: function get(m) {
16309 //eslint-disable-line no-unused-vars
16310 return {
16311 set: noop
16312 };
16313 }
16314 };
16315 }
16316
16317 if (typeof window !== 'undefined') {
16318 var Hammer$1 = window['Hammer'] || Hammer;
16319 module.exports = Hammer$1;
16320 } else {
16321 module.exports = function () {
16322 // hammer.js is only available in a browser, not in node.js. Replacing it with a mock object.
16323 return hammerMock();
16324 };
16325 }
16326 });
16327
16328 var hammer$1 = /*#__PURE__*/Object.freeze({
16329 __proto__: null,
16330 'default': hammer,
16331 __moduleExports: hammer
16332 });
16333
16334 getCjsExportFromNamespace(Activator);
16335
16336 /**
16337 * Turn an element into an clickToUse element.
16338 * When not active, the element has a transparent overlay. When the overlay is
16339 * clicked, the mode is changed to active.
16340 * When active, the element is displayed with a blue border around it, and
16341 * the interactive contents of the element can be used. When clicked outside
16342 * the element, the elements mode is changed to inactive.
16343 * @param {Element} container
16344 * @constructor Activator
16345 */
16346
16347 function Activator$1(container) {
16348 var _this = this;
16349
16350 this.active = false;
16351 this.dom = {
16352 container: container
16353 };
16354 this.dom.overlay = document.createElement('div');
16355 this.dom.overlay.className = 'vis-overlay';
16356 this.dom.container.appendChild(this.dom.overlay);
16357 this.hammer = hammer(this.dom.overlay);
16358 this.hammer.on('tap', this._onTapOverlay.bind(this)); // block all touch events (except tap)
16359
16360 var events = ['tap', 'doubletap', 'press', 'pinch', 'pan', 'panstart', 'panmove', 'panend'];
16361 events.forEach(function (event) {
16362 _this.hammer.on(event, function (event) {
16363 event.srcEvent.stopPropagation();
16364 });
16365 }); // attach a click event to the window, in order to deactivate when clicking outside the timeline
16366
16367 if (document && document.body) {
16368 this.onClick = function (event) {
16369 if (!_hasParent(event.target, container)) {
16370 _this.deactivate();
16371 }
16372 };
16373
16374 document.body.addEventListener('click', this.onClick);
16375 }
16376
16377 if (this.keycharm !== undefined) {
16378 this.keycharm.destroy();
16379 }
16380
16381 this.keycharm = keycharm(); // keycharm listener only bounded when active)
16382
16383 this.escListener = this.deactivate.bind(this);
16384 } // turn into an event emitter
16385
16386
16387 componentEmitter(Activator$1.prototype); // The currently active activator
16388
16389 Activator$1.current = null;
16390 /**
16391 * Destroy the activator. Cleans up all created DOM and event listeners
16392 */
16393
16394 Activator$1.prototype.destroy = function () {
16395 this.deactivate(); // remove dom
16396
16397 this.dom.overlay.parentNode.removeChild(this.dom.overlay); // remove global event listener
16398
16399 if (this.onClick) {
16400 document.body.removeEventListener('click', this.onClick);
16401 } // remove keycharm
16402
16403
16404 if (this.keycharm !== undefined) {
16405 this.keycharm.destroy();
16406 }
16407
16408 this.keycharm = null; // cleanup hammer instances
16409
16410 this.hammer.destroy();
16411 this.hammer = null; // FIXME: cleaning up hammer instances doesn't work (Timeline not removed from memory)
16412 };
16413 /**
16414 * Activate the element
16415 * Overlay is hidden, element is decorated with a blue shadow border
16416 */
16417
16418
16419 Activator$1.prototype.activate = function () {
16420 // we allow only one active activator at a time
16421 if (Activator$1.current) {
16422 Activator$1.current.deactivate();
16423 }
16424
16425 Activator$1.current = this;
16426 this.active = true;
16427 this.dom.overlay.style.display = 'none';
16428 util.addClassName(this.dom.container, 'vis-active');
16429 this.emit('change');
16430 this.emit('activate'); // ugly hack: bind ESC after emitting the events, as the Network rebinds all
16431 // keyboard events on a 'change' event
16432
16433 this.keycharm.bind('esc', this.escListener);
16434 };
16435 /**
16436 * Deactivate the element
16437 * Overlay is displayed on top of the element
16438 */
16439
16440
16441 Activator$1.prototype.deactivate = function () {
16442 this.active = false;
16443 this.dom.overlay.style.display = 'block';
16444 util.removeClassName(this.dom.container, 'vis-active');
16445 this.keycharm.unbind('esc', this.escListener);
16446 this.emit('change');
16447 this.emit('deactivate');
16448 };
16449 /**
16450 * Handle a tap event: activate the container
16451 * @param {Event} event The event
16452 * @private
16453 */
16454
16455
16456 Activator$1.prototype._onTapOverlay = function (event) {
16457 // activate the container
16458 this.activate();
16459 event.srcEvent.stopPropagation();
16460 };
16461 /**
16462 * Test whether the element has the requested parent element somewhere in
16463 * its chain of parent nodes.
16464 * @param {HTMLElement} element
16465 * @param {HTMLElement} parent
16466 * @returns {boolean} Returns true when the parent is found somewhere in the
16467 * chain of parent nodes.
16468 * @private
16469 */
16470
16471
16472 function _hasParent(element, parent) {
16473 while (element) {
16474 if (element === parent) {
16475 return true;
16476 }
16477
16478 element = element.parentNode;
16479 }
16480
16481 return false;
16482 }
16483
16484 var Activator_1 = Activator$1;
16485
16486 var locales = createCommonjsModule(function (module, exports) {
16487 // English
16488 exports['en'] = {
16489 edit: 'Edit',
16490 del: 'Delete selected',
16491 back: 'Back',
16492 addNode: 'Add Node',
16493 addEdge: 'Add Edge',
16494 editNode: 'Edit Node',
16495 editEdge: 'Edit Edge',
16496 addDescription: 'Click in an empty space to place a new node.',
16497 edgeDescription: 'Click on a node and drag the edge to another node to connect them.',
16498 editEdgeDescription: 'Click on the control points and drag them to a node to connect to it.',
16499 createEdgeError: 'Cannot link edges to a cluster.',
16500 deleteClusterError: 'Clusters cannot be deleted.',
16501 editClusterError: 'Clusters cannot be edited.'
16502 };
16503 exports['en_EN'] = exports['en'];
16504 exports['en_US'] = exports['en']; // German
16505
16506 exports['de'] = {
16507 edit: 'Editieren',
16508 del: "L\xF6sche Auswahl",
16509 back: "Zur\xFCck",
16510 addNode: "Knoten hinzuf\xFCgen",
16511 addEdge: "Kante hinzuf\xFCgen",
16512 editNode: 'Knoten editieren',
16513 editEdge: 'Kante editieren',
16514 addDescription: 'Klicke auf eine freie Stelle, um einen neuen Knoten zu plazieren.',
16515 edgeDescription: 'Klicke auf einen Knoten und ziehe die Kante zu einem anderen Knoten, um diese zu verbinden.',
16516 editEdgeDescription: 'Klicke auf die Verbindungspunkte und ziehe diese auf einen Knoten, um sie zu verbinden.',
16517 createEdgeError: "Es ist nicht m\xF6glich, Kanten mit Clustern zu verbinden.",
16518 deleteClusterError: "Cluster k\xF6nnen nicht gel\xF6scht werden.",
16519 editClusterError: "Cluster k\xF6nnen nicht editiert werden."
16520 };
16521 exports['de_DE'] = exports['de']; // Spanish
16522
16523 exports['es'] = {
16524 edit: 'Editar',
16525 del: "Eliminar selecci\xF3n",
16526 back: "Atr\xE1s",
16527 addNode: "A\xF1adir nodo",
16528 addEdge: "A\xF1adir arista",
16529 editNode: 'Editar nodo',
16530 editEdge: 'Editar arista',
16531 addDescription: "Haga clic en un lugar vac\xEDo para colocar un nuevo nodo.",
16532 edgeDescription: 'Haga clic en un nodo y arrastre la arista hacia otro nodo para conectarlos.',
16533 editEdgeDescription: 'Haga clic en un punto de control y arrastrelo a un nodo para conectarlo.',
16534 createEdgeError: 'No se puede conectar una arista a un grupo.',
16535 deleteClusterError: 'No es posible eliminar grupos.',
16536 editClusterError: 'No es posible editar grupos.'
16537 };
16538 exports['es_ES'] = exports['es']; //Italiano
16539
16540 exports['it'] = {
16541 edit: 'Modifica',
16542 del: 'Cancella la selezione',
16543 back: 'Indietro',
16544 addNode: 'Aggiungi un nodo',
16545 addEdge: 'Aggiungi un vertice',
16546 editNode: 'Modifica il nodo',
16547 editEdge: 'Modifica il vertice',
16548 addDescription: 'Clicca per aggiungere un nuovo nodo',
16549 edgeDescription: 'Clicca su un nodo e trascinalo ad un altro nodo per connetterli.',
16550 editEdgeDescription: 'Clicca sui Punti di controllo e trascinali ad un nodo per connetterli.',
16551 createEdgeError: 'Non si possono collegare vertici ad un cluster',
16552 deleteClusterError: 'I cluster non possono essere cancellati',
16553 editClusterError: 'I clusters non possono essere modificati.'
16554 };
16555 exports['it_IT'] = exports['it']; // Dutch
16556
16557 exports['nl'] = {
16558 edit: 'Wijzigen',
16559 del: 'Selectie verwijderen',
16560 back: 'Terug',
16561 addNode: 'Node toevoegen',
16562 addEdge: 'Link toevoegen',
16563 editNode: 'Node wijzigen',
16564 editEdge: 'Link wijzigen',
16565 addDescription: 'Klik op een leeg gebied om een nieuwe node te maken.',
16566 edgeDescription: 'Klik op een node en sleep de link naar een andere node om ze te verbinden.',
16567 editEdgeDescription: 'Klik op de verbindingspunten en sleep ze naar een node om daarmee te verbinden.',
16568 createEdgeError: 'Kan geen link maken naar een cluster.',
16569 deleteClusterError: 'Clusters kunnen niet worden verwijderd.',
16570 editClusterError: 'Clusters kunnen niet worden aangepast.'
16571 };
16572 exports['nl_NL'] = exports['nl'];
16573 exports['nl_BE'] = exports['nl']; // Portuguese Brazil
16574
16575 exports['pt-br'] = {
16576 edit: 'Editar',
16577 del: 'Remover selecionado',
16578 back: 'Voltar',
16579 addNode: 'Adicionar nó',
16580 addEdge: 'Adicionar aresta',
16581 editNode: 'Editar nó',
16582 editEdge: 'Editar aresta',
16583 addDescription: 'Clique em um espaço em branco para adicionar um novo nó',
16584 edgeDescription: 'Clique em um nó e arraste a aresta até outro nó para conectá-los',
16585 editEdgeDescription: 'Clique nos pontos de controle e os arraste para um nó para conectá-los',
16586 createEdgeError: 'Não foi possível linkar arestas a um cluster.',
16587 deleteClusterError: 'Clusters não puderam ser removidos.',
16588 editClusterError: 'Clusters não puderam ser editados.'
16589 };
16590 exports['pt-BR'] = exports['pt-br'];
16591 exports['pt_BR'] = exports['pt-br'];
16592 exports['pt_br'] = exports['pt-br']; // Russian
16593
16594 exports['ru'] = {
16595 edit: 'Редактировать',
16596 del: 'Удалить выбранное',
16597 back: 'Назад',
16598 addNode: 'Добавить узел',
16599 addEdge: 'Добавить ребро',
16600 editNode: 'Редактировать узел',
16601 editEdge: 'Редактировать ребро',
16602 addDescription: 'Кликните в свободное место, чтобы добавить новый узел.',
16603 edgeDescription: 'Кликните на узел и протяните ребро к другому узлу, чтобы соединить их.',
16604 editEdgeDescription: 'Кликните на контрольные точки и перетащите их в узел, чтобы подключиться к нему.',
16605 createEdgeError: 'Невозможно соединить ребра в кластер.',
16606 deleteClusterError: 'Кластеры не могут быть удалены',
16607 editClusterError: 'Кластеры недоступны для редактирования.'
16608 };
16609 exports['ru_RU'] = exports['ru']; // Chinese
16610
16611 exports['cn'] = {
16612 edit: '编辑',
16613 del: '删除选定',
16614 back: '返回',
16615 addNode: '添加节点',
16616 addEdge: '添加连接线',
16617 editNode: '编辑节点',
16618 editEdge: '编辑连接线',
16619 addDescription: '单击空白处放置新节点。',
16620 edgeDescription: '单击某个节点并将该连接线拖动到另一个节点以连接它们。',
16621 editEdgeDescription: '单击控制节点并将它们拖到节点上连接。',
16622 createEdgeError: '无法将连接线连接到群集。',
16623 deleteClusterError: '无法删除群集。',
16624 editClusterError: '无法编辑群集。'
16625 };
16626 exports['zh_CN'] = exports['cn']; // Ukrainian
16627
16628 exports['uk'] = {
16629 edit: 'Редагувати',
16630 del: 'Видалити обране',
16631 back: 'Назад',
16632 addNode: 'Додати вузол',
16633 addEdge: 'Додати край',
16634 editNode: 'Редагувати вузол',
16635 editEdge: 'Редагувати край',
16636 addDescription: 'Kлікніть на вільне місце, щоб додати новий вузол.',
16637 edgeDescription: 'Клікніть на вузол і перетягніть край до іншого вузла, щоб їх з\'єднати.',
16638 editEdgeDescription: 'Клікніть на контрольні точки і перетягніть їх у вузол, щоб підключитися до нього.',
16639 createEdgeError: 'Не можливо об\'єднати краї в групу.',
16640 deleteClusterError: 'Групи не можуть бути видалені.',
16641 editClusterError: 'Групи недоступні для редагування.'
16642 };
16643 exports['uk_UA'] = exports['uk']; // French
16644
16645 exports['fr'] = {
16646 edit: 'Editer',
16647 del: 'Effacer la selection',
16648 back: 'Retour',
16649 addNode: 'Ajouter un noeud',
16650 addEdge: 'Ajouter un lien',
16651 editNode: 'Editer le noeud',
16652 editEdge: 'Editer le lien',
16653 addDescription: 'Cliquez dans un endroit vide pour placer un noeud.',
16654 edgeDescription: 'Cliquez sur un noeud et glissez le lien vers un autre noeud pour les connecter.',
16655 editEdgeDescription: 'Cliquez sur les points de contrôle et glissez-les pour connecter un noeud.',
16656 createEdgeError: 'Impossible de créer un lien vers un cluster.',
16657 deleteClusterError: 'Les clusters ne peuvent pas être éffacés.',
16658 editClusterError: 'Les clusters ne peuvent pas être édites.'
16659 };
16660 exports['fr_FR'] = exports['fr']; // Czech
16661
16662 exports['cs'] = {
16663 edit: 'Upravit',
16664 del: 'Smazat výběr',
16665 back: 'Zpět',
16666 addNode: 'Přidat vrchol',
16667 addEdge: 'Přidat hranu',
16668 editNode: 'Upravit vrchol',
16669 editEdge: 'Upravit hranu',
16670 addDescription: 'Kluknutím do prázdného prostoru můžete přidat nový vrchol.',
16671 edgeDescription: 'Přetažením z jednoho vrcholu do druhého můžete spojit tyto vrcholy novou hranou.',
16672 editEdgeDescription: 'Přetažením kontrolního vrcholu hrany ji můžete připojit k jinému vrcholu.',
16673 createEdgeError: 'Nelze připojit hranu ke shluku.',
16674 deleteClusterError: 'Nelze mazat shluky.',
16675 editClusterError: 'Nelze upravovat shluky.'
16676 };
16677 exports['cs_CZ'] = exports['cs'];
16678 });
16679
16680 function _typeof$1(obj) {
16681 if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
16682 _typeof$1 = function (obj) {
16683 return typeof obj;
16684 };
16685 } else {
16686 _typeof$1 = function (obj) {
16687 return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
16688 };
16689 }
16690
16691 return _typeof$1(obj);
16692 }
16693
16694 function _classCallCheck(instance, Constructor) {
16695 if (!(instance instanceof Constructor)) {
16696 throw new TypeError("Cannot call a class as a function");
16697 }
16698 }
16699
16700 function _defineProperties(target, props) {
16701 for (var i = 0; i < props.length; i++) {
16702 var descriptor = props[i];
16703 descriptor.enumerable = descriptor.enumerable || false;
16704 descriptor.configurable = true;
16705 if ("value" in descriptor) descriptor.writable = true;
16706 Object.defineProperty(target, descriptor.key, descriptor);
16707 }
16708 }
16709
16710 function _createClass(Constructor, protoProps, staticProps) {
16711 if (protoProps) _defineProperties(Constructor.prototype, protoProps);
16712 if (staticProps) _defineProperties(Constructor, staticProps);
16713 return Constructor;
16714 }
16715
16716 function _defineProperty$1(obj, key, value) {
16717 if (key in obj) {
16718 Object.defineProperty(obj, key, {
16719 value: value,
16720 enumerable: true,
16721 configurable: true,
16722 writable: true
16723 });
16724 } else {
16725 obj[key] = value;
16726 }
16727
16728 return obj;
16729 }
16730
16731 function ownKeys$2(object, enumerableOnly) {
16732 var keys = Object.keys(object);
16733
16734 if (Object.getOwnPropertySymbols) {
16735 var symbols = Object.getOwnPropertySymbols(object);
16736 if (enumerableOnly) symbols = symbols.filter(function (sym) {
16737 return Object.getOwnPropertyDescriptor(object, sym).enumerable;
16738 });
16739 keys.push.apply(keys, symbols);
16740 }
16741
16742 return keys;
16743 }
16744
16745 function _objectSpread2$1(target) {
16746 for (var i = 1; i < arguments.length; i++) {
16747 var source = arguments[i] != null ? arguments[i] : {};
16748
16749 if (i % 2) {
16750 ownKeys$2(source, true).forEach(function (key) {
16751 _defineProperty$1(target, key, source[key]);
16752 });
16753 } else if (Object.getOwnPropertyDescriptors) {
16754 Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
16755 } else {
16756 ownKeys$2(source).forEach(function (key) {
16757 Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
16758 });
16759 }
16760 }
16761
16762 return target;
16763 }
16764
16765 function _inherits(subClass, superClass) {
16766 if (typeof superClass !== "function" && superClass !== null) {
16767 throw new TypeError("Super expression must either be null or a function");
16768 }
16769
16770 subClass.prototype = Object.create(superClass && superClass.prototype, {
16771 constructor: {
16772 value: subClass,
16773 writable: true,
16774 configurable: true
16775 }
16776 });
16777 if (superClass) _setPrototypeOf(subClass, superClass);
16778 }
16779
16780 function _getPrototypeOf(o) {
16781 _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) {
16782 return o.__proto__ || Object.getPrototypeOf(o);
16783 };
16784 return _getPrototypeOf(o);
16785 }
16786
16787 function _setPrototypeOf(o, p) {
16788 _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) {
16789 o.__proto__ = p;
16790 return o;
16791 };
16792
16793 return _setPrototypeOf(o, p);
16794 }
16795
16796 function _assertThisInitialized$1(self) {
16797 if (self === void 0) {
16798 throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
16799 }
16800
16801 return self;
16802 }
16803
16804 function _possibleConstructorReturn(self, call) {
16805 if (call && (typeof call === "object" || typeof call === "function")) {
16806 return call;
16807 }
16808
16809 return _assertThisInitialized$1(self);
16810 }
16811
16812 function _superPropBase(object, property) {
16813 while (!Object.prototype.hasOwnProperty.call(object, property)) {
16814 object = _getPrototypeOf(object);
16815 if (object === null) break;
16816 }
16817
16818 return object;
16819 }
16820
16821 function _get(target, property, receiver) {
16822 if (typeof Reflect !== "undefined" && Reflect.get) {
16823 _get = Reflect.get;
16824 } else {
16825 _get = function _get(target, property, receiver) {
16826 var base = _superPropBase(target, property);
16827
16828 if (!base) return;
16829 var desc = Object.getOwnPropertyDescriptor(base, property);
16830
16831 if (desc.get) {
16832 return desc.get.call(receiver);
16833 }
16834
16835 return desc.value;
16836 };
16837 }
16838
16839 return _get(target, property, receiver || target);
16840 }
16841
16842 function _readOnlyError(name) {
16843 throw new Error("\"" + name + "\" is read-only");
16844 }
16845
16846 function _slicedToArray(arr, i) {
16847 return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest();
16848 }
16849
16850 function _arrayWithHoles(arr) {
16851 if (Array.isArray(arr)) return arr;
16852 }
16853
16854 function _iterableToArrayLimit(arr, i) {
16855 if (!(Symbol.iterator in Object(arr) || Object.prototype.toString.call(arr) === "[object Arguments]")) {
16856 return;
16857 }
16858
16859 var _arr = [];
16860 var _n = true;
16861 var _d = false;
16862 var _e = undefined;
16863
16864 try {
16865 for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) {
16866 _arr.push(_s.value);
16867
16868 if (i && _arr.length === i) break;
16869 }
16870 } catch (err) {
16871 _d = true;
16872 _e = err;
16873 } finally {
16874 try {
16875 if (!_n && _i["return"] != null) _i["return"]();
16876 } finally {
16877 if (_d) throw _e;
16878 }
16879 }
16880
16881 return _arr;
16882 }
16883
16884 function _nonIterableRest() {
16885 throw new TypeError("Invalid attempt to destructure non-iterable instance");
16886 }
16887
16888 /**
16889 * Associates a canvas to a given image, containing a number of renderings
16890 * of the image at various sizes.
16891 *
16892 * This technique is known as 'mipmapping'.
16893 *
16894 * NOTE: Images can also be of type 'data:svg+xml`. This code also works
16895 * for svg, but the mipmapping may not be necessary.
16896 *
16897 * @param {Image} image
16898 */
16899 var CachedImage =
16900 /*#__PURE__*/
16901 function () {
16902 /**
16903 * @ignore
16904 */
16905 function CachedImage() {
16906 _classCallCheck(this, CachedImage);
16907
16908 // eslint-disable-line no-unused-vars
16909 this.NUM_ITERATIONS = 4; // Number of items in the coordinates array
16910
16911 this.image = new Image();
16912 this.canvas = document.createElement('canvas');
16913 }
16914 /**
16915 * Called when the image has been successfully loaded.
16916 */
16917
16918
16919 _createClass(CachedImage, [{
16920 key: "init",
16921 value: function init() {
16922 if (this.initialized()) return;
16923 this.src = this.image.src; // For same interface with Image
16924
16925 var w = this.image.width;
16926 var h = this.image.height; // Ease external access
16927
16928 this.width = w;
16929 this.height = h;
16930 var h2 = Math.floor(h / 2);
16931 var h4 = Math.floor(h / 4);
16932 var h8 = Math.floor(h / 8);
16933 var h16 = Math.floor(h / 16);
16934 var w2 = Math.floor(w / 2);
16935 var w4 = Math.floor(w / 4);
16936 var w8 = Math.floor(w / 8);
16937 var w16 = Math.floor(w / 16); // Make canvas as small as possible
16938
16939 this.canvas.width = 3 * w4;
16940 this.canvas.height = h2; // Coordinates and sizes of images contained in the canvas
16941 // Values per row: [top x, left y, width, height]
16942
16943 this.coordinates = [[0, 0, w2, h2], [w2, 0, w4, h4], [w2, h4, w8, h8], [5 * w8, h4, w16, h16]];
16944
16945 this._fillMipMap();
16946 }
16947 /**
16948 * @return {Boolean} true if init() has been called, false otherwise.
16949 */
16950
16951 }, {
16952 key: "initialized",
16953 value: function initialized() {
16954 return this.coordinates !== undefined;
16955 }
16956 /**
16957 * Redraw main image in various sizes to the context.
16958 *
16959 * The rationale behind this is to reduce artefacts due to interpolation
16960 * at differing zoom levels.
16961 *
16962 * Source: http://stackoverflow.com/q/18761404/1223531
16963 *
16964 * This methods takes the resizing out of the drawing loop, in order to
16965 * reduce performance overhead.
16966 *
16967 * TODO: The code assumes that a 2D context can always be gotten. This is
16968 * not necessarily true! OTOH, if not true then usage of this class
16969 * is senseless.
16970 *
16971 * @private
16972 */
16973
16974 }, {
16975 key: "_fillMipMap",
16976 value: function _fillMipMap() {
16977 var ctx = this.canvas.getContext('2d'); // First zoom-level comes from the image
16978
16979 var to = this.coordinates[0];
16980 ctx.drawImage(this.image, to[0], to[1], to[2], to[3]); // The rest are copy actions internal to the canvas/context
16981
16982 for (var iterations = 1; iterations < this.NUM_ITERATIONS; iterations++) {
16983 var from = this.coordinates[iterations - 1];
16984 var _to = this.coordinates[iterations];
16985 ctx.drawImage(this.canvas, from[0], from[1], from[2], from[3], _to[0], _to[1], _to[2], _to[3]);
16986 }
16987 }
16988 /**
16989 * Draw the image, using the mipmap if necessary.
16990 *
16991 * MipMap is only used if param factor > 2; otherwise, original bitmap
16992 * is resized. This is also used to skip mipmap usage, e.g. by setting factor = 1
16993 *
16994 * Credits to 'Alex de Mulder' for original implementation.
16995 *
16996 * @param {CanvasRenderingContext2D} ctx context on which to draw zoomed image
16997 * @param {Float} factor scale factor at which to draw
16998 * @param {number} left
16999 * @param {number} top
17000 * @param {number} width
17001 * @param {number} height
17002 */
17003
17004 }, {
17005 key: "drawImageAtPosition",
17006 value: function drawImageAtPosition(ctx, factor, left, top, width, height) {
17007 if (!this.initialized()) return; //can't draw image yet not intialized
17008
17009 if (factor > 2) {
17010 // Determine which zoomed image to use
17011 factor *= 0.5;
17012 var iterations = 0;
17013
17014 while (factor > 2 && iterations < this.NUM_ITERATIONS) {
17015 factor *= 0.5;
17016 iterations += 1;
17017 }
17018
17019 if (iterations >= this.NUM_ITERATIONS) {
17020 iterations = this.NUM_ITERATIONS - 1;
17021 } //console.log("iterations: " + iterations);
17022
17023
17024 var from = this.coordinates[iterations];
17025 ctx.drawImage(this.canvas, from[0], from[1], from[2], from[3], left, top, width, height);
17026 } else {
17027 // Draw image directly
17028 ctx.drawImage(this.image, left, top, width, height);
17029 }
17030 }
17031 }]);
17032
17033 return CachedImage;
17034 }();
17035
17036 /**
17037 * This callback is a callback that accepts an Image.
17038 * @callback ImageCallback
17039 * @param {Image} image
17040 */
17041
17042 /**
17043 * This class loads images and keeps them stored.
17044 *
17045 * @param {ImageCallback} callback
17046 */
17047
17048 var Images =
17049 /*#__PURE__*/
17050 function () {
17051 /**
17052 * @param {ImageCallback} callback
17053 */
17054 function Images(callback) {
17055 _classCallCheck(this, Images);
17056
17057 this.images = {};
17058 this.imageBroken = {};
17059 this.callback = callback;
17060 }
17061 /**
17062 * @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
17063 * @param {string} brokenUrl Url the broken image to try and load
17064 * @param {Image} imageToLoadBrokenUrlOn The image object
17065 */
17066
17067
17068 _createClass(Images, [{
17069 key: "_tryloadBrokenUrl",
17070 value: function _tryloadBrokenUrl(url, brokenUrl, imageToLoadBrokenUrlOn) {
17071 //If these parameters aren't specified then exit the function because nothing constructive can be done
17072 if (url === undefined || imageToLoadBrokenUrlOn === undefined) return;
17073
17074 if (brokenUrl === undefined) {
17075 console.warn("No broken url image defined");
17076 return;
17077 } //Clear the old subscription to the error event and put a new in place that only handle errors in loading the brokenImageUrl
17078
17079
17080 imageToLoadBrokenUrlOn.image.onerror = function () {
17081 console.error("Could not load brokenImage:", brokenUrl); // cache item will contain empty image, this should be OK for default
17082 }; //Set the source of the image to the brokenUrl, this is actually what kicks off the loading of the broken image
17083
17084
17085 imageToLoadBrokenUrlOn.image.src = brokenUrl;
17086 }
17087 /**
17088 *
17089 * @param {vis.Image} imageToRedrawWith
17090 * @private
17091 */
17092
17093 }, {
17094 key: "_redrawWithImage",
17095 value: function _redrawWithImage(imageToRedrawWith) {
17096 if (this.callback) {
17097 this.callback(imageToRedrawWith);
17098 }
17099 }
17100 /**
17101 * @param {string} url Url of the image
17102 * @param {string} brokenUrl Url of an image to use if the url image is not found
17103 * @return {Image} img The image object
17104 */
17105
17106 }, {
17107 key: "load",
17108 value: function load(url, brokenUrl) {
17109 var _this = this;
17110
17111 //Try and get the image from the cache, if successful then return the cached image
17112 var cachedImage = this.images[url];
17113 if (cachedImage) return cachedImage; //Create a new image
17114
17115 var img = new CachedImage(); // Need to add to cache here, otherwise final return will spawn different copies of the same image,
17116 // Also, there will be multiple loads of the same image.
17117
17118 this.images[url] = img; //Subscribe to the event that is raised if the image loads successfully
17119
17120 img.image.onload = function () {
17121 // Properly init the cached item and then request a redraw
17122 _this._fixImageCoordinates(img.image);
17123
17124 img.init();
17125
17126 _this._redrawWithImage(img);
17127 }; //Subscribe to the event that is raised if the image fails to load
17128
17129
17130 img.image.onerror = function () {
17131 console.error("Could not load image:", url); //Try and load the image specified by the brokenUrl using
17132
17133 _this._tryloadBrokenUrl(url, brokenUrl, img);
17134 }; //Set the source of the image to the url, this is what actually kicks off the loading of the image
17135
17136
17137 img.image.src = url; //Return the new image
17138
17139 return img;
17140 }
17141 /**
17142 * IE11 fix -- thanks dponch!
17143 *
17144 * Local helper function
17145 * @param {vis.Image} imageToCache
17146 * @private
17147 */
17148
17149 }, {
17150 key: "_fixImageCoordinates",
17151 value: function _fixImageCoordinates(imageToCache) {
17152 if (imageToCache.width === 0) {
17153 document.body.appendChild(imageToCache);
17154 imageToCache.width = imageToCache.offsetWidth;
17155 imageToCache.height = imageToCache.offsetHeight;
17156 document.body.removeChild(imageToCache);
17157 }
17158 }
17159 }]);
17160
17161 return Images;
17162 }();
17163
17164 /**
17165 * This class can store groups and options specific for groups.
17166 */
17167
17168 var Groups =
17169 /*#__PURE__*/
17170 function () {
17171 /**
17172 * @ignore
17173 */
17174 function Groups() {
17175 _classCallCheck(this, Groups);
17176
17177 this.clear();
17178 this.defaultIndex = 0;
17179 this.groupsArray = [];
17180 this.groupIndex = 0;
17181 this.defaultGroups = [{
17182 border: "#2B7CE9",
17183 background: "#97C2FC",
17184 highlight: {
17185 border: "#2B7CE9",
17186 background: "#D2E5FF"
17187 },
17188 hover: {
17189 border: "#2B7CE9",
17190 background: "#D2E5FF"
17191 }
17192 }, // 0: blue
17193 {
17194 border: "#FFA500",
17195 background: "#FFFF00",
17196 highlight: {
17197 border: "#FFA500",
17198 background: "#FFFFA3"
17199 },
17200 hover: {
17201 border: "#FFA500",
17202 background: "#FFFFA3"
17203 }
17204 }, // 1: yellow
17205 {
17206 border: "#FA0A10",
17207 background: "#FB7E81",
17208 highlight: {
17209 border: "#FA0A10",
17210 background: "#FFAFB1"
17211 },
17212 hover: {
17213 border: "#FA0A10",
17214 background: "#FFAFB1"
17215 }
17216 }, // 2: red
17217 {
17218 border: "#41A906",
17219 background: "#7BE141",
17220 highlight: {
17221 border: "#41A906",
17222 background: "#A1EC76"
17223 },
17224 hover: {
17225 border: "#41A906",
17226 background: "#A1EC76"
17227 }
17228 }, // 3: green
17229 {
17230 border: "#E129F0",
17231 background: "#EB7DF4",
17232 highlight: {
17233 border: "#E129F0",
17234 background: "#F0B3F5"
17235 },
17236 hover: {
17237 border: "#E129F0",
17238 background: "#F0B3F5"
17239 }
17240 }, // 4: magenta
17241 {
17242 border: "#7C29F0",
17243 background: "#AD85E4",
17244 highlight: {
17245 border: "#7C29F0",
17246 background: "#D3BDF0"
17247 },
17248 hover: {
17249 border: "#7C29F0",
17250 background: "#D3BDF0"
17251 }
17252 }, // 5: purple
17253 {
17254 border: "#C37F00",
17255 background: "#FFA807",
17256 highlight: {
17257 border: "#C37F00",
17258 background: "#FFCA66"
17259 },
17260 hover: {
17261 border: "#C37F00",
17262 background: "#FFCA66"
17263 }
17264 }, // 6: orange
17265 {
17266 border: "#4220FB",
17267 background: "#6E6EFD",
17268 highlight: {
17269 border: "#4220FB",
17270 background: "#9B9BFD"
17271 },
17272 hover: {
17273 border: "#4220FB",
17274 background: "#9B9BFD"
17275 }
17276 }, // 7: darkblue
17277 {
17278 border: "#FD5A77",
17279 background: "#FFC0CB",
17280 highlight: {
17281 border: "#FD5A77",
17282 background: "#FFD1D9"
17283 },
17284 hover: {
17285 border: "#FD5A77",
17286 background: "#FFD1D9"
17287 }
17288 }, // 8: pink
17289 {
17290 border: "#4AD63A",
17291 background: "#C2FABC",
17292 highlight: {
17293 border: "#4AD63A",
17294 background: "#E6FFE3"
17295 },
17296 hover: {
17297 border: "#4AD63A",
17298 background: "#E6FFE3"
17299 }
17300 }, // 9: mint
17301 {
17302 border: "#990000",
17303 background: "#EE0000",
17304 highlight: {
17305 border: "#BB0000",
17306 background: "#FF3333"
17307 },
17308 hover: {
17309 border: "#BB0000",
17310 background: "#FF3333"
17311 }
17312 }, // 10:bright red
17313 {
17314 border: "#FF6000",
17315 background: "#FF6000",
17316 highlight: {
17317 border: "#FF6000",
17318 background: "#FF6000"
17319 },
17320 hover: {
17321 border: "#FF6000",
17322 background: "#FF6000"
17323 }
17324 }, // 12: real orange
17325 {
17326 border: "#97C2FC",
17327 background: "#2B7CE9",
17328 highlight: {
17329 border: "#D2E5FF",
17330 background: "#2B7CE9"
17331 },
17332 hover: {
17333 border: "#D2E5FF",
17334 background: "#2B7CE9"
17335 }
17336 }, // 13: blue
17337 {
17338 border: "#399605",
17339 background: "#255C03",
17340 highlight: {
17341 border: "#399605",
17342 background: "#255C03"
17343 },
17344 hover: {
17345 border: "#399605",
17346 background: "#255C03"
17347 }
17348 }, // 14: green
17349 {
17350 border: "#B70054",
17351 background: "#FF007E",
17352 highlight: {
17353 border: "#B70054",
17354 background: "#FF007E"
17355 },
17356 hover: {
17357 border: "#B70054",
17358 background: "#FF007E"
17359 }
17360 }, // 15: magenta
17361 {
17362 border: "#AD85E4",
17363 background: "#7C29F0",
17364 highlight: {
17365 border: "#D3BDF0",
17366 background: "#7C29F0"
17367 },
17368 hover: {
17369 border: "#D3BDF0",
17370 background: "#7C29F0"
17371 }
17372 }, // 16: purple
17373 {
17374 border: "#4557FA",
17375 background: "#000EA1",
17376 highlight: {
17377 border: "#6E6EFD",
17378 background: "#000EA1"
17379 },
17380 hover: {
17381 border: "#6E6EFD",
17382 background: "#000EA1"
17383 }
17384 }, // 17: darkblue
17385 {
17386 border: "#FFC0CB",
17387 background: "#FD5A77",
17388 highlight: {
17389 border: "#FFD1D9",
17390 background: "#FD5A77"
17391 },
17392 hover: {
17393 border: "#FFD1D9",
17394 background: "#FD5A77"
17395 }
17396 }, // 18: pink
17397 {
17398 border: "#C2FABC",
17399 background: "#74D66A",
17400 highlight: {
17401 border: "#E6FFE3",
17402 background: "#74D66A"
17403 },
17404 hover: {
17405 border: "#E6FFE3",
17406 background: "#74D66A"
17407 }
17408 }, // 19: mint
17409 {
17410 border: "#EE0000",
17411 background: "#990000",
17412 highlight: {
17413 border: "#FF3333",
17414 background: "#BB0000"
17415 },
17416 hover: {
17417 border: "#FF3333",
17418 background: "#BB0000"
17419 }
17420 } // 20:bright red
17421 ];
17422 this.options = {};
17423 this.defaultOptions = {
17424 useDefaultGroups: true
17425 };
17426 extend(this.options, this.defaultOptions);
17427 }
17428 /**
17429 *
17430 * @param {Object} options
17431 */
17432
17433
17434 _createClass(Groups, [{
17435 key: "setOptions",
17436 value: function setOptions(options) {
17437 var optionFields = ['useDefaultGroups'];
17438
17439 if (options !== undefined) {
17440 for (var groupName in options) {
17441 if (options.hasOwnProperty(groupName)) {
17442 if (optionFields.indexOf(groupName) === -1) {
17443 var group = options[groupName];
17444 this.add(groupName, group);
17445 }
17446 }
17447 }
17448 }
17449 }
17450 /**
17451 * Clear all groups
17452 */
17453
17454 }, {
17455 key: "clear",
17456 value: function clear() {
17457 this.groups = {};
17458 this.groupsArray = [];
17459 }
17460 /**
17461 * Get group options of a groupname.
17462 * If groupname is not found, a new group may be created.
17463 *
17464 * @param {*} groupname Can be a number, string, Date, etc.
17465 * @param {boolean} [shouldCreate=true] If true, create a new group
17466 * @return {Object} The found or created group
17467 */
17468
17469 }, {
17470 key: "get",
17471 value: function get(groupname) {
17472 var shouldCreate = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
17473 var group = this.groups[groupname];
17474
17475 if (group === undefined && shouldCreate) {
17476 if (this.options.useDefaultGroups === false && this.groupsArray.length > 0) {
17477 // create new group
17478 var index = this.groupIndex % this.groupsArray.length;
17479 this.groupIndex++;
17480 group = {};
17481 group.color = this.groups[this.groupsArray[index]];
17482 this.groups[groupname] = group;
17483 } else {
17484 // create new group
17485 var _index = this.defaultIndex % this.defaultGroups.length;
17486
17487 this.defaultIndex++;
17488 group = {};
17489 group.color = this.defaultGroups[_index];
17490 this.groups[groupname] = group;
17491 }
17492 }
17493
17494 return group;
17495 }
17496 /**
17497 * Add a custom group style
17498 * @param {string} groupName
17499 * @param {Object} style An object containing borderColor,
17500 * backgroundColor, etc.
17501 * @return {Object} group The created group object
17502 */
17503
17504 }, {
17505 key: "add",
17506 value: function add(groupName, style) {
17507 this.groups[groupName] = style;
17508 this.groupsArray.push(groupName);
17509 return style;
17510 }
17511 }]);
17512
17513 return Groups;
17514 }();
17515
17516 var $some = arrayIteration.some; // `Array.prototype.some` method
17517 // https://tc39.github.io/ecma262/#sec-array.prototype.some
17518
17519 _export({
17520 target: 'Array',
17521 proto: true,
17522 forced: sloppyArrayMethod('some')
17523 }, {
17524 some: function some(callbackfn
17525 /* , thisArg */
17526 ) {
17527 return $some(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined);
17528 }
17529 });
17530
17531 /**
17532 * vis-data - data
17533 * http://visjs.org/
17534 *
17535 * Manage unstructured data using DataSet. Add, update, and remove data, and listen for changes in the data.
17536 *
17537 * @version 6.2.1
17538 * @date 2019-09-13T21:24:53Z
17539 *
17540 * @copyright (c) 2011-2017 Almende B.V, http://almende.com
17541 * @copyright (c) 2018-2019 visjs contributors, https://github.com/visjs
17542 *
17543 * @license
17544 * vis.js is dual licensed under both
17545 *
17546 * 1. The Apache 2.0 License
17547 * http://www.apache.org/licenses/LICENSE-2.0
17548 *
17549 * and
17550 *
17551 * 2. The MIT License
17552 * http://opensource.org/licenses/MIT
17553 *
17554 * vis.js may be distributed under either license.
17555 */
17556 function createCommonjsModule$2(fn, module) {
17557 return module = {
17558 exports: {}
17559 }, fn(module, module.exports), module.exports;
17560 }
17561
17562 var runtime_1 = createCommonjsModule$2(function (module) {
17563 /**
17564 * Copyright (c) 2014-present, Facebook, Inc.
17565 *
17566 * This source code is licensed under the MIT license found in the
17567 * LICENSE file in the root directory of this source tree.
17568 */
17569 var runtime = function (exports) {
17570 var Op = Object.prototype;
17571 var hasOwn = Op.hasOwnProperty;
17572 var undefined$1; // More compressible than void 0.
17573
17574 var $Symbol = typeof Symbol === "function" ? Symbol : {};
17575 var iteratorSymbol = $Symbol.iterator || "@@iterator";
17576 var asyncIteratorSymbol = $Symbol.asyncIterator || "@@asyncIterator";
17577 var toStringTagSymbol = $Symbol.toStringTag || "@@toStringTag";
17578
17579 function wrap(innerFn, outerFn, self, tryLocsList) {
17580 // If outerFn provided and outerFn.prototype is a Generator, then outerFn.prototype instanceof Generator.
17581 var protoGenerator = outerFn && outerFn.prototype instanceof Generator ? outerFn : Generator;
17582 var generator = Object.create(protoGenerator.prototype);
17583 var context = new Context(tryLocsList || []); // The ._invoke method unifies the implementations of the .next,
17584 // .throw, and .return methods.
17585
17586 generator._invoke = makeInvokeMethod(innerFn, self, context);
17587 return generator;
17588 }
17589
17590 exports.wrap = wrap; // Try/catch helper to minimize deoptimizations. Returns a completion
17591 // record like context.tryEntries[i].completion. This interface could
17592 // have been (and was previously) designed to take a closure to be
17593 // invoked without arguments, but in all the cases we care about we
17594 // already have an existing method we want to call, so there's no need
17595 // to create a new function object. We can even get away with assuming
17596 // the method takes exactly one argument, since that happens to be true
17597 // in every case, so we don't have to touch the arguments object. The
17598 // only additional allocation required is the completion record, which
17599 // has a stable shape and so hopefully should be cheap to allocate.
17600
17601 function tryCatch(fn, obj, arg) {
17602 try {
17603 return {
17604 type: "normal",
17605 arg: fn.call(obj, arg)
17606 };
17607 } catch (err) {
17608 return {
17609 type: "throw",
17610 arg: err
17611 };
17612 }
17613 }
17614
17615 var GenStateSuspendedStart = "suspendedStart";
17616 var GenStateSuspendedYield = "suspendedYield";
17617 var GenStateExecuting = "executing";
17618 var GenStateCompleted = "completed"; // Returning this object from the innerFn has the same effect as
17619 // breaking out of the dispatch switch statement.
17620
17621 var ContinueSentinel = {}; // Dummy constructor functions that we use as the .constructor and
17622 // .constructor.prototype properties for functions that return Generator
17623 // objects. For full spec compliance, you may wish to configure your
17624 // minifier not to mangle the names of these two functions.
17625
17626 function Generator() {}
17627
17628 function GeneratorFunction() {}
17629
17630 function GeneratorFunctionPrototype() {} // This is a polyfill for %IteratorPrototype% for environments that
17631 // don't natively support it.
17632
17633
17634 var IteratorPrototype = {};
17635
17636 IteratorPrototype[iteratorSymbol] = function () {
17637 return this;
17638 };
17639
17640 var getProto = Object.getPrototypeOf;
17641 var NativeIteratorPrototype = getProto && getProto(getProto(values([])));
17642
17643 if (NativeIteratorPrototype && NativeIteratorPrototype !== Op && hasOwn.call(NativeIteratorPrototype, iteratorSymbol)) {
17644 // This environment has a native %IteratorPrototype%; use it instead
17645 // of the polyfill.
17646 IteratorPrototype = NativeIteratorPrototype;
17647 }
17648
17649 var Gp = GeneratorFunctionPrototype.prototype = Generator.prototype = Object.create(IteratorPrototype);
17650 GeneratorFunction.prototype = Gp.constructor = GeneratorFunctionPrototype;
17651 GeneratorFunctionPrototype.constructor = GeneratorFunction;
17652 GeneratorFunctionPrototype[toStringTagSymbol] = GeneratorFunction.displayName = "GeneratorFunction"; // Helper for defining the .next, .throw, and .return methods of the
17653 // Iterator interface in terms of a single ._invoke method.
17654
17655 function defineIteratorMethods(prototype) {
17656 ["next", "throw", "return"].forEach(function (method) {
17657 prototype[method] = function (arg) {
17658 return this._invoke(method, arg);
17659 };
17660 });
17661 }
17662
17663 exports.isGeneratorFunction = function (genFun) {
17664 var ctor = typeof genFun === "function" && genFun.constructor;
17665 return ctor ? ctor === GeneratorFunction || // For the native GeneratorFunction constructor, the best we can
17666 // do is to check its .name property.
17667 (ctor.displayName || ctor.name) === "GeneratorFunction" : false;
17668 };
17669
17670 exports.mark = function (genFun) {
17671 if (Object.setPrototypeOf) {
17672 Object.setPrototypeOf(genFun, GeneratorFunctionPrototype);
17673 } else {
17674 genFun.__proto__ = GeneratorFunctionPrototype;
17675
17676 if (!(toStringTagSymbol in genFun)) {
17677 genFun[toStringTagSymbol] = "GeneratorFunction";
17678 }
17679 }
17680
17681 genFun.prototype = Object.create(Gp);
17682 return genFun;
17683 }; // Within the body of any async function, `await x` is transformed to
17684 // `yield regeneratorRuntime.awrap(x)`, so that the runtime can test
17685 // `hasOwn.call(value, "__await")` to determine if the yielded value is
17686 // meant to be awaited.
17687
17688
17689 exports.awrap = function (arg) {
17690 return {
17691 __await: arg
17692 };
17693 };
17694
17695 function AsyncIterator(generator) {
17696 function invoke(method, arg, resolve, reject) {
17697 var record = tryCatch(generator[method], generator, arg);
17698
17699 if (record.type === "throw") {
17700 reject(record.arg);
17701 } else {
17702 var result = record.arg;
17703 var value = result.value;
17704
17705 if (value && typeof value === "object" && hasOwn.call(value, "__await")) {
17706 return Promise.resolve(value.__await).then(function (value) {
17707 invoke("next", value, resolve, reject);
17708 }, function (err) {
17709 invoke("throw", err, resolve, reject);
17710 });
17711 }
17712
17713 return Promise.resolve(value).then(function (unwrapped) {
17714 // When a yielded Promise is resolved, its final value becomes
17715 // the .value of the Promise<{value,done}> result for the
17716 // current iteration.
17717 result.value = unwrapped;
17718 resolve(result);
17719 }, function (error) {
17720 // If a rejected Promise was yielded, throw the rejection back
17721 // into the async generator function so it can be handled there.
17722 return invoke("throw", error, resolve, reject);
17723 });
17724 }
17725 }
17726
17727 var previousPromise;
17728
17729 function enqueue(method, arg) {
17730 function callInvokeWithMethodAndArg() {
17731 return new Promise(function (resolve, reject) {
17732 invoke(method, arg, resolve, reject);
17733 });
17734 }
17735
17736 return previousPromise = // If enqueue has been called before, then we want to wait until
17737 // all previous Promises have been resolved before calling invoke,
17738 // so that results are always delivered in the correct order. If
17739 // enqueue has not been called before, then it is important to
17740 // call invoke immediately, without waiting on a callback to fire,
17741 // so that the async generator function has the opportunity to do
17742 // any necessary setup in a predictable way. This predictability
17743 // is why the Promise constructor synchronously invokes its
17744 // executor callback, and why async functions synchronously
17745 // execute code before the first await. Since we implement simple
17746 // async functions in terms of async generators, it is especially
17747 // important to get this right, even though it requires care.
17748 previousPromise ? previousPromise.then(callInvokeWithMethodAndArg, // Avoid propagating failures to Promises returned by later
17749 // invocations of the iterator.
17750 callInvokeWithMethodAndArg) : callInvokeWithMethodAndArg();
17751 } // Define the unified helper method that is used to implement .next,
17752 // .throw, and .return (see defineIteratorMethods).
17753
17754
17755 this._invoke = enqueue;
17756 }
17757
17758 defineIteratorMethods(AsyncIterator.prototype);
17759
17760 AsyncIterator.prototype[asyncIteratorSymbol] = function () {
17761 return this;
17762 };
17763
17764 exports.AsyncIterator = AsyncIterator; // Note that simple async functions are implemented on top of
17765 // AsyncIterator objects; they just return a Promise for the value of
17766 // the final result produced by the iterator.
17767
17768 exports.async = function (innerFn, outerFn, self, tryLocsList) {
17769 var iter = new AsyncIterator(wrap(innerFn, outerFn, self, tryLocsList));
17770 return exports.isGeneratorFunction(outerFn) ? iter // If outerFn is a generator, return the full iterator.
17771 : iter.next().then(function (result) {
17772 return result.done ? result.value : iter.next();
17773 });
17774 };
17775
17776 function makeInvokeMethod(innerFn, self, context) {
17777 var state = GenStateSuspendedStart;
17778 return function invoke(method, arg) {
17779 if (state === GenStateExecuting) {
17780 throw new Error("Generator is already running");
17781 }
17782
17783 if (state === GenStateCompleted) {
17784 if (method === "throw") {
17785 throw arg;
17786 } // Be forgiving, per 25.3.3.3.3 of the spec:
17787 // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-generatorresume
17788
17789
17790 return doneResult();
17791 }
17792
17793 context.method = method;
17794 context.arg = arg;
17795
17796 while (true) {
17797 var delegate = context.delegate;
17798
17799 if (delegate) {
17800 var delegateResult = maybeInvokeDelegate(delegate, context);
17801
17802 if (delegateResult) {
17803 if (delegateResult === ContinueSentinel) continue;
17804 return delegateResult;
17805 }
17806 }
17807
17808 if (context.method === "next") {
17809 // Setting context._sent for legacy support of Babel's
17810 // function.sent implementation.
17811 context.sent = context._sent = context.arg;
17812 } else if (context.method === "throw") {
17813 if (state === GenStateSuspendedStart) {
17814 state = GenStateCompleted;
17815 throw context.arg;
17816 }
17817
17818 context.dispatchException(context.arg);
17819 } else if (context.method === "return") {
17820 context.abrupt("return", context.arg);
17821 }
17822
17823 state = GenStateExecuting;
17824 var record = tryCatch(innerFn, self, context);
17825
17826 if (record.type === "normal") {
17827 // If an exception is thrown from innerFn, we leave state ===
17828 // GenStateExecuting and loop back for another invocation.
17829 state = context.done ? GenStateCompleted : GenStateSuspendedYield;
17830
17831 if (record.arg === ContinueSentinel) {
17832 continue;
17833 }
17834
17835 return {
17836 value: record.arg,
17837 done: context.done
17838 };
17839 } else if (record.type === "throw") {
17840 state = GenStateCompleted; // Dispatch the exception by looping back around to the
17841 // context.dispatchException(context.arg) call above.
17842
17843 context.method = "throw";
17844 context.arg = record.arg;
17845 }
17846 }
17847 };
17848 } // Call delegate.iterator[context.method](context.arg) and handle the
17849 // result, either by returning a { value, done } result from the
17850 // delegate iterator, or by modifying context.method and context.arg,
17851 // setting context.delegate to null, and returning the ContinueSentinel.
17852
17853
17854 function maybeInvokeDelegate(delegate, context) {
17855 var method = delegate.iterator[context.method];
17856
17857 if (method === undefined$1) {
17858 // A .throw or .return when the delegate iterator has no .throw
17859 // method always terminates the yield* loop.
17860 context.delegate = null;
17861
17862 if (context.method === "throw") {
17863 // Note: ["return"] must be used for ES3 parsing compatibility.
17864 if (delegate.iterator["return"]) {
17865 // If the delegate iterator has a return method, give it a
17866 // chance to clean up.
17867 context.method = "return";
17868 context.arg = undefined$1;
17869 maybeInvokeDelegate(delegate, context);
17870
17871 if (context.method === "throw") {
17872 // If maybeInvokeDelegate(context) changed context.method from
17873 // "return" to "throw", let that override the TypeError below.
17874 return ContinueSentinel;
17875 }
17876 }
17877
17878 context.method = "throw";
17879 context.arg = new TypeError("The iterator does not provide a 'throw' method");
17880 }
17881
17882 return ContinueSentinel;
17883 }
17884
17885 var record = tryCatch(method, delegate.iterator, context.arg);
17886
17887 if (record.type === "throw") {
17888 context.method = "throw";
17889 context.arg = record.arg;
17890 context.delegate = null;
17891 return ContinueSentinel;
17892 }
17893
17894 var info = record.arg;
17895
17896 if (!info) {
17897 context.method = "throw";
17898 context.arg = new TypeError("iterator result is not an object");
17899 context.delegate = null;
17900 return ContinueSentinel;
17901 }
17902
17903 if (info.done) {
17904 // Assign the result of the finished delegate to the temporary
17905 // variable specified by delegate.resultName (see delegateYield).
17906 context[delegate.resultName] = info.value; // Resume execution at the desired location (see delegateYield).
17907
17908 context.next = delegate.nextLoc; // If context.method was "throw" but the delegate handled the
17909 // exception, let the outer generator proceed normally. If
17910 // context.method was "next", forget context.arg since it has been
17911 // "consumed" by the delegate iterator. If context.method was
17912 // "return", allow the original .return call to continue in the
17913 // outer generator.
17914
17915 if (context.method !== "return") {
17916 context.method = "next";
17917 context.arg = undefined$1;
17918 }
17919 } else {
17920 // Re-yield the result returned by the delegate method.
17921 return info;
17922 } // The delegate iterator is finished, so forget it and continue with
17923 // the outer generator.
17924
17925
17926 context.delegate = null;
17927 return ContinueSentinel;
17928 } // Define Generator.prototype.{next,throw,return} in terms of the
17929 // unified ._invoke helper method.
17930
17931
17932 defineIteratorMethods(Gp);
17933 Gp[toStringTagSymbol] = "Generator"; // A Generator should always return itself as the iterator object when the
17934 // @@iterator function is called on it. Some browsers' implementations of the
17935 // iterator prototype chain incorrectly implement this, causing the Generator
17936 // object to not be returned from this call. This ensures that doesn't happen.
17937 // See https://github.com/facebook/regenerator/issues/274 for more details.
17938
17939 Gp[iteratorSymbol] = function () {
17940 return this;
17941 };
17942
17943 Gp.toString = function () {
17944 return "[object Generator]";
17945 };
17946
17947 function pushTryEntry(locs) {
17948 var entry = {
17949 tryLoc: locs[0]
17950 };
17951
17952 if (1 in locs) {
17953 entry.catchLoc = locs[1];
17954 }
17955
17956 if (2 in locs) {
17957 entry.finallyLoc = locs[2];
17958 entry.afterLoc = locs[3];
17959 }
17960
17961 this.tryEntries.push(entry);
17962 }
17963
17964 function resetTryEntry(entry) {
17965 var record = entry.completion || {};
17966 record.type = "normal";
17967 delete record.arg;
17968 entry.completion = record;
17969 }
17970
17971 function Context(tryLocsList) {
17972 // The root entry object (effectively a try statement without a catch
17973 // or a finally block) gives us a place to store values thrown from
17974 // locations where there is no enclosing try statement.
17975 this.tryEntries = [{
17976 tryLoc: "root"
17977 }];
17978 tryLocsList.forEach(pushTryEntry, this);
17979 this.reset(true);
17980 }
17981
17982 exports.keys = function (object) {
17983 var keys = [];
17984
17985 for (var key in object) {
17986 keys.push(key);
17987 }
17988
17989 keys.reverse(); // Rather than returning an object with a next method, we keep
17990 // things simple and return the next function itself.
17991
17992 return function next() {
17993 while (keys.length) {
17994 var key = keys.pop();
17995
17996 if (key in object) {
17997 next.value = key;
17998 next.done = false;
17999 return next;
18000 }
18001 } // To avoid creating an additional object, we just hang the .value
18002 // and .done properties off the next function object itself. This
18003 // also ensures that the minifier will not anonymize the function.
18004
18005
18006 next.done = true;
18007 return next;
18008 };
18009 };
18010
18011 function values(iterable) {
18012 if (iterable) {
18013 var iteratorMethod = iterable[iteratorSymbol];
18014
18015 if (iteratorMethod) {
18016 return iteratorMethod.call(iterable);
18017 }
18018
18019 if (typeof iterable.next === "function") {
18020 return iterable;
18021 }
18022
18023 if (!isNaN(iterable.length)) {
18024 var i = -1,
18025 next = function next() {
18026 while (++i < iterable.length) {
18027 if (hasOwn.call(iterable, i)) {
18028 next.value = iterable[i];
18029 next.done = false;
18030 return next;
18031 }
18032 }
18033
18034 next.value = undefined$1;
18035 next.done = true;
18036 return next;
18037 };
18038
18039 return next.next = next;
18040 }
18041 } // Return an iterator with no values.
18042
18043
18044 return {
18045 next: doneResult
18046 };
18047 }
18048
18049 exports.values = values;
18050
18051 function doneResult() {
18052 return {
18053 value: undefined$1,
18054 done: true
18055 };
18056 }
18057
18058 Context.prototype = {
18059 constructor: Context,
18060 reset: function (skipTempReset) {
18061 this.prev = 0;
18062 this.next = 0; // Resetting context._sent for legacy support of Babel's
18063 // function.sent implementation.
18064
18065 this.sent = this._sent = undefined$1;
18066 this.done = false;
18067 this.delegate = null;
18068 this.method = "next";
18069 this.arg = undefined$1;
18070 this.tryEntries.forEach(resetTryEntry);
18071
18072 if (!skipTempReset) {
18073 for (var name in this) {
18074 // Not sure about the optimal order of these conditions:
18075 if (name.charAt(0) === "t" && hasOwn.call(this, name) && !isNaN(+name.slice(1))) {
18076 this[name] = undefined$1;
18077 }
18078 }
18079 }
18080 },
18081 stop: function () {
18082 this.done = true;
18083 var rootEntry = this.tryEntries[0];
18084 var rootRecord = rootEntry.completion;
18085
18086 if (rootRecord.type === "throw") {
18087 throw rootRecord.arg;
18088 }
18089
18090 return this.rval;
18091 },
18092 dispatchException: function (exception) {
18093 if (this.done) {
18094 throw exception;
18095 }
18096
18097 var context = this;
18098
18099 function handle(loc, caught) {
18100 record.type = "throw";
18101 record.arg = exception;
18102 context.next = loc;
18103
18104 if (caught) {
18105 // If the dispatched exception was caught by a catch block,
18106 // then let that catch block handle the exception normally.
18107 context.method = "next";
18108 context.arg = undefined$1;
18109 }
18110
18111 return !!caught;
18112 }
18113
18114 for (var i = this.tryEntries.length - 1; i >= 0; --i) {
18115 var entry = this.tryEntries[i];
18116 var record = entry.completion;
18117
18118 if (entry.tryLoc === "root") {
18119 // Exception thrown outside of any try block that could handle
18120 // it, so set the completion value of the entire function to
18121 // throw the exception.
18122 return handle("end");
18123 }
18124
18125 if (entry.tryLoc <= this.prev) {
18126 var hasCatch = hasOwn.call(entry, "catchLoc");
18127 var hasFinally = hasOwn.call(entry, "finallyLoc");
18128
18129 if (hasCatch && hasFinally) {
18130 if (this.prev < entry.catchLoc) {
18131 return handle(entry.catchLoc, true);
18132 } else if (this.prev < entry.finallyLoc) {
18133 return handle(entry.finallyLoc);
18134 }
18135 } else if (hasCatch) {
18136 if (this.prev < entry.catchLoc) {
18137 return handle(entry.catchLoc, true);
18138 }
18139 } else if (hasFinally) {
18140 if (this.prev < entry.finallyLoc) {
18141 return handle(entry.finallyLoc);
18142 }
18143 } else {
18144 throw new Error("try statement without catch or finally");
18145 }
18146 }
18147 }
18148 },
18149 abrupt: function (type, arg) {
18150 for (var i = this.tryEntries.length - 1; i >= 0; --i) {
18151 var entry = this.tryEntries[i];
18152
18153 if (entry.tryLoc <= this.prev && hasOwn.call(entry, "finallyLoc") && this.prev < entry.finallyLoc) {
18154 var finallyEntry = entry;
18155 break;
18156 }
18157 }
18158
18159 if (finallyEntry && (type === "break" || type === "continue") && finallyEntry.tryLoc <= arg && arg <= finallyEntry.finallyLoc) {
18160 // Ignore the finally entry if control is not jumping to a
18161 // location outside the try/catch block.
18162 finallyEntry = null;
18163 }
18164
18165 var record = finallyEntry ? finallyEntry.completion : {};
18166 record.type = type;
18167 record.arg = arg;
18168
18169 if (finallyEntry) {
18170 this.method = "next";
18171 this.next = finallyEntry.finallyLoc;
18172 return ContinueSentinel;
18173 }
18174
18175 return this.complete(record);
18176 },
18177 complete: function (record, afterLoc) {
18178 if (record.type === "throw") {
18179 throw record.arg;
18180 }
18181
18182 if (record.type === "break" || record.type === "continue") {
18183 this.next = record.arg;
18184 } else if (record.type === "return") {
18185 this.rval = this.arg = record.arg;
18186 this.method = "return";
18187 this.next = "end";
18188 } else if (record.type === "normal" && afterLoc) {
18189 this.next = afterLoc;
18190 }
18191
18192 return ContinueSentinel;
18193 },
18194 finish: function (finallyLoc) {
18195 for (var i = this.tryEntries.length - 1; i >= 0; --i) {
18196 var entry = this.tryEntries[i];
18197
18198 if (entry.finallyLoc === finallyLoc) {
18199 this.complete(entry.completion, entry.afterLoc);
18200 resetTryEntry(entry);
18201 return ContinueSentinel;
18202 }
18203 }
18204 },
18205 "catch": function (tryLoc) {
18206 for (var i = this.tryEntries.length - 1; i >= 0; --i) {
18207 var entry = this.tryEntries[i];
18208
18209 if (entry.tryLoc === tryLoc) {
18210 var record = entry.completion;
18211
18212 if (record.type === "throw") {
18213 var thrown = record.arg;
18214 resetTryEntry(entry);
18215 }
18216
18217 return thrown;
18218 }
18219 } // The context.catch method must only be called with a location
18220 // argument that corresponds to a known catch block.
18221
18222
18223 throw new Error("illegal catch attempt");
18224 },
18225 delegateYield: function (iterable, resultName, nextLoc) {
18226 this.delegate = {
18227 iterator: values(iterable),
18228 resultName: resultName,
18229 nextLoc: nextLoc
18230 };
18231
18232 if (this.method === "next") {
18233 // Deliberately forget the last sent value so that we don't
18234 // accidentally pass it on to the delegate.
18235 this.arg = undefined$1;
18236 }
18237
18238 return ContinueSentinel;
18239 }
18240 }; // Regardless of whether this script is executing as a CommonJS module
18241 // or not, return the runtime object so that we can declare the variable
18242 // regeneratorRuntime in the outer scope, which allows this module to be
18243 // injected easily by `bin/regenerator --include-runtime script.js`.
18244
18245 return exports;
18246 }( // If this script is executing as a CommonJS module, use module.exports
18247 // as the regeneratorRuntime namespace. Otherwise create a new empty
18248 // object. Either way, the resulting object will be used to initialize
18249 // the regeneratorRuntime variable at the top of this file.
18250 module.exports);
18251
18252 try {
18253 regeneratorRuntime = runtime;
18254 } catch (accidentalStrictMode) {
18255 // This module should not be running in strict mode, so the above
18256 // assignment should always work unless something is misconfigured. Just
18257 // in case runtime.js accidentally runs in strict mode, we can escape
18258 // strict mode using a global Function call. This could conceivably fail
18259 // if a Content Security Policy forbids using Function, but in that case
18260 // the proper solution is to fix the accidental strict mode problem. If
18261 // you've misconfigured your bundler to force strict mode and applied a
18262 // CSP to forbid Function, and you're not willing to fix either of those
18263 // problems, please detail your unique predicament in a GitHub issue.
18264 Function("r", "regeneratorRuntime = r")(runtime);
18265 }
18266 });
18267 var regenerator = runtime_1;
18268
18269 function _defineProperty$2(obj, key, value) {
18270 if (key in obj) {
18271 Object.defineProperty(obj, key, {
18272 value: value,
18273 enumerable: true,
18274 configurable: true,
18275 writable: true
18276 });
18277 } else {
18278 obj[key] = value;
18279 }
18280
18281 return obj;
18282 }
18283
18284 var defineProperty$6 = _defineProperty$2;
18285
18286 function _arrayWithoutHoles$1(arr) {
18287 if (Array.isArray(arr)) {
18288 for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) {
18289 arr2[i] = arr[i];
18290 }
18291
18292 return arr2;
18293 }
18294 }
18295
18296 var arrayWithoutHoles = _arrayWithoutHoles$1;
18297
18298 function _iterableToArray$1(iter) {
18299 if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter);
18300 }
18301
18302 var iterableToArray = _iterableToArray$1;
18303
18304 function _nonIterableSpread$1() {
18305 throw new TypeError("Invalid attempt to spread non-iterable instance");
18306 }
18307
18308 var nonIterableSpread = _nonIterableSpread$1;
18309
18310 function _toConsumableArray$1(arr) {
18311 return arrayWithoutHoles(arr) || iterableToArray(arr) || nonIterableSpread();
18312 }
18313
18314 var toConsumableArray = _toConsumableArray$1;
18315
18316 var _typeof_1 = createCommonjsModule$2(function (module) {
18317 function _typeof2(obj) {
18318 if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
18319 _typeof2 = function _typeof2(obj) {
18320 return typeof obj;
18321 };
18322 } else {
18323 _typeof2 = function _typeof2(obj) {
18324 return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
18325 };
18326 }
18327
18328 return _typeof2(obj);
18329 }
18330
18331 function _typeof(obj) {
18332 if (typeof Symbol === "function" && _typeof2(Symbol.iterator) === "symbol") {
18333 module.exports = _typeof = function _typeof(obj) {
18334 return _typeof2(obj);
18335 };
18336 } else {
18337 module.exports = _typeof = function _typeof(obj) {
18338 return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : _typeof2(obj);
18339 };
18340 }
18341
18342 return _typeof(obj);
18343 }
18344
18345 module.exports = _typeof;
18346 });
18347
18348 function _classCallCheck$1(instance, Constructor) {
18349 if (!(instance instanceof Constructor)) {
18350 throw new TypeError("Cannot call a class as a function");
18351 }
18352 }
18353
18354 var classCallCheck = _classCallCheck$1;
18355
18356 function _defineProperties$1(target, props) {
18357 for (var i = 0; i < props.length; i++) {
18358 var descriptor = props[i];
18359 descriptor.enumerable = descriptor.enumerable || false;
18360 descriptor.configurable = true;
18361 if ("value" in descriptor) descriptor.writable = true;
18362 Object.defineProperty(target, descriptor.key, descriptor);
18363 }
18364 }
18365
18366 function _createClass$1(Constructor, protoProps, staticProps) {
18367 if (protoProps) _defineProperties$1(Constructor.prototype, protoProps);
18368 if (staticProps) _defineProperties$1(Constructor, staticProps);
18369 return Constructor;
18370 }
18371
18372 var createClass = _createClass$1;
18373
18374 function _assertThisInitialized$2(self) {
18375 if (self === void 0) {
18376 throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
18377 }
18378
18379 return self;
18380 }
18381
18382 var assertThisInitialized = _assertThisInitialized$2;
18383
18384 function _possibleConstructorReturn$1(self, call) {
18385 if (call && (_typeof_1(call) === "object" || typeof call === "function")) {
18386 return call;
18387 }
18388
18389 return assertThisInitialized(self);
18390 }
18391
18392 var possibleConstructorReturn = _possibleConstructorReturn$1;
18393 var getPrototypeOf = createCommonjsModule$2(function (module) {
18394 function _getPrototypeOf(o) {
18395 module.exports = _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) {
18396 return o.__proto__ || Object.getPrototypeOf(o);
18397 };
18398 return _getPrototypeOf(o);
18399 }
18400
18401 module.exports = _getPrototypeOf;
18402 });
18403 var setPrototypeOf$1 = createCommonjsModule$2(function (module) {
18404 function _setPrototypeOf(o, p) {
18405 module.exports = _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) {
18406 o.__proto__ = p;
18407 return o;
18408 };
18409
18410 return _setPrototypeOf(o, p);
18411 }
18412
18413 module.exports = _setPrototypeOf;
18414 });
18415
18416 function _inherits$1(subClass, superClass) {
18417 if (typeof superClass !== "function" && superClass !== null) {
18418 throw new TypeError("Super expression must either be null or a function");
18419 }
18420
18421 subClass.prototype = Object.create(superClass && superClass.prototype, {
18422 constructor: {
18423 value: subClass,
18424 writable: true,
18425 configurable: true
18426 }
18427 });
18428 if (superClass) setPrototypeOf$1(subClass, superClass);
18429 }
18430
18431 var inherits = _inherits$1; // Maps for number <-> hex string conversion
18432
18433 var byteToHex$2 = [];
18434
18435 for (var i$2 = 0; i$2 < 256; i$2++) {
18436 byteToHex$2[i$2] = (i$2 + 0x100).toString(16).substr(1);
18437 }
18438 /**
18439 * Represent binary UUID into it's string representation.
18440 *
18441 * @param buf - Buffer containing UUID bytes.
18442 * @param offset - Offset from the start of the buffer where the UUID is saved (not needed if the buffer starts with the UUID).
18443 *
18444 * @returns String representation of the UUID.
18445 */
18446
18447
18448 function stringifyUUID$1(buf, offset) {
18449 var i = offset || 0;
18450 var bth = byteToHex$2;
18451 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++]];
18452 }
18453 /**
18454 * Generate 16 random bytes to be used as a base for UUID.
18455 *
18456 * @ignore
18457 */
18458
18459
18460 var random$1 = function () {
18461 if (typeof crypto !== 'undefined' && crypto.getRandomValues) {
18462 // WHATWG crypto-based RNG - http://wiki.whatwg.org/wiki/Crypto
18463 // Moderately fast, high quality
18464 var _rnds8 = new Uint8Array(16);
18465
18466 return function whatwgRNG() {
18467 crypto.getRandomValues(_rnds8);
18468 return _rnds8;
18469 };
18470 } // Math.random()-based (RNG)
18471 //
18472 // If all else fails, use Math.random().
18473 // It's fast, but is of unspecified quality.
18474
18475
18476 var _rnds = new Array(16);
18477
18478 return function () {
18479 for (var i = 0, r; i < 16; i++) {
18480 if ((i & 0x03) === 0) {
18481 r = Math.random() * 0x100000000;
18482 }
18483
18484 _rnds[i] = r >>> ((i & 0x03) << 3) & 0xff;
18485 }
18486
18487 return _rnds;
18488 }; // uuid.js
18489 //
18490 // Copyright (c) 2010-2012 Robert Kieffer
18491 // MIT License - http://opensource.org/licenses/mit-license.php
18492 // Unique ID creation requires a high quality random # generator. We feature
18493 // detect to determine the best RNG source, normalizing to a function that
18494 // returns 128-bits of randomness, since that's what's usually required
18495 // return require('./rng');
18496 }();
18497
18498 var byteToHex$1$1 = [];
18499
18500 for (var i$1$2 = 0; i$1$2 < 256; i$1$2++) {
18501 byteToHex$1$1[i$1$2] = (i$1$2 + 0x100).toString(16).substr(1);
18502 } // **`v1()` - Generate time-based UUID**
18503 //
18504 // Inspired by https://github.com/LiosK/UUID.js
18505 // and http://docs.python.org/library/uuid.html
18506 // random #'s we need to init node and clockseq
18507
18508
18509 var seedBytes$1 = random$1(); // Per 4.5, create and 48-bit node id, (47 random bits + multicast bit = 1)
18510
18511 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
18512
18513 var defaultClockseq$1 = (seedBytes$1[6] << 8 | seedBytes$1[7]) & 0x3fff; // Previous uuid creation time
18514
18515 /**
18516 * UUIDv4 options.
18517 */
18518
18519 /**
18520 * Generate UUIDv4
18521 *
18522 * @param options - Options to be used instead of default generated values.
18523 * String 'binary' is a shorthand for uuid4({}, new Array(16)).
18524 * @param buf - If present the buffer will be filled with the generated UUID.
18525 * @param offset - Offset of the UUID from the start of the buffer.
18526 *
18527 * @returns UUIDv4
18528 */
18529
18530 function uuid4$1() {
18531 var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
18532 var buf = arguments.length > 1 ? arguments[1] : undefined;
18533 var offset = arguments.length > 2 ? arguments[2] : undefined; // Deprecated - 'format' argument, as supported in v1.2
18534
18535 var i = buf && offset || 0;
18536
18537 if (typeof options === 'string') {
18538 buf = options === 'binary' ? new Array(16) : undefined;
18539 options = {};
18540 }
18541
18542 var rnds = options.random || (options.rng || random$1)(); // Per 4.4, set bits for version and `clock_seq_hi_and_reserved`
18543
18544 rnds[6] = rnds[6] & 0x0f | 0x40;
18545 rnds[8] = rnds[8] & 0x3f | 0x80; // Copy bytes to buffer, if provided
18546
18547 if (buf) {
18548 for (var ii = 0; ii < 16; ii++) {
18549 buf[i + ii] = rnds[ii];
18550 }
18551 }
18552
18553 return buf || stringifyUUID$1(rnds);
18554 } // Rollup will complain about mixing default and named exports in UMD build,
18555
18556
18557 function _typeof$2(obj) {
18558 if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
18559 _typeof$2 = function (obj) {
18560 return typeof obj;
18561 };
18562 } else {
18563 _typeof$2 = function (obj) {
18564 return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
18565 };
18566 }
18567
18568 return _typeof$2(obj);
18569 }
18570
18571 var commonjsGlobal$2 = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
18572
18573 function commonjsRequire$2() {
18574 throw new Error('Dynamic requires are not currently supported by rollup-plugin-commonjs');
18575 }
18576
18577 function createCommonjsModule$1$1(fn, module) {
18578 return module = {
18579 exports: {}
18580 }, fn(module, module.exports), module.exports;
18581 }
18582
18583 var moment$1 = createCommonjsModule$1$1(function (module, exports) {
18584 (function (global, factory) {
18585 module.exports = factory();
18586 })(commonjsGlobal$2, function () {
18587 var hookCallback;
18588
18589 function hooks() {
18590 return hookCallback.apply(null, arguments);
18591 } // This is done to register the method called with moment()
18592 // without creating circular dependencies.
18593
18594
18595 function setHookCallback(callback) {
18596 hookCallback = callback;
18597 }
18598
18599 function isArray(input) {
18600 return input instanceof Array || Object.prototype.toString.call(input) === '[object Array]';
18601 }
18602
18603 function isObject(input) {
18604 // IE8 will treat undefined and null as object if it wasn't for
18605 // input != null
18606 return input != null && Object.prototype.toString.call(input) === '[object Object]';
18607 }
18608
18609 function isObjectEmpty(obj) {
18610 if (Object.getOwnPropertyNames) {
18611 return Object.getOwnPropertyNames(obj).length === 0;
18612 } else {
18613 var k;
18614
18615 for (k in obj) {
18616 if (obj.hasOwnProperty(k)) {
18617 return false;
18618 }
18619 }
18620
18621 return true;
18622 }
18623 }
18624
18625 function isUndefined(input) {
18626 return input === void 0;
18627 }
18628
18629 function isNumber(input) {
18630 return typeof input === 'number' || Object.prototype.toString.call(input) === '[object Number]';
18631 }
18632
18633 function isDate(input) {
18634 return input instanceof Date || Object.prototype.toString.call(input) === '[object Date]';
18635 }
18636
18637 function map(arr, fn) {
18638 var res = [],
18639 i;
18640
18641 for (i = 0; i < arr.length; ++i) {
18642 res.push(fn(arr[i], i));
18643 }
18644
18645 return res;
18646 }
18647
18648 function hasOwnProp(a, b) {
18649 return Object.prototype.hasOwnProperty.call(a, b);
18650 }
18651
18652 function extend(a, b) {
18653 for (var i in b) {
18654 if (hasOwnProp(b, i)) {
18655 a[i] = b[i];
18656 }
18657 }
18658
18659 if (hasOwnProp(b, 'toString')) {
18660 a.toString = b.toString;
18661 }
18662
18663 if (hasOwnProp(b, 'valueOf')) {
18664 a.valueOf = b.valueOf;
18665 }
18666
18667 return a;
18668 }
18669
18670 function createUTC(input, format, locale, strict) {
18671 return createLocalOrUTC(input, format, locale, strict, true).utc();
18672 }
18673
18674 function defaultParsingFlags() {
18675 // We need to deep clone this object.
18676 return {
18677 empty: false,
18678 unusedTokens: [],
18679 unusedInput: [],
18680 overflow: -2,
18681 charsLeftOver: 0,
18682 nullInput: false,
18683 invalidMonth: null,
18684 invalidFormat: false,
18685 userInvalidated: false,
18686 iso: false,
18687 parsedDateParts: [],
18688 meridiem: null,
18689 rfc2822: false,
18690 weekdayMismatch: false
18691 };
18692 }
18693
18694 function getParsingFlags(m) {
18695 if (m._pf == null) {
18696 m._pf = defaultParsingFlags();
18697 }
18698
18699 return m._pf;
18700 }
18701
18702 var some;
18703
18704 if (Array.prototype.some) {
18705 some = Array.prototype.some;
18706 } else {
18707 some = function (fun) {
18708 var t = Object(this);
18709 var len = t.length >>> 0;
18710
18711 for (var i = 0; i < len; i++) {
18712 if (i in t && fun.call(this, t[i], i, t)) {
18713 return true;
18714 }
18715 }
18716
18717 return false;
18718 };
18719 }
18720
18721 function isValid(m) {
18722 if (m._isValid == null) {
18723 var flags = getParsingFlags(m);
18724 var parsedParts = some.call(flags.parsedDateParts, function (i) {
18725 return i != null;
18726 });
18727 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);
18728
18729 if (m._strict) {
18730 isNowValid = isNowValid && flags.charsLeftOver === 0 && flags.unusedTokens.length === 0 && flags.bigHour === undefined;
18731 }
18732
18733 if (Object.isFrozen == null || !Object.isFrozen(m)) {
18734 m._isValid = isNowValid;
18735 } else {
18736 return isNowValid;
18737 }
18738 }
18739
18740 return m._isValid;
18741 }
18742
18743 function createInvalid(flags) {
18744 var m = createUTC(NaN);
18745
18746 if (flags != null) {
18747 extend(getParsingFlags(m), flags);
18748 } else {
18749 getParsingFlags(m).userInvalidated = true;
18750 }
18751
18752 return m;
18753 } // Plugins that add properties should also add the key here (null value),
18754 // so we can properly clone ourselves.
18755
18756
18757 var momentProperties = hooks.momentProperties = [];
18758
18759 function copyConfig(to, from) {
18760 var i, prop, val;
18761
18762 if (!isUndefined(from._isAMomentObject)) {
18763 to._isAMomentObject = from._isAMomentObject;
18764 }
18765
18766 if (!isUndefined(from._i)) {
18767 to._i = from._i;
18768 }
18769
18770 if (!isUndefined(from._f)) {
18771 to._f = from._f;
18772 }
18773
18774 if (!isUndefined(from._l)) {
18775 to._l = from._l;
18776 }
18777
18778 if (!isUndefined(from._strict)) {
18779 to._strict = from._strict;
18780 }
18781
18782 if (!isUndefined(from._tzm)) {
18783 to._tzm = from._tzm;
18784 }
18785
18786 if (!isUndefined(from._isUTC)) {
18787 to._isUTC = from._isUTC;
18788 }
18789
18790 if (!isUndefined(from._offset)) {
18791 to._offset = from._offset;
18792 }
18793
18794 if (!isUndefined(from._pf)) {
18795 to._pf = getParsingFlags(from);
18796 }
18797
18798 if (!isUndefined(from._locale)) {
18799 to._locale = from._locale;
18800 }
18801
18802 if (momentProperties.length > 0) {
18803 for (i = 0; i < momentProperties.length; i++) {
18804 prop = momentProperties[i];
18805 val = from[prop];
18806
18807 if (!isUndefined(val)) {
18808 to[prop] = val;
18809 }
18810 }
18811 }
18812
18813 return to;
18814 }
18815
18816 var updateInProgress = false; // Moment prototype object
18817
18818 function Moment(config) {
18819 copyConfig(this, config);
18820 this._d = new Date(config._d != null ? config._d.getTime() : NaN);
18821
18822 if (!this.isValid()) {
18823 this._d = new Date(NaN);
18824 } // Prevent infinite loop in case updateOffset creates new moment
18825 // objects.
18826
18827
18828 if (updateInProgress === false) {
18829 updateInProgress = true;
18830 hooks.updateOffset(this);
18831 updateInProgress = false;
18832 }
18833 }
18834
18835 function isMoment(obj) {
18836 return obj instanceof Moment || obj != null && obj._isAMomentObject != null;
18837 }
18838
18839 function absFloor(number) {
18840 if (number < 0) {
18841 // -0 -> 0
18842 return Math.ceil(number) || 0;
18843 } else {
18844 return Math.floor(number);
18845 }
18846 }
18847
18848 function toInt(argumentForCoercion) {
18849 var coercedNumber = +argumentForCoercion,
18850 value = 0;
18851
18852 if (coercedNumber !== 0 && isFinite(coercedNumber)) {
18853 value = absFloor(coercedNumber);
18854 }
18855
18856 return value;
18857 } // compare two arrays, return the number of differences
18858
18859
18860 function compareArrays(array1, array2, dontConvert) {
18861 var len = Math.min(array1.length, array2.length),
18862 lengthDiff = Math.abs(array1.length - array2.length),
18863 diffs = 0,
18864 i;
18865
18866 for (i = 0; i < len; i++) {
18867 if (dontConvert && array1[i] !== array2[i] || !dontConvert && toInt(array1[i]) !== toInt(array2[i])) {
18868 diffs++;
18869 }
18870 }
18871
18872 return diffs + lengthDiff;
18873 }
18874
18875 function warn(msg) {
18876 if (hooks.suppressDeprecationWarnings === false && typeof console !== 'undefined' && console.warn) {
18877 console.warn('Deprecation warning: ' + msg);
18878 }
18879 }
18880
18881 function deprecate(msg, fn) {
18882 var firstTime = true;
18883 return extend(function () {
18884 if (hooks.deprecationHandler != null) {
18885 hooks.deprecationHandler(null, msg);
18886 }
18887
18888 if (firstTime) {
18889 var args = [];
18890 var arg;
18891
18892 for (var i = 0; i < arguments.length; i++) {
18893 arg = '';
18894
18895 if (typeof arguments[i] === 'object') {
18896 arg += '\n[' + i + '] ';
18897
18898 for (var key in arguments[0]) {
18899 arg += key + ': ' + arguments[0][key] + ', ';
18900 }
18901
18902 arg = arg.slice(0, -2); // Remove trailing comma and space
18903 } else {
18904 arg = arguments[i];
18905 }
18906
18907 args.push(arg);
18908 }
18909
18910 warn(msg + '\nArguments: ' + Array.prototype.slice.call(args).join('') + '\n' + new Error().stack);
18911 firstTime = false;
18912 }
18913
18914 return fn.apply(this, arguments);
18915 }, fn);
18916 }
18917
18918 var deprecations = {};
18919
18920 function deprecateSimple(name, msg) {
18921 if (hooks.deprecationHandler != null) {
18922 hooks.deprecationHandler(name, msg);
18923 }
18924
18925 if (!deprecations[name]) {
18926 warn(msg);
18927 deprecations[name] = true;
18928 }
18929 }
18930
18931 hooks.suppressDeprecationWarnings = false;
18932 hooks.deprecationHandler = null;
18933
18934 function isFunction(input) {
18935 return input instanceof Function || Object.prototype.toString.call(input) === '[object Function]';
18936 }
18937
18938 function set(config) {
18939 var prop, i;
18940
18941 for (i in config) {
18942 prop = config[i];
18943
18944 if (isFunction(prop)) {
18945 this[i] = prop;
18946 } else {
18947 this['_' + i] = prop;
18948 }
18949 }
18950
18951 this._config = config; // Lenient ordinal parsing accepts just a number in addition to
18952 // number + (possibly) stuff coming from _dayOfMonthOrdinalParse.
18953 // TODO: Remove "ordinalParse" fallback in next major release.
18954
18955 this._dayOfMonthOrdinalParseLenient = new RegExp((this._dayOfMonthOrdinalParse.source || this._ordinalParse.source) + '|' + /\d{1,2}/.source);
18956 }
18957
18958 function mergeConfigs(parentConfig, childConfig) {
18959 var res = extend({}, parentConfig),
18960 prop;
18961
18962 for (prop in childConfig) {
18963 if (hasOwnProp(childConfig, prop)) {
18964 if (isObject(parentConfig[prop]) && isObject(childConfig[prop])) {
18965 res[prop] = {};
18966 extend(res[prop], parentConfig[prop]);
18967 extend(res[prop], childConfig[prop]);
18968 } else if (childConfig[prop] != null) {
18969 res[prop] = childConfig[prop];
18970 } else {
18971 delete res[prop];
18972 }
18973 }
18974 }
18975
18976 for (prop in parentConfig) {
18977 if (hasOwnProp(parentConfig, prop) && !hasOwnProp(childConfig, prop) && isObject(parentConfig[prop])) {
18978 // make sure changes to properties don't modify parent config
18979 res[prop] = extend({}, res[prop]);
18980 }
18981 }
18982
18983 return res;
18984 }
18985
18986 function Locale(config) {
18987 if (config != null) {
18988 this.set(config);
18989 }
18990 }
18991
18992 var keys;
18993
18994 if (Object.keys) {
18995 keys = Object.keys;
18996 } else {
18997 keys = function (obj) {
18998 var i,
18999 res = [];
19000
19001 for (i in obj) {
19002 if (hasOwnProp(obj, i)) {
19003 res.push(i);
19004 }
19005 }
19006
19007 return res;
19008 };
19009 }
19010
19011 var defaultCalendar = {
19012 sameDay: '[Today at] LT',
19013 nextDay: '[Tomorrow at] LT',
19014 nextWeek: 'dddd [at] LT',
19015 lastDay: '[Yesterday at] LT',
19016 lastWeek: '[Last] dddd [at] LT',
19017 sameElse: 'L'
19018 };
19019
19020 function calendar(key, mom, now) {
19021 var output = this._calendar[key] || this._calendar['sameElse'];
19022 return isFunction(output) ? output.call(mom, now) : output;
19023 }
19024
19025 var defaultLongDateFormat = {
19026 LTS: 'h:mm:ss A',
19027 LT: 'h:mm A',
19028 L: 'MM/DD/YYYY',
19029 LL: 'MMMM D, YYYY',
19030 LLL: 'MMMM D, YYYY h:mm A',
19031 LLLL: 'dddd, MMMM D, YYYY h:mm A'
19032 };
19033
19034 function longDateFormat(key) {
19035 var format = this._longDateFormat[key],
19036 formatUpper = this._longDateFormat[key.toUpperCase()];
19037
19038 if (format || !formatUpper) {
19039 return format;
19040 }
19041
19042 this._longDateFormat[key] = formatUpper.replace(/MMMM|MM|DD|dddd/g, function (val) {
19043 return val.slice(1);
19044 });
19045 return this._longDateFormat[key];
19046 }
19047
19048 var defaultInvalidDate = 'Invalid date';
19049
19050 function invalidDate() {
19051 return this._invalidDate;
19052 }
19053
19054 var defaultOrdinal = '%d';
19055 var defaultDayOfMonthOrdinalParse = /\d{1,2}/;
19056
19057 function ordinal(number) {
19058 return this._ordinal.replace('%d', number);
19059 }
19060
19061 var defaultRelativeTime = {
19062 future: 'in %s',
19063 past: '%s ago',
19064 s: 'a few seconds',
19065 ss: '%d seconds',
19066 m: 'a minute',
19067 mm: '%d minutes',
19068 h: 'an hour',
19069 hh: '%d hours',
19070 d: 'a day',
19071 dd: '%d days',
19072 M: 'a month',
19073 MM: '%d months',
19074 y: 'a year',
19075 yy: '%d years'
19076 };
19077
19078 function relativeTime(number, withoutSuffix, string, isFuture) {
19079 var output = this._relativeTime[string];
19080 return isFunction(output) ? output(number, withoutSuffix, string, isFuture) : output.replace(/%d/i, number);
19081 }
19082
19083 function pastFuture(diff, output) {
19084 var format = this._relativeTime[diff > 0 ? 'future' : 'past'];
19085 return isFunction(format) ? format(output) : format.replace(/%s/i, output);
19086 }
19087
19088 var aliases = {};
19089
19090 function addUnitAlias(unit, shorthand) {
19091 var lowerCase = unit.toLowerCase();
19092 aliases[lowerCase] = aliases[lowerCase + 's'] = aliases[shorthand] = unit;
19093 }
19094
19095 function normalizeUnits(units) {
19096 return typeof units === 'string' ? aliases[units] || aliases[units.toLowerCase()] : undefined;
19097 }
19098
19099 function normalizeObjectUnits(inputObject) {
19100 var normalizedInput = {},
19101 normalizedProp,
19102 prop;
19103
19104 for (prop in inputObject) {
19105 if (hasOwnProp(inputObject, prop)) {
19106 normalizedProp = normalizeUnits(prop);
19107
19108 if (normalizedProp) {
19109 normalizedInput[normalizedProp] = inputObject[prop];
19110 }
19111 }
19112 }
19113
19114 return normalizedInput;
19115 }
19116
19117 var priorities = {};
19118
19119 function addUnitPriority(unit, priority) {
19120 priorities[unit] = priority;
19121 }
19122
19123 function getPrioritizedUnits(unitsObj) {
19124 var units = [];
19125
19126 for (var u in unitsObj) {
19127 units.push({
19128 unit: u,
19129 priority: priorities[u]
19130 });
19131 }
19132
19133 units.sort(function (a, b) {
19134 return a.priority - b.priority;
19135 });
19136 return units;
19137 }
19138
19139 function zeroFill(number, targetLength, forceSign) {
19140 var absNumber = '' + Math.abs(number),
19141 zerosToFill = targetLength - absNumber.length,
19142 sign = number >= 0;
19143 return (sign ? forceSign ? '+' : '' : '-') + Math.pow(10, Math.max(0, zerosToFill)).toString().substr(1) + absNumber;
19144 }
19145
19146 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;
19147 var localFormattingTokens = /(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g;
19148 var formatFunctions = {};
19149 var formatTokenFunctions = {}; // token: 'M'
19150 // padded: ['MM', 2]
19151 // ordinal: 'Mo'
19152 // callback: function () { this.month() + 1 }
19153
19154 function addFormatToken(token, padded, ordinal, callback) {
19155 var func = callback;
19156
19157 if (typeof callback === 'string') {
19158 func = function () {
19159 return this[callback]();
19160 };
19161 }
19162
19163 if (token) {
19164 formatTokenFunctions[token] = func;
19165 }
19166
19167 if (padded) {
19168 formatTokenFunctions[padded[0]] = function () {
19169 return zeroFill(func.apply(this, arguments), padded[1], padded[2]);
19170 };
19171 }
19172
19173 if (ordinal) {
19174 formatTokenFunctions[ordinal] = function () {
19175 return this.localeData().ordinal(func.apply(this, arguments), token);
19176 };
19177 }
19178 }
19179
19180 function removeFormattingTokens(input) {
19181 if (input.match(/\[[\s\S]/)) {
19182 return input.replace(/^\[|\]$/g, '');
19183 }
19184
19185 return input.replace(/\\/g, '');
19186 }
19187
19188 function makeFormatFunction(format) {
19189 var array = format.match(formattingTokens),
19190 i,
19191 length;
19192
19193 for (i = 0, length = array.length; i < length; i++) {
19194 if (formatTokenFunctions[array[i]]) {
19195 array[i] = formatTokenFunctions[array[i]];
19196 } else {
19197 array[i] = removeFormattingTokens(array[i]);
19198 }
19199 }
19200
19201 return function (mom) {
19202 var output = '',
19203 i;
19204
19205 for (i = 0; i < length; i++) {
19206 output += isFunction(array[i]) ? array[i].call(mom, format) : array[i];
19207 }
19208
19209 return output;
19210 };
19211 } // format date using native date object
19212
19213
19214 function formatMoment(m, format) {
19215 if (!m.isValid()) {
19216 return m.localeData().invalidDate();
19217 }
19218
19219 format = expandFormat(format, m.localeData());
19220 formatFunctions[format] = formatFunctions[format] || makeFormatFunction(format);
19221 return formatFunctions[format](m);
19222 }
19223
19224 function expandFormat(format, locale) {
19225 var i = 5;
19226
19227 function replaceLongDateFormatTokens(input) {
19228 return locale.longDateFormat(input) || input;
19229 }
19230
19231 localFormattingTokens.lastIndex = 0;
19232
19233 while (i >= 0 && localFormattingTokens.test(format)) {
19234 format = format.replace(localFormattingTokens, replaceLongDateFormatTokens);
19235 localFormattingTokens.lastIndex = 0;
19236 i -= 1;
19237 }
19238
19239 return format;
19240 }
19241
19242 var match1 = /\d/; // 0 - 9
19243
19244 var match2 = /\d\d/; // 00 - 99
19245
19246 var match3 = /\d{3}/; // 000 - 999
19247
19248 var match4 = /\d{4}/; // 0000 - 9999
19249
19250 var match6 = /[+-]?\d{6}/; // -999999 - 999999
19251
19252 var match1to2 = /\d\d?/; // 0 - 99
19253
19254 var match3to4 = /\d\d\d\d?/; // 999 - 9999
19255
19256 var match5to6 = /\d\d\d\d\d\d?/; // 99999 - 999999
19257
19258 var match1to3 = /\d{1,3}/; // 0 - 999
19259
19260 var match1to4 = /\d{1,4}/; // 0 - 9999
19261
19262 var match1to6 = /[+-]?\d{1,6}/; // -999999 - 999999
19263
19264 var matchUnsigned = /\d+/; // 0 - inf
19265
19266 var matchSigned = /[+-]?\d+/; // -inf - inf
19267
19268 var matchOffset = /Z|[+-]\d\d:?\d\d/gi; // +00:00 -00:00 +0000 -0000 or Z
19269
19270 var matchShortOffset = /Z|[+-]\d\d(?::?\d\d)?/gi; // +00 -00 +00:00 -00:00 +0000 -0000 or Z
19271
19272 var matchTimestamp = /[+-]?\d+(\.\d{1,3})?/; // 123456789 123456789.123
19273 // any word (or two) characters or numbers including two/three word month in arabic.
19274 // includes scottish gaelic two word and hyphenated months
19275
19276 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;
19277 var regexes = {};
19278
19279 function addRegexToken(token, regex, strictRegex) {
19280 regexes[token] = isFunction(regex) ? regex : function (isStrict, localeData) {
19281 return isStrict && strictRegex ? strictRegex : regex;
19282 };
19283 }
19284
19285 function getParseRegexForToken(token, config) {
19286 if (!hasOwnProp(regexes, token)) {
19287 return new RegExp(unescapeFormat(token));
19288 }
19289
19290 return regexes[token](config._strict, config._locale);
19291 } // Code from http://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript
19292
19293
19294 function unescapeFormat(s) {
19295 return regexEscape(s.replace('\\', '').replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g, function (matched, p1, p2, p3, p4) {
19296 return p1 || p2 || p3 || p4;
19297 }));
19298 }
19299
19300 function regexEscape(s) {
19301 return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
19302 }
19303
19304 var tokens = {};
19305
19306 function addParseToken(token, callback) {
19307 var i,
19308 func = callback;
19309
19310 if (typeof token === 'string') {
19311 token = [token];
19312 }
19313
19314 if (isNumber(callback)) {
19315 func = function (input, array) {
19316 array[callback] = toInt(input);
19317 };
19318 }
19319
19320 for (i = 0; i < token.length; i++) {
19321 tokens[token[i]] = func;
19322 }
19323 }
19324
19325 function addWeekParseToken(token, callback) {
19326 addParseToken(token, function (input, array, config, token) {
19327 config._w = config._w || {};
19328 callback(input, config._w, config, token);
19329 });
19330 }
19331
19332 function addTimeToArrayFromToken(token, input, config) {
19333 if (input != null && hasOwnProp(tokens, token)) {
19334 tokens[token](input, config._a, config, token);
19335 }
19336 }
19337
19338 var YEAR = 0;
19339 var MONTH = 1;
19340 var DATE = 2;
19341 var HOUR = 3;
19342 var MINUTE = 4;
19343 var SECOND = 5;
19344 var MILLISECOND = 6;
19345 var WEEK = 7;
19346 var WEEKDAY = 8; // FORMATTING
19347
19348 addFormatToken('Y', 0, 0, function () {
19349 var y = this.year();
19350 return y <= 9999 ? '' + y : '+' + y;
19351 });
19352 addFormatToken(0, ['YY', 2], 0, function () {
19353 return this.year() % 100;
19354 });
19355 addFormatToken(0, ['YYYY', 4], 0, 'year');
19356 addFormatToken(0, ['YYYYY', 5], 0, 'year');
19357 addFormatToken(0, ['YYYYYY', 6, true], 0, 'year'); // ALIASES
19358
19359 addUnitAlias('year', 'y'); // PRIORITIES
19360
19361 addUnitPriority('year', 1); // PARSING
19362
19363 addRegexToken('Y', matchSigned);
19364 addRegexToken('YY', match1to2, match2);
19365 addRegexToken('YYYY', match1to4, match4);
19366 addRegexToken('YYYYY', match1to6, match6);
19367 addRegexToken('YYYYYY', match1to6, match6);
19368 addParseToken(['YYYYY', 'YYYYYY'], YEAR);
19369 addParseToken('YYYY', function (input, array) {
19370 array[YEAR] = input.length === 2 ? hooks.parseTwoDigitYear(input) : toInt(input);
19371 });
19372 addParseToken('YY', function (input, array) {
19373 array[YEAR] = hooks.parseTwoDigitYear(input);
19374 });
19375 addParseToken('Y', function (input, array) {
19376 array[YEAR] = parseInt(input, 10);
19377 }); // HELPERS
19378
19379 function daysInYear(year) {
19380 return isLeapYear(year) ? 366 : 365;
19381 }
19382
19383 function isLeapYear(year) {
19384 return year % 4 === 0 && year % 100 !== 0 || year % 400 === 0;
19385 } // HOOKS
19386
19387
19388 hooks.parseTwoDigitYear = function (input) {
19389 return toInt(input) + (toInt(input) > 68 ? 1900 : 2000);
19390 }; // MOMENTS
19391
19392
19393 var getSetYear = makeGetSet('FullYear', true);
19394
19395 function getIsLeapYear() {
19396 return isLeapYear(this.year());
19397 }
19398
19399 function makeGetSet(unit, keepTime) {
19400 return function (value) {
19401 if (value != null) {
19402 set$1(this, unit, value);
19403 hooks.updateOffset(this, keepTime);
19404 return this;
19405 } else {
19406 return get(this, unit);
19407 }
19408 };
19409 }
19410
19411 function get(mom, unit) {
19412 return mom.isValid() ? mom._d['get' + (mom._isUTC ? 'UTC' : '') + unit]() : NaN;
19413 }
19414
19415 function set$1(mom, unit, value) {
19416 if (mom.isValid() && !isNaN(value)) {
19417 if (unit === 'FullYear' && isLeapYear(mom.year()) && mom.month() === 1 && mom.date() === 29) {
19418 mom._d['set' + (mom._isUTC ? 'UTC' : '') + unit](value, mom.month(), daysInMonth(value, mom.month()));
19419 } else {
19420 mom._d['set' + (mom._isUTC ? 'UTC' : '') + unit](value);
19421 }
19422 }
19423 } // MOMENTS
19424
19425
19426 function stringGet(units) {
19427 units = normalizeUnits(units);
19428
19429 if (isFunction(this[units])) {
19430 return this[units]();
19431 }
19432
19433 return this;
19434 }
19435
19436 function stringSet(units, value) {
19437 if (typeof units === 'object') {
19438 units = normalizeObjectUnits(units);
19439 var prioritized = getPrioritizedUnits(units);
19440
19441 for (var i = 0; i < prioritized.length; i++) {
19442 this[prioritized[i].unit](units[prioritized[i].unit]);
19443 }
19444 } else {
19445 units = normalizeUnits(units);
19446
19447 if (isFunction(this[units])) {
19448 return this[units](value);
19449 }
19450 }
19451
19452 return this;
19453 }
19454
19455 function mod(n, x) {
19456 return (n % x + x) % x;
19457 }
19458
19459 var indexOf;
19460
19461 if (Array.prototype.indexOf) {
19462 indexOf = Array.prototype.indexOf;
19463 } else {
19464 indexOf = function (o) {
19465 // I know
19466 var i;
19467
19468 for (i = 0; i < this.length; ++i) {
19469 if (this[i] === o) {
19470 return i;
19471 }
19472 }
19473
19474 return -1;
19475 };
19476 }
19477
19478 function daysInMonth(year, month) {
19479 if (isNaN(year) || isNaN(month)) {
19480 return NaN;
19481 }
19482
19483 var modMonth = mod(month, 12);
19484 year += (month - modMonth) / 12;
19485 return modMonth === 1 ? isLeapYear(year) ? 29 : 28 : 31 - modMonth % 7 % 2;
19486 } // FORMATTING
19487
19488
19489 addFormatToken('M', ['MM', 2], 'Mo', function () {
19490 return this.month() + 1;
19491 });
19492 addFormatToken('MMM', 0, 0, function (format) {
19493 return this.localeData().monthsShort(this, format);
19494 });
19495 addFormatToken('MMMM', 0, 0, function (format) {
19496 return this.localeData().months(this, format);
19497 }); // ALIASES
19498
19499 addUnitAlias('month', 'M'); // PRIORITY
19500
19501 addUnitPriority('month', 8); // PARSING
19502
19503 addRegexToken('M', match1to2);
19504 addRegexToken('MM', match1to2, match2);
19505 addRegexToken('MMM', function (isStrict, locale) {
19506 return locale.monthsShortRegex(isStrict);
19507 });
19508 addRegexToken('MMMM', function (isStrict, locale) {
19509 return locale.monthsRegex(isStrict);
19510 });
19511 addParseToken(['M', 'MM'], function (input, array) {
19512 array[MONTH] = toInt(input) - 1;
19513 });
19514 addParseToken(['MMM', 'MMMM'], function (input, array, config, token) {
19515 var month = config._locale.monthsParse(input, token, config._strict); // if we didn't find a month name, mark the date as invalid.
19516
19517
19518 if (month != null) {
19519 array[MONTH] = month;
19520 } else {
19521 getParsingFlags(config).invalidMonth = input;
19522 }
19523 }); // LOCALES
19524
19525 var MONTHS_IN_FORMAT = /D[oD]?(\[[^\[\]]*\]|\s)+MMMM?/;
19526 var defaultLocaleMonths = 'January_February_March_April_May_June_July_August_September_October_November_December'.split('_');
19527
19528 function localeMonths(m, format) {
19529 if (!m) {
19530 return isArray(this._months) ? this._months : this._months['standalone'];
19531 }
19532
19533 return isArray(this._months) ? this._months[m.month()] : this._months[(this._months.isFormat || MONTHS_IN_FORMAT).test(format) ? 'format' : 'standalone'][m.month()];
19534 }
19535
19536 var defaultLocaleMonthsShort = 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_');
19537
19538 function localeMonthsShort(m, format) {
19539 if (!m) {
19540 return isArray(this._monthsShort) ? this._monthsShort : this._monthsShort['standalone'];
19541 }
19542
19543 return isArray(this._monthsShort) ? this._monthsShort[m.month()] : this._monthsShort[MONTHS_IN_FORMAT.test(format) ? 'format' : 'standalone'][m.month()];
19544 }
19545
19546 function handleStrictParse(monthName, format, strict) {
19547 var i,
19548 ii,
19549 mom,
19550 llc = monthName.toLocaleLowerCase();
19551
19552 if (!this._monthsParse) {
19553 // this is not used
19554 this._monthsParse = [];
19555 this._longMonthsParse = [];
19556 this._shortMonthsParse = [];
19557
19558 for (i = 0; i < 12; ++i) {
19559 mom = createUTC([2000, i]);
19560 this._shortMonthsParse[i] = this.monthsShort(mom, '').toLocaleLowerCase();
19561 this._longMonthsParse[i] = this.months(mom, '').toLocaleLowerCase();
19562 }
19563 }
19564
19565 if (strict) {
19566 if (format === 'MMM') {
19567 ii = indexOf.call(this._shortMonthsParse, llc);
19568 return ii !== -1 ? ii : null;
19569 } else {
19570 ii = indexOf.call(this._longMonthsParse, llc);
19571 return ii !== -1 ? ii : null;
19572 }
19573 } else {
19574 if (format === 'MMM') {
19575 ii = indexOf.call(this._shortMonthsParse, llc);
19576
19577 if (ii !== -1) {
19578 return ii;
19579 }
19580
19581 ii = indexOf.call(this._longMonthsParse, llc);
19582 return ii !== -1 ? ii : null;
19583 } else {
19584 ii = indexOf.call(this._longMonthsParse, llc);
19585
19586 if (ii !== -1) {
19587 return ii;
19588 }
19589
19590 ii = indexOf.call(this._shortMonthsParse, llc);
19591 return ii !== -1 ? ii : null;
19592 }
19593 }
19594 }
19595
19596 function localeMonthsParse(monthName, format, strict) {
19597 var i, mom, regex;
19598
19599 if (this._monthsParseExact) {
19600 return handleStrictParse.call(this, monthName, format, strict);
19601 }
19602
19603 if (!this._monthsParse) {
19604 this._monthsParse = [];
19605 this._longMonthsParse = [];
19606 this._shortMonthsParse = [];
19607 } // TODO: add sorting
19608 // Sorting makes sure if one month (or abbr) is a prefix of another
19609 // see sorting in computeMonthsParse
19610
19611
19612 for (i = 0; i < 12; i++) {
19613 // make the regex if we don't have it already
19614 mom = createUTC([2000, i]);
19615
19616 if (strict && !this._longMonthsParse[i]) {
19617 this._longMonthsParse[i] = new RegExp('^' + this.months(mom, '').replace('.', '') + '$', 'i');
19618 this._shortMonthsParse[i] = new RegExp('^' + this.monthsShort(mom, '').replace('.', '') + '$', 'i');
19619 }
19620
19621 if (!strict && !this._monthsParse[i]) {
19622 regex = '^' + this.months(mom, '') + '|^' + this.monthsShort(mom, '');
19623 this._monthsParse[i] = new RegExp(regex.replace('.', ''), 'i');
19624 } // test the regex
19625
19626
19627 if (strict && format === 'MMMM' && this._longMonthsParse[i].test(monthName)) {
19628 return i;
19629 } else if (strict && format === 'MMM' && this._shortMonthsParse[i].test(monthName)) {
19630 return i;
19631 } else if (!strict && this._monthsParse[i].test(monthName)) {
19632 return i;
19633 }
19634 }
19635 } // MOMENTS
19636
19637
19638 function setMonth(mom, value) {
19639 var dayOfMonth;
19640
19641 if (!mom.isValid()) {
19642 // No op
19643 return mom;
19644 }
19645
19646 if (typeof value === 'string') {
19647 if (/^\d+$/.test(value)) {
19648 value = toInt(value);
19649 } else {
19650 value = mom.localeData().monthsParse(value); // TODO: Another silent failure?
19651
19652 if (!isNumber(value)) {
19653 return mom;
19654 }
19655 }
19656 }
19657
19658 dayOfMonth = Math.min(mom.date(), daysInMonth(mom.year(), value));
19659
19660 mom._d['set' + (mom._isUTC ? 'UTC' : '') + 'Month'](value, dayOfMonth);
19661
19662 return mom;
19663 }
19664
19665 function getSetMonth(value) {
19666 if (value != null) {
19667 setMonth(this, value);
19668 hooks.updateOffset(this, true);
19669 return this;
19670 } else {
19671 return get(this, 'Month');
19672 }
19673 }
19674
19675 function getDaysInMonth() {
19676 return daysInMonth(this.year(), this.month());
19677 }
19678
19679 var defaultMonthsShortRegex = matchWord;
19680
19681 function monthsShortRegex(isStrict) {
19682 if (this._monthsParseExact) {
19683 if (!hasOwnProp(this, '_monthsRegex')) {
19684 computeMonthsParse.call(this);
19685 }
19686
19687 if (isStrict) {
19688 return this._monthsShortStrictRegex;
19689 } else {
19690 return this._monthsShortRegex;
19691 }
19692 } else {
19693 if (!hasOwnProp(this, '_monthsShortRegex')) {
19694 this._monthsShortRegex = defaultMonthsShortRegex;
19695 }
19696
19697 return this._monthsShortStrictRegex && isStrict ? this._monthsShortStrictRegex : this._monthsShortRegex;
19698 }
19699 }
19700
19701 var defaultMonthsRegex = matchWord;
19702
19703 function monthsRegex(isStrict) {
19704 if (this._monthsParseExact) {
19705 if (!hasOwnProp(this, '_monthsRegex')) {
19706 computeMonthsParse.call(this);
19707 }
19708
19709 if (isStrict) {
19710 return this._monthsStrictRegex;
19711 } else {
19712 return this._monthsRegex;
19713 }
19714 } else {
19715 if (!hasOwnProp(this, '_monthsRegex')) {
19716 this._monthsRegex = defaultMonthsRegex;
19717 }
19718
19719 return this._monthsStrictRegex && isStrict ? this._monthsStrictRegex : this._monthsRegex;
19720 }
19721 }
19722
19723 function computeMonthsParse() {
19724 function cmpLenRev(a, b) {
19725 return b.length - a.length;
19726 }
19727
19728 var shortPieces = [],
19729 longPieces = [],
19730 mixedPieces = [],
19731 i,
19732 mom;
19733
19734 for (i = 0; i < 12; i++) {
19735 // make the regex if we don't have it already
19736 mom = createUTC([2000, i]);
19737 shortPieces.push(this.monthsShort(mom, ''));
19738 longPieces.push(this.months(mom, ''));
19739 mixedPieces.push(this.months(mom, ''));
19740 mixedPieces.push(this.monthsShort(mom, ''));
19741 } // Sorting makes sure if one month (or abbr) is a prefix of another it
19742 // will match the longer piece.
19743
19744
19745 shortPieces.sort(cmpLenRev);
19746 longPieces.sort(cmpLenRev);
19747 mixedPieces.sort(cmpLenRev);
19748
19749 for (i = 0; i < 12; i++) {
19750 shortPieces[i] = regexEscape(shortPieces[i]);
19751 longPieces[i] = regexEscape(longPieces[i]);
19752 }
19753
19754 for (i = 0; i < 24; i++) {
19755 mixedPieces[i] = regexEscape(mixedPieces[i]);
19756 }
19757
19758 this._monthsRegex = new RegExp('^(' + mixedPieces.join('|') + ')', 'i');
19759 this._monthsShortRegex = this._monthsRegex;
19760 this._monthsStrictRegex = new RegExp('^(' + longPieces.join('|') + ')', 'i');
19761 this._monthsShortStrictRegex = new RegExp('^(' + shortPieces.join('|') + ')', 'i');
19762 }
19763
19764 function createDate(y, m, d, h, M, s, ms) {
19765 // can't just apply() to create a date:
19766 // https://stackoverflow.com/q/181348
19767 var date; // the date constructor remaps years 0-99 to 1900-1999
19768
19769 if (y < 100 && y >= 0) {
19770 // preserve leap years using a full 400 year cycle, then reset
19771 date = new Date(y + 400, m, d, h, M, s, ms);
19772
19773 if (isFinite(date.getFullYear())) {
19774 date.setFullYear(y);
19775 }
19776 } else {
19777 date = new Date(y, m, d, h, M, s, ms);
19778 }
19779
19780 return date;
19781 }
19782
19783 function createUTCDate(y) {
19784 var date; // the Date.UTC function remaps years 0-99 to 1900-1999
19785
19786 if (y < 100 && y >= 0) {
19787 var args = Array.prototype.slice.call(arguments); // preserve leap years using a full 400 year cycle, then reset
19788
19789 args[0] = y + 400;
19790 date = new Date(Date.UTC.apply(null, args));
19791
19792 if (isFinite(date.getUTCFullYear())) {
19793 date.setUTCFullYear(y);
19794 }
19795 } else {
19796 date = new Date(Date.UTC.apply(null, arguments));
19797 }
19798
19799 return date;
19800 } // start-of-first-week - start-of-year
19801
19802
19803 function firstWeekOffset(year, dow, doy) {
19804 var // first-week day -- which january is always in the first week (4 for iso, 1 for other)
19805 fwd = 7 + dow - doy,
19806 // first-week day local weekday -- which local weekday is fwd
19807 fwdlw = (7 + createUTCDate(year, 0, fwd).getUTCDay() - dow) % 7;
19808 return -fwdlw + fwd - 1;
19809 } // https://en.wikipedia.org/wiki/ISO_week_date#Calculating_a_date_given_the_year.2C_week_number_and_weekday
19810
19811
19812 function dayOfYearFromWeeks(year, week, weekday, dow, doy) {
19813 var localWeekday = (7 + weekday - dow) % 7,
19814 weekOffset = firstWeekOffset(year, dow, doy),
19815 dayOfYear = 1 + 7 * (week - 1) + localWeekday + weekOffset,
19816 resYear,
19817 resDayOfYear;
19818
19819 if (dayOfYear <= 0) {
19820 resYear = year - 1;
19821 resDayOfYear = daysInYear(resYear) + dayOfYear;
19822 } else if (dayOfYear > daysInYear(year)) {
19823 resYear = year + 1;
19824 resDayOfYear = dayOfYear - daysInYear(year);
19825 } else {
19826 resYear = year;
19827 resDayOfYear = dayOfYear;
19828 }
19829
19830 return {
19831 year: resYear,
19832 dayOfYear: resDayOfYear
19833 };
19834 }
19835
19836 function weekOfYear(mom, dow, doy) {
19837 var weekOffset = firstWeekOffset(mom.year(), dow, doy),
19838 week = Math.floor((mom.dayOfYear() - weekOffset - 1) / 7) + 1,
19839 resWeek,
19840 resYear;
19841
19842 if (week < 1) {
19843 resYear = mom.year() - 1;
19844 resWeek = week + weeksInYear(resYear, dow, doy);
19845 } else if (week > weeksInYear(mom.year(), dow, doy)) {
19846 resWeek = week - weeksInYear(mom.year(), dow, doy);
19847 resYear = mom.year() + 1;
19848 } else {
19849 resYear = mom.year();
19850 resWeek = week;
19851 }
19852
19853 return {
19854 week: resWeek,
19855 year: resYear
19856 };
19857 }
19858
19859 function weeksInYear(year, dow, doy) {
19860 var weekOffset = firstWeekOffset(year, dow, doy),
19861 weekOffsetNext = firstWeekOffset(year + 1, dow, doy);
19862 return (daysInYear(year) - weekOffset + weekOffsetNext) / 7;
19863 } // FORMATTING
19864
19865
19866 addFormatToken('w', ['ww', 2], 'wo', 'week');
19867 addFormatToken('W', ['WW', 2], 'Wo', 'isoWeek'); // ALIASES
19868
19869 addUnitAlias('week', 'w');
19870 addUnitAlias('isoWeek', 'W'); // PRIORITIES
19871
19872 addUnitPriority('week', 5);
19873 addUnitPriority('isoWeek', 5); // PARSING
19874
19875 addRegexToken('w', match1to2);
19876 addRegexToken('ww', match1to2, match2);
19877 addRegexToken('W', match1to2);
19878 addRegexToken('WW', match1to2, match2);
19879 addWeekParseToken(['w', 'ww', 'W', 'WW'], function (input, week, config, token) {
19880 week[token.substr(0, 1)] = toInt(input);
19881 }); // HELPERS
19882 // LOCALES
19883
19884 function localeWeek(mom) {
19885 return weekOfYear(mom, this._week.dow, this._week.doy).week;
19886 }
19887
19888 var defaultLocaleWeek = {
19889 dow: 0,
19890 // Sunday is the first day of the week.
19891 doy: 6 // The week that contains Jan 6th is the first week of the year.
19892
19893 };
19894
19895 function localeFirstDayOfWeek() {
19896 return this._week.dow;
19897 }
19898
19899 function localeFirstDayOfYear() {
19900 return this._week.doy;
19901 } // MOMENTS
19902
19903
19904 function getSetWeek(input) {
19905 var week = this.localeData().week(this);
19906 return input == null ? week : this.add((input - week) * 7, 'd');
19907 }
19908
19909 function getSetISOWeek(input) {
19910 var week = weekOfYear(this, 1, 4).week;
19911 return input == null ? week : this.add((input - week) * 7, 'd');
19912 } // FORMATTING
19913
19914
19915 addFormatToken('d', 0, 'do', 'day');
19916 addFormatToken('dd', 0, 0, function (format) {
19917 return this.localeData().weekdaysMin(this, format);
19918 });
19919 addFormatToken('ddd', 0, 0, function (format) {
19920 return this.localeData().weekdaysShort(this, format);
19921 });
19922 addFormatToken('dddd', 0, 0, function (format) {
19923 return this.localeData().weekdays(this, format);
19924 });
19925 addFormatToken('e', 0, 0, 'weekday');
19926 addFormatToken('E', 0, 0, 'isoWeekday'); // ALIASES
19927
19928 addUnitAlias('day', 'd');
19929 addUnitAlias('weekday', 'e');
19930 addUnitAlias('isoWeekday', 'E'); // PRIORITY
19931
19932 addUnitPriority('day', 11);
19933 addUnitPriority('weekday', 11);
19934 addUnitPriority('isoWeekday', 11); // PARSING
19935
19936 addRegexToken('d', match1to2);
19937 addRegexToken('e', match1to2);
19938 addRegexToken('E', match1to2);
19939 addRegexToken('dd', function (isStrict, locale) {
19940 return locale.weekdaysMinRegex(isStrict);
19941 });
19942 addRegexToken('ddd', function (isStrict, locale) {
19943 return locale.weekdaysShortRegex(isStrict);
19944 });
19945 addRegexToken('dddd', function (isStrict, locale) {
19946 return locale.weekdaysRegex(isStrict);
19947 });
19948 addWeekParseToken(['dd', 'ddd', 'dddd'], function (input, week, config, token) {
19949 var weekday = config._locale.weekdaysParse(input, token, config._strict); // if we didn't get a weekday name, mark the date as invalid
19950
19951
19952 if (weekday != null) {
19953 week.d = weekday;
19954 } else {
19955 getParsingFlags(config).invalidWeekday = input;
19956 }
19957 });
19958 addWeekParseToken(['d', 'e', 'E'], function (input, week, config, token) {
19959 week[token] = toInt(input);
19960 }); // HELPERS
19961
19962 function parseWeekday(input, locale) {
19963 if (typeof input !== 'string') {
19964 return input;
19965 }
19966
19967 if (!isNaN(input)) {
19968 return parseInt(input, 10);
19969 }
19970
19971 input = locale.weekdaysParse(input);
19972
19973 if (typeof input === 'number') {
19974 return input;
19975 }
19976
19977 return null;
19978 }
19979
19980 function parseIsoWeekday(input, locale) {
19981 if (typeof input === 'string') {
19982 return locale.weekdaysParse(input) % 7 || 7;
19983 }
19984
19985 return isNaN(input) ? null : input;
19986 } // LOCALES
19987
19988
19989 function shiftWeekdays(ws, n) {
19990 return ws.slice(n, 7).concat(ws.slice(0, n));
19991 }
19992
19993 var defaultLocaleWeekdays = 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_');
19994
19995 function localeWeekdays(m, format) {
19996 var weekdays = isArray(this._weekdays) ? this._weekdays : this._weekdays[m && m !== true && this._weekdays.isFormat.test(format) ? 'format' : 'standalone'];
19997 return m === true ? shiftWeekdays(weekdays, this._week.dow) : m ? weekdays[m.day()] : weekdays;
19998 }
19999
20000 var defaultLocaleWeekdaysShort = 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_');
20001
20002 function localeWeekdaysShort(m) {
20003 return m === true ? shiftWeekdays(this._weekdaysShort, this._week.dow) : m ? this._weekdaysShort[m.day()] : this._weekdaysShort;
20004 }
20005
20006 var defaultLocaleWeekdaysMin = 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_');
20007
20008 function localeWeekdaysMin(m) {
20009 return m === true ? shiftWeekdays(this._weekdaysMin, this._week.dow) : m ? this._weekdaysMin[m.day()] : this._weekdaysMin;
20010 }
20011
20012 function handleStrictParse$1(weekdayName, format, strict) {
20013 var i,
20014 ii,
20015 mom,
20016 llc = weekdayName.toLocaleLowerCase();
20017
20018 if (!this._weekdaysParse) {
20019 this._weekdaysParse = [];
20020 this._shortWeekdaysParse = [];
20021 this._minWeekdaysParse = [];
20022
20023 for (i = 0; i < 7; ++i) {
20024 mom = createUTC([2000, 1]).day(i);
20025 this._minWeekdaysParse[i] = this.weekdaysMin(mom, '').toLocaleLowerCase();
20026 this._shortWeekdaysParse[i] = this.weekdaysShort(mom, '').toLocaleLowerCase();
20027 this._weekdaysParse[i] = this.weekdays(mom, '').toLocaleLowerCase();
20028 }
20029 }
20030
20031 if (strict) {
20032 if (format === 'dddd') {
20033 ii = indexOf.call(this._weekdaysParse, llc);
20034 return ii !== -1 ? ii : null;
20035 } else if (format === 'ddd') {
20036 ii = indexOf.call(this._shortWeekdaysParse, llc);
20037 return ii !== -1 ? ii : null;
20038 } else {
20039 ii = indexOf.call(this._minWeekdaysParse, llc);
20040 return ii !== -1 ? ii : null;
20041 }
20042 } else {
20043 if (format === 'dddd') {
20044 ii = indexOf.call(this._weekdaysParse, llc);
20045
20046 if (ii !== -1) {
20047 return ii;
20048 }
20049
20050 ii = indexOf.call(this._shortWeekdaysParse, llc);
20051
20052 if (ii !== -1) {
20053 return ii;
20054 }
20055
20056 ii = indexOf.call(this._minWeekdaysParse, llc);
20057 return ii !== -1 ? ii : null;
20058 } else if (format === 'ddd') {
20059 ii = indexOf.call(this._shortWeekdaysParse, llc);
20060
20061 if (ii !== -1) {
20062 return ii;
20063 }
20064
20065 ii = indexOf.call(this._weekdaysParse, llc);
20066
20067 if (ii !== -1) {
20068 return ii;
20069 }
20070
20071 ii = indexOf.call(this._minWeekdaysParse, llc);
20072 return ii !== -1 ? ii : null;
20073 } else {
20074 ii = indexOf.call(this._minWeekdaysParse, llc);
20075
20076 if (ii !== -1) {
20077 return ii;
20078 }
20079
20080 ii = indexOf.call(this._weekdaysParse, llc);
20081
20082 if (ii !== -1) {
20083 return ii;
20084 }
20085
20086 ii = indexOf.call(this._shortWeekdaysParse, llc);
20087 return ii !== -1 ? ii : null;
20088 }
20089 }
20090 }
20091
20092 function localeWeekdaysParse(weekdayName, format, strict) {
20093 var i, mom, regex;
20094
20095 if (this._weekdaysParseExact) {
20096 return handleStrictParse$1.call(this, weekdayName, format, strict);
20097 }
20098
20099 if (!this._weekdaysParse) {
20100 this._weekdaysParse = [];
20101 this._minWeekdaysParse = [];
20102 this._shortWeekdaysParse = [];
20103 this._fullWeekdaysParse = [];
20104 }
20105
20106 for (i = 0; i < 7; i++) {
20107 // make the regex if we don't have it already
20108 mom = createUTC([2000, 1]).day(i);
20109
20110 if (strict && !this._fullWeekdaysParse[i]) {
20111 this._fullWeekdaysParse[i] = new RegExp('^' + this.weekdays(mom, '').replace('.', '\\.?') + '$', 'i');
20112 this._shortWeekdaysParse[i] = new RegExp('^' + this.weekdaysShort(mom, '').replace('.', '\\.?') + '$', 'i');
20113 this._minWeekdaysParse[i] = new RegExp('^' + this.weekdaysMin(mom, '').replace('.', '\\.?') + '$', 'i');
20114 }
20115
20116 if (!this._weekdaysParse[i]) {
20117 regex = '^' + this.weekdays(mom, '') + '|^' + this.weekdaysShort(mom, '') + '|^' + this.weekdaysMin(mom, '');
20118 this._weekdaysParse[i] = new RegExp(regex.replace('.', ''), 'i');
20119 } // test the regex
20120
20121
20122 if (strict && format === 'dddd' && this._fullWeekdaysParse[i].test(weekdayName)) {
20123 return i;
20124 } else if (strict && format === 'ddd' && this._shortWeekdaysParse[i].test(weekdayName)) {
20125 return i;
20126 } else if (strict && format === 'dd' && this._minWeekdaysParse[i].test(weekdayName)) {
20127 return i;
20128 } else if (!strict && this._weekdaysParse[i].test(weekdayName)) {
20129 return i;
20130 }
20131 }
20132 } // MOMENTS
20133
20134
20135 function getSetDayOfWeek(input) {
20136 if (!this.isValid()) {
20137 return input != null ? this : NaN;
20138 }
20139
20140 var day = this._isUTC ? this._d.getUTCDay() : this._d.getDay();
20141
20142 if (input != null) {
20143 input = parseWeekday(input, this.localeData());
20144 return this.add(input - day, 'd');
20145 } else {
20146 return day;
20147 }
20148 }
20149
20150 function getSetLocaleDayOfWeek(input) {
20151 if (!this.isValid()) {
20152 return input != null ? this : NaN;
20153 }
20154
20155 var weekday = (this.day() + 7 - this.localeData()._week.dow) % 7;
20156 return input == null ? weekday : this.add(input - weekday, 'd');
20157 }
20158
20159 function getSetISODayOfWeek(input) {
20160 if (!this.isValid()) {
20161 return input != null ? this : NaN;
20162 } // behaves the same as moment#day except
20163 // as a getter, returns 7 instead of 0 (1-7 range instead of 0-6)
20164 // as a setter, sunday should belong to the previous week.
20165
20166
20167 if (input != null) {
20168 var weekday = parseIsoWeekday(input, this.localeData());
20169 return this.day(this.day() % 7 ? weekday : weekday - 7);
20170 } else {
20171 return this.day() || 7;
20172 }
20173 }
20174
20175 var defaultWeekdaysRegex = matchWord;
20176
20177 function weekdaysRegex(isStrict) {
20178 if (this._weekdaysParseExact) {
20179 if (!hasOwnProp(this, '_weekdaysRegex')) {
20180 computeWeekdaysParse.call(this);
20181 }
20182
20183 if (isStrict) {
20184 return this._weekdaysStrictRegex;
20185 } else {
20186 return this._weekdaysRegex;
20187 }
20188 } else {
20189 if (!hasOwnProp(this, '_weekdaysRegex')) {
20190 this._weekdaysRegex = defaultWeekdaysRegex;
20191 }
20192
20193 return this._weekdaysStrictRegex && isStrict ? this._weekdaysStrictRegex : this._weekdaysRegex;
20194 }
20195 }
20196
20197 var defaultWeekdaysShortRegex = matchWord;
20198
20199 function weekdaysShortRegex(isStrict) {
20200 if (this._weekdaysParseExact) {
20201 if (!hasOwnProp(this, '_weekdaysRegex')) {
20202 computeWeekdaysParse.call(this);
20203 }
20204
20205 if (isStrict) {
20206 return this._weekdaysShortStrictRegex;
20207 } else {
20208 return this._weekdaysShortRegex;
20209 }
20210 } else {
20211 if (!hasOwnProp(this, '_weekdaysShortRegex')) {
20212 this._weekdaysShortRegex = defaultWeekdaysShortRegex;
20213 }
20214
20215 return this._weekdaysShortStrictRegex && isStrict ? this._weekdaysShortStrictRegex : this._weekdaysShortRegex;
20216 }
20217 }
20218
20219 var defaultWeekdaysMinRegex = matchWord;
20220
20221 function weekdaysMinRegex(isStrict) {
20222 if (this._weekdaysParseExact) {
20223 if (!hasOwnProp(this, '_weekdaysRegex')) {
20224 computeWeekdaysParse.call(this);
20225 }
20226
20227 if (isStrict) {
20228 return this._weekdaysMinStrictRegex;
20229 } else {
20230 return this._weekdaysMinRegex;
20231 }
20232 } else {
20233 if (!hasOwnProp(this, '_weekdaysMinRegex')) {
20234 this._weekdaysMinRegex = defaultWeekdaysMinRegex;
20235 }
20236
20237 return this._weekdaysMinStrictRegex && isStrict ? this._weekdaysMinStrictRegex : this._weekdaysMinRegex;
20238 }
20239 }
20240
20241 function computeWeekdaysParse() {
20242 function cmpLenRev(a, b) {
20243 return b.length - a.length;
20244 }
20245
20246 var minPieces = [],
20247 shortPieces = [],
20248 longPieces = [],
20249 mixedPieces = [],
20250 i,
20251 mom,
20252 minp,
20253 shortp,
20254 longp;
20255
20256 for (i = 0; i < 7; i++) {
20257 // make the regex if we don't have it already
20258 mom = createUTC([2000, 1]).day(i);
20259 minp = this.weekdaysMin(mom, '');
20260 shortp = this.weekdaysShort(mom, '');
20261 longp = this.weekdays(mom, '');
20262 minPieces.push(minp);
20263 shortPieces.push(shortp);
20264 longPieces.push(longp);
20265 mixedPieces.push(minp);
20266 mixedPieces.push(shortp);
20267 mixedPieces.push(longp);
20268 } // Sorting makes sure if one weekday (or abbr) is a prefix of another it
20269 // will match the longer piece.
20270
20271
20272 minPieces.sort(cmpLenRev);
20273 shortPieces.sort(cmpLenRev);
20274 longPieces.sort(cmpLenRev);
20275 mixedPieces.sort(cmpLenRev);
20276
20277 for (i = 0; i < 7; i++) {
20278 shortPieces[i] = regexEscape(shortPieces[i]);
20279 longPieces[i] = regexEscape(longPieces[i]);
20280 mixedPieces[i] = regexEscape(mixedPieces[i]);
20281 }
20282
20283 this._weekdaysRegex = new RegExp('^(' + mixedPieces.join('|') + ')', 'i');
20284 this._weekdaysShortRegex = this._weekdaysRegex;
20285 this._weekdaysMinRegex = this._weekdaysRegex;
20286 this._weekdaysStrictRegex = new RegExp('^(' + longPieces.join('|') + ')', 'i');
20287 this._weekdaysShortStrictRegex = new RegExp('^(' + shortPieces.join('|') + ')', 'i');
20288 this._weekdaysMinStrictRegex = new RegExp('^(' + minPieces.join('|') + ')', 'i');
20289 } // FORMATTING
20290
20291
20292 function hFormat() {
20293 return this.hours() % 12 || 12;
20294 }
20295
20296 function kFormat() {
20297 return this.hours() || 24;
20298 }
20299
20300 addFormatToken('H', ['HH', 2], 0, 'hour');
20301 addFormatToken('h', ['hh', 2], 0, hFormat);
20302 addFormatToken('k', ['kk', 2], 0, kFormat);
20303 addFormatToken('hmm', 0, 0, function () {
20304 return '' + hFormat.apply(this) + zeroFill(this.minutes(), 2);
20305 });
20306 addFormatToken('hmmss', 0, 0, function () {
20307 return '' + hFormat.apply(this) + zeroFill(this.minutes(), 2) + zeroFill(this.seconds(), 2);
20308 });
20309 addFormatToken('Hmm', 0, 0, function () {
20310 return '' + this.hours() + zeroFill(this.minutes(), 2);
20311 });
20312 addFormatToken('Hmmss', 0, 0, function () {
20313 return '' + this.hours() + zeroFill(this.minutes(), 2) + zeroFill(this.seconds(), 2);
20314 });
20315
20316 function meridiem(token, lowercase) {
20317 addFormatToken(token, 0, 0, function () {
20318 return this.localeData().meridiem(this.hours(), this.minutes(), lowercase);
20319 });
20320 }
20321
20322 meridiem('a', true);
20323 meridiem('A', false); // ALIASES
20324
20325 addUnitAlias('hour', 'h'); // PRIORITY
20326
20327 addUnitPriority('hour', 13); // PARSING
20328
20329 function matchMeridiem(isStrict, locale) {
20330 return locale._meridiemParse;
20331 }
20332
20333 addRegexToken('a', matchMeridiem);
20334 addRegexToken('A', matchMeridiem);
20335 addRegexToken('H', match1to2);
20336 addRegexToken('h', match1to2);
20337 addRegexToken('k', match1to2);
20338 addRegexToken('HH', match1to2, match2);
20339 addRegexToken('hh', match1to2, match2);
20340 addRegexToken('kk', match1to2, match2);
20341 addRegexToken('hmm', match3to4);
20342 addRegexToken('hmmss', match5to6);
20343 addRegexToken('Hmm', match3to4);
20344 addRegexToken('Hmmss', match5to6);
20345 addParseToken(['H', 'HH'], HOUR);
20346 addParseToken(['k', 'kk'], function (input, array, config) {
20347 var kInput = toInt(input);
20348 array[HOUR] = kInput === 24 ? 0 : kInput;
20349 });
20350 addParseToken(['a', 'A'], function (input, array, config) {
20351 config._isPm = config._locale.isPM(input);
20352 config._meridiem = input;
20353 });
20354 addParseToken(['h', 'hh'], function (input, array, config) {
20355 array[HOUR] = toInt(input);
20356 getParsingFlags(config).bigHour = true;
20357 });
20358 addParseToken('hmm', function (input, array, config) {
20359 var pos = input.length - 2;
20360 array[HOUR] = toInt(input.substr(0, pos));
20361 array[MINUTE] = toInt(input.substr(pos));
20362 getParsingFlags(config).bigHour = true;
20363 });
20364 addParseToken('hmmss', function (input, array, config) {
20365 var pos1 = input.length - 4;
20366 var pos2 = input.length - 2;
20367 array[HOUR] = toInt(input.substr(0, pos1));
20368 array[MINUTE] = toInt(input.substr(pos1, 2));
20369 array[SECOND] = toInt(input.substr(pos2));
20370 getParsingFlags(config).bigHour = true;
20371 });
20372 addParseToken('Hmm', function (input, array, config) {
20373 var pos = input.length - 2;
20374 array[HOUR] = toInt(input.substr(0, pos));
20375 array[MINUTE] = toInt(input.substr(pos));
20376 });
20377 addParseToken('Hmmss', function (input, array, config) {
20378 var pos1 = input.length - 4;
20379 var pos2 = input.length - 2;
20380 array[HOUR] = toInt(input.substr(0, pos1));
20381 array[MINUTE] = toInt(input.substr(pos1, 2));
20382 array[SECOND] = toInt(input.substr(pos2));
20383 }); // LOCALES
20384
20385 function localeIsPM(input) {
20386 // IE8 Quirks Mode & IE7 Standards Mode do not allow accessing strings like arrays
20387 // Using charAt should be more compatible.
20388 return (input + '').toLowerCase().charAt(0) === 'p';
20389 }
20390
20391 var defaultLocaleMeridiemParse = /[ap]\.?m?\.?/i;
20392
20393 function localeMeridiem(hours, minutes, isLower) {
20394 if (hours > 11) {
20395 return isLower ? 'pm' : 'PM';
20396 } else {
20397 return isLower ? 'am' : 'AM';
20398 }
20399 } // MOMENTS
20400 // Setting the hour should keep the time, because the user explicitly
20401 // specified which hour they want. So trying to maintain the same hour (in
20402 // a new timezone) makes sense. Adding/subtracting hours does not follow
20403 // this rule.
20404
20405
20406 var getSetHour = makeGetSet('Hours', true);
20407 var baseConfig = {
20408 calendar: defaultCalendar,
20409 longDateFormat: defaultLongDateFormat,
20410 invalidDate: defaultInvalidDate,
20411 ordinal: defaultOrdinal,
20412 dayOfMonthOrdinalParse: defaultDayOfMonthOrdinalParse,
20413 relativeTime: defaultRelativeTime,
20414 months: defaultLocaleMonths,
20415 monthsShort: defaultLocaleMonthsShort,
20416 week: defaultLocaleWeek,
20417 weekdays: defaultLocaleWeekdays,
20418 weekdaysMin: defaultLocaleWeekdaysMin,
20419 weekdaysShort: defaultLocaleWeekdaysShort,
20420 meridiemParse: defaultLocaleMeridiemParse
20421 }; // internal storage for locale config files
20422
20423 var locales = {};
20424 var localeFamilies = {};
20425 var globalLocale;
20426
20427 function normalizeLocale(key) {
20428 return key ? key.toLowerCase().replace('_', '-') : key;
20429 } // pick the locale from the array
20430 // try ['en-au', 'en-gb'] as 'en-au', 'en-gb', 'en', as in move through the list trying each
20431 // substring from most specific to least, but move to the next array item if it's a more specific variant than the current root
20432
20433
20434 function chooseLocale(names) {
20435 var i = 0,
20436 j,
20437 next,
20438 locale,
20439 split;
20440
20441 while (i < names.length) {
20442 split = normalizeLocale(names[i]).split('-');
20443 j = split.length;
20444 next = normalizeLocale(names[i + 1]);
20445 next = next ? next.split('-') : null;
20446
20447 while (j > 0) {
20448 locale = loadLocale(split.slice(0, j).join('-'));
20449
20450 if (locale) {
20451 return locale;
20452 }
20453
20454 if (next && next.length >= j && compareArrays(split, next, true) >= j - 1) {
20455 //the next array item is better than a shallower substring of this one
20456 break;
20457 }
20458
20459 j--;
20460 }
20461
20462 i++;
20463 }
20464
20465 return globalLocale;
20466 }
20467
20468 function loadLocale(name) {
20469 var oldLocale = null; // TODO: Find a better way to register and load all the locales in Node
20470
20471 if (!locales[name] && 'object' !== 'undefined' && module && module.exports) {
20472 try {
20473 oldLocale = globalLocale._abbr;
20474 var aliasedRequire = commonjsRequire$2;
20475 aliasedRequire('./locale/' + name);
20476 getSetGlobalLocale(oldLocale);
20477 } catch (e) {}
20478 }
20479
20480 return locales[name];
20481 } // This function will load locale and then set the global locale. If
20482 // no arguments are passed in, it will simply return the current global
20483 // locale key.
20484
20485
20486 function getSetGlobalLocale(key, values) {
20487 var data;
20488
20489 if (key) {
20490 if (isUndefined(values)) {
20491 data = getLocale(key);
20492 } else {
20493 data = defineLocale(key, values);
20494 }
20495
20496 if (data) {
20497 // moment.duration._locale = moment._locale = data;
20498 globalLocale = data;
20499 } else {
20500 if (typeof console !== 'undefined' && console.warn) {
20501 //warn user if arguments are passed but the locale could not be set
20502 console.warn('Locale ' + key + ' not found. Did you forget to load it?');
20503 }
20504 }
20505 }
20506
20507 return globalLocale._abbr;
20508 }
20509
20510 function defineLocale(name, config) {
20511 if (config !== null) {
20512 var locale,
20513 parentConfig = baseConfig;
20514 config.abbr = name;
20515
20516 if (locales[name] != null) {
20517 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.');
20518 parentConfig = locales[name]._config;
20519 } else if (config.parentLocale != null) {
20520 if (locales[config.parentLocale] != null) {
20521 parentConfig = locales[config.parentLocale]._config;
20522 } else {
20523 locale = loadLocale(config.parentLocale);
20524
20525 if (locale != null) {
20526 parentConfig = locale._config;
20527 } else {
20528 if (!localeFamilies[config.parentLocale]) {
20529 localeFamilies[config.parentLocale] = [];
20530 }
20531
20532 localeFamilies[config.parentLocale].push({
20533 name: name,
20534 config: config
20535 });
20536 return null;
20537 }
20538 }
20539 }
20540
20541 locales[name] = new Locale(mergeConfigs(parentConfig, config));
20542
20543 if (localeFamilies[name]) {
20544 localeFamilies[name].forEach(function (x) {
20545 defineLocale(x.name, x.config);
20546 });
20547 } // backwards compat for now: also set the locale
20548 // make sure we set the locale AFTER all child locales have been
20549 // created, so we won't end up with the child locale set.
20550
20551
20552 getSetGlobalLocale(name);
20553 return locales[name];
20554 } else {
20555 // useful for testing
20556 delete locales[name];
20557 return null;
20558 }
20559 }
20560
20561 function updateLocale(name, config) {
20562 if (config != null) {
20563 var locale,
20564 tmpLocale,
20565 parentConfig = baseConfig; // MERGE
20566
20567 tmpLocale = loadLocale(name);
20568
20569 if (tmpLocale != null) {
20570 parentConfig = tmpLocale._config;
20571 }
20572
20573 config = mergeConfigs(parentConfig, config);
20574 locale = new Locale(config);
20575 locale.parentLocale = locales[name];
20576 locales[name] = locale; // backwards compat for now: also set the locale
20577
20578 getSetGlobalLocale(name);
20579 } else {
20580 // pass null for config to unupdate, useful for tests
20581 if (locales[name] != null) {
20582 if (locales[name].parentLocale != null) {
20583 locales[name] = locales[name].parentLocale;
20584 } else if (locales[name] != null) {
20585 delete locales[name];
20586 }
20587 }
20588 }
20589
20590 return locales[name];
20591 } // returns locale data
20592
20593
20594 function getLocale(key) {
20595 var locale;
20596
20597 if (key && key._locale && key._locale._abbr) {
20598 key = key._locale._abbr;
20599 }
20600
20601 if (!key) {
20602 return globalLocale;
20603 }
20604
20605 if (!isArray(key)) {
20606 //short-circuit everything else
20607 locale = loadLocale(key);
20608
20609 if (locale) {
20610 return locale;
20611 }
20612
20613 key = [key];
20614 }
20615
20616 return chooseLocale(key);
20617 }
20618
20619 function listLocales() {
20620 return keys(locales);
20621 }
20622
20623 function checkOverflow(m) {
20624 var overflow;
20625 var a = m._a;
20626
20627 if (a && getParsingFlags(m).overflow === -2) {
20628 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;
20629
20630 if (getParsingFlags(m)._overflowDayOfYear && (overflow < YEAR || overflow > DATE)) {
20631 overflow = DATE;
20632 }
20633
20634 if (getParsingFlags(m)._overflowWeeks && overflow === -1) {
20635 overflow = WEEK;
20636 }
20637
20638 if (getParsingFlags(m)._overflowWeekday && overflow === -1) {
20639 overflow = WEEKDAY;
20640 }
20641
20642 getParsingFlags(m).overflow = overflow;
20643 }
20644
20645 return m;
20646 } // Pick the first defined of two or three arguments.
20647
20648
20649 function defaults(a, b, c) {
20650 if (a != null) {
20651 return a;
20652 }
20653
20654 if (b != null) {
20655 return b;
20656 }
20657
20658 return c;
20659 }
20660
20661 function currentDateArray(config) {
20662 // hooks is actually the exported moment object
20663 var nowValue = new Date(hooks.now());
20664
20665 if (config._useUTC) {
20666 return [nowValue.getUTCFullYear(), nowValue.getUTCMonth(), nowValue.getUTCDate()];
20667 }
20668
20669 return [nowValue.getFullYear(), nowValue.getMonth(), nowValue.getDate()];
20670 } // convert an array to a date.
20671 // the array should mirror the parameters below
20672 // note: all values past the year are optional and will default to the lowest possible value.
20673 // [year, month, day , hour, minute, second, millisecond]
20674
20675
20676 function configFromArray(config) {
20677 var i,
20678 date,
20679 input = [],
20680 currentDate,
20681 expectedWeekday,
20682 yearToUse;
20683
20684 if (config._d) {
20685 return;
20686 }
20687
20688 currentDate = currentDateArray(config); //compute day of the year from weeks and weekdays
20689
20690 if (config._w && config._a[DATE] == null && config._a[MONTH] == null) {
20691 dayOfYearFromWeekInfo(config);
20692 } //if the day of the year is set, figure out what it is
20693
20694
20695 if (config._dayOfYear != null) {
20696 yearToUse = defaults(config._a[YEAR], currentDate[YEAR]);
20697
20698 if (config._dayOfYear > daysInYear(yearToUse) || config._dayOfYear === 0) {
20699 getParsingFlags(config)._overflowDayOfYear = true;
20700 }
20701
20702 date = createUTCDate(yearToUse, 0, config._dayOfYear);
20703 config._a[MONTH] = date.getUTCMonth();
20704 config._a[DATE] = date.getUTCDate();
20705 } // Default to current date.
20706 // * if no year, month, day of month are given, default to today
20707 // * if day of month is given, default month and year
20708 // * if month is given, default only year
20709 // * if year is given, don't default anything
20710
20711
20712 for (i = 0; i < 3 && config._a[i] == null; ++i) {
20713 config._a[i] = input[i] = currentDate[i];
20714 } // Zero out whatever was not defaulted, including time
20715
20716
20717 for (; i < 7; i++) {
20718 config._a[i] = input[i] = config._a[i] == null ? i === 2 ? 1 : 0 : config._a[i];
20719 } // Check for 24:00:00.000
20720
20721
20722 if (config._a[HOUR] === 24 && config._a[MINUTE] === 0 && config._a[SECOND] === 0 && config._a[MILLISECOND] === 0) {
20723 config._nextDay = true;
20724 config._a[HOUR] = 0;
20725 }
20726
20727 config._d = (config._useUTC ? createUTCDate : createDate).apply(null, input);
20728 expectedWeekday = config._useUTC ? config._d.getUTCDay() : config._d.getDay(); // Apply timezone offset from input. The actual utcOffset can be changed
20729 // with parseZone.
20730
20731 if (config._tzm != null) {
20732 config._d.setUTCMinutes(config._d.getUTCMinutes() - config._tzm);
20733 }
20734
20735 if (config._nextDay) {
20736 config._a[HOUR] = 24;
20737 } // check for mismatching day of week
20738
20739
20740 if (config._w && typeof config._w.d !== 'undefined' && config._w.d !== expectedWeekday) {
20741 getParsingFlags(config).weekdayMismatch = true;
20742 }
20743 }
20744
20745 function dayOfYearFromWeekInfo(config) {
20746 var w, weekYear, week, weekday, dow, doy, temp, weekdayOverflow;
20747 w = config._w;
20748
20749 if (w.GG != null || w.W != null || w.E != null) {
20750 dow = 1;
20751 doy = 4; // TODO: We need to take the current isoWeekYear, but that depends on
20752 // how we interpret now (local, utc, fixed offset). So create
20753 // a now version of current config (take local/utc/offset flags, and
20754 // create now).
20755
20756 weekYear = defaults(w.GG, config._a[YEAR], weekOfYear(createLocal(), 1, 4).year);
20757 week = defaults(w.W, 1);
20758 weekday = defaults(w.E, 1);
20759
20760 if (weekday < 1 || weekday > 7) {
20761 weekdayOverflow = true;
20762 }
20763 } else {
20764 dow = config._locale._week.dow;
20765 doy = config._locale._week.doy;
20766 var curWeek = weekOfYear(createLocal(), dow, doy);
20767 weekYear = defaults(w.gg, config._a[YEAR], curWeek.year); // Default to current week.
20768
20769 week = defaults(w.w, curWeek.week);
20770
20771 if (w.d != null) {
20772 // weekday -- low day numbers are considered next week
20773 weekday = w.d;
20774
20775 if (weekday < 0 || weekday > 6) {
20776 weekdayOverflow = true;
20777 }
20778 } else if (w.e != null) {
20779 // local weekday -- counting starts from beginning of week
20780 weekday = w.e + dow;
20781
20782 if (w.e < 0 || w.e > 6) {
20783 weekdayOverflow = true;
20784 }
20785 } else {
20786 // default to beginning of week
20787 weekday = dow;
20788 }
20789 }
20790
20791 if (week < 1 || week > weeksInYear(weekYear, dow, doy)) {
20792 getParsingFlags(config)._overflowWeeks = true;
20793 } else if (weekdayOverflow != null) {
20794 getParsingFlags(config)._overflowWeekday = true;
20795 } else {
20796 temp = dayOfYearFromWeeks(weekYear, week, weekday, dow, doy);
20797 config._a[YEAR] = temp.year;
20798 config._dayOfYear = temp.dayOfYear;
20799 }
20800 } // iso 8601 regex
20801 // 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)
20802
20803
20804 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)?)?$/;
20805 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)?)?$/;
20806 var tzRegex = /Z|[+-]\d\d(?::?\d\d)?/;
20807 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
20808 ['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
20809
20810 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/]];
20811 var aspNetJsonRegex = /^\/?Date\((\-?\d+)/i; // date from iso format
20812
20813 function configFromISO(config) {
20814 var i,
20815 l,
20816 string = config._i,
20817 match = extendedIsoRegex.exec(string) || basicIsoRegex.exec(string),
20818 allowTime,
20819 dateFormat,
20820 timeFormat,
20821 tzFormat;
20822
20823 if (match) {
20824 getParsingFlags(config).iso = true;
20825
20826 for (i = 0, l = isoDates.length; i < l; i++) {
20827 if (isoDates[i][1].exec(match[1])) {
20828 dateFormat = isoDates[i][0];
20829 allowTime = isoDates[i][2] !== false;
20830 break;
20831 }
20832 }
20833
20834 if (dateFormat == null) {
20835 config._isValid = false;
20836 return;
20837 }
20838
20839 if (match[3]) {
20840 for (i = 0, l = isoTimes.length; i < l; i++) {
20841 if (isoTimes[i][1].exec(match[3])) {
20842 // match[2] should be 'T' or space
20843 timeFormat = (match[2] || ' ') + isoTimes[i][0];
20844 break;
20845 }
20846 }
20847
20848 if (timeFormat == null) {
20849 config._isValid = false;
20850 return;
20851 }
20852 }
20853
20854 if (!allowTime && timeFormat != null) {
20855 config._isValid = false;
20856 return;
20857 }
20858
20859 if (match[4]) {
20860 if (tzRegex.exec(match[4])) {
20861 tzFormat = 'Z';
20862 } else {
20863 config._isValid = false;
20864 return;
20865 }
20866 }
20867
20868 config._f = dateFormat + (timeFormat || '') + (tzFormat || '');
20869 configFromStringAndFormat(config);
20870 } else {
20871 config._isValid = false;
20872 }
20873 } // RFC 2822 regex: For details see https://tools.ietf.org/html/rfc2822#section-3.3
20874
20875
20876 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}))$/;
20877
20878 function extractFromRFC2822Strings(yearStr, monthStr, dayStr, hourStr, minuteStr, secondStr) {
20879 var result = [untruncateYear(yearStr), defaultLocaleMonthsShort.indexOf(monthStr), parseInt(dayStr, 10), parseInt(hourStr, 10), parseInt(minuteStr, 10)];
20880
20881 if (secondStr) {
20882 result.push(parseInt(secondStr, 10));
20883 }
20884
20885 return result;
20886 }
20887
20888 function untruncateYear(yearStr) {
20889 var year = parseInt(yearStr, 10);
20890
20891 if (year <= 49) {
20892 return 2000 + year;
20893 } else if (year <= 999) {
20894 return 1900 + year;
20895 }
20896
20897 return year;
20898 }
20899
20900 function preprocessRFC2822(s) {
20901 // Remove comments and folding whitespace and replace multiple-spaces with a single space
20902 return s.replace(/\([^)]*\)|[\n\t]/g, ' ').replace(/(\s\s+)/g, ' ').replace(/^\s\s*/, '').replace(/\s\s*$/, '');
20903 }
20904
20905 function checkWeekday(weekdayStr, parsedInput, config) {
20906 if (weekdayStr) {
20907 // TODO: Replace the vanilla JS Date object with an indepentent day-of-week check.
20908 var weekdayProvided = defaultLocaleWeekdaysShort.indexOf(weekdayStr),
20909 weekdayActual = new Date(parsedInput[0], parsedInput[1], parsedInput[2]).getDay();
20910
20911 if (weekdayProvided !== weekdayActual) {
20912 getParsingFlags(config).weekdayMismatch = true;
20913 config._isValid = false;
20914 return false;
20915 }
20916 }
20917
20918 return true;
20919 }
20920
20921 var obsOffsets = {
20922 UT: 0,
20923 GMT: 0,
20924 EDT: -4 * 60,
20925 EST: -5 * 60,
20926 CDT: -5 * 60,
20927 CST: -6 * 60,
20928 MDT: -6 * 60,
20929 MST: -7 * 60,
20930 PDT: -7 * 60,
20931 PST: -8 * 60
20932 };
20933
20934 function calculateOffset(obsOffset, militaryOffset, numOffset) {
20935 if (obsOffset) {
20936 return obsOffsets[obsOffset];
20937 } else if (militaryOffset) {
20938 // the only allowed military tz is Z
20939 return 0;
20940 } else {
20941 var hm = parseInt(numOffset, 10);
20942 var m = hm % 100,
20943 h = (hm - m) / 100;
20944 return h * 60 + m;
20945 }
20946 } // date and time from ref 2822 format
20947
20948
20949 function configFromRFC2822(config) {
20950 var match = rfc2822.exec(preprocessRFC2822(config._i));
20951
20952 if (match) {
20953 var parsedArray = extractFromRFC2822Strings(match[4], match[3], match[2], match[5], match[6], match[7]);
20954
20955 if (!checkWeekday(match[1], parsedArray, config)) {
20956 return;
20957 }
20958
20959 config._a = parsedArray;
20960 config._tzm = calculateOffset(match[8], match[9], match[10]);
20961 config._d = createUTCDate.apply(null, config._a);
20962
20963 config._d.setUTCMinutes(config._d.getUTCMinutes() - config._tzm);
20964
20965 getParsingFlags(config).rfc2822 = true;
20966 } else {
20967 config._isValid = false;
20968 }
20969 } // date from iso format or fallback
20970
20971
20972 function configFromString(config) {
20973 var matched = aspNetJsonRegex.exec(config._i);
20974
20975 if (matched !== null) {
20976 config._d = new Date(+matched[1]);
20977 return;
20978 }
20979
20980 configFromISO(config);
20981
20982 if (config._isValid === false) {
20983 delete config._isValid;
20984 } else {
20985 return;
20986 }
20987
20988 configFromRFC2822(config);
20989
20990 if (config._isValid === false) {
20991 delete config._isValid;
20992 } else {
20993 return;
20994 } // Final attempt, use Input Fallback
20995
20996
20997 hooks.createFromInputFallback(config);
20998 }
20999
21000 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) {
21001 config._d = new Date(config._i + (config._useUTC ? ' UTC' : ''));
21002 }); // constant that refers to the ISO standard
21003
21004 hooks.ISO_8601 = function () {}; // constant that refers to the RFC 2822 form
21005
21006
21007 hooks.RFC_2822 = function () {}; // date from string and format string
21008
21009
21010 function configFromStringAndFormat(config) {
21011 // TODO: Move this to another part of the creation flow to prevent circular deps
21012 if (config._f === hooks.ISO_8601) {
21013 configFromISO(config);
21014 return;
21015 }
21016
21017 if (config._f === hooks.RFC_2822) {
21018 configFromRFC2822(config);
21019 return;
21020 }
21021
21022 config._a = [];
21023 getParsingFlags(config).empty = true; // This array is used to make a Date, either with `new Date` or `Date.UTC`
21024
21025 var string = '' + config._i,
21026 i,
21027 parsedInput,
21028 tokens,
21029 token,
21030 skipped,
21031 stringLength = string.length,
21032 totalParsedInputLength = 0;
21033 tokens = expandFormat(config._f, config._locale).match(formattingTokens) || [];
21034
21035 for (i = 0; i < tokens.length; i++) {
21036 token = tokens[i];
21037 parsedInput = (string.match(getParseRegexForToken(token, config)) || [])[0]; // console.log('token', token, 'parsedInput', parsedInput,
21038 // 'regex', getParseRegexForToken(token, config));
21039
21040 if (parsedInput) {
21041 skipped = string.substr(0, string.indexOf(parsedInput));
21042
21043 if (skipped.length > 0) {
21044 getParsingFlags(config).unusedInput.push(skipped);
21045 }
21046
21047 string = string.slice(string.indexOf(parsedInput) + parsedInput.length);
21048 totalParsedInputLength += parsedInput.length;
21049 } // don't parse if it's not a known token
21050
21051
21052 if (formatTokenFunctions[token]) {
21053 if (parsedInput) {
21054 getParsingFlags(config).empty = false;
21055 } else {
21056 getParsingFlags(config).unusedTokens.push(token);
21057 }
21058
21059 addTimeToArrayFromToken(token, parsedInput, config);
21060 } else if (config._strict && !parsedInput) {
21061 getParsingFlags(config).unusedTokens.push(token);
21062 }
21063 } // add remaining unparsed input length to the string
21064
21065
21066 getParsingFlags(config).charsLeftOver = stringLength - totalParsedInputLength;
21067
21068 if (string.length > 0) {
21069 getParsingFlags(config).unusedInput.push(string);
21070 } // clear _12h flag if hour is <= 12
21071
21072
21073 if (config._a[HOUR] <= 12 && getParsingFlags(config).bigHour === true && config._a[HOUR] > 0) {
21074 getParsingFlags(config).bigHour = undefined;
21075 }
21076
21077 getParsingFlags(config).parsedDateParts = config._a.slice(0);
21078 getParsingFlags(config).meridiem = config._meridiem; // handle meridiem
21079
21080 config._a[HOUR] = meridiemFixWrap(config._locale, config._a[HOUR], config._meridiem);
21081 configFromArray(config);
21082 checkOverflow(config);
21083 }
21084
21085 function meridiemFixWrap(locale, hour, meridiem) {
21086 var isPm;
21087
21088 if (meridiem == null) {
21089 // nothing to do
21090 return hour;
21091 }
21092
21093 if (locale.meridiemHour != null) {
21094 return locale.meridiemHour(hour, meridiem);
21095 } else if (locale.isPM != null) {
21096 // Fallback
21097 isPm = locale.isPM(meridiem);
21098
21099 if (isPm && hour < 12) {
21100 hour += 12;
21101 }
21102
21103 if (!isPm && hour === 12) {
21104 hour = 0;
21105 }
21106
21107 return hour;
21108 } else {
21109 // this is not supposed to happen
21110 return hour;
21111 }
21112 } // date from string and array of format strings
21113
21114
21115 function configFromStringAndArray(config) {
21116 var tempConfig, bestMoment, scoreToBeat, i, currentScore;
21117
21118 if (config._f.length === 0) {
21119 getParsingFlags(config).invalidFormat = true;
21120 config._d = new Date(NaN);
21121 return;
21122 }
21123
21124 for (i = 0; i < config._f.length; i++) {
21125 currentScore = 0;
21126 tempConfig = copyConfig({}, config);
21127
21128 if (config._useUTC != null) {
21129 tempConfig._useUTC = config._useUTC;
21130 }
21131
21132 tempConfig._f = config._f[i];
21133 configFromStringAndFormat(tempConfig);
21134
21135 if (!isValid(tempConfig)) {
21136 continue;
21137 } // if there is any input that was not parsed add a penalty for that format
21138
21139
21140 currentScore += getParsingFlags(tempConfig).charsLeftOver; //or tokens
21141
21142 currentScore += getParsingFlags(tempConfig).unusedTokens.length * 10;
21143 getParsingFlags(tempConfig).score = currentScore;
21144
21145 if (scoreToBeat == null || currentScore < scoreToBeat) {
21146 scoreToBeat = currentScore;
21147 bestMoment = tempConfig;
21148 }
21149 }
21150
21151 extend(config, bestMoment || tempConfig);
21152 }
21153
21154 function configFromObject(config) {
21155 if (config._d) {
21156 return;
21157 }
21158
21159 var i = normalizeObjectUnits(config._i);
21160 config._a = map([i.year, i.month, i.day || i.date, i.hour, i.minute, i.second, i.millisecond], function (obj) {
21161 return obj && parseInt(obj, 10);
21162 });
21163 configFromArray(config);
21164 }
21165
21166 function createFromConfig(config) {
21167 var res = new Moment(checkOverflow(prepareConfig(config)));
21168
21169 if (res._nextDay) {
21170 // Adding is smart enough around DST
21171 res.add(1, 'd');
21172 res._nextDay = undefined;
21173 }
21174
21175 return res;
21176 }
21177
21178 function prepareConfig(config) {
21179 var input = config._i,
21180 format = config._f;
21181 config._locale = config._locale || getLocale(config._l);
21182
21183 if (input === null || format === undefined && input === '') {
21184 return createInvalid({
21185 nullInput: true
21186 });
21187 }
21188
21189 if (typeof input === 'string') {
21190 config._i = input = config._locale.preparse(input);
21191 }
21192
21193 if (isMoment(input)) {
21194 return new Moment(checkOverflow(input));
21195 } else if (isDate(input)) {
21196 config._d = input;
21197 } else if (isArray(format)) {
21198 configFromStringAndArray(config);
21199 } else if (format) {
21200 configFromStringAndFormat(config);
21201 } else {
21202 configFromInput(config);
21203 }
21204
21205 if (!isValid(config)) {
21206 config._d = null;
21207 }
21208
21209 return config;
21210 }
21211
21212 function configFromInput(config) {
21213 var input = config._i;
21214
21215 if (isUndefined(input)) {
21216 config._d = new Date(hooks.now());
21217 } else if (isDate(input)) {
21218 config._d = new Date(input.valueOf());
21219 } else if (typeof input === 'string') {
21220 configFromString(config);
21221 } else if (isArray(input)) {
21222 config._a = map(input.slice(0), function (obj) {
21223 return parseInt(obj, 10);
21224 });
21225 configFromArray(config);
21226 } else if (isObject(input)) {
21227 configFromObject(config);
21228 } else if (isNumber(input)) {
21229 // from milliseconds
21230 config._d = new Date(input);
21231 } else {
21232 hooks.createFromInputFallback(config);
21233 }
21234 }
21235
21236 function createLocalOrUTC(input, format, locale, strict, isUTC) {
21237 var c = {};
21238
21239 if (locale === true || locale === false) {
21240 strict = locale;
21241 locale = undefined;
21242 }
21243
21244 if (isObject(input) && isObjectEmpty(input) || isArray(input) && input.length === 0) {
21245 input = undefined;
21246 } // object construction must be done this way.
21247 // https://github.com/moment/moment/issues/1423
21248
21249
21250 c._isAMomentObject = true;
21251 c._useUTC = c._isUTC = isUTC;
21252 c._l = locale;
21253 c._i = input;
21254 c._f = format;
21255 c._strict = strict;
21256 return createFromConfig(c);
21257 }
21258
21259 function createLocal(input, format, locale, strict) {
21260 return createLocalOrUTC(input, format, locale, strict, false);
21261 }
21262
21263 var prototypeMin = deprecate('moment().min is deprecated, use moment.max instead. http://momentjs.com/guides/#/warnings/min-max/', function () {
21264 var other = createLocal.apply(null, arguments);
21265
21266 if (this.isValid() && other.isValid()) {
21267 return other < this ? this : other;
21268 } else {
21269 return createInvalid();
21270 }
21271 });
21272 var prototypeMax = deprecate('moment().max is deprecated, use moment.min instead. http://momentjs.com/guides/#/warnings/min-max/', function () {
21273 var other = createLocal.apply(null, arguments);
21274
21275 if (this.isValid() && other.isValid()) {
21276 return other > this ? this : other;
21277 } else {
21278 return createInvalid();
21279 }
21280 }); // Pick a moment m from moments so that m[fn](other) is true for all
21281 // other. This relies on the function fn to be transitive.
21282 //
21283 // moments should either be an array of moment objects or an array, whose
21284 // first element is an array of moment objects.
21285
21286 function pickBy(fn, moments) {
21287 var res, i;
21288
21289 if (moments.length === 1 && isArray(moments[0])) {
21290 moments = moments[0];
21291 }
21292
21293 if (!moments.length) {
21294 return createLocal();
21295 }
21296
21297 res = moments[0];
21298
21299 for (i = 1; i < moments.length; ++i) {
21300 if (!moments[i].isValid() || moments[i][fn](res)) {
21301 res = moments[i];
21302 }
21303 }
21304
21305 return res;
21306 } // TODO: Use [].sort instead?
21307
21308
21309 function min() {
21310 var args = [].slice.call(arguments, 0);
21311 return pickBy('isBefore', args);
21312 }
21313
21314 function max() {
21315 var args = [].slice.call(arguments, 0);
21316 return pickBy('isAfter', args);
21317 }
21318
21319 var now = function () {
21320 return Date.now ? Date.now() : +new Date();
21321 };
21322
21323 var ordering = ['year', 'quarter', 'month', 'week', 'day', 'hour', 'minute', 'second', 'millisecond'];
21324
21325 function isDurationValid(m) {
21326 for (var key in m) {
21327 if (!(indexOf.call(ordering, key) !== -1 && (m[key] == null || !isNaN(m[key])))) {
21328 return false;
21329 }
21330 }
21331
21332 var unitHasDecimal = false;
21333
21334 for (var i = 0; i < ordering.length; ++i) {
21335 if (m[ordering[i]]) {
21336 if (unitHasDecimal) {
21337 return false; // only allow non-integers for smallest unit
21338 }
21339
21340 if (parseFloat(m[ordering[i]]) !== toInt(m[ordering[i]])) {
21341 unitHasDecimal = true;
21342 }
21343 }
21344 }
21345
21346 return true;
21347 }
21348
21349 function isValid$1() {
21350 return this._isValid;
21351 }
21352
21353 function createInvalid$1() {
21354 return createDuration(NaN);
21355 }
21356
21357 function Duration(duration) {
21358 var normalizedInput = normalizeObjectUnits(duration),
21359 years = normalizedInput.year || 0,
21360 quarters = normalizedInput.quarter || 0,
21361 months = normalizedInput.month || 0,
21362 weeks = normalizedInput.week || normalizedInput.isoWeek || 0,
21363 days = normalizedInput.day || 0,
21364 hours = normalizedInput.hour || 0,
21365 minutes = normalizedInput.minute || 0,
21366 seconds = normalizedInput.second || 0,
21367 milliseconds = normalizedInput.millisecond || 0;
21368 this._isValid = isDurationValid(normalizedInput); // representation for dateAddRemove
21369
21370 this._milliseconds = +milliseconds + seconds * 1e3 + // 1000
21371 minutes * 6e4 + // 1000 * 60
21372 hours * 1000 * 60 * 60; //using 1000 * 60 * 60 instead of 36e5 to avoid floating point rounding errors https://github.com/moment/moment/issues/2978
21373 // Because of dateAddRemove treats 24 hours as different from a
21374 // day when working around DST, we need to store them separately
21375
21376 this._days = +days + weeks * 7; // It is impossible to translate months into days without knowing
21377 // which months you are are talking about, so we have to store
21378 // it separately.
21379
21380 this._months = +months + quarters * 3 + years * 12;
21381 this._data = {};
21382 this._locale = getLocale();
21383
21384 this._bubble();
21385 }
21386
21387 function isDuration(obj) {
21388 return obj instanceof Duration;
21389 }
21390
21391 function absRound(number) {
21392 if (number < 0) {
21393 return Math.round(-1 * number) * -1;
21394 } else {
21395 return Math.round(number);
21396 }
21397 } // FORMATTING
21398
21399
21400 function offset(token, separator) {
21401 addFormatToken(token, 0, 0, function () {
21402 var offset = this.utcOffset();
21403 var sign = '+';
21404
21405 if (offset < 0) {
21406 offset = -offset;
21407 sign = '-';
21408 }
21409
21410 return sign + zeroFill(~~(offset / 60), 2) + separator + zeroFill(~~offset % 60, 2);
21411 });
21412 }
21413
21414 offset('Z', ':');
21415 offset('ZZ', ''); // PARSING
21416
21417 addRegexToken('Z', matchShortOffset);
21418 addRegexToken('ZZ', matchShortOffset);
21419 addParseToken(['Z', 'ZZ'], function (input, array, config) {
21420 config._useUTC = true;
21421 config._tzm = offsetFromString(matchShortOffset, input);
21422 }); // HELPERS
21423 // timezone chunker
21424 // '+10:00' > ['10', '00']
21425 // '-1530' > ['-15', '30']
21426
21427 var chunkOffset = /([\+\-]|\d\d)/gi;
21428
21429 function offsetFromString(matcher, string) {
21430 var matches = (string || '').match(matcher);
21431
21432 if (matches === null) {
21433 return null;
21434 }
21435
21436 var chunk = matches[matches.length - 1] || [];
21437 var parts = (chunk + '').match(chunkOffset) || ['-', 0, 0];
21438 var minutes = +(parts[1] * 60) + toInt(parts[2]);
21439 return minutes === 0 ? 0 : parts[0] === '+' ? minutes : -minutes;
21440 } // Return a moment from input, that is local/utc/zone equivalent to model.
21441
21442
21443 function cloneWithOffset(input, model) {
21444 var res, diff;
21445
21446 if (model._isUTC) {
21447 res = model.clone();
21448 diff = (isMoment(input) || isDate(input) ? input.valueOf() : createLocal(input).valueOf()) - res.valueOf(); // Use low-level api, because this fn is low-level api.
21449
21450 res._d.setTime(res._d.valueOf() + diff);
21451
21452 hooks.updateOffset(res, false);
21453 return res;
21454 } else {
21455 return createLocal(input).local();
21456 }
21457 }
21458
21459 function getDateOffset(m) {
21460 // On Firefox.24 Date#getTimezoneOffset returns a floating point.
21461 // https://github.com/moment/moment/pull/1871
21462 return -Math.round(m._d.getTimezoneOffset() / 15) * 15;
21463 } // HOOKS
21464 // This function will be called whenever a moment is mutated.
21465 // It is intended to keep the offset in sync with the timezone.
21466
21467
21468 hooks.updateOffset = function () {}; // MOMENTS
21469 // keepLocalTime = true means only change the timezone, without
21470 // affecting the local hour. So 5:31:26 +0300 --[utcOffset(2, true)]-->
21471 // 5:31:26 +0200 It is possible that 5:31:26 doesn't exist with offset
21472 // +0200, so we adjust the time as needed, to be valid.
21473 //
21474 // Keeping the time actually adds/subtracts (one hour)
21475 // from the actual represented time. That is why we call updateOffset
21476 // a second time. In case it wants us to change the offset again
21477 // _changeInProgress == true case, then we have to adjust, because
21478 // there is no such time in the given timezone.
21479
21480
21481 function getSetOffset(input, keepLocalTime, keepMinutes) {
21482 var offset = this._offset || 0,
21483 localAdjust;
21484
21485 if (!this.isValid()) {
21486 return input != null ? this : NaN;
21487 }
21488
21489 if (input != null) {
21490 if (typeof input === 'string') {
21491 input = offsetFromString(matchShortOffset, input);
21492
21493 if (input === null) {
21494 return this;
21495 }
21496 } else if (Math.abs(input) < 16 && !keepMinutes) {
21497 input = input * 60;
21498 }
21499
21500 if (!this._isUTC && keepLocalTime) {
21501 localAdjust = getDateOffset(this);
21502 }
21503
21504 this._offset = input;
21505 this._isUTC = true;
21506
21507 if (localAdjust != null) {
21508 this.add(localAdjust, 'm');
21509 }
21510
21511 if (offset !== input) {
21512 if (!keepLocalTime || this._changeInProgress) {
21513 addSubtract(this, createDuration(input - offset, 'm'), 1, false);
21514 } else if (!this._changeInProgress) {
21515 this._changeInProgress = true;
21516 hooks.updateOffset(this, true);
21517 this._changeInProgress = null;
21518 }
21519 }
21520
21521 return this;
21522 } else {
21523 return this._isUTC ? offset : getDateOffset(this);
21524 }
21525 }
21526
21527 function getSetZone(input, keepLocalTime) {
21528 if (input != null) {
21529 if (typeof input !== 'string') {
21530 input = -input;
21531 }
21532
21533 this.utcOffset(input, keepLocalTime);
21534 return this;
21535 } else {
21536 return -this.utcOffset();
21537 }
21538 }
21539
21540 function setOffsetToUTC(keepLocalTime) {
21541 return this.utcOffset(0, keepLocalTime);
21542 }
21543
21544 function setOffsetToLocal(keepLocalTime) {
21545 if (this._isUTC) {
21546 this.utcOffset(0, keepLocalTime);
21547 this._isUTC = false;
21548
21549 if (keepLocalTime) {
21550 this.subtract(getDateOffset(this), 'm');
21551 }
21552 }
21553
21554 return this;
21555 }
21556
21557 function setOffsetToParsedOffset() {
21558 if (this._tzm != null) {
21559 this.utcOffset(this._tzm, false, true);
21560 } else if (typeof this._i === 'string') {
21561 var tZone = offsetFromString(matchOffset, this._i);
21562
21563 if (tZone != null) {
21564 this.utcOffset(tZone);
21565 } else {
21566 this.utcOffset(0, true);
21567 }
21568 }
21569
21570 return this;
21571 }
21572
21573 function hasAlignedHourOffset(input) {
21574 if (!this.isValid()) {
21575 return false;
21576 }
21577
21578 input = input ? createLocal(input).utcOffset() : 0;
21579 return (this.utcOffset() - input) % 60 === 0;
21580 }
21581
21582 function isDaylightSavingTime() {
21583 return this.utcOffset() > this.clone().month(0).utcOffset() || this.utcOffset() > this.clone().month(5).utcOffset();
21584 }
21585
21586 function isDaylightSavingTimeShifted() {
21587 if (!isUndefined(this._isDSTShifted)) {
21588 return this._isDSTShifted;
21589 }
21590
21591 var c = {};
21592 copyConfig(c, this);
21593 c = prepareConfig(c);
21594
21595 if (c._a) {
21596 var other = c._isUTC ? createUTC(c._a) : createLocal(c._a);
21597 this._isDSTShifted = this.isValid() && compareArrays(c._a, other.toArray()) > 0;
21598 } else {
21599 this._isDSTShifted = false;
21600 }
21601
21602 return this._isDSTShifted;
21603 }
21604
21605 function isLocal() {
21606 return this.isValid() ? !this._isUTC : false;
21607 }
21608
21609 function isUtcOffset() {
21610 return this.isValid() ? this._isUTC : false;
21611 }
21612
21613 function isUtc() {
21614 return this.isValid() ? this._isUTC && this._offset === 0 : false;
21615 } // ASP.NET json date format regex
21616
21617
21618 var aspNetRegex = /^(\-|\+)?(?:(\d*)[. ])?(\d+)\:(\d+)(?:\:(\d+)(\.\d*)?)?$/; // from http://docs.closure-library.googlecode.com/git/closure_goog_date_date.js.source.html
21619 // somewhat more in line with 4.4.3.2 2004 spec, but allows decimal anywhere
21620 // and further modified to allow for strings containing both week and day
21621
21622 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)?)?$/;
21623
21624 function createDuration(input, key) {
21625 var duration = input,
21626 // matching against regexp is expensive, do it on demand
21627 match = null,
21628 sign,
21629 ret,
21630 diffRes;
21631
21632 if (isDuration(input)) {
21633 duration = {
21634 ms: input._milliseconds,
21635 d: input._days,
21636 M: input._months
21637 };
21638 } else if (isNumber(input)) {
21639 duration = {};
21640
21641 if (key) {
21642 duration[key] = input;
21643 } else {
21644 duration.milliseconds = input;
21645 }
21646 } else if (!!(match = aspNetRegex.exec(input))) {
21647 sign = match[1] === '-' ? -1 : 1;
21648 duration = {
21649 y: 0,
21650 d: toInt(match[DATE]) * sign,
21651 h: toInt(match[HOUR]) * sign,
21652 m: toInt(match[MINUTE]) * sign,
21653 s: toInt(match[SECOND]) * sign,
21654 ms: toInt(absRound(match[MILLISECOND] * 1000)) * sign // the millisecond decimal point is included in the match
21655
21656 };
21657 } else if (!!(match = isoRegex.exec(input))) {
21658 sign = match[1] === '-' ? -1 : 1;
21659 duration = {
21660 y: parseIso(match[2], sign),
21661 M: parseIso(match[3], sign),
21662 w: parseIso(match[4], sign),
21663 d: parseIso(match[5], sign),
21664 h: parseIso(match[6], sign),
21665 m: parseIso(match[7], sign),
21666 s: parseIso(match[8], sign)
21667 };
21668 } else if (duration == null) {
21669 // checks for null or undefined
21670 duration = {};
21671 } else if (typeof duration === 'object' && ('from' in duration || 'to' in duration)) {
21672 diffRes = momentsDifference(createLocal(duration.from), createLocal(duration.to));
21673 duration = {};
21674 duration.ms = diffRes.milliseconds;
21675 duration.M = diffRes.months;
21676 }
21677
21678 ret = new Duration(duration);
21679
21680 if (isDuration(input) && hasOwnProp(input, '_locale')) {
21681 ret._locale = input._locale;
21682 }
21683
21684 return ret;
21685 }
21686
21687 createDuration.fn = Duration.prototype;
21688 createDuration.invalid = createInvalid$1;
21689
21690 function parseIso(inp, sign) {
21691 // We'd normally use ~~inp for this, but unfortunately it also
21692 // converts floats to ints.
21693 // inp may be undefined, so careful calling replace on it.
21694 var res = inp && parseFloat(inp.replace(',', '.')); // apply sign while we're at it
21695
21696 return (isNaN(res) ? 0 : res) * sign;
21697 }
21698
21699 function positiveMomentsDifference(base, other) {
21700 var res = {};
21701 res.months = other.month() - base.month() + (other.year() - base.year()) * 12;
21702
21703 if (base.clone().add(res.months, 'M').isAfter(other)) {
21704 --res.months;
21705 }
21706
21707 res.milliseconds = +other - +base.clone().add(res.months, 'M');
21708 return res;
21709 }
21710
21711 function momentsDifference(base, other) {
21712 var res;
21713
21714 if (!(base.isValid() && other.isValid())) {
21715 return {
21716 milliseconds: 0,
21717 months: 0
21718 };
21719 }
21720
21721 other = cloneWithOffset(other, base);
21722
21723 if (base.isBefore(other)) {
21724 res = positiveMomentsDifference(base, other);
21725 } else {
21726 res = positiveMomentsDifference(other, base);
21727 res.milliseconds = -res.milliseconds;
21728 res.months = -res.months;
21729 }
21730
21731 return res;
21732 } // TODO: remove 'name' arg after deprecation is removed
21733
21734
21735 function createAdder(direction, name) {
21736 return function (val, period) {
21737 var dur, tmp; //invert the arguments, but complain about it
21738
21739 if (period !== null && !isNaN(+period)) {
21740 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.');
21741 tmp = val;
21742 val = period;
21743 period = tmp;
21744 }
21745
21746 val = typeof val === 'string' ? +val : val;
21747 dur = createDuration(val, period);
21748 addSubtract(this, dur, direction);
21749 return this;
21750 };
21751 }
21752
21753 function addSubtract(mom, duration, isAdding, updateOffset) {
21754 var milliseconds = duration._milliseconds,
21755 days = absRound(duration._days),
21756 months = absRound(duration._months);
21757
21758 if (!mom.isValid()) {
21759 // No op
21760 return;
21761 }
21762
21763 updateOffset = updateOffset == null ? true : updateOffset;
21764
21765 if (months) {
21766 setMonth(mom, get(mom, 'Month') + months * isAdding);
21767 }
21768
21769 if (days) {
21770 set$1(mom, 'Date', get(mom, 'Date') + days * isAdding);
21771 }
21772
21773 if (milliseconds) {
21774 mom._d.setTime(mom._d.valueOf() + milliseconds * isAdding);
21775 }
21776
21777 if (updateOffset) {
21778 hooks.updateOffset(mom, days || months);
21779 }
21780 }
21781
21782 var add = createAdder(1, 'add');
21783 var subtract = createAdder(-1, 'subtract');
21784
21785 function getCalendarFormat(myMoment, now) {
21786 var diff = myMoment.diff(now, 'days', true);
21787 return diff < -6 ? 'sameElse' : diff < -1 ? 'lastWeek' : diff < 0 ? 'lastDay' : diff < 1 ? 'sameDay' : diff < 2 ? 'nextDay' : diff < 7 ? 'nextWeek' : 'sameElse';
21788 }
21789
21790 function calendar$1(time, formats) {
21791 // We want to compare the start of today, vs this.
21792 // Getting start-of-today depends on whether we're local/utc/offset or not.
21793 var now = time || createLocal(),
21794 sod = cloneWithOffset(now, this).startOf('day'),
21795 format = hooks.calendarFormat(this, sod) || 'sameElse';
21796 var output = formats && (isFunction(formats[format]) ? formats[format].call(this, now) : formats[format]);
21797 return this.format(output || this.localeData().calendar(format, this, createLocal(now)));
21798 }
21799
21800 function clone() {
21801 return new Moment(this);
21802 }
21803
21804 function isAfter(input, units) {
21805 var localInput = isMoment(input) ? input : createLocal(input);
21806
21807 if (!(this.isValid() && localInput.isValid())) {
21808 return false;
21809 }
21810
21811 units = normalizeUnits(units) || 'millisecond';
21812
21813 if (units === 'millisecond') {
21814 return this.valueOf() > localInput.valueOf();
21815 } else {
21816 return localInput.valueOf() < this.clone().startOf(units).valueOf();
21817 }
21818 }
21819
21820 function isBefore(input, units) {
21821 var localInput = isMoment(input) ? input : createLocal(input);
21822
21823 if (!(this.isValid() && localInput.isValid())) {
21824 return false;
21825 }
21826
21827 units = normalizeUnits(units) || 'millisecond';
21828
21829 if (units === 'millisecond') {
21830 return this.valueOf() < localInput.valueOf();
21831 } else {
21832 return this.clone().endOf(units).valueOf() < localInput.valueOf();
21833 }
21834 }
21835
21836 function isBetween(from, to, units, inclusivity) {
21837 var localFrom = isMoment(from) ? from : createLocal(from),
21838 localTo = isMoment(to) ? to : createLocal(to);
21839
21840 if (!(this.isValid() && localFrom.isValid() && localTo.isValid())) {
21841 return false;
21842 }
21843
21844 inclusivity = inclusivity || '()';
21845 return (inclusivity[0] === '(' ? this.isAfter(localFrom, units) : !this.isBefore(localFrom, units)) && (inclusivity[1] === ')' ? this.isBefore(localTo, units) : !this.isAfter(localTo, units));
21846 }
21847
21848 function isSame(input, units) {
21849 var localInput = isMoment(input) ? input : createLocal(input),
21850 inputMs;
21851
21852 if (!(this.isValid() && localInput.isValid())) {
21853 return false;
21854 }
21855
21856 units = normalizeUnits(units) || 'millisecond';
21857
21858 if (units === 'millisecond') {
21859 return this.valueOf() === localInput.valueOf();
21860 } else {
21861 inputMs = localInput.valueOf();
21862 return this.clone().startOf(units).valueOf() <= inputMs && inputMs <= this.clone().endOf(units).valueOf();
21863 }
21864 }
21865
21866 function isSameOrAfter(input, units) {
21867 return this.isSame(input, units) || this.isAfter(input, units);
21868 }
21869
21870 function isSameOrBefore(input, units) {
21871 return this.isSame(input, units) || this.isBefore(input, units);
21872 }
21873
21874 function diff(input, units, asFloat) {
21875 var that, zoneDelta, output;
21876
21877 if (!this.isValid()) {
21878 return NaN;
21879 }
21880
21881 that = cloneWithOffset(input, this);
21882
21883 if (!that.isValid()) {
21884 return NaN;
21885 }
21886
21887 zoneDelta = (that.utcOffset() - this.utcOffset()) * 6e4;
21888 units = normalizeUnits(units);
21889
21890 switch (units) {
21891 case 'year':
21892 output = monthDiff(this, that) / 12;
21893 break;
21894
21895 case 'month':
21896 output = monthDiff(this, that);
21897 break;
21898
21899 case 'quarter':
21900 output = monthDiff(this, that) / 3;
21901 break;
21902
21903 case 'second':
21904 output = (this - that) / 1e3;
21905 break;
21906 // 1000
21907
21908 case 'minute':
21909 output = (this - that) / 6e4;
21910 break;
21911 // 1000 * 60
21912
21913 case 'hour':
21914 output = (this - that) / 36e5;
21915 break;
21916 // 1000 * 60 * 60
21917
21918 case 'day':
21919 output = (this - that - zoneDelta) / 864e5;
21920 break;
21921 // 1000 * 60 * 60 * 24, negate dst
21922
21923 case 'week':
21924 output = (this - that - zoneDelta) / 6048e5;
21925 break;
21926 // 1000 * 60 * 60 * 24 * 7, negate dst
21927
21928 default:
21929 output = this - that;
21930 }
21931
21932 return asFloat ? output : absFloor(output);
21933 }
21934
21935 function monthDiff(a, b) {
21936 // difference in months
21937 var wholeMonthDiff = (b.year() - a.year()) * 12 + (b.month() - a.month()),
21938 // b is in (anchor - 1 month, anchor + 1 month)
21939 anchor = a.clone().add(wholeMonthDiff, 'months'),
21940 anchor2,
21941 adjust;
21942
21943 if (b - anchor < 0) {
21944 anchor2 = a.clone().add(wholeMonthDiff - 1, 'months'); // linear across the month
21945
21946 adjust = (b - anchor) / (anchor - anchor2);
21947 } else {
21948 anchor2 = a.clone().add(wholeMonthDiff + 1, 'months'); // linear across the month
21949
21950 adjust = (b - anchor) / (anchor2 - anchor);
21951 } //check for negative zero, return zero if negative zero
21952
21953
21954 return -(wholeMonthDiff + adjust) || 0;
21955 }
21956
21957 hooks.defaultFormat = 'YYYY-MM-DDTHH:mm:ssZ';
21958 hooks.defaultFormatUtc = 'YYYY-MM-DDTHH:mm:ss[Z]';
21959
21960 function toString() {
21961 return this.clone().locale('en').format('ddd MMM DD YYYY HH:mm:ss [GMT]ZZ');
21962 }
21963
21964 function toISOString(keepOffset) {
21965 if (!this.isValid()) {
21966 return null;
21967 }
21968
21969 var utc = keepOffset !== true;
21970 var m = utc ? this.clone().utc() : this;
21971
21972 if (m.year() < 0 || m.year() > 9999) {
21973 return formatMoment(m, utc ? 'YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]' : 'YYYYYY-MM-DD[T]HH:mm:ss.SSSZ');
21974 }
21975
21976 if (isFunction(Date.prototype.toISOString)) {
21977 // native implementation is ~50x faster, use it when we can
21978 if (utc) {
21979 return this.toDate().toISOString();
21980 } else {
21981 return new Date(this.valueOf() + this.utcOffset() * 60 * 1000).toISOString().replace('Z', formatMoment(m, 'Z'));
21982 }
21983 }
21984
21985 return formatMoment(m, utc ? 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]' : 'YYYY-MM-DD[T]HH:mm:ss.SSSZ');
21986 }
21987 /**
21988 * Return a human readable representation of a moment that can
21989 * also be evaluated to get a new moment which is the same
21990 *
21991 * @link https://nodejs.org/dist/latest/docs/api/util.html#util_custom_inspect_function_on_objects
21992 */
21993
21994
21995 function inspect() {
21996 if (!this.isValid()) {
21997 return 'moment.invalid(/* ' + this._i + ' */)';
21998 }
21999
22000 var func = 'moment';
22001 var zone = '';
22002
22003 if (!this.isLocal()) {
22004 func = this.utcOffset() === 0 ? 'moment.utc' : 'moment.parseZone';
22005 zone = 'Z';
22006 }
22007
22008 var prefix = '[' + func + '("]';
22009 var year = 0 <= this.year() && this.year() <= 9999 ? 'YYYY' : 'YYYYYY';
22010 var datetime = '-MM-DD[T]HH:mm:ss.SSS';
22011 var suffix = zone + '[")]';
22012 return this.format(prefix + year + datetime + suffix);
22013 }
22014
22015 function format(inputString) {
22016 if (!inputString) {
22017 inputString = this.isUtc() ? hooks.defaultFormatUtc : hooks.defaultFormat;
22018 }
22019
22020 var output = formatMoment(this, inputString);
22021 return this.localeData().postformat(output);
22022 }
22023
22024 function from(time, withoutSuffix) {
22025 if (this.isValid() && (isMoment(time) && time.isValid() || createLocal(time).isValid())) {
22026 return createDuration({
22027 to: this,
22028 from: time
22029 }).locale(this.locale()).humanize(!withoutSuffix);
22030 } else {
22031 return this.localeData().invalidDate();
22032 }
22033 }
22034
22035 function fromNow(withoutSuffix) {
22036 return this.from(createLocal(), withoutSuffix);
22037 }
22038
22039 function to(time, withoutSuffix) {
22040 if (this.isValid() && (isMoment(time) && time.isValid() || createLocal(time).isValid())) {
22041 return createDuration({
22042 from: this,
22043 to: time
22044 }).locale(this.locale()).humanize(!withoutSuffix);
22045 } else {
22046 return this.localeData().invalidDate();
22047 }
22048 }
22049
22050 function toNow(withoutSuffix) {
22051 return this.to(createLocal(), withoutSuffix);
22052 } // If passed a locale key, it will set the locale for this
22053 // instance. Otherwise, it will return the locale configuration
22054 // variables for this instance.
22055
22056
22057 function locale(key) {
22058 var newLocaleData;
22059
22060 if (key === undefined) {
22061 return this._locale._abbr;
22062 } else {
22063 newLocaleData = getLocale(key);
22064
22065 if (newLocaleData != null) {
22066 this._locale = newLocaleData;
22067 }
22068
22069 return this;
22070 }
22071 }
22072
22073 var lang = deprecate('moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.', function (key) {
22074 if (key === undefined) {
22075 return this.localeData();
22076 } else {
22077 return this.locale(key);
22078 }
22079 });
22080
22081 function localeData() {
22082 return this._locale;
22083 }
22084
22085 var MS_PER_SECOND = 1000;
22086 var MS_PER_MINUTE = 60 * MS_PER_SECOND;
22087 var MS_PER_HOUR = 60 * MS_PER_MINUTE;
22088 var MS_PER_400_YEARS = (365 * 400 + 97) * 24 * MS_PER_HOUR; // actual modulo - handles negative numbers (for dates before 1970):
22089
22090 function mod$1(dividend, divisor) {
22091 return (dividend % divisor + divisor) % divisor;
22092 }
22093
22094 function localStartOfDate(y, m, d) {
22095 // the date constructor remaps years 0-99 to 1900-1999
22096 if (y < 100 && y >= 0) {
22097 // preserve leap years using a full 400 year cycle, then reset
22098 return new Date(y + 400, m, d) - MS_PER_400_YEARS;
22099 } else {
22100 return new Date(y, m, d).valueOf();
22101 }
22102 }
22103
22104 function utcStartOfDate(y, m, d) {
22105 // Date.UTC remaps years 0-99 to 1900-1999
22106 if (y < 100 && y >= 0) {
22107 // preserve leap years using a full 400 year cycle, then reset
22108 return Date.UTC(y + 400, m, d) - MS_PER_400_YEARS;
22109 } else {
22110 return Date.UTC(y, m, d);
22111 }
22112 }
22113
22114 function startOf(units) {
22115 var time;
22116 units = normalizeUnits(units);
22117
22118 if (units === undefined || units === 'millisecond' || !this.isValid()) {
22119 return this;
22120 }
22121
22122 var startOfDate = this._isUTC ? utcStartOfDate : localStartOfDate;
22123
22124 switch (units) {
22125 case 'year':
22126 time = startOfDate(this.year(), 0, 1);
22127 break;
22128
22129 case 'quarter':
22130 time = startOfDate(this.year(), this.month() - this.month() % 3, 1);
22131 break;
22132
22133 case 'month':
22134 time = startOfDate(this.year(), this.month(), 1);
22135 break;
22136
22137 case 'week':
22138 time = startOfDate(this.year(), this.month(), this.date() - this.weekday());
22139 break;
22140
22141 case 'isoWeek':
22142 time = startOfDate(this.year(), this.month(), this.date() - (this.isoWeekday() - 1));
22143 break;
22144
22145 case 'day':
22146 case 'date':
22147 time = startOfDate(this.year(), this.month(), this.date());
22148 break;
22149
22150 case 'hour':
22151 time = this._d.valueOf();
22152 time -= mod$1(time + (this._isUTC ? 0 : this.utcOffset() * MS_PER_MINUTE), MS_PER_HOUR);
22153 break;
22154
22155 case 'minute':
22156 time = this._d.valueOf();
22157 time -= mod$1(time, MS_PER_MINUTE);
22158 break;
22159
22160 case 'second':
22161 time = this._d.valueOf();
22162 time -= mod$1(time, MS_PER_SECOND);
22163 break;
22164 }
22165
22166 this._d.setTime(time);
22167
22168 hooks.updateOffset(this, true);
22169 return this;
22170 }
22171
22172 function endOf(units) {
22173 var time;
22174 units = normalizeUnits(units);
22175
22176 if (units === undefined || units === 'millisecond' || !this.isValid()) {
22177 return this;
22178 }
22179
22180 var startOfDate = this._isUTC ? utcStartOfDate : localStartOfDate;
22181
22182 switch (units) {
22183 case 'year':
22184 time = startOfDate(this.year() + 1, 0, 1) - 1;
22185 break;
22186
22187 case 'quarter':
22188 time = startOfDate(this.year(), this.month() - this.month() % 3 + 3, 1) - 1;
22189 break;
22190
22191 case 'month':
22192 time = startOfDate(this.year(), this.month() + 1, 1) - 1;
22193 break;
22194
22195 case 'week':
22196 time = startOfDate(this.year(), this.month(), this.date() - this.weekday() + 7) - 1;
22197 break;
22198
22199 case 'isoWeek':
22200 time = startOfDate(this.year(), this.month(), this.date() - (this.isoWeekday() - 1) + 7) - 1;
22201 break;
22202
22203 case 'day':
22204 case 'date':
22205 time = startOfDate(this.year(), this.month(), this.date() + 1) - 1;
22206 break;
22207
22208 case 'hour':
22209 time = this._d.valueOf();
22210 time += MS_PER_HOUR - mod$1(time + (this._isUTC ? 0 : this.utcOffset() * MS_PER_MINUTE), MS_PER_HOUR) - 1;
22211 break;
22212
22213 case 'minute':
22214 time = this._d.valueOf();
22215 time += MS_PER_MINUTE - mod$1(time, MS_PER_MINUTE) - 1;
22216 break;
22217
22218 case 'second':
22219 time = this._d.valueOf();
22220 time += MS_PER_SECOND - mod$1(time, MS_PER_SECOND) - 1;
22221 break;
22222 }
22223
22224 this._d.setTime(time);
22225
22226 hooks.updateOffset(this, true);
22227 return this;
22228 }
22229
22230 function valueOf() {
22231 return this._d.valueOf() - (this._offset || 0) * 60000;
22232 }
22233
22234 function unix() {
22235 return Math.floor(this.valueOf() / 1000);
22236 }
22237
22238 function toDate() {
22239 return new Date(this.valueOf());
22240 }
22241
22242 function toArray() {
22243 var m = this;
22244 return [m.year(), m.month(), m.date(), m.hour(), m.minute(), m.second(), m.millisecond()];
22245 }
22246
22247 function toObject() {
22248 var m = this;
22249 return {
22250 years: m.year(),
22251 months: m.month(),
22252 date: m.date(),
22253 hours: m.hours(),
22254 minutes: m.minutes(),
22255 seconds: m.seconds(),
22256 milliseconds: m.milliseconds()
22257 };
22258 }
22259
22260 function toJSON() {
22261 // new Date(NaN).toJSON() === null
22262 return this.isValid() ? this.toISOString() : null;
22263 }
22264
22265 function isValid$2() {
22266 return isValid(this);
22267 }
22268
22269 function parsingFlags() {
22270 return extend({}, getParsingFlags(this));
22271 }
22272
22273 function invalidAt() {
22274 return getParsingFlags(this).overflow;
22275 }
22276
22277 function creationData() {
22278 return {
22279 input: this._i,
22280 format: this._f,
22281 locale: this._locale,
22282 isUTC: this._isUTC,
22283 strict: this._strict
22284 };
22285 } // FORMATTING
22286
22287
22288 addFormatToken(0, ['gg', 2], 0, function () {
22289 return this.weekYear() % 100;
22290 });
22291 addFormatToken(0, ['GG', 2], 0, function () {
22292 return this.isoWeekYear() % 100;
22293 });
22294
22295 function addWeekYearFormatToken(token, getter) {
22296 addFormatToken(0, [token, token.length], 0, getter);
22297 }
22298
22299 addWeekYearFormatToken('gggg', 'weekYear');
22300 addWeekYearFormatToken('ggggg', 'weekYear');
22301 addWeekYearFormatToken('GGGG', 'isoWeekYear');
22302 addWeekYearFormatToken('GGGGG', 'isoWeekYear'); // ALIASES
22303
22304 addUnitAlias('weekYear', 'gg');
22305 addUnitAlias('isoWeekYear', 'GG'); // PRIORITY
22306
22307 addUnitPriority('weekYear', 1);
22308 addUnitPriority('isoWeekYear', 1); // PARSING
22309
22310 addRegexToken('G', matchSigned);
22311 addRegexToken('g', matchSigned);
22312 addRegexToken('GG', match1to2, match2);
22313 addRegexToken('gg', match1to2, match2);
22314 addRegexToken('GGGG', match1to4, match4);
22315 addRegexToken('gggg', match1to4, match4);
22316 addRegexToken('GGGGG', match1to6, match6);
22317 addRegexToken('ggggg', match1to6, match6);
22318 addWeekParseToken(['gggg', 'ggggg', 'GGGG', 'GGGGG'], function (input, week, config, token) {
22319 week[token.substr(0, 2)] = toInt(input);
22320 });
22321 addWeekParseToken(['gg', 'GG'], function (input, week, config, token) {
22322 week[token] = hooks.parseTwoDigitYear(input);
22323 }); // MOMENTS
22324
22325 function getSetWeekYear(input) {
22326 return getSetWeekYearHelper.call(this, input, this.week(), this.weekday(), this.localeData()._week.dow, this.localeData()._week.doy);
22327 }
22328
22329 function getSetISOWeekYear(input) {
22330 return getSetWeekYearHelper.call(this, input, this.isoWeek(), this.isoWeekday(), 1, 4);
22331 }
22332
22333 function getISOWeeksInYear() {
22334 return weeksInYear(this.year(), 1, 4);
22335 }
22336
22337 function getWeeksInYear() {
22338 var weekInfo = this.localeData()._week;
22339
22340 return weeksInYear(this.year(), weekInfo.dow, weekInfo.doy);
22341 }
22342
22343 function getSetWeekYearHelper(input, week, weekday, dow, doy) {
22344 var weeksTarget;
22345
22346 if (input == null) {
22347 return weekOfYear(this, dow, doy).year;
22348 } else {
22349 weeksTarget = weeksInYear(input, dow, doy);
22350
22351 if (week > weeksTarget) {
22352 week = weeksTarget;
22353 }
22354
22355 return setWeekAll.call(this, input, week, weekday, dow, doy);
22356 }
22357 }
22358
22359 function setWeekAll(weekYear, week, weekday, dow, doy) {
22360 var dayOfYearData = dayOfYearFromWeeks(weekYear, week, weekday, dow, doy),
22361 date = createUTCDate(dayOfYearData.year, 0, dayOfYearData.dayOfYear);
22362 this.year(date.getUTCFullYear());
22363 this.month(date.getUTCMonth());
22364 this.date(date.getUTCDate());
22365 return this;
22366 } // FORMATTING
22367
22368
22369 addFormatToken('Q', 0, 'Qo', 'quarter'); // ALIASES
22370
22371 addUnitAlias('quarter', 'Q'); // PRIORITY
22372
22373 addUnitPriority('quarter', 7); // PARSING
22374
22375 addRegexToken('Q', match1);
22376 addParseToken('Q', function (input, array) {
22377 array[MONTH] = (toInt(input) - 1) * 3;
22378 }); // MOMENTS
22379
22380 function getSetQuarter(input) {
22381 return input == null ? Math.ceil((this.month() + 1) / 3) : this.month((input - 1) * 3 + this.month() % 3);
22382 } // FORMATTING
22383
22384
22385 addFormatToken('D', ['DD', 2], 'Do', 'date'); // ALIASES
22386
22387 addUnitAlias('date', 'D'); // PRIORITY
22388
22389 addUnitPriority('date', 9); // PARSING
22390
22391 addRegexToken('D', match1to2);
22392 addRegexToken('DD', match1to2, match2);
22393 addRegexToken('Do', function (isStrict, locale) {
22394 // TODO: Remove "ordinalParse" fallback in next major release.
22395 return isStrict ? locale._dayOfMonthOrdinalParse || locale._ordinalParse : locale._dayOfMonthOrdinalParseLenient;
22396 });
22397 addParseToken(['D', 'DD'], DATE);
22398 addParseToken('Do', function (input, array) {
22399 array[DATE] = toInt(input.match(match1to2)[0]);
22400 }); // MOMENTS
22401
22402 var getSetDayOfMonth = makeGetSet('Date', true); // FORMATTING
22403
22404 addFormatToken('DDD', ['DDDD', 3], 'DDDo', 'dayOfYear'); // ALIASES
22405
22406 addUnitAlias('dayOfYear', 'DDD'); // PRIORITY
22407
22408 addUnitPriority('dayOfYear', 4); // PARSING
22409
22410 addRegexToken('DDD', match1to3);
22411 addRegexToken('DDDD', match3);
22412 addParseToken(['DDD', 'DDDD'], function (input, array, config) {
22413 config._dayOfYear = toInt(input);
22414 }); // HELPERS
22415 // MOMENTS
22416
22417 function getSetDayOfYear(input) {
22418 var dayOfYear = Math.round((this.clone().startOf('day') - this.clone().startOf('year')) / 864e5) + 1;
22419 return input == null ? dayOfYear : this.add(input - dayOfYear, 'd');
22420 } // FORMATTING
22421
22422
22423 addFormatToken('m', ['mm', 2], 0, 'minute'); // ALIASES
22424
22425 addUnitAlias('minute', 'm'); // PRIORITY
22426
22427 addUnitPriority('minute', 14); // PARSING
22428
22429 addRegexToken('m', match1to2);
22430 addRegexToken('mm', match1to2, match2);
22431 addParseToken(['m', 'mm'], MINUTE); // MOMENTS
22432
22433 var getSetMinute = makeGetSet('Minutes', false); // FORMATTING
22434
22435 addFormatToken('s', ['ss', 2], 0, 'second'); // ALIASES
22436
22437 addUnitAlias('second', 's'); // PRIORITY
22438
22439 addUnitPriority('second', 15); // PARSING
22440
22441 addRegexToken('s', match1to2);
22442 addRegexToken('ss', match1to2, match2);
22443 addParseToken(['s', 'ss'], SECOND); // MOMENTS
22444
22445 var getSetSecond = makeGetSet('Seconds', false); // FORMATTING
22446
22447 addFormatToken('S', 0, 0, function () {
22448 return ~~(this.millisecond() / 100);
22449 });
22450 addFormatToken(0, ['SS', 2], 0, function () {
22451 return ~~(this.millisecond() / 10);
22452 });
22453 addFormatToken(0, ['SSS', 3], 0, 'millisecond');
22454 addFormatToken(0, ['SSSS', 4], 0, function () {
22455 return this.millisecond() * 10;
22456 });
22457 addFormatToken(0, ['SSSSS', 5], 0, function () {
22458 return this.millisecond() * 100;
22459 });
22460 addFormatToken(0, ['SSSSSS', 6], 0, function () {
22461 return this.millisecond() * 1000;
22462 });
22463 addFormatToken(0, ['SSSSSSS', 7], 0, function () {
22464 return this.millisecond() * 10000;
22465 });
22466 addFormatToken(0, ['SSSSSSSS', 8], 0, function () {
22467 return this.millisecond() * 100000;
22468 });
22469 addFormatToken(0, ['SSSSSSSSS', 9], 0, function () {
22470 return this.millisecond() * 1000000;
22471 }); // ALIASES
22472
22473 addUnitAlias('millisecond', 'ms'); // PRIORITY
22474
22475 addUnitPriority('millisecond', 16); // PARSING
22476
22477 addRegexToken('S', match1to3, match1);
22478 addRegexToken('SS', match1to3, match2);
22479 addRegexToken('SSS', match1to3, match3);
22480 var token;
22481
22482 for (token = 'SSSS'; token.length <= 9; token += 'S') {
22483 addRegexToken(token, matchUnsigned);
22484 }
22485
22486 function parseMs(input, array) {
22487 array[MILLISECOND] = toInt(('0.' + input) * 1000);
22488 }
22489
22490 for (token = 'S'; token.length <= 9; token += 'S') {
22491 addParseToken(token, parseMs);
22492 } // MOMENTS
22493
22494
22495 var getSetMillisecond = makeGetSet('Milliseconds', false); // FORMATTING
22496
22497 addFormatToken('z', 0, 0, 'zoneAbbr');
22498 addFormatToken('zz', 0, 0, 'zoneName'); // MOMENTS
22499
22500 function getZoneAbbr() {
22501 return this._isUTC ? 'UTC' : '';
22502 }
22503
22504 function getZoneName() {
22505 return this._isUTC ? 'Coordinated Universal Time' : '';
22506 }
22507
22508 var proto = Moment.prototype;
22509 proto.add = add;
22510 proto.calendar = calendar$1;
22511 proto.clone = clone;
22512 proto.diff = diff;
22513 proto.endOf = endOf;
22514 proto.format = format;
22515 proto.from = from;
22516 proto.fromNow = fromNow;
22517 proto.to = to;
22518 proto.toNow = toNow;
22519 proto.get = stringGet;
22520 proto.invalidAt = invalidAt;
22521 proto.isAfter = isAfter;
22522 proto.isBefore = isBefore;
22523 proto.isBetween = isBetween;
22524 proto.isSame = isSame;
22525 proto.isSameOrAfter = isSameOrAfter;
22526 proto.isSameOrBefore = isSameOrBefore;
22527 proto.isValid = isValid$2;
22528 proto.lang = lang;
22529 proto.locale = locale;
22530 proto.localeData = localeData;
22531 proto.max = prototypeMax;
22532 proto.min = prototypeMin;
22533 proto.parsingFlags = parsingFlags;
22534 proto.set = stringSet;
22535 proto.startOf = startOf;
22536 proto.subtract = subtract;
22537 proto.toArray = toArray;
22538 proto.toObject = toObject;
22539 proto.toDate = toDate;
22540 proto.toISOString = toISOString;
22541 proto.inspect = inspect;
22542 proto.toJSON = toJSON;
22543 proto.toString = toString;
22544 proto.unix = unix;
22545 proto.valueOf = valueOf;
22546 proto.creationData = creationData;
22547 proto.year = getSetYear;
22548 proto.isLeapYear = getIsLeapYear;
22549 proto.weekYear = getSetWeekYear;
22550 proto.isoWeekYear = getSetISOWeekYear;
22551 proto.quarter = proto.quarters = getSetQuarter;
22552 proto.month = getSetMonth;
22553 proto.daysInMonth = getDaysInMonth;
22554 proto.week = proto.weeks = getSetWeek;
22555 proto.isoWeek = proto.isoWeeks = getSetISOWeek;
22556 proto.weeksInYear = getWeeksInYear;
22557 proto.isoWeeksInYear = getISOWeeksInYear;
22558 proto.date = getSetDayOfMonth;
22559 proto.day = proto.days = getSetDayOfWeek;
22560 proto.weekday = getSetLocaleDayOfWeek;
22561 proto.isoWeekday = getSetISODayOfWeek;
22562 proto.dayOfYear = getSetDayOfYear;
22563 proto.hour = proto.hours = getSetHour;
22564 proto.minute = proto.minutes = getSetMinute;
22565 proto.second = proto.seconds = getSetSecond;
22566 proto.millisecond = proto.milliseconds = getSetMillisecond;
22567 proto.utcOffset = getSetOffset;
22568 proto.utc = setOffsetToUTC;
22569 proto.local = setOffsetToLocal;
22570 proto.parseZone = setOffsetToParsedOffset;
22571 proto.hasAlignedHourOffset = hasAlignedHourOffset;
22572 proto.isDST = isDaylightSavingTime;
22573 proto.isLocal = isLocal;
22574 proto.isUtcOffset = isUtcOffset;
22575 proto.isUtc = isUtc;
22576 proto.isUTC = isUtc;
22577 proto.zoneAbbr = getZoneAbbr;
22578 proto.zoneName = getZoneName;
22579 proto.dates = deprecate('dates accessor is deprecated. Use date instead.', getSetDayOfMonth);
22580 proto.months = deprecate('months accessor is deprecated. Use month instead', getSetMonth);
22581 proto.years = deprecate('years accessor is deprecated. Use year instead', getSetYear);
22582 proto.zone = deprecate('moment().zone is deprecated, use moment().utcOffset instead. http://momentjs.com/guides/#/warnings/zone/', getSetZone);
22583 proto.isDSTShifted = deprecate('isDSTShifted is deprecated. See http://momentjs.com/guides/#/warnings/dst-shifted/ for more information', isDaylightSavingTimeShifted);
22584
22585 function createUnix(input) {
22586 return createLocal(input * 1000);
22587 }
22588
22589 function createInZone() {
22590 return createLocal.apply(null, arguments).parseZone();
22591 }
22592
22593 function preParsePostFormat(string) {
22594 return string;
22595 }
22596
22597 var proto$1 = Locale.prototype;
22598 proto$1.calendar = calendar;
22599 proto$1.longDateFormat = longDateFormat;
22600 proto$1.invalidDate = invalidDate;
22601 proto$1.ordinal = ordinal;
22602 proto$1.preparse = preParsePostFormat;
22603 proto$1.postformat = preParsePostFormat;
22604 proto$1.relativeTime = relativeTime;
22605 proto$1.pastFuture = pastFuture;
22606 proto$1.set = set;
22607 proto$1.months = localeMonths;
22608 proto$1.monthsShort = localeMonthsShort;
22609 proto$1.monthsParse = localeMonthsParse;
22610 proto$1.monthsRegex = monthsRegex;
22611 proto$1.monthsShortRegex = monthsShortRegex;
22612 proto$1.week = localeWeek;
22613 proto$1.firstDayOfYear = localeFirstDayOfYear;
22614 proto$1.firstDayOfWeek = localeFirstDayOfWeek;
22615 proto$1.weekdays = localeWeekdays;
22616 proto$1.weekdaysMin = localeWeekdaysMin;
22617 proto$1.weekdaysShort = localeWeekdaysShort;
22618 proto$1.weekdaysParse = localeWeekdaysParse;
22619 proto$1.weekdaysRegex = weekdaysRegex;
22620 proto$1.weekdaysShortRegex = weekdaysShortRegex;
22621 proto$1.weekdaysMinRegex = weekdaysMinRegex;
22622 proto$1.isPM = localeIsPM;
22623 proto$1.meridiem = localeMeridiem;
22624
22625 function get$1(format, index, field, setter) {
22626 var locale = getLocale();
22627 var utc = createUTC().set(setter, index);
22628 return locale[field](utc, format);
22629 }
22630
22631 function listMonthsImpl(format, index, field) {
22632 if (isNumber(format)) {
22633 index = format;
22634 format = undefined;
22635 }
22636
22637 format = format || '';
22638
22639 if (index != null) {
22640 return get$1(format, index, field, 'month');
22641 }
22642
22643 var i;
22644 var out = [];
22645
22646 for (i = 0; i < 12; i++) {
22647 out[i] = get$1(format, i, field, 'month');
22648 }
22649
22650 return out;
22651 } // ()
22652 // (5)
22653 // (fmt, 5)
22654 // (fmt)
22655 // (true)
22656 // (true, 5)
22657 // (true, fmt, 5)
22658 // (true, fmt)
22659
22660
22661 function listWeekdaysImpl(localeSorted, format, index, field) {
22662 if (typeof localeSorted === 'boolean') {
22663 if (isNumber(format)) {
22664 index = format;
22665 format = undefined;
22666 }
22667
22668 format = format || '';
22669 } else {
22670 format = localeSorted;
22671 index = format;
22672 localeSorted = false;
22673
22674 if (isNumber(format)) {
22675 index = format;
22676 format = undefined;
22677 }
22678
22679 format = format || '';
22680 }
22681
22682 var locale = getLocale(),
22683 shift = localeSorted ? locale._week.dow : 0;
22684
22685 if (index != null) {
22686 return get$1(format, (index + shift) % 7, field, 'day');
22687 }
22688
22689 var i;
22690 var out = [];
22691
22692 for (i = 0; i < 7; i++) {
22693 out[i] = get$1(format, (i + shift) % 7, field, 'day');
22694 }
22695
22696 return out;
22697 }
22698
22699 function listMonths(format, index) {
22700 return listMonthsImpl(format, index, 'months');
22701 }
22702
22703 function listMonthsShort(format, index) {
22704 return listMonthsImpl(format, index, 'monthsShort');
22705 }
22706
22707 function listWeekdays(localeSorted, format, index) {
22708 return listWeekdaysImpl(localeSorted, format, index, 'weekdays');
22709 }
22710
22711 function listWeekdaysShort(localeSorted, format, index) {
22712 return listWeekdaysImpl(localeSorted, format, index, 'weekdaysShort');
22713 }
22714
22715 function listWeekdaysMin(localeSorted, format, index) {
22716 return listWeekdaysImpl(localeSorted, format, index, 'weekdaysMin');
22717 }
22718
22719 getSetGlobalLocale('en', {
22720 dayOfMonthOrdinalParse: /\d{1,2}(th|st|nd|rd)/,
22721 ordinal: function (number) {
22722 var b = number % 10,
22723 output = toInt(number % 100 / 10) === 1 ? 'th' : b === 1 ? 'st' : b === 2 ? 'nd' : b === 3 ? 'rd' : 'th';
22724 return number + output;
22725 }
22726 }); // Side effect imports
22727
22728 hooks.lang = deprecate('moment.lang is deprecated. Use moment.locale instead.', getSetGlobalLocale);
22729 hooks.langData = deprecate('moment.langData is deprecated. Use moment.localeData instead.', getLocale);
22730 var mathAbs = Math.abs;
22731
22732 function abs() {
22733 var data = this._data;
22734 this._milliseconds = mathAbs(this._milliseconds);
22735 this._days = mathAbs(this._days);
22736 this._months = mathAbs(this._months);
22737 data.milliseconds = mathAbs(data.milliseconds);
22738 data.seconds = mathAbs(data.seconds);
22739 data.minutes = mathAbs(data.minutes);
22740 data.hours = mathAbs(data.hours);
22741 data.months = mathAbs(data.months);
22742 data.years = mathAbs(data.years);
22743 return this;
22744 }
22745
22746 function addSubtract$1(duration, input, value, direction) {
22747 var other = createDuration(input, value);
22748 duration._milliseconds += direction * other._milliseconds;
22749 duration._days += direction * other._days;
22750 duration._months += direction * other._months;
22751 return duration._bubble();
22752 } // supports only 2.0-style add(1, 's') or add(duration)
22753
22754
22755 function add$1(input, value) {
22756 return addSubtract$1(this, input, value, 1);
22757 } // supports only 2.0-style subtract(1, 's') or subtract(duration)
22758
22759
22760 function subtract$1(input, value) {
22761 return addSubtract$1(this, input, value, -1);
22762 }
22763
22764 function absCeil(number) {
22765 if (number < 0) {
22766 return Math.floor(number);
22767 } else {
22768 return Math.ceil(number);
22769 }
22770 }
22771
22772 function bubble() {
22773 var milliseconds = this._milliseconds;
22774 var days = this._days;
22775 var months = this._months;
22776 var data = this._data;
22777 var seconds, minutes, hours, years, monthsFromDays; // if we have a mix of positive and negative values, bubble down first
22778 // check: https://github.com/moment/moment/issues/2166
22779
22780 if (!(milliseconds >= 0 && days >= 0 && months >= 0 || milliseconds <= 0 && days <= 0 && months <= 0)) {
22781 milliseconds += absCeil(monthsToDays(months) + days) * 864e5;
22782 days = 0;
22783 months = 0;
22784 } // The following code bubbles up values, see the tests for
22785 // examples of what that means.
22786
22787
22788 data.milliseconds = milliseconds % 1000;
22789 seconds = absFloor(milliseconds / 1000);
22790 data.seconds = seconds % 60;
22791 minutes = absFloor(seconds / 60);
22792 data.minutes = minutes % 60;
22793 hours = absFloor(minutes / 60);
22794 data.hours = hours % 24;
22795 days += absFloor(hours / 24); // convert days to months
22796
22797 monthsFromDays = absFloor(daysToMonths(days));
22798 months += monthsFromDays;
22799 days -= absCeil(monthsToDays(monthsFromDays)); // 12 months -> 1 year
22800
22801 years = absFloor(months / 12);
22802 months %= 12;
22803 data.days = days;
22804 data.months = months;
22805 data.years = years;
22806 return this;
22807 }
22808
22809 function daysToMonths(days) {
22810 // 400 years have 146097 days (taking into account leap year rules)
22811 // 400 years have 12 months === 4800
22812 return days * 4800 / 146097;
22813 }
22814
22815 function monthsToDays(months) {
22816 // the reverse of daysToMonths
22817 return months * 146097 / 4800;
22818 }
22819
22820 function as(units) {
22821 if (!this.isValid()) {
22822 return NaN;
22823 }
22824
22825 var days;
22826 var months;
22827 var milliseconds = this._milliseconds;
22828 units = normalizeUnits(units);
22829
22830 if (units === 'month' || units === 'quarter' || units === 'year') {
22831 days = this._days + milliseconds / 864e5;
22832 months = this._months + daysToMonths(days);
22833
22834 switch (units) {
22835 case 'month':
22836 return months;
22837
22838 case 'quarter':
22839 return months / 3;
22840
22841 case 'year':
22842 return months / 12;
22843 }
22844 } else {
22845 // handle milliseconds separately because of floating point math errors (issue #1867)
22846 days = this._days + Math.round(monthsToDays(this._months));
22847
22848 switch (units) {
22849 case 'week':
22850 return days / 7 + milliseconds / 6048e5;
22851
22852 case 'day':
22853 return days + milliseconds / 864e5;
22854
22855 case 'hour':
22856 return days * 24 + milliseconds / 36e5;
22857
22858 case 'minute':
22859 return days * 1440 + milliseconds / 6e4;
22860
22861 case 'second':
22862 return days * 86400 + milliseconds / 1000;
22863 // Math.floor prevents floating point math errors here
22864
22865 case 'millisecond':
22866 return Math.floor(days * 864e5) + milliseconds;
22867
22868 default:
22869 throw new Error('Unknown unit ' + units);
22870 }
22871 }
22872 } // TODO: Use this.as('ms')?
22873
22874
22875 function valueOf$1() {
22876 if (!this.isValid()) {
22877 return NaN;
22878 }
22879
22880 return this._milliseconds + this._days * 864e5 + this._months % 12 * 2592e6 + toInt(this._months / 12) * 31536e6;
22881 }
22882
22883 function makeAs(alias) {
22884 return function () {
22885 return this.as(alias);
22886 };
22887 }
22888
22889 var asMilliseconds = makeAs('ms');
22890 var asSeconds = makeAs('s');
22891 var asMinutes = makeAs('m');
22892 var asHours = makeAs('h');
22893 var asDays = makeAs('d');
22894 var asWeeks = makeAs('w');
22895 var asMonths = makeAs('M');
22896 var asQuarters = makeAs('Q');
22897 var asYears = makeAs('y');
22898
22899 function clone$1() {
22900 return createDuration(this);
22901 }
22902
22903 function get$2(units) {
22904 units = normalizeUnits(units);
22905 return this.isValid() ? this[units + 's']() : NaN;
22906 }
22907
22908 function makeGetter(name) {
22909 return function () {
22910 return this.isValid() ? this._data[name] : NaN;
22911 };
22912 }
22913
22914 var milliseconds = makeGetter('milliseconds');
22915 var seconds = makeGetter('seconds');
22916 var minutes = makeGetter('minutes');
22917 var hours = makeGetter('hours');
22918 var days = makeGetter('days');
22919 var months = makeGetter('months');
22920 var years = makeGetter('years');
22921
22922 function weeks() {
22923 return absFloor(this.days() / 7);
22924 }
22925
22926 var round = Math.round;
22927 var thresholds = {
22928 ss: 44,
22929 // a few seconds to seconds
22930 s: 45,
22931 // seconds to minute
22932 m: 45,
22933 // minutes to hour
22934 h: 22,
22935 // hours to day
22936 d: 26,
22937 // days to month
22938 M: 11 // months to year
22939
22940 }; // helper function for moment.fn.from, moment.fn.fromNow, and moment.duration.fn.humanize
22941
22942 function substituteTimeAgo(string, number, withoutSuffix, isFuture, locale) {
22943 return locale.relativeTime(number || 1, !!withoutSuffix, string, isFuture);
22944 }
22945
22946 function relativeTime$1(posNegDuration, withoutSuffix, locale) {
22947 var duration = createDuration(posNegDuration).abs();
22948 var seconds = round(duration.as('s'));
22949 var minutes = round(duration.as('m'));
22950 var hours = round(duration.as('h'));
22951 var days = round(duration.as('d'));
22952 var months = round(duration.as('M'));
22953 var years = round(duration.as('y'));
22954 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];
22955 a[2] = withoutSuffix;
22956 a[3] = +posNegDuration > 0;
22957 a[4] = locale;
22958 return substituteTimeAgo.apply(null, a);
22959 } // This function allows you to set the rounding function for relative time strings
22960
22961
22962 function getSetRelativeTimeRounding(roundingFunction) {
22963 if (roundingFunction === undefined) {
22964 return round;
22965 }
22966
22967 if (typeof roundingFunction === 'function') {
22968 round = roundingFunction;
22969 return true;
22970 }
22971
22972 return false;
22973 } // This function allows you to set a threshold for relative time strings
22974
22975
22976 function getSetRelativeTimeThreshold(threshold, limit) {
22977 if (thresholds[threshold] === undefined) {
22978 return false;
22979 }
22980
22981 if (limit === undefined) {
22982 return thresholds[threshold];
22983 }
22984
22985 thresholds[threshold] = limit;
22986
22987 if (threshold === 's') {
22988 thresholds.ss = limit - 1;
22989 }
22990
22991 return true;
22992 }
22993
22994 function humanize(withSuffix) {
22995 if (!this.isValid()) {
22996 return this.localeData().invalidDate();
22997 }
22998
22999 var locale = this.localeData();
23000 var output = relativeTime$1(this, !withSuffix, locale);
23001
23002 if (withSuffix) {
23003 output = locale.pastFuture(+this, output);
23004 }
23005
23006 return locale.postformat(output);
23007 }
23008
23009 var abs$1 = Math.abs;
23010
23011 function sign(x) {
23012 return (x > 0) - (x < 0) || +x;
23013 }
23014
23015 function toISOString$1() {
23016 // for ISO strings we do not use the normal bubbling rules:
23017 // * milliseconds bubble up until they become hours
23018 // * days do not bubble at all
23019 // * months bubble up until they become years
23020 // This is because there is no context-free conversion between hours and days
23021 // (think of clock changes)
23022 // and also not between days and months (28-31 days per month)
23023 if (!this.isValid()) {
23024 return this.localeData().invalidDate();
23025 }
23026
23027 var seconds = abs$1(this._milliseconds) / 1000;
23028 var days = abs$1(this._days);
23029 var months = abs$1(this._months);
23030 var minutes, hours, years; // 3600 seconds -> 60 minutes -> 1 hour
23031
23032 minutes = absFloor(seconds / 60);
23033 hours = absFloor(minutes / 60);
23034 seconds %= 60;
23035 minutes %= 60; // 12 months -> 1 year
23036
23037 years = absFloor(months / 12);
23038 months %= 12; // inspired by https://github.com/dordille/moment-isoduration/blob/master/moment.isoduration.js
23039
23040 var Y = years;
23041 var M = months;
23042 var D = days;
23043 var h = hours;
23044 var m = minutes;
23045 var s = seconds ? seconds.toFixed(3).replace(/\.?0+$/, '') : '';
23046 var total = this.asSeconds();
23047
23048 if (!total) {
23049 // this is the same as C#'s (Noda) and python (isodate)...
23050 // but not other JS (goog.date)
23051 return 'P0D';
23052 }
23053
23054 var totalSign = total < 0 ? '-' : '';
23055 var ymSign = sign(this._months) !== sign(total) ? '-' : '';
23056 var daysSign = sign(this._days) !== sign(total) ? '-' : '';
23057 var hmsSign = sign(this._milliseconds) !== sign(total) ? '-' : '';
23058 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' : '');
23059 }
23060
23061 var proto$2 = Duration.prototype;
23062 proto$2.isValid = isValid$1;
23063 proto$2.abs = abs;
23064 proto$2.add = add$1;
23065 proto$2.subtract = subtract$1;
23066 proto$2.as = as;
23067 proto$2.asMilliseconds = asMilliseconds;
23068 proto$2.asSeconds = asSeconds;
23069 proto$2.asMinutes = asMinutes;
23070 proto$2.asHours = asHours;
23071 proto$2.asDays = asDays;
23072 proto$2.asWeeks = asWeeks;
23073 proto$2.asMonths = asMonths;
23074 proto$2.asQuarters = asQuarters;
23075 proto$2.asYears = asYears;
23076 proto$2.valueOf = valueOf$1;
23077 proto$2._bubble = bubble;
23078 proto$2.clone = clone$1;
23079 proto$2.get = get$2;
23080 proto$2.milliseconds = milliseconds;
23081 proto$2.seconds = seconds;
23082 proto$2.minutes = minutes;
23083 proto$2.hours = hours;
23084 proto$2.days = days;
23085 proto$2.weeks = weeks;
23086 proto$2.months = months;
23087 proto$2.years = years;
23088 proto$2.humanize = humanize;
23089 proto$2.toISOString = toISOString$1;
23090 proto$2.toString = toISOString$1;
23091 proto$2.toJSON = toISOString$1;
23092 proto$2.locale = locale;
23093 proto$2.localeData = localeData;
23094 proto$2.toIsoString = deprecate('toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)', toISOString$1);
23095 proto$2.lang = lang; // Side effect imports
23096 // FORMATTING
23097
23098 addFormatToken('X', 0, 0, 'unix');
23099 addFormatToken('x', 0, 0, 'valueOf'); // PARSING
23100
23101 addRegexToken('x', matchSigned);
23102 addRegexToken('X', matchTimestamp);
23103 addParseToken('X', function (input, array, config) {
23104 config._d = new Date(parseFloat(input, 10) * 1000);
23105 });
23106 addParseToken('x', function (input, array, config) {
23107 config._d = new Date(toInt(input));
23108 }); // Side effect imports
23109
23110 hooks.version = '2.24.0';
23111 setHookCallback(createLocal);
23112 hooks.fn = proto;
23113 hooks.min = min;
23114 hooks.max = max;
23115 hooks.now = now;
23116 hooks.utc = createUTC;
23117 hooks.unix = createUnix;
23118 hooks.months = listMonths;
23119 hooks.isDate = isDate;
23120 hooks.locale = getSetGlobalLocale;
23121 hooks.invalid = createInvalid;
23122 hooks.duration = createDuration;
23123 hooks.isMoment = isMoment;
23124 hooks.weekdays = listWeekdays;
23125 hooks.parseZone = createInZone;
23126 hooks.localeData = getLocale;
23127 hooks.isDuration = isDuration;
23128 hooks.monthsShort = listMonthsShort;
23129 hooks.weekdaysMin = listWeekdaysMin;
23130 hooks.defineLocale = defineLocale;
23131 hooks.updateLocale = updateLocale;
23132 hooks.locales = listLocales;
23133 hooks.weekdaysShort = listWeekdaysShort;
23134 hooks.normalizeUnits = normalizeUnits;
23135 hooks.relativeTimeRounding = getSetRelativeTimeRounding;
23136 hooks.relativeTimeThreshold = getSetRelativeTimeThreshold;
23137 hooks.calendarFormat = getCalendarFormat;
23138 hooks.prototype = proto; // currently HTML5 input type only supports 24-hour formats
23139
23140 hooks.HTML5_FMT = {
23141 DATETIME_LOCAL: 'YYYY-MM-DDTHH:mm',
23142 // <input type="datetime-local" />
23143 DATETIME_LOCAL_SECONDS: 'YYYY-MM-DDTHH:mm:ss',
23144 // <input type="datetime-local" step="1" />
23145 DATETIME_LOCAL_MS: 'YYYY-MM-DDTHH:mm:ss.SSS',
23146 // <input type="datetime-local" step="0.001" />
23147 DATE: 'YYYY-MM-DD',
23148 // <input type="date" />
23149 TIME: 'HH:mm',
23150 // <input type="time" />
23151 TIME_SECONDS: 'HH:mm:ss',
23152 // <input type="time" step="1" />
23153 TIME_MS: 'HH:mm:ss.SSS',
23154 // <input type="time" step="0.001" />
23155 WEEK: 'GGGG-[W]WW',
23156 // <input type="week" />
23157 MONTH: 'YYYY-MM' // <input type="month" />
23158
23159 };
23160 return hooks;
23161 });
23162 }); // Maps for number <-> hex string conversion
23163
23164 var byteToHex$2$1 = [];
23165
23166 for (var i$2$1 = 0; i$2$1 < 256; i$2$1++) {
23167 byteToHex$2$1[i$2$1] = (i$2$1 + 0x100).toString(16).substr(1);
23168 }
23169 /**
23170 * Generate 16 random bytes to be used as a base for UUID.
23171 *
23172 * @ignore
23173 */
23174
23175
23176 var random$1$1 = function () {
23177 if (typeof crypto !== 'undefined' && crypto.getRandomValues) {
23178 // WHATWG crypto-based RNG - http://wiki.whatwg.org/wiki/Crypto
23179 // Moderately fast, high quality
23180 var _rnds8 = new Uint8Array(16);
23181
23182 return function whatwgRNG() {
23183 crypto.getRandomValues(_rnds8);
23184 return _rnds8;
23185 };
23186 } // Math.random()-based (RNG)
23187 //
23188 // If all else fails, use Math.random().
23189 // It's fast, but is of unspecified quality.
23190
23191
23192 var _rnds = new Array(16);
23193
23194 return function () {
23195 for (var i = 0, r; i < 16; i++) {
23196 if ((i & 0x03) === 0) {
23197 r = Math.random() * 0x100000000;
23198 }
23199
23200 _rnds[i] = r >>> ((i & 0x03) << 3) & 0xff;
23201 }
23202
23203 return _rnds;
23204 }; // uuid.js
23205 //
23206 // Copyright (c) 2010-2012 Robert Kieffer
23207 // MIT License - http://opensource.org/licenses/mit-license.php
23208 // Unique ID creation requires a high quality random # generator. We feature
23209 // detect to determine the best RNG source, normalizing to a function that
23210 // returns 128-bits of randomness, since that's what's usually required
23211 // return require('./rng');
23212 }();
23213
23214 var byteToHex$1$1$1 = [];
23215
23216 for (var i$1$1$1 = 0; i$1$1$1 < 256; i$1$1$1++) {
23217 byteToHex$1$1$1[i$1$1$1] = (i$1$1$1 + 0x100).toString(16).substr(1);
23218 } // **`v1()` - Generate time-based UUID**
23219 //
23220 // Inspired by https://github.com/LiosK/UUID.js
23221 // and http://docs.python.org/library/uuid.html
23222 // random #'s we need to init node and clockseq
23223
23224
23225 var seedBytes$1$1 = random$1$1(); // Per 4.5, create and 48-bit node id, (47 random bits + multicast bit = 1)
23226
23227 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
23228
23229 var defaultClockseq$1$1 = (seedBytes$1$1[6] << 8 | seedBytes$1$1[7]) & 0x3fff; // Previous uuid creation time
23230 // for example '/Date(1198908717056)/' or '/Date(1198908717056-0700)/'
23231 // code from http://momentjs.com/
23232
23233 var ASPDateRegex$1 = /^\/?Date\((-?\d+)/i; // Hex color
23234
23235 /**
23236 * Hue, Saturation, Value.
23237 */
23238
23239 /**
23240 * Test whether given object is a number
23241 *
23242 * @param value - Input value of unknown type.
23243 *
23244 * @returns True if number, false otherwise.
23245 */
23246
23247 function isNumber$1(value) {
23248 return value instanceof Number || typeof value === 'number';
23249 }
23250 /**
23251 * Test whether given object is a string
23252 *
23253 * @param value - Input value of unknown type.
23254 *
23255 * @returns True if string, false otherwise.
23256 */
23257
23258
23259 function isString$1(value) {
23260 return value instanceof String || typeof value === 'string';
23261 }
23262 /**
23263 * Test whether given object is a Moment date.
23264 * @TODO: This is basically a workaround, if Moment was imported property it wouldn't necessary as moment.isMoment is a TS type guard.
23265 *
23266 * @param value - Input value of unknown type.
23267 *
23268 * @returns True if Moment instance, false otherwise.
23269 */
23270
23271
23272 function isMoment$1(value) {
23273 return moment$1.isMoment(value);
23274 }
23275 /**
23276 * Copy property from b to a if property present in a.
23277 * If property in b explicitly set to null, delete it if `allowDeletion` set.
23278 *
23279 * Internal helper routine, should not be exported. Not added to `exports` for that reason.
23280 *
23281 * @param a - Target object.
23282 * @param b - Source object.
23283 * @param prop - Name of property to copy from b to a.
23284 * @param allowDeletion if true, delete property in a if explicitly set to null in b
23285 */
23286
23287
23288 function copyOrDelete$1(a, b, prop, allowDeletion) {
23289 var doDeletion = false;
23290
23291 if (allowDeletion === true) {
23292 doDeletion = b[prop] === null && a[prop] !== undefined;
23293 }
23294
23295 if (doDeletion) {
23296 delete a[prop];
23297 } else {
23298 a[prop] = b[prop]; // Remember, this is a reference copy!
23299 }
23300 }
23301 /**
23302 * Deep extend an object a with the properties of object b
23303 *
23304 * @param a - Target object.
23305 * @param b - Source object.
23306 * @param protoExtend - If true, the prototype values will also be extended
23307 * (ie. the options objects that inherit from others will also get the inherited options).
23308 * @param allowDeletion - If true, the values of fields that are null will be deleted.
23309 *
23310 * @returns Argument a.
23311 */
23312
23313
23314 function deepExtend$1(a, b) {
23315 var protoExtend = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
23316 var allowDeletion = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
23317
23318 for (var prop in b) {
23319 if (Object.prototype.hasOwnProperty.call(b, prop) || protoExtend === true) {
23320 if (b[prop] && b[prop].constructor === Object) {
23321 if (a[prop] === undefined) {
23322 a[prop] = {};
23323 }
23324
23325 if (a[prop].constructor === Object) {
23326 deepExtend$1(a[prop], b[prop], protoExtend); // NOTE: allowDeletion not propagated!
23327 } else {
23328 copyOrDelete$1(a, b, prop, allowDeletion);
23329 }
23330 } else if (Array.isArray(b[prop])) {
23331 a[prop] = [];
23332
23333 for (var i = 0; i < b[prop].length; i++) {
23334 a[prop].push(b[prop][i]);
23335 }
23336 } else {
23337 copyOrDelete$1(a, b, prop, allowDeletion);
23338 }
23339 }
23340 }
23341
23342 return a;
23343 }
23344 /**
23345 * Convert an object into another type
23346 *
23347 * @param object - Value of unknown type.
23348 * @param type - Name of the desired type.
23349 *
23350 * @returns Object in the desired type.
23351 * @throws Error
23352 */
23353
23354
23355 function convert$1(object, type) {
23356 var match;
23357
23358 if (object === undefined) {
23359 return undefined;
23360 }
23361
23362 if (object === null) {
23363 return null;
23364 }
23365
23366 if (!type) {
23367 return object;
23368 }
23369
23370 if (!(typeof type === 'string') && !(type instanceof String)) {
23371 throw new Error('Type must be a string');
23372 } //noinspection FallthroughInSwitchStatementJS
23373
23374
23375 switch (type) {
23376 case 'boolean':
23377 case 'Boolean':
23378 return Boolean(object);
23379
23380 case 'number':
23381 case 'Number':
23382 if (isString$1(object) && !isNaN(Date.parse(object))) {
23383 return moment$1(object).valueOf();
23384 } else {
23385 // @TODO: I don't think that Number and String constructors are a good idea.
23386 // This could also fail if the object doesn't have valueOf method or if it's redefined.
23387 // For example: Object.create(null) or { valueOf: 7 }.
23388 return Number(object.valueOf());
23389 }
23390
23391 case 'string':
23392 case 'String':
23393 return String(object);
23394
23395 case 'Date':
23396 if (isNumber$1(object)) {
23397 return new Date(object);
23398 }
23399
23400 if (object instanceof Date) {
23401 return new Date(object.valueOf());
23402 } else if (isMoment$1(object)) {
23403 return new Date(object.valueOf());
23404 }
23405
23406 if (isString$1(object)) {
23407 match = ASPDateRegex$1.exec(object);
23408
23409 if (match) {
23410 // object is an ASP date
23411 return new Date(Number(match[1])); // parse number
23412 } else {
23413 return moment$1(new Date(object)).toDate(); // parse string
23414 }
23415 } else {
23416 throw new Error('Cannot convert object of type ' + getType$1(object) + ' to type Date');
23417 }
23418
23419 case 'Moment':
23420 if (isNumber$1(object)) {
23421 return moment$1(object);
23422 }
23423
23424 if (object instanceof Date) {
23425 return moment$1(object.valueOf());
23426 } else if (isMoment$1(object)) {
23427 return moment$1(object);
23428 }
23429
23430 if (isString$1(object)) {
23431 match = ASPDateRegex$1.exec(object);
23432
23433 if (match) {
23434 // object is an ASP date
23435 return moment$1(Number(match[1])); // parse number
23436 } else {
23437 return moment$1(object); // parse string
23438 }
23439 } else {
23440 throw new Error('Cannot convert object of type ' + getType$1(object) + ' to type Date');
23441 }
23442
23443 case 'ISODate':
23444 if (isNumber$1(object)) {
23445 return new Date(object);
23446 } else if (object instanceof Date) {
23447 return object.toISOString();
23448 } else if (isMoment$1(object)) {
23449 return object.toDate().toISOString();
23450 } else if (isString$1(object)) {
23451 match = ASPDateRegex$1.exec(object);
23452
23453 if (match) {
23454 // object is an ASP date
23455 return new Date(Number(match[1])).toISOString(); // parse number
23456 } else {
23457 return moment$1(object).format(); // ISO 8601
23458 }
23459 } else {
23460 throw new Error('Cannot convert object of type ' + getType$1(object) + ' to type ISODate');
23461 }
23462
23463 case 'ASPDate':
23464 if (isNumber$1(object)) {
23465 return '/Date(' + object + ')/';
23466 } else if (object instanceof Date) {
23467 return '/Date(' + object.valueOf() + ')/';
23468 } else if (isString$1(object)) {
23469 match = ASPDateRegex$1.exec(object);
23470
23471 var _value;
23472
23473 if (match) {
23474 // object is an ASP date
23475 _value = new Date(Number(match[1])).valueOf(); // parse number
23476 } else {
23477 _value = new Date(object).valueOf(); // parse string
23478 }
23479
23480 return '/Date(' + _value + ')/';
23481 } else {
23482 throw new Error('Cannot convert object of type ' + getType$1(object) + ' to type ASPDate');
23483 }
23484
23485 default:
23486 var never = type;
23487 throw new Error("Unknown type ".concat(never));
23488 }
23489 }
23490 /**
23491 * Get the type of an object, for example exports.getType([]) returns 'Array'
23492 *
23493 * @param object - Input value of unknown type.
23494 *
23495 * @returns Detected type.
23496 */
23497
23498
23499 function getType$1(object) {
23500 var type = _typeof$2(object);
23501
23502 if (type === 'object') {
23503 if (object === null) {
23504 return 'null';
23505 }
23506
23507 if (object instanceof Boolean) {
23508 return 'Boolean';
23509 }
23510
23511 if (object instanceof Number) {
23512 return 'Number';
23513 }
23514
23515 if (object instanceof String) {
23516 return 'String';
23517 }
23518
23519 if (Array.isArray(object)) {
23520 return 'Array';
23521 }
23522
23523 if (object instanceof Date) {
23524 return 'Date';
23525 }
23526
23527 return 'Object';
23528 }
23529
23530 if (type === 'number') {
23531 return 'Number';
23532 }
23533
23534 if (type === 'boolean') {
23535 return 'Boolean';
23536 }
23537
23538 if (type === 'string') {
23539 return 'String';
23540 }
23541
23542 if (type === undefined) {
23543 return 'undefined';
23544 }
23545
23546 return type;
23547 }
23548 /**
23549 * Determine whether a value can be used as an id.
23550 *
23551 * @param value - Input value of unknown type.
23552 *
23553 * @returns True if the value is valid id, false otherwise.
23554 */
23555
23556
23557 function isId(value) {
23558 return typeof value === "string" || typeof value === "number";
23559 }
23560 /* eslint @typescript-eslint/member-ordering: ["error", { "classes": ["field", "constructor", "method"] }] */
23561
23562 /**
23563 * A queue.
23564 *
23565 * @typeParam T - The type of method names to be replaced by queued versions.
23566 */
23567
23568
23569 var Queue =
23570 /*#__PURE__*/
23571 function () {
23572 /**
23573 * Construct a new Queue.
23574 *
23575 * @param options - Queue configuration.
23576 */
23577 function Queue(options) {
23578 classCallCheck(this, Queue);
23579 this._queue = [];
23580 this._timeout = null;
23581 this._extended = null; // options
23582
23583 this.delay = null;
23584 this.max = Infinity;
23585 this.setOptions(options);
23586 }
23587 /**
23588 * Update the configuration of the queue.
23589 *
23590 * @param options - Queue configuration.
23591 */
23592
23593
23594 createClass(Queue, [{
23595 key: "setOptions",
23596 value: function setOptions(options) {
23597 if (options && typeof options.delay !== "undefined") {
23598 this.delay = options.delay;
23599 }
23600
23601 if (options && typeof options.max !== "undefined") {
23602 this.max = options.max;
23603 }
23604
23605 this._flushIfNeeded();
23606 }
23607 /**
23608 * Extend an object with queuing functionality.
23609 * The object will be extended with a function flush, and the methods provided in options.replace will be replaced with queued ones.
23610 *
23611 * @param object - The object to be extended.
23612 * @param options - Additional options.
23613 *
23614 * @returns The created queue.
23615 */
23616
23617 }, {
23618 key: "destroy",
23619
23620 /**
23621 * Destroy the queue. The queue will first flush all queued actions, and in case it has extended an object, will restore the original object.
23622 */
23623 value: function destroy() {
23624 this.flush();
23625
23626 if (this._extended) {
23627 var object = this._extended.object;
23628 var methods = this._extended.methods;
23629
23630 for (var i = 0; i < methods.length; i++) {
23631 var method = methods[i];
23632
23633 if (method.original) {
23634 // @TODO: better solution?
23635 object[method.name] = method.original;
23636 } else {
23637 // @TODO: better solution?
23638 delete object[method.name];
23639 }
23640 }
23641
23642 this._extended = null;
23643 }
23644 }
23645 /**
23646 * Replace a method on an object with a queued version.
23647 *
23648 * @param object - Object having the method.
23649 * @param method - The method name.
23650 */
23651
23652 }, {
23653 key: "replace",
23654 value: function replace(object, method) {
23655 /* eslint-disable-next-line @typescript-eslint/no-this-alias */
23656 var me = this;
23657 var original = object[method];
23658
23659 if (!original) {
23660 throw new Error("Method " + method + " undefined");
23661 }
23662
23663 object[method] = function () {
23664 for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
23665 args[_key] = arguments[_key];
23666 } // add this call to the queue
23667
23668
23669 me.queue({
23670 args: args,
23671 fn: original,
23672 context: this
23673 });
23674 };
23675 }
23676 /**
23677 * Queue a call.
23678 *
23679 * @param entry - The function or entry to be queued.
23680 */
23681
23682 }, {
23683 key: "queue",
23684 value: function queue(entry) {
23685 if (typeof entry === "function") {
23686 this._queue.push({
23687 fn: entry
23688 });
23689 } else {
23690 this._queue.push(entry);
23691 }
23692
23693 this._flushIfNeeded();
23694 }
23695 /**
23696 * Check whether the queue needs to be flushed.
23697 */
23698
23699 }, {
23700 key: "_flushIfNeeded",
23701 value: function _flushIfNeeded() {
23702 var _this = this; // flush when the maximum is exceeded.
23703
23704
23705 if (this._queue.length > this.max) {
23706 this.flush();
23707 } // flush after a period of inactivity when a delay is configured
23708
23709
23710 if (this._timeout != null) {
23711 clearTimeout(this._timeout);
23712 this._timeout = null;
23713 }
23714
23715 if (this.queue.length > 0 && typeof this.delay === "number") {
23716 this._timeout = setTimeout(function () {
23717 _this.flush();
23718 }, this.delay);
23719 }
23720 }
23721 /**
23722 * Flush all queued calls
23723 */
23724
23725 }, {
23726 key: "flush",
23727 value: function flush() {
23728 this._queue.splice(0).forEach(function (entry) {
23729 entry.fn.apply(entry.context || entry.fn, entry.args || []);
23730 });
23731 }
23732 }], [{
23733 key: "extend",
23734 value: function extend(object, options) {
23735 var queue = new Queue(options);
23736
23737 if (object.flush !== undefined) {
23738 throw new Error("Target object already has a property flush");
23739 }
23740
23741 object.flush = function () {
23742 queue.flush();
23743 };
23744
23745 var methods = [{
23746 name: "flush",
23747 original: undefined
23748 }];
23749
23750 if (options && options.replace) {
23751 for (var i = 0; i < options.replace.length; i++) {
23752 var name = options.replace[i];
23753 methods.push({
23754 name: name,
23755 // @TODO: better solution?
23756 original: object[name]
23757 }); // @TODO: better solution?
23758
23759 queue.replace(object, name);
23760 }
23761 }
23762
23763 queue._extended = {
23764 object: object,
23765 methods: methods
23766 };
23767 return queue;
23768 }
23769 }]);
23770 return Queue;
23771 }();
23772 /* eslint-disable @typescript-eslint/member-ordering */
23773
23774 /**
23775 * [[DataSet]] code that can be reused in [[DataView]] or other similar implementations of [[DataInterface]].
23776 *
23777 * @typeParam Item - Item type that may or may not have an id.
23778 * @typeParam IdProp - Name of the property that contains the id.
23779 */
23780
23781
23782 var DataSetPart =
23783 /*#__PURE__*/
23784 function () {
23785 function DataSetPart() {
23786 classCallCheck(this, DataSetPart);
23787 this._subscribers = {
23788 "*": [],
23789 add: [],
23790 remove: [],
23791 update: []
23792 };
23793 /**
23794 * @deprecated Use on instead (PS: DataView.subscribe === DataView.on).
23795 */
23796
23797 this.subscribe = DataSetPart.prototype.on;
23798 /**
23799 * @deprecated Use off instead (PS: DataView.unsubscribe === DataView.off).
23800 */
23801
23802 this.unsubscribe = DataSetPart.prototype.off;
23803 }
23804 /**
23805 * Trigger an event
23806 *
23807 * @param event - Event name.
23808 * @param payload - Event payload.
23809 * @param senderId - Id of the sender.
23810 */
23811
23812
23813 createClass(DataSetPart, [{
23814 key: "_trigger",
23815 value: function _trigger(event, payload, senderId) {
23816 if (event === "*") {
23817 throw new Error("Cannot trigger event *");
23818 }
23819
23820 [].concat(toConsumableArray(this._subscribers[event]), toConsumableArray(this._subscribers["*"])).forEach(function (subscriber) {
23821 subscriber(event, payload, senderId != null ? senderId : null);
23822 });
23823 }
23824 /**
23825 * Subscribe to an event, add an event listener.
23826 *
23827 * @remarks Non-function callbacks are ignored.
23828 *
23829 * @param event - Event name.
23830 * @param callback - Callback method.
23831 */
23832
23833 }, {
23834 key: "on",
23835 value: function on(event, callback) {
23836 if (typeof callback === "function") {
23837 this._subscribers[event].push(callback);
23838 } // @TODO: Maybe throw for invalid callbacks?
23839
23840 }
23841 /**
23842 * Unsubscribe from an event, remove an event listener.
23843 *
23844 * @remarks If the same callback was subscribed more than once **all** occurences will be removed.
23845 *
23846 * @param event - Event name.
23847 * @param callback - Callback method.
23848 */
23849
23850 }, {
23851 key: "off",
23852 value: function off(event, callback) {
23853 this._subscribers[event] = this._subscribers[event].filter(function (subscriber) {
23854 return subscriber !== callback;
23855 });
23856 }
23857 }]);
23858 return DataSetPart;
23859 }();
23860
23861 function _arrayWithHoles$1(arr) {
23862 if (Array.isArray(arr)) return arr;
23863 }
23864
23865 var arrayWithHoles = _arrayWithHoles$1;
23866
23867 function _iterableToArrayLimit$1(arr, i) {
23868 var _arr = [];
23869 var _n = true;
23870 var _d = false;
23871 var _e = undefined;
23872
23873 try {
23874 for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) {
23875 _arr.push(_s.value);
23876
23877 if (i && _arr.length === i) break;
23878 }
23879 } catch (err) {
23880 _d = true;
23881 _e = err;
23882 } finally {
23883 try {
23884 if (!_n && _i["return"] != null) _i["return"]();
23885 } finally {
23886 if (_d) throw _e;
23887 }
23888 }
23889
23890 return _arr;
23891 }
23892
23893 var iterableToArrayLimit = _iterableToArrayLimit$1;
23894
23895 function _nonIterableRest$1() {
23896 throw new TypeError("Invalid attempt to destructure non-iterable instance");
23897 }
23898
23899 var nonIterableRest = _nonIterableRest$1;
23900
23901 function _slicedToArray$1(arr, i) {
23902 return arrayWithHoles(arr) || iterableToArrayLimit(arr, i) || nonIterableRest();
23903 }
23904
23905 var slicedToArray = _slicedToArray$1;
23906 /**
23907 * Data stream
23908 *
23909 * @remarks
23910 * [[DataStream]] offers an always up to date stream of items from a [[DataSet]] or [[DataView]].
23911 * 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.
23912 * Multiple invocations of for example [[toItemArray]] may yield different results (if the data source like for example [[DataSet]] gets modified).
23913 *
23914 * @typeparam Item - The item type this stream is going to work with.
23915 */
23916
23917 var DataStream =
23918 /*#__PURE__*/
23919 function () {
23920 /**
23921 * Create a new data stream.
23922 *
23923 * @param _pairs - The id, item pairs.
23924 */
23925 function DataStream(_pairs) {
23926 classCallCheck(this, DataStream);
23927 this._pairs = _pairs;
23928 }
23929 /**
23930 * Return an iterable of key, value pairs for every entry in the stream.
23931 */
23932
23933
23934 createClass(DataStream, [{
23935 key: Symbol.iterator,
23936 value:
23937 /*#__PURE__*/
23938 regenerator.mark(function value() {
23939 var _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, _step$value, id, item;
23940
23941 return regenerator.wrap(function value$(_context) {
23942 while (1) {
23943 switch (_context.prev = _context.next) {
23944 case 0:
23945 _iteratorNormalCompletion = true;
23946 _didIteratorError = false;
23947 _iteratorError = undefined;
23948 _context.prev = 3;
23949 _iterator = this._pairs[Symbol.iterator]();
23950
23951 case 5:
23952 if (_iteratorNormalCompletion = (_step = _iterator.next()).done) {
23953 _context.next = 12;
23954 break;
23955 }
23956
23957 _step$value = slicedToArray(_step.value, 2), id = _step$value[0], item = _step$value[1];
23958 _context.next = 9;
23959 return [id, item];
23960
23961 case 9:
23962 _iteratorNormalCompletion = true;
23963 _context.next = 5;
23964 break;
23965
23966 case 12:
23967 _context.next = 18;
23968 break;
23969
23970 case 14:
23971 _context.prev = 14;
23972 _context.t0 = _context["catch"](3);
23973 _didIteratorError = true;
23974 _iteratorError = _context.t0;
23975
23976 case 18:
23977 _context.prev = 18;
23978 _context.prev = 19;
23979
23980 if (!_iteratorNormalCompletion && _iterator.return != null) {
23981 _iterator.return();
23982 }
23983
23984 case 21:
23985 _context.prev = 21;
23986
23987 if (!_didIteratorError) {
23988 _context.next = 24;
23989 break;
23990 }
23991
23992 throw _iteratorError;
23993
23994 case 24:
23995 return _context.finish(21);
23996
23997 case 25:
23998 return _context.finish(18);
23999
24000 case 26:
24001 case "end":
24002 return _context.stop();
24003 }
24004 }
24005 }, value, this, [[3, 14, 18, 26], [19,, 21, 25]]);
24006 })
24007 /**
24008 * Return an iterable of key, value pairs for every entry in the stream.
24009 */
24010
24011 }, {
24012 key: "entries",
24013 value:
24014 /*#__PURE__*/
24015 regenerator.mark(function entries() {
24016 var _iteratorNormalCompletion2, _didIteratorError2, _iteratorError2, _iterator2, _step2, _step2$value, id, item;
24017
24018 return regenerator.wrap(function entries$(_context2) {
24019 while (1) {
24020 switch (_context2.prev = _context2.next) {
24021 case 0:
24022 _iteratorNormalCompletion2 = true;
24023 _didIteratorError2 = false;
24024 _iteratorError2 = undefined;
24025 _context2.prev = 3;
24026 _iterator2 = this._pairs[Symbol.iterator]();
24027
24028 case 5:
24029 if (_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done) {
24030 _context2.next = 12;
24031 break;
24032 }
24033
24034 _step2$value = slicedToArray(_step2.value, 2), id = _step2$value[0], item = _step2$value[1];
24035 _context2.next = 9;
24036 return [id, item];
24037
24038 case 9:
24039 _iteratorNormalCompletion2 = true;
24040 _context2.next = 5;
24041 break;
24042
24043 case 12:
24044 _context2.next = 18;
24045 break;
24046
24047 case 14:
24048 _context2.prev = 14;
24049 _context2.t0 = _context2["catch"](3);
24050 _didIteratorError2 = true;
24051 _iteratorError2 = _context2.t0;
24052
24053 case 18:
24054 _context2.prev = 18;
24055 _context2.prev = 19;
24056
24057 if (!_iteratorNormalCompletion2 && _iterator2.return != null) {
24058 _iterator2.return();
24059 }
24060
24061 case 21:
24062 _context2.prev = 21;
24063
24064 if (!_didIteratorError2) {
24065 _context2.next = 24;
24066 break;
24067 }
24068
24069 throw _iteratorError2;
24070
24071 case 24:
24072 return _context2.finish(21);
24073
24074 case 25:
24075 return _context2.finish(18);
24076
24077 case 26:
24078 case "end":
24079 return _context2.stop();
24080 }
24081 }
24082 }, entries, this, [[3, 14, 18, 26], [19,, 21, 25]]);
24083 })
24084 /**
24085 * Return an iterable of keys in the stream.
24086 */
24087
24088 }, {
24089 key: "keys",
24090 value:
24091 /*#__PURE__*/
24092 regenerator.mark(function keys() {
24093 var _iteratorNormalCompletion3, _didIteratorError3, _iteratorError3, _iterator3, _step3, _step3$value, id;
24094
24095 return regenerator.wrap(function keys$(_context3) {
24096 while (1) {
24097 switch (_context3.prev = _context3.next) {
24098 case 0:
24099 _iteratorNormalCompletion3 = true;
24100 _didIteratorError3 = false;
24101 _iteratorError3 = undefined;
24102 _context3.prev = 3;
24103 _iterator3 = this._pairs[Symbol.iterator]();
24104
24105 case 5:
24106 if (_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done) {
24107 _context3.next = 12;
24108 break;
24109 }
24110
24111 _step3$value = slicedToArray(_step3.value, 1), id = _step3$value[0];
24112 _context3.next = 9;
24113 return id;
24114
24115 case 9:
24116 _iteratorNormalCompletion3 = true;
24117 _context3.next = 5;
24118 break;
24119
24120 case 12:
24121 _context3.next = 18;
24122 break;
24123
24124 case 14:
24125 _context3.prev = 14;
24126 _context3.t0 = _context3["catch"](3);
24127 _didIteratorError3 = true;
24128 _iteratorError3 = _context3.t0;
24129
24130 case 18:
24131 _context3.prev = 18;
24132 _context3.prev = 19;
24133
24134 if (!_iteratorNormalCompletion3 && _iterator3.return != null) {
24135 _iterator3.return();
24136 }
24137
24138 case 21:
24139 _context3.prev = 21;
24140
24141 if (!_didIteratorError3) {
24142 _context3.next = 24;
24143 break;
24144 }
24145
24146 throw _iteratorError3;
24147
24148 case 24:
24149 return _context3.finish(21);
24150
24151 case 25:
24152 return _context3.finish(18);
24153
24154 case 26:
24155 case "end":
24156 return _context3.stop();
24157 }
24158 }
24159 }, keys, this, [[3, 14, 18, 26], [19,, 21, 25]]);
24160 })
24161 /**
24162 * Return an iterable of values in the stream.
24163 */
24164
24165 }, {
24166 key: "values",
24167 value:
24168 /*#__PURE__*/
24169 regenerator.mark(function values() {
24170 var _iteratorNormalCompletion4, _didIteratorError4, _iteratorError4, _iterator4, _step4, _step4$value, item;
24171
24172 return regenerator.wrap(function values$(_context4) {
24173 while (1) {
24174 switch (_context4.prev = _context4.next) {
24175 case 0:
24176 _iteratorNormalCompletion4 = true;
24177 _didIteratorError4 = false;
24178 _iteratorError4 = undefined;
24179 _context4.prev = 3;
24180 _iterator4 = this._pairs[Symbol.iterator]();
24181
24182 case 5:
24183 if (_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done) {
24184 _context4.next = 12;
24185 break;
24186 }
24187
24188 _step4$value = slicedToArray(_step4.value, 2), item = _step4$value[1];
24189 _context4.next = 9;
24190 return item;
24191
24192 case 9:
24193 _iteratorNormalCompletion4 = true;
24194 _context4.next = 5;
24195 break;
24196
24197 case 12:
24198 _context4.next = 18;
24199 break;
24200
24201 case 14:
24202 _context4.prev = 14;
24203 _context4.t0 = _context4["catch"](3);
24204 _didIteratorError4 = true;
24205 _iteratorError4 = _context4.t0;
24206
24207 case 18:
24208 _context4.prev = 18;
24209 _context4.prev = 19;
24210
24211 if (!_iteratorNormalCompletion4 && _iterator4.return != null) {
24212 _iterator4.return();
24213 }
24214
24215 case 21:
24216 _context4.prev = 21;
24217
24218 if (!_didIteratorError4) {
24219 _context4.next = 24;
24220 break;
24221 }
24222
24223 throw _iteratorError4;
24224
24225 case 24:
24226 return _context4.finish(21);
24227
24228 case 25:
24229 return _context4.finish(18);
24230
24231 case 26:
24232 case "end":
24233 return _context4.stop();
24234 }
24235 }
24236 }, values, this, [[3, 14, 18, 26], [19,, 21, 25]]);
24237 })
24238 /**
24239 * Return an array containing all the ids in this stream.
24240 *
24241 * @remarks
24242 * The array may contain duplicities.
24243 *
24244 * @returns The array with all ids from this stream.
24245 */
24246
24247 }, {
24248 key: "toIdArray",
24249 value: function toIdArray() {
24250 return toConsumableArray(this._pairs).map(function (pair) {
24251 return pair[0];
24252 });
24253 }
24254 /**
24255 * Return an array containing all the items in this stream.
24256 *
24257 * @remarks
24258 * The array may contain duplicities.
24259 *
24260 * @returns The array with all items from this stream.
24261 */
24262
24263 }, {
24264 key: "toItemArray",
24265 value: function toItemArray() {
24266 return toConsumableArray(this._pairs).map(function (pair) {
24267 return pair[1];
24268 });
24269 }
24270 /**
24271 * Return an array containing all the entries in this stream.
24272 *
24273 * @remarks
24274 * The array may contain duplicities.
24275 *
24276 * @returns The array with all entries from this stream.
24277 */
24278
24279 }, {
24280 key: "toEntryArray",
24281 value: function toEntryArray() {
24282 return toConsumableArray(this._pairs);
24283 }
24284 /**
24285 * Return an object map containing all the items in this stream accessible by ids.
24286 *
24287 * @remarks
24288 * In case of duplicate ids (coerced to string so `7 == '7'`) the last encoutered appears in the returned object.
24289 *
24290 * @returns The object map of all id → item pairs from this stream.
24291 */
24292
24293 }, {
24294 key: "toObjectMap",
24295 value: function toObjectMap() {
24296 var map = Object.create(null);
24297 var _iteratorNormalCompletion5 = true;
24298 var _didIteratorError5 = false;
24299 var _iteratorError5 = undefined;
24300
24301 try {
24302 for (var _iterator5 = this._pairs[Symbol.iterator](), _step5; !(_iteratorNormalCompletion5 = (_step5 = _iterator5.next()).done); _iteratorNormalCompletion5 = true) {
24303 var _step5$value = slicedToArray(_step5.value, 2),
24304 id = _step5$value[0],
24305 item = _step5$value[1];
24306
24307 map[id] = item;
24308 }
24309 } catch (err) {
24310 _didIteratorError5 = true;
24311 _iteratorError5 = err;
24312 } finally {
24313 try {
24314 if (!_iteratorNormalCompletion5 && _iterator5.return != null) {
24315 _iterator5.return();
24316 }
24317 } finally {
24318 if (_didIteratorError5) {
24319 throw _iteratorError5;
24320 }
24321 }
24322 }
24323
24324 return map;
24325 }
24326 /**
24327 * Return a map containing all the items in this stream accessible by ids.
24328 *
24329 * @returns The map of all id → item pairs from this stream.
24330 */
24331
24332 }, {
24333 key: "toMap",
24334 value: function toMap() {
24335 return new Map(this._pairs);
24336 }
24337 /**
24338 * Return a set containing all the (unique) ids in this stream.
24339 *
24340 * @returns The set of all ids from this stream.
24341 */
24342
24343 }, {
24344 key: "toIdSet",
24345 value: function toIdSet() {
24346 return new Set(this.toIdArray());
24347 }
24348 /**
24349 * Return a set containing all the (unique) items in this stream.
24350 *
24351 * @returns The set of all items from this stream.
24352 */
24353
24354 }, {
24355 key: "toItemSet",
24356 value: function toItemSet() {
24357 return new Set(this.toItemArray());
24358 }
24359 /**
24360 * Cache the items from this stream.
24361 *
24362 * @remarks
24363 * This method allows for items to be fetched immediatelly and used (possibly multiple times) later.
24364 * It can also be used to optimize performance as [[DataStream]] would otherwise reevaluate everything upon each iteration.
24365 *
24366 * ## Example
24367 * ```javascript
24368 * const ds = new DataSet([…])
24369 *
24370 * const cachedStream = ds.stream()
24371 * .filter(…)
24372 * .sort(…)
24373 * .map(…)
24374 * .cached(…) // Data are fetched, processed and cached here.
24375 *
24376 * ds.clear()
24377 * chachedStream // Still has all the items.
24378 * ```
24379 *
24380 * @returns A new [[DataStream]] with cached items (detached from the original [[DataSet]]).
24381 */
24382
24383 }, {
24384 key: "cache",
24385 value: function cache() {
24386 return new DataStream(toConsumableArray(this._pairs));
24387 }
24388 /**
24389 * Get the distinct values of given property.
24390 *
24391 * @param callback - The function that picks and possibly converts the property.
24392 *
24393 * @typeparam T - The type of the distinct value.
24394 *
24395 * @returns A set of all distinct properties.
24396 */
24397
24398 }, {
24399 key: "distinct",
24400 value: function distinct(callback) {
24401 var set = new Set();
24402 var _iteratorNormalCompletion6 = true;
24403 var _didIteratorError6 = false;
24404 var _iteratorError6 = undefined;
24405
24406 try {
24407 for (var _iterator6 = this._pairs[Symbol.iterator](), _step6; !(_iteratorNormalCompletion6 = (_step6 = _iterator6.next()).done); _iteratorNormalCompletion6 = true) {
24408 var _step6$value = slicedToArray(_step6.value, 2),
24409 id = _step6$value[0],
24410 item = _step6$value[1];
24411
24412 set.add(callback(item, id));
24413 }
24414 } catch (err) {
24415 _didIteratorError6 = true;
24416 _iteratorError6 = err;
24417 } finally {
24418 try {
24419 if (!_iteratorNormalCompletion6 && _iterator6.return != null) {
24420 _iterator6.return();
24421 }
24422 } finally {
24423 if (_didIteratorError6) {
24424 throw _iteratorError6;
24425 }
24426 }
24427 }
24428
24429 return set;
24430 }
24431 /**
24432 * Filter the items of the stream.
24433 *
24434 * @param callback - The function that decides whether an item will be included.
24435 *
24436 * @returns A new data stream with the filtered items.
24437 */
24438
24439 }, {
24440 key: "filter",
24441 value: function filter(callback) {
24442 var pairs = this._pairs;
24443 return new DataStream(defineProperty$6({}, Symbol.iterator,
24444 /*#__PURE__*/
24445 regenerator.mark(function _callee() {
24446 var _iteratorNormalCompletion7, _didIteratorError7, _iteratorError7, _iterator7, _step7, _step7$value, id, item;
24447
24448 return regenerator.wrap(function _callee$(_context5) {
24449 while (1) {
24450 switch (_context5.prev = _context5.next) {
24451 case 0:
24452 _iteratorNormalCompletion7 = true;
24453 _didIteratorError7 = false;
24454 _iteratorError7 = undefined;
24455 _context5.prev = 3;
24456 _iterator7 = pairs[Symbol.iterator]();
24457
24458 case 5:
24459 if (_iteratorNormalCompletion7 = (_step7 = _iterator7.next()).done) {
24460 _context5.next = 13;
24461 break;
24462 }
24463
24464 _step7$value = slicedToArray(_step7.value, 2), id = _step7$value[0], item = _step7$value[1];
24465
24466 if (!callback(item, id)) {
24467 _context5.next = 10;
24468 break;
24469 }
24470
24471 _context5.next = 10;
24472 return [id, item];
24473
24474 case 10:
24475 _iteratorNormalCompletion7 = true;
24476 _context5.next = 5;
24477 break;
24478
24479 case 13:
24480 _context5.next = 19;
24481 break;
24482
24483 case 15:
24484 _context5.prev = 15;
24485 _context5.t0 = _context5["catch"](3);
24486 _didIteratorError7 = true;
24487 _iteratorError7 = _context5.t0;
24488
24489 case 19:
24490 _context5.prev = 19;
24491 _context5.prev = 20;
24492
24493 if (!_iteratorNormalCompletion7 && _iterator7.return != null) {
24494 _iterator7.return();
24495 }
24496
24497 case 22:
24498 _context5.prev = 22;
24499
24500 if (!_didIteratorError7) {
24501 _context5.next = 25;
24502 break;
24503 }
24504
24505 throw _iteratorError7;
24506
24507 case 25:
24508 return _context5.finish(22);
24509
24510 case 26:
24511 return _context5.finish(19);
24512
24513 case 27:
24514 case "end":
24515 return _context5.stop();
24516 }
24517 }
24518 }, _callee, null, [[3, 15, 19, 27], [20,, 22, 26]]);
24519 })));
24520 }
24521 /**
24522 * Execute a callback for each item of the stream.
24523 *
24524 * @param callback - The function that will be invoked for each item.
24525 */
24526
24527 }, {
24528 key: "forEach",
24529 value: function forEach(callback) {
24530 var _iteratorNormalCompletion8 = true;
24531 var _didIteratorError8 = false;
24532 var _iteratorError8 = undefined;
24533
24534 try {
24535 for (var _iterator8 = this._pairs[Symbol.iterator](), _step8; !(_iteratorNormalCompletion8 = (_step8 = _iterator8.next()).done); _iteratorNormalCompletion8 = true) {
24536 var _step8$value = slicedToArray(_step8.value, 2),
24537 id = _step8$value[0],
24538 item = _step8$value[1];
24539
24540 callback(item, id);
24541 }
24542 } catch (err) {
24543 _didIteratorError8 = true;
24544 _iteratorError8 = err;
24545 } finally {
24546 try {
24547 if (!_iteratorNormalCompletion8 && _iterator8.return != null) {
24548 _iterator8.return();
24549 }
24550 } finally {
24551 if (_didIteratorError8) {
24552 throw _iteratorError8;
24553 }
24554 }
24555 }
24556 }
24557 /**
24558 * Map the items into a different type.
24559 *
24560 * @param callback - The function that does the conversion.
24561 *
24562 * @typeparam Mapped - The type of the item after mapping.
24563 *
24564 * @returns A new data stream with the mapped items.
24565 */
24566
24567 }, {
24568 key: "map",
24569 value: function map(callback) {
24570 var pairs = this._pairs;
24571 return new DataStream(defineProperty$6({}, Symbol.iterator,
24572 /*#__PURE__*/
24573 regenerator.mark(function _callee2() {
24574 var _iteratorNormalCompletion9, _didIteratorError9, _iteratorError9, _iterator9, _step9, _step9$value, id, item;
24575
24576 return regenerator.wrap(function _callee2$(_context6) {
24577 while (1) {
24578 switch (_context6.prev = _context6.next) {
24579 case 0:
24580 _iteratorNormalCompletion9 = true;
24581 _didIteratorError9 = false;
24582 _iteratorError9 = undefined;
24583 _context6.prev = 3;
24584 _iterator9 = pairs[Symbol.iterator]();
24585
24586 case 5:
24587 if (_iteratorNormalCompletion9 = (_step9 = _iterator9.next()).done) {
24588 _context6.next = 12;
24589 break;
24590 }
24591
24592 _step9$value = slicedToArray(_step9.value, 2), id = _step9$value[0], item = _step9$value[1];
24593 _context6.next = 9;
24594 return [id, callback(item, id)];
24595
24596 case 9:
24597 _iteratorNormalCompletion9 = true;
24598 _context6.next = 5;
24599 break;
24600
24601 case 12:
24602 _context6.next = 18;
24603 break;
24604
24605 case 14:
24606 _context6.prev = 14;
24607 _context6.t0 = _context6["catch"](3);
24608 _didIteratorError9 = true;
24609 _iteratorError9 = _context6.t0;
24610
24611 case 18:
24612 _context6.prev = 18;
24613 _context6.prev = 19;
24614
24615 if (!_iteratorNormalCompletion9 && _iterator9.return != null) {
24616 _iterator9.return();
24617 }
24618
24619 case 21:
24620 _context6.prev = 21;
24621
24622 if (!_didIteratorError9) {
24623 _context6.next = 24;
24624 break;
24625 }
24626
24627 throw _iteratorError9;
24628
24629 case 24:
24630 return _context6.finish(21);
24631
24632 case 25:
24633 return _context6.finish(18);
24634
24635 case 26:
24636 case "end":
24637 return _context6.stop();
24638 }
24639 }
24640 }, _callee2, null, [[3, 14, 18, 26], [19,, 21, 25]]);
24641 })));
24642 }
24643 /**
24644 * Get the item with the maximum value of given property.
24645 *
24646 * @param callback - The function that picks and possibly converts the property.
24647 *
24648 * @returns The item with the maximum if found otherwise null.
24649 */
24650
24651 }, {
24652 key: "max",
24653 value: function max(callback) {
24654 var iter = this._pairs[Symbol.iterator]();
24655
24656 var curr = iter.next();
24657
24658 if (curr.done) {
24659 return null;
24660 }
24661
24662 var maxItem = curr.value[1];
24663 var maxValue = callback(curr.value[1], curr.value[0]);
24664
24665 while (!(curr = iter.next()).done) {
24666 var _curr$value = slicedToArray(curr.value, 2),
24667 id = _curr$value[0],
24668 item = _curr$value[1];
24669
24670 var _value = callback(item, id);
24671
24672 if (_value > maxValue) {
24673 maxValue = _value;
24674 maxItem = item;
24675 }
24676 }
24677
24678 return maxItem;
24679 }
24680 /**
24681 * Get the item with the minimum value of given property.
24682 *
24683 * @param callback - The function that picks and possibly converts the property.
24684 *
24685 * @returns The item with the minimum if found otherwise null.
24686 */
24687
24688 }, {
24689 key: "min",
24690 value: function min(callback) {
24691 var iter = this._pairs[Symbol.iterator]();
24692
24693 var curr = iter.next();
24694
24695 if (curr.done) {
24696 return null;
24697 }
24698
24699 var minItem = curr.value[1];
24700 var minValue = callback(curr.value[1], curr.value[0]);
24701
24702 while (!(curr = iter.next()).done) {
24703 var _curr$value2 = slicedToArray(curr.value, 2),
24704 id = _curr$value2[0],
24705 item = _curr$value2[1];
24706
24707 var _value2 = callback(item, id);
24708
24709 if (_value2 < minValue) {
24710 minValue = _value2;
24711 minItem = item;
24712 }
24713 }
24714
24715 return minItem;
24716 }
24717 /**
24718 * Reduce the items into a single value.
24719 *
24720 * @param callback - The function that does the reduction.
24721 * @param accumulator - The initial value of the accumulator.
24722 *
24723 * @typeparam T - The type of the accumulated value.
24724 *
24725 * @returns The reduced value.
24726 */
24727
24728 }, {
24729 key: "reduce",
24730 value: function reduce(callback, accumulator) {
24731 var _iteratorNormalCompletion10 = true;
24732 var _didIteratorError10 = false;
24733 var _iteratorError10 = undefined;
24734
24735 try {
24736 for (var _iterator10 = this._pairs[Symbol.iterator](), _step10; !(_iteratorNormalCompletion10 = (_step10 = _iterator10.next()).done); _iteratorNormalCompletion10 = true) {
24737 var _step10$value = slicedToArray(_step10.value, 2),
24738 id = _step10$value[0],
24739 item = _step10$value[1];
24740
24741 accumulator = callback(accumulator, item, id);
24742 }
24743 } catch (err) {
24744 _didIteratorError10 = true;
24745 _iteratorError10 = err;
24746 } finally {
24747 try {
24748 if (!_iteratorNormalCompletion10 && _iterator10.return != null) {
24749 _iterator10.return();
24750 }
24751 } finally {
24752 if (_didIteratorError10) {
24753 throw _iteratorError10;
24754 }
24755 }
24756 }
24757
24758 return accumulator;
24759 }
24760 /**
24761 * Sort the items.
24762 *
24763 * @param callback - Item comparator.
24764 *
24765 * @returns A new stream with sorted items.
24766 */
24767
24768 }, {
24769 key: "sort",
24770 value: function sort(callback) {
24771 var _this = this;
24772
24773 return new DataStream(defineProperty$6({}, Symbol.iterator, function () {
24774 return toConsumableArray(_this._pairs).sort(function (_ref3, _ref4) {
24775 var _ref5 = slicedToArray(_ref3, 2),
24776 idA = _ref5[0],
24777 itemA = _ref5[1];
24778
24779 var _ref6 = slicedToArray(_ref4, 2),
24780 idB = _ref6[0],
24781 itemB = _ref6[1];
24782
24783 return callback(itemA, itemB, idA, idB);
24784 })[Symbol.iterator]();
24785 }));
24786 }
24787 }]);
24788 return DataStream;
24789 }();
24790
24791 function ownKeys$3(object, enumerableOnly) {
24792 var keys = Object.keys(object);
24793
24794 if (Object.getOwnPropertySymbols) {
24795 keys.push.apply(keys, Object.getOwnPropertySymbols(object));
24796 }
24797
24798 if (enumerableOnly) keys = keys.filter(function (sym) {
24799 return Object.getOwnPropertyDescriptor(object, sym).enumerable;
24800 });
24801 return keys;
24802 }
24803
24804 function _objectSpread(target) {
24805 for (var i = 1; i < arguments.length; i++) {
24806 var source = arguments[i] != null ? arguments[i] : {};
24807
24808 if (i % 2) {
24809 ownKeys$3(source, true).forEach(function (key) {
24810 defineProperty$6(target, key, source[key]);
24811 });
24812 } else if (Object.getOwnPropertyDescriptors) {
24813 Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
24814 } else {
24815 ownKeys$3(source).forEach(function (key) {
24816 Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
24817 });
24818 }
24819 }
24820
24821 return target;
24822 }
24823 /**
24824 * # DataSet
24825 *
24826 * 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.
24827 *
24828 * ## Example
24829 *
24830 * The following example shows how to use a DataSet.
24831 *
24832 * ```javascript
24833 * // create a DataSet
24834 * var options = {};
24835 * var data = new vis.DataSet(options);
24836 *
24837 * // add items
24838 * // note that the data items can contain different properties and data formats
24839 * data.add([
24840 * {id: 1, text: 'item 1', date: new Date(2013, 6, 20), group: 1, first: true},
24841 * {id: 2, text: 'item 2', date: '2013-06-23', group: 2},
24842 * {id: 3, text: 'item 3', date: '2013-06-25', group: 2},
24843 * {id: 4, text: 'item 4'}
24844 * ]);
24845 *
24846 * // subscribe to any change in the DataSet
24847 * data.on('*', function (event, properties, senderId) {
24848 * console.log('event', event, properties);
24849 * });
24850 *
24851 * // update an existing item
24852 * data.update({id: 2, group: 1});
24853 *
24854 * // remove an item
24855 * data.remove(4);
24856 *
24857 * // get all ids
24858 * var ids = data.getIds();
24859 * console.log('ids', ids);
24860 *
24861 * // get a specific item
24862 * var item1 = data.get(1);
24863 * console.log('item1', item1);
24864 *
24865 * // retrieve a filtered subset of the data
24866 * var items = data.get({
24867 * filter: function (item) {
24868 * return item.group == 1;
24869 * }
24870 * });
24871 * console.log('filtered items', items);
24872 *
24873 * // retrieve formatted items
24874 * var items = data.get({
24875 * fields: ['id', 'date'],
24876 * type: {
24877 * date: 'ISODate'
24878 * }
24879 * });
24880 * console.log('formatted items', items);
24881 * ```
24882 *
24883 * @typeParam Item - Item type that may or may not have an id.
24884 * @typeParam IdProp - Name of the property that contains the id.
24885 */
24886
24887
24888 var DataSet =
24889 /*#__PURE__*/
24890 function (_DataSetPart) {
24891 inherits(DataSet, _DataSetPart);
24892 /**
24893 * Construct a new DataSet.
24894 *
24895 * @param data - Initial data or options.
24896 * @param options - Options (type error if data is also options).
24897 */
24898
24899 function DataSet(data, options) {
24900 var _this;
24901
24902 classCallCheck(this, DataSet);
24903 _this = possibleConstructorReturn(this, getPrototypeOf(DataSet).call(this)); // correctly read optional arguments
24904
24905 if (data && !Array.isArray(data)) {
24906 options = data;
24907 data = [];
24908 }
24909
24910 _this._options = options || {};
24911 _this._data = new Map(); // map with data indexed by id
24912
24913 _this.length = 0; // number of items in the DataSet
24914
24915 _this._idProp = _this._options.fieldId || "id"; // name of the field containing id
24916
24917 _this._type = {}; // internal field types (NOTE: this can differ from this._options.type)
24918 // all variants of a Date are internally stored as Date, so we can convert
24919 // from everything to everything (also from ISODate to Number for example)
24920
24921 if (_this._options.type) {
24922 var fields = Object.keys(_this._options.type);
24923
24924 for (var i = 0, len = fields.length; i < len; i++) {
24925 var field = fields[i];
24926 var value = _this._options.type[field];
24927
24928 if (value == "Date" || value == "ISODate" || value == "ASPDate") {
24929 _this._type[field] = "Date";
24930 } else {
24931 _this._type[field] = value;
24932 }
24933 }
24934 } // add initial data when provided
24935
24936
24937 if (data && data.length) {
24938 _this.add(data);
24939 }
24940
24941 _this.setOptions(options);
24942
24943 return _this;
24944 }
24945 /**
24946 * Set new options.
24947 *
24948 * @param options - The new options.
24949 */
24950
24951
24952 createClass(DataSet, [{
24953 key: "setOptions",
24954 value: function setOptions(options) {
24955 if (options && options.queue !== undefined) {
24956 if (options.queue === false) {
24957 // delete queue if loaded
24958 if (this._queue) {
24959 this._queue.destroy();
24960
24961 delete this._queue;
24962 }
24963 } else {
24964 // create queue and update its options
24965 if (!this._queue) {
24966 this._queue = Queue.extend(this, {
24967 replace: ["add", "update", "remove"]
24968 });
24969 }
24970
24971 if (options.queue && _typeof_1(options.queue) === "object") {
24972 this._queue.setOptions(options.queue);
24973 }
24974 }
24975 }
24976 }
24977 /**
24978 * Add a data item or an array with items.
24979 *
24980 * 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.
24981 *
24982 * ## Example
24983 *
24984 * ```javascript
24985 * // create a DataSet
24986 * const data = new vis.DataSet()
24987 *
24988 * // add items
24989 * const ids = data.add([
24990 * { id: 1, text: 'item 1' },
24991 * { id: 2, text: 'item 2' },
24992 * { text: 'item without an id' }
24993 * ])
24994 *
24995 * console.log(ids) // [1, 2, '<UUIDv4>']
24996 * ```
24997 *
24998 * @param data - Items to be added (ids will be generated if missing).
24999 * @param senderId - Sender id.
25000 *
25001 * @returns addedIds - Array with the ids (generated if not present) of the added items.
25002 *
25003 * @throws When an item with the same id as any of the added items already exists.
25004 */
25005
25006 }, {
25007 key: "add",
25008 value: function add(data, senderId) {
25009 var _this2 = this;
25010
25011 var addedIds = [];
25012 var id;
25013
25014 if (Array.isArray(data)) {
25015 // Array
25016 var idsToAdd = data.map(function (d) {
25017 return d[_this2._idProp];
25018 });
25019
25020 if (idsToAdd.some(function (id) {
25021 return _this2._data.has(id);
25022 })) {
25023 throw new Error("A duplicate id was found in the parameter array.");
25024 }
25025
25026 for (var i = 0, len = data.length; i < len; i++) {
25027 id = this._addItem(data[i]);
25028 addedIds.push(id);
25029 }
25030 } else if (data && _typeof_1(data) === "object") {
25031 // Single item
25032 id = this._addItem(data);
25033 addedIds.push(id);
25034 } else {
25035 throw new Error("Unknown dataType");
25036 }
25037
25038 if (addedIds.length) {
25039 this._trigger("add", {
25040 items: addedIds
25041 }, senderId);
25042 }
25043
25044 return addedIds;
25045 }
25046 /**
25047 * Update existing items. When an item does not exist, it will be created.
25048 *
25049 * @remarks
25050 * The provided properties will be merged in the existing item. When an item does not exist, it will be created.
25051 *
25052 * 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.
25053 *
25054 * ## Example
25055 *
25056 * ```javascript
25057 * // create a DataSet
25058 * const data = new vis.DataSet([
25059 * { id: 1, text: 'item 1' },
25060 * { id: 2, text: 'item 2' },
25061 * { id: 3, text: 'item 3' }
25062 * ])
25063 *
25064 * // update items
25065 * const ids = data.update([
25066 * { id: 2, text: 'item 2 (updated)' },
25067 * { id: 4, text: 'item 4 (new)' }
25068 * ])
25069 *
25070 * console.log(ids) // [2, 4]
25071 * ```
25072 *
25073 * ## Warning for TypeScript users
25074 * This method may introduce partial items into the data set. Use add or updateOnly instead for better type safety.
25075 *
25076 * @param data - Items to be updated (if the id is already present) or added (if the id is missing).
25077 * @param senderId - Sender id.
25078 *
25079 * @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.
25080 *
25081 * @throws When the supplied data is neither an item nor an array of items.
25082 */
25083
25084 }, {
25085 key: "update",
25086 value: function update(data, senderId) {
25087 var _this3 = this;
25088
25089 var addedIds = [];
25090 var updatedIds = [];
25091 var oldData = [];
25092 var updatedData = [];
25093 var idProp = this._idProp;
25094
25095 var addOrUpdate = function addOrUpdate(item) {
25096 var origId = item[idProp];
25097
25098 if (origId != null && _this3._data.has(origId)) {
25099 var fullItem = item; // it has an id, therefore it is a fullitem
25100
25101 var oldItem = Object.assign({}, _this3._data.get(origId)); // update item
25102
25103 var id = _this3._updateItem(fullItem);
25104
25105 updatedIds.push(id);
25106 updatedData.push(fullItem);
25107 oldData.push(oldItem);
25108 } else {
25109 // add new item
25110 var _id = _this3._addItem(item);
25111
25112 addedIds.push(_id);
25113 }
25114 };
25115
25116 if (Array.isArray(data)) {
25117 // Array
25118 for (var i = 0, len = data.length; i < len; i++) {
25119 if (data[i] && _typeof_1(data[i]) === "object") {
25120 addOrUpdate(data[i]);
25121 } else {
25122 console.warn("Ignoring input item, which is not an object at index " + i);
25123 }
25124 }
25125 } else if (data && _typeof_1(data) === "object") {
25126 // Single item
25127 addOrUpdate(data);
25128 } else {
25129 throw new Error("Unknown dataType");
25130 }
25131
25132 if (addedIds.length) {
25133 this._trigger("add", {
25134 items: addedIds
25135 }, senderId);
25136 }
25137
25138 if (updatedIds.length) {
25139 var props = {
25140 items: updatedIds,
25141 oldData: oldData,
25142 data: updatedData
25143 }; // TODO: remove deprecated property 'data' some day
25144 //Object.defineProperty(props, 'data', {
25145 // 'get': (function() {
25146 // 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');
25147 // return updatedData;
25148 // }).bind(this)
25149 //});
25150
25151 this._trigger("update", props, senderId);
25152 }
25153
25154 return addedIds.concat(updatedIds);
25155 }
25156 /**
25157 * Update existing items. When an item does not exist, an error will be thrown.
25158 *
25159 * @remarks
25160 * The provided properties will be deeply merged into the existing item.
25161 * 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.
25162 *
25163 * After the items are updated, the DataSet will trigger an event `update`.
25164 * When a `senderId` is provided, this id will be passed with the triggered event to all subscribers.
25165 *
25166 * ## Example
25167 *
25168 * ```javascript
25169 * // create a DataSet
25170 * const data = new vis.DataSet([
25171 * { id: 1, text: 'item 1' },
25172 * { id: 2, text: 'item 2' },
25173 * { id: 3, text: 'item 3' },
25174 * ])
25175 *
25176 * // update items
25177 * const ids = data.update([
25178 * { id: 2, text: 'item 2 (updated)' }, // works
25179 * // { id: 4, text: 'item 4 (new)' }, // would throw
25180 * // { text: 'item 4 (new)' }, // would also throw
25181 * ])
25182 *
25183 * console.log(ids) // [2]
25184 * ```
25185 *
25186 * @param data - Updates (the id and optionally other props) to the items in this data set.
25187 * @param senderId - Sender id.
25188 *
25189 * @returns updatedIds - The ids of the updated items.
25190 *
25191 * @throws When the supplied data is neither an item nor an array of items, when the ids are missing.
25192 */
25193
25194 }, {
25195 key: "updateOnly",
25196 value: function updateOnly(data, senderId) {
25197 var _this4 = this;
25198
25199 if (!Array.isArray(data)) {
25200 data = [data];
25201 }
25202
25203 var updateEventData = data.map(function (update) {
25204 var oldData = _this4._data.get(update[_this4._idProp]);
25205
25206 if (oldData == null) {
25207 throw new Error("Updating non-existent items is not allowed.");
25208 }
25209
25210 return {
25211 oldData: oldData,
25212 update: update
25213 };
25214 }).map(function (_ref) {
25215 var oldData = _ref.oldData,
25216 update = _ref.update;
25217 var id = oldData[_this4._idProp];
25218 var updatedData = deepExtend$1(deepExtend$1({}, oldData), update);
25219
25220 _this4._data.set(id, updatedData);
25221
25222 return {
25223 id: id,
25224 oldData: oldData,
25225 updatedData: updatedData
25226 };
25227 });
25228
25229 if (updateEventData.length) {
25230 var props = {
25231 items: updateEventData.map(function (value) {
25232 return value.id;
25233 }),
25234 oldData: updateEventData.map(function (value) {
25235 return value.oldData;
25236 }),
25237 data: updateEventData.map(function (value) {
25238 return value.updatedData;
25239 })
25240 }; // TODO: remove deprecated property 'data' some day
25241 //Object.defineProperty(props, 'data', {
25242 // 'get': (function() {
25243 // 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');
25244 // return updatedData;
25245 // }).bind(this)
25246 //});
25247
25248 this._trigger("update", props, senderId);
25249
25250 return props.items;
25251 } else {
25252 return [];
25253 }
25254 }
25255 /** @inheritdoc */
25256
25257 }, {
25258 key: "get",
25259 value: function get(first, second) {
25260 // @TODO: Woudn't it be better to split this into multiple methods?
25261 // parse the arguments
25262 var id = undefined;
25263 var ids = undefined;
25264 var options = undefined;
25265
25266 if (isId(first)) {
25267 // get(id [, options])
25268 id = first;
25269 options = second;
25270 } else if (Array.isArray(first)) {
25271 // get(ids [, options])
25272 ids = first;
25273 options = second;
25274 } else {
25275 // get([, options])
25276 options = first;
25277 } // determine the return type
25278
25279
25280 var returnType = options && options.returnType === "Object" ? "Object" : "Array"; // @TODO: WTF is this? Or am I missing something?
25281 // var returnType
25282 // if (options && options.returnType) {
25283 // var allowedValues = ['Array', 'Object']
25284 // returnType =
25285 // allowedValues.indexOf(options.returnType) == -1
25286 // ? 'Array'
25287 // : options.returnType
25288 // } else {
25289 // returnType = 'Array'
25290 // }
25291 // build options
25292
25293 var type = options && options.type || this._options.type;
25294 var filter = options && options.filter;
25295 var items = [];
25296 var item = null;
25297 var itemIds = null;
25298 var itemId = null; // convert items
25299
25300 if (id != null) {
25301 // return a single item
25302 item = this._getItem(id, type);
25303
25304 if (item && filter && !filter(item)) {
25305 item = null;
25306 }
25307 } else if (ids != null) {
25308 // return a subset of items
25309 for (var i = 0, len = ids.length; i < len; i++) {
25310 item = this._getItem(ids[i], type);
25311
25312 if (item != null && (!filter || filter(item))) {
25313 items.push(item);
25314 }
25315 }
25316 } else {
25317 // return all items
25318 itemIds = toConsumableArray(this._data.keys());
25319
25320 for (var _i = 0, _len = itemIds.length; _i < _len; _i++) {
25321 itemId = itemIds[_i];
25322 item = this._getItem(itemId, type);
25323
25324 if (item != null && (!filter || filter(item))) {
25325 items.push(item);
25326 }
25327 }
25328 } // order the results
25329
25330
25331 if (options && options.order && id == undefined) {
25332 this._sort(items, options.order);
25333 } // filter fields of the items
25334
25335
25336 if (options && options.fields) {
25337 var fields = options.fields;
25338
25339 if (id != undefined && item != null) {
25340 item = this._filterFields(item, fields);
25341 } else {
25342 for (var _i2 = 0, _len2 = items.length; _i2 < _len2; _i2++) {
25343 items[_i2] = this._filterFields(items[_i2], fields);
25344 }
25345 }
25346 } // return the results
25347
25348
25349 if (returnType == "Object") {
25350 var result = {};
25351
25352 for (var _i3 = 0, _len3 = items.length; _i3 < _len3; _i3++) {
25353 var resultant = items[_i3]; // @TODO: Shoudn't this be this._fieldId?
25354 // result[resultant.id] = resultant
25355
25356 var _id2 = resultant[this._idProp];
25357 result[_id2] = resultant;
25358 }
25359
25360 return result;
25361 } else {
25362 if (id != null) {
25363 // a single item
25364 return item;
25365 } else {
25366 // just return our array
25367 return items;
25368 }
25369 }
25370 }
25371 /** @inheritdoc */
25372
25373 }, {
25374 key: "getIds",
25375 value: function getIds(options) {
25376 var data = this._data;
25377 var filter = options && options.filter;
25378 var order = options && options.order;
25379 var type = options && options.type || this._options.type;
25380 var itemIds = toConsumableArray(data.keys());
25381 var ids = [];
25382 var item;
25383 var items;
25384
25385 if (filter) {
25386 // get filtered items
25387 if (order) {
25388 // create ordered list
25389 items = [];
25390
25391 for (var i = 0, len = itemIds.length; i < len; i++) {
25392 var id = itemIds[i];
25393 item = this._getItem(id, type);
25394
25395 if (filter(item)) {
25396 items.push(item);
25397 }
25398 }
25399
25400 this._sort(items, order);
25401
25402 for (var _i4 = 0, _len4 = items.length; _i4 < _len4; _i4++) {
25403 ids.push(items[_i4][this._idProp]);
25404 }
25405 } else {
25406 // create unordered list
25407 for (var _i5 = 0, _len5 = itemIds.length; _i5 < _len5; _i5++) {
25408 var _id3 = itemIds[_i5];
25409 item = this._getItem(_id3, type);
25410
25411 if (filter(item)) {
25412 ids.push(item[this._idProp]);
25413 }
25414 }
25415 }
25416 } else {
25417 // get all items
25418 if (order) {
25419 // create an ordered list
25420 items = [];
25421
25422 for (var _i6 = 0, _len6 = itemIds.length; _i6 < _len6; _i6++) {
25423 var _id4 = itemIds[_i6];
25424 items.push(data.get(_id4));
25425 }
25426
25427 this._sort(items, order);
25428
25429 for (var _i7 = 0, _len7 = items.length; _i7 < _len7; _i7++) {
25430 ids.push(items[_i7][this._idProp]);
25431 }
25432 } else {
25433 // create unordered list
25434 for (var _i8 = 0, _len8 = itemIds.length; _i8 < _len8; _i8++) {
25435 var _id5 = itemIds[_i8];
25436 item = data.get(_id5);
25437 ids.push(item[this._idProp]);
25438 }
25439 }
25440 }
25441
25442 return ids;
25443 }
25444 /** @inheritdoc */
25445
25446 }, {
25447 key: "getDataSet",
25448 value: function getDataSet() {
25449 return this;
25450 }
25451 /** @inheritdoc */
25452
25453 }, {
25454 key: "forEach",
25455 value: function forEach(callback, options) {
25456 var filter = options && options.filter;
25457 var type = options && options.type || this._options.type;
25458 var data = this._data;
25459 var itemIds = toConsumableArray(data.keys());
25460
25461 if (options && options.order) {
25462 // execute forEach on ordered list
25463 var items = this.get(options);
25464
25465 for (var i = 0, len = items.length; i < len; i++) {
25466 var item = items[i];
25467 var id = item[this._idProp];
25468 callback(item, id);
25469 }
25470 } else {
25471 // unordered
25472 for (var _i9 = 0, _len9 = itemIds.length; _i9 < _len9; _i9++) {
25473 var _id6 = itemIds[_i9];
25474
25475 var _item = this._getItem(_id6, type);
25476
25477 if (!filter || filter(_item)) {
25478 callback(_item, _id6);
25479 }
25480 }
25481 }
25482 }
25483 /** @inheritdoc */
25484
25485 }, {
25486 key: "map",
25487 value: function map(callback, options) {
25488 var filter = options && options.filter;
25489 var type = options && options.type || this._options.type;
25490 var mappedItems = [];
25491 var data = this._data;
25492 var itemIds = toConsumableArray(data.keys()); // convert and filter items
25493
25494 for (var i = 0, len = itemIds.length; i < len; i++) {
25495 var id = itemIds[i];
25496
25497 var item = this._getItem(id, type);
25498
25499 if (!filter || filter(item)) {
25500 mappedItems.push(callback(item, id));
25501 }
25502 } // order items
25503
25504
25505 if (options && options.order) {
25506 this._sort(mappedItems, options.order);
25507 }
25508
25509 return mappedItems;
25510 }
25511 /**
25512 * Filter the fields of an item.
25513 *
25514 * @param item - The item whose fields should be filtered.
25515 * @param fields - The names of the fields that will be kept.
25516 *
25517 * @typeParam K - Field name type.
25518 *
25519 * @returns The item without any additional fields.
25520 */
25521
25522 }, {
25523 key: "_filterFields",
25524 value: function _filterFields(item, fields) {
25525 if (!item) {
25526 // item is null
25527 return item;
25528 }
25529
25530 return (Array.isArray(fields) ? // Use the supplied array
25531 fields : // Use the keys of the supplied object
25532 Object.keys(fields)).reduce(function (filteredItem, field) {
25533 filteredItem[field] = item[field];
25534 return filteredItem;
25535 }, {});
25536 }
25537 /**
25538 * Sort the provided array with items.
25539 *
25540 * @param items - Items to be sorted in place.
25541 * @param order - A field name or custom sort function.
25542 *
25543 * @typeParam T - The type of the items in the items array.
25544 */
25545
25546 }, {
25547 key: "_sort",
25548 value: function _sort(items, order) {
25549 if (typeof order === "string") {
25550 // order by provided field name
25551 var name = order; // field name
25552
25553 items.sort(function (a, b) {
25554 // @TODO: How to treat missing properties?
25555 var av = a[name];
25556 var bv = b[name];
25557 return av > bv ? 1 : av < bv ? -1 : 0;
25558 });
25559 } else if (typeof order === "function") {
25560 // order by sort function
25561 items.sort(order);
25562 } else {
25563 // TODO: extend order by an Object {field:string, direction:string}
25564 // where direction can be 'asc' or 'desc'
25565 throw new TypeError("Order must be a function or a string");
25566 }
25567 }
25568 /**
25569 * Remove an item or multiple items by “reference” (only the id is used) or by id.
25570 *
25571 * 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.
25572 *
25573 * 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.
25574 *
25575 * ## Example
25576 * ```javascript
25577 * // create a DataSet
25578 * const data = new vis.DataSet([
25579 * { id: 1, text: 'item 1' },
25580 * { id: 2, text: 'item 2' },
25581 * { id: 3, text: 'item 3' }
25582 * ])
25583 *
25584 * // remove items
25585 * const ids = data.remove([2, { id: 3 }, 4])
25586 *
25587 * console.log(ids) // [2, 3]
25588 * ```
25589 *
25590 * @param id - One or more items or ids of items to be removed.
25591 * @param senderId - Sender id.
25592 *
25593 * @returns The ids of the removed items.
25594 */
25595
25596 }, {
25597 key: "remove",
25598 value: function remove(id, senderId) {
25599 var removedIds = [];
25600 var removedItems = []; // force everything to be an array for simplicity
25601
25602 var ids = Array.isArray(id) ? id : [id];
25603
25604 for (var i = 0, len = ids.length; i < len; i++) {
25605 var item = this._remove(ids[i]);
25606
25607 if (item) {
25608 var itemId = item[this._idProp];
25609
25610 if (itemId != null) {
25611 removedIds.push(itemId);
25612 removedItems.push(item);
25613 }
25614 }
25615 }
25616
25617 if (removedIds.length) {
25618 this._trigger("remove", {
25619 items: removedIds,
25620 oldData: removedItems
25621 }, senderId);
25622 }
25623
25624 return removedIds;
25625 }
25626 /**
25627 * Remove an item by its id or reference.
25628 *
25629 * @param id - Id of an item or the item itself.
25630 *
25631 * @returns The removed item if removed, null otherwise.
25632 */
25633
25634 }, {
25635 key: "_remove",
25636 value: function _remove(id) {
25637 // @TODO: It origianlly returned the item although the docs say id.
25638 // The code expects the item, so probably an error in the docs.
25639 var ident; // confirm the id to use based on the args type
25640
25641 if (isId(id)) {
25642 ident = id;
25643 } else if (id && _typeof_1(id) === "object") {
25644 ident = id[this._idProp]; // look for the identifier field using ._idProp
25645 } // do the removing if the item is found
25646
25647
25648 if (ident != null && this._data.has(ident)) {
25649 var item = this._data.get(ident) || null;
25650
25651 this._data.delete(ident);
25652
25653 --this.length;
25654 return item;
25655 }
25656
25657 return null;
25658 }
25659 /**
25660 * Clear the entire data set.
25661 *
25662 * 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.
25663 *
25664 * @param senderId - Sender id.
25665 *
25666 * @returns removedIds - The ids of all removed items.
25667 */
25668
25669 }, {
25670 key: "clear",
25671 value: function clear(senderId) {
25672 var ids = toConsumableArray(this._data.keys());
25673 var items = [];
25674
25675 for (var i = 0, len = ids.length; i < len; i++) {
25676 items.push(this._data.get(ids[i]));
25677 }
25678
25679 this._data.clear();
25680
25681 this.length = 0;
25682
25683 this._trigger("remove", {
25684 items: ids,
25685 oldData: items
25686 }, senderId);
25687
25688 return ids;
25689 }
25690 /**
25691 * Find the item with maximum value of a specified field.
25692 *
25693 * @param field - Name of the property that should be searched for max value.
25694 *
25695 * @returns Item containing max value, or null if no items.
25696 */
25697
25698 }, {
25699 key: "max",
25700 value: function max(field) {
25701 var max = null;
25702 var maxField = null;
25703 var _iteratorNormalCompletion = true;
25704 var _didIteratorError = false;
25705 var _iteratorError = undefined;
25706
25707 try {
25708 for (var _iterator = this._data.values()[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
25709 var item = _step.value;
25710 var itemField = item[field];
25711
25712 if (typeof itemField === "number" && (maxField == null || itemField > maxField)) {
25713 max = item;
25714 maxField = itemField;
25715 }
25716 }
25717 } catch (err) {
25718 _didIteratorError = true;
25719 _iteratorError = err;
25720 } finally {
25721 try {
25722 if (!_iteratorNormalCompletion && _iterator.return != null) {
25723 _iterator.return();
25724 }
25725 } finally {
25726 if (_didIteratorError) {
25727 throw _iteratorError;
25728 }
25729 }
25730 }
25731
25732 return max || null;
25733 }
25734 /**
25735 * Find the item with minimum value of a specified field.
25736 *
25737 * @param field - Name of the property that should be searched for min value.
25738 *
25739 * @returns Item containing min value, or null if no items.
25740 */
25741
25742 }, {
25743 key: "min",
25744 value: function min(field) {
25745 var min = null;
25746 var minField = null;
25747 var _iteratorNormalCompletion2 = true;
25748 var _didIteratorError2 = false;
25749 var _iteratorError2 = undefined;
25750
25751 try {
25752 for (var _iterator2 = this._data.values()[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
25753 var item = _step2.value;
25754 var itemField = item[field];
25755
25756 if (typeof itemField === "number" && (minField == null || itemField < minField)) {
25757 min = item;
25758 minField = itemField;
25759 }
25760 }
25761 } catch (err) {
25762 _didIteratorError2 = true;
25763 _iteratorError2 = err;
25764 } finally {
25765 try {
25766 if (!_iteratorNormalCompletion2 && _iterator2.return != null) {
25767 _iterator2.return();
25768 }
25769 } finally {
25770 if (_didIteratorError2) {
25771 throw _iteratorError2;
25772 }
25773 }
25774 }
25775
25776 return min || null;
25777 }
25778 /**
25779 * Find all distinct values of a specified field
25780 *
25781 * @param prop - The property name whose distinct values should be returned.
25782 *
25783 * @returns Unordered array containing all distinct values. Items without specified property are ignored.
25784 */
25785
25786 }, {
25787 key: "distinct",
25788 value: function distinct(prop) {
25789 var data = this._data;
25790 var itemIds = toConsumableArray(data.keys());
25791 var values = [];
25792 var fieldType = this._options.type && this._options.type[prop] || null;
25793 var count = 0;
25794
25795 for (var i = 0, len = itemIds.length; i < len; i++) {
25796 var id = itemIds[i];
25797 var item = data.get(id);
25798 var value = item[prop];
25799 var exists = false;
25800
25801 for (var j = 0; j < count; j++) {
25802 if (values[j] == value) {
25803 exists = true;
25804 break;
25805 }
25806 }
25807
25808 if (!exists && value !== undefined) {
25809 values[count] = value;
25810 count++;
25811 }
25812 }
25813
25814 if (fieldType) {
25815 for (var _i10 = 0, _len10 = values.length; _i10 < _len10; _i10++) {
25816 values[_i10] = convert$1(values[_i10], fieldType);
25817 }
25818 }
25819
25820 return values;
25821 }
25822 /**
25823 * Add a single item. Will fail when an item with the same id already exists.
25824 *
25825 * @param item - A new item to be added.
25826 *
25827 * @returns Added item's id. An id is generated when it is not present in the item.
25828 */
25829
25830 }, {
25831 key: "_addItem",
25832 value: function _addItem(item) {
25833 var id = item[this._idProp];
25834
25835 if (id != null) {
25836 // check whether this id is already taken
25837 if (this._data.has(id)) {
25838 // item already exists
25839 throw new Error("Cannot add item: item with id " + id + " already exists");
25840 }
25841 } else {
25842 // generate an id
25843 id = uuid4$1();
25844 item[this._idProp] = id;
25845 }
25846
25847 var d = {};
25848 var fields = Object.keys(item);
25849
25850 for (var i = 0, len = fields.length; i < len; i++) {
25851 var field = fields[i];
25852 var fieldType = this._type[field]; // type may be undefined
25853
25854 d[field] = convert$1(item[field], fieldType);
25855 }
25856
25857 this._data.set(id, d);
25858
25859 ++this.length;
25860 return id;
25861 }
25862 /**
25863 * Get an item. Fields can be converted to a specific type
25864 *
25865 * @param id - Id of the requested item.
25866 * @param types - Property name to type name object map of type converstions.
25867 *
25868 * @returns The item, optionally after type conversion.
25869 */
25870
25871 }, {
25872 key: "_getItem",
25873 value: function _getItem(id, types) {
25874 // @TODO: I have no idea how to type this.
25875 // get the item from the dataset
25876 var raw = this._data.get(id);
25877
25878 if (!raw) {
25879 return null;
25880 } // convert the items field types
25881
25882
25883 var converted;
25884 var fields = Object.keys(raw);
25885
25886 if (types) {
25887 converted = {};
25888
25889 for (var i = 0, len = fields.length; i < len; i++) {
25890 var field = fields[i];
25891 var value = raw[field];
25892 converted[field] = convert$1(value, types[field]);
25893 }
25894 } else {
25895 // no field types specified, no converting needed
25896 converted = _objectSpread({}, raw);
25897 }
25898
25899 if (converted[this._idProp] == null) {
25900 converted[this._idProp] = raw.id;
25901 }
25902
25903 return converted;
25904 }
25905 /**
25906 * Update a single item: merge with existing item.
25907 * Will fail when the item has no id, or when there does not exist an item with the same id.
25908 *
25909 * @param item - The new item
25910 *
25911 * @returns The id of the updated item.
25912 */
25913
25914 }, {
25915 key: "_updateItem",
25916 value: function _updateItem(item) {
25917 var id = item[this._idProp];
25918
25919 if (id == null) {
25920 throw new Error("Cannot update item: item has no id (item: " + JSON.stringify(item) + ")");
25921 }
25922
25923 var d = this._data.get(id);
25924
25925 if (!d) {
25926 // item doesn't exist
25927 throw new Error("Cannot update item: no item with id " + id + " found");
25928 } // merge with current item
25929
25930
25931 var fields = Object.keys(item);
25932
25933 for (var i = 0, len = fields.length; i < len; i++) {
25934 var field = fields[i];
25935 var fieldType = this._type[field]; // type may be undefined
25936
25937 d[field] = convert$1(item[field], fieldType);
25938 }
25939
25940 return id;
25941 }
25942 /** @inheritdoc */
25943
25944 }, {
25945 key: "stream",
25946 value: function stream(ids) {
25947 if (ids) {
25948 var data = this._data;
25949 return new DataStream(defineProperty$6({}, Symbol.iterator,
25950 /*#__PURE__*/
25951 regenerator.mark(function _callee() {
25952 var _iteratorNormalCompletion3, _didIteratorError3, _iteratorError3, _iterator3, _step3, id, item;
25953
25954 return regenerator.wrap(function _callee$(_context) {
25955 while (1) {
25956 switch (_context.prev = _context.next) {
25957 case 0:
25958 _iteratorNormalCompletion3 = true;
25959 _didIteratorError3 = false;
25960 _iteratorError3 = undefined;
25961 _context.prev = 3;
25962 _iterator3 = ids[Symbol.iterator]();
25963
25964 case 5:
25965 if (_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done) {
25966 _context.next = 14;
25967 break;
25968 }
25969
25970 id = _step3.value;
25971 item = data.get(id);
25972
25973 if (!(item != null)) {
25974 _context.next = 11;
25975 break;
25976 }
25977
25978 _context.next = 11;
25979 return [id, item];
25980
25981 case 11:
25982 _iteratorNormalCompletion3 = true;
25983 _context.next = 5;
25984 break;
25985
25986 case 14:
25987 _context.next = 20;
25988 break;
25989
25990 case 16:
25991 _context.prev = 16;
25992 _context.t0 = _context["catch"](3);
25993 _didIteratorError3 = true;
25994 _iteratorError3 = _context.t0;
25995
25996 case 20:
25997 _context.prev = 20;
25998 _context.prev = 21;
25999
26000 if (!_iteratorNormalCompletion3 && _iterator3.return != null) {
26001 _iterator3.return();
26002 }
26003
26004 case 23:
26005 _context.prev = 23;
26006
26007 if (!_didIteratorError3) {
26008 _context.next = 26;
26009 break;
26010 }
26011
26012 throw _iteratorError3;
26013
26014 case 26:
26015 return _context.finish(23);
26016
26017 case 27:
26018 return _context.finish(20);
26019
26020 case 28:
26021 case "end":
26022 return _context.stop();
26023 }
26024 }
26025 }, _callee, null, [[3, 16, 20, 28], [21,, 23, 27]]);
26026 })));
26027 } else {
26028 return new DataStream(defineProperty$6({}, Symbol.iterator, this._data.entries.bind(this._data)));
26029 }
26030 }
26031 }]);
26032 return DataSet;
26033 }(DataSetPart);
26034 /**
26035 * DataView
26036 *
26037 * 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.
26038 *
26039 * ## Example
26040 * ```javascript
26041 * // create a DataSet
26042 * var data = new vis.DataSet();
26043 * data.add([
26044 * {id: 1, text: 'item 1', date: new Date(2013, 6, 20), group: 1, first: true},
26045 * {id: 2, text: 'item 2', date: '2013-06-23', group: 2},
26046 * {id: 3, text: 'item 3', date: '2013-06-25', group: 2},
26047 * {id: 4, text: 'item 4'}
26048 * ]);
26049 *
26050 * // create a DataView
26051 * // the view will only contain items having a property group with value 1,
26052 * // and will only output fields id, text, and date.
26053 * var view = new vis.DataView(data, {
26054 * filter: function (item) {
26055 * return (item.group == 1);
26056 * },
26057 * fields: ['id', 'text', 'date']
26058 * });
26059 *
26060 * // subscribe to any change in the DataView
26061 * view.on('*', function (event, properties, senderId) {
26062 * console.log('event', event, properties);
26063 * });
26064 *
26065 * // update an item in the data set
26066 * data.update({id: 2, group: 1});
26067 *
26068 * // get all ids in the view
26069 * var ids = view.getIds();
26070 * console.log('ids', ids); // will output [1, 2]
26071 *
26072 * // get all items in the view
26073 * var items = view.get();
26074 * ```
26075 *
26076 * @typeParam Item - Item type that may or may not have an id.
26077 * @typeParam IdProp - Name of the property that contains the id.
26078 */
26079
26080
26081 var DataView$2 =
26082 /*#__PURE__*/
26083 function (_DataSetPart) {
26084 inherits(DataView, _DataSetPart);
26085 /**
26086 * Create a DataView.
26087 *
26088 * @param data - The instance containing data (directly or indirectly).
26089 * @param options - Options to configure this data view.
26090 */
26091
26092 function DataView(data, options) {
26093 var _this;
26094
26095 classCallCheck(this, DataView);
26096 _this = possibleConstructorReturn(this, getPrototypeOf(DataView).call(this));
26097 /** @inheritdoc */
26098
26099 _this.length = 0;
26100 _this._ids = new Set(); // ids of the items currently in memory (just contains a boolean true)
26101
26102 _this._options = options || {};
26103 _this._listener = _this._onEvent.bind(assertThisInitialized(_this));
26104
26105 _this.setData(data);
26106
26107 return _this;
26108 } // TODO: implement a function .config() to dynamically update things like configured filter
26109 // and trigger changes accordingly
26110
26111 /**
26112 * Set a data source for the view.
26113 *
26114 * @param data - The instance containing data (directly or indirectly).
26115 */
26116
26117
26118 createClass(DataView, [{
26119 key: "setData",
26120 value: function setData(data) {
26121 if (this._data) {
26122 // unsubscribe from current dataset
26123 if (this._data.off) {
26124 this._data.off("*", this._listener);
26125 } // trigger a remove of all items in memory
26126
26127
26128 var ids = this._data.getIds({
26129 filter: this._options.filter
26130 });
26131
26132 var items = this._data.get(ids);
26133
26134 this._ids.clear();
26135
26136 this.length = 0;
26137
26138 this._trigger("remove", {
26139 items: ids,
26140 oldData: items
26141 });
26142 }
26143
26144 if (data != null) {
26145 this._data = data; // trigger an add of all added items
26146
26147 var _ids = this._data.getIds({
26148 filter: this._options.filter
26149 });
26150
26151 for (var i = 0, len = _ids.length; i < len; i++) {
26152 var id = _ids[i];
26153
26154 this._ids.add(id);
26155 }
26156
26157 this.length = _ids.length;
26158
26159 this._trigger("add", {
26160 items: _ids
26161 });
26162 } else {
26163 this._data = new DataSet();
26164 } // subscribe to new dataset
26165
26166
26167 if (this._data.on) {
26168 this._data.on("*", this._listener);
26169 }
26170 }
26171 /**
26172 * Refresh the DataView.
26173 * Useful when the DataView has a filter function containing a variable parameter.
26174 */
26175
26176 }, {
26177 key: "refresh",
26178 value: function refresh() {
26179 var ids = this._data.getIds({
26180 filter: this._options.filter
26181 });
26182
26183 var oldIds = toConsumableArray(this._ids);
26184 var newIds = {};
26185 var addedIds = [];
26186 var removedIds = [];
26187 var removedItems = []; // check for additions
26188
26189 for (var i = 0, len = ids.length; i < len; i++) {
26190 var id = ids[i];
26191 newIds[id] = true;
26192
26193 if (!this._ids.has(id)) {
26194 addedIds.push(id);
26195
26196 this._ids.add(id);
26197 }
26198 } // check for removals
26199
26200
26201 for (var _i = 0, _len = oldIds.length; _i < _len; _i++) {
26202 var _id = oldIds[_i];
26203
26204 var item = this._data.get(_id);
26205
26206 if (item == null) {
26207 // @TODO: Investigate.
26208 // Doesn't happen during tests or examples.
26209 // Is it really impossible or could it eventually happen?
26210 // How to handle it if it does? The types guarantee non-nullable items.
26211 console.error("If you see this, report it please.");
26212 } else if (!newIds[_id]) {
26213 removedIds.push(_id);
26214 removedItems.push(item);
26215
26216 this._ids.delete(_id);
26217 }
26218 }
26219
26220 this.length += addedIds.length - removedIds.length; // trigger events
26221
26222 if (addedIds.length) {
26223 this._trigger("add", {
26224 items: addedIds
26225 });
26226 }
26227
26228 if (removedIds.length) {
26229 this._trigger("remove", {
26230 items: removedIds,
26231 oldData: removedItems
26232 });
26233 }
26234 }
26235 /** @inheritdoc */
26236
26237 }, {
26238 key: "get",
26239 value: function get(first, second) {
26240 if (this._data == null) {
26241 return null;
26242 } // parse the arguments
26243
26244
26245 var ids = null;
26246 var options;
26247
26248 if (isId(first) || Array.isArray(first)) {
26249 ids = first;
26250 options = second;
26251 } else {
26252 options = first;
26253 } // extend the options with the default options and provided options
26254
26255
26256 var viewOptions = Object.assign({}, this._options, options); // create a combined filter method when needed
26257
26258 var thisFilter = this._options.filter;
26259 var optionsFilter = options && options.filter;
26260
26261 if (thisFilter && optionsFilter) {
26262 viewOptions.filter = function (item) {
26263 return thisFilter(item) && optionsFilter(item);
26264 };
26265 }
26266
26267 if (ids == null) {
26268 return this._data.get(viewOptions);
26269 } else {
26270 return this._data.get(ids, viewOptions);
26271 }
26272 }
26273 /** @inheritdoc */
26274
26275 }, {
26276 key: "getIds",
26277 value: function getIds(options) {
26278 if (this._data.length) {
26279 var defaultFilter = this._options.filter;
26280 var optionsFilter = options != null ? options.filter : null;
26281 var filter;
26282
26283 if (optionsFilter) {
26284 if (defaultFilter) {
26285 filter = function filter(item) {
26286 return defaultFilter(item) && optionsFilter(item);
26287 };
26288 } else {
26289 filter = optionsFilter;
26290 }
26291 } else {
26292 filter = defaultFilter;
26293 }
26294
26295 return this._data.getIds({
26296 filter: filter,
26297 order: options && options.order
26298 });
26299 } else {
26300 return [];
26301 }
26302 }
26303 /** @inheritdoc */
26304
26305 }, {
26306 key: "forEach",
26307 value: function forEach(callback, options) {
26308 if (this._data) {
26309 var defaultFilter = this._options.filter;
26310 var optionsFilter = options && options.filter;
26311 var filter;
26312
26313 if (optionsFilter) {
26314 if (defaultFilter) {
26315 filter = function filter(item) {
26316 return defaultFilter(item) && optionsFilter(item);
26317 };
26318 } else {
26319 filter = optionsFilter;
26320 }
26321 } else {
26322 filter = defaultFilter;
26323 }
26324
26325 this._data.forEach(callback, {
26326 filter: filter,
26327 order: options && options.order
26328 });
26329 }
26330 }
26331 /** @inheritdoc */
26332
26333 }, {
26334 key: "map",
26335 value: function map(callback, options) {
26336 if (this._data) {
26337 var defaultFilter = this._options.filter;
26338 var optionsFilter = options && options.filter;
26339 var filter;
26340
26341 if (optionsFilter) {
26342 if (defaultFilter) {
26343 filter = function filter(item) {
26344 return defaultFilter(item) && optionsFilter(item);
26345 };
26346 } else {
26347 filter = optionsFilter;
26348 }
26349 } else {
26350 filter = defaultFilter;
26351 }
26352
26353 return this._data.map(callback, {
26354 filter: filter,
26355 order: options && options.order
26356 });
26357 } else {
26358 return [];
26359 }
26360 }
26361 /** @inheritdoc */
26362
26363 }, {
26364 key: "getDataSet",
26365 value: function getDataSet() {
26366 return this._data.getDataSet();
26367 }
26368 /** @inheritdoc */
26369
26370 }, {
26371 key: "stream",
26372 value: function stream(ids) {
26373 return this._data.stream(ids || defineProperty$6({}, Symbol.iterator, this._ids.keys.bind(this._ids)));
26374 }
26375 /**
26376 * 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.
26377 *
26378 * @param event - The name of the event.
26379 * @param params - Parameters of the event.
26380 * @param senderId - Id supplied by the sender.
26381 */
26382
26383 }, {
26384 key: "_onEvent",
26385 value: function _onEvent(event, params, senderId) {
26386 if (!params || !params.items || !this._data) {
26387 return;
26388 }
26389
26390 var ids = params.items;
26391 var addedIds = [];
26392 var updatedIds = [];
26393 var removedIds = [];
26394 var oldItems = [];
26395 var updatedItems = [];
26396 var removedItems = [];
26397
26398 switch (event) {
26399 case "add":
26400 // filter the ids of the added items
26401 for (var i = 0, len = ids.length; i < len; i++) {
26402 var id = ids[i];
26403 var item = this.get(id);
26404
26405 if (item) {
26406 this._ids.add(id);
26407
26408 addedIds.push(id);
26409 }
26410 }
26411
26412 break;
26413
26414 case "update":
26415 // determine the event from the views viewpoint: an updated
26416 // item can be added, updated, or removed from this view.
26417 for (var _i2 = 0, _len2 = ids.length; _i2 < _len2; _i2++) {
26418 var _id2 = ids[_i2];
26419
26420 var _item = this.get(_id2);
26421
26422 if (_item) {
26423 if (this._ids.has(_id2)) {
26424 updatedIds.push(_id2);
26425 updatedItems.push(params.data[_i2]);
26426 oldItems.push(params.oldData[_i2]);
26427 } else {
26428 this._ids.add(_id2);
26429
26430 addedIds.push(_id2);
26431 }
26432 } else {
26433 if (this._ids.has(_id2)) {
26434 this._ids.delete(_id2);
26435
26436 removedIds.push(_id2);
26437 removedItems.push(params.oldData[_i2]);
26438 }
26439 }
26440 }
26441
26442 break;
26443
26444 case "remove":
26445 // filter the ids of the removed items
26446 for (var _i3 = 0, _len3 = ids.length; _i3 < _len3; _i3++) {
26447 var _id3 = ids[_i3];
26448
26449 if (this._ids.has(_id3)) {
26450 this._ids.delete(_id3);
26451
26452 removedIds.push(_id3);
26453 removedItems.push(params.oldData[_i3]);
26454 }
26455 }
26456
26457 break;
26458 }
26459
26460 this.length += addedIds.length - removedIds.length;
26461
26462 if (addedIds.length) {
26463 this._trigger("add", {
26464 items: addedIds
26465 }, senderId);
26466 }
26467
26468 if (updatedIds.length) {
26469 this._trigger("update", {
26470 items: updatedIds,
26471 oldData: oldItems,
26472 data: updatedItems
26473 }, senderId);
26474 }
26475
26476 if (removedIds.length) {
26477 this._trigger("remove", {
26478 items: removedIds,
26479 oldData: removedItems
26480 }, senderId);
26481 }
26482 }
26483 }]);
26484 return DataView;
26485 }(DataSetPart);
26486
26487 var index$1 = {
26488 DataSet: DataSet,
26489 DataView: DataView$2,
26490 Queue: Queue
26491 };
26492
26493 var esm$1 = /*#__PURE__*/Object.freeze({
26494 __proto__: null,
26495 'default': index$1,
26496 DataSet: DataSet,
26497 DataStream: DataStream,
26498 DataView: DataView$2,
26499 Queue: Queue
26500 });
26501
26502 var trim$2 = stringTrim.trim;
26503 var nativeParseFloat = global_1.parseFloat;
26504 var FORCED = 1 / nativeParseFloat(whitespaces + '-0') !== -Infinity; // `parseFloat` method
26505 // https://tc39.github.io/ecma262/#sec-parsefloat-string
26506
26507 var _parseFloat = FORCED ? function parseFloat(string) {
26508 var trimmedString = trim$2(String(string));
26509 var result = nativeParseFloat(trimmedString);
26510 return result === 0 && trimmedString.charAt(0) == '-' ? -0 : result;
26511 } : nativeParseFloat;
26512
26513 // https://tc39.github.io/ecma262/#sec-parsefloat-string
26514
26515 _export({
26516 global: true,
26517 forced: parseFloat != _parseFloat
26518 }, {
26519 parseFloat: _parseFloat
26520 });
26521
26522 var trim$3 = stringTrim.trim;
26523 var nativeParseInt = global_1.parseInt;
26524 var hex = /^[+-]?0[Xx]/;
26525 var FORCED$1 = nativeParseInt(whitespaces + '08') !== 8 || nativeParseInt(whitespaces + '0x16') !== 22; // `parseInt` method
26526 // https://tc39.github.io/ecma262/#sec-parseint-string-radix
26527
26528 var _parseInt = FORCED$1 ? function parseInt(string, radix) {
26529 var S = trim$3(String(string));
26530 return nativeParseInt(S, radix >>> 0 || (hex.test(S) ? 16 : 10));
26531 } : nativeParseInt;
26532
26533 // https://tc39.github.io/ecma262/#sec-parseint-string-radix
26534
26535 _export({
26536 global: true,
26537 forced: parseInt != _parseInt
26538 }, {
26539 parseInt: _parseInt
26540 });
26541
26542 var max$3 = Math.max;
26543 var min$5 = Math.min;
26544 var floor$3 = Math.floor;
26545 var SUBSTITUTION_SYMBOLS$1 = /\$([$&'`]|\d\d?|<[^>]*>)/g;
26546 var SUBSTITUTION_SYMBOLS_NO_NAMED$1 = /\$([$&'`]|\d\d?)/g;
26547
26548 var maybeToString$1 = function (it) {
26549 return it === undefined ? it : String(it);
26550 }; // @@replace logic
26551
26552
26553 fixRegexpWellKnownSymbolLogic('replace', 2, function (REPLACE, nativeReplace, maybeCallNative) {
26554 return [// `String.prototype.replace` method
26555 // https://tc39.github.io/ecma262/#sec-string.prototype.replace
26556 function replace(searchValue, replaceValue) {
26557 var O = requireObjectCoercible(this);
26558 var replacer = searchValue == undefined ? undefined : searchValue[REPLACE];
26559 return replacer !== undefined ? replacer.call(searchValue, O, replaceValue) : nativeReplace.call(String(O), searchValue, replaceValue);
26560 }, // `RegExp.prototype[@@replace]` method
26561 // https://tc39.github.io/ecma262/#sec-regexp.prototype-@@replace
26562 function (regexp, replaceValue) {
26563 var res = maybeCallNative(nativeReplace, regexp, this, replaceValue);
26564 if (res.done) return res.value;
26565 var rx = anObject(regexp);
26566 var S = String(this);
26567 var functionalReplace = typeof replaceValue === 'function';
26568 if (!functionalReplace) replaceValue = String(replaceValue);
26569 var global = rx.global;
26570
26571 if (global) {
26572 var fullUnicode = rx.unicode;
26573 rx.lastIndex = 0;
26574 }
26575
26576 var results = [];
26577
26578 while (true) {
26579 var result = regexpExecAbstract(rx, S);
26580 if (result === null) break;
26581 results.push(result);
26582 if (!global) break;
26583 var matchStr = String(result[0]);
26584 if (matchStr === '') rx.lastIndex = advanceStringIndex(S, toLength(rx.lastIndex), fullUnicode);
26585 }
26586
26587 var accumulatedResult = '';
26588 var nextSourcePosition = 0;
26589
26590 for (var i = 0; i < results.length; i++) {
26591 result = results[i];
26592 var matched = String(result[0]);
26593 var position = max$3(min$5(toInteger(result.index), S.length), 0);
26594 var captures = []; // NOTE: This is equivalent to
26595 // captures = result.slice(1).map(maybeToString)
26596 // but for some reason `nativeSlice.call(result, 1, result.length)` (called in
26597 // the slice polyfill when slicing native arrays) "doesn't work" in safari 9 and
26598 // causes a crash (https://pastebin.com/N21QzeQA) when trying to debug it.
26599
26600 for (var j = 1; j < result.length; j++) captures.push(maybeToString$1(result[j]));
26601
26602 var namedCaptures = result.groups;
26603
26604 if (functionalReplace) {
26605 var replacerArgs = [matched].concat(captures, position, S);
26606 if (namedCaptures !== undefined) replacerArgs.push(namedCaptures);
26607 var replacement = String(replaceValue.apply(undefined, replacerArgs));
26608 } else {
26609 replacement = getSubstitution(matched, S, position, captures, namedCaptures, replaceValue);
26610 }
26611
26612 if (position >= nextSourcePosition) {
26613 accumulatedResult += S.slice(nextSourcePosition, position) + replacement;
26614 nextSourcePosition = position + matched.length;
26615 }
26616 }
26617
26618 return accumulatedResult + S.slice(nextSourcePosition);
26619 }]; // https://tc39.github.io/ecma262/#sec-getsubstitution
26620
26621 function getSubstitution(matched, str, position, captures, namedCaptures, replacement) {
26622 var tailPos = position + matched.length;
26623 var m = captures.length;
26624 var symbols = SUBSTITUTION_SYMBOLS_NO_NAMED$1;
26625
26626 if (namedCaptures !== undefined) {
26627 namedCaptures = toObject(namedCaptures);
26628 symbols = SUBSTITUTION_SYMBOLS$1;
26629 }
26630
26631 return nativeReplace.call(replacement, symbols, function (match, ch) {
26632 var capture;
26633
26634 switch (ch.charAt(0)) {
26635 case '$':
26636 return '$';
26637
26638 case '&':
26639 return matched;
26640
26641 case '`':
26642 return str.slice(0, position);
26643
26644 case "'":
26645 return str.slice(tailPos);
26646
26647 case '<':
26648 capture = namedCaptures[ch.slice(1, -1)];
26649 break;
26650
26651 default:
26652 // \d\d?
26653 var n = +ch;
26654 if (n === 0) return match;
26655
26656 if (n > m) {
26657 var f = floor$3(n / 10);
26658 if (f === 0) return match;
26659 if (f <= m) return captures[f - 1] === undefined ? ch.charAt(1) : captures[f - 1] + ch.charAt(1);
26660 return match;
26661 }
26662
26663 capture = captures[n - 1];
26664 }
26665
26666 return capture === undefined ? '' : capture;
26667 });
26668 }
26669 });
26670
26671 var nativeJoin = [].join;
26672 var ES3_STRINGS = indexedObject != Object;
26673 var SLOPPY_METHOD$1 = sloppyArrayMethod('join', ','); // `Array.prototype.join` method
26674 // https://tc39.github.io/ecma262/#sec-array.prototype.join
26675
26676 _export({
26677 target: 'Array',
26678 proto: true,
26679 forced: ES3_STRINGS || SLOPPY_METHOD$1
26680 }, {
26681 join: function join(separator) {
26682 return nativeJoin.call(toIndexedObject(this), separator === undefined ? ',' : separator);
26683 }
26684 });
26685
26686 /**
26687 * Helper functions for components
26688 * @class
26689 */
26690
26691 var ComponentUtil =
26692 /*#__PURE__*/
26693 function () {
26694 function ComponentUtil() {
26695 _classCallCheck(this, ComponentUtil);
26696 }
26697
26698 _createClass(ComponentUtil, null, [{
26699 key: "choosify",
26700
26701 /**
26702 * Determine values to use for (sub)options of 'chosen'.
26703 *
26704 * This option is either a boolean or an object whose values should be examined further.
26705 * The relevant structures are:
26706 *
26707 * - chosen: <boolean value>
26708 * - chosen: { subOption: <boolean or function> }
26709 *
26710 * Where subOption is 'node', 'edge' or 'label'.
26711 *
26712 * The intention of this method appears to be to set a specific priority to the options;
26713 * Since most properties are either bridged or merged into the local options objects, there
26714 * is not much point in handling them separately.
26715 * TODO: examine if 'most' in previous sentence can be replaced with 'all'. In that case, we
26716 * should be able to get rid of this method.
26717 *
26718 * @param {string} subOption option within object 'chosen' to consider; either 'node', 'edge' or 'label'
26719 * @param {Object} pile array of options objects to consider
26720 *
26721 * @return {boolean|function} value for passed subOption of 'chosen' to use
26722 */
26723 value: function choosify(subOption, pile) {
26724 // allowed values for subOption
26725 var allowed = ['node', 'edge', 'label'];
26726 var value = true;
26727 var chosen = topMost(pile, 'chosen');
26728
26729 if (typeof chosen === 'boolean') {
26730 value = chosen;
26731 } else if (_typeof$1(chosen) === 'object') {
26732 if (allowed.indexOf(subOption) === -1) {
26733 throw new Error('choosify: subOption \'' + subOption + '\' should be one of ' + "'" + allowed.join("', '") + "'");
26734 }
26735
26736 var chosenEdge = topMost(pile, ['chosen', subOption]);
26737
26738 if (typeof chosenEdge === 'boolean' || typeof chosenEdge === 'function') {
26739 value = chosenEdge;
26740 }
26741 }
26742
26743 return value;
26744 }
26745 /**
26746 * Check if the point falls within the given rectangle.
26747 *
26748 * @param {rect} rect
26749 * @param {point} point
26750 * @param {rotationPoint} [rotationPoint] if specified, the rotation that applies to the rectangle.
26751 * @returns {boolean} true if point within rectangle, false otherwise
26752 * @static
26753 */
26754
26755 }, {
26756 key: "pointInRect",
26757 value: function pointInRect(rect, point, rotationPoint) {
26758 if (rect.width <= 0 || rect.height <= 0) {
26759 return false; // early out
26760 }
26761
26762 if (rotationPoint !== undefined) {
26763 // Rotate the point the same amount as the rectangle
26764 var tmp = {
26765 x: point.x - rotationPoint.x,
26766 y: point.y - rotationPoint.y
26767 };
26768
26769 if (rotationPoint.angle !== 0) {
26770 // In order to get the coordinates the same, you need to
26771 // rotate in the reverse direction
26772 var angle = -rotationPoint.angle;
26773 var tmp2 = {
26774 x: Math.cos(angle) * tmp.x - Math.sin(angle) * tmp.y,
26775 y: Math.sin(angle) * tmp.x + Math.cos(angle) * tmp.y
26776 };
26777 point = tmp2;
26778 } else {
26779 point = tmp;
26780 } // Note that if a rotation is specified, the rectangle coordinates
26781 // are **not* the full canvas coordinates. They are relative to the
26782 // rotationPoint. Hence, the point coordinates need not be translated
26783 // back in this case.
26784
26785 }
26786
26787 var right = rect.x + rect.width;
26788 var bottom = rect.y + rect.width;
26789 return rect.left < point.x && right > point.x && rect.top < point.y && bottom > point.y;
26790 }
26791 /**
26792 * Check if given value is acceptable as a label text.
26793 *
26794 * @param {*} text value to check; can be anything at this point
26795 * @returns {boolean} true if valid label value, false otherwise
26796 */
26797
26798 }, {
26799 key: "isValidLabel",
26800 value: function isValidLabel(text) {
26801 // Note that this is quite strict: types that *might* be converted to string are disallowed
26802 return typeof text === 'string' && text !== '';
26803 }
26804 }]);
26805
26806 return ComponentUtil;
26807 }();
26808
26809 var SPECIES$5 = wellKnownSymbol('species');
26810 var nativeSlice = [].slice;
26811 var max$4 = Math.max; // `Array.prototype.slice` method
26812 // https://tc39.github.io/ecma262/#sec-array.prototype.slice
26813 // fallback for not array-like ES3 strings and DOM objects
26814
26815 _export({
26816 target: 'Array',
26817 proto: true,
26818 forced: !arrayMethodHasSpeciesSupport('slice')
26819 }, {
26820 slice: function slice(start, end) {
26821 var O = toIndexedObject(this);
26822 var length = toLength(O.length);
26823 var k = toAbsoluteIndex(start, length);
26824 var fin = toAbsoluteIndex(end === undefined ? length : end, length); // inline `ArraySpeciesCreate` for usage native `Array#slice` where it's possible
26825
26826 var Constructor, result, n;
26827
26828 if (isArray(O)) {
26829 Constructor = O.constructor; // cross-realm fallback
26830
26831 if (typeof Constructor == 'function' && (Constructor === Array || isArray(Constructor.prototype))) {
26832 Constructor = undefined;
26833 } else if (isObject(Constructor)) {
26834 Constructor = Constructor[SPECIES$5];
26835 if (Constructor === null) Constructor = undefined;
26836 }
26837
26838 if (Constructor === Array || Constructor === undefined) {
26839 return nativeSlice.call(O, k, fin);
26840 }
26841 }
26842
26843 result = new (Constructor === undefined ? Array : Constructor)(max$4(fin - k, 0));
26844
26845 for (n = 0; k < fin; k++, n++) if (k in O) createProperty(result, n, O[k]);
26846
26847 result.length = n;
26848 return result;
26849 }
26850 });
26851
26852 var SPECIES$6 = wellKnownSymbol('species');
26853
26854 var setSpecies = function (CONSTRUCTOR_NAME) {
26855 var Constructor = getBuiltIn(CONSTRUCTOR_NAME);
26856 var defineProperty = objectDefineProperty.f;
26857
26858 if (descriptors && Constructor && !Constructor[SPECIES$6]) {
26859 defineProperty(Constructor, SPECIES$6, {
26860 configurable: true,
26861 get: function () {
26862 return this;
26863 }
26864 });
26865 }
26866 };
26867
26868 var defineProperty$7 = objectDefineProperty.f;
26869 var getOwnPropertyNames$2 = objectGetOwnPropertyNames.f;
26870 var MATCH$3 = wellKnownSymbol('match');
26871 var NativeRegExp = global_1.RegExp;
26872 var RegExpPrototype = NativeRegExp.prototype;
26873 var re1 = /a/g;
26874 var re2 = /a/g; // "new" should create a new object, old webkit bug
26875
26876 var CORRECT_NEW = new NativeRegExp(re1) !== re1;
26877 var FORCED$2 = descriptors && isForced_1('RegExp', !CORRECT_NEW || fails(function () {
26878 re2[MATCH$3] = false; // RegExp constructor can alter flags and IsRegExp works correct with @@match
26879
26880 return NativeRegExp(re1) != re1 || NativeRegExp(re2) == re2 || NativeRegExp(re1, 'i') != '/a/i';
26881 })); // `RegExp` constructor
26882 // https://tc39.github.io/ecma262/#sec-regexp-constructor
26883
26884 if (FORCED$2) {
26885 var RegExpWrapper = function RegExp(pattern, flags) {
26886 var thisIsRegExp = this instanceof RegExpWrapper;
26887 var patternIsRegExp = isRegexp(pattern);
26888 var flagsAreUndefined = flags === undefined;
26889 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);
26890 };
26891
26892 var proxy = function (key) {
26893 key in RegExpWrapper || defineProperty$7(RegExpWrapper, key, {
26894 configurable: true,
26895 get: function () {
26896 return NativeRegExp[key];
26897 },
26898 set: function (it) {
26899 NativeRegExp[key] = it;
26900 }
26901 });
26902 };
26903
26904 var keys$4 = getOwnPropertyNames$2(NativeRegExp);
26905 var index$2 = 0;
26906
26907 while (keys$4.length > index$2) proxy(keys$4[index$2++]);
26908
26909 RegExpPrototype.constructor = RegExpWrapper;
26910 RegExpWrapper.prototype = RegExpPrototype;
26911 redefine(global_1, 'RegExp', RegExpWrapper);
26912 } // https://tc39.github.io/ecma262/#sec-get-regexp-@@species
26913
26914
26915 setSpecies('RegExp');
26916
26917 var TO_STRING$1 = 'toString';
26918 var RegExpPrototype$1 = RegExp.prototype;
26919 var nativeToString = RegExpPrototype$1[TO_STRING$1];
26920 var NOT_GENERIC = fails(function () {
26921 return nativeToString.call({
26922 source: 'a',
26923 flags: 'b'
26924 }) != '/a/b';
26925 }); // FF44- RegExp#toString has a wrong name
26926
26927 var INCORRECT_NAME = nativeToString.name != TO_STRING$1; // `RegExp.prototype.toString` method
26928 // https://tc39.github.io/ecma262/#sec-regexp.prototype.tostring
26929
26930 if (NOT_GENERIC || INCORRECT_NAME) {
26931 redefine(RegExp.prototype, TO_STRING$1, function toString() {
26932 var R = anObject(this);
26933 var p = String(R.source);
26934 var rf = R.flags;
26935 var f = String(rf === undefined && R instanceof RegExp && !('flags' in RegExpPrototype$1) ? regexpFlags.call(R) : rf);
26936 return '/' + p + '/' + f;
26937 }, {
26938 unsafe: true
26939 });
26940 }
26941
26942 fixRegexpWellKnownSymbolLogic('match', 1, function (MATCH, nativeMatch, maybeCallNative) {
26943 return [// `String.prototype.match` method
26944 // https://tc39.github.io/ecma262/#sec-string.prototype.match
26945 function match(regexp) {
26946 var O = requireObjectCoercible(this);
26947 var matcher = regexp == undefined ? undefined : regexp[MATCH];
26948 return matcher !== undefined ? matcher.call(regexp, O) : new RegExp(regexp)[MATCH](String(O));
26949 }, // `RegExp.prototype[@@match]` method
26950 // https://tc39.github.io/ecma262/#sec-regexp.prototype-@@match
26951 function (regexp) {
26952 var res = maybeCallNative(nativeMatch, regexp, this);
26953 if (res.done) return res.value;
26954 var rx = anObject(regexp);
26955 var S = String(this);
26956 if (!rx.global) return regexpExecAbstract(rx, S);
26957 var fullUnicode = rx.unicode;
26958 rx.lastIndex = 0;
26959 var A = [];
26960 var n = 0;
26961 var result;
26962
26963 while ((result = regexpExecAbstract(rx, S)) !== null) {
26964 var matchStr = String(result[0]);
26965 A[n] = matchStr;
26966 if (matchStr === '') rx.lastIndex = advanceStringIndex(S, toLength(rx.lastIndex), fullUnicode);
26967 n++;
26968 }
26969
26970 return n === 0 ? null : A;
26971 }];
26972 });
26973
26974 // https://tc39.github.io/ecma262/#sec-string.prototype.bold
26975
26976
26977 _export({
26978 target: 'String',
26979 proto: true,
26980 forced: forcedStringHtmlMethod('bold')
26981 }, {
26982 bold: function bold() {
26983 return createHtml(this, 'b', '', '');
26984 }
26985 });
26986
26987 var iterators = {};
26988
26989 var ITERATOR$2 = wellKnownSymbol('iterator');
26990 var BUGGY_SAFARI_ITERATORS = false;
26991
26992 var returnThis$1 = function () {
26993 return this;
26994 }; // `%IteratorPrototype%` object
26995 // https://tc39.github.io/ecma262/#sec-%iteratorprototype%-object
26996
26997
26998 var IteratorPrototype$1, PrototypeOfArrayIteratorPrototype, arrayIterator;
26999
27000 if ([].keys) {
27001 arrayIterator = [].keys(); // Safari 8 has buggy iterators w/o `next`
27002
27003 if (!('next' in arrayIterator)) BUGGY_SAFARI_ITERATORS = true;else {
27004 PrototypeOfArrayIteratorPrototype = objectGetPrototypeOf(objectGetPrototypeOf(arrayIterator));
27005 if (PrototypeOfArrayIteratorPrototype !== Object.prototype) IteratorPrototype$1 = PrototypeOfArrayIteratorPrototype;
27006 }
27007 }
27008
27009 if (IteratorPrototype$1 == undefined) IteratorPrototype$1 = {}; // 25.1.2.1.1 %IteratorPrototype%[@@iterator]()
27010
27011 if ( !has(IteratorPrototype$1, ITERATOR$2)) {
27012 createNonEnumerableProperty(IteratorPrototype$1, ITERATOR$2, returnThis$1);
27013 }
27014
27015 var iteratorsCore = {
27016 IteratorPrototype: IteratorPrototype$1,
27017 BUGGY_SAFARI_ITERATORS: BUGGY_SAFARI_ITERATORS
27018 };
27019
27020 var IteratorPrototype$2 = iteratorsCore.IteratorPrototype;
27021
27022 var returnThis$2 = function () {
27023 return this;
27024 };
27025
27026 var createIteratorConstructor = function (IteratorConstructor, NAME, next) {
27027 var TO_STRING_TAG = NAME + ' Iterator';
27028 IteratorConstructor.prototype = objectCreate(IteratorPrototype$2, {
27029 next: createPropertyDescriptor(1, next)
27030 });
27031 setToStringTag(IteratorConstructor, TO_STRING_TAG, false);
27032 iterators[TO_STRING_TAG] = returnThis$2;
27033 return IteratorConstructor;
27034 };
27035
27036 var IteratorPrototype$3 = iteratorsCore.IteratorPrototype;
27037 var BUGGY_SAFARI_ITERATORS$1 = iteratorsCore.BUGGY_SAFARI_ITERATORS;
27038 var ITERATOR$3 = wellKnownSymbol('iterator');
27039 var KEYS$1 = 'keys';
27040 var VALUES$1 = 'values';
27041 var ENTRIES = 'entries';
27042
27043 var returnThis$3 = function () {
27044 return this;
27045 };
27046
27047 var defineIterator = function (Iterable, NAME, IteratorConstructor, next, DEFAULT, IS_SET, FORCED) {
27048 createIteratorConstructor(IteratorConstructor, NAME, next);
27049
27050 var getIterationMethod = function (KIND) {
27051 if (KIND === DEFAULT && defaultIterator) return defaultIterator;
27052 if (!BUGGY_SAFARI_ITERATORS$1 && KIND in IterablePrototype) return IterablePrototype[KIND];
27053
27054 switch (KIND) {
27055 case KEYS$1:
27056 return function keys() {
27057 return new IteratorConstructor(this, KIND);
27058 };
27059
27060 case VALUES$1:
27061 return function values() {
27062 return new IteratorConstructor(this, KIND);
27063 };
27064
27065 case ENTRIES:
27066 return function entries() {
27067 return new IteratorConstructor(this, KIND);
27068 };
27069 }
27070
27071 return function () {
27072 return new IteratorConstructor(this);
27073 };
27074 };
27075
27076 var TO_STRING_TAG = NAME + ' Iterator';
27077 var INCORRECT_VALUES_NAME = false;
27078 var IterablePrototype = Iterable.prototype;
27079 var nativeIterator = IterablePrototype[ITERATOR$3] || IterablePrototype['@@iterator'] || DEFAULT && IterablePrototype[DEFAULT];
27080 var defaultIterator = !BUGGY_SAFARI_ITERATORS$1 && nativeIterator || getIterationMethod(DEFAULT);
27081 var anyNativeIterator = NAME == 'Array' ? IterablePrototype.entries || nativeIterator : nativeIterator;
27082 var CurrentIteratorPrototype, methods, KEY; // fix native
27083
27084 if (anyNativeIterator) {
27085 CurrentIteratorPrototype = objectGetPrototypeOf(anyNativeIterator.call(new Iterable()));
27086
27087 if (IteratorPrototype$3 !== Object.prototype && CurrentIteratorPrototype.next) {
27088 if ( objectGetPrototypeOf(CurrentIteratorPrototype) !== IteratorPrototype$3) {
27089 if (objectSetPrototypeOf) {
27090 objectSetPrototypeOf(CurrentIteratorPrototype, IteratorPrototype$3);
27091 } else if (typeof CurrentIteratorPrototype[ITERATOR$3] != 'function') {
27092 createNonEnumerableProperty(CurrentIteratorPrototype, ITERATOR$3, returnThis$3);
27093 }
27094 } // Set @@toStringTag to native iterators
27095
27096
27097 setToStringTag(CurrentIteratorPrototype, TO_STRING_TAG, true);
27098 }
27099 } // fix Array#{values, @@iterator}.name in V8 / FF
27100
27101
27102 if (DEFAULT == VALUES$1 && nativeIterator && nativeIterator.name !== VALUES$1) {
27103 INCORRECT_VALUES_NAME = true;
27104
27105 defaultIterator = function values() {
27106 return nativeIterator.call(this);
27107 };
27108 } // define iterator
27109
27110
27111 if ( IterablePrototype[ITERATOR$3] !== defaultIterator) {
27112 createNonEnumerableProperty(IterablePrototype, ITERATOR$3, defaultIterator);
27113 }
27114
27115 iterators[NAME] = defaultIterator; // export additional methods
27116
27117 if (DEFAULT) {
27118 methods = {
27119 values: getIterationMethod(VALUES$1),
27120 keys: IS_SET ? defaultIterator : getIterationMethod(KEYS$1),
27121 entries: getIterationMethod(ENTRIES)
27122 };
27123 if (FORCED) for (KEY in methods) {
27124 if (BUGGY_SAFARI_ITERATORS$1 || INCORRECT_VALUES_NAME || !(KEY in IterablePrototype)) {
27125 redefine(IterablePrototype, KEY, methods[KEY]);
27126 }
27127 } else _export({
27128 target: NAME,
27129 proto: true,
27130 forced: BUGGY_SAFARI_ITERATORS$1 || INCORRECT_VALUES_NAME
27131 }, methods);
27132 }
27133
27134 return methods;
27135 };
27136
27137 var ARRAY_ITERATOR = 'Array Iterator';
27138 var setInternalState$1 = internalState.set;
27139 var getInternalState$1 = internalState.getterFor(ARRAY_ITERATOR); // `Array.prototype.entries` method
27140 // https://tc39.github.io/ecma262/#sec-array.prototype.entries
27141 // `Array.prototype.keys` method
27142 // https://tc39.github.io/ecma262/#sec-array.prototype.keys
27143 // `Array.prototype.values` method
27144 // https://tc39.github.io/ecma262/#sec-array.prototype.values
27145 // `Array.prototype[@@iterator]` method
27146 // https://tc39.github.io/ecma262/#sec-array.prototype-@@iterator
27147 // `CreateArrayIterator` internal method
27148 // https://tc39.github.io/ecma262/#sec-createarrayiterator
27149
27150 var es_array_iterator = defineIterator(Array, 'Array', function (iterated, kind) {
27151 setInternalState$1(this, {
27152 type: ARRAY_ITERATOR,
27153 target: toIndexedObject(iterated),
27154 // target
27155 index: 0,
27156 // next index
27157 kind: kind // kind
27158
27159 }); // `%ArrayIteratorPrototype%.next` method
27160 // https://tc39.github.io/ecma262/#sec-%arrayiteratorprototype%.next
27161 }, function () {
27162 var state = getInternalState$1(this);
27163 var target = state.target;
27164 var kind = state.kind;
27165 var index = state.index++;
27166
27167 if (!target || index >= target.length) {
27168 state.target = undefined;
27169 return {
27170 value: undefined,
27171 done: true
27172 };
27173 }
27174
27175 if (kind == 'keys') return {
27176 value: index,
27177 done: false
27178 };
27179 if (kind == 'values') return {
27180 value: target[index],
27181 done: false
27182 };
27183 return {
27184 value: [index, target[index]],
27185 done: false
27186 };
27187 }, 'values'); // argumentsList[@@iterator] is %ArrayProto_values%
27188 // https://tc39.github.io/ecma262/#sec-createunmappedargumentsobject
27189 // https://tc39.github.io/ecma262/#sec-createmappedargumentsobject
27190
27191 iterators.Arguments = iterators.Array; // https://tc39.github.io/ecma262/#sec-array.prototype-@@unscopables
27192
27193 addToUnscopables('keys');
27194 addToUnscopables('values');
27195 addToUnscopables('entries');
27196
27197 var nativeAssign = Object.assign; // `Object.assign` method
27198 // https://tc39.github.io/ecma262/#sec-object.assign
27199 // should work with symbols and should have deterministic property order (V8 bug)
27200
27201 var objectAssign = !nativeAssign || fails(function () {
27202 var A = {};
27203 var B = {}; // eslint-disable-next-line no-undef
27204
27205 var symbol = Symbol();
27206 var alphabet = 'abcdefghijklmnopqrst';
27207 A[symbol] = 7;
27208 alphabet.split('').forEach(function (chr) {
27209 B[chr] = chr;
27210 });
27211 return nativeAssign({}, A)[symbol] != 7 || objectKeys(nativeAssign({}, B)).join('') != alphabet;
27212 }) ? function assign(target, source) {
27213 // eslint-disable-line no-unused-vars
27214 var T = toObject(target);
27215 var argumentsLength = arguments.length;
27216 var index = 1;
27217 var getOwnPropertySymbols = objectGetOwnPropertySymbols.f;
27218 var propertyIsEnumerable = objectPropertyIsEnumerable.f;
27219
27220 while (argumentsLength > index) {
27221 var S = indexedObject(arguments[index++]);
27222 var keys = getOwnPropertySymbols ? objectKeys(S).concat(getOwnPropertySymbols(S)) : objectKeys(S);
27223 var length = keys.length;
27224 var j = 0;
27225 var key;
27226
27227 while (length > j) {
27228 key = keys[j++];
27229 if (!descriptors || propertyIsEnumerable.call(S, key)) T[key] = S[key];
27230 }
27231 }
27232
27233 return T;
27234 } : nativeAssign;
27235
27236 // https://tc39.github.io/ecma262/#sec-object.assign
27237
27238 _export({
27239 target: 'Object',
27240 stat: true,
27241 forced: Object.assign !== objectAssign
27242 }, {
27243 assign: objectAssign
27244 });
27245
27246 var ITERATOR$4 = wellKnownSymbol('iterator');
27247 var TO_STRING_TAG$5 = wellKnownSymbol('toStringTag');
27248 var ArrayValues$1 = es_array_iterator.values;
27249
27250 for (var COLLECTION_NAME$1 in domIterables) {
27251 var Collection$2 = global_1[COLLECTION_NAME$1];
27252 var CollectionPrototype$1 = Collection$2 && Collection$2.prototype;
27253
27254 if (CollectionPrototype$1) {
27255 // some Chrome versions have non-configurable methods on DOMTokenList
27256 if (CollectionPrototype$1[ITERATOR$4] !== ArrayValues$1) try {
27257 createNonEnumerableProperty(CollectionPrototype$1, ITERATOR$4, ArrayValues$1);
27258 } catch (error) {
27259 CollectionPrototype$1[ITERATOR$4] = ArrayValues$1;
27260 }
27261
27262 if (!CollectionPrototype$1[TO_STRING_TAG$5]) {
27263 createNonEnumerableProperty(CollectionPrototype$1, TO_STRING_TAG$5, COLLECTION_NAME$1);
27264 }
27265
27266 if (domIterables[COLLECTION_NAME$1]) for (var METHOD_NAME in es_array_iterator) {
27267 // some Chrome versions have non-configurable methods on DOMTokenList
27268 if (CollectionPrototype$1[METHOD_NAME] !== es_array_iterator[METHOD_NAME]) try {
27269 createNonEnumerableProperty(CollectionPrototype$1, METHOD_NAME, es_array_iterator[METHOD_NAME]);
27270 } catch (error) {
27271 CollectionPrototype$1[METHOD_NAME] = es_array_iterator[METHOD_NAME];
27272 }
27273 }
27274 }
27275 }
27276
27277 /**
27278 * Callback to determine text dimensions, using the parent label settings.
27279 * @callback MeasureText
27280 * @param {text} text
27281 * @param {text} mod
27282 * @return {Object} { width, values} width in pixels and font attributes
27283 */
27284
27285 /**
27286 * Helper class for Label which collects results of splitting labels into lines and blocks.
27287 *
27288 * @private
27289 */
27290 var LabelAccumulator =
27291 /*#__PURE__*/
27292 function () {
27293 /**
27294 * @param {MeasureText} measureText
27295 */
27296 function LabelAccumulator(measureText) {
27297 _classCallCheck(this, LabelAccumulator);
27298
27299 this.measureText = measureText;
27300 this.current = 0;
27301 this.width = 0;
27302 this.height = 0;
27303 this.lines = [];
27304 }
27305 /**
27306 * Append given text to the given line.
27307 *
27308 * @param {number} l index of line to add to
27309 * @param {string} text string to append to line
27310 * @param {'bold'|'ital'|'boldital'|'mono'|'normal'} [mod='normal']
27311 * @private
27312 */
27313
27314
27315 _createClass(LabelAccumulator, [{
27316 key: "_add",
27317 value: function _add(l, text) {
27318 var mod = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'normal';
27319
27320 if (this.lines[l] === undefined) {
27321 this.lines[l] = {
27322 width: 0,
27323 height: 0,
27324 blocks: []
27325 };
27326 } // We still need to set a block for undefined and empty texts, hence return at this point
27327 // This is necessary because we don't know at this point if we're at the
27328 // start of an empty line or not.
27329 // To compensate, empty blocks are removed in `finalize()`.
27330 //
27331 // Empty strings should still have a height
27332
27333
27334 var tmpText = text;
27335 if (text === undefined || text === "") tmpText = " "; // Determine width and get the font properties
27336
27337 var result = this.measureText(tmpText, mod);
27338 var block = Object.assign({}, result.values);
27339 block.text = text;
27340 block.width = result.width;
27341 block.mod = mod;
27342
27343 if (text === undefined || text === "") {
27344 block.width = 0;
27345 }
27346
27347 this.lines[l].blocks.push(block); // Update the line width. We need this for determining if a string goes over max width
27348
27349 this.lines[l].width += block.width;
27350 }
27351 /**
27352 * Returns the width in pixels of the current line.
27353 *
27354 * @returns {number}
27355 */
27356
27357 }, {
27358 key: "curWidth",
27359 value: function curWidth() {
27360 var line = this.lines[this.current];
27361 if (line === undefined) return 0;
27362 return line.width;
27363 }
27364 /**
27365 * Add text in block to current line
27366 *
27367 * @param {string} text
27368 * @param {'bold'|'ital'|'boldital'|'mono'|'normal'} [mod='normal']
27369 */
27370
27371 }, {
27372 key: "append",
27373 value: function append(text) {
27374 var mod = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'normal';
27375
27376 this._add(this.current, text, mod);
27377 }
27378 /**
27379 * Add text in block to current line and start a new line
27380 *
27381 * @param {string} text
27382 * @param {'bold'|'ital'|'boldital'|'mono'|'normal'} [mod='normal']
27383 */
27384
27385 }, {
27386 key: "newLine",
27387 value: function newLine(text) {
27388 var mod = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'normal';
27389
27390 this._add(this.current, text, mod);
27391
27392 this.current++;
27393 }
27394 /**
27395 * Determine and set the heights of all the lines currently contained in this instance
27396 *
27397 * Note that width has already been set.
27398 *
27399 * @private
27400 */
27401
27402 }, {
27403 key: "determineLineHeights",
27404 value: function determineLineHeights() {
27405 for (var k = 0; k < this.lines.length; k++) {
27406 var line = this.lines[k]; // Looking for max height of blocks in line
27407
27408 var height = 0;
27409
27410 if (line.blocks !== undefined) {
27411 // Can happen if text contains e.g. '\n '
27412 for (var l = 0; l < line.blocks.length; l++) {
27413 var block = line.blocks[l];
27414
27415 if (height < block.height) {
27416 height = block.height;
27417 }
27418 }
27419 }
27420
27421 line.height = height;
27422 }
27423 }
27424 /**
27425 * Determine the full size of the label text, as determined by current lines and blocks
27426 *
27427 * @private
27428 */
27429
27430 }, {
27431 key: "determineLabelSize",
27432 value: function determineLabelSize() {
27433 var width = 0;
27434 var height = 0;
27435
27436 for (var k = 0; k < this.lines.length; k++) {
27437 var line = this.lines[k];
27438
27439 if (line.width > width) {
27440 width = line.width;
27441 }
27442
27443 height += line.height;
27444 }
27445
27446 this.width = width;
27447 this.height = height;
27448 }
27449 /**
27450 * Remove all empty blocks and empty lines we don't need
27451 *
27452 * This must be done after the width/height determination,
27453 * so that these are set properly for processing here.
27454 *
27455 * @returns {Array<Line>} Lines with empty blocks (and some empty lines) removed
27456 * @private
27457 */
27458
27459 }, {
27460 key: "removeEmptyBlocks",
27461 value: function removeEmptyBlocks() {
27462 var tmpLines = [];
27463
27464 for (var k = 0; k < this.lines.length; k++) {
27465 var line = this.lines[k]; // Note: an empty line in between text has width zero but is still relevant to layout.
27466 // So we can't use width for testing empty line here
27467
27468 if (line.blocks.length === 0) continue; // Discard final empty line always
27469
27470 if (k === this.lines.length - 1) {
27471 if (line.width === 0) continue;
27472 }
27473
27474 var tmpLine = {};
27475 Object.assign(tmpLine, line);
27476 tmpLine.blocks = [];
27477 var firstEmptyBlock = void 0;
27478 var tmpBlocks = [];
27479
27480 for (var l = 0; l < line.blocks.length; l++) {
27481 var block = line.blocks[l];
27482
27483 if (block.width !== 0) {
27484 tmpBlocks.push(block);
27485 } else {
27486 if (firstEmptyBlock === undefined) {
27487 firstEmptyBlock = block;
27488 }
27489 }
27490 } // Ensure that there is *some* text present
27491
27492
27493 if (tmpBlocks.length === 0 && firstEmptyBlock !== undefined) {
27494 tmpBlocks.push(firstEmptyBlock);
27495 }
27496
27497 tmpLine.blocks = tmpBlocks;
27498 tmpLines.push(tmpLine);
27499 }
27500
27501 return tmpLines;
27502 }
27503 /**
27504 * Set the sizes for all lines and the whole thing.
27505 *
27506 * @returns {{width: (number|*), height: (number|*), lines: Array}}
27507 */
27508
27509 }, {
27510 key: "finalize",
27511 value: function finalize() {
27512 //console.log(JSON.stringify(this.lines, null, 2));
27513 this.determineLineHeights();
27514 this.determineLabelSize();
27515 var tmpLines = this.removeEmptyBlocks(); // Return a simple hash object for further processing.
27516
27517 return {
27518 width: this.width,
27519 height: this.height,
27520 lines: tmpLines
27521 };
27522 }
27523 }]);
27524
27525 return LabelAccumulator;
27526 }();
27527
27528 var tagPattern = {
27529 // HTML
27530 '<b>': /<b>/,
27531 '<i>': /<i>/,
27532 '<code>': /<code>/,
27533 '</b>': /<\/b>/,
27534 '</i>': /<\/i>/,
27535 '</code>': /<\/code>/,
27536 // Markdown
27537 '*': /\*/,
27538 // bold
27539 '_': /\_/,
27540 // ital
27541 '`': /`/,
27542 // mono
27543 'afterBold': /[^\*]/,
27544 'afterItal': /[^_]/,
27545 'afterMono': /[^`]/
27546 };
27547 /**
27548 * Internal helper class for parsing the markup tags for HTML and Markdown.
27549 *
27550 * NOTE: Sequences of tabs and spaces are reduced to single space.
27551 * Scan usage of `this.spacing` within method
27552 */
27553
27554 var MarkupAccumulator =
27555 /*#__PURE__*/
27556 function () {
27557 /**
27558 * Create an instance
27559 *
27560 * @param {string} text text to parse for markup
27561 */
27562 function MarkupAccumulator(text) {
27563 _classCallCheck(this, MarkupAccumulator);
27564
27565 this.text = text;
27566 this.bold = false;
27567 this.ital = false;
27568 this.mono = false;
27569 this.spacing = false;
27570 this.position = 0;
27571 this.buffer = "";
27572 this.modStack = [];
27573 this.blocks = [];
27574 }
27575 /**
27576 * Return the mod label currently on the top of the stack
27577 *
27578 * @returns {string} label of topmost mod
27579 * @private
27580 */
27581
27582
27583 _createClass(MarkupAccumulator, [{
27584 key: "mod",
27585 value: function mod() {
27586 return this.modStack.length === 0 ? 'normal' : this.modStack[0];
27587 }
27588 /**
27589 * Return the mod label currently active
27590 *
27591 * @returns {string} label of active mod
27592 * @private
27593 */
27594
27595 }, {
27596 key: "modName",
27597 value: function modName() {
27598 if (this.modStack.length === 0) return 'normal';else if (this.modStack[0] === 'mono') return 'mono';else {
27599 if (this.bold && this.ital) {
27600 return 'boldital';
27601 } else if (this.bold) {
27602 return 'bold';
27603 } else if (this.ital) {
27604 return 'ital';
27605 }
27606 }
27607 }
27608 /**
27609 * @private
27610 */
27611
27612 }, {
27613 key: "emitBlock",
27614 value: function emitBlock() {
27615 if (this.spacing) {
27616 this.add(" ");
27617 this.spacing = false;
27618 }
27619
27620 if (this.buffer.length > 0) {
27621 this.blocks.push({
27622 text: this.buffer,
27623 mod: this.modName()
27624 });
27625 this.buffer = "";
27626 }
27627 }
27628 /**
27629 * Output text to buffer
27630 *
27631 * @param {string} text text to add
27632 * @private
27633 */
27634
27635 }, {
27636 key: "add",
27637 value: function add(text) {
27638 if (text === " ") {
27639 this.spacing = true;
27640 }
27641
27642 if (this.spacing) {
27643 this.buffer += " ";
27644 this.spacing = false;
27645 }
27646
27647 if (text != " ") {
27648 this.buffer += text;
27649 }
27650 }
27651 /**
27652 * Handle parsing of whitespace
27653 *
27654 * @param {string} ch the character to check
27655 * @returns {boolean} true if the character was processed as whitespace, false otherwise
27656 */
27657
27658 }, {
27659 key: "parseWS",
27660 value: function parseWS(ch) {
27661 if (/[ \t]/.test(ch)) {
27662 if (!this.mono) {
27663 this.spacing = true;
27664 } else {
27665 this.add(ch);
27666 }
27667
27668 return true;
27669 }
27670
27671 return false;
27672 }
27673 /**
27674 * @param {string} tagName label for block type to set
27675 * @private
27676 */
27677
27678 }, {
27679 key: "setTag",
27680 value: function setTag(tagName) {
27681 this.emitBlock();
27682 this[tagName] = true;
27683 this.modStack.unshift(tagName);
27684 }
27685 /**
27686 * @param {string} tagName label for block type to unset
27687 * @private
27688 */
27689
27690 }, {
27691 key: "unsetTag",
27692 value: function unsetTag(tagName) {
27693 this.emitBlock();
27694 this[tagName] = false;
27695 this.modStack.shift();
27696 }
27697 /**
27698 * @param {string} tagName label for block type we are currently processing
27699 * @param {string|RegExp} tag string to match in text
27700 * @returns {boolean} true if the tag was processed, false otherwise
27701 */
27702
27703 }, {
27704 key: "parseStartTag",
27705 value: function parseStartTag(tagName, tag) {
27706 // Note: if 'mono' passed as tagName, there is a double check here. This is OK
27707 if (!this.mono && !this[tagName] && this.match(tag)) {
27708 this.setTag(tagName);
27709 return true;
27710 }
27711
27712 return false;
27713 }
27714 /**
27715 * @param {string|RegExp} tag
27716 * @param {number} [advance=true] if set, advance current position in text
27717 * @returns {boolean} true if match at given position, false otherwise
27718 * @private
27719 */
27720
27721 }, {
27722 key: "match",
27723 value: function match(tag) {
27724 var advance = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
27725
27726 var _this$prepareRegExp = this.prepareRegExp(tag),
27727 _this$prepareRegExp2 = _slicedToArray(_this$prepareRegExp, 2),
27728 regExp = _this$prepareRegExp2[0],
27729 length = _this$prepareRegExp2[1];
27730
27731 var matched = regExp.test(this.text.substr(this.position, length));
27732
27733 if (matched && advance) {
27734 this.position += length - 1;
27735 }
27736
27737 return matched;
27738 }
27739 /**
27740 * @param {string} tagName label for block type we are currently processing
27741 * @param {string|RegExp} tag string to match in text
27742 * @param {RegExp} [nextTag] regular expression to match for characters *following* the current tag
27743 * @returns {boolean} true if the tag was processed, false otherwise
27744 */
27745
27746 }, {
27747 key: "parseEndTag",
27748 value: function parseEndTag(tagName, tag, nextTag) {
27749 var checkTag = this.mod() === tagName;
27750
27751 if (tagName === 'mono') {
27752 // special handling for 'mono'
27753 checkTag = checkTag && this.mono;
27754 } else {
27755 checkTag = checkTag && !this.mono;
27756 }
27757
27758 if (checkTag && this.match(tag)) {
27759 if (nextTag !== undefined) {
27760 // Purpose of the following match is to prevent a direct unset/set of a given tag
27761 // E.g. '*bold **still bold*' => '*bold still bold*'
27762 if (this.position === this.text.length - 1 || this.match(nextTag, false)) {
27763 this.unsetTag(tagName);
27764 }
27765 } else {
27766 this.unsetTag(tagName);
27767 }
27768
27769 return true;
27770 }
27771
27772 return false;
27773 }
27774 /**
27775 * @param {string|RegExp} tag string to match in text
27776 * @param {value} value string to replace tag with, if found at current position
27777 * @returns {boolean} true if the tag was processed, false otherwise
27778 */
27779
27780 }, {
27781 key: "replace",
27782 value: function replace(tag, value) {
27783 if (this.match(tag)) {
27784 this.add(value);
27785 this.position += length - 1;
27786 return true;
27787 }
27788
27789 return false;
27790 }
27791 /**
27792 * Create a regular expression for the tag if it isn't already one.
27793 *
27794 * The return value is an array `[RegExp, number]`, with exactly two value, where:
27795 * - RegExp is the regular expression to use
27796 * - number is the lenth of the input string to match
27797 *
27798 * @param {string|RegExp} tag string to match in text
27799 * @returns {Array} regular expression to use and length of input string to match
27800 * @private
27801 */
27802
27803 }, {
27804 key: "prepareRegExp",
27805 value: function prepareRegExp(tag) {
27806 var length;
27807 var regExp;
27808
27809 if (tag instanceof RegExp) {
27810 regExp = tag;
27811 length = 1; // ASSUMPTION: regexp only tests one character
27812 } else {
27813 // use prepared regexp if present
27814 var prepared = tagPattern[tag];
27815
27816 if (prepared !== undefined) {
27817 regExp = prepared;
27818 } else {
27819 regExp = new RegExp(tag);
27820 }
27821
27822 length = tag.length;
27823 }
27824
27825 return [regExp, length];
27826 }
27827 }]);
27828
27829 return MarkupAccumulator;
27830 }();
27831 /**
27832 * Helper class for Label which explodes the label text into lines and blocks within lines
27833 *
27834 * @private
27835 */
27836
27837
27838 var LabelSplitter =
27839 /*#__PURE__*/
27840 function () {
27841 /**
27842 * @param {CanvasRenderingContext2D} ctx Canvas rendering context
27843 * @param {Label} parent reference to the Label instance using current instance
27844 * @param {boolean} selected
27845 * @param {boolean} hover
27846 */
27847 function LabelSplitter(ctx, parent, selected, hover) {
27848 var _this = this;
27849
27850 _classCallCheck(this, LabelSplitter);
27851
27852 this.ctx = ctx;
27853 this.parent = parent;
27854 this.selected = selected;
27855 this.hover = hover;
27856 /**
27857 * Callback to determine text width; passed to LabelAccumulator instance
27858 *
27859 * @param {String} text string to determine width of
27860 * @param {String} mod font type to use for this text
27861 * @return {Object} { width, values} width in pixels and font attributes
27862 */
27863
27864 var textWidth = function textWidth(text, mod) {
27865 if (text === undefined) return 0; // TODO: This can be done more efficiently with caching
27866 // This will set the ctx.font correctly, depending on selected/hover and mod - so that ctx.measureText() will be accurate.
27867
27868 var values = _this.parent.getFormattingValues(ctx, selected, hover, mod);
27869
27870 var width = 0;
27871
27872 if (text !== '') {
27873 var measure = _this.ctx.measureText(text);
27874
27875 width = measure.width;
27876 }
27877
27878 return {
27879 width: width,
27880 values: values
27881 };
27882 };
27883
27884 this.lines = new LabelAccumulator(textWidth);
27885 }
27886 /**
27887 * Split passed text of a label into lines and blocks.
27888 *
27889 * # NOTE
27890 *
27891 * The handling of spacing is option dependent:
27892 *
27893 * - if `font.multi : false`, all spaces are retained
27894 * - if `font.multi : true`, every sequence of spaces is compressed to a single space
27895 *
27896 * This might not be the best way to do it, but this is as it has been working till now.
27897 * In order not to break existing functionality, for the time being this behaviour will
27898 * be retained in any code changes.
27899 *
27900 * @param {string} text text to split
27901 * @returns {Array<line>}
27902 */
27903
27904
27905 _createClass(LabelSplitter, [{
27906 key: "process",
27907 value: function process(text) {
27908 if (!ComponentUtil.isValidLabel(text)) {
27909 return this.lines.finalize();
27910 }
27911
27912 var font = this.parent.fontOptions; // Normalize the end-of-line's to a single representation - order important
27913
27914 text = text.replace(/\r\n/g, '\n'); // Dos EOL's
27915
27916 text = text.replace(/\r/g, '\n'); // Mac EOL's
27917 // Note that at this point, there can be no \r's in the text.
27918 // This is used later on splitStringIntoLines() to split multifont texts.
27919
27920 var nlLines = String(text).split('\n');
27921 var lineCount = nlLines.length;
27922
27923 if (font.multi) {
27924 // Multi-font case: styling tags active
27925 for (var i = 0; i < lineCount; i++) {
27926 var blocks = this.splitBlocks(nlLines[i], font.multi); // Post: Sequences of tabs and spaces are reduced to single space
27927
27928 if (blocks === undefined) continue;
27929
27930 if (blocks.length === 0) {
27931 this.lines.newLine("");
27932 continue;
27933 }
27934
27935 if (font.maxWdt > 0) {
27936 // widthConstraint.maximum defined
27937 //console.log('Running widthConstraint multi, max: ' + this.fontOptions.maxWdt);
27938 for (var j = 0; j < blocks.length; j++) {
27939 var mod = blocks[j].mod;
27940 var _text = blocks[j].text;
27941 this.splitStringIntoLines(_text, mod, true);
27942 }
27943 } else {
27944 // widthConstraint.maximum NOT defined
27945 for (var _j = 0; _j < blocks.length; _j++) {
27946 var _mod = blocks[_j].mod;
27947 var _text2 = blocks[_j].text;
27948 this.lines.append(_text2, _mod);
27949 }
27950 }
27951
27952 this.lines.newLine();
27953 }
27954 } else {
27955 // Single-font case
27956 if (font.maxWdt > 0) {
27957 // widthConstraint.maximum defined
27958 // console.log('Running widthConstraint normal, max: ' + this.fontOptions.maxWdt);
27959 for (var _i = 0; _i < lineCount; _i++) {
27960 this.splitStringIntoLines(nlLines[_i]);
27961 }
27962 } else {
27963 // widthConstraint.maximum NOT defined
27964 for (var _i2 = 0; _i2 < lineCount; _i2++) {
27965 this.lines.newLine(nlLines[_i2]);
27966 }
27967 }
27968 }
27969
27970 return this.lines.finalize();
27971 }
27972 /**
27973 * normalize the markup system
27974 *
27975 * @param {boolean|'md'|'markdown'|'html'} markupSystem
27976 * @returns {string}
27977 */
27978
27979 }, {
27980 key: "decodeMarkupSystem",
27981 value: function decodeMarkupSystem(markupSystem) {
27982 var system = 'none';
27983
27984 if (markupSystem === 'markdown' || markupSystem === 'md') {
27985 system = 'markdown';
27986 } else if (markupSystem === true || markupSystem === 'html') {
27987 system = 'html';
27988 }
27989
27990 return system;
27991 }
27992 /**
27993 *
27994 * @param {string} text
27995 * @returns {Array}
27996 */
27997
27998 }, {
27999 key: "splitHtmlBlocks",
28000 value: function splitHtmlBlocks(text) {
28001 var s = new MarkupAccumulator(text);
28002
28003 var parseEntities = function parseEntities(ch) {
28004 if (/&/.test(ch)) {
28005 var parsed = s.replace(s.text, '&lt;', '<') || s.replace(s.text, '&amp;', '&');
28006
28007 if (!parsed) {
28008 s.add("&");
28009 }
28010
28011 return true;
28012 }
28013
28014 return false;
28015 };
28016
28017 while (s.position < s.text.length) {
28018 var ch = s.text.charAt(s.position);
28019 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);
28020
28021 if (!parsed) {
28022 s.add(ch);
28023 }
28024
28025 s.position++;
28026 }
28027
28028 s.emitBlock();
28029 return s.blocks;
28030 }
28031 /**
28032 *
28033 * @param {string} text
28034 * @returns {Array}
28035 */
28036
28037 }, {
28038 key: "splitMarkdownBlocks",
28039 value: function splitMarkdownBlocks(text) {
28040 var _this2 = this;
28041
28042 var s = new MarkupAccumulator(text);
28043 var beginable = true;
28044
28045 var parseOverride = function parseOverride(ch) {
28046 if (/\\/.test(ch)) {
28047 if (s.position < _this2.text.length + 1) {
28048 s.position++;
28049 ch = _this2.text.charAt(s.position);
28050
28051 if (/ \t/.test(ch)) {
28052 s.spacing = true;
28053 } else {
28054 s.add(ch);
28055 beginable = false;
28056 }
28057 }
28058
28059 return true;
28060 }
28061
28062 return false;
28063 };
28064
28065 while (s.position < s.text.length) {
28066 var ch = s.text.charAt(s.position);
28067 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');
28068
28069 if (!parsed) {
28070 s.add(ch);
28071 beginable = false;
28072 }
28073
28074 s.position++;
28075 }
28076
28077 s.emitBlock();
28078 return s.blocks;
28079 }
28080 /**
28081 * Explodes a piece of text into single-font blocks using a given markup
28082 *
28083 * @param {string} text
28084 * @param {boolean|'md'|'markdown'|'html'} markupSystem
28085 * @returns {Array.<{text: string, mod: string}>}
28086 * @private
28087 */
28088
28089 }, {
28090 key: "splitBlocks",
28091 value: function splitBlocks(text, markupSystem) {
28092 var system = this.decodeMarkupSystem(markupSystem);
28093
28094 if (system === 'none') {
28095 return [{
28096 text: text,
28097 mod: 'normal'
28098 }];
28099 } else if (system === 'markdown') {
28100 return this.splitMarkdownBlocks(text);
28101 } else if (system === 'html') {
28102 return this.splitHtmlBlocks(text);
28103 }
28104 }
28105 /**
28106 * @param {string} text
28107 * @returns {boolean} true if text length over the current max with
28108 * @private
28109 */
28110
28111 }, {
28112 key: "overMaxWidth",
28113 value: function overMaxWidth(text) {
28114 var width = this.ctx.measureText(text).width;
28115 return this.lines.curWidth() + width > this.parent.fontOptions.maxWdt;
28116 }
28117 /**
28118 * Determine the longest part of the sentence which still fits in the
28119 * current max width.
28120 *
28121 * @param {Array} words Array of strings signifying a text lines
28122 * @return {number} index of first item in string making string go over max
28123 * @private
28124 */
28125
28126 }, {
28127 key: "getLongestFit",
28128 value: function getLongestFit(words) {
28129 var text = '';
28130 var w = 0;
28131
28132 while (w < words.length) {
28133 var pre = text === '' ? '' : ' ';
28134 var newText = text + pre + words[w];
28135 if (this.overMaxWidth(newText)) break;
28136 text = newText;
28137 w++;
28138 }
28139
28140 return w;
28141 }
28142 /**
28143 * Determine the longest part of the string which still fits in the
28144 * current max width.
28145 *
28146 * @param {Array} words Array of strings signifying a text lines
28147 * @return {number} index of first item in string making string go over max
28148 */
28149
28150 }, {
28151 key: "getLongestFitWord",
28152 value: function getLongestFitWord(words) {
28153 var w = 0;
28154
28155 while (w < words.length) {
28156 if (this.overMaxWidth(words.slice(0, w))) break;
28157 w++;
28158 }
28159
28160 return w;
28161 }
28162 /**
28163 * Split the passed text into lines, according to width constraint (if any).
28164 *
28165 * The method assumes that the input string is a single line, i.e. without lines break.
28166 *
28167 * This method retains spaces, if still present (case `font.multi: false`).
28168 * A space which falls on an internal line break, will be replaced by a newline.
28169 * There is no special handling of tabs; these go along with the flow.
28170 *
28171 * @param {string} str
28172 * @param {string} [mod='normal']
28173 * @param {boolean} [appendLast=false]
28174 * @private
28175 */
28176
28177 }, {
28178 key: "splitStringIntoLines",
28179 value: function splitStringIntoLines(str) {
28180 var mod = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'normal';
28181 var appendLast = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
28182 // Set the canvas context font, based upon the current selected/hover state
28183 // and the provided mod, so the text measurement performed by getLongestFit
28184 // will be accurate - and not just use the font of whoever last used the canvas.
28185 this.parent.getFormattingValues(this.ctx, this.selected, this.hover, mod); // Still-present spaces are relevant, retain them
28186
28187 str = str.replace(/^( +)/g, '$1\r');
28188 str = str.replace(/([^\r][^ ]*)( +)/g, '$1\r$2\r');
28189 var words = str.split('\r');
28190
28191 while (words.length > 0) {
28192 var w = this.getLongestFit(words);
28193
28194 if (w === 0) {
28195 // Special case: the first word is already larger than the max width.
28196 var word = words[0]; // Break the word to the largest part that fits the line
28197
28198 var x = this.getLongestFitWord(word);
28199 this.lines.newLine(word.slice(0, x), mod); // Adjust the word, so that the rest will be done next iteration
28200
28201 words[0] = word.slice(x);
28202 } else {
28203 // skip any space that is replaced by a newline
28204 var newW = w;
28205
28206 if (words[w - 1] === ' ') {
28207 w--;
28208 } else if (words[newW] === ' ') {
28209 newW++;
28210 }
28211
28212 var text = words.slice(0, w).join("");
28213
28214 if (w == words.length && appendLast) {
28215 this.lines.append(text, mod);
28216 } else {
28217 this.lines.newLine(text, mod);
28218 } // Adjust the word, so that the rest will be done next iteration
28219
28220
28221 words = words.slice(newW);
28222 }
28223 }
28224 }
28225 }]);
28226
28227 return LabelSplitter;
28228 }();
28229
28230 /**
28231 * List of special styles for multi-fonts
28232 * @private
28233 */
28234
28235 var multiFontStyle = ['bold', 'ital', 'boldital', 'mono'];
28236 /**
28237 * A Label to be used for Nodes or Edges.
28238 */
28239
28240 var Label =
28241 /*#__PURE__*/
28242 function () {
28243 /**
28244 * @param {Object} body
28245 * @param {Object} options
28246 * @param {boolean} [edgelabel=false]
28247 */
28248 function Label(body, options) {
28249 var edgelabel = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
28250
28251 _classCallCheck(this, Label);
28252
28253 this.body = body;
28254 this.pointToSelf = false;
28255 this.baseSize = undefined;
28256 this.fontOptions = {}; // instance variable containing the *instance-local* font options
28257
28258 this.setOptions(options);
28259 this.size = {
28260 top: 0,
28261 left: 0,
28262 width: 0,
28263 height: 0,
28264 yLine: 0
28265 };
28266 this.isEdgeLabel = edgelabel;
28267 }
28268 /**
28269 * @param {Object} options the options of the parent Node-instance
28270 */
28271
28272
28273 _createClass(Label, [{
28274 key: "setOptions",
28275 value: function setOptions(options) {
28276 this.elementOptions = options; // Reference to the options of the parent Node-instance
28277
28278 this.initFontOptions(options.font);
28279
28280 if (ComponentUtil.isValidLabel(options.label)) {
28281 this.labelDirty = true;
28282 } else {
28283 // Bad label! Change the option value to prevent bad stuff happening
28284 options.label = undefined;
28285 }
28286
28287 if (options.font !== undefined && options.font !== null) {
28288 // font options can be deleted at various levels
28289 if (typeof options.font === 'string') {
28290 this.baseSize = this.fontOptions.size;
28291 } else if (_typeof$1(options.font) === 'object') {
28292 var size = options.font.size;
28293
28294 if (size !== undefined) {
28295 this.baseSize = size;
28296 }
28297 }
28298 }
28299 }
28300 /**
28301 * Init the font Options structure.
28302 *
28303 * Member fontOptions serves as an accumulator for the current font options.
28304 * As such, it needs to be completely separated from the node options.
28305 *
28306 * @param {Object} newFontOptions the new font options to process
28307 * @private
28308 */
28309
28310 }, {
28311 key: "initFontOptions",
28312 value: function initFontOptions(newFontOptions) {
28313 var _this = this;
28314
28315 // Prepare the multi-font option objects.
28316 // These will be filled in propagateFonts(), if required
28317 forEach(multiFontStyle, function (style) {
28318 _this.fontOptions[style] = {};
28319 }); // Handle shorthand option, if present
28320
28321 if (Label.parseFontString(this.fontOptions, newFontOptions)) {
28322 this.fontOptions.vadjust = 0;
28323 return;
28324 } // Copy over the non-multifont options, if specified
28325
28326
28327 forEach(newFontOptions, function (prop, n) {
28328 if (prop !== undefined && prop !== null && _typeof$1(prop) !== 'object') {
28329 _this.fontOptions[n] = prop;
28330 }
28331 });
28332 }
28333 /**
28334 * If in-variable is a string, parse it as a font specifier.
28335 *
28336 * Note that following is not done here and have to be done after the call:
28337 * - Not all font options are set (vadjust, mod)
28338 *
28339 * @param {Object} outOptions out-parameter, object in which to store the parse results (if any)
28340 * @param {Object} inOptions font options to parse
28341 * @return {boolean} true if font parsed as string, false otherwise
28342 * @static
28343 */
28344
28345 }, {
28346 key: "constrain",
28347
28348 /**
28349 * Set the width and height constraints based on 'nearest' value
28350 *
28351 * @param {Array} pile array of option objects to consider
28352 * @returns {object} the actual constraint values to use
28353 * @private
28354 */
28355 value: function constrain(pile) {
28356 // NOTE: constrainWidth and constrainHeight never set!
28357 // NOTE: for edge labels, only 'maxWdt' set
28358 // Node labels can set all the fields
28359 var fontOptions = {
28360 constrainWidth: false,
28361 maxWdt: -1,
28362 minWdt: -1,
28363 constrainHeight: false,
28364 minHgt: -1,
28365 valign: 'middle'
28366 };
28367 var widthConstraint = topMost(pile, 'widthConstraint');
28368
28369 if (typeof widthConstraint === 'number') {
28370 fontOptions.maxWdt = Number(widthConstraint);
28371 fontOptions.minWdt = Number(widthConstraint);
28372 } else if (_typeof$1(widthConstraint) === 'object') {
28373 var widthConstraintMaximum = topMost(pile, ['widthConstraint', 'maximum']);
28374
28375 if (typeof widthConstraintMaximum === 'number') {
28376 fontOptions.maxWdt = Number(widthConstraintMaximum);
28377 }
28378
28379 var widthConstraintMinimum = topMost(pile, ['widthConstraint', 'minimum']);
28380
28381 if (typeof widthConstraintMinimum === 'number') {
28382 fontOptions.minWdt = Number(widthConstraintMinimum);
28383 }
28384 }
28385
28386 var heightConstraint = topMost(pile, 'heightConstraint');
28387
28388 if (typeof heightConstraint === 'number') {
28389 fontOptions.minHgt = Number(heightConstraint);
28390 } else if (_typeof$1(heightConstraint) === 'object') {
28391 var heightConstraintMinimum = topMost(pile, ['heightConstraint', 'minimum']);
28392
28393 if (typeof heightConstraintMinimum === 'number') {
28394 fontOptions.minHgt = Number(heightConstraintMinimum);
28395 }
28396
28397 var heightConstraintValign = topMost(pile, ['heightConstraint', 'valign']);
28398
28399 if (typeof heightConstraintValign === 'string') {
28400 if (heightConstraintValign === 'top' || heightConstraintValign === 'bottom') {
28401 fontOptions.valign = heightConstraintValign;
28402 }
28403 }
28404 }
28405
28406 return fontOptions;
28407 }
28408 /**
28409 * Set options and update internal state
28410 *
28411 * @param {Object} options options to set
28412 * @param {Array} pile array of option objects to consider for option 'chosen'
28413 */
28414
28415 }, {
28416 key: "update",
28417 value: function update(options, pile) {
28418 this.setOptions(options, true);
28419 this.propagateFonts(pile);
28420 deepExtend(this.fontOptions, this.constrain(pile));
28421 this.fontOptions.chooser = ComponentUtil.choosify('label', pile);
28422 }
28423 /**
28424 * When margins are set in an element, adjust sizes is called to remove them
28425 * from the width/height constraints. This must be done prior to label sizing.
28426 *
28427 * @param {{top: number, right: number, bottom: number, left: number}} margins
28428 */
28429
28430 }, {
28431 key: "adjustSizes",
28432 value: function adjustSizes(margins) {
28433 var widthBias = margins ? margins.right + margins.left : 0;
28434
28435 if (this.fontOptions.constrainWidth) {
28436 this.fontOptions.maxWdt -= widthBias;
28437 this.fontOptions.minWdt -= widthBias;
28438 }
28439
28440 var heightBias = margins ? margins.top + margins.bottom : 0;
28441
28442 if (this.fontOptions.constrainHeight) {
28443 this.fontOptions.minHgt -= heightBias;
28444 }
28445 } /////////////////////////////////////////////////////////
28446 // Methods for handling options piles
28447 // Eventually, these will be moved to a separate class
28448 /////////////////////////////////////////////////////////
28449
28450 /**
28451 * Add the font members of the passed list of option objects to the pile.
28452 *
28453 * @param {Pile} dstPile pile of option objects add to
28454 * @param {Pile} srcPile pile of option objects to take font options from
28455 * @private
28456 */
28457
28458 }, {
28459 key: "addFontOptionsToPile",
28460 value: function addFontOptionsToPile(dstPile, srcPile) {
28461 for (var i = 0; i < srcPile.length; ++i) {
28462 this.addFontToPile(dstPile, srcPile[i]);
28463 }
28464 }
28465 /**
28466 * Add given font option object to the list of objects (the 'pile') to consider for determining
28467 * multi-font option values.
28468 *
28469 * @param {Pile} pile pile of option objects to use
28470 * @param {object} options instance to add to pile
28471 * @private
28472 */
28473
28474 }, {
28475 key: "addFontToPile",
28476 value: function addFontToPile(pile, options) {
28477 if (options === undefined) return;
28478 if (options.font === undefined || options.font === null) return;
28479 var item = options.font;
28480 pile.push(item);
28481 }
28482 /**
28483 * Collect all own-property values from the font pile that aren't multi-font option objectss.
28484 *
28485 * @param {Pile} pile pile of option objects to use
28486 * @returns {object} object with all current own basic font properties
28487 * @private
28488 */
28489
28490 }, {
28491 key: "getBasicOptions",
28492 value: function getBasicOptions(pile) {
28493 var ret = {}; // Scans the whole pile to get all options present
28494
28495 for (var n = 0; n < pile.length; ++n) {
28496 var fontOptions = pile[n]; // Convert shorthand if necessary
28497
28498 var tmpShorthand = {};
28499
28500 if (Label.parseFontString(tmpShorthand, fontOptions)) {
28501 fontOptions = tmpShorthand;
28502 }
28503
28504 forEach(fontOptions, function (opt, name) {
28505 if (opt === undefined) return; // multi-font option need not be present
28506
28507 if (ret.hasOwnProperty(name)) return; // Keep first value we encounter
28508
28509 if (multiFontStyle.indexOf(name) !== -1) {
28510 // Skip multi-font properties but we do need the structure
28511 ret[name] = {};
28512 } else {
28513 ret[name] = opt;
28514 }
28515 });
28516 }
28517
28518 return ret;
28519 }
28520 /**
28521 * Return the value for given option for the given multi-font.
28522 *
28523 * All available option objects are trawled in the set order to construct the option values.
28524 *
28525 * ---------------------------------------------------------------------
28526 * ## Traversal of pile for multi-fonts
28527 *
28528 * The determination of multi-font option values is a special case, because any values not
28529 * present in the multi-font options should by definition be taken from the main font options,
28530 * i.e. from the current 'parent' object of the multi-font option.
28531 *
28532 * ### Search order for multi-fonts
28533 *
28534 * 'bold' used as example:
28535 *
28536 * - search in option group 'bold' in local properties
28537 * - search in main font option group in local properties
28538 *
28539 * ---------------------------------------------------------------------
28540 *
28541 * @param {Pile} pile pile of option objects to use
28542 * @param {MultiFontStyle} multiName sub path for the multi-font
28543 * @param {string} option the option to search for, for the given multi-font
28544 * @returns {string|number} the value for the given option
28545 * @private
28546 */
28547
28548 }, {
28549 key: "getFontOption",
28550 value: function getFontOption(pile, multiName, option) {
28551 var multiFont; // Search multi font in local properties
28552
28553 for (var n = 0; n < pile.length; ++n) {
28554 var fontOptions = pile[n];
28555
28556 if (fontOptions.hasOwnProperty(multiName)) {
28557 multiFont = fontOptions[multiName];
28558 if (multiFont === undefined || multiFont === null) continue; // Convert shorthand if necessary
28559 // TODO: inefficient to do this conversion every time; find a better way.
28560
28561 var tmpShorthand = {};
28562
28563 if (Label.parseFontString(tmpShorthand, multiFont)) {
28564 multiFont = tmpShorthand;
28565 }
28566
28567 if (multiFont.hasOwnProperty(option)) {
28568 return multiFont[option];
28569 }
28570 }
28571 } // Option is not mentioned in the multi font options; take it from the parent font options.
28572 // These have already been converted with getBasicOptions(), so use the converted values.
28573
28574
28575 if (this.fontOptions.hasOwnProperty(option)) {
28576 return this.fontOptions[option];
28577 } // A value **must** be found; you should never get here.
28578
28579
28580 throw new Error("Did not find value for multi-font for property: '" + option + "'");
28581 }
28582 /**
28583 * Return all options values for the given multi-font.
28584 *
28585 * All available option objects are trawled in the set order to construct the option values.
28586 *
28587 * @param {Pile} pile pile of option objects to use
28588 * @param {MultiFontStyle} multiName sub path for the mod-font
28589 * @returns {MultiFontOptions}
28590 * @private
28591 */
28592
28593 }, {
28594 key: "getFontOptions",
28595 value: function getFontOptions(pile, multiName) {
28596 var result = {};
28597 var optionNames = ['color', 'size', 'face', 'mod', 'vadjust']; // List of allowed options per multi-font
28598
28599 for (var i = 0; i < optionNames.length; ++i) {
28600 var mod = optionNames[i];
28601 result[mod] = this.getFontOption(pile, multiName, mod);
28602 }
28603
28604 return result;
28605 } /////////////////////////////////////////////////////////
28606 // End methods for handling options piles
28607 /////////////////////////////////////////////////////////
28608
28609 /**
28610 * Collapse the font options for the multi-font to single objects, from
28611 * the chain of option objects passed (the 'pile').
28612 *
28613 * @param {Pile} pile sequence of option objects to consider.
28614 * First item in list assumed to be the newly set options.
28615 */
28616
28617 }, {
28618 key: "propagateFonts",
28619 value: function propagateFonts(pile) {
28620 var _this2 = this;
28621
28622 var fontPile = []; // sequence of font objects to consider, order important
28623 // Note that this.elementOptions is not used here.
28624
28625 this.addFontOptionsToPile(fontPile, pile);
28626 this.fontOptions = this.getBasicOptions(fontPile); // We set multifont values even if multi === false, for consistency (things break otherwise)
28627
28628 var _loop = function _loop(i) {
28629 var mod = multiFontStyle[i];
28630 var modOptions = _this2.fontOptions[mod];
28631
28632 var tmpMultiFontOptions = _this2.getFontOptions(fontPile, mod); // Copy over found values
28633
28634
28635 forEach(tmpMultiFontOptions, function (option, n) {
28636 modOptions[n] = option;
28637 });
28638 modOptions.size = Number(modOptions.size);
28639 modOptions.vadjust = Number(modOptions.vadjust);
28640 };
28641
28642 for (var i = 0; i < multiFontStyle.length; ++i) {
28643 _loop(i);
28644 }
28645 }
28646 /**
28647 * Main function. This is called from anything that wants to draw a label.
28648 * @param {CanvasRenderingContext2D} ctx
28649 * @param {number} x
28650 * @param {number} y
28651 * @param {boolean} selected
28652 * @param {boolean} hover
28653 * @param {string} [baseline='middle']
28654 */
28655
28656 }, {
28657 key: "draw",
28658 value: function draw(ctx, x, y, selected, hover) {
28659 var baseline = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : 'middle';
28660 // if no label, return
28661 if (this.elementOptions.label === undefined) return; // check if we have to render the label
28662
28663 var viewFontSize = this.fontOptions.size * this.body.view.scale;
28664 if (this.elementOptions.label && viewFontSize < this.elementOptions.scaling.label.drawThreshold - 1) return; // This ensures that there will not be HUGE letters on screen
28665 // by setting an upper limit on the visible text size (regardless of zoomLevel)
28666
28667 if (viewFontSize >= this.elementOptions.scaling.label.maxVisible) {
28668 viewFontSize = Number(this.elementOptions.scaling.label.maxVisible) / this.body.view.scale;
28669 } // update the size cache if required
28670
28671
28672 this.calculateLabelSize(ctx, selected, hover, x, y, baseline);
28673
28674 this._drawBackground(ctx);
28675
28676 this._drawText(ctx, x, this.size.yLine, baseline, viewFontSize);
28677 }
28678 /**
28679 * Draws the label background
28680 * @param {CanvasRenderingContext2D} ctx
28681 * @private
28682 */
28683
28684 }, {
28685 key: "_drawBackground",
28686 value: function _drawBackground(ctx) {
28687 if (this.fontOptions.background !== undefined && this.fontOptions.background !== "none") {
28688 ctx.fillStyle = this.fontOptions.background;
28689 var size = this.getSize();
28690 ctx.fillRect(size.left, size.top, size.width, size.height);
28691 }
28692 }
28693 /**
28694 *
28695 * @param {CanvasRenderingContext2D} ctx
28696 * @param {number} x
28697 * @param {number} y
28698 * @param {string} [baseline='middle']
28699 * @param {number} viewFontSize
28700 * @private
28701 */
28702
28703 }, {
28704 key: "_drawText",
28705 value: function _drawText(ctx, x, y) {
28706 var baseline = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 'middle';
28707 var viewFontSize = arguments.length > 4 ? arguments[4] : undefined;
28708
28709 var _this$_setAlignment = this._setAlignment(ctx, x, y, baseline);
28710
28711 var _this$_setAlignment2 = _slicedToArray(_this$_setAlignment, 2);
28712
28713 x = _this$_setAlignment2[0];
28714 y = _this$_setAlignment2[1];
28715 ctx.textAlign = 'left';
28716 x = x - this.size.width / 2; // Shift label 1/2-distance to the left
28717
28718 if (this.fontOptions.valign && this.size.height > this.size.labelHeight) {
28719 if (this.fontOptions.valign === 'top') {
28720 y -= (this.size.height - this.size.labelHeight) / 2;
28721 }
28722
28723 if (this.fontOptions.valign === 'bottom') {
28724 y += (this.size.height - this.size.labelHeight) / 2;
28725 }
28726 } // draw the text
28727
28728
28729 for (var i = 0; i < this.lineCount; i++) {
28730 var line = this.lines[i];
28731
28732 if (line && line.blocks) {
28733 var width = 0;
28734
28735 if (this.isEdgeLabel || this.fontOptions.align === 'center') {
28736 width += (this.size.width - line.width) / 2;
28737 } else if (this.fontOptions.align === 'right') {
28738 width += this.size.width - line.width;
28739 }
28740
28741 for (var j = 0; j < line.blocks.length; j++) {
28742 var block = line.blocks[j];
28743 ctx.font = block.font;
28744
28745 var _this$_getColor = this._getColor(block.color, viewFontSize, block.strokeColor),
28746 _this$_getColor2 = _slicedToArray(_this$_getColor, 2),
28747 fontColor = _this$_getColor2[0],
28748 strokeColor = _this$_getColor2[1];
28749
28750 if (block.strokeWidth > 0) {
28751 ctx.lineWidth = block.strokeWidth;
28752 ctx.strokeStyle = strokeColor;
28753 ctx.lineJoin = 'round';
28754 }
28755
28756 ctx.fillStyle = fontColor;
28757
28758 if (block.strokeWidth > 0) {
28759 ctx.strokeText(block.text, x + width, y + block.vadjust);
28760 }
28761
28762 ctx.fillText(block.text, x + width, y + block.vadjust);
28763 width += block.width;
28764 }
28765
28766 y += line.height;
28767 }
28768 }
28769 }
28770 /**
28771 *
28772 * @param {CanvasRenderingContext2D} ctx
28773 * @param {number} x
28774 * @param {number} y
28775 * @param {string} baseline
28776 * @returns {Array.<number>}
28777 * @private
28778 */
28779
28780 }, {
28781 key: "_setAlignment",
28782 value: function _setAlignment(ctx, x, y, baseline) {
28783 // check for label alignment (for edges)
28784 // TODO: make alignment for nodes
28785 if (this.isEdgeLabel && this.fontOptions.align !== 'horizontal' && this.pointToSelf === false) {
28786 x = 0;
28787 y = 0;
28788 var lineMargin = 2;
28789
28790 if (this.fontOptions.align === 'top') {
28791 ctx.textBaseline = 'alphabetic';
28792 y -= 2 * lineMargin; // distance from edge, required because we use alphabetic. Alphabetic has less difference between browsers
28793 } else if (this.fontOptions.align === 'bottom') {
28794 ctx.textBaseline = 'hanging';
28795 y += 2 * lineMargin; // distance from edge, required because we use hanging. Hanging has less difference between browsers
28796 } else {
28797 ctx.textBaseline = 'middle';
28798 }
28799 } else {
28800 ctx.textBaseline = baseline;
28801 }
28802
28803 return [x, y];
28804 }
28805 /**
28806 * fade in when relative scale is between threshold and threshold - 1.
28807 * If the relative scale would be smaller than threshold -1 the draw function would have returned before coming here.
28808 *
28809 * @param {string} color The font color to use
28810 * @param {number} viewFontSize
28811 * @param {string} initialStrokeColor
28812 * @returns {Array.<string>} An array containing the font color and stroke color
28813 * @private
28814 */
28815
28816 }, {
28817 key: "_getColor",
28818 value: function _getColor(color, viewFontSize, initialStrokeColor) {
28819 var fontColor = color || '#000000';
28820 var strokeColor = initialStrokeColor || '#ffffff';
28821
28822 if (viewFontSize <= this.elementOptions.scaling.label.drawThreshold) {
28823 var opacity = Math.max(0, Math.min(1, 1 - (this.elementOptions.scaling.label.drawThreshold - viewFontSize)));
28824 fontColor = overrideOpacity(fontColor, opacity);
28825 strokeColor = overrideOpacity(strokeColor, opacity);
28826 }
28827
28828 return [fontColor, strokeColor];
28829 }
28830 /**
28831 *
28832 * @param {CanvasRenderingContext2D} ctx
28833 * @param {boolean} selected
28834 * @param {boolean} hover
28835 * @returns {{width: number, height: number}}
28836 */
28837
28838 }, {
28839 key: "getTextSize",
28840 value: function getTextSize(ctx) {
28841 var selected = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
28842 var hover = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
28843
28844 this._processLabel(ctx, selected, hover);
28845
28846 return {
28847 width: this.size.width,
28848 height: this.size.height,
28849 lineCount: this.lineCount
28850 };
28851 }
28852 /**
28853 * Get the current dimensions of the label
28854 *
28855 * @return {rect}
28856 */
28857
28858 }, {
28859 key: "getSize",
28860 value: function getSize() {
28861 var lineMargin = 2;
28862 var x = this.size.left; // default values which might be overridden below
28863
28864 var y = this.size.top - 0.5 * lineMargin; // idem
28865
28866 if (this.isEdgeLabel) {
28867 var x2 = -this.size.width * 0.5;
28868
28869 switch (this.fontOptions.align) {
28870 case 'middle':
28871 x = x2;
28872 y = -this.size.height * 0.5;
28873 break;
28874
28875 case 'top':
28876 x = x2;
28877 y = -(this.size.height + lineMargin);
28878 break;
28879
28880 case 'bottom':
28881 x = x2;
28882 y = lineMargin;
28883 break;
28884 }
28885 }
28886
28887 var ret = {
28888 left: x,
28889 top: y,
28890 width: this.size.width,
28891 height: this.size.height
28892 };
28893 return ret;
28894 }
28895 /**
28896 *
28897 * @param {CanvasRenderingContext2D} ctx
28898 * @param {boolean} selected
28899 * @param {boolean} hover
28900 * @param {number} [x=0]
28901 * @param {number} [y=0]
28902 * @param {'middle'|'hanging'} [baseline='middle']
28903 */
28904
28905 }, {
28906 key: "calculateLabelSize",
28907 value: function calculateLabelSize(ctx, selected, hover) {
28908 var x = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0;
28909 var y = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 0;
28910 var baseline = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : 'middle';
28911
28912 this._processLabel(ctx, selected, hover);
28913
28914 this.size.left = x - this.size.width * 0.5;
28915 this.size.top = y - this.size.height * 0.5;
28916 this.size.yLine = y + (1 - this.lineCount) * 0.5 * this.fontOptions.size;
28917
28918 if (baseline === "hanging") {
28919 this.size.top += 0.5 * this.fontOptions.size;
28920 this.size.top += 4; // distance from node, required because we use hanging. Hanging has less difference between browsers
28921
28922 this.size.yLine += 4; // distance from node
28923 }
28924 }
28925 /**
28926 *
28927 * @param {CanvasRenderingContext2D} ctx
28928 * @param {boolean} selected
28929 * @param {boolean} hover
28930 * @param {string} mod
28931 * @returns {{color, size, face, mod, vadjust, strokeWidth: *, strokeColor: (*|string|allOptions.edges.font.strokeColor|{string}|allOptions.nodes.font.strokeColor|Array)}}
28932 */
28933
28934 }, {
28935 key: "getFormattingValues",
28936 value: function getFormattingValues(ctx, selected, hover, mod) {
28937 var getValue = function getValue(fontOptions, mod, option) {
28938 if (mod === "normal") {
28939 if (option === 'mod') return "";
28940 return fontOptions[option];
28941 }
28942
28943 if (fontOptions[mod][option] !== undefined) {
28944 // Grumbl leaving out test on undefined equals false for ""
28945 return fontOptions[mod][option];
28946 } else {
28947 // Take from parent font option
28948 return fontOptions[option];
28949 }
28950 };
28951
28952 var values = {
28953 color: getValue(this.fontOptions, mod, 'color'),
28954 size: getValue(this.fontOptions, mod, 'size'),
28955 face: getValue(this.fontOptions, mod, 'face'),
28956 mod: getValue(this.fontOptions, mod, 'mod'),
28957 vadjust: getValue(this.fontOptions, mod, 'vadjust'),
28958 strokeWidth: this.fontOptions.strokeWidth,
28959 strokeColor: this.fontOptions.strokeColor
28960 };
28961
28962 if (selected || hover) {
28963 if (mod === "normal" && this.fontOptions.chooser === true && this.elementOptions.labelHighlightBold) {
28964 values.mod = 'bold';
28965 } else {
28966 if (typeof this.fontOptions.chooser === 'function') {
28967 this.fontOptions.chooser(values, this.elementOptions.id, selected, hover);
28968 }
28969 }
28970 }
28971
28972 var fontString = "";
28973
28974 if (values.mod !== undefined && values.mod !== "") {
28975 // safeguard for undefined - this happened
28976 fontString += values.mod + " ";
28977 }
28978
28979 fontString += values.size + "px " + values.face;
28980 ctx.font = fontString.replace(/"/g, "");
28981 values.font = ctx.font;
28982 values.height = values.size;
28983 return values;
28984 }
28985 /**
28986 *
28987 * @param {boolean} selected
28988 * @param {boolean} hover
28989 * @returns {boolean}
28990 */
28991
28992 }, {
28993 key: "differentState",
28994 value: function differentState(selected, hover) {
28995 return selected !== this.selectedState || hover !== this.hoverState;
28996 }
28997 /**
28998 * This explodes the passed text into lines and determines the width, height and number of lines.
28999 *
29000 * @param {CanvasRenderingContext2D} ctx
29001 * @param {boolean} selected
29002 * @param {boolean} hover
29003 * @param {string} inText the text to explode
29004 * @returns {{width, height, lines}|*}
29005 * @private
29006 */
29007
29008 }, {
29009 key: "_processLabelText",
29010 value: function _processLabelText(ctx, selected, hover, inText) {
29011 var splitter = new LabelSplitter(ctx, this, selected, hover);
29012 return splitter.process(inText);
29013 }
29014 /**
29015 * This explodes the label string into lines and sets the width, height and number of lines.
29016 * @param {CanvasRenderingContext2D} ctx
29017 * @param {boolean} selected
29018 * @param {boolean} hover
29019 * @private
29020 */
29021
29022 }, {
29023 key: "_processLabel",
29024 value: function _processLabel(ctx, selected, hover) {
29025 if (this.labelDirty === false && !this.differentState(selected, hover)) return;
29026
29027 var state = this._processLabelText(ctx, selected, hover, this.elementOptions.label);
29028
29029 if (this.fontOptions.minWdt > 0 && state.width < this.fontOptions.minWdt) {
29030 state.width = this.fontOptions.minWdt;
29031 }
29032
29033 this.size.labelHeight = state.height;
29034
29035 if (this.fontOptions.minHgt > 0 && state.height < this.fontOptions.minHgt) {
29036 state.height = this.fontOptions.minHgt;
29037 }
29038
29039 this.lines = state.lines;
29040 this.lineCount = state.lines.length;
29041 this.size.width = state.width;
29042 this.size.height = state.height;
29043 this.selectedState = selected;
29044 this.hoverState = hover;
29045 this.labelDirty = false;
29046 }
29047 /**
29048 * Check if this label is visible
29049 *
29050 * @return {boolean} true if this label will be show, false otherwise
29051 */
29052
29053 }, {
29054 key: "visible",
29055 value: function visible() {
29056 if (this.size.width === 0 || this.size.height === 0 || this.elementOptions.label === undefined) {
29057 return false; // nothing to display
29058 }
29059
29060 var viewFontSize = this.fontOptions.size * this.body.view.scale;
29061
29062 if (viewFontSize < this.elementOptions.scaling.label.drawThreshold - 1) {
29063 return false; // Too small or too far away to show
29064 }
29065
29066 return true;
29067 }
29068 }], [{
29069 key: "parseFontString",
29070 value: function parseFontString(outOptions, inOptions) {
29071 if (!inOptions || typeof inOptions !== 'string') return false;
29072 var newOptionsArray = inOptions.split(" ");
29073 outOptions.size = +newOptionsArray[0].replace("px", '');
29074 outOptions.face = newOptionsArray[1];
29075 outOptions.color = newOptionsArray[2];
29076 return true;
29077 }
29078 }]);
29079
29080 return Label;
29081 }();
29082
29083 // https://tc39.github.io/ecma262/#sec-array.prototype.fill
29084
29085 _export({
29086 target: 'Array',
29087 proto: true
29088 }, {
29089 fill: arrayFill
29090 }); // https://tc39.github.io/ecma262/#sec-array.prototype-@@unscopables
29091
29092 addToUnscopables('fill');
29093
29094 /**
29095 * The Base class for all Nodes.
29096 */
29097 var NodeBase =
29098 /*#__PURE__*/
29099 function () {
29100 /**
29101 * @param {Object} options
29102 * @param {Object} body
29103 * @param {Label} labelModule
29104 */
29105 function NodeBase(options, body, labelModule) {
29106 _classCallCheck(this, NodeBase);
29107
29108 this.body = body;
29109 this.labelModule = labelModule;
29110 this.setOptions(options);
29111 this.top = undefined;
29112 this.left = undefined;
29113 this.height = undefined;
29114 this.width = undefined;
29115 this.radius = undefined;
29116 this.margin = undefined;
29117 this.refreshNeeded = true;
29118 this.boundingBox = {
29119 top: 0,
29120 left: 0,
29121 right: 0,
29122 bottom: 0
29123 };
29124 }
29125 /**
29126 *
29127 * @param {Object} options
29128 */
29129
29130
29131 _createClass(NodeBase, [{
29132 key: "setOptions",
29133 value: function setOptions(options) {
29134 this.options = options;
29135 }
29136 /**
29137 *
29138 * @param {Label} labelModule
29139 * @private
29140 */
29141
29142 }, {
29143 key: "_setMargins",
29144 value: function _setMargins(labelModule) {
29145 this.margin = {};
29146
29147 if (this.options.margin) {
29148 if (_typeof$1(this.options.margin) == 'object') {
29149 this.margin.top = this.options.margin.top;
29150 this.margin.right = this.options.margin.right;
29151 this.margin.bottom = this.options.margin.bottom;
29152 this.margin.left = this.options.margin.left;
29153 } else {
29154 this.margin.top = this.options.margin;
29155 this.margin.right = this.options.margin;
29156 this.margin.bottom = this.options.margin;
29157 this.margin.left = this.options.margin;
29158 }
29159 }
29160
29161 labelModule.adjustSizes(this.margin);
29162 }
29163 /**
29164 *
29165 * @param {CanvasRenderingContext2D} ctx
29166 * @param {number} angle
29167 * @returns {number}
29168 * @private
29169 */
29170
29171 }, {
29172 key: "_distanceToBorder",
29173 value: function _distanceToBorder(ctx, angle) {
29174 var borderWidth = this.options.borderWidth;
29175 this.resize(ctx);
29176 return Math.min(Math.abs(this.width / 2 / Math.cos(angle)), Math.abs(this.height / 2 / Math.sin(angle))) + borderWidth;
29177 }
29178 /**
29179 *
29180 * @param {CanvasRenderingContext2D} ctx
29181 * @param {ArrowOptions} values
29182 */
29183
29184 }, {
29185 key: "enableShadow",
29186 value: function enableShadow(ctx, values) {
29187 if (values.shadow) {
29188 ctx.shadowColor = values.shadowColor;
29189 ctx.shadowBlur = values.shadowSize;
29190 ctx.shadowOffsetX = values.shadowX;
29191 ctx.shadowOffsetY = values.shadowY;
29192 }
29193 }
29194 /**
29195 *
29196 * @param {CanvasRenderingContext2D} ctx
29197 * @param {ArrowOptions} values
29198 */
29199
29200 }, {
29201 key: "disableShadow",
29202 value: function disableShadow(ctx, values) {
29203 if (values.shadow) {
29204 ctx.shadowColor = 'rgba(0,0,0,0)';
29205 ctx.shadowBlur = 0;
29206 ctx.shadowOffsetX = 0;
29207 ctx.shadowOffsetY = 0;
29208 }
29209 }
29210 /**
29211 *
29212 * @param {CanvasRenderingContext2D} ctx
29213 * @param {ArrowOptions} values
29214 */
29215
29216 }, {
29217 key: "enableBorderDashes",
29218 value: function enableBorderDashes(ctx, values) {
29219 if (values.borderDashes !== false) {
29220 if (ctx.setLineDash !== undefined) {
29221 var dashes = values.borderDashes;
29222
29223 if (dashes === true) {
29224 dashes = [5, 15];
29225 }
29226
29227 ctx.setLineDash(dashes);
29228 } else {
29229 console.warn("setLineDash is not supported in this browser. The dashed borders cannot be used.");
29230 this.options.shapeProperties.borderDashes = false;
29231 values.borderDashes = false;
29232 }
29233 }
29234 }
29235 /**
29236 *
29237 * @param {CanvasRenderingContext2D} ctx
29238 * @param {ArrowOptions} values
29239 */
29240
29241 }, {
29242 key: "disableBorderDashes",
29243 value: function disableBorderDashes(ctx, values) {
29244 if (values.borderDashes !== false) {
29245 if (ctx.setLineDash !== undefined) {
29246 ctx.setLineDash([0]);
29247 } else {
29248 console.warn("setLineDash is not supported in this browser. The dashed borders cannot be used.");
29249 this.options.shapeProperties.borderDashes = false;
29250 values.borderDashes = false;
29251 }
29252 }
29253 }
29254 /**
29255 * Determine if the shape of a node needs to be recalculated.
29256 *
29257 * @param {boolean} selected
29258 * @param {boolean} hover
29259 * @returns {boolean}
29260 * @protected
29261 */
29262
29263 }, {
29264 key: "needsRefresh",
29265 value: function needsRefresh(selected, hover) {
29266 if (this.refreshNeeded === true) {
29267 // This is probably not the best location to reset this member.
29268 // However, in the current logic, it is the most convenient one.
29269 this.refreshNeeded = false;
29270 return true;
29271 }
29272
29273 return this.width === undefined || this.labelModule.differentState(selected, hover);
29274 }
29275 /**
29276 *
29277 * @param {CanvasRenderingContext2D} ctx
29278 * @param {ArrowOptions} values
29279 */
29280
29281 }, {
29282 key: "initContextForDraw",
29283 value: function initContextForDraw(ctx, values) {
29284 var borderWidth = values.borderWidth / this.body.view.scale;
29285 ctx.lineWidth = Math.min(this.width, borderWidth);
29286 ctx.strokeStyle = values.borderColor;
29287 ctx.fillStyle = values.color;
29288 }
29289 /**
29290 *
29291 * @param {CanvasRenderingContext2D} ctx
29292 * @param {ArrowOptions} values
29293 */
29294
29295 }, {
29296 key: "performStroke",
29297 value: function performStroke(ctx, values) {
29298 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.
29299
29300 ctx.save(); // if borders are zero width, they will be drawn with width 1 by default. This prevents that
29301
29302 if (borderWidth > 0) {
29303 this.enableBorderDashes(ctx, values); //draw the border
29304
29305 ctx.stroke(); //disable dashed border for other elements
29306
29307 this.disableBorderDashes(ctx, values);
29308 }
29309
29310 ctx.restore();
29311 }
29312 /**
29313 *
29314 * @param {CanvasRenderingContext2D} ctx
29315 * @param {ArrowOptions} values
29316 */
29317
29318 }, {
29319 key: "performFill",
29320 value: function performFill(ctx, values) {
29321 // draw shadow if enabled
29322 this.enableShadow(ctx, values); // draw the background
29323
29324 ctx.fill(); // disable shadows for other elements.
29325
29326 this.disableShadow(ctx, values);
29327 this.performStroke(ctx, values);
29328 }
29329 /**
29330 *
29331 * @param {number} margin
29332 * @private
29333 */
29334
29335 }, {
29336 key: "_addBoundingBoxMargin",
29337 value: function _addBoundingBoxMargin(margin) {
29338 this.boundingBox.left -= margin;
29339 this.boundingBox.top -= margin;
29340 this.boundingBox.bottom += margin;
29341 this.boundingBox.right += margin;
29342 }
29343 /**
29344 * Actual implementation of this method call.
29345 *
29346 * Doing it like this makes it easier to override
29347 * in the child classes.
29348 *
29349 * @param {number} x width
29350 * @param {number} y height
29351 * @param {CanvasRenderingContext2D} ctx
29352 * @param {boolean} selected
29353 * @param {boolean} hover
29354 * @private
29355 */
29356
29357 }, {
29358 key: "_updateBoundingBox",
29359 value: function _updateBoundingBox(x, y, ctx, selected, hover) {
29360 if (ctx !== undefined) {
29361 this.resize(ctx, selected, hover);
29362 }
29363
29364 this.left = x - this.width / 2;
29365 this.top = y - this.height / 2;
29366 this.boundingBox.left = this.left;
29367 this.boundingBox.top = this.top;
29368 this.boundingBox.bottom = this.top + this.height;
29369 this.boundingBox.right = this.left + this.width;
29370 }
29371 /**
29372 * Default implementation of this method call.
29373 * This acts as a stub which can be overridden.
29374 *
29375 * @param {number} x width
29376 * @param {number} y height
29377 * @param {CanvasRenderingContext2D} ctx
29378 * @param {boolean} selected
29379 * @param {boolean} hover
29380 */
29381
29382 }, {
29383 key: "updateBoundingBox",
29384 value: function updateBoundingBox(x, y, ctx, selected, hover) {
29385 this._updateBoundingBox(x, y, ctx, selected, hover);
29386 }
29387 /**
29388 * Determine the dimensions to use for nodes with an internal label
29389 *
29390 * Currently, these are: Circle, Ellipse, Database, Box
29391 * The other nodes have external labels, and will not call this method
29392 *
29393 * If there is no label, decent default values are supplied.
29394 *
29395 * @param {CanvasRenderingContext2D} ctx
29396 * @param {boolean} [selected]
29397 * @param {boolean} [hover]
29398 * @returns {{width:number, height:number}}
29399 */
29400
29401 }, {
29402 key: "getDimensionsFromLabel",
29403 value: function getDimensionsFromLabel(ctx, selected, hover) {
29404 // NOTE: previously 'textSize' was not put in 'this' for Ellipse
29405 // TODO: examine the consequences.
29406 this.textSize = this.labelModule.getTextSize(ctx, selected, hover);
29407 var width = this.textSize.width;
29408 var height = this.textSize.height;
29409 var DEFAULT_SIZE = 14;
29410
29411 if (width === 0) {
29412 // This happens when there is no label text set
29413 width = DEFAULT_SIZE; // use a decent default
29414
29415 height = DEFAULT_SIZE; // if width zero, then height also always zero
29416 }
29417
29418 return {
29419 width: width,
29420 height: height
29421 };
29422 }
29423 }]);
29424
29425 return NodeBase;
29426 }();
29427
29428 /**
29429 * A Box Node/Cluster shape.
29430 *
29431 * @extends NodeBase
29432 */
29433
29434 var Box =
29435 /*#__PURE__*/
29436 function (_NodeBase) {
29437 _inherits(Box, _NodeBase);
29438
29439 /**
29440 * @param {Object} options
29441 * @param {Object} body
29442 * @param {Label} labelModule
29443 */
29444 function Box(options, body, labelModule) {
29445 var _this;
29446
29447 _classCallCheck(this, Box);
29448
29449 _this = _possibleConstructorReturn(this, _getPrototypeOf(Box).call(this, options, body, labelModule));
29450
29451 _this._setMargins(labelModule);
29452
29453 return _this;
29454 }
29455 /**
29456 *
29457 * @param {CanvasRenderingContext2D} ctx
29458 * @param {boolean} [selected]
29459 * @param {boolean} [hover]
29460 */
29461
29462
29463 _createClass(Box, [{
29464 key: "resize",
29465 value: function resize(ctx) {
29466 var selected = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.selected;
29467 var hover = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : this.hover;
29468
29469 if (this.needsRefresh(selected, hover)) {
29470 var dimensions = this.getDimensionsFromLabel(ctx, selected, hover);
29471 this.width = dimensions.width + this.margin.right + this.margin.left;
29472 this.height = dimensions.height + this.margin.top + this.margin.bottom;
29473 this.radius = this.width / 2;
29474 }
29475 }
29476 /**
29477 *
29478 * @param {CanvasRenderingContext2D} ctx
29479 * @param {number} x width
29480 * @param {number} y height
29481 * @param {boolean} selected
29482 * @param {boolean} hover
29483 * @param {ArrowOptions} values
29484 */
29485
29486 }, {
29487 key: "draw",
29488 value: function draw(ctx, x, y, selected, hover, values) {
29489 this.resize(ctx, selected, hover);
29490 this.left = x - this.width / 2;
29491 this.top = y - this.height / 2;
29492 this.initContextForDraw(ctx, values);
29493 ctx.roundRect(this.left, this.top, this.width, this.height, values.borderRadius);
29494 this.performFill(ctx, values);
29495 this.updateBoundingBox(x, y, ctx, selected, hover);
29496 this.labelModule.draw(ctx, this.left + this.textSize.width / 2 + this.margin.left, this.top + this.textSize.height / 2 + this.margin.top, selected, hover);
29497 }
29498 /**
29499 *
29500 * @param {number} x width
29501 * @param {number} y height
29502 * @param {CanvasRenderingContext2D} ctx
29503 * @param {boolean} selected
29504 * @param {boolean} hover
29505 */
29506
29507 }, {
29508 key: "updateBoundingBox",
29509 value: function updateBoundingBox(x, y, ctx, selected, hover) {
29510 this._updateBoundingBox(x, y, ctx, selected, hover);
29511
29512 var borderRadius = this.options.shapeProperties.borderRadius; // only effective for box
29513
29514 this._addBoundingBoxMargin(borderRadius);
29515 }
29516 /**
29517 *
29518 * @param {CanvasRenderingContext2D} ctx
29519 * @param {number} angle
29520 * @returns {number}
29521 */
29522
29523 }, {
29524 key: "distanceToBorder",
29525 value: function distanceToBorder(ctx, angle) {
29526 this.resize(ctx);
29527 var borderWidth = this.options.borderWidth;
29528 return Math.min(Math.abs(this.width / 2 / Math.cos(angle)), Math.abs(this.height / 2 / Math.sin(angle))) + borderWidth;
29529 }
29530 }]);
29531
29532 return Box;
29533 }(NodeBase);
29534
29535 /**
29536 * NOTE: This is a bad base class
29537 *
29538 * Child classes are:
29539 *
29540 * Image - uses *only* image methods
29541 * Circle - uses *only* _drawRawCircle
29542 * CircleImage - uses all
29543 *
29544 * TODO: Refactor, move _drawRawCircle to different module, derive Circle from NodeBase
29545 * Rename this to ImageBase
29546 * Consolidate common code in Image and CircleImage to base class
29547 *
29548 * @extends NodeBase
29549 */
29550
29551 var CircleImageBase =
29552 /*#__PURE__*/
29553 function (_NodeBase) {
29554 _inherits(CircleImageBase, _NodeBase);
29555
29556 /**
29557 * @param {Object} options
29558 * @param {Object} body
29559 * @param {Label} labelModule
29560 */
29561 function CircleImageBase(options, body, labelModule) {
29562 var _this;
29563
29564 _classCallCheck(this, CircleImageBase);
29565
29566 _this = _possibleConstructorReturn(this, _getPrototypeOf(CircleImageBase).call(this, options, body, labelModule));
29567 _this.labelOffset = 0;
29568 _this.selected = false;
29569 return _this;
29570 }
29571 /**
29572 *
29573 * @param {Object} options
29574 * @param {Object} [imageObj]
29575 * @param {Object} [imageObjAlt]
29576 */
29577
29578
29579 _createClass(CircleImageBase, [{
29580 key: "setOptions",
29581 value: function setOptions(options, imageObj, imageObjAlt) {
29582 this.options = options;
29583
29584 if (!(imageObj === undefined && imageObjAlt === undefined)) {
29585 this.setImages(imageObj, imageObjAlt);
29586 }
29587 }
29588 /**
29589 * Set the images for this node.
29590 *
29591 * The images can be updated after the initial setting of options;
29592 * therefore, this method needs to be reentrant.
29593 *
29594 * For correct working in error cases, it is necessary to properly set
29595 * field 'nodes.brokenImage' in the options.
29596 *
29597 * @param {Image} imageObj required; main image to show for this node
29598 * @param {Image|undefined} imageObjAlt optional; image to show when node is selected
29599 */
29600
29601 }, {
29602 key: "setImages",
29603 value: function setImages(imageObj, imageObjAlt) {
29604 if (imageObjAlt && this.selected) {
29605 this.imageObj = imageObjAlt;
29606 this.imageObjAlt = imageObj;
29607 } else {
29608 this.imageObj = imageObj;
29609 this.imageObjAlt = imageObjAlt;
29610 }
29611 }
29612 /**
29613 * Set selection and switch between the base and the selected image.
29614 *
29615 * Do the switch only if imageObjAlt exists.
29616 *
29617 * @param {boolean} selected value of new selected state for current node
29618 */
29619
29620 }, {
29621 key: "switchImages",
29622 value: function switchImages(selected) {
29623 var selection_changed = selected && !this.selected || !selected && this.selected;
29624 this.selected = selected; // Remember new selection
29625
29626 if (this.imageObjAlt !== undefined && selection_changed) {
29627 var imageTmp = this.imageObj;
29628 this.imageObj = this.imageObjAlt;
29629 this.imageObjAlt = imageTmp;
29630 }
29631 }
29632 /**
29633 * Returns Image Padding from node options
29634 *
29635 * @returns {{top: number,left: number,bottom: number,right: number}} image padding inside this shape
29636 * @private
29637 */
29638
29639 }, {
29640 key: "_getImagePadding",
29641 value: function _getImagePadding() {
29642 var imgPadding = {
29643 top: 0,
29644 right: 0,
29645 bottom: 0,
29646 left: 0
29647 };
29648
29649 if (this.options.imagePadding) {
29650 var optImgPadding = this.options.imagePadding;
29651
29652 if (_typeof$1(optImgPadding) == 'object') {
29653 imgPadding.top = optImgPadding.top;
29654 imgPadding.right = optImgPadding.right;
29655 imgPadding.bottom = optImgPadding.bottom;
29656 imgPadding.left = optImgPadding.left;
29657 } else {
29658 imgPadding.top = optImgPadding;
29659 imgPadding.right = optImgPadding;
29660 imgPadding.bottom = optImgPadding;
29661 imgPadding.left = optImgPadding;
29662 }
29663 }
29664
29665 return imgPadding;
29666 }
29667 /**
29668 * Adjust the node dimensions for a loaded image.
29669 *
29670 * Pre: this.imageObj is valid
29671 */
29672
29673 }, {
29674 key: "_resizeImage",
29675 value: function _resizeImage() {
29676 var width, height;
29677
29678 if (this.options.shapeProperties.useImageSize === false) {
29679 // Use the size property
29680 var ratio_width = 1;
29681 var ratio_height = 1; // Only calculate the proper ratio if both width and height not zero
29682
29683 if (this.imageObj.width && this.imageObj.height) {
29684 if (this.imageObj.width > this.imageObj.height) {
29685 ratio_width = this.imageObj.width / this.imageObj.height;
29686 } else {
29687 ratio_height = this.imageObj.height / this.imageObj.width;
29688 }
29689 }
29690
29691 width = this.options.size * 2 * ratio_width;
29692 height = this.options.size * 2 * ratio_height;
29693 } else {
29694 // Use the image size with image padding
29695 var imgPadding = this._getImagePadding();
29696
29697 width = this.imageObj.width + imgPadding.left + imgPadding.right;
29698 height = this.imageObj.height + imgPadding.top + imgPadding.bottom;
29699 }
29700
29701 this.width = width;
29702 this.height = height;
29703 this.radius = 0.5 * this.width;
29704 }
29705 /**
29706 *
29707 * @param {CanvasRenderingContext2D} ctx
29708 * @param {number} x width
29709 * @param {number} y height
29710 * @param {ArrowOptions} values
29711 * @private
29712 */
29713
29714 }, {
29715 key: "_drawRawCircle",
29716 value: function _drawRawCircle(ctx, x, y, values) {
29717 this.initContextForDraw(ctx, values);
29718 ctx.circle(x, y, values.size);
29719 this.performFill(ctx, values);
29720 }
29721 /**
29722 *
29723 * @param {CanvasRenderingContext2D} ctx
29724 * @param {ArrowOptions} values
29725 * @private
29726 */
29727
29728 }, {
29729 key: "_drawImageAtPosition",
29730 value: function _drawImageAtPosition(ctx, values) {
29731 if (this.imageObj.width != 0) {
29732 // draw the image
29733 ctx.globalAlpha = 1.0; // draw shadow if enabled
29734
29735 this.enableShadow(ctx, values);
29736 var factor = 1;
29737
29738 if (this.options.shapeProperties.interpolation === true) {
29739 factor = this.imageObj.width / this.width / this.body.view.scale;
29740 }
29741
29742 var imgPadding = this._getImagePadding();
29743
29744 var imgPosLeft = this.left + imgPadding.left;
29745 var imgPosTop = this.top + imgPadding.top;
29746 var imgWidth = this.width - imgPadding.left - imgPadding.right;
29747 var imgHeight = this.height - imgPadding.top - imgPadding.bottom;
29748 this.imageObj.drawImageAtPosition(ctx, factor, imgPosLeft, imgPosTop, imgWidth, imgHeight); // disable shadows for other elements.
29749
29750 this.disableShadow(ctx, values);
29751 }
29752 }
29753 /**
29754 *
29755 * @param {CanvasRenderingContext2D} ctx
29756 * @param {number} x width
29757 * @param {number} y height
29758 * @param {boolean} selected
29759 * @param {boolean} hover
29760 * @private
29761 */
29762
29763 }, {
29764 key: "_drawImageLabel",
29765 value: function _drawImageLabel(ctx, x, y, selected, hover) {
29766 var yLabel;
29767 var offset = 0;
29768
29769 if (this.height !== undefined) {
29770 offset = this.height * 0.5;
29771 var labelDimensions = this.labelModule.getTextSize(ctx, selected, hover);
29772
29773 if (labelDimensions.lineCount >= 1) {
29774 offset += labelDimensions.height / 2;
29775 }
29776 }
29777
29778 yLabel = y + offset;
29779
29780 if (this.options.label) {
29781 this.labelOffset = offset;
29782 }
29783
29784 this.labelModule.draw(ctx, x, yLabel, selected, hover, 'hanging');
29785 }
29786 }]);
29787
29788 return CircleImageBase;
29789 }(NodeBase);
29790
29791 /**
29792 * A Circle Node/Cluster shape.
29793 *
29794 * @extends CircleImageBase
29795 */
29796
29797 var Circle =
29798 /*#__PURE__*/
29799 function (_CircleImageBase) {
29800 _inherits(Circle, _CircleImageBase);
29801
29802 /**
29803 * @param {Object} options
29804 * @param {Object} body
29805 * @param {Label} labelModule
29806 */
29807 function Circle(options, body, labelModule) {
29808 var _this;
29809
29810 _classCallCheck(this, Circle);
29811
29812 _this = _possibleConstructorReturn(this, _getPrototypeOf(Circle).call(this, options, body, labelModule));
29813
29814 _this._setMargins(labelModule);
29815
29816 return _this;
29817 }
29818 /**
29819 *
29820 * @param {CanvasRenderingContext2D} ctx
29821 * @param {boolean} [selected]
29822 * @param {boolean} [hover]
29823 */
29824
29825
29826 _createClass(Circle, [{
29827 key: "resize",
29828 value: function resize(ctx) {
29829 var selected = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.selected;
29830 var hover = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : this.hover;
29831
29832 if (this.needsRefresh(selected, hover)) {
29833 var dimensions = this.getDimensionsFromLabel(ctx, selected, hover);
29834 var diameter = Math.max(dimensions.width + this.margin.right + this.margin.left, dimensions.height + this.margin.top + this.margin.bottom);
29835 this.options.size = diameter / 2; // NOTE: this size field only set here, not in Ellipse, Database, Box
29836
29837 this.width = diameter;
29838 this.height = diameter;
29839 this.radius = this.width / 2;
29840 }
29841 }
29842 /**
29843 *
29844 * @param {CanvasRenderingContext2D} ctx
29845 * @param {number} x width
29846 * @param {number} y height
29847 * @param {boolean} selected
29848 * @param {boolean} hover
29849 * @param {ArrowOptions} values
29850 */
29851
29852 }, {
29853 key: "draw",
29854 value: function draw(ctx, x, y, selected, hover, values) {
29855 this.resize(ctx, selected, hover);
29856 this.left = x - this.width / 2;
29857 this.top = y - this.height / 2;
29858
29859 this._drawRawCircle(ctx, x, y, values);
29860
29861 this.updateBoundingBox(x, y);
29862 this.labelModule.draw(ctx, this.left + this.textSize.width / 2 + this.margin.left, y, selected, hover);
29863 }
29864 /**
29865 *
29866 * @param {number} x width
29867 * @param {number} y height
29868 */
29869
29870 }, {
29871 key: "updateBoundingBox",
29872 value: function updateBoundingBox(x, y) {
29873 this.boundingBox.top = y - this.options.size;
29874 this.boundingBox.left = x - this.options.size;
29875 this.boundingBox.right = x + this.options.size;
29876 this.boundingBox.bottom = y + this.options.size;
29877 }
29878 /**
29879 *
29880 * @param {CanvasRenderingContext2D} ctx
29881 * @param {number} angle - Unused
29882 * @returns {number}
29883 */
29884
29885 }, {
29886 key: "distanceToBorder",
29887 value: function distanceToBorder(ctx, angle) {
29888 // eslint-disable-line no-unused-vars
29889 this.resize(ctx);
29890 return this.width * 0.5;
29891 }
29892 }]);
29893
29894 return Circle;
29895 }(CircleImageBase);
29896
29897 /**
29898 * A CircularImage Node/Cluster shape.
29899 *
29900 * @extends CircleImageBase
29901 */
29902
29903 var CircularImage =
29904 /*#__PURE__*/
29905 function (_CircleImageBase) {
29906 _inherits(CircularImage, _CircleImageBase);
29907
29908 /**
29909 * @param {Object} options
29910 * @param {Object} body
29911 * @param {Label} labelModule
29912 * @param {Image} imageObj
29913 * @param {Image} imageObjAlt
29914 */
29915 function CircularImage(options, body, labelModule, imageObj, imageObjAlt) {
29916 var _this;
29917
29918 _classCallCheck(this, CircularImage);
29919
29920 _this = _possibleConstructorReturn(this, _getPrototypeOf(CircularImage).call(this, options, body, labelModule));
29921
29922 _this.setImages(imageObj, imageObjAlt);
29923
29924 return _this;
29925 }
29926 /**
29927 *
29928 * @param {CanvasRenderingContext2D} ctx
29929 * @param {boolean} [selected]
29930 * @param {boolean} [hover]
29931 */
29932
29933
29934 _createClass(CircularImage, [{
29935 key: "resize",
29936 value: function resize(ctx) {
29937 var selected = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.selected;
29938 var hover = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : this.hover;
29939 var imageAbsent = this.imageObj.src === undefined || this.imageObj.width === undefined || this.imageObj.height === undefined;
29940
29941 if (imageAbsent) {
29942 var diameter = this.options.size * 2;
29943 this.width = diameter;
29944 this.height = diameter;
29945 this.radius = 0.5 * this.width;
29946 return;
29947 } // At this point, an image is present, i.e. this.imageObj is valid.
29948
29949
29950 if (this.needsRefresh(selected, hover)) {
29951 this._resizeImage();
29952 }
29953 }
29954 /**
29955 *
29956 * @param {CanvasRenderingContext2D} ctx
29957 * @param {number} x width
29958 * @param {number} y height
29959 * @param {boolean} selected
29960 * @param {boolean} hover
29961 * @param {ArrowOptions} values
29962 */
29963
29964 }, {
29965 key: "draw",
29966 value: function draw(ctx, x, y, selected, hover, values) {
29967 this.switchImages(selected);
29968 this.resize();
29969 this.left = x - this.width / 2;
29970 this.top = y - this.height / 2; // draw the background circle. IMPORTANT: the stroke in this method is used by the clip method below.
29971
29972 this._drawRawCircle(ctx, x, y, values); // now we draw in the circle, we save so we can revert the clip operation after drawing.
29973
29974
29975 ctx.save(); // clip is used to use the stroke in drawRawCircle as an area that we can draw in.
29976
29977 ctx.clip(); // draw the image
29978
29979 this._drawImageAtPosition(ctx, values); // restore so we can again draw on the full canvas
29980
29981
29982 ctx.restore();
29983
29984 this._drawImageLabel(ctx, x, y, selected, hover);
29985
29986 this.updateBoundingBox(x, y);
29987 } // TODO: compare with Circle.updateBoundingBox(), consolidate? More stuff is happening here
29988
29989 /**
29990 *
29991 * @param {number} x width
29992 * @param {number} y height
29993 */
29994
29995 }, {
29996 key: "updateBoundingBox",
29997 value: function updateBoundingBox(x, y) {
29998 this.boundingBox.top = y - this.options.size;
29999 this.boundingBox.left = x - this.options.size;
30000 this.boundingBox.right = x + this.options.size;
30001 this.boundingBox.bottom = y + this.options.size; // TODO: compare with Image.updateBoundingBox(), consolidate?
30002
30003 this.boundingBox.left = Math.min(this.boundingBox.left, this.labelModule.size.left);
30004 this.boundingBox.right = Math.max(this.boundingBox.right, this.labelModule.size.left + this.labelModule.size.width);
30005 this.boundingBox.bottom = Math.max(this.boundingBox.bottom, this.boundingBox.bottom + this.labelOffset);
30006 }
30007 /**
30008 *
30009 * @param {CanvasRenderingContext2D} ctx
30010 * @param {number} angle - Unused
30011 * @returns {number}
30012 */
30013
30014 }, {
30015 key: "distanceToBorder",
30016 value: function distanceToBorder(ctx, angle) {
30017 // eslint-disable-line no-unused-vars
30018 this.resize(ctx);
30019 return this.width * 0.5;
30020 }
30021 }]);
30022
30023 return CircularImage;
30024 }(CircleImageBase);
30025
30026 /**
30027 * A Database Node/Cluster shape.
30028 *
30029 * @extends NodeBase
30030 */
30031
30032 var Database =
30033 /*#__PURE__*/
30034 function (_NodeBase) {
30035 _inherits(Database, _NodeBase);
30036
30037 /**
30038 * @param {Object} options
30039 * @param {Object} body
30040 * @param {Label} labelModule
30041 */
30042 function Database(options, body, labelModule) {
30043 var _this;
30044
30045 _classCallCheck(this, Database);
30046
30047 _this = _possibleConstructorReturn(this, _getPrototypeOf(Database).call(this, options, body, labelModule));
30048
30049 _this._setMargins(labelModule);
30050
30051 return _this;
30052 }
30053 /**
30054 *
30055 * @param {CanvasRenderingContext2D} ctx
30056 * @param {boolean} selected
30057 * @param {boolean} hover
30058 */
30059
30060
30061 _createClass(Database, [{
30062 key: "resize",
30063 value: function resize(ctx, selected, hover) {
30064 if (this.needsRefresh(selected, hover)) {
30065 var dimensions = this.getDimensionsFromLabel(ctx, selected, hover);
30066 var size = dimensions.width + this.margin.right + this.margin.left;
30067 this.width = size;
30068 this.height = size;
30069 this.radius = this.width / 2;
30070 }
30071 }
30072 /**
30073 *
30074 * @param {CanvasRenderingContext2D} ctx
30075 * @param {number} x width
30076 * @param {number} y height
30077 * @param {boolean} selected
30078 * @param {boolean} hover
30079 * @param {ArrowOptions} values
30080 */
30081
30082 }, {
30083 key: "draw",
30084 value: function draw(ctx, x, y, selected, hover, values) {
30085 this.resize(ctx, selected, hover);
30086 this.left = x - this.width / 2;
30087 this.top = y - this.height / 2;
30088 this.initContextForDraw(ctx, values);
30089 ctx.database(x - this.width / 2, y - this.height / 2, this.width, this.height);
30090 this.performFill(ctx, values);
30091 this.updateBoundingBox(x, y, ctx, selected, hover);
30092 this.labelModule.draw(ctx, this.left + this.textSize.width / 2 + this.margin.left, this.top + this.textSize.height / 2 + this.margin.top, selected, hover);
30093 }
30094 /**
30095 *
30096 * @param {CanvasRenderingContext2D} ctx
30097 * @param {number} angle
30098 * @returns {number}
30099 */
30100
30101 }, {
30102 key: "distanceToBorder",
30103 value: function distanceToBorder(ctx, angle) {
30104 return this._distanceToBorder(ctx, angle);
30105 }
30106 }]);
30107
30108 return Database;
30109 }(NodeBase);
30110
30111 /**
30112 * Base class for constructing Node/Cluster Shapes.
30113 *
30114 * @extends NodeBase
30115 */
30116
30117 var ShapeBase =
30118 /*#__PURE__*/
30119 function (_NodeBase) {
30120 _inherits(ShapeBase, _NodeBase);
30121
30122 /**
30123 * @param {Object} options
30124 * @param {Object} body
30125 * @param {Label} labelModule
30126 */
30127 function ShapeBase(options, body, labelModule) {
30128 _classCallCheck(this, ShapeBase);
30129
30130 return _possibleConstructorReturn(this, _getPrototypeOf(ShapeBase).call(this, options, body, labelModule));
30131 }
30132 /**
30133 *
30134 * @param {CanvasRenderingContext2D} ctx
30135 * @param {boolean} [selected]
30136 * @param {boolean} [hover]
30137 * @param {Object} [values={size: this.options.size}]
30138 */
30139
30140
30141 _createClass(ShapeBase, [{
30142 key: "resize",
30143 value: function resize(ctx) {
30144 var selected = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.selected;
30145 var hover = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : this.hover;
30146 var values = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {
30147 size: this.options.size
30148 };
30149
30150 if (this.needsRefresh(selected, hover)) {
30151 this.labelModule.getTextSize(ctx, selected, hover);
30152 var size = 2 * values.size;
30153 this.width = size;
30154 this.height = size;
30155 this.radius = 0.5 * this.width;
30156 }
30157 }
30158 /**
30159 *
30160 * @param {CanvasRenderingContext2D} ctx
30161 * @param {string} shape
30162 * @param {number} sizeMultiplier - Unused! TODO: Remove next major release
30163 * @param {number} x
30164 * @param {number} y
30165 * @param {boolean} selected
30166 * @param {boolean} hover
30167 * @param {ArrowOptions} values
30168 * @private
30169 */
30170
30171 }, {
30172 key: "_drawShape",
30173 value: function _drawShape(ctx, shape, sizeMultiplier, x, y, selected, hover, values) {
30174 this.resize(ctx, selected, hover, values);
30175 this.left = x - this.width / 2;
30176 this.top = y - this.height / 2;
30177 this.initContextForDraw(ctx, values);
30178 ctx[shape](x, y, values.size);
30179 this.performFill(ctx, values);
30180
30181 if (this.options.icon !== undefined) {
30182 if (this.options.icon.code !== undefined) {
30183 ctx.font = (selected ? "bold " : "") + this.height / 2 + "px " + (this.options.icon.face || 'FontAwesome');
30184 ctx.fillStyle = this.options.icon.color || "black";
30185 ctx.textAlign = "center";
30186 ctx.textBaseline = "middle";
30187 ctx.fillText(this.options.icon.code, x, y);
30188 }
30189 }
30190
30191 if (this.options.label !== undefined) {
30192 // Need to call following here in order to ensure value for `this.labelModule.size.height`
30193 this.labelModule.calculateLabelSize(ctx, selected, hover, x, y, 'hanging');
30194 var yLabel = y + 0.5 * this.height + 0.5 * this.labelModule.size.height;
30195 this.labelModule.draw(ctx, x, yLabel, selected, hover, 'hanging');
30196 }
30197
30198 this.updateBoundingBox(x, y);
30199 }
30200 /**
30201 *
30202 * @param {number} x
30203 * @param {number} y
30204 */
30205
30206 }, {
30207 key: "updateBoundingBox",
30208 value: function updateBoundingBox(x, y) {
30209 this.boundingBox.top = y - this.options.size;
30210 this.boundingBox.left = x - this.options.size;
30211 this.boundingBox.right = x + this.options.size;
30212 this.boundingBox.bottom = y + this.options.size;
30213
30214 if (this.options.label !== undefined && this.labelModule.size.width > 0) {
30215 this.boundingBox.left = Math.min(this.boundingBox.left, this.labelModule.size.left);
30216 this.boundingBox.right = Math.max(this.boundingBox.right, this.labelModule.size.left + this.labelModule.size.width);
30217 this.boundingBox.bottom = Math.max(this.boundingBox.bottom, this.boundingBox.bottom + this.labelModule.size.height);
30218 }
30219 }
30220 }]);
30221
30222 return ShapeBase;
30223 }(NodeBase);
30224
30225 /**
30226 * A Diamond Node/Cluster shape.
30227 *
30228 * @extends ShapeBase
30229 */
30230
30231 var Diamond =
30232 /*#__PURE__*/
30233 function (_ShapeBase) {
30234 _inherits(Diamond, _ShapeBase);
30235
30236 /**
30237 * @param {Object} options
30238 * @param {Object} body
30239 * @param {Label} labelModule
30240 */
30241 function Diamond(options, body, labelModule) {
30242 _classCallCheck(this, Diamond);
30243
30244 return _possibleConstructorReturn(this, _getPrototypeOf(Diamond).call(this, options, body, labelModule));
30245 }
30246 /**
30247 *
30248 * @param {CanvasRenderingContext2D} ctx
30249 * @param {number} x width
30250 * @param {number} y height
30251 * @param {boolean} selected
30252 * @param {boolean} hover
30253 * @param {ArrowOptions} values
30254 */
30255
30256
30257 _createClass(Diamond, [{
30258 key: "draw",
30259 value: function draw(ctx, x, y, selected, hover, values) {
30260 this._drawShape(ctx, 'diamond', 4, x, y, selected, hover, values);
30261 }
30262 /**
30263 *
30264 * @param {CanvasRenderingContext2D} ctx
30265 * @param {number} angle
30266 * @returns {number}
30267 */
30268
30269 }, {
30270 key: "distanceToBorder",
30271 value: function distanceToBorder(ctx, angle) {
30272 return this._distanceToBorder(ctx, angle);
30273 }
30274 }]);
30275
30276 return Diamond;
30277 }(ShapeBase);
30278
30279 /**
30280 * A Dot Node/Cluster shape.
30281 *
30282 * @extends ShapeBase
30283 */
30284
30285 var Dot =
30286 /*#__PURE__*/
30287 function (_ShapeBase) {
30288 _inherits(Dot, _ShapeBase);
30289
30290 /**
30291 * @param {Object} options
30292 * @param {Object} body
30293 * @param {Label} labelModule
30294 */
30295 function Dot(options, body, labelModule) {
30296 _classCallCheck(this, Dot);
30297
30298 return _possibleConstructorReturn(this, _getPrototypeOf(Dot).call(this, options, body, labelModule));
30299 }
30300 /**
30301 *
30302 * @param {CanvasRenderingContext2D} ctx
30303 * @param {number} x width
30304 * @param {number} y height
30305 * @param {boolean} selected
30306 * @param {boolean} hover
30307 * @param {ArrowOptions} values
30308 */
30309
30310
30311 _createClass(Dot, [{
30312 key: "draw",
30313 value: function draw(ctx, x, y, selected, hover, values) {
30314 this._drawShape(ctx, 'circle', 2, x, y, selected, hover, values);
30315 }
30316 /**
30317 *
30318 * @param {CanvasRenderingContext2D} ctx
30319 * @param {number} angle
30320 * @returns {number}
30321 */
30322
30323 }, {
30324 key: "distanceToBorder",
30325 value: function distanceToBorder(ctx, angle) {
30326 // eslint-disable-line no-unused-vars
30327 this.resize(ctx);
30328 return this.options.size;
30329 }
30330 }]);
30331
30332 return Dot;
30333 }(ShapeBase);
30334
30335 /**
30336 * Am Ellipse Node/Cluster shape.
30337 *
30338 * @extends NodeBase
30339 */
30340
30341 var Ellipse =
30342 /*#__PURE__*/
30343 function (_NodeBase) {
30344 _inherits(Ellipse, _NodeBase);
30345
30346 /**
30347 * @param {Object} options
30348 * @param {Object} body
30349 * @param {Label} labelModule
30350 */
30351 function Ellipse(options, body, labelModule) {
30352 _classCallCheck(this, Ellipse);
30353
30354 return _possibleConstructorReturn(this, _getPrototypeOf(Ellipse).call(this, options, body, labelModule));
30355 }
30356 /**
30357 *
30358 * @param {CanvasRenderingContext2D} ctx
30359 * @param {boolean} [selected]
30360 * @param {boolean} [hover]
30361 */
30362
30363
30364 _createClass(Ellipse, [{
30365 key: "resize",
30366 value: function resize(ctx) {
30367 var selected = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.selected;
30368 var hover = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : this.hover;
30369
30370 if (this.needsRefresh(selected, hover)) {
30371 var dimensions = this.getDimensionsFromLabel(ctx, selected, hover);
30372 this.height = dimensions.height * 2;
30373 this.width = dimensions.width + dimensions.height;
30374 this.radius = 0.5 * this.width;
30375 }
30376 }
30377 /**
30378 *
30379 * @param {CanvasRenderingContext2D} ctx
30380 * @param {number} x width
30381 * @param {number} y height
30382 * @param {boolean} selected
30383 * @param {boolean} hover
30384 * @param {ArrowOptions} values
30385 */
30386
30387 }, {
30388 key: "draw",
30389 value: function draw(ctx, x, y, selected, hover, values) {
30390 this.resize(ctx, selected, hover);
30391 this.left = x - this.width * 0.5;
30392 this.top = y - this.height * 0.5;
30393 this.initContextForDraw(ctx, values);
30394 ctx.ellipse_vis(this.left, this.top, this.width, this.height);
30395 this.performFill(ctx, values);
30396 this.updateBoundingBox(x, y, ctx, selected, hover);
30397 this.labelModule.draw(ctx, x, y, selected, hover);
30398 }
30399 /**
30400 *
30401 * @param {CanvasRenderingContext2D} ctx
30402 * @param {number} angle
30403 * @returns {number}
30404 */
30405
30406 }, {
30407 key: "distanceToBorder",
30408 value: function distanceToBorder(ctx, angle) {
30409 this.resize(ctx);
30410 var a = this.width * 0.5;
30411 var b = this.height * 0.5;
30412 var w = Math.sin(angle) * a;
30413 var h = Math.cos(angle) * b;
30414 return a * b / Math.sqrt(w * w + h * h);
30415 }
30416 }]);
30417
30418 return Ellipse;
30419 }(NodeBase);
30420
30421 /**
30422 * An icon replacement for the default Node shape.
30423 *
30424 * @extends NodeBase
30425 */
30426
30427 var Icon =
30428 /*#__PURE__*/
30429 function (_NodeBase) {
30430 _inherits(Icon, _NodeBase);
30431
30432 /**
30433 * @param {Object} options
30434 * @param {Object} body
30435 * @param {Label} labelModule
30436 */
30437 function Icon(options, body, labelModule) {
30438 var _this;
30439
30440 _classCallCheck(this, Icon);
30441
30442 _this = _possibleConstructorReturn(this, _getPrototypeOf(Icon).call(this, options, body, labelModule));
30443
30444 _this._setMargins(labelModule);
30445
30446 return _this;
30447 }
30448 /**
30449 *
30450 * @param {CanvasRenderingContext2D} ctx - Unused.
30451 * @param {boolean} [selected]
30452 * @param {boolean} [hover]
30453 */
30454
30455
30456 _createClass(Icon, [{
30457 key: "resize",
30458 value: function resize(ctx, selected, hover) {
30459 if (this.needsRefresh(selected, hover)) {
30460 this.iconSize = {
30461 width: Number(this.options.icon.size),
30462 height: Number(this.options.icon.size)
30463 };
30464 this.width = this.iconSize.width + this.margin.right + this.margin.left;
30465 this.height = this.iconSize.height + this.margin.top + this.margin.bottom;
30466 this.radius = 0.5 * this.width;
30467 }
30468 }
30469 /**
30470 *
30471 * @param {CanvasRenderingContext2D} ctx
30472 * @param {number} x width
30473 * @param {number} y height
30474 * @param {boolean} selected
30475 * @param {boolean} hover
30476 * @param {ArrowOptions} values
30477 */
30478
30479 }, {
30480 key: "draw",
30481 value: function draw(ctx, x, y, selected, hover, values) {
30482 this.resize(ctx, selected, hover);
30483 this.options.icon.size = this.options.icon.size || 50;
30484 this.left = x - this.width / 2;
30485 this.top = y - this.height / 2;
30486
30487 this._icon(ctx, x, y, selected, hover, values);
30488
30489 if (this.options.label !== undefined) {
30490 var iconTextSpacing = 5;
30491 this.labelModule.draw(ctx, this.left + this.iconSize.width / 2 + this.margin.left, y + this.height / 2 + iconTextSpacing, selected);
30492 }
30493
30494 this.updateBoundingBox(x, y);
30495 }
30496 /**
30497 *
30498 * @param {number} x
30499 * @param {number} y
30500 */
30501
30502 }, {
30503 key: "updateBoundingBox",
30504 value: function updateBoundingBox(x, y) {
30505 this.boundingBox.top = y - this.options.icon.size * 0.5;
30506 this.boundingBox.left = x - this.options.icon.size * 0.5;
30507 this.boundingBox.right = x + this.options.icon.size * 0.5;
30508 this.boundingBox.bottom = y + this.options.icon.size * 0.5;
30509
30510 if (this.options.label !== undefined && this.labelModule.size.width > 0) {
30511 var iconTextSpacing = 5;
30512 this.boundingBox.left = Math.min(this.boundingBox.left, this.labelModule.size.left);
30513 this.boundingBox.right = Math.max(this.boundingBox.right, this.labelModule.size.left + this.labelModule.size.width);
30514 this.boundingBox.bottom = Math.max(this.boundingBox.bottom, this.boundingBox.bottom + this.labelModule.size.height + iconTextSpacing);
30515 }
30516 }
30517 /**
30518 *
30519 * @param {CanvasRenderingContext2D} ctx
30520 * @param {number} x width
30521 * @param {number} y height
30522 * @param {boolean} selected
30523 * @param {boolean} hover - Unused
30524 * @param {ArrowOptions} values
30525 */
30526
30527 }, {
30528 key: "_icon",
30529 value: function _icon(ctx, x, y, selected, hover, values) {
30530 var iconSize = Number(this.options.icon.size);
30531
30532 if (this.options.icon.code !== undefined) {
30533 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
30534 // properly) substitute slightly bigger size for bold font face.
30535 (this.options.icon.weight != null && selected ? 5 : 0) + iconSize + "px", this.options.icon.face].join(" "); // draw icon
30536
30537 ctx.fillStyle = this.options.icon.color || "black";
30538 ctx.textAlign = "center";
30539 ctx.textBaseline = "middle"; // draw shadow if enabled
30540
30541 this.enableShadow(ctx, values);
30542 ctx.fillText(this.options.icon.code, x, y); // disable shadows for other elements.
30543
30544 this.disableShadow(ctx, values);
30545 } else {
30546 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.');
30547 }
30548 }
30549 /**
30550 *
30551 * @param {CanvasRenderingContext2D} ctx
30552 * @param {number} angle
30553 * @returns {number}
30554 */
30555
30556 }, {
30557 key: "distanceToBorder",
30558 value: function distanceToBorder(ctx, angle) {
30559 return this._distanceToBorder(ctx, angle);
30560 }
30561 }]);
30562
30563 return Icon;
30564 }(NodeBase);
30565
30566 /**
30567 * An image-based replacement for the default Node shape.
30568 *
30569 * @extends CircleImageBase
30570 */
30571
30572 var Image$1 =
30573 /*#__PURE__*/
30574 function (_CircleImageBase) {
30575 _inherits(Image, _CircleImageBase);
30576
30577 /**
30578 * @param {Object} options
30579 * @param {Object} body
30580 * @param {Label} labelModule
30581 * @param {Image} imageObj
30582 * @param {Image} imageObjAlt
30583 */
30584 function Image(options, body, labelModule, imageObj, imageObjAlt) {
30585 var _this;
30586
30587 _classCallCheck(this, Image);
30588
30589 _this = _possibleConstructorReturn(this, _getPrototypeOf(Image).call(this, options, body, labelModule));
30590
30591 _this.setImages(imageObj, imageObjAlt);
30592
30593 return _this;
30594 }
30595 /**
30596 *
30597 * @param {CanvasRenderingContext2D} ctx - Unused.
30598 * @param {boolean} [selected]
30599 * @param {boolean} [hover]
30600 */
30601
30602
30603 _createClass(Image, [{
30604 key: "resize",
30605 value: function resize(ctx) {
30606 var selected = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.selected;
30607 var hover = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : this.hover;
30608 var imageAbsent = this.imageObj.src === undefined || this.imageObj.width === undefined || this.imageObj.height === undefined;
30609
30610 if (imageAbsent) {
30611 var side = this.options.size * 2;
30612 this.width = side;
30613 this.height = side;
30614 return;
30615 }
30616
30617 if (this.needsRefresh(selected, hover)) {
30618 this._resizeImage();
30619 }
30620 }
30621 /**
30622 *
30623 * @param {CanvasRenderingContext2D} ctx
30624 * @param {number} x width
30625 * @param {number} y height
30626 * @param {boolean} selected
30627 * @param {boolean} hover
30628 * @param {ArrowOptions} values
30629 */
30630
30631 }, {
30632 key: "draw",
30633 value: function draw(ctx, x, y, selected, hover, values) {
30634 this.switchImages(selected);
30635 this.resize();
30636 this.left = x - this.width / 2;
30637 this.top = y - this.height / 2;
30638
30639 if (this.options.shapeProperties.useBorderWithImage === true) {
30640 var neutralborderWidth = this.options.borderWidth;
30641 var selectionLineWidth = this.options.borderWidthSelected || 2 * this.options.borderWidth;
30642 var borderWidth = (selected ? selectionLineWidth : neutralborderWidth) / this.body.view.scale;
30643 ctx.lineWidth = Math.min(this.width, borderWidth);
30644 ctx.beginPath(); // setup the line properties.
30645
30646 ctx.strokeStyle = selected ? this.options.color.highlight.border : hover ? this.options.color.hover.border : this.options.color.border; // set a fillstyle
30647
30648 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
30649
30650 ctx.rect(this.left - 0.5 * ctx.lineWidth, this.top - 0.5 * ctx.lineWidth, this.width + ctx.lineWidth, this.height + ctx.lineWidth);
30651 ctx.fill();
30652 this.performStroke(ctx, values);
30653 ctx.closePath();
30654 }
30655
30656 this._drawImageAtPosition(ctx, values);
30657
30658 this._drawImageLabel(ctx, x, y, selected, hover);
30659
30660 this.updateBoundingBox(x, y);
30661 }
30662 /**
30663 *
30664 * @param {number} x
30665 * @param {number} y
30666 */
30667
30668 }, {
30669 key: "updateBoundingBox",
30670 value: function updateBoundingBox(x, y) {
30671 this.resize();
30672
30673 this._updateBoundingBox(x, y);
30674
30675 if (this.options.label !== undefined && this.labelModule.size.width > 0) {
30676 this.boundingBox.left = Math.min(this.boundingBox.left, this.labelModule.size.left);
30677 this.boundingBox.right = Math.max(this.boundingBox.right, this.labelModule.size.left + this.labelModule.size.width);
30678 this.boundingBox.bottom = Math.max(this.boundingBox.bottom, this.boundingBox.bottom + this.labelOffset);
30679 }
30680 }
30681 /**
30682 *
30683 * @param {CanvasRenderingContext2D} ctx
30684 * @param {number} angle
30685 * @returns {number}
30686 */
30687
30688 }, {
30689 key: "distanceToBorder",
30690 value: function distanceToBorder(ctx, angle) {
30691 return this._distanceToBorder(ctx, angle);
30692 }
30693 }]);
30694
30695 return Image;
30696 }(CircleImageBase);
30697
30698 /**
30699 * A Square Node/Cluster shape.
30700 *
30701 * @extends ShapeBase
30702 */
30703
30704 var Square =
30705 /*#__PURE__*/
30706 function (_ShapeBase) {
30707 _inherits(Square, _ShapeBase);
30708
30709 /**
30710 * @param {Object} options
30711 * @param {Object} body
30712 * @param {Label} labelModule
30713 */
30714 function Square(options, body, labelModule) {
30715 _classCallCheck(this, Square);
30716
30717 return _possibleConstructorReturn(this, _getPrototypeOf(Square).call(this, options, body, labelModule));
30718 }
30719 /**
30720 *
30721 * @param {CanvasRenderingContext2D} ctx
30722 * @param {number} x width
30723 * @param {number} y height
30724 * @param {boolean} selected
30725 * @param {boolean} hover
30726 * @param {ArrowOptions} values
30727 */
30728
30729
30730 _createClass(Square, [{
30731 key: "draw",
30732 value: function draw(ctx, x, y, selected, hover, values) {
30733 this._drawShape(ctx, 'square', 2, x, y, selected, hover, values);
30734 }
30735 /**
30736 *
30737 * @param {CanvasRenderingContext2D} ctx
30738 * @param {number} angle
30739 * @returns {number}
30740 */
30741
30742 }, {
30743 key: "distanceToBorder",
30744 value: function distanceToBorder(ctx, angle) {
30745 return this._distanceToBorder(ctx, angle);
30746 }
30747 }]);
30748
30749 return Square;
30750 }(ShapeBase);
30751
30752 /**
30753 * A Hexagon Node/Cluster shape.
30754 *
30755 * @extends ShapeBase
30756 */
30757
30758 var Hexagon =
30759 /*#__PURE__*/
30760 function (_ShapeBase) {
30761 _inherits(Hexagon, _ShapeBase);
30762
30763 /**
30764 * @param {Object} options
30765 * @param {Object} body
30766 * @param {Label} labelModule
30767 */
30768 function Hexagon(options, body, labelModule) {
30769 _classCallCheck(this, Hexagon);
30770
30771 return _possibleConstructorReturn(this, _getPrototypeOf(Hexagon).call(this, options, body, labelModule));
30772 }
30773 /**
30774 *
30775 * @param {CanvasRenderingContext2D} ctx
30776 * @param {number} x width
30777 * @param {number} y height
30778 * @param {boolean} selected
30779 * @param {boolean} hover
30780 * @param {ArrowOptions} values
30781 */
30782
30783
30784 _createClass(Hexagon, [{
30785 key: "draw",
30786 value: function draw(ctx, x, y, selected, hover, values) {
30787 this._drawShape(ctx, 'hexagon', 4, x, y, selected, hover, values);
30788 }
30789 /**
30790 *
30791 * @param {CanvasRenderingContext2D} ctx
30792 * @param {number} angle
30793 * @returns {number}
30794 */
30795
30796 }, {
30797 key: "distanceToBorder",
30798 value: function distanceToBorder(ctx, angle) {
30799 return this._distanceToBorder(ctx, angle);
30800 }
30801 }]);
30802
30803 return Hexagon;
30804 }(ShapeBase);
30805
30806 /**
30807 * A Star Node/Cluster shape.
30808 *
30809 * @extends ShapeBase
30810 */
30811
30812 var Star =
30813 /*#__PURE__*/
30814 function (_ShapeBase) {
30815 _inherits(Star, _ShapeBase);
30816
30817 /**
30818 * @param {Object} options
30819 * @param {Object} body
30820 * @param {Label} labelModule
30821 */
30822 function Star(options, body, labelModule) {
30823 _classCallCheck(this, Star);
30824
30825 return _possibleConstructorReturn(this, _getPrototypeOf(Star).call(this, options, body, labelModule));
30826 }
30827 /**
30828 *
30829 * @param {CanvasRenderingContext2D} ctx
30830 * @param {number} x width
30831 * @param {number} y height
30832 * @param {boolean} selected
30833 * @param {boolean} hover
30834 * @param {ArrowOptions} values
30835 */
30836
30837
30838 _createClass(Star, [{
30839 key: "draw",
30840 value: function draw(ctx, x, y, selected, hover, values) {
30841 this._drawShape(ctx, 'star', 4, x, y, selected, hover, values);
30842 }
30843 /**
30844 *
30845 * @param {CanvasRenderingContext2D} ctx
30846 * @param {number} angle
30847 * @returns {number}
30848 */
30849
30850 }, {
30851 key: "distanceToBorder",
30852 value: function distanceToBorder(ctx, angle) {
30853 return this._distanceToBorder(ctx, angle);
30854 }
30855 }]);
30856
30857 return Star;
30858 }(ShapeBase);
30859
30860 /**
30861 * A text-based replacement for the default Node shape.
30862 *
30863 * @extends NodeBase
30864 */
30865
30866 var Text =
30867 /*#__PURE__*/
30868 function (_NodeBase) {
30869 _inherits(Text, _NodeBase);
30870
30871 /**
30872 * @param {Object} options
30873 * @param {Object} body
30874 * @param {Label} labelModule
30875 */
30876 function Text(options, body, labelModule) {
30877 var _this;
30878
30879 _classCallCheck(this, Text);
30880
30881 _this = _possibleConstructorReturn(this, _getPrototypeOf(Text).call(this, options, body, labelModule));
30882
30883 _this._setMargins(labelModule);
30884
30885 return _this;
30886 }
30887 /**
30888 *
30889 * @param {CanvasRenderingContext2D} ctx
30890 * @param {boolean} selected
30891 * @param {boolean} hover
30892 */
30893
30894
30895 _createClass(Text, [{
30896 key: "resize",
30897 value: function resize(ctx, selected, hover) {
30898 if (this.needsRefresh(selected, hover)) {
30899 this.textSize = this.labelModule.getTextSize(ctx, selected, hover);
30900 this.width = this.textSize.width + this.margin.right + this.margin.left;
30901 this.height = this.textSize.height + this.margin.top + this.margin.bottom;
30902 this.radius = 0.5 * this.width;
30903 }
30904 }
30905 /**
30906 *
30907 * @param {CanvasRenderingContext2D} ctx
30908 * @param {number} x width
30909 * @param {number} y height
30910 * @param {boolean} selected
30911 * @param {boolean} hover
30912 * @param {ArrowOptions} values
30913 */
30914
30915 }, {
30916 key: "draw",
30917 value: function draw(ctx, x, y, selected, hover, values) {
30918 this.resize(ctx, selected, hover);
30919 this.left = x - this.width / 2;
30920 this.top = y - this.height / 2; // draw shadow if enabled
30921
30922 this.enableShadow(ctx, values);
30923 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.
30924
30925 this.disableShadow(ctx, values);
30926 this.updateBoundingBox(x, y, ctx, selected, hover);
30927 }
30928 /**
30929 *
30930 * @param {CanvasRenderingContext2D} ctx
30931 * @param {number} angle
30932 * @returns {number}
30933 */
30934
30935 }, {
30936 key: "distanceToBorder",
30937 value: function distanceToBorder(ctx, angle) {
30938 return this._distanceToBorder(ctx, angle);
30939 }
30940 }]);
30941
30942 return Text;
30943 }(NodeBase);
30944
30945 /**
30946 * A Triangle Node/Cluster shape.
30947 *
30948 * @extends ShapeBase
30949 */
30950
30951 var Triangle =
30952 /*#__PURE__*/
30953 function (_ShapeBase) {
30954 _inherits(Triangle, _ShapeBase);
30955
30956 /**
30957 * @param {Object} options
30958 * @param {Object} body
30959 * @param {Label} labelModule
30960 */
30961 function Triangle(options, body, labelModule) {
30962 _classCallCheck(this, Triangle);
30963
30964 return _possibleConstructorReturn(this, _getPrototypeOf(Triangle).call(this, options, body, labelModule));
30965 }
30966 /**
30967 *
30968 * @param {CanvasRenderingContext2D} ctx
30969 * @param {number} x
30970 * @param {number} y
30971 * @param {boolean} selected
30972 * @param {boolean} hover
30973 * @param {ArrowOptions} values
30974 */
30975
30976
30977 _createClass(Triangle, [{
30978 key: "draw",
30979 value: function draw(ctx, x, y, selected, hover, values) {
30980 this._drawShape(ctx, 'triangle', 3, x, y, selected, hover, values);
30981 }
30982 /**
30983 *
30984 * @param {CanvasRenderingContext2D} ctx
30985 * @param {number} angle
30986 * @returns {number}
30987 */
30988
30989 }, {
30990 key: "distanceToBorder",
30991 value: function distanceToBorder(ctx, angle) {
30992 return this._distanceToBorder(ctx, angle);
30993 }
30994 }]);
30995
30996 return Triangle;
30997 }(ShapeBase);
30998
30999 /**
31000 * A downward facing Triangle Node/Cluster shape.
31001 *
31002 * @extends ShapeBase
31003 */
31004
31005 var TriangleDown =
31006 /*#__PURE__*/
31007 function (_ShapeBase) {
31008 _inherits(TriangleDown, _ShapeBase);
31009
31010 /**
31011 * @param {Object} options
31012 * @param {Object} body
31013 * @param {Label} labelModule
31014 */
31015 function TriangleDown(options, body, labelModule) {
31016 _classCallCheck(this, TriangleDown);
31017
31018 return _possibleConstructorReturn(this, _getPrototypeOf(TriangleDown).call(this, options, body, labelModule));
31019 }
31020 /**
31021 *
31022 * @param {CanvasRenderingContext2D} ctx
31023 * @param {number} x
31024 * @param {number} y
31025 * @param {boolean} selected
31026 * @param {boolean} hover
31027 * @param {ArrowOptions} values
31028 */
31029
31030
31031 _createClass(TriangleDown, [{
31032 key: "draw",
31033 value: function draw(ctx, x, y, selected, hover, values) {
31034 this._drawShape(ctx, 'triangleDown', 3, x, y, selected, hover, values);
31035 }
31036 /**
31037 *
31038 * @param {CanvasRenderingContext2D} ctx
31039 * @param {number} angle
31040 * @returns {number}
31041 */
31042
31043 }, {
31044 key: "distanceToBorder",
31045 value: function distanceToBorder(ctx, angle) {
31046 return this._distanceToBorder(ctx, angle);
31047 }
31048 }]);
31049
31050 return TriangleDown;
31051 }(ShapeBase);
31052
31053 var DatePrototype = Date.prototype;
31054 var INVALID_DATE = 'Invalid Date';
31055 var TO_STRING$2 = 'toString';
31056 var nativeDateToString = DatePrototype[TO_STRING$2];
31057 var getTime = DatePrototype.getTime; // `Date.prototype.toString` method
31058 // https://tc39.github.io/ecma262/#sec-date.prototype.tostring
31059
31060 if (new Date(NaN) + '' != INVALID_DATE) {
31061 redefine(DatePrototype, TO_STRING$2, function toString() {
31062 var value = getTime.call(this); // eslint-disable-next-line no-self-compare
31063
31064 return value === value ? nativeDateToString.call(this) : INVALID_DATE;
31065 });
31066 }
31067
31068 var FAILS_ON_PRIMITIVES$1 = fails(function () {
31069 objectKeys(1);
31070 }); // `Object.keys` method
31071 // https://tc39.github.io/ecma262/#sec-object.keys
31072
31073 _export({
31074 target: 'Object',
31075 stat: true,
31076 forced: FAILS_ON_PRIMITIVES$1
31077 }, {
31078 keys: function keys(it) {
31079 return objectKeys(toObject(it));
31080 }
31081 });
31082
31083 var errorFound = false;
31084 var allOptions;
31085 var printStyle = 'background: #FFeeee; color: #dd0000';
31086 /**
31087 * Used to validate options.
31088 */
31089
31090 var Validator =
31091 /*#__PURE__*/
31092 function () {
31093 /**
31094 * @ignore
31095 */
31096 function Validator() {
31097 _classCallCheck(this, Validator);
31098 }
31099 /**
31100 * Main function to be called
31101 * @param {Object} options
31102 * @param {Object} referenceOptions
31103 * @param {Object} subObject
31104 * @returns {boolean}
31105 * @static
31106 */
31107
31108
31109 _createClass(Validator, null, [{
31110 key: "validate",
31111 value: function validate(options, referenceOptions, subObject) {
31112 errorFound = false;
31113 allOptions = referenceOptions;
31114 var usedOptions = referenceOptions;
31115
31116 if (subObject !== undefined) {
31117 usedOptions = referenceOptions[subObject];
31118 }
31119
31120 Validator.parse(options, usedOptions, []);
31121 return errorFound;
31122 }
31123 /**
31124 * Will traverse an object recursively and check every value
31125 * @param {Object} options
31126 * @param {Object} referenceOptions
31127 * @param {array} path | where to look for the actual option
31128 * @static
31129 */
31130
31131 }, {
31132 key: "parse",
31133 value: function parse(options, referenceOptions, path) {
31134 for (var option in options) {
31135 if (options.hasOwnProperty(option)) {
31136 Validator.check(option, options, referenceOptions, path);
31137 }
31138 }
31139 }
31140 /**
31141 * Check every value. If the value is an object, call the parse function on that object.
31142 * @param {string} option
31143 * @param {Object} options
31144 * @param {Object} referenceOptions
31145 * @param {array} path | where to look for the actual option
31146 * @static
31147 */
31148
31149 }, {
31150 key: "check",
31151 value: function check(option, options, referenceOptions, path) {
31152 if (referenceOptions[option] === undefined && referenceOptions.__any__ === undefined) {
31153 Validator.getSuggestion(option, referenceOptions, path);
31154 return;
31155 }
31156
31157 var referenceOption = option;
31158 var is_object = true;
31159
31160 if (referenceOptions[option] === undefined && referenceOptions.__any__ !== undefined) {
31161 // NOTE: This only triggers if the __any__ is in the top level of the options object.
31162 // THAT'S A REALLY BAD PLACE TO ALLOW IT!!!!
31163 // TODO: Examine if needed, remove if possible
31164 // __any__ is a wildcard. Any value is accepted and will be further analysed by reference.
31165 referenceOption = '__any__'; // if the any-subgroup is not a predefined object in the configurator,
31166 // we do not look deeper into the object.
31167
31168 is_object = Validator.getType(options[option]) === 'object';
31169 }
31170
31171 var refOptionObj = referenceOptions[referenceOption];
31172
31173 if (is_object && refOptionObj.__type__ !== undefined) {
31174 refOptionObj = refOptionObj.__type__;
31175 }
31176
31177 Validator.checkFields(option, options, referenceOptions, referenceOption, refOptionObj, path);
31178 }
31179 /**
31180 *
31181 * @param {string} option | the option property
31182 * @param {Object} options | The supplied options object
31183 * @param {Object} referenceOptions | The reference options containing all options and their allowed formats
31184 * @param {string} referenceOption | Usually this is the same as option, except when handling an __any__ tag.
31185 * @param {string} refOptionObj | This is the type object from the reference options
31186 * @param {Array} path | where in the object is the option
31187 * @static
31188 */
31189
31190 }, {
31191 key: "checkFields",
31192 value: function checkFields(option, options, referenceOptions, referenceOption, refOptionObj, path) {
31193 var log = function log(message) {
31194 console.log('%c' + message + Validator.printLocation(path, option), printStyle);
31195 };
31196
31197 var optionType = Validator.getType(options[option]);
31198 var refOptionType = refOptionObj[optionType];
31199
31200 if (refOptionType !== undefined) {
31201 // if the type is correct, we check if it is supposed to be one of a few select values
31202 if (Validator.getType(refOptionType) === 'array' && refOptionType.indexOf(options[option]) === -1) {
31203 log('Invalid option detected in "' + option + '".' + ' Allowed values are:' + Validator.print(refOptionType) + ' not "' + options[option] + '". ');
31204 errorFound = true;
31205 } else if (optionType === 'object' && referenceOption !== "__any__") {
31206 path = copyAndExtendArray(path, option);
31207 Validator.parse(options[option], referenceOptions[referenceOption], path);
31208 }
31209 } else if (refOptionObj['any'] === undefined) {
31210 // type of the field is incorrect and the field cannot be any
31211 log('Invalid type received for "' + option + '". Expected: ' + Validator.print(Object.keys(refOptionObj)) + '. Received [' + optionType + '] "' + options[option] + '"');
31212 errorFound = true;
31213 }
31214 }
31215 /**
31216 *
31217 * @param {Object|boolean|number|string|Array.<number>|Date|Node|Moment|undefined|null} object
31218 * @returns {string}
31219 * @static
31220 */
31221
31222 }, {
31223 key: "getType",
31224 value: function getType(object) {
31225 var type = _typeof$1(object);
31226
31227 if (type === 'object') {
31228 if (object === null) {
31229 return 'null';
31230 }
31231
31232 if (object instanceof Boolean) {
31233 return 'boolean';
31234 }
31235
31236 if (object instanceof Number) {
31237 return 'number';
31238 }
31239
31240 if (object instanceof String) {
31241 return 'string';
31242 }
31243
31244 if (Array.isArray(object)) {
31245 return 'array';
31246 }
31247
31248 if (object instanceof Date) {
31249 return 'date';
31250 }
31251
31252 if (object.nodeType !== undefined) {
31253 return 'dom';
31254 }
31255
31256 if (object._isAMomentObject === true) {
31257 return 'moment';
31258 }
31259
31260 return 'object';
31261 } else if (type === 'number') {
31262 return 'number';
31263 } else if (type === 'boolean') {
31264 return 'boolean';
31265 } else if (type === 'string') {
31266 return 'string';
31267 } else if (type === undefined) {
31268 return 'undefined';
31269 }
31270
31271 return type;
31272 }
31273 /**
31274 * @param {string} option
31275 * @param {Object} options
31276 * @param {Array.<string>} path
31277 * @static
31278 */
31279
31280 }, {
31281 key: "getSuggestion",
31282 value: function getSuggestion(option, options, path) {
31283 var localSearch = Validator.findInOptions(option, options, path, false);
31284 var globalSearch = Validator.findInOptions(option, allOptions, [], true);
31285 var localSearchThreshold = 8;
31286 var globalSearchThreshold = 4;
31287 var msg;
31288
31289 if (localSearch.indexMatch !== undefined) {
31290 msg = ' in ' + Validator.printLocation(localSearch.path, option, '') + 'Perhaps it was incomplete? Did you mean: "' + localSearch.indexMatch + '"?\n\n';
31291 } else if (globalSearch.distance <= globalSearchThreshold && localSearch.distance > globalSearch.distance) {
31292 msg = ' in ' + Validator.printLocation(localSearch.path, option, '') + 'Perhaps it was misplaced? Matching option found at: ' + Validator.printLocation(globalSearch.path, globalSearch.closestMatch, '');
31293 } else if (localSearch.distance <= localSearchThreshold) {
31294 msg = '. Did you mean "' + localSearch.closestMatch + '"?' + Validator.printLocation(localSearch.path, option);
31295 } else {
31296 msg = '. Did you mean one of these: ' + Validator.print(Object.keys(options)) + Validator.printLocation(path, option);
31297 }
31298
31299 console.log('%cUnknown option detected: "' + option + '"' + msg, printStyle);
31300 errorFound = true;
31301 }
31302 /**
31303 * traverse the options in search for a match.
31304 * @param {string} option
31305 * @param {Object} options
31306 * @param {Array} path | where to look for the actual option
31307 * @param {boolean} [recursive=false]
31308 * @returns {{closestMatch: string, path: Array, distance: number}}
31309 * @static
31310 */
31311
31312 }, {
31313 key: "findInOptions",
31314 value: function findInOptions(option, options, path) {
31315 var recursive = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
31316 var min = 1e9;
31317 var closestMatch = '';
31318 var closestMatchPath = [];
31319 var lowerCaseOption = option.toLowerCase();
31320 var indexMatch = undefined;
31321
31322 for (var op in options) {
31323 // eslint-disable-line guard-for-in
31324 var distance = void 0;
31325
31326 if (options[op].__type__ !== undefined && recursive === true) {
31327 var result = Validator.findInOptions(option, options[op], copyAndExtendArray(path, op));
31328
31329 if (min > result.distance) {
31330 closestMatch = result.closestMatch;
31331 closestMatchPath = result.path;
31332 min = result.distance;
31333 indexMatch = result.indexMatch;
31334 }
31335 } else {
31336 if (op.toLowerCase().indexOf(lowerCaseOption) !== -1) {
31337 indexMatch = op;
31338 }
31339
31340 distance = Validator.levenshteinDistance(option, op);
31341
31342 if (min > distance) {
31343 closestMatch = op;
31344 closestMatchPath = copyArray(path);
31345 min = distance;
31346 }
31347 }
31348 }
31349
31350 return {
31351 closestMatch: closestMatch,
31352 path: closestMatchPath,
31353 distance: min,
31354 indexMatch: indexMatch
31355 };
31356 }
31357 /**
31358 * @param {Array.<string>} path
31359 * @param {Object} option
31360 * @param {string} prefix
31361 * @returns {String}
31362 * @static
31363 */
31364
31365 }, {
31366 key: "printLocation",
31367 value: function printLocation(path, option) {
31368 var prefix = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'Problem value found at: \n';
31369 var str = '\n\n' + prefix + 'options = {\n';
31370
31371 for (var i = 0; i < path.length; i++) {
31372 for (var j = 0; j < i + 1; j++) {
31373 str += ' ';
31374 }
31375
31376 str += path[i] + ': {\n';
31377 }
31378
31379 for (var _j = 0; _j < path.length + 1; _j++) {
31380 str += ' ';
31381 }
31382
31383 str += option + '\n';
31384
31385 for (var _i = 0; _i < path.length + 1; _i++) {
31386 for (var _j2 = 0; _j2 < path.length - _i; _j2++) {
31387 str += ' ';
31388 }
31389
31390 str += '}\n';
31391 }
31392
31393 return str + '\n\n';
31394 }
31395 /**
31396 * @param {Object} options
31397 * @returns {String}
31398 * @static
31399 */
31400
31401 }, {
31402 key: "print",
31403 value: function print(options) {
31404 return JSON.stringify(options).replace(/(\")|(\[)|(\])|(,"__type__")/g, "").replace(/(\,)/g, ', ');
31405 }
31406 /**
31407 * Compute the edit distance between the two given strings
31408 * http://en.wikibooks.org/wiki/Algorithm_Implementation/Strings/Levenshtein_distance#JavaScript
31409 *
31410 * Copyright (c) 2011 Andrei Mackenzie
31411 *
31412 * 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:
31413 *
31414 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
31415 *
31416 * 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.
31417 *
31418 * @param {string} a
31419 * @param {string} b
31420 * @returns {Array.<Array.<number>>}}
31421 * @static
31422 */
31423
31424 }, {
31425 key: "levenshteinDistance",
31426 value: function levenshteinDistance(a, b) {
31427 if (a.length === 0) return b.length;
31428 if (b.length === 0) return a.length;
31429 var matrix = []; // increment along the first column of each row
31430
31431 var i;
31432
31433 for (i = 0; i <= b.length; i++) {
31434 matrix[i] = [i];
31435 } // increment each column in the first row
31436
31437
31438 var j;
31439
31440 for (j = 0; j <= a.length; j++) {
31441 matrix[0][j] = j;
31442 } // Fill in the rest of the matrix
31443
31444
31445 for (i = 1; i <= b.length; i++) {
31446 for (j = 1; j <= a.length; j++) {
31447 if (b.charAt(i - 1) == a.charAt(j - 1)) {
31448 matrix[i][j] = matrix[i - 1][j - 1];
31449 } else {
31450 matrix[i][j] = Math.min(matrix[i - 1][j - 1] + 1, // substitution
31451 Math.min(matrix[i][j - 1] + 1, // insertion
31452 matrix[i - 1][j] + 1)); // deletion
31453 }
31454 }
31455 }
31456
31457 return matrix[b.length][a.length];
31458 }
31459 }]);
31460
31461 return Validator;
31462 }();
31463
31464 /**
31465 * A node. A node can be connected to other nodes via one or multiple edges.
31466 */
31467
31468 var Node =
31469 /*#__PURE__*/
31470 function () {
31471 /**
31472 *
31473 * @param {object} options An object containing options for the node. All
31474 * options are optional, except for the id.
31475 * {number} id Id of the node. Required
31476 * {string} label Text label for the node
31477 * {number} x Horizontal position of the node
31478 * {number} y Vertical position of the node
31479 * {string} shape Node shape
31480 * {string} image An image url
31481 * {string} title A title text, can be HTML
31482 * {anytype} group A group name or number
31483 *
31484 * @param {Object} body Shared state of current network instance
31485 * @param {Network.Images} imagelist A list with images. Only needed when the node has an image
31486 * @param {Groups} grouplist A list with groups. Needed for retrieving group options
31487 * @param {Object} globalOptions Current global node options; these serve as defaults for the node instance
31488 * @param {Object} defaultOptions Global default options for nodes; note that this is also the prototype
31489 * for parameter `globalOptions`.
31490 */
31491 function Node(options, body, imagelist, grouplist, globalOptions, defaultOptions) {
31492 _classCallCheck(this, Node);
31493
31494 this.options = bridgeObject(globalOptions);
31495 this.globalOptions = globalOptions;
31496 this.defaultOptions = defaultOptions;
31497 this.body = body;
31498 this.edges = []; // all edges connected to this node
31499 // set defaults for the options
31500
31501 this.id = undefined;
31502 this.imagelist = imagelist;
31503 this.grouplist = grouplist; // state options
31504
31505 this.x = undefined;
31506 this.y = undefined;
31507 this.baseSize = this.options.size;
31508 this.baseFontSize = this.options.font.size;
31509 this.predefinedPosition = false; // used to check if initial fit should just take the range or approximate
31510
31511 this.selected = false;
31512 this.hover = false;
31513 this.labelModule = new Label(this.body, this.options, false
31514 /* Not edge label */
31515 );
31516 this.setOptions(options);
31517 }
31518 /**
31519 * Attach a edge to the node
31520 * @param {Edge} edge
31521 */
31522
31523
31524 _createClass(Node, [{
31525 key: "attachEdge",
31526 value: function attachEdge(edge) {
31527 if (this.edges.indexOf(edge) === -1) {
31528 this.edges.push(edge);
31529 }
31530 }
31531 /**
31532 * Detach a edge from the node
31533 *
31534 * @param {Edge} edge
31535 */
31536
31537 }, {
31538 key: "detachEdge",
31539 value: function detachEdge(edge) {
31540 var index = this.edges.indexOf(edge);
31541
31542 if (index != -1) {
31543 this.edges.splice(index, 1);
31544 }
31545 }
31546 /**
31547 * Set or overwrite options for the node
31548 *
31549 * @param {Object} options an object with options
31550 * @returns {null|boolean}
31551 */
31552
31553 }, {
31554 key: "setOptions",
31555 value: function setOptions(options) {
31556 var currentShape = this.options.shape;
31557
31558 if (!options) {
31559 return; // Note that the return value will be 'undefined'! This is OK.
31560 } // Save the color for later.
31561 // This is necessary in order to prevent local color from being overwritten by group color.
31562 // TODO: To prevent such workarounds the way options are handled should be rewritten from scratch.
31563 // This is not the only problem with current options handling.
31564
31565
31566 if (typeof options.color !== 'undefined') {
31567 this._localColor = options.color;
31568 } // basic options
31569
31570
31571 if (options.id !== undefined) {
31572 this.id = options.id;
31573 }
31574
31575 if (this.id === undefined) {
31576 throw new Error("Node must have an id");
31577 }
31578
31579 Node.checkMass(options, this.id); // set these options locally
31580 // clear x and y positions
31581
31582 if (options.x !== undefined) {
31583 if (options.x === null) {
31584 this.x = undefined;
31585 this.predefinedPosition = false;
31586 } else {
31587 this.x = parseInt(options.x);
31588 this.predefinedPosition = true;
31589 }
31590 }
31591
31592 if (options.y !== undefined) {
31593 if (options.y === null) {
31594 this.y = undefined;
31595 this.predefinedPosition = false;
31596 } else {
31597 this.y = parseInt(options.y);
31598 this.predefinedPosition = true;
31599 }
31600 }
31601
31602 if (options.size !== undefined) {
31603 this.baseSize = options.size;
31604 }
31605
31606 if (options.value !== undefined) {
31607 options.value = parseFloat(options.value);
31608 } // this transforms all shorthands into fully defined options
31609
31610
31611 Node.parseOptions(this.options, options, true, this.globalOptions, this.grouplist);
31612 var pile = [options, this.options, this.defaultOptions];
31613 this.chooser = ComponentUtil.choosify('node', pile);
31614
31615 this._load_images();
31616
31617 this.updateLabelModule(options);
31618 this.updateShape(currentShape);
31619 return options.hidden !== undefined || options.physics !== undefined;
31620 }
31621 /**
31622 * Load the images from the options, for the nodes that need them.
31623 *
31624 * Images are always loaded, even if they are not used in the current shape.
31625 * The user may switch to an image shape later on.
31626 *
31627 * @private
31628 */
31629
31630 }, {
31631 key: "_load_images",
31632 value: function _load_images() {
31633 if (this.options.shape === 'circularImage' || this.options.shape === 'image') {
31634 if (this.options.image === undefined) {
31635 throw new Error("Option image must be defined for node type '" + this.options.shape + "'");
31636 }
31637 }
31638
31639 if (this.options.image === undefined) {
31640 return;
31641 }
31642
31643 if (this.imagelist === undefined) {
31644 throw new Error("Internal Error: No images provided");
31645 }
31646
31647 if (typeof this.options.image === 'string') {
31648 this.imageObj = this.imagelist.load(this.options.image, this.options.brokenImage, this.id);
31649 } else {
31650 if (this.options.image.unselected === undefined) {
31651 throw new Error("No unselected image provided");
31652 }
31653
31654 this.imageObj = this.imagelist.load(this.options.image.unselected, this.options.brokenImage, this.id);
31655
31656 if (this.options.image.selected !== undefined) {
31657 this.imageObjAlt = this.imagelist.load(this.options.image.selected, this.options.brokenImage, this.id);
31658 } else {
31659 this.imageObjAlt = undefined;
31660 }
31661 }
31662 }
31663 /**
31664 * Copy group option values into the node options.
31665 *
31666 * The group options override the global node options, so the copy of group options
31667 * must happen *after* the global node options have been set.
31668 *
31669 * This method must also be called also if the global node options have changed and the group options did not.
31670 *
31671 * @param {Object} parentOptions
31672 * @param {Object} newOptions new values for the options, currently only passed in for check
31673 * @param {Object} groupList
31674 */
31675
31676 }, {
31677 key: "getFormattingValues",
31678
31679 /**
31680 *
31681 * @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: *}}
31682 */
31683 value: function getFormattingValues() {
31684 var values = {
31685 color: this.options.color.background,
31686 borderWidth: this.options.borderWidth,
31687 borderColor: this.options.color.border,
31688 size: this.options.size,
31689 borderDashes: this.options.shapeProperties.borderDashes,
31690 borderRadius: this.options.shapeProperties.borderRadius,
31691 shadow: this.options.shadow.enabled,
31692 shadowColor: this.options.shadow.color,
31693 shadowSize: this.options.shadow.size,
31694 shadowX: this.options.shadow.x,
31695 shadowY: this.options.shadow.y
31696 };
31697
31698 if (this.selected || this.hover) {
31699 if (this.chooser === true) {
31700 if (this.selected) {
31701 values.borderWidth *= 2;
31702 values.color = this.options.color.highlight.background;
31703 values.borderColor = this.options.color.highlight.border;
31704 values.shadow = this.options.shadow.enabled;
31705 } else if (this.hover) {
31706 values.color = this.options.color.hover.background;
31707 values.borderColor = this.options.color.hover.border;
31708 values.shadow = this.options.shadow.enabled;
31709 }
31710 } else if (typeof this.chooser === 'function') {
31711 this.chooser(values, this.options.id, this.selected, this.hover);
31712
31713 if (values.shadow === false) {
31714 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) {
31715 values.shadow = true;
31716 }
31717 }
31718 }
31719 } else {
31720 values.shadow = this.options.shadow.enabled;
31721 }
31722
31723 return values;
31724 }
31725 /**
31726 *
31727 * @param {Object} options
31728 */
31729
31730 }, {
31731 key: "updateLabelModule",
31732 value: function updateLabelModule(options) {
31733 if (this.options.label === undefined || this.options.label === null) {
31734 this.options.label = '';
31735 }
31736
31737 Node.updateGroupOptions(this.options, _objectSpread2$1({}, options, {
31738 color: options && options.color || this._localColor || undefined
31739 }), this.grouplist); //
31740 // Note:The prototype chain for this.options is:
31741 //
31742 // this.options -> NodesHandler.options -> NodesHandler.defaultOptions
31743 // (also: this.globalOptions)
31744 //
31745 // Note that the prototypes are mentioned explicitly in the pile list below;
31746 // WE DON'T WANT THE ORDER OF THE PROTOTYPES!!!! At least, not for font handling of labels.
31747 // This is a good indication that the prototype usage of options is deficient.
31748 //
31749
31750 var currentGroup = this.grouplist.get(this.options.group, false);
31751 var pile = [options, // new options
31752 this.options, // current node options, see comment above for prototype
31753 currentGroup, // group options, if any
31754 this.globalOptions, // Currently set global node options
31755 this.defaultOptions // Default global node options
31756 ];
31757 this.labelModule.update(this.options, pile);
31758
31759 if (this.labelModule.baseSize !== undefined) {
31760 this.baseFontSize = this.labelModule.baseSize;
31761 }
31762 }
31763 /**
31764 *
31765 * @param {string} currentShape
31766 */
31767
31768 }, {
31769 key: "updateShape",
31770 value: function updateShape(currentShape) {
31771 if (currentShape === this.options.shape && this.shape) {
31772 this.shape.setOptions(this.options, this.imageObj, this.imageObjAlt);
31773 } else {
31774 // choose draw method depending on the shape
31775 switch (this.options.shape) {
31776 case 'box':
31777 this.shape = new Box(this.options, this.body, this.labelModule);
31778 break;
31779
31780 case 'circle':
31781 this.shape = new Circle(this.options, this.body, this.labelModule);
31782 break;
31783
31784 case 'circularImage':
31785 this.shape = new CircularImage(this.options, this.body, this.labelModule, this.imageObj, this.imageObjAlt);
31786 break;
31787
31788 case 'database':
31789 this.shape = new Database(this.options, this.body, this.labelModule);
31790 break;
31791
31792 case 'diamond':
31793 this.shape = new Diamond(this.options, this.body, this.labelModule);
31794 break;
31795
31796 case 'dot':
31797 this.shape = new Dot(this.options, this.body, this.labelModule);
31798 break;
31799
31800 case 'ellipse':
31801 this.shape = new Ellipse(this.options, this.body, this.labelModule);
31802 break;
31803
31804 case 'icon':
31805 this.shape = new Icon(this.options, this.body, this.labelModule);
31806 break;
31807
31808 case 'image':
31809 this.shape = new Image$1(this.options, this.body, this.labelModule, this.imageObj, this.imageObjAlt);
31810 break;
31811
31812 case 'square':
31813 this.shape = new Square(this.options, this.body, this.labelModule);
31814 break;
31815
31816 case 'hexagon':
31817 this.shape = new Hexagon(this.options, this.body, this.labelModule);
31818 break;
31819
31820 case 'star':
31821 this.shape = new Star(this.options, this.body, this.labelModule);
31822 break;
31823
31824 case 'text':
31825 this.shape = new Text(this.options, this.body, this.labelModule);
31826 break;
31827
31828 case 'triangle':
31829 this.shape = new Triangle(this.options, this.body, this.labelModule);
31830 break;
31831
31832 case 'triangleDown':
31833 this.shape = new TriangleDown(this.options, this.body, this.labelModule);
31834 break;
31835
31836 default:
31837 this.shape = new Ellipse(this.options, this.body, this.labelModule);
31838 break;
31839 }
31840 }
31841
31842 this.needsRefresh();
31843 }
31844 /**
31845 * select this node
31846 */
31847
31848 }, {
31849 key: "select",
31850 value: function select() {
31851 this.selected = true;
31852 this.needsRefresh();
31853 }
31854 /**
31855 * unselect this node
31856 */
31857
31858 }, {
31859 key: "unselect",
31860 value: function unselect() {
31861 this.selected = false;
31862 this.needsRefresh();
31863 }
31864 /**
31865 * Reset the calculated size of the node, forces it to recalculate its size
31866 */
31867
31868 }, {
31869 key: "needsRefresh",
31870 value: function needsRefresh() {
31871 this.shape.refreshNeeded = true;
31872 }
31873 /**
31874 * get the title of this node.
31875 * @return {string} title The title of the node, or undefined when no title
31876 * has been set.
31877 */
31878
31879 }, {
31880 key: "getTitle",
31881 value: function getTitle() {
31882 return this.options.title;
31883 }
31884 /**
31885 * Calculate the distance to the border of the Node
31886 * @param {CanvasRenderingContext2D} ctx
31887 * @param {number} angle Angle in radians
31888 * @returns {number} distance Distance to the border in pixels
31889 */
31890
31891 }, {
31892 key: "distanceToBorder",
31893 value: function distanceToBorder(ctx, angle) {
31894 return this.shape.distanceToBorder(ctx, angle);
31895 }
31896 /**
31897 * Check if this node has a fixed x and y position
31898 * @return {boolean} true if fixed, false if not
31899 */
31900
31901 }, {
31902 key: "isFixed",
31903 value: function isFixed() {
31904 return this.options.fixed.x && this.options.fixed.y;
31905 }
31906 /**
31907 * check if this node is selecte
31908 * @return {boolean} selected True if node is selected, else false
31909 */
31910
31911 }, {
31912 key: "isSelected",
31913 value: function isSelected() {
31914 return this.selected;
31915 }
31916 /**
31917 * Retrieve the value of the node. Can be undefined
31918 * @return {number} value
31919 */
31920
31921 }, {
31922 key: "getValue",
31923 value: function getValue() {
31924 return this.options.value;
31925 }
31926 /**
31927 * Get the current dimensions of the label
31928 *
31929 * @return {rect}
31930 */
31931
31932 }, {
31933 key: "getLabelSize",
31934 value: function getLabelSize() {
31935 return this.labelModule.size();
31936 }
31937 /**
31938 * Adjust the value range of the node. The node will adjust it's size
31939 * based on its value.
31940 * @param {number} min
31941 * @param {number} max
31942 * @param {number} total
31943 */
31944
31945 }, {
31946 key: "setValueRange",
31947 value: function setValueRange(min, max, total) {
31948 if (this.options.value !== undefined) {
31949 var scale = this.options.scaling.customScalingFunction(min, max, total, this.options.value);
31950 var sizeDiff = this.options.scaling.max - this.options.scaling.min;
31951
31952 if (this.options.scaling.label.enabled === true) {
31953 var fontDiff = this.options.scaling.label.max - this.options.scaling.label.min;
31954 this.options.font.size = this.options.scaling.label.min + scale * fontDiff;
31955 }
31956
31957 this.options.size = this.options.scaling.min + scale * sizeDiff;
31958 } else {
31959 this.options.size = this.baseSize;
31960 this.options.font.size = this.baseFontSize;
31961 }
31962
31963 this.updateLabelModule();
31964 }
31965 /**
31966 * Draw this node in the given canvas
31967 * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d");
31968 * @param {CanvasRenderingContext2D} ctx
31969 */
31970
31971 }, {
31972 key: "draw",
31973 value: function draw(ctx) {
31974 var values = this.getFormattingValues();
31975 this.shape.draw(ctx, this.x, this.y, this.selected, this.hover, values);
31976 }
31977 /**
31978 * Update the bounding box of the shape
31979 * @param {CanvasRenderingContext2D} ctx
31980 */
31981
31982 }, {
31983 key: "updateBoundingBox",
31984 value: function updateBoundingBox(ctx) {
31985 this.shape.updateBoundingBox(this.x, this.y, ctx);
31986 }
31987 /**
31988 * Recalculate the size of this node in the given canvas
31989 * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d");
31990 * @param {CanvasRenderingContext2D} ctx
31991 */
31992
31993 }, {
31994 key: "resize",
31995 value: function resize(ctx) {
31996 var values = this.getFormattingValues();
31997 this.shape.resize(ctx, this.selected, this.hover, values);
31998 }
31999 /**
32000 * Determine all visual elements of this node instance, in which the given
32001 * point falls within the bounding shape.
32002 *
32003 * @param {point} point
32004 * @returns {Array.<nodeClickItem|nodeLabelClickItem>} list with the items which are on the point
32005 */
32006
32007 }, {
32008 key: "getItemsOnPoint",
32009 value: function getItemsOnPoint(point) {
32010 var ret = [];
32011
32012 if (this.labelModule.visible()) {
32013 if (ComponentUtil.pointInRect(this.labelModule.getSize(), point)) {
32014 ret.push({
32015 nodeId: this.id,
32016 labelId: 0
32017 });
32018 }
32019 }
32020
32021 if (ComponentUtil.pointInRect(this.shape.boundingBox, point)) {
32022 ret.push({
32023 nodeId: this.id
32024 });
32025 }
32026
32027 return ret;
32028 }
32029 /**
32030 * Check if this object is overlapping with the provided object
32031 * @param {Object} obj an object with parameters left, top, right, bottom
32032 * @return {boolean} True if location is located on node
32033 */
32034
32035 }, {
32036 key: "isOverlappingWith",
32037 value: function isOverlappingWith(obj) {
32038 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;
32039 }
32040 /**
32041 * Check if this object is overlapping with the provided object
32042 * @param {Object} obj an object with parameters left, top, right, bottom
32043 * @return {boolean} True if location is located on node
32044 */
32045
32046 }, {
32047 key: "isBoundingBoxOverlappingWith",
32048 value: function isBoundingBoxOverlappingWith(obj) {
32049 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;
32050 }
32051 /**
32052 * Check valid values for mass
32053 *
32054 * The mass may not be negative or zero. If it is, reset to 1
32055 *
32056 * @param {object} options
32057 * @param {Node.id} id
32058 * @static
32059 */
32060
32061 }], [{
32062 key: "updateGroupOptions",
32063 value: function updateGroupOptions(parentOptions, newOptions, groupList) {
32064 if (groupList === undefined) return; // No groups, nothing to do
32065
32066 var group = parentOptions.group; // paranoia: the selected group is already merged into node options, check.
32067
32068 if (newOptions !== undefined && newOptions.group !== undefined && group !== newOptions.group) {
32069 throw new Error("updateGroupOptions: group values in options don't match.");
32070 }
32071
32072 var hasGroup = typeof group === 'number' || typeof group === 'string' && group != '';
32073 if (!hasGroup) return; // current node has no group, no need to merge
32074
32075 var groupObj = groupList.get(group); // Skip merging of group font options into parent; these are required to be distinct for labels
32076 // Also skip mergin of color IF it is already defined in the node itself. This is to avoid the color of the
32077 // group overriding the color set at the node level
32078 // TODO: It might not be a good idea either to merge the rest of the options, investigate this.
32079
32080 var skipProperties = ['font'];
32081 if (newOptions !== undefined && newOptions.color !== undefined && newOptions.color != null) skipProperties.push('color');
32082 selectiveNotDeepExtend(skipProperties, parentOptions, groupObj); // the color object needs to be completely defined.
32083 // Since groups can partially overwrite the colors, we parse it again, just in case.
32084
32085 parentOptions.color = parseColor(parentOptions.color);
32086 }
32087 /**
32088 * This process all possible shorthands in the new options and makes sure that the parentOptions are fully defined.
32089 * Static so it can also be used by the handler.
32090 *
32091 * @param {Object} parentOptions
32092 * @param {Object} newOptions
32093 * @param {boolean} [allowDeletion=false]
32094 * @param {Object} [globalOptions={}]
32095 * @param {Object} [groupList]
32096 * @static
32097 */
32098
32099 }, {
32100 key: "parseOptions",
32101 value: function parseOptions(parentOptions, newOptions) {
32102 var allowDeletion = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
32103 var globalOptions = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
32104 var groupList = arguments.length > 4 ? arguments[4] : undefined;
32105 var fields = ['color', 'fixed', 'shadow'];
32106 selectiveNotDeepExtend(fields, parentOptions, newOptions, allowDeletion);
32107 Node.checkMass(newOptions); // merge the shadow options into the parent.
32108
32109 mergeOptions(parentOptions, newOptions, 'shadow', globalOptions); // individual shape newOptions
32110
32111 if (newOptions.color !== undefined && newOptions.color !== null) {
32112 var parsedColor = parseColor(newOptions.color);
32113 fillIfDefined(parentOptions.color, parsedColor);
32114 } else if (allowDeletion === true && newOptions.color === null) {
32115 parentOptions.color = bridgeObject(globalOptions.color); // set the object back to the global options
32116 } // handle the fixed options
32117
32118
32119 if (newOptions.fixed !== undefined && newOptions.fixed !== null) {
32120 if (typeof newOptions.fixed === 'boolean') {
32121 parentOptions.fixed.x = newOptions.fixed;
32122 parentOptions.fixed.y = newOptions.fixed;
32123 } else {
32124 if (newOptions.fixed.x !== undefined && typeof newOptions.fixed.x === 'boolean') {
32125 parentOptions.fixed.x = newOptions.fixed.x;
32126 }
32127
32128 if (newOptions.fixed.y !== undefined && typeof newOptions.fixed.y === 'boolean') {
32129 parentOptions.fixed.y = newOptions.fixed.y;
32130 }
32131 }
32132 }
32133
32134 if (allowDeletion === true && newOptions.font === null) {
32135 parentOptions.font = bridgeObject(globalOptions.font); // set the object back to the global options
32136 }
32137
32138 Node.updateGroupOptions(parentOptions, newOptions, groupList); // handle the scaling options, specifically the label part
32139
32140 if (newOptions.scaling !== undefined) {
32141 mergeOptions(parentOptions.scaling, newOptions.scaling, 'label', globalOptions.scaling);
32142 }
32143 }
32144 }, {
32145 key: "checkMass",
32146 value: function checkMass(options, id) {
32147 if (options.mass !== undefined && options.mass <= 0) {
32148 var strId = '';
32149
32150 if (id !== undefined) {
32151 strId = ' in node id: ' + id;
32152 }
32153
32154 console.log('%cNegative or zero mass disallowed' + strId + ', setting mass to 1.', printStyle);
32155 options.mass = 1;
32156 }
32157 }
32158 }]);
32159
32160 return Node;
32161 }();
32162
32163 /**
32164 * Handler for Nodes
32165 */
32166
32167 var NodesHandler =
32168 /*#__PURE__*/
32169 function () {
32170 /**
32171 * @param {Object} body
32172 * @param {Images} images
32173 * @param {Array.<Group>} groups
32174 * @param {LayoutEngine} layoutEngine
32175 */
32176 function NodesHandler(body, images, groups, layoutEngine) {
32177 var _this = this;
32178
32179 _classCallCheck(this, NodesHandler);
32180
32181 this.body = body;
32182 this.images = images;
32183 this.groups = groups;
32184 this.layoutEngine = layoutEngine; // create the node API in the body container
32185
32186 this.body.functions.createNode = this.create.bind(this);
32187 this.nodesListeners = {
32188 add: function add(event, params) {
32189 _this.add(params.items);
32190 },
32191 update: function update(event, params) {
32192 _this.update(params.items, params.data, params.oldData);
32193 },
32194 remove: function remove(event, params) {
32195 _this.remove(params.items);
32196 }
32197 };
32198 this.defaultOptions = {
32199 borderWidth: 1,
32200 borderWidthSelected: 2,
32201 brokenImage: undefined,
32202 color: {
32203 border: '#2B7CE9',
32204 background: '#97C2FC',
32205 highlight: {
32206 border: '#2B7CE9',
32207 background: '#D2E5FF'
32208 },
32209 hover: {
32210 border: '#2B7CE9',
32211 background: '#D2E5FF'
32212 }
32213 },
32214 fixed: {
32215 x: false,
32216 y: false
32217 },
32218 font: {
32219 color: '#343434',
32220 size: 14,
32221 // px
32222 face: 'arial',
32223 background: 'none',
32224 strokeWidth: 0,
32225 // px
32226 strokeColor: '#ffffff',
32227 align: 'center',
32228 vadjust: 0,
32229 multi: false,
32230 bold: {
32231 mod: 'bold'
32232 },
32233 boldital: {
32234 mod: 'bold italic'
32235 },
32236 ital: {
32237 mod: 'italic'
32238 },
32239 mono: {
32240 mod: '',
32241 size: 15,
32242 // px
32243 face: 'monospace',
32244 vadjust: 2
32245 }
32246 },
32247 group: undefined,
32248 hidden: false,
32249 icon: {
32250 face: 'FontAwesome',
32251 //'FontAwesome',
32252 code: undefined,
32253 //'\uf007',
32254 size: 50,
32255 //50,
32256 color: '#2B7CE9' //'#aa00ff'
32257
32258 },
32259 image: undefined,
32260 // --> URL
32261 imagePadding: {
32262 // only for image shape
32263 top: 0,
32264 right: 0,
32265 bottom: 0,
32266 left: 0
32267 },
32268 label: undefined,
32269 labelHighlightBold: true,
32270 level: undefined,
32271 margin: {
32272 top: 5,
32273 right: 5,
32274 bottom: 5,
32275 left: 5
32276 },
32277 mass: 1,
32278 physics: true,
32279 scaling: {
32280 min: 10,
32281 max: 30,
32282 label: {
32283 enabled: false,
32284 min: 14,
32285 max: 30,
32286 maxVisible: 30,
32287 drawThreshold: 5
32288 },
32289 customScalingFunction: function customScalingFunction(min, max, total, value) {
32290 if (max === min) {
32291 return 0.5;
32292 } else {
32293 var scale = 1 / (max - min);
32294 return Math.max(0, (value - min) * scale);
32295 }
32296 }
32297 },
32298 shadow: {
32299 enabled: false,
32300 color: 'rgba(0,0,0,0.5)',
32301 size: 10,
32302 x: 5,
32303 y: 5
32304 },
32305 shape: 'ellipse',
32306 shapeProperties: {
32307 borderDashes: false,
32308 // only for borders
32309 borderRadius: 6,
32310 // only for box shape
32311 interpolation: true,
32312 // only for image and circularImage shapes
32313 useImageSize: false,
32314 // only for image and circularImage shapes
32315 useBorderWithImage: false // only for image shape
32316
32317 },
32318 size: 25,
32319 title: undefined,
32320 value: undefined,
32321 x: undefined,
32322 y: undefined
32323 }; // Protect from idiocy
32324
32325 if (this.defaultOptions.mass <= 0) {
32326 throw 'Internal error: mass in defaultOptions of NodesHandler may not be zero or negative';
32327 }
32328
32329 this.options = bridgeObject(this.defaultOptions);
32330 this.bindEventListeners();
32331 }
32332 /**
32333 * Binds event listeners
32334 */
32335
32336
32337 _createClass(NodesHandler, [{
32338 key: "bindEventListeners",
32339 value: function bindEventListeners() {
32340 var _this2 = this;
32341
32342 // refresh the nodes. Used when reverting from hierarchical layout
32343 this.body.emitter.on('refreshNodes', this.refresh.bind(this));
32344 this.body.emitter.on('refresh', this.refresh.bind(this));
32345 this.body.emitter.on('destroy', function () {
32346 forEach(_this2.nodesListeners, function (callback, event) {
32347 if (_this2.body.data.nodes) _this2.body.data.nodes.off(event, callback);
32348 });
32349 delete _this2.body.functions.createNode;
32350 delete _this2.nodesListeners.add;
32351 delete _this2.nodesListeners.update;
32352 delete _this2.nodesListeners.remove;
32353 delete _this2.nodesListeners;
32354 });
32355 }
32356 /**
32357 *
32358 * @param {Object} options
32359 */
32360
32361 }, {
32362 key: "setOptions",
32363 value: function setOptions(options) {
32364 if (options !== undefined) {
32365 Node.parseOptions(this.options, options); // update the shape in all nodes
32366
32367 if (options.shape !== undefined) {
32368 for (var nodeId in this.body.nodes) {
32369 if (this.body.nodes.hasOwnProperty(nodeId)) {
32370 this.body.nodes[nodeId].updateShape();
32371 }
32372 }
32373 } // update the font in all nodes
32374
32375
32376 if (options.font !== undefined) {
32377 for (var _nodeId in this.body.nodes) {
32378 if (this.body.nodes.hasOwnProperty(_nodeId)) {
32379 this.body.nodes[_nodeId].updateLabelModule();
32380
32381 this.body.nodes[_nodeId].needsRefresh();
32382 }
32383 }
32384 } // update the shape size in all nodes
32385
32386
32387 if (options.size !== undefined) {
32388 for (var _nodeId2 in this.body.nodes) {
32389 if (this.body.nodes.hasOwnProperty(_nodeId2)) {
32390 this.body.nodes[_nodeId2].needsRefresh();
32391 }
32392 }
32393 } // update the state of the variables if needed
32394
32395
32396 if (options.hidden !== undefined || options.physics !== undefined) {
32397 this.body.emitter.emit('_dataChanged');
32398 }
32399 }
32400 }
32401 /**
32402 * Set a data set with nodes for the network
32403 * @param {Array | DataSet | DataView} nodes The data containing the nodes.
32404 * @param {boolean} [doNotEmit=false]
32405 * @private
32406 */
32407
32408 }, {
32409 key: "setData",
32410 value: function setData(nodes) {
32411 var doNotEmit = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
32412 var oldNodesData = this.body.data.nodes;
32413
32414 if (nodes instanceof DataSet || nodes instanceof DataView$2) {
32415 this.body.data.nodes = nodes;
32416 } else if (Array.isArray(nodes)) {
32417 this.body.data.nodes = new DataSet();
32418 this.body.data.nodes.add(nodes);
32419 } else if (!nodes) {
32420 this.body.data.nodes = new DataSet();
32421 } else {
32422 throw new TypeError('Array or DataSet expected');
32423 }
32424
32425 if (oldNodesData) {
32426 // unsubscribe from old dataset
32427 forEach(this.nodesListeners, function (callback, event) {
32428 oldNodesData.off(event, callback);
32429 });
32430 } // remove drawn nodes
32431
32432
32433 this.body.nodes = {};
32434
32435 if (this.body.data.nodes) {
32436 // subscribe to new dataset
32437 var me = this;
32438 forEach(this.nodesListeners, function (callback, event) {
32439 me.body.data.nodes.on(event, callback);
32440 }); // draw all new nodes
32441
32442 var ids = this.body.data.nodes.getIds();
32443 this.add(ids, true);
32444 }
32445
32446 if (doNotEmit === false) {
32447 this.body.emitter.emit("_dataChanged");
32448 }
32449 }
32450 /**
32451 * Add nodes
32452 * @param {number[] | string[]} ids
32453 * @param {boolean} [doNotEmit=false]
32454 * @private
32455 */
32456
32457 }, {
32458 key: "add",
32459 value: function add(ids) {
32460 var doNotEmit = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
32461 var id;
32462 var newNodes = [];
32463
32464 for (var i = 0; i < ids.length; i++) {
32465 id = ids[i];
32466 var properties = this.body.data.nodes.get(id);
32467 var node = this.create(properties);
32468 newNodes.push(node);
32469 this.body.nodes[id] = node; // note: this may replace an existing node
32470 }
32471
32472 this.layoutEngine.positionInitially(newNodes);
32473
32474 if (doNotEmit === false) {
32475 this.body.emitter.emit("_dataChanged");
32476 }
32477 }
32478 /**
32479 * Update existing nodes, or create them when not yet existing
32480 * @param {number[] | string[]} ids id's of changed nodes
32481 * @param {Array} changedData array with changed data
32482 * @param {Array|undefined} oldData optional; array with previous data
32483 * @private
32484 */
32485
32486 }, {
32487 key: "update",
32488 value: function update(ids, changedData, oldData) {
32489 var nodes = this.body.nodes;
32490 var dataChanged = false;
32491
32492 for (var i = 0; i < ids.length; i++) {
32493 var id = ids[i];
32494 var node = nodes[id];
32495 var data = changedData[i];
32496
32497 if (node !== undefined) {
32498 // update node
32499 if (node.setOptions(data)) {
32500 dataChanged = true;
32501 }
32502 } else {
32503 dataChanged = true; // create node
32504
32505 node = this.create(data);
32506 nodes[id] = node;
32507 }
32508 }
32509
32510 if (!dataChanged && oldData !== undefined) {
32511 // Check for any changes which should trigger a layout recalculation
32512 // For now, this is just 'level' for hierarchical layout
32513 // Assumption: old and new data arranged in same order; at time of writing, this holds.
32514 dataChanged = changedData.some(function (newValue, index) {
32515 var oldValue = oldData[index];
32516 return oldValue && oldValue.level !== newValue.level;
32517 });
32518 }
32519
32520 if (dataChanged === true) {
32521 this.body.emitter.emit("_dataChanged");
32522 } else {
32523 this.body.emitter.emit("_dataUpdated");
32524 }
32525 }
32526 /**
32527 * Remove existing nodes. If nodes do not exist, the method will just ignore it.
32528 * @param {number[] | string[]} ids
32529 * @private
32530 */
32531
32532 }, {
32533 key: "remove",
32534 value: function remove(ids) {
32535 var nodes = this.body.nodes;
32536
32537 for (var i = 0; i < ids.length; i++) {
32538 var id = ids[i];
32539 delete nodes[id];
32540 }
32541
32542 this.body.emitter.emit("_dataChanged");
32543 }
32544 /**
32545 * create a node
32546 * @param {Object} properties
32547 * @param {class} [constructorClass=Node.default]
32548 * @returns {*}
32549 */
32550
32551 }, {
32552 key: "create",
32553 value: function create(properties) {
32554 var constructorClass = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : Node;
32555 return new constructorClass(properties, this.body, this.images, this.groups, this.options, this.defaultOptions);
32556 }
32557 /**
32558 *
32559 * @param {boolean} [clearPositions=false]
32560 */
32561
32562 }, {
32563 key: "refresh",
32564 value: function refresh() {
32565 var _this3 = this;
32566
32567 var clearPositions = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
32568 forEach(this.body.nodes, function (node, nodeId) {
32569 var data = _this3.body.data.nodes.get(nodeId);
32570
32571 if (data !== undefined) {
32572 if (clearPositions === true) {
32573 node.setOptions({
32574 x: null,
32575 y: null
32576 });
32577 }
32578
32579 node.setOptions({
32580 fixed: false
32581 });
32582 node.setOptions(data);
32583 }
32584 });
32585 }
32586 /**
32587 * Returns the positions of the nodes.
32588 * @param {Array.<Node.id>|String} [ids] --> optional, can be array of nodeIds, can be string
32589 * @returns {{}}
32590 */
32591
32592 }, {
32593 key: "getPositions",
32594 value: function getPositions(ids) {
32595 var dataArray = {};
32596
32597 if (ids !== undefined) {
32598 if (Array.isArray(ids) === true) {
32599 for (var i = 0; i < ids.length; i++) {
32600 if (this.body.nodes[ids[i]] !== undefined) {
32601 var node = this.body.nodes[ids[i]];
32602 dataArray[ids[i]] = {
32603 x: Math.round(node.x),
32604 y: Math.round(node.y)
32605 };
32606 }
32607 }
32608 } else {
32609 if (this.body.nodes[ids] !== undefined) {
32610 var _node = this.body.nodes[ids];
32611 dataArray[ids] = {
32612 x: Math.round(_node.x),
32613 y: Math.round(_node.y)
32614 };
32615 }
32616 }
32617 } else {
32618 for (var _i = 0; _i < this.body.nodeIndices.length; _i++) {
32619 var _node2 = this.body.nodes[this.body.nodeIndices[_i]];
32620 dataArray[this.body.nodeIndices[_i]] = {
32621 x: Math.round(_node2.x),
32622 y: Math.round(_node2.y)
32623 };
32624 }
32625 }
32626
32627 return dataArray;
32628 }
32629 /**
32630 * Load the XY positions of the nodes into the dataset.
32631 */
32632
32633 }, {
32634 key: "storePositions",
32635 value: function storePositions() {
32636 // todo: add support for clusters and hierarchical.
32637 var dataArray = [];
32638 var dataset = this.body.data.nodes.getDataSet();
32639
32640 for (var nodeId in dataset._data) {
32641 if (dataset._data.hasOwnProperty(nodeId)) {
32642 var node = this.body.nodes[nodeId];
32643
32644 if (dataset._data[nodeId].x != Math.round(node.x) || dataset._data[nodeId].y != Math.round(node.y)) {
32645 dataArray.push({
32646 id: node.id,
32647 x: Math.round(node.x),
32648 y: Math.round(node.y)
32649 });
32650 }
32651 }
32652 }
32653
32654 dataset.update(dataArray);
32655 }
32656 /**
32657 * get the bounding box of a node.
32658 * @param {Node.id} nodeId
32659 * @returns {j|*}
32660 */
32661
32662 }, {
32663 key: "getBoundingBox",
32664 value: function getBoundingBox(nodeId) {
32665 if (this.body.nodes[nodeId] !== undefined) {
32666 return this.body.nodes[nodeId].shape.boundingBox;
32667 }
32668 }
32669 /**
32670 * Get the Ids of nodes connected to this node.
32671 * @param {Node.id} nodeId
32672 * @param {'to'|'from'|undefined} direction values 'from' and 'to' select respectively parent and child nodes only.
32673 * Any other value returns both parent and child nodes.
32674 * @returns {Array}
32675 */
32676
32677 }, {
32678 key: "getConnectedNodes",
32679 value: function getConnectedNodes(nodeId, direction) {
32680 var nodeList = [];
32681
32682 if (this.body.nodes[nodeId] !== undefined) {
32683 var node = this.body.nodes[nodeId];
32684 var nodeObj = {}; // used to quickly check if node already exists
32685
32686 for (var i = 0; i < node.edges.length; i++) {
32687 var edge = node.edges[i];
32688
32689 if (direction !== 'to' && edge.toId == node.id) {
32690 // these are double equals since ids can be numeric or string
32691 if (nodeObj[edge.fromId] === undefined) {
32692 nodeList.push(edge.fromId);
32693 nodeObj[edge.fromId] = true;
32694 }
32695 } else if (direction !== 'from' && edge.fromId == node.id) {
32696 // these are double equals since ids can be numeric or string
32697 if (nodeObj[edge.toId] === undefined) {
32698 nodeList.push(edge.toId);
32699 nodeObj[edge.toId] = true;
32700 }
32701 }
32702 }
32703 }
32704
32705 return nodeList;
32706 }
32707 /**
32708 * Get the ids of the edges connected to this node.
32709 * @param {Node.id} nodeId
32710 * @returns {*}
32711 */
32712
32713 }, {
32714 key: "getConnectedEdges",
32715 value: function getConnectedEdges(nodeId) {
32716 var edgeList = [];
32717
32718 if (this.body.nodes[nodeId] !== undefined) {
32719 var node = this.body.nodes[nodeId];
32720
32721 for (var i = 0; i < node.edges.length; i++) {
32722 edgeList.push(node.edges[i].id);
32723 }
32724 } else {
32725 console.log("NodeId provided for getConnectedEdges does not exist. Provided: ", nodeId);
32726 }
32727
32728 return edgeList;
32729 }
32730 /**
32731 * Move a node.
32732 *
32733 * @param {Node.id} nodeId
32734 * @param {number} x
32735 * @param {number} y
32736 */
32737
32738 }, {
32739 key: "moveNode",
32740 value: function moveNode(nodeId, x, y) {
32741 var _this4 = this;
32742
32743 if (this.body.nodes[nodeId] !== undefined) {
32744 this.body.nodes[nodeId].x = Number(x);
32745 this.body.nodes[nodeId].y = Number(y);
32746 setTimeout(function () {
32747 _this4.body.emitter.emit("startSimulation");
32748 }, 0);
32749 } else {
32750 console.log("Node id supplied to moveNode does not exist. Provided: ", nodeId);
32751 }
32752 }
32753 }]);
32754
32755 return NodesHandler;
32756 }();
32757
32758 var $hypot = Math.hypot;
32759 var abs$2 = Math.abs;
32760 var sqrt = Math.sqrt; // Chrome 77 bug
32761 // https://bugs.chromium.org/p/v8/issues/detail?id=9546
32762
32763 var BUGGY$1 = !!$hypot && $hypot(Infinity, NaN) !== Infinity; // `Math.hypot` method
32764 // https://tc39.github.io/ecma262/#sec-math.hypot
32765
32766 _export({
32767 target: 'Math',
32768 stat: true,
32769 forced: BUGGY$1
32770 }, {
32771 hypot: function hypot(value1, value2) {
32772 // eslint-disable-line no-unused-vars
32773 var sum = 0;
32774 var i = 0;
32775 var aLen = arguments.length;
32776 var larg = 0;
32777 var arg, div;
32778
32779 while (i < aLen) {
32780 arg = abs$2(arguments[i++]);
32781
32782 if (larg < arg) {
32783 div = larg / arg;
32784 sum = sum * div * div + 1;
32785 larg = arg;
32786 } else if (arg > 0) {
32787 div = arg / larg;
32788 sum += div * div;
32789 } else sum += arg;
32790 }
32791
32792 return larg === Infinity ? Infinity : larg * sqrt(sum);
32793 }
32794 });
32795
32796 /** ============================================================================
32797 * Location of all the endpoint drawing routines.
32798 *
32799 * Every endpoint has its own drawing routine, which contains an endpoint definition.
32800 *
32801 * The endpoint definitions must have the following properies:
32802 *
32803 * - (0,0) is the connection point to the node it attaches to
32804 * - The endpoints are orientated to the positive x-direction
32805 * - The length of the endpoint is at most 1
32806 *
32807 * As long as the endpoint classes remain simple and not too numerous, they will
32808 * be contained within this module.
32809 * All classes here except `EndPoints` should be considered as private to this module.
32810 *
32811 * -----------------------------------------------------------------------------
32812 * ### Further Actions
32813 *
32814 * After adding a new endpoint here, you also need to do the following things:
32815 *
32816 * - Add the new endpoint name to `network/options.js` in array `endPoints`.
32817 * - Add the new endpoint name to the documentation.
32818 * Scan for 'arrows.to.type` and add it to the description.
32819 * - Add the endpoint to the examples. At the very least, add it to example
32820 * `edgeStyles/arrowTypes`.
32821 * ============================================================================= */
32822
32823 /**
32824 * Common methods for endpoints
32825 *
32826 * @class
32827 */
32828 var EndPoint =
32829 /*#__PURE__*/
32830 function () {
32831 function EndPoint() {
32832 _classCallCheck(this, EndPoint);
32833 }
32834
32835 _createClass(EndPoint, null, [{
32836 key: "transform",
32837
32838 /**
32839 * Apply transformation on points for display.
32840 *
32841 * The following is done:
32842 * - rotate by the specified angle
32843 * - multiply the (normalized) coordinates by the passed length
32844 * - offset by the target coordinates
32845 *
32846 * @param points - The point(s) to be transformed.
32847 * @param arrowData - The data determining the result of the transformation.
32848 */
32849 value: function transform(points, arrowData) {
32850 if (!Array.isArray(points)) {
32851 points = [points];
32852 }
32853
32854 var x = arrowData.point.x;
32855 var y = arrowData.point.y;
32856 var angle = arrowData.angle;
32857 var length = arrowData.length;
32858
32859 for (var i = 0; i < points.length; ++i) {
32860 var p = points[i];
32861 var xt = p.x * Math.cos(angle) - p.y * Math.sin(angle);
32862 var yt = p.x * Math.sin(angle) + p.y * Math.cos(angle);
32863 p.x = x + length * xt;
32864 p.y = y + length * yt;
32865 }
32866 }
32867 /**
32868 * Draw a closed path using the given real coordinates.
32869 *
32870 * @param ctx - The path will be rendered into this context.
32871 * @param points - The points of the path.
32872 */
32873
32874 }, {
32875 key: "drawPath",
32876 value: function drawPath(ctx, points) {
32877 ctx.beginPath();
32878 ctx.moveTo(points[0].x, points[0].y);
32879
32880 for (var i = 1; i < points.length; ++i) {
32881 ctx.lineTo(points[i].x, points[i].y);
32882 }
32883
32884 ctx.closePath();
32885 }
32886 }]);
32887
32888 return EndPoint;
32889 }();
32890 /**
32891 * Drawing methods for the arrow endpoint.
32892 */
32893
32894
32895 var Image$2 =
32896 /*#__PURE__*/
32897 function (_EndPoint) {
32898 _inherits(Image, _EndPoint);
32899
32900 function Image() {
32901 _classCallCheck(this, Image);
32902
32903 return _possibleConstructorReturn(this, _getPrototypeOf(Image).apply(this, arguments));
32904 }
32905
32906 _createClass(Image, null, [{
32907 key: "draw",
32908
32909 /**
32910 * Draw this shape at the end of a line.
32911 *
32912 * @param ctx - The shape will be rendered into this context.
32913 * @param arrowData - The data determining the shape.
32914 *
32915 * @returns False as there is no way to fill an image.
32916 */
32917 value: function draw(ctx, arrowData) {
32918 if (arrowData.image) {
32919 ctx.save();
32920 ctx.translate(arrowData.point.x, arrowData.point.y);
32921 ctx.rotate(Math.PI / 2 + arrowData.angle);
32922 var width = arrowData.imageWidth != null ? arrowData.imageWidth : arrowData.image.width;
32923 var height = arrowData.imageHeight != null ? arrowData.imageHeight : arrowData.image.height;
32924 arrowData.image.drawImageAtPosition(ctx, 1, // scale
32925 -width / 2, // x
32926 0, // y
32927 width, height);
32928 ctx.restore();
32929 }
32930
32931 return false;
32932 }
32933 }]);
32934
32935 return Image;
32936 }(EndPoint);
32937 /**
32938 * Drawing methods for the arrow endpoint.
32939 */
32940
32941
32942 var Arrow =
32943 /*#__PURE__*/
32944 function (_EndPoint2) {
32945 _inherits(Arrow, _EndPoint2);
32946
32947 function Arrow() {
32948 _classCallCheck(this, Arrow);
32949
32950 return _possibleConstructorReturn(this, _getPrototypeOf(Arrow).apply(this, arguments));
32951 }
32952
32953 _createClass(Arrow, null, [{
32954 key: "draw",
32955
32956 /**
32957 * Draw this shape at the end of a line.
32958 *
32959 * @param ctx - The shape will be rendered into this context.
32960 * @param arrowData - The data determining the shape.
32961 *
32962 * @returns True because ctx.fill() can be used to fill the arrow.
32963 */
32964 value: function draw(ctx, arrowData) {
32965 // Normalized points of closed path, in the order that they should be drawn.
32966 // (0, 0) is the attachment point, and the point around which should be rotated
32967 var points = [{
32968 x: 0,
32969 y: 0
32970 }, {
32971 x: -1,
32972 y: 0.3
32973 }, {
32974 x: -0.9,
32975 y: 0
32976 }, {
32977 x: -1,
32978 y: -0.3
32979 }];
32980 EndPoint.transform(points, arrowData);
32981 EndPoint.drawPath(ctx, points);
32982 return true;
32983 }
32984 }]);
32985
32986 return Arrow;
32987 }(EndPoint);
32988 /**
32989 * Drawing methods for the crow endpoint.
32990 */
32991
32992
32993 var Crow =
32994 /*#__PURE__*/
32995 function () {
32996 function Crow() {
32997 _classCallCheck(this, Crow);
32998 }
32999
33000 _createClass(Crow, null, [{
33001 key: "draw",
33002
33003 /**
33004 * Draw this shape at the end of a line.
33005 *
33006 * @param ctx - The shape will be rendered into this context.
33007 * @param arrowData - The data determining the shape.
33008 *
33009 * @returns True because ctx.fill() can be used to fill the arrow.
33010 */
33011 value: function draw(ctx, arrowData) {
33012 // Normalized points of closed path, in the order that they should be drawn.
33013 // (0, 0) is the attachment point, and the point around which should be rotated
33014 var points = [{
33015 x: -1,
33016 y: 0
33017 }, {
33018 x: 0,
33019 y: 0.3
33020 }, {
33021 x: -0.4,
33022 y: 0
33023 }, {
33024 x: 0,
33025 y: -0.3
33026 }];
33027 EndPoint.transform(points, arrowData);
33028 EndPoint.drawPath(ctx, points);
33029 return true;
33030 }
33031 }]);
33032
33033 return Crow;
33034 }();
33035 /**
33036 * Drawing methods for the curve endpoint.
33037 */
33038
33039
33040 var Curve =
33041 /*#__PURE__*/
33042 function () {
33043 function Curve() {
33044 _classCallCheck(this, Curve);
33045 }
33046
33047 _createClass(Curve, null, [{
33048 key: "draw",
33049
33050 /**
33051 * Draw this shape at the end of a line.
33052 *
33053 * @param ctx - The shape will be rendered into this context.
33054 * @param arrowData - The data determining the shape.
33055 *
33056 * @returns True because ctx.fill() can be used to fill the arrow.
33057 */
33058 value: function draw(ctx, arrowData) {
33059 // Normalized points of closed path, in the order that they should be drawn.
33060 // (0, 0) is the attachment point, and the point around which should be rotated
33061 var point = {
33062 x: -0.4,
33063 y: 0
33064 };
33065 EndPoint.transform(point, arrowData); // Update endpoint style for drawing transparent arc.
33066
33067 ctx.strokeStyle = ctx.fillStyle;
33068 ctx.fillStyle = "rgba(0, 0, 0, 0)"; // Define curve endpoint as semicircle.
33069
33070 var pi = Math.PI;
33071 var startAngle = arrowData.angle - pi / 2;
33072 var endAngle = arrowData.angle + pi / 2;
33073 ctx.beginPath();
33074 ctx.arc(point.x, point.y, arrowData.length * 0.4, startAngle, endAngle, false);
33075 ctx.stroke();
33076 return true;
33077 }
33078 }]);
33079
33080 return Curve;
33081 }();
33082 /**
33083 * Drawing methods for the inverted curve endpoint.
33084 */
33085
33086
33087 var InvertedCurve =
33088 /*#__PURE__*/
33089 function () {
33090 function InvertedCurve() {
33091 _classCallCheck(this, InvertedCurve);
33092 }
33093
33094 _createClass(InvertedCurve, null, [{
33095 key: "draw",
33096
33097 /**
33098 * Draw this shape at the end of a line.
33099 *
33100 * @param ctx - The shape will be rendered into this context.
33101 * @param arrowData - The data determining the shape.
33102 *
33103 * @returns True because ctx.fill() can be used to fill the arrow.
33104 */
33105 value: function draw(ctx, arrowData) {
33106 // Normalized points of closed path, in the order that they should be drawn.
33107 // (0, 0) is the attachment point, and the point around which should be rotated
33108 var point = {
33109 x: -0.3,
33110 y: 0
33111 };
33112 EndPoint.transform(point, arrowData); // Update endpoint style for drawing transparent arc.
33113
33114 ctx.strokeStyle = ctx.fillStyle;
33115 ctx.fillStyle = "rgba(0, 0, 0, 0)"; // Define inverted curve endpoint as semicircle.
33116
33117 var pi = Math.PI;
33118 var startAngle = arrowData.angle + pi / 2;
33119 var endAngle = arrowData.angle + 3 * pi / 2;
33120 ctx.beginPath();
33121 ctx.arc(point.x, point.y, arrowData.length * 0.4, startAngle, endAngle, false);
33122 ctx.stroke();
33123 return true;
33124 }
33125 }]);
33126
33127 return InvertedCurve;
33128 }();
33129 /**
33130 * Drawing methods for the trinagle endpoint.
33131 */
33132
33133
33134 var Triangle$1 =
33135 /*#__PURE__*/
33136 function () {
33137 function Triangle() {
33138 _classCallCheck(this, Triangle);
33139 }
33140
33141 _createClass(Triangle, null, [{
33142 key: "draw",
33143
33144 /**
33145 * Draw this shape at the end of a line.
33146 *
33147 * @param ctx - The shape will be rendered into this context.
33148 * @param arrowData - The data determining the shape.
33149 *
33150 * @returns True because ctx.fill() can be used to fill the arrow.
33151 */
33152 value: function draw(ctx, arrowData) {
33153 // Normalized points of closed path, in the order that they should be drawn.
33154 // (0, 0) is the attachment point, and the point around which should be rotated
33155 var points = [{
33156 x: 0.02,
33157 y: 0
33158 }, {
33159 x: -1,
33160 y: 0.3
33161 }, {
33162 x: -1,
33163 y: -0.3
33164 }];
33165 EndPoint.transform(points, arrowData);
33166 EndPoint.drawPath(ctx, points);
33167 return true;
33168 }
33169 }]);
33170
33171 return Triangle;
33172 }();
33173 /**
33174 * Drawing methods for the inverted trinagle endpoint.
33175 */
33176
33177
33178 var InvertedTriangle =
33179 /*#__PURE__*/
33180 function () {
33181 function InvertedTriangle() {
33182 _classCallCheck(this, InvertedTriangle);
33183 }
33184
33185 _createClass(InvertedTriangle, null, [{
33186 key: "draw",
33187
33188 /**
33189 * Draw this shape at the end of a line.
33190 *
33191 * @param ctx - The shape will be rendered into this context.
33192 * @param arrowData - The data determining the shape.
33193 *
33194 * @returns True because ctx.fill() can be used to fill the arrow.
33195 */
33196 value: function draw(ctx, arrowData) {
33197 // Normalized points of closed path, in the order that they should be drawn.
33198 // (0, 0) is the attachment point, and the point around which should be rotated
33199 var points = [{
33200 x: 0,
33201 y: 0.3
33202 }, {
33203 x: 0,
33204 y: -0.3
33205 }, {
33206 x: -1,
33207 y: 0
33208 }];
33209 EndPoint.transform(points, arrowData);
33210 EndPoint.drawPath(ctx, points);
33211 return true;
33212 }
33213 }]);
33214
33215 return InvertedTriangle;
33216 }();
33217 /**
33218 * Drawing methods for the circle endpoint.
33219 */
33220
33221
33222 var Circle$1 =
33223 /*#__PURE__*/
33224 function () {
33225 function Circle() {
33226 _classCallCheck(this, Circle);
33227 }
33228
33229 _createClass(Circle, null, [{
33230 key: "draw",
33231
33232 /**
33233 * Draw this shape at the end of a line.
33234 *
33235 * @param ctx - The shape will be rendered into this context.
33236 * @param arrowData - The data determining the shape.
33237 *
33238 * @returns True because ctx.fill() can be used to fill the arrow.
33239 */
33240 value: function draw(ctx, arrowData) {
33241 var point = {
33242 x: -0.4,
33243 y: 0
33244 };
33245 EndPoint.transform(point, arrowData);
33246 ctx.circle(point.x, point.y, arrowData.length * 0.4);
33247 return true;
33248 }
33249 }]);
33250
33251 return Circle;
33252 }();
33253 /**
33254 * Drawing methods for the bar endpoint.
33255 */
33256
33257
33258 var Bar =
33259 /*#__PURE__*/
33260 function () {
33261 function Bar() {
33262 _classCallCheck(this, Bar);
33263 }
33264
33265 _createClass(Bar, null, [{
33266 key: "draw",
33267
33268 /**
33269 * Draw this shape at the end of a line.
33270 *
33271 * @param ctx - The shape will be rendered into this context.
33272 * @param arrowData - The data determining the shape.
33273 *
33274 * @returns True because ctx.fill() can be used to fill the arrow.
33275 */
33276 value: function draw(ctx, arrowData) {
33277 /*
33278 var points = [
33279 {x:0, y:0.5},
33280 {x:0, y:-0.5}
33281 ];
33282 EndPoint.transform(points, arrowData);
33283 ctx.beginPath();
33284 ctx.moveTo(points[0].x, points[0].y);
33285 ctx.lineTo(points[1].x, points[1].y);
33286 ctx.stroke();
33287 */
33288 var points = [{
33289 x: 0,
33290 y: 0.5
33291 }, {
33292 x: 0,
33293 y: -0.5
33294 }, {
33295 x: -0.15,
33296 y: -0.5
33297 }, {
33298 x: -0.15,
33299 y: 0.5
33300 }];
33301 EndPoint.transform(points, arrowData);
33302 EndPoint.drawPath(ctx, points);
33303 return true;
33304 }
33305 }]);
33306
33307 return Bar;
33308 }();
33309 /**
33310 * Drawing methods for the box endpoint.
33311 */
33312
33313
33314 var Box$1 =
33315 /*#__PURE__*/
33316 function () {
33317 function Box() {
33318 _classCallCheck(this, Box);
33319 }
33320
33321 _createClass(Box, null, [{
33322 key: "draw",
33323
33324 /**
33325 * Draw this shape at the end of a line.
33326 *
33327 * @param ctx - The shape will be rendered into this context.
33328 * @param arrowData - The data determining the shape.
33329 *
33330 * @returns True because ctx.fill() can be used to fill the arrow.
33331 */
33332 value: function draw(ctx, arrowData) {
33333 var points = [{
33334 x: 0,
33335 y: 0.3
33336 }, {
33337 x: 0,
33338 y: -0.3
33339 }, {
33340 x: -0.6,
33341 y: -0.3
33342 }, {
33343 x: -0.6,
33344 y: 0.3
33345 }];
33346 EndPoint.transform(points, arrowData);
33347 EndPoint.drawPath(ctx, points);
33348 return true;
33349 }
33350 }]);
33351
33352 return Box;
33353 }();
33354 /**
33355 * Drawing methods for the diamond endpoint.
33356 */
33357
33358
33359 var Diamond$1 =
33360 /*#__PURE__*/
33361 function () {
33362 function Diamond() {
33363 _classCallCheck(this, Diamond);
33364 }
33365
33366 _createClass(Diamond, null, [{
33367 key: "draw",
33368
33369 /**
33370 * Draw this shape at the end of a line.
33371 *
33372 * @param ctx - The shape will be rendered into this context.
33373 * @param arrowData - The data determining the shape.
33374 *
33375 * @returns True because ctx.fill() can be used to fill the arrow.
33376 */
33377 value: function draw(ctx, arrowData) {
33378 var points = [{
33379 x: 0,
33380 y: 0
33381 }, {
33382 x: -0.5,
33383 y: -0.3
33384 }, {
33385 x: -1,
33386 y: 0
33387 }, {
33388 x: -0.5,
33389 y: 0.3
33390 }];
33391 EndPoint.transform(points, arrowData);
33392 EndPoint.drawPath(ctx, points);
33393 return true;
33394 }
33395 }]);
33396
33397 return Diamond;
33398 }();
33399 /**
33400 * Drawing methods for the vee endpoint.
33401 */
33402
33403
33404 var Vee =
33405 /*#__PURE__*/
33406 function () {
33407 function Vee() {
33408 _classCallCheck(this, Vee);
33409 }
33410
33411 _createClass(Vee, null, [{
33412 key: "draw",
33413
33414 /**
33415 * Draw this shape at the end of a line.
33416 *
33417 * @param ctx - The shape will be rendered into this context.
33418 * @param arrowData - The data determining the shape.
33419 *
33420 * @returns True because ctx.fill() can be used to fill the arrow.
33421 */
33422 value: function draw(ctx, arrowData) {
33423 // Normalized points of closed path, in the order that they should be drawn.
33424 // (0, 0) is the attachment point, and the point around which should be rotated
33425 var points = [{
33426 x: -1,
33427 y: 0.3
33428 }, {
33429 x: -0.5,
33430 y: 0
33431 }, {
33432 x: -1,
33433 y: -0.3
33434 }, {
33435 x: 0,
33436 y: 0
33437 }];
33438 EndPoint.transform(points, arrowData);
33439 EndPoint.drawPath(ctx, points);
33440 return true;
33441 }
33442 }]);
33443
33444 return Vee;
33445 }();
33446 /**
33447 * Drawing methods for the endpoints.
33448 */
33449
33450
33451 var EndPoints =
33452 /*#__PURE__*/
33453 function () {
33454 function EndPoints() {
33455 _classCallCheck(this, EndPoints);
33456 }
33457
33458 _createClass(EndPoints, null, [{
33459 key: "draw",
33460
33461 /**
33462 * Draw an endpoint.
33463 *
33464 * @param ctx - The shape will be rendered into this context.
33465 * @param arrowData - The data determining the shape.
33466 *
33467 * @returns True if ctx.fill() can be used to fill the arrow, false otherwise.
33468 */
33469 value: function draw(ctx, arrowData) {
33470 var type;
33471
33472 if (arrowData.type) {
33473 type = arrowData.type.toLowerCase();
33474 }
33475
33476 switch (type) {
33477 case "image":
33478 return Image$2.draw(ctx, arrowData);
33479
33480 case "circle":
33481 return Circle$1.draw(ctx, arrowData);
33482
33483 case "box":
33484 return Box$1.draw(ctx, arrowData);
33485
33486 case "crow":
33487 return Crow.draw(ctx, arrowData);
33488
33489 case "curve":
33490 return Curve.draw(ctx, arrowData);
33491
33492 case "diamond":
33493 return Diamond$1.draw(ctx, arrowData);
33494
33495 case "inv_curve":
33496 return InvertedCurve.draw(ctx, arrowData);
33497
33498 case "triangle":
33499 return Triangle$1.draw(ctx, arrowData);
33500
33501 case "inv_triangle":
33502 return InvertedTriangle.draw(ctx, arrowData);
33503
33504 case "bar":
33505 return Bar.draw(ctx, arrowData);
33506
33507 case "vee":
33508 return Vee.draw(ctx, arrowData);
33509
33510 case "arrow": // fall-through
33511
33512 default:
33513 return Arrow.draw(ctx, arrowData);
33514 }
33515 }
33516 }]);
33517
33518 return EndPoints;
33519 }();
33520
33521 /**
33522 * The Base Class for all edges.
33523 */
33524
33525 var EdgeBase =
33526 /*#__PURE__*/
33527 function () {
33528 /**
33529 * Create a new instance.
33530 *
33531 * @param options - The options object of given edge.
33532 * @param _body - The body of the network.
33533 * @param _labelModule - Label module.
33534 */
33535 function EdgeBase(options, _body, _labelModule) {
33536 _classCallCheck(this, EdgeBase);
33537
33538 this._body = _body;
33539 this._labelModule = _labelModule;
33540 this.color = {};
33541 this.colorDirty = true;
33542 this.hoverWidth = 1.5;
33543 this.selectionWidth = 2;
33544 this.setOptions(options);
33545 this.fromPoint = this.from;
33546 this.toPoint = this.to;
33547 }
33548 /** @inheritdoc */
33549
33550
33551 _createClass(EdgeBase, [{
33552 key: "connect",
33553 value: function connect() {
33554 this.from = this._body.nodes[this.options.from];
33555 this.to = this._body.nodes[this.options.to];
33556 }
33557 /** @inheritdoc */
33558
33559 }, {
33560 key: "cleanup",
33561 value: function cleanup() {
33562 return false;
33563 }
33564 /**
33565 * Set new edge options.
33566 *
33567 * @param options - The new edge options object.
33568 */
33569
33570 }, {
33571 key: "setOptions",
33572 value: function setOptions(options) {
33573 this.options = options;
33574 this.from = this._body.nodes[this.options.from];
33575 this.to = this._body.nodes[this.options.to];
33576 this.id = this.options.id;
33577 }
33578 /** @inheritdoc */
33579
33580 }, {
33581 key: "drawLine",
33582 value: function drawLine(ctx, values, _selected, _hover) {
33583 var viaNode = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : this.getViaNode();
33584 // set style
33585 ctx.strokeStyle = this.getColor(ctx, values);
33586 ctx.lineWidth = values.width;
33587
33588 if (values.dashes !== false) {
33589 this._drawDashedLine(ctx, values, viaNode);
33590 } else {
33591 this._drawLine(ctx, values, viaNode);
33592 }
33593 }
33594 /**
33595 * Draw a line with given style between two nodes through supplied node(s).
33596 *
33597 * @param ctx - The context that will be used for rendering.
33598 * @param values - Formatting values like color, opacity or shadow.
33599 * @param viaNode - Additional control point(s) for the edge.
33600 * @param fromPoint - TODO: Seems ignored, remove?
33601 * @param toPoint - TODO: Seems ignored, remove?
33602 */
33603
33604 }, {
33605 key: "_drawLine",
33606 value: function _drawLine(ctx, values, viaNode, fromPoint, toPoint) {
33607 if (this.from != this.to) {
33608 // draw line
33609 this._line(ctx, values, viaNode, fromPoint, toPoint);
33610 } else {
33611 var _this$_getCircleData = this._getCircleData(ctx),
33612 _this$_getCircleData2 = _slicedToArray(_this$_getCircleData, 3),
33613 x = _this$_getCircleData2[0],
33614 y = _this$_getCircleData2[1],
33615 radius = _this$_getCircleData2[2];
33616
33617 this._circle(ctx, values, x, y, radius);
33618 }
33619 }
33620 /**
33621 * Draw a dashed line with given style between two nodes through supplied node(s).
33622 *
33623 * @param ctx - The context that will be used for rendering.
33624 * @param values - Formatting values like color, opacity or shadow.
33625 * @param viaNode - Additional control point(s) for the edge.
33626 * @param _fromPoint - Ignored (TODO: remove in the future).
33627 * @param _toPoint - Ignored (TODO: remove in the future).
33628 */
33629
33630 }, {
33631 key: "_drawDashedLine",
33632 value: function _drawDashedLine(ctx, values, viaNode, _fromPoint, _toPoint) {
33633 ctx.lineCap = "round";
33634 var pattern = Array.isArray(values.dashes) ? values.dashes : [5, 5]; // only firefox and chrome support this method, else we use the legacy one.
33635
33636 if (ctx.setLineDash !== undefined) {
33637 ctx.save(); // set dash settings for chrome or firefox
33638
33639 ctx.setLineDash(pattern);
33640 ctx.lineDashOffset = 0; // draw the line
33641
33642 if (this.from != this.to) {
33643 // draw line
33644 this._line(ctx, values, viaNode);
33645 } else {
33646 var _this$_getCircleData3 = this._getCircleData(ctx),
33647 _this$_getCircleData4 = _slicedToArray(_this$_getCircleData3, 3),
33648 x = _this$_getCircleData4[0],
33649 y = _this$_getCircleData4[1],
33650 radius = _this$_getCircleData4[2];
33651
33652 this._circle(ctx, values, x, y, radius);
33653 } // restore the dash settings.
33654
33655
33656 ctx.setLineDash([0]);
33657 ctx.lineDashOffset = 0;
33658 ctx.restore();
33659 } else {
33660 // unsupporting smooth lines
33661 if (this.from != this.to) {
33662 // draw line
33663 ctx.dashedLine(this.from.x, this.from.y, this.to.x, this.to.y, pattern);
33664 } else {
33665 var _this$_getCircleData5 = this._getCircleData(ctx),
33666 _this$_getCircleData6 = _slicedToArray(_this$_getCircleData5, 3),
33667 _x = _this$_getCircleData6[0],
33668 _y = _this$_getCircleData6[1],
33669 _radius = _this$_getCircleData6[2];
33670
33671 this._circle(ctx, values, _x, _y, _radius);
33672 } // draw shadow if enabled
33673
33674
33675 this.enableShadow(ctx, values);
33676 ctx.stroke(); // disable shadows for other elements.
33677
33678 this.disableShadow(ctx, values);
33679 }
33680 }
33681 /**
33682 * Find the intersection between the border of the node and the edge.
33683 *
33684 * @param node - The node (either from or to node of the edge).
33685 * @param ctx - The context that will be used for rendering.
33686 * @param options - Additional options.
33687 *
33688 * @returns Cartesian coordinates of the intersection between the border of the node and the edge.
33689 */
33690
33691 }, {
33692 key: "findBorderPosition",
33693 value: function findBorderPosition(node, ctx, options) {
33694 if (this.from != this.to) {
33695 return this._findBorderPosition(node, ctx, options);
33696 } else {
33697 return this._findBorderPositionCircle(node, ctx, options);
33698 }
33699 }
33700 /** @inheritdoc */
33701
33702 }, {
33703 key: "findBorderPositions",
33704 value: function findBorderPositions(ctx) {
33705 if (this.from != this.to) {
33706 return {
33707 from: this._findBorderPosition(this.from, ctx),
33708 to: this._findBorderPosition(this.to, ctx)
33709 };
33710 } else {
33711 var _this$_getCircleData$ = this._getCircleData(ctx).slice(0, 2),
33712 _this$_getCircleData$2 = _slicedToArray(_this$_getCircleData$, 2),
33713 x = _this$_getCircleData$2[0],
33714 y = _this$_getCircleData$2[1];
33715
33716 return {
33717 from: this._findBorderPositionCircle(this.from, ctx, {
33718 x: x,
33719 y: y,
33720 low: 0.25,
33721 high: 0.6,
33722 direction: -1
33723 }),
33724 to: this._findBorderPositionCircle(this.from, ctx, {
33725 x: x,
33726 y: y,
33727 low: 0.6,
33728 high: 0.8,
33729 direction: 1
33730 })
33731 };
33732 }
33733 }
33734 /**
33735 * Compute the center point and radius of an edge connected to the same node at both ends.
33736 *
33737 * @param ctx - The context that will be used for rendering.
33738 *
33739 * @returns `[x, y, radius]`
33740 */
33741
33742 }, {
33743 key: "_getCircleData",
33744 value: function _getCircleData(ctx) {
33745 var x;
33746 var y;
33747 var node = this.from;
33748 var radius = this.options.selfReferenceSize;
33749
33750 if (ctx !== undefined) {
33751 if (node.shape.width === undefined) {
33752 node.shape.resize(ctx);
33753 }
33754 } // get circle coordinates
33755
33756
33757 if (node.shape.width > node.shape.height) {
33758 x = node.x + node.shape.width * 0.5;
33759 y = node.y - radius;
33760 } else {
33761 x = node.x + radius;
33762 y = node.y - node.shape.height * 0.5;
33763 }
33764
33765 return [x, y, radius];
33766 }
33767 /**
33768 * Get a point on a circle.
33769 *
33770 * @param x - Center of the circle on the x axis.
33771 * @param y - Center of the circle on the y axis.
33772 * @param radius - Radius of the circle.
33773 * @param position - Value between 0 (line start) and 1 (line end).
33774 *
33775 * @returns Cartesian coordinates of requested point on the circle.
33776 */
33777
33778 }, {
33779 key: "_pointOnCircle",
33780 value: function _pointOnCircle(x, y, radius, position) {
33781 var angle = position * 2 * Math.PI;
33782 return {
33783 x: x + radius * Math.cos(angle),
33784 y: y - radius * Math.sin(angle)
33785 };
33786 }
33787 /**
33788 * Find the intersection between the border of the node and the edge.
33789 *
33790 * @remarks
33791 * This function uses binary search to look for the point where the circle crosses the border of the node.
33792 *
33793 * @param nearNode - The node (either from or to node of the edge).
33794 * @param ctx - The context that will be used for rendering.
33795 * @param options - Additional options.
33796 *
33797 * @returns Cartesian coordinates of the intersection between the border of the node and the edge.
33798 */
33799
33800 }, {
33801 key: "_findBorderPositionCircle",
33802 value: function _findBorderPositionCircle(nearNode, ctx, options) {
33803 var x = options.x;
33804 var y = options.y;
33805 var low = options.low;
33806 var high = options.high;
33807 var direction = options.direction;
33808 var maxIterations = 10;
33809 var radius = this.options.selfReferenceSize;
33810 var threshold = 0.05;
33811 var pos;
33812 var middle = (low + high) * 0.5;
33813 var iteration = 0;
33814
33815 do {
33816 middle = (low + high) * 0.5;
33817 pos = this._pointOnCircle(x, y, radius, middle);
33818 var angle = Math.atan2(nearNode.y - pos.y, nearNode.x - pos.x);
33819 var distanceToBorder = nearNode.distanceToBorder(ctx, angle);
33820 var distanceToPoint = Math.sqrt(Math.pow(pos.x - nearNode.x, 2) + Math.pow(pos.y - nearNode.y, 2));
33821 var difference = distanceToBorder - distanceToPoint;
33822
33823 if (Math.abs(difference) < threshold) {
33824 break; // found
33825 } else if (difference > 0) {
33826 // distance to nodes is larger than distance to border --> t needs to be bigger if we're looking at the to node.
33827 if (direction > 0) {
33828 low = middle;
33829 } else {
33830 high = middle;
33831 }
33832 } else {
33833 if (direction > 0) {
33834 high = middle;
33835 } else {
33836 low = middle;
33837 }
33838 }
33839
33840 ++iteration;
33841 } while (low <= high && iteration < maxIterations);
33842
33843 return _objectSpread2$1({}, pos, {
33844 t: middle
33845 });
33846 }
33847 /**
33848 * Get the line width of the edge. Depends on width and whether one of the connected nodes is selected.
33849 *
33850 * @param selected - Determines wheter the line is selected.
33851 * @param hover - Determines wheter the line is being hovered, only applies if selected is false.
33852 *
33853 * @returns The width of the line.
33854 */
33855
33856 }, {
33857 key: "getLineWidth",
33858 value: function getLineWidth(selected, hover) {
33859 if (selected === true) {
33860 return Math.max(this.selectionWidth, 0.3 / this._body.view.scale);
33861 } else if (hover === true) {
33862 return Math.max(this.hoverWidth, 0.3 / this._body.view.scale);
33863 } else {
33864 return Math.max(this.options.width, 0.3 / this._body.view.scale);
33865 }
33866 }
33867 /**
33868 * Compute the color or gradient for given edge.
33869 *
33870 * @param ctx - The context that will be used for rendering.
33871 * @param values - Formatting values like color, opacity or shadow.
33872 * @param _selected - Ignored (TODO: remove in the future).
33873 * @param _hover - Ignored (TODO: remove in the future).
33874 *
33875 * @returns Color string if single color is inherited or gradient if two.
33876 */
33877
33878 }, {
33879 key: "getColor",
33880 value: function getColor(ctx, values) {
33881 if (values.inheritsColor !== false) {
33882 // when this is a loop edge, just use the 'from' method
33883 if (values.inheritsColor === "both" && this.from.id !== this.to.id) {
33884 var grd = ctx.createLinearGradient(this.from.x, this.from.y, this.to.x, this.to.y);
33885 var fromColor = this.from.options.color.highlight.border;
33886 var toColor = this.to.options.color.highlight.border;
33887
33888 if (this.from.selected === false && this.to.selected === false) {
33889 fromColor = overrideOpacity(this.from.options.color.border, values.opacity);
33890 toColor = overrideOpacity(this.to.options.color.border, values.opacity);
33891 } else if (this.from.selected === true && this.to.selected === false) {
33892 toColor = this.to.options.color.border;
33893 } else if (this.from.selected === false && this.to.selected === true) {
33894 fromColor = this.from.options.color.border;
33895 }
33896
33897 grd.addColorStop(0, fromColor);
33898 grd.addColorStop(1, toColor); // -------------------- this returns -------------------- //
33899
33900 return grd;
33901 }
33902
33903 if (values.inheritsColor === "to") {
33904 return overrideOpacity(this.to.options.color.border, values.opacity);
33905 } else {
33906 // "from"
33907 return overrideOpacity(this.from.options.color.border, values.opacity);
33908 }
33909 } else {
33910 return overrideOpacity(values.color, values.opacity);
33911 }
33912 }
33913 /**
33914 * Draw a line from a node to itself, a circle.
33915 *
33916 * @param ctx - The context that will be used for rendering.
33917 * @param values - Formatting values like color, opacity or shadow.
33918 * @param x - Center of the circle on the x axis.
33919 * @param y - Center of the circle on the y axis.
33920 * @param radius - Radius of the circle.
33921 */
33922
33923 }, {
33924 key: "_circle",
33925 value: function _circle(ctx, values, x, y, radius) {
33926 // draw shadow if enabled
33927 this.enableShadow(ctx, values); // draw a circle
33928
33929 ctx.beginPath();
33930 ctx.arc(x, y, radius, 0, 2 * Math.PI, false);
33931 ctx.stroke(); // disable shadows for other elements.
33932
33933 this.disableShadow(ctx, values);
33934 }
33935 /**
33936 * @inheritdoc
33937 *
33938 * @remarks
33939 * http://stackoverflow.com/questions/849211/shortest-distancae-between-a-point-and-a-line-segment
33940 */
33941
33942 }, {
33943 key: "getDistanceToEdge",
33944 value: function getDistanceToEdge(x1, y1, x2, y2, x3, y3) {
33945 if (this.from != this.to) {
33946 return this._getDistanceToEdge(x1, y1, x2, y2, x3, y3);
33947 } else {
33948 var _this$_getCircleData7 = this._getCircleData(undefined),
33949 _this$_getCircleData8 = _slicedToArray(_this$_getCircleData7, 3),
33950 x = _this$_getCircleData8[0],
33951 y = _this$_getCircleData8[1],
33952 radius = _this$_getCircleData8[2];
33953
33954 var dx = x - x3;
33955 var dy = y - y3;
33956 return Math.abs(Math.sqrt(dx * dx + dy * dy) - radius);
33957 }
33958 }
33959 /**
33960 * Calculate the distance between a point (x3, y3) and a line segment from (x1, y1) to (x2, y2).
33961 *
33962 * @param x1 - First end of the line segment on the x axis.
33963 * @param y1 - First end of the line segment on the y axis.
33964 * @param x2 - Second end of the line segment on the x axis.
33965 * @param y2 - Second end of the line segment on the y axis.
33966 * @param x3 - Position of the point on the x axis.
33967 * @param y3 - Position of the point on the y axis.
33968 *
33969 * @returns The distance between the line segment and the point.
33970 */
33971
33972 }, {
33973 key: "_getDistanceToLine",
33974 value: function _getDistanceToLine(x1, y1, x2, y2, x3, y3) {
33975 var px = x2 - x1;
33976 var py = y2 - y1;
33977 var something = px * px + py * py;
33978 var u = ((x3 - x1) * px + (y3 - y1) * py) / something;
33979
33980 if (u > 1) {
33981 u = 1;
33982 } else if (u < 0) {
33983 u = 0;
33984 }
33985
33986 var x = x1 + u * px;
33987 var y = y1 + u * py;
33988 var dx = x - x3;
33989 var dy = y - y3; //# Note: If the actual distance does not matter,
33990 //# if you only want to compare what this function
33991 //# returns to other results of this function, you
33992 //# can just return the squared distance instead
33993 //# (i.e. remove the sqrt) to gain a little performance
33994
33995 return Math.sqrt(dx * dx + dy * dy);
33996 }
33997 /** @inheritdoc */
33998
33999 }, {
34000 key: "getArrowData",
34001 value: function getArrowData(ctx, position, viaNode, _selected, _hover, values) {
34002 // set lets
34003 var angle;
34004 var arrowPoint;
34005 var node1;
34006 var node2;
34007 var reversed;
34008 var scaleFactor;
34009 var type;
34010 var lineWidth = values.width;
34011
34012 if (position === "from") {
34013 node1 = this.from;
34014 node2 = this.to;
34015 reversed = values.fromArrowScale < 0;
34016 scaleFactor = Math.abs(values.fromArrowScale);
34017 type = values.fromArrowType;
34018 } else if (position === "to") {
34019 node1 = this.to;
34020 node2 = this.from;
34021 reversed = values.toArrowScale < 0;
34022 scaleFactor = Math.abs(values.toArrowScale);
34023 type = values.toArrowType;
34024 } else {
34025 node1 = this.to;
34026 node2 = this.from;
34027 reversed = values.middleArrowScale < 0;
34028 scaleFactor = Math.abs(values.middleArrowScale);
34029 type = values.middleArrowType;
34030 }
34031
34032 var length = 15 * scaleFactor + 3 * lineWidth; // 3* lineWidth is the width of the edge.
34033 // if not connected to itself
34034
34035 if (node1 != node2) {
34036 var approximateEdgeLength = Math.hypot(node1.x - node2.x, node1.y - node2.y);
34037 var relativeLength = length / approximateEdgeLength;
34038
34039 if (position !== "middle") {
34040 // draw arrow head
34041 if (this.options.smooth.enabled === true) {
34042 var pointT = this._findBorderPosition(node1, ctx, {
34043 via: viaNode
34044 });
34045
34046 var guidePos = this.getPoint(pointT.t + relativeLength * (position === "from" ? 1 : -1), viaNode);
34047 angle = Math.atan2(pointT.y - guidePos.y, pointT.x - guidePos.x);
34048 arrowPoint = pointT;
34049 } else {
34050 angle = Math.atan2(node1.y - node2.y, node1.x - node2.x);
34051 arrowPoint = this._findBorderPosition(node1, ctx);
34052 }
34053 } else {
34054 // Negative half length reverses arrow direction.
34055 var halfLength = (reversed ? -relativeLength : relativeLength) / 2;
34056 var guidePos1 = this.getPoint(0.5 + halfLength, viaNode);
34057 var guidePos2 = this.getPoint(0.5 - halfLength, viaNode);
34058 angle = Math.atan2(guidePos1.y - guidePos2.y, guidePos1.x - guidePos2.x);
34059 arrowPoint = this.getPoint(0.5, viaNode);
34060 }
34061 } else {
34062 // draw circle
34063 var _this$_getCircleData9 = this._getCircleData(ctx),
34064 _this$_getCircleData10 = _slicedToArray(_this$_getCircleData9, 3),
34065 x = _this$_getCircleData10[0],
34066 y = _this$_getCircleData10[1],
34067 radius = _this$_getCircleData10[2];
34068
34069 if (position === "from") {
34070 var _pointT = this._findBorderPositionCircle(this.from, ctx, {
34071 x: x,
34072 y: y,
34073 low: 0.25,
34074 high: 0.6,
34075 direction: -1
34076 });
34077
34078 angle = _pointT.t * -2 * Math.PI + 1.5 * Math.PI + 0.1 * Math.PI;
34079 arrowPoint = _pointT;
34080 } else if (position === "to") {
34081 var _pointT2 = this._findBorderPositionCircle(this.from, ctx, {
34082 x: x,
34083 y: y,
34084 low: 0.6,
34085 high: 1.0,
34086 direction: 1
34087 });
34088
34089 angle = _pointT2.t * -2 * Math.PI + 1.5 * Math.PI - 1.1 * Math.PI;
34090 arrowPoint = _pointT2;
34091 } else {
34092 arrowPoint = this._pointOnCircle(x, y, radius, 0.175);
34093 angle = 3.9269908169872414; // === 0.175 * -2 * Math.PI + 1.5 * Math.PI + 0.1 * Math.PI;
34094 }
34095 }
34096
34097 var xi = arrowPoint.x - length * 0.9 * Math.cos(angle);
34098 var yi = arrowPoint.y - length * 0.9 * Math.sin(angle);
34099 var arrowCore = {
34100 x: xi,
34101 y: yi
34102 };
34103 return {
34104 point: arrowPoint,
34105 core: arrowCore,
34106 angle: angle,
34107 length: length,
34108 type: type
34109 };
34110 }
34111 /** @inheritdoc */
34112
34113 }, {
34114 key: "drawArrowHead",
34115 value: function drawArrowHead(ctx, values, _selected, _hover, arrowData) {
34116 // set style
34117 ctx.strokeStyle = this.getColor(ctx, values);
34118 ctx.fillStyle = ctx.strokeStyle;
34119 ctx.lineWidth = values.width;
34120 var canFill = EndPoints.draw(ctx, arrowData);
34121
34122 if (canFill) {
34123 // draw shadow if enabled
34124 this.enableShadow(ctx, values);
34125 ctx.fill(); // disable shadows for other elements.
34126
34127 this.disableShadow(ctx, values);
34128 }
34129 }
34130 /**
34131 * Set the shadow formatting values in the context if enabled, do nothing otherwise.
34132 *
34133 * @param ctx - The context that will be used for rendering.
34134 * @param values - Formatting values for the shadow.
34135 */
34136
34137 }, {
34138 key: "enableShadow",
34139 value: function enableShadow(ctx, values) {
34140 if (values.shadow === true) {
34141 ctx.shadowColor = values.shadowColor;
34142 ctx.shadowBlur = values.shadowSize;
34143 ctx.shadowOffsetX = values.shadowX;
34144 ctx.shadowOffsetY = values.shadowY;
34145 }
34146 }
34147 /**
34148 * Reset the shadow formatting values in the context if enabled, do nothing otherwise.
34149 *
34150 * @param ctx - The context that will be used for rendering.
34151 * @param values - Formatting values for the shadow.
34152 */
34153
34154 }, {
34155 key: "disableShadow",
34156 value: function disableShadow(ctx, values) {
34157 if (values.shadow === true) {
34158 ctx.shadowColor = "rgba(0,0,0,0)";
34159 ctx.shadowBlur = 0;
34160 ctx.shadowOffsetX = 0;
34161 ctx.shadowOffsetY = 0;
34162 }
34163 }
34164 /**
34165 * Render the background according to the formatting values.
34166 *
34167 * @param ctx - The context that will be used for rendering.
34168 * @param values - Formatting values for the background.
34169 */
34170
34171 }, {
34172 key: "drawBackground",
34173 value: function drawBackground(ctx, values) {
34174 if (values.background !== false) {
34175 // save original line attrs
34176 var origCtxAttr = {
34177 strokeStyle: ctx.strokeStyle,
34178 lineWidth: ctx.lineWidth,
34179 dashes: ctx.dashes
34180 };
34181 ctx.strokeStyle = values.backgroundColor;
34182 ctx.lineWidth = values.backgroundSize;
34183 this.setStrokeDashed(ctx, values.backgroundDashes);
34184 ctx.stroke(); // restore original line attrs
34185
34186 ctx.strokeStyle = origCtxAttr.strokeStyle;
34187 ctx.lineWidth = origCtxAttr.lineWidth;
34188 ctx.dashes = origCtxAttr.dashes;
34189 this.setStrokeDashed(ctx, values.dashes);
34190 }
34191 }
34192 /**
34193 * Set the line dash pattern if supported. Logs a warning to the console if it isn't supported.
34194 *
34195 * @param ctx - The context that will be used for rendering.
34196 * @param dashes - The pattern [line, space, line…], true for default dashed line or false for normal line.
34197 */
34198
34199 }, {
34200 key: "setStrokeDashed",
34201 value: function setStrokeDashed(ctx, dashes) {
34202 if (dashes !== false) {
34203 if (ctx.setLineDash !== undefined) {
34204 var pattern = Array.isArray(dashes) ? dashes : [5, 5];
34205 ctx.setLineDash(pattern);
34206 } else {
34207 console.warn("setLineDash is not supported in this browser. The dashed stroke cannot be used.");
34208 }
34209 } else {
34210 if (ctx.setLineDash !== undefined) {
34211 ctx.setLineDash([]);
34212 } else {
34213 console.warn("setLineDash is not supported in this browser. The dashed stroke cannot be used.");
34214 }
34215 }
34216 }
34217 }]);
34218
34219 return EdgeBase;
34220 }();
34221
34222 /**
34223 * The Base Class for all Bezier edges.
34224 * Bezier curves are used to model smooth gradual curves in paths between nodes.
34225 */
34226
34227 var BezierEdgeBase =
34228 /*#__PURE__*/
34229 function (_EdgeBase) {
34230 _inherits(BezierEdgeBase, _EdgeBase);
34231
34232 /**
34233 * Create a new instance.
34234 *
34235 * @param options - The options object of given edge.
34236 * @param body - The body of the network.
34237 * @param labelModule - Label module.
34238 */
34239 function BezierEdgeBase(options, body, labelModule) {
34240 _classCallCheck(this, BezierEdgeBase);
34241
34242 return _possibleConstructorReturn(this, _getPrototypeOf(BezierEdgeBase).call(this, options, body, labelModule));
34243 }
34244 /**
34245 * Find the intersection between the border of the node and the edge.
34246 *
34247 * @remarks
34248 * This function uses binary search to look for the point where the bezier curve crosses the border of the node.
34249 *
34250 * @param nearNode - The node (either from or to node of the edge).
34251 * @param ctx - The context that will be used for rendering.
34252 * @param viaNode - Additional node(s) the edge passes through.
34253 *
34254 * @returns Cartesian coordinates of the intersection between the border of the node and the edge.
34255 */
34256
34257
34258 _createClass(BezierEdgeBase, [{
34259 key: "_findBorderPositionBezier",
34260 value: function _findBorderPositionBezier(nearNode, ctx) {
34261 var viaNode = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : this._getViaCoordinates();
34262 var maxIterations = 10;
34263 var threshold = 0.2;
34264 var from = false;
34265 var high = 1;
34266 var low = 0;
34267 var node = this.to;
34268 var pos;
34269 var middle;
34270
34271 if (nearNode.id === this.from.id) {
34272 node = this.from;
34273 from = true;
34274 }
34275
34276 var iteration = 0;
34277
34278 do {
34279 middle = (low + high) * 0.5;
34280 pos = this.getPoint(middle, viaNode);
34281 var angle = Math.atan2(node.y - pos.y, node.x - pos.x);
34282 var distanceToBorder = node.distanceToBorder(ctx, angle);
34283 var distanceToPoint = Math.sqrt(Math.pow(pos.x - node.x, 2) + Math.pow(pos.y - node.y, 2));
34284 var difference = distanceToBorder - distanceToPoint;
34285
34286 if (Math.abs(difference) < threshold) {
34287 break; // found
34288 } else if (difference < 0) {
34289 // distance to nodes is larger than distance to border --> t needs to be bigger if we're looking at the to node.
34290 if (from === false) {
34291 low = middle;
34292 } else {
34293 high = middle;
34294 }
34295 } else {
34296 if (from === false) {
34297 high = middle;
34298 } else {
34299 low = middle;
34300 }
34301 }
34302
34303 ++iteration;
34304 } while (low <= high && iteration < maxIterations);
34305
34306 return _objectSpread2$1({}, pos, {
34307 t: middle
34308 });
34309 }
34310 /**
34311 * Calculate the distance between a point (x3,y3) and a line segment from (x1,y1) to (x2,y2).
34312 *
34313 * @remarks
34314 * http://stackoverflow.com/questions/849211/shortest-distancae-between-a-point-and-a-line-segment
34315 *
34316 * @param x1 - First end of the line segment on the x axis.
34317 * @param y1 - First end of the line segment on the y axis.
34318 * @param x2 - Second end of the line segment on the x axis.
34319 * @param y2 - Second end of the line segment on the y axis.
34320 * @param x3 - Position of the point on the x axis.
34321 * @param y3 - Position of the point on the y axis.
34322 * @param via - The control point for the edge.
34323 *
34324 * @returns The distance between the line segment and the point.
34325 */
34326
34327 }, {
34328 key: "_getDistanceToBezierEdge",
34329 value: function _getDistanceToBezierEdge(x1, y1, x2, y2, x3, y3, via) {
34330 // x3,y3 is the point
34331 var minDistance = 1e9;
34332 var distance;
34333 var i, t, x, y;
34334 var lastX = x1;
34335 var lastY = y1;
34336
34337 for (i = 1; i < 10; i++) {
34338 t = 0.1 * i;
34339 x = Math.pow(1 - t, 2) * x1 + 2 * t * (1 - t) * via.x + Math.pow(t, 2) * x2;
34340 y = Math.pow(1 - t, 2) * y1 + 2 * t * (1 - t) * via.y + Math.pow(t, 2) * y2;
34341
34342 if (i > 0) {
34343 distance = this._getDistanceToLine(lastX, lastY, x, y, x3, y3);
34344 minDistance = distance < minDistance ? distance : minDistance;
34345 }
34346
34347 lastX = x;
34348 lastY = y;
34349 }
34350
34351 return minDistance;
34352 }
34353 /**
34354 * Render a bezier curve between two nodes.
34355 *
34356 * @remarks
34357 * The method accepts zero, one or two control points.
34358 * Passing zero control points just draws a straight line.
34359 *
34360 * @param ctx - The context that will be used for rendering.
34361 * @param values - Style options for edge drawing.
34362 * @param viaNode1 - First control point for curve drawing.
34363 * @param viaNode2 - Second control point for curve drawing.
34364 */
34365
34366 }, {
34367 key: "_bezierCurve",
34368 value: function _bezierCurve(ctx, values, viaNode1, viaNode2) {
34369 ctx.beginPath();
34370 ctx.moveTo(this.fromPoint.x, this.fromPoint.y);
34371
34372 if (viaNode1 != null && viaNode1.x != null) {
34373 if (viaNode2 != null && viaNode2.x != null) {
34374 ctx.bezierCurveTo(viaNode1.x, viaNode1.y, viaNode2.x, viaNode2.y, this.toPoint.x, this.toPoint.y);
34375 } else {
34376 ctx.quadraticCurveTo(viaNode1.x, viaNode1.y, this.toPoint.x, this.toPoint.y);
34377 }
34378 } else {
34379 // fallback to normal straight edge
34380 ctx.lineTo(this.toPoint.x, this.toPoint.y);
34381 } // draw a background
34382
34383
34384 this.drawBackground(ctx, values); // draw shadow if enabled
34385
34386 this.enableShadow(ctx, values);
34387 ctx.stroke();
34388 this.disableShadow(ctx, values);
34389 }
34390 /** @inheritdoc */
34391
34392 }, {
34393 key: "getViaNode",
34394 value: function getViaNode() {
34395 return this._getViaCoordinates();
34396 }
34397 }]);
34398
34399 return BezierEdgeBase;
34400 }(EdgeBase);
34401
34402 /**
34403 * A Dynamic Bezier Edge. Bezier curves are used to model smooth gradual
34404 * curves in paths between nodes. The Dynamic piece refers to how the curve
34405 * reacts to physics changes.
34406 *
34407 * @extends BezierEdgeBase
34408 */
34409
34410 var BezierEdgeDynamic =
34411 /*#__PURE__*/
34412 function (_BezierEdgeBase) {
34413 _inherits(BezierEdgeDynamic, _BezierEdgeBase);
34414
34415 /**
34416 * Create a new instance.
34417 *
34418 * @param options - The options object of given edge.
34419 * @param body - The body of the network.
34420 * @param labelModule - Label module.
34421 */
34422 function BezierEdgeDynamic(options, body, labelModule) {
34423 var _this;
34424
34425 _classCallCheck(this, BezierEdgeDynamic);
34426
34427 //this.via = undefined; // Here for completeness but not allowed to defined before super() is invoked.
34428 _this = _possibleConstructorReturn(this, _getPrototypeOf(BezierEdgeDynamic).call(this, options, body, labelModule)); // --> this calls the setOptions below
34429
34430 _this.via = _this.via; // constructor → super → super → setOptions → setupSupportNode
34431
34432 _this._boundFunction = function () {
34433 _this.positionBezierNode();
34434 };
34435
34436 _this._body.emitter.on("_repositionBezierNodes", _this._boundFunction);
34437
34438 return _this;
34439 }
34440 /** @inheritdoc */
34441
34442
34443 _createClass(BezierEdgeDynamic, [{
34444 key: "setOptions",
34445 value: function setOptions(options) {
34446 _get(_getPrototypeOf(BezierEdgeDynamic.prototype), "setOptions", this).call(this, options); // check if the physics has changed.
34447
34448
34449 var physicsChange = false;
34450
34451 if (this.options.physics !== options.physics) {
34452 physicsChange = true;
34453 } // set the options and the to and from nodes
34454
34455
34456 this.options = options;
34457 this.id = this.options.id;
34458 this.from = this._body.nodes[this.options.from];
34459 this.to = this._body.nodes[this.options.to]; // setup the support node and connect
34460
34461 this.setupSupportNode();
34462 this.connect(); // when we change the physics state of the edge, we reposition the support node.
34463
34464 if (physicsChange === true) {
34465 this.via.setOptions({
34466 physics: this.options.physics
34467 });
34468 this.positionBezierNode();
34469 }
34470 }
34471 /** @inheritdoc */
34472
34473 }, {
34474 key: "connect",
34475 value: function connect() {
34476 this.from = this._body.nodes[this.options.from];
34477 this.to = this._body.nodes[this.options.to];
34478
34479 if (this.from === undefined || this.to === undefined || this.options.physics === false) {
34480 this.via.setOptions({
34481 physics: false
34482 });
34483 } else {
34484 // fix weird behaviour where a self referencing node has physics enabled
34485 if (this.from.id === this.to.id) {
34486 this.via.setOptions({
34487 physics: false
34488 });
34489 } else {
34490 this.via.setOptions({
34491 physics: true
34492 });
34493 }
34494 }
34495 }
34496 /** @inheritdoc */
34497
34498 }, {
34499 key: "cleanup",
34500 value: function cleanup() {
34501 this._body.emitter.off("_repositionBezierNodes", this._boundFunction);
34502
34503 if (this.via !== undefined) {
34504 delete this._body.nodes[this.via.id];
34505 this.via = undefined;
34506 return true;
34507 }
34508
34509 return false;
34510 }
34511 /**
34512 * Create and add a support node if not already present.
34513 *
34514 * @remarks
34515 * Bezier curves require an anchor point to calculate the smooth flow.
34516 * These points are nodes.
34517 * These nodes are invisible but are used for the force calculation.
34518 *
34519 * The changed data is not called, if needed, it is returned by the main edge constructor.
34520 */
34521
34522 }, {
34523 key: "setupSupportNode",
34524 value: function setupSupportNode() {
34525 if (this.via === undefined) {
34526 var nodeId = "edgeId:" + this.id;
34527
34528 var node = this._body.functions.createNode({
34529 id: nodeId,
34530 shape: "circle",
34531 physics: true,
34532 hidden: true
34533 });
34534
34535 this._body.nodes[nodeId] = node;
34536 this.via = node;
34537 this.via.parentEdgeId = this.id;
34538 this.positionBezierNode();
34539 }
34540 }
34541 /**
34542 * Position bezier node.
34543 */
34544
34545 }, {
34546 key: "positionBezierNode",
34547 value: function positionBezierNode() {
34548 if (this.via !== undefined && this.from !== undefined && this.to !== undefined) {
34549 this.via.x = 0.5 * (this.from.x + this.to.x);
34550 this.via.y = 0.5 * (this.from.y + this.to.y);
34551 } else if (this.via !== undefined) {
34552 this.via.x = 0;
34553 this.via.y = 0;
34554 }
34555 }
34556 /** @inheritdoc */
34557
34558 }, {
34559 key: "_line",
34560 value: function _line(ctx, values, viaNode) {
34561 this._bezierCurve(ctx, values, viaNode);
34562 }
34563 /** @inheritdoc */
34564
34565 }, {
34566 key: "_getViaCoordinates",
34567 value: function _getViaCoordinates() {
34568 return this.via;
34569 }
34570 /** @inheritdoc */
34571
34572 }, {
34573 key: "getViaNode",
34574 value: function getViaNode() {
34575 return this.via;
34576 }
34577 /** @inheritdoc */
34578
34579 }, {
34580 key: "getPoint",
34581 value: function getPoint(position) {
34582 var viaNode = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.via;
34583
34584 if (this.from === this.to) {
34585 var _this$_getCircleData = this._getCircleData(),
34586 _this$_getCircleData2 = _slicedToArray(_this$_getCircleData, 3),
34587 cx = _this$_getCircleData2[0],
34588 cy = _this$_getCircleData2[1],
34589 cr = _this$_getCircleData2[2];
34590
34591 var a = 2 * Math.PI * (1 - position);
34592 return {
34593 x: cx + cr * Math.sin(a),
34594 y: cy + cr - cr * (1 - Math.cos(a))
34595 };
34596 } else {
34597 return {
34598 x: Math.pow(1 - position, 2) * this.fromPoint.x + 2 * position * (1 - position) * viaNode.x + Math.pow(position, 2) * this.toPoint.x,
34599 y: Math.pow(1 - position, 2) * this.fromPoint.y + 2 * position * (1 - position) * viaNode.y + Math.pow(position, 2) * this.toPoint.y
34600 };
34601 }
34602 }
34603 /** @inheritdoc */
34604
34605 }, {
34606 key: "_findBorderPosition",
34607 value: function _findBorderPosition(nearNode, ctx) {
34608 return this._findBorderPositionBezier(nearNode, ctx, this.via);
34609 }
34610 /** @inheritdoc */
34611
34612 }, {
34613 key: "_getDistanceToEdge",
34614 value: function _getDistanceToEdge(x1, y1, x2, y2, x3, y3) {
34615 // x3,y3 is the point
34616 return this._getDistanceToBezierEdge(x1, y1, x2, y2, x3, y3, this.via);
34617 }
34618 }]);
34619
34620 return BezierEdgeDynamic;
34621 }(BezierEdgeBase);
34622
34623 /**
34624 * A Static Bezier Edge. Bezier curves are used to model smooth gradual curves in paths between nodes.
34625 */
34626
34627 var BezierEdgeStatic =
34628 /*#__PURE__*/
34629 function (_BezierEdgeBase) {
34630 _inherits(BezierEdgeStatic, _BezierEdgeBase);
34631
34632 /**
34633 * Create a new instance.
34634 *
34635 * @param options - The options object of given edge.
34636 * @param body - The body of the network.
34637 * @param labelModule - Label module.
34638 */
34639 function BezierEdgeStatic(options, body, labelModule) {
34640 _classCallCheck(this, BezierEdgeStatic);
34641
34642 return _possibleConstructorReturn(this, _getPrototypeOf(BezierEdgeStatic).call(this, options, body, labelModule));
34643 }
34644 /** @inheritdoc */
34645
34646
34647 _createClass(BezierEdgeStatic, [{
34648 key: "_line",
34649 value: function _line(ctx, values, viaNode) {
34650 this._bezierCurve(ctx, values, viaNode);
34651 }
34652 /** @inheritdoc */
34653
34654 }, {
34655 key: "getViaNode",
34656 value: function getViaNode() {
34657 return this._getViaCoordinates();
34658 }
34659 /**
34660 * Compute the coordinates of the via node.
34661 *
34662 * @remarks
34663 * We do not use the to and fromPoints here to make the via nodes the same as edges without arrows.
34664 *
34665 * @returns Cartesian coordinates of the via node.
34666 */
34667
34668 }, {
34669 key: "_getViaCoordinates",
34670 value: function _getViaCoordinates() {
34671 // Assumption: x/y coordinates in from/to always defined
34672 var factor = this.options.smooth.roundness;
34673 var type = this.options.smooth.type;
34674 var dx = Math.abs(this.from.x - this.to.x);
34675 var dy = Math.abs(this.from.y - this.to.y);
34676
34677 if (type === "discrete" || type === "diagonalCross") {
34678 var stepX;
34679 var stepY;
34680
34681 if (dx <= dy) {
34682 stepX = stepY = factor * dy;
34683 } else {
34684 stepX = stepY = factor * dx;
34685 }
34686
34687 if (this.from.x > this.to.x) {
34688 stepX = -stepX;
34689 }
34690
34691 if (this.from.y >= this.to.y) {
34692 stepY = -stepY;
34693 }
34694
34695 var xVia = this.from.x + stepX;
34696 var yVia = this.from.y + stepY;
34697
34698 if (type === "discrete") {
34699 if (dx <= dy) {
34700 xVia = dx < factor * dy ? this.from.x : xVia;
34701 } else {
34702 yVia = dy < factor * dx ? this.from.y : yVia;
34703 }
34704 }
34705
34706 return {
34707 x: xVia,
34708 y: yVia
34709 };
34710 } else if (type === "straightCross") {
34711 var _stepX = (1 - factor) * dx;
34712
34713 var _stepY = (1 - factor) * dy;
34714
34715 if (dx <= dy) {
34716 // up - down
34717 _stepX = 0;
34718
34719 if (this.from.y < this.to.y) {
34720 _stepY = -_stepY;
34721 }
34722 } else {
34723 // left - right
34724 if (this.from.x < this.to.x) {
34725 _stepX = -_stepX;
34726 }
34727
34728 _stepY = 0;
34729 }
34730
34731 return {
34732 x: this.to.x + _stepX,
34733 y: this.to.y + _stepY
34734 };
34735 } else if (type === "horizontal") {
34736 var _stepX2 = (1 - factor) * dx;
34737
34738 if (this.from.x < this.to.x) {
34739 _stepX2 = -_stepX2;
34740 }
34741
34742 return {
34743 x: this.to.x + _stepX2,
34744 y: this.from.y
34745 };
34746 } else if (type === "vertical") {
34747 var _stepY2 = (1 - factor) * dy;
34748
34749 if (this.from.y < this.to.y) {
34750 _stepY2 = -_stepY2;
34751 }
34752
34753 return {
34754 x: this.from.x,
34755 y: this.to.y + _stepY2
34756 };
34757 } else if (type === "curvedCW") {
34758 dx = this.to.x - this.from.x;
34759 dy = this.from.y - this.to.y;
34760 var radius = Math.sqrt(dx * dx + dy * dy);
34761 var pi = Math.PI;
34762 var originalAngle = Math.atan2(dy, dx);
34763 var myAngle = (originalAngle + (factor * 0.5 + 0.5) * pi) % (2 * pi);
34764 return {
34765 x: this.from.x + (factor * 0.5 + 0.5) * radius * Math.sin(myAngle),
34766 y: this.from.y + (factor * 0.5 + 0.5) * radius * Math.cos(myAngle)
34767 };
34768 } else if (type === "curvedCCW") {
34769 dx = this.to.x - this.from.x;
34770 dy = this.from.y - this.to.y;
34771
34772 var _radius = Math.sqrt(dx * dx + dy * dy);
34773
34774 var _pi = Math.PI;
34775
34776 var _originalAngle = Math.atan2(dy, dx);
34777
34778 var _myAngle = (_originalAngle + (-factor * 0.5 + 0.5) * _pi) % (2 * _pi);
34779
34780 return {
34781 x: this.from.x + (factor * 0.5 + 0.5) * _radius * Math.sin(_myAngle),
34782 y: this.from.y + (factor * 0.5 + 0.5) * _radius * Math.cos(_myAngle)
34783 };
34784 } else {
34785 // continuous
34786 var _stepX3;
34787
34788 var _stepY3;
34789
34790 if (dx <= dy) {
34791 _stepX3 = _stepY3 = factor * dy;
34792 } else {
34793 _stepX3 = _stepY3 = factor * dx;
34794 }
34795
34796 if (this.from.x > this.to.x) {
34797 _stepX3 = -_stepX3;
34798 }
34799
34800 if (this.from.y >= this.to.y) {
34801 _stepY3 = -_stepY3;
34802 }
34803
34804 var _xVia = this.from.x + _stepX3;
34805
34806 var _yVia = this.from.y + _stepY3;
34807
34808 if (dx <= dy) {
34809 if (this.from.x <= this.to.x) {
34810 _xVia = this.to.x < _xVia ? this.to.x : _xVia;
34811 } else {
34812 _xVia = this.to.x > _xVia ? this.to.x : _xVia;
34813 }
34814 } else {
34815 if (this.from.y >= this.to.y) {
34816 _yVia = this.to.y > _yVia ? this.to.y : _yVia;
34817 } else {
34818 _yVia = this.to.y < _yVia ? this.to.y : _yVia;
34819 }
34820 }
34821
34822 return {
34823 x: _xVia,
34824 y: _yVia
34825 };
34826 }
34827 }
34828 /** @inheritdoc */
34829
34830 }, {
34831 key: "_findBorderPosition",
34832 value: function _findBorderPosition(nearNode, ctx) {
34833 var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
34834 return this._findBorderPositionBezier(nearNode, ctx, options.via);
34835 }
34836 /** @inheritdoc */
34837
34838 }, {
34839 key: "_getDistanceToEdge",
34840 value: function _getDistanceToEdge(x1, y1, x2, y2, x3, y3) {
34841 var viaNode = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : this._getViaCoordinates();
34842 // x3,y3 is the point
34843 return this._getDistanceToBezierEdge(x1, y1, x2, y2, x3, y3, viaNode);
34844 }
34845 /** @inheritdoc */
34846
34847 }, {
34848 key: "getPoint",
34849 value: function getPoint(position) {
34850 var viaNode = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this._getViaCoordinates();
34851 var t = position;
34852 var x = Math.pow(1 - t, 2) * this.fromPoint.x + 2 * t * (1 - t) * viaNode.x + Math.pow(t, 2) * this.toPoint.x;
34853 var y = Math.pow(1 - t, 2) * this.fromPoint.y + 2 * t * (1 - t) * viaNode.y + Math.pow(t, 2) * this.toPoint.y;
34854 return {
34855 x: x,
34856 y: y
34857 };
34858 }
34859 }]);
34860
34861 return BezierEdgeStatic;
34862 }(BezierEdgeBase);
34863
34864 /**
34865 * A Base Class for all Cubic Bezier Edges. Bezier curves are used to model
34866 * smooth gradual curves in paths between nodes.
34867 *
34868 * @extends BezierEdgeBase
34869 */
34870
34871 var CubicBezierEdgeBase =
34872 /*#__PURE__*/
34873 function (_BezierEdgeBase) {
34874 _inherits(CubicBezierEdgeBase, _BezierEdgeBase);
34875
34876 /**
34877 * Create a new instance.
34878 *
34879 * @param options - The options object of given edge.
34880 * @param body - The body of the network.
34881 * @param labelModule - Label module.
34882 */
34883 function CubicBezierEdgeBase(options, body, labelModule) {
34884 _classCallCheck(this, CubicBezierEdgeBase);
34885
34886 return _possibleConstructorReturn(this, _getPrototypeOf(CubicBezierEdgeBase).call(this, options, body, labelModule));
34887 }
34888 /**
34889 * Calculate the distance between a point (x3,y3) and a line segment from (x1,y1) to (x2,y2).
34890 *
34891 * @remarks
34892 * http://stackoverflow.com/questions/849211/shortest-distancae-between-a-point-and-a-line-segment
34893 * https://en.wikipedia.org/wiki/B%C3%A9zier_curve
34894 *
34895 * @param x1 - First end of the line segment on the x axis.
34896 * @param y1 - First end of the line segment on the y axis.
34897 * @param x2 - Second end of the line segment on the x axis.
34898 * @param y2 - Second end of the line segment on the y axis.
34899 * @param x3 - Position of the point on the x axis.
34900 * @param y3 - Position of the point on the y axis.
34901 * @param via1 - The first point this edge passes through.
34902 * @param via2 - The second point this edge passes through.
34903 *
34904 * @returns The distance between the line segment and the point.
34905 */
34906
34907
34908 _createClass(CubicBezierEdgeBase, [{
34909 key: "_getDistanceToBezierEdge2",
34910 value: function _getDistanceToBezierEdge2(x1, y1, x2, y2, x3, y3, via1, via2) {
34911 // x3,y3 is the point
34912 var minDistance = 1e9;
34913 var lastX = x1;
34914 var lastY = y1;
34915 var vec = [0, 0, 0, 0];
34916
34917 for (var i = 1; i < 10; i++) {
34918 var t = 0.1 * i;
34919 vec[0] = Math.pow(1 - t, 3);
34920 vec[1] = 3 * t * Math.pow(1 - t, 2);
34921 vec[2] = 3 * Math.pow(t, 2) * (1 - t);
34922 vec[3] = Math.pow(t, 3);
34923 var x = vec[0] * x1 + vec[1] * via1.x + vec[2] * via2.x + vec[3] * x2;
34924 var y = vec[0] * y1 + vec[1] * via1.y + vec[2] * via2.y + vec[3] * y2;
34925
34926 if (i > 0) {
34927 var distance = this._getDistanceToLine(lastX, lastY, x, y, x3, y3);
34928
34929 minDistance = distance < minDistance ? distance : minDistance;
34930 }
34931
34932 lastX = x;
34933 lastY = y;
34934 }
34935
34936 return minDistance;
34937 }
34938 }]);
34939
34940 return CubicBezierEdgeBase;
34941 }(BezierEdgeBase);
34942
34943 /**
34944 * A Cubic Bezier Edge. Bezier curves are used to model smooth gradual curves in paths between nodes.
34945 */
34946
34947 var CubicBezierEdge =
34948 /*#__PURE__*/
34949 function (_CubicBezierEdgeBase) {
34950 _inherits(CubicBezierEdge, _CubicBezierEdgeBase);
34951
34952 /**
34953 * Create a new instance.
34954 *
34955 * @param options - The options object of given edge.
34956 * @param body - The body of the network.
34957 * @param labelModule - Label module.
34958 */
34959 function CubicBezierEdge(options, body, labelModule) {
34960 _classCallCheck(this, CubicBezierEdge);
34961
34962 return _possibleConstructorReturn(this, _getPrototypeOf(CubicBezierEdge).call(this, options, body, labelModule));
34963 }
34964 /** @inheritdoc */
34965
34966
34967 _createClass(CubicBezierEdge, [{
34968 key: "_line",
34969 value: function _line(ctx, values, viaNodes) {
34970 // get the coordinates of the support points.
34971 var via1 = viaNodes[0];
34972 var via2 = viaNodes[1];
34973
34974 this._bezierCurve(ctx, values, via1, via2);
34975 }
34976 /**
34977 * Compute the additional points the edge passes through.
34978 *
34979 * @returns Cartesian coordinates of the points the edge passes through.
34980 */
34981
34982 }, {
34983 key: "_getViaCoordinates",
34984 value: function _getViaCoordinates() {
34985 var dx = this.from.x - this.to.x;
34986 var dy = this.from.y - this.to.y;
34987 var x1;
34988 var y1;
34989 var x2;
34990 var y2;
34991 var roundness = this.options.smooth.roundness; // horizontal if x > y or if direction is forced or if direction is horizontal
34992
34993 if ((Math.abs(dx) > Math.abs(dy) || this.options.smooth.forceDirection === true || this.options.smooth.forceDirection === "horizontal") && this.options.smooth.forceDirection !== "vertical") {
34994 y1 = this.from.y;
34995 y2 = this.to.y;
34996 x1 = this.from.x - roundness * dx;
34997 x2 = this.to.x + roundness * dx;
34998 } else {
34999 y1 = this.from.y - roundness * dy;
35000 y2 = this.to.y + roundness * dy;
35001 x1 = this.from.x;
35002 x2 = this.to.x;
35003 }
35004
35005 return [{
35006 x: x1,
35007 y: y1
35008 }, {
35009 x: x2,
35010 y: y2
35011 }];
35012 }
35013 /** @inheritdoc */
35014
35015 }, {
35016 key: "getViaNode",
35017 value: function getViaNode() {
35018 return this._getViaCoordinates();
35019 }
35020 /** @inheritdoc */
35021
35022 }, {
35023 key: "_findBorderPosition",
35024 value: function _findBorderPosition(nearNode, ctx) {
35025 return this._findBorderPositionBezier(nearNode, ctx);
35026 }
35027 /** @inheritdoc */
35028
35029 }, {
35030 key: "_getDistanceToEdge",
35031 value: function _getDistanceToEdge(x1, y1, x2, y2, x3, y3) {
35032 var _ref = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : this._getViaCoordinates(),
35033 _ref2 = _slicedToArray(_ref, 2),
35034 via1 = _ref2[0],
35035 via2 = _ref2[1];
35036
35037 // x3,y3 is the point
35038 return this._getDistanceToBezierEdge2(x1, y1, x2, y2, x3, y3, via1, via2);
35039 }
35040 /** @inheritdoc */
35041
35042 }, {
35043 key: "getPoint",
35044 value: function getPoint(position) {
35045 var _ref3 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this._getViaCoordinates(),
35046 _ref4 = _slicedToArray(_ref3, 2),
35047 via1 = _ref4[0],
35048 via2 = _ref4[1];
35049
35050 var t = position;
35051 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)];
35052 var x = vec[0] * this.fromPoint.x + vec[1] * via1.x + vec[2] * via2.x + vec[3] * this.toPoint.x;
35053 var y = vec[0] * this.fromPoint.y + vec[1] * via1.y + vec[2] * via2.y + vec[3] * this.toPoint.y;
35054 return {
35055 x: x,
35056 y: y
35057 };
35058 }
35059 }]);
35060
35061 return CubicBezierEdge;
35062 }(CubicBezierEdgeBase);
35063
35064 /**
35065 * A Straight Edge.
35066 */
35067
35068 var StraightEdge =
35069 /*#__PURE__*/
35070 function (_EdgeBase) {
35071 _inherits(StraightEdge, _EdgeBase);
35072
35073 /**
35074 * Create a new instance.
35075 *
35076 * @param options - The options object of given edge.
35077 * @param body - The body of the network.
35078 * @param labelModule - Label module.
35079 */
35080 function StraightEdge(options, body, labelModule) {
35081 _classCallCheck(this, StraightEdge);
35082
35083 return _possibleConstructorReturn(this, _getPrototypeOf(StraightEdge).call(this, options, body, labelModule));
35084 }
35085 /** @inheritdoc */
35086
35087
35088 _createClass(StraightEdge, [{
35089 key: "_line",
35090 value: function _line(ctx, values) {
35091 // draw a straight line
35092 ctx.beginPath();
35093 ctx.moveTo(this.fromPoint.x, this.fromPoint.y);
35094 ctx.lineTo(this.toPoint.x, this.toPoint.y); // draw shadow if enabled
35095
35096 this.enableShadow(ctx, values);
35097 ctx.stroke();
35098 this.disableShadow(ctx, values);
35099 }
35100 /** @inheritdoc */
35101
35102 }, {
35103 key: "getViaNode",
35104 value: function getViaNode() {
35105 return undefined;
35106 }
35107 /** @inheritdoc */
35108
35109 }, {
35110 key: "getPoint",
35111 value: function getPoint(position) {
35112 return {
35113 x: (1 - position) * this.fromPoint.x + position * this.toPoint.x,
35114 y: (1 - position) * this.fromPoint.y + position * this.toPoint.y
35115 };
35116 }
35117 /** @inheritdoc */
35118
35119 }, {
35120 key: "_findBorderPosition",
35121 value: function _findBorderPosition(nearNode, ctx) {
35122 var node1 = this.to;
35123 var node2 = this.from;
35124
35125 if (nearNode.id === this.from.id) {
35126 node1 = this.from;
35127 node2 = this.to;
35128 }
35129
35130 var angle = Math.atan2(node1.y - node2.y, node1.x - node2.x);
35131 var dx = node1.x - node2.x;
35132 var dy = node1.y - node2.y;
35133 var edgeSegmentLength = Math.sqrt(dx * dx + dy * dy);
35134 var toBorderDist = nearNode.distanceToBorder(ctx, angle);
35135 var toBorderPoint = (edgeSegmentLength - toBorderDist) / edgeSegmentLength;
35136 return {
35137 x: (1 - toBorderPoint) * node2.x + toBorderPoint * node1.x,
35138 y: (1 - toBorderPoint) * node2.y + toBorderPoint * node1.y,
35139 t: 0
35140 };
35141 }
35142 /** @inheritdoc */
35143
35144 }, {
35145 key: "_getDistanceToEdge",
35146 value: function _getDistanceToEdge(x1, y1, x2, y2, x3, y3) {
35147 // x3,y3 is the point
35148 return this._getDistanceToLine(x1, y1, x2, y2, x3, y3);
35149 }
35150 }]);
35151
35152 return StraightEdge;
35153 }(EdgeBase);
35154
35155 /**
35156 * An edge connects two nodes and has a specific direction.
35157 */
35158
35159 var Edge =
35160 /*#__PURE__*/
35161 function () {
35162 /**
35163 * @param {Object} options values specific to this edge, must contain at least 'from' and 'to'
35164 * @param {Object} body shared state from Network instance
35165 * @param {Network.Images} imagelist A list with images. Only needed when the edge has image arrows.
35166 * @param {Object} globalOptions options from the EdgesHandler instance
35167 * @param {Object} defaultOptions default options from the EdgeHandler instance. Value and reference are constant
35168 */
35169 function Edge(options, body, imagelist, globalOptions, defaultOptions) {
35170 _classCallCheck(this, Edge);
35171
35172 if (body === undefined) {
35173 throw new Error("No body provided");
35174 } // Since globalOptions is constant in values as well as reference,
35175 // Following needs to be done only once.
35176
35177
35178 this.options = bridgeObject(globalOptions);
35179 this.globalOptions = globalOptions;
35180 this.defaultOptions = defaultOptions;
35181 this.body = body;
35182 this.imagelist = imagelist; // initialize variables
35183
35184 this.id = undefined;
35185 this.fromId = undefined;
35186 this.toId = undefined;
35187 this.selected = false;
35188 this.hover = false;
35189 this.labelDirty = true;
35190 this.baseWidth = this.options.width;
35191 this.baseFontSize = this.options.font.size;
35192 this.from = undefined; // a node
35193
35194 this.to = undefined; // a node
35195
35196 this.edgeType = undefined;
35197 this.connected = false;
35198 this.labelModule = new Label(this.body, this.options, true
35199 /* It's an edge label */
35200 );
35201 this.setOptions(options);
35202 }
35203 /**
35204 * Set or overwrite options for the edge
35205 * @param {Object} options an object with options
35206 * @returns {undefined|boolean} undefined if no options, true if layout affecting data changed, false otherwise.
35207 */
35208
35209
35210 _createClass(Edge, [{
35211 key: "setOptions",
35212 value: function setOptions(options) {
35213 if (!options) {
35214 return;
35215 } // Following options if changed affect the layout.
35216
35217
35218 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;
35219 Edge.parseOptions(this.options, options, true, this.globalOptions);
35220
35221 if (options.id !== undefined) {
35222 this.id = options.id;
35223 }
35224
35225 if (options.from !== undefined) {
35226 this.fromId = options.from;
35227 }
35228
35229 if (options.to !== undefined) {
35230 this.toId = options.to;
35231 }
35232
35233 if (options.title !== undefined) {
35234 this.title = options.title;
35235 }
35236
35237 if (options.value !== undefined) {
35238 options.value = parseFloat(options.value);
35239 }
35240
35241 var pile = [options, this.options, this.defaultOptions];
35242 this.chooser = ComponentUtil.choosify('edge', pile); // update label Module
35243
35244 this.updateLabelModule(options); // Update edge type, this if changed affects the layout.
35245
35246 affectsLayout = this.updateEdgeType() || affectsLayout; // if anything has been updates, reset the selection width and the hover width
35247
35248 this._setInteractionWidths(); // A node is connected when it has a from and to node that both exist in the network.body.nodes.
35249
35250
35251 this.connect();
35252 return affectsLayout;
35253 }
35254 /**
35255 *
35256 * @param {Object} parentOptions
35257 * @param {Object} newOptions
35258 * @param {boolean} [allowDeletion=false]
35259 * @param {Object} [globalOptions={}]
35260 * @param {boolean} [copyFromGlobals=false]
35261 */
35262
35263 }, {
35264 key: "getFormattingValues",
35265
35266 /**
35267 *
35268 * @returns {ArrowOptions}
35269 */
35270 value: function getFormattingValues() {
35271 var toArrow = this.options.arrows.to === true || this.options.arrows.to.enabled === true;
35272 var fromArrow = this.options.arrows.from === true || this.options.arrows.from.enabled === true;
35273 var middleArrow = this.options.arrows.middle === true || this.options.arrows.middle.enabled === true;
35274 var inheritsColor = this.options.color.inherit;
35275 var values = {
35276 toArrow: toArrow,
35277 toArrowScale: this.options.arrows.to.scaleFactor,
35278 toArrowType: this.options.arrows.to.type,
35279 toArrowSrc: this.options.arrows.to.src,
35280 toArrowImageWidth: this.options.arrows.to.imageWidth,
35281 toArrowImageHeight: this.options.arrows.to.imageHeight,
35282 middleArrow: middleArrow,
35283 middleArrowScale: this.options.arrows.middle.scaleFactor,
35284 middleArrowType: this.options.arrows.middle.type,
35285 middleArrowSrc: this.options.arrows.middle.src,
35286 middleArrowImageWidth: this.options.arrows.middle.imageWidth,
35287 middleArrowImageHeight: this.options.arrows.middle.imageHeight,
35288 fromArrow: fromArrow,
35289 fromArrowScale: this.options.arrows.from.scaleFactor,
35290 fromArrowType: this.options.arrows.from.type,
35291 fromArrowSrc: this.options.arrows.from.src,
35292 fromArrowImageWidth: this.options.arrows.from.imageWidth,
35293 fromArrowImageHeight: this.options.arrows.from.imageHeight,
35294 arrowStrikethrough: this.options.arrowStrikethrough,
35295 color: inheritsColor ? undefined : this.options.color.color,
35296 inheritsColor: inheritsColor,
35297 opacity: this.options.color.opacity,
35298 hidden: this.options.hidden,
35299 length: this.options.length,
35300 shadow: this.options.shadow.enabled,
35301 shadowColor: this.options.shadow.color,
35302 shadowSize: this.options.shadow.size,
35303 shadowX: this.options.shadow.x,
35304 shadowY: this.options.shadow.y,
35305 dashes: this.options.dashes,
35306 width: this.options.width,
35307 background: this.options.background.enabled,
35308 backgroundColor: this.options.background.color,
35309 backgroundSize: this.options.background.size,
35310 backgroundDashes: this.options.background.dashes
35311 };
35312
35313 if (this.selected || this.hover) {
35314 if (this.chooser === true) {
35315 if (this.selected) {
35316 var selectedWidth = this.options.selectionWidth;
35317
35318 if (typeof selectedWidth === 'function') {
35319 values.width = selectedWidth(values.width);
35320 } else if (typeof selectedWidth === 'number') {
35321 values.width += selectedWidth;
35322 }
35323
35324 values.width = Math.max(values.width, 0.3 / this.body.view.scale);
35325 values.color = this.options.color.highlight;
35326 values.shadow = this.options.shadow.enabled;
35327 } else if (this.hover) {
35328 var hoverWidth = this.options.hoverWidth;
35329
35330 if (typeof hoverWidth === 'function') {
35331 values.width = hoverWidth(values.width);
35332 } else if (typeof hoverWidth === 'number') {
35333 values.width += hoverWidth;
35334 }
35335
35336 values.width = Math.max(values.width, 0.3 / this.body.view.scale);
35337 values.color = this.options.color.hover;
35338 values.shadow = this.options.shadow.enabled;
35339 }
35340 } else if (typeof this.chooser === 'function') {
35341 this.chooser(values, this.options.id, this.selected, this.hover);
35342
35343 if (values.color !== undefined) {
35344 values.inheritsColor = false;
35345 }
35346
35347 if (values.shadow === false) {
35348 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) {
35349 values.shadow = true;
35350 }
35351 }
35352 }
35353 } else {
35354 values.shadow = this.options.shadow.enabled;
35355 values.width = Math.max(values.width, 0.3 / this.body.view.scale);
35356 }
35357
35358 return values;
35359 }
35360 /**
35361 * update the options in the label module
35362 *
35363 * @param {Object} options
35364 */
35365
35366 }, {
35367 key: "updateLabelModule",
35368 value: function updateLabelModule(options) {
35369 var pile = [options, this.options, this.globalOptions, // Currently set global edge options
35370 this.defaultOptions];
35371 this.labelModule.update(this.options, pile);
35372
35373 if (this.labelModule.baseSize !== undefined) {
35374 this.baseFontSize = this.labelModule.baseSize;
35375 }
35376 }
35377 /**
35378 * update the edge type, set the options
35379 * @returns {boolean}
35380 */
35381
35382 }, {
35383 key: "updateEdgeType",
35384 value: function updateEdgeType() {
35385 var smooth = this.options.smooth;
35386 var dataChanged = false;
35387 var changeInType = true;
35388
35389 if (this.edgeType !== undefined) {
35390 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) {
35391 changeInType = false;
35392 }
35393
35394 if (changeInType === true) {
35395 dataChanged = this.cleanup();
35396 }
35397 }
35398
35399 if (changeInType === true) {
35400 if (smooth.enabled === true) {
35401 if (smooth.type === 'dynamic') {
35402 dataChanged = true;
35403 this.edgeType = new BezierEdgeDynamic(this.options, this.body, this.labelModule);
35404 } else if (smooth.type === 'cubicBezier') {
35405 this.edgeType = new CubicBezierEdge(this.options, this.body, this.labelModule);
35406 } else {
35407 this.edgeType = new BezierEdgeStatic(this.options, this.body, this.labelModule);
35408 }
35409 } else {
35410 this.edgeType = new StraightEdge(this.options, this.body, this.labelModule);
35411 }
35412 } else {
35413 // if nothing changes, we just set the options.
35414 this.edgeType.setOptions(this.options);
35415 }
35416
35417 return dataChanged;
35418 }
35419 /**
35420 * Connect an edge to its nodes
35421 */
35422
35423 }, {
35424 key: "connect",
35425 value: function connect() {
35426 this.disconnect();
35427 this.from = this.body.nodes[this.fromId] || undefined;
35428 this.to = this.body.nodes[this.toId] || undefined;
35429 this.connected = this.from !== undefined && this.to !== undefined;
35430
35431 if (this.connected === true) {
35432 this.from.attachEdge(this);
35433 this.to.attachEdge(this);
35434 } else {
35435 if (this.from) {
35436 this.from.detachEdge(this);
35437 }
35438
35439 if (this.to) {
35440 this.to.detachEdge(this);
35441 }
35442 }
35443
35444 this.edgeType.connect();
35445 }
35446 /**
35447 * Disconnect an edge from its nodes
35448 */
35449
35450 }, {
35451 key: "disconnect",
35452 value: function disconnect() {
35453 if (this.from) {
35454 this.from.detachEdge(this);
35455 this.from = undefined;
35456 }
35457
35458 if (this.to) {
35459 this.to.detachEdge(this);
35460 this.to = undefined;
35461 }
35462
35463 this.connected = false;
35464 }
35465 /**
35466 * get the title of this edge.
35467 * @return {string} title The title of the edge, or undefined when no title
35468 * has been set.
35469 */
35470
35471 }, {
35472 key: "getTitle",
35473 value: function getTitle() {
35474 return this.title;
35475 }
35476 /**
35477 * check if this node is selecte
35478 * @return {boolean} selected True if node is selected, else false
35479 */
35480
35481 }, {
35482 key: "isSelected",
35483 value: function isSelected() {
35484 return this.selected;
35485 }
35486 /**
35487 * Retrieve the value of the edge. Can be undefined
35488 * @return {number} value
35489 */
35490
35491 }, {
35492 key: "getValue",
35493 value: function getValue() {
35494 return this.options.value;
35495 }
35496 /**
35497 * Adjust the value range of the edge. The edge will adjust it's width
35498 * based on its value.
35499 * @param {number} min
35500 * @param {number} max
35501 * @param {number} total
35502 */
35503
35504 }, {
35505 key: "setValueRange",
35506 value: function setValueRange(min, max, total) {
35507 if (this.options.value !== undefined) {
35508 var scale = this.options.scaling.customScalingFunction(min, max, total, this.options.value);
35509 var widthDiff = this.options.scaling.max - this.options.scaling.min;
35510
35511 if (this.options.scaling.label.enabled === true) {
35512 var fontDiff = this.options.scaling.label.max - this.options.scaling.label.min;
35513 this.options.font.size = this.options.scaling.label.min + scale * fontDiff;
35514 }
35515
35516 this.options.width = this.options.scaling.min + scale * widthDiff;
35517 } else {
35518 this.options.width = this.baseWidth;
35519 this.options.font.size = this.baseFontSize;
35520 }
35521
35522 this._setInteractionWidths();
35523
35524 this.updateLabelModule();
35525 }
35526 /**
35527 *
35528 * @private
35529 */
35530
35531 }, {
35532 key: "_setInteractionWidths",
35533 value: function _setInteractionWidths() {
35534 if (typeof this.options.hoverWidth === 'function') {
35535 this.edgeType.hoverWidth = this.options.hoverWidth(this.options.width);
35536 } else {
35537 this.edgeType.hoverWidth = this.options.hoverWidth + this.options.width;
35538 }
35539
35540 if (typeof this.options.selectionWidth === 'function') {
35541 this.edgeType.selectionWidth = this.options.selectionWidth(this.options.width);
35542 } else {
35543 this.edgeType.selectionWidth = this.options.selectionWidth + this.options.width;
35544 }
35545 }
35546 /**
35547 * Redraw a edge
35548 * Draw this edge in the given canvas
35549 * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d");
35550 * @param {CanvasRenderingContext2D} ctx
35551 */
35552
35553 }, {
35554 key: "draw",
35555 value: function draw(ctx) {
35556 var values = this.getFormattingValues();
35557
35558 if (values.hidden) {
35559 return;
35560 } // get the via node from the edge type
35561
35562
35563 var viaNode = this.edgeType.getViaNode();
35564 var arrowData = {}; // restore edge targets to defaults
35565
35566 this.edgeType.fromPoint = this.edgeType.from;
35567 this.edgeType.toPoint = this.edgeType.to; // from and to arrows give a different end point for edges. we set them here
35568
35569 if (values.fromArrow) {
35570 arrowData.from = this.edgeType.getArrowData(ctx, "from", viaNode, this.selected, this.hover, values);
35571 if (values.arrowStrikethrough === false) this.edgeType.fromPoint = arrowData.from.core;
35572
35573 if (values.fromArrowSrc) {
35574 arrowData.from.image = this.imagelist.load(values.fromArrowSrc);
35575 }
35576
35577 if (values.fromArrowImageWidth) {
35578 arrowData.from.imageWidth = values.fromArrowImageWidth;
35579 }
35580
35581 if (values.fromArrowImageHeight) {
35582 arrowData.from.imageHeight = values.fromArrowImageHeight;
35583 }
35584 }
35585
35586 if (values.toArrow) {
35587 arrowData.to = this.edgeType.getArrowData(ctx, "to", viaNode, this.selected, this.hover, values);
35588 if (values.arrowStrikethrough === false) this.edgeType.toPoint = arrowData.to.core;
35589
35590 if (values.toArrowSrc) {
35591 arrowData.to.image = this.imagelist.load(values.toArrowSrc);
35592 }
35593
35594 if (values.toArrowImageWidth) {
35595 arrowData.to.imageWidth = values.toArrowImageWidth;
35596 }
35597
35598 if (values.toArrowImageHeight) {
35599 arrowData.to.imageHeight = values.toArrowImageHeight;
35600 }
35601 } // the middle arrow depends on the line, which can depend on the to and from arrows so we do this one lastly.
35602
35603
35604 if (values.middleArrow) {
35605 arrowData.middle = this.edgeType.getArrowData(ctx, "middle", viaNode, this.selected, this.hover, values);
35606
35607 if (values.middleArrowSrc) {
35608 arrowData.middle.image = this.imagelist.load(values.middleArrowSrc);
35609 }
35610
35611 if (values.middleArrowImageWidth) {
35612 arrowData.middle.imageWidth = values.middleArrowImageWidth;
35613 }
35614
35615 if (values.middleArrowImageHeight) {
35616 arrowData.middle.imageHeight = values.middleArrowImageHeight;
35617 }
35618 } // draw everything
35619
35620
35621 this.edgeType.drawLine(ctx, values, this.selected, this.hover, viaNode);
35622 this.drawArrows(ctx, arrowData, values);
35623 this.drawLabel(ctx, viaNode);
35624 }
35625 /**
35626 *
35627 * @param {CanvasRenderingContext2D} ctx
35628 * @param {Object} arrowData
35629 * @param {ArrowOptions} values
35630 */
35631
35632 }, {
35633 key: "drawArrows",
35634 value: function drawArrows(ctx, arrowData, values) {
35635 if (values.fromArrow) {
35636 this.edgeType.drawArrowHead(ctx, values, this.selected, this.hover, arrowData.from);
35637 }
35638
35639 if (values.middleArrow) {
35640 this.edgeType.drawArrowHead(ctx, values, this.selected, this.hover, arrowData.middle);
35641 }
35642
35643 if (values.toArrow) {
35644 this.edgeType.drawArrowHead(ctx, values, this.selected, this.hover, arrowData.to);
35645 }
35646 }
35647 /**
35648 *
35649 * @param {CanvasRenderingContext2D} ctx
35650 * @param {Node} viaNode
35651 */
35652
35653 }, {
35654 key: "drawLabel",
35655 value: function drawLabel(ctx, viaNode) {
35656 if (this.options.label !== undefined) {
35657 // set style
35658 var node1 = this.from;
35659 var node2 = this.to;
35660
35661 if (this.labelModule.differentState(this.selected, this.hover)) {
35662 this.labelModule.getTextSize(ctx, this.selected, this.hover);
35663 }
35664
35665 if (node1.id != node2.id) {
35666 this.labelModule.pointToSelf = false;
35667 var point = this.edgeType.getPoint(0.5, viaNode);
35668 ctx.save();
35669
35670 var rotationPoint = this._getRotation(ctx);
35671
35672 if (rotationPoint.angle != 0) {
35673 ctx.translate(rotationPoint.x, rotationPoint.y);
35674 ctx.rotate(rotationPoint.angle);
35675 } // draw the label
35676
35677
35678 this.labelModule.draw(ctx, point.x, point.y, this.selected, this.hover);
35679 /*
35680 // Useful debug code: draw a border around the label
35681 // This should **not** be enabled in production!
35682 var size = this.labelModule.getSize();; // ;; intentional so lint catches it
35683 ctx.strokeStyle = "#ff0000";
35684 ctx.strokeRect(size.left, size.top, size.width, size.height);
35685 // End debug code
35686 */
35687
35688 ctx.restore();
35689 } else {
35690 // Ignore the orientations.
35691 this.labelModule.pointToSelf = true;
35692 var x, y;
35693 var radius = this.options.selfReferenceSize;
35694
35695 if (node1.shape.width > node1.shape.height) {
35696 x = node1.x + node1.shape.width * 0.5;
35697 y = node1.y - radius;
35698 } else {
35699 x = node1.x + radius;
35700 y = node1.y - node1.shape.height * 0.5;
35701 }
35702
35703 point = this._pointOnCircle(x, y, radius, 0.125);
35704 this.labelModule.draw(ctx, point.x, point.y, this.selected, this.hover);
35705 }
35706 }
35707 }
35708 /**
35709 * Determine all visual elements of this edge instance, in which the given
35710 * point falls within the bounding shape.
35711 *
35712 * @param {point} point
35713 * @returns {Array.<edgeClickItem|edgeLabelClickItem>} list with the items which are on the point
35714 */
35715
35716 }, {
35717 key: "getItemsOnPoint",
35718 value: function getItemsOnPoint(point) {
35719 var ret = [];
35720
35721 if (this.labelModule.visible()) {
35722 var rotationPoint = this._getRotation();
35723
35724 if (ComponentUtil.pointInRect(this.labelModule.getSize(), point, rotationPoint)) {
35725 ret.push({
35726 edgeId: this.id,
35727 labelId: 0
35728 });
35729 }
35730 }
35731
35732 var obj = {
35733 left: point.x,
35734 top: point.y
35735 };
35736
35737 if (this.isOverlappingWith(obj)) {
35738 ret.push({
35739 edgeId: this.id
35740 });
35741 }
35742
35743 return ret;
35744 }
35745 /**
35746 * Check if this object is overlapping with the provided object
35747 * @param {Object} obj an object with parameters left, top
35748 * @return {boolean} True if location is located on the edge
35749 */
35750
35751 }, {
35752 key: "isOverlappingWith",
35753 value: function isOverlappingWith(obj) {
35754 if (this.connected) {
35755 var distMax = 10;
35756 var xFrom = this.from.x;
35757 var yFrom = this.from.y;
35758 var xTo = this.to.x;
35759 var yTo = this.to.y;
35760 var xObj = obj.left;
35761 var yObj = obj.top;
35762 var dist = this.edgeType.getDistanceToEdge(xFrom, yFrom, xTo, yTo, xObj, yObj);
35763 return dist < distMax;
35764 } else {
35765 return false;
35766 }
35767 }
35768 /**
35769 * Determine the rotation point, if any.
35770 *
35771 * @param {CanvasRenderingContext2D} [ctx] if passed, do a recalculation of the label size
35772 * @returns {rotationPoint} the point to rotate around and the angle in radians to rotate
35773 * @private
35774 */
35775
35776 }, {
35777 key: "_getRotation",
35778 value: function _getRotation(ctx) {
35779 var viaNode = this.edgeType.getViaNode();
35780 var point = this.edgeType.getPoint(0.5, viaNode);
35781
35782 if (ctx !== undefined) {
35783 this.labelModule.calculateLabelSize(ctx, this.selected, this.hover, point.x, point.y);
35784 }
35785
35786 var ret = {
35787 x: point.x,
35788 y: this.labelModule.size.yLine,
35789 angle: 0
35790 };
35791
35792 if (!this.labelModule.visible()) {
35793 return ret; // Don't even bother doing the atan2, there's nothing to draw
35794 }
35795
35796 if (this.options.font.align === "horizontal") {
35797 return ret; // No need to calculate angle
35798 }
35799
35800 var dy = this.from.y - this.to.y;
35801 var dx = this.from.x - this.to.x;
35802 var angle = Math.atan2(dy, dx); // radians
35803 // rotate so that label is readable
35804
35805 if (angle < -1 && dx < 0 || angle > 0 && dx < 0) {
35806 angle += Math.PI;
35807 }
35808
35809 ret.angle = angle;
35810 return ret;
35811 }
35812 /**
35813 * Get a point on a circle
35814 * @param {number} x
35815 * @param {number} y
35816 * @param {number} radius
35817 * @param {number} percentage Value between 0 (line start) and 1 (line end)
35818 * @return {Object} point
35819 * @private
35820 */
35821
35822 }, {
35823 key: "_pointOnCircle",
35824 value: function _pointOnCircle(x, y, radius, percentage) {
35825 var angle = percentage * 2 * Math.PI;
35826 return {
35827 x: x + radius * Math.cos(angle),
35828 y: y - radius * Math.sin(angle)
35829 };
35830 }
35831 /**
35832 * Sets selected state to true
35833 */
35834
35835 }, {
35836 key: "select",
35837 value: function select() {
35838 this.selected = true;
35839 }
35840 /**
35841 * Sets selected state to false
35842 */
35843
35844 }, {
35845 key: "unselect",
35846 value: function unselect() {
35847 this.selected = false;
35848 }
35849 /**
35850 * cleans all required things on delete
35851 * @returns {*}
35852 */
35853
35854 }, {
35855 key: "cleanup",
35856 value: function cleanup() {
35857 return this.edgeType.cleanup();
35858 }
35859 /**
35860 * Remove edge from the list and perform necessary cleanup.
35861 */
35862
35863 }, {
35864 key: "remove",
35865 value: function remove() {
35866 this.cleanup();
35867 this.disconnect();
35868 delete this.body.edges[this.id];
35869 }
35870 /**
35871 * Check if both connecting nodes exist
35872 * @returns {boolean}
35873 */
35874
35875 }, {
35876 key: "endPointsValid",
35877 value: function endPointsValid() {
35878 return this.body.nodes[this.fromId] !== undefined && this.body.nodes[this.toId] !== undefined;
35879 }
35880 }], [{
35881 key: "parseOptions",
35882 value: function parseOptions(parentOptions, newOptions) {
35883 var allowDeletion = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
35884 var globalOptions = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
35885 var copyFromGlobals = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false;
35886 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.
35887
35888 selectiveDeepExtend(fields, parentOptions, newOptions, allowDeletion); // Only copy label if it's a legal value.
35889
35890 if (ComponentUtil.isValidLabel(newOptions.label)) {
35891 parentOptions.label = newOptions.label;
35892 } else if (!ComponentUtil.isValidLabel(parentOptions.label)) {
35893 parentOptions.label = undefined;
35894 }
35895
35896 mergeOptions(parentOptions, newOptions, 'smooth', globalOptions);
35897 mergeOptions(parentOptions, newOptions, 'shadow', globalOptions);
35898 mergeOptions(parentOptions, newOptions, 'background', globalOptions);
35899
35900 if (newOptions.dashes !== undefined && newOptions.dashes !== null) {
35901 parentOptions.dashes = newOptions.dashes;
35902 } else if (allowDeletion === true && newOptions.dashes === null) {
35903 parentOptions.dashes = Object.create(globalOptions.dashes); // this sets the pointer of the option back to the global option.
35904 } // set the scaling newOptions
35905
35906
35907 if (newOptions.scaling !== undefined && newOptions.scaling !== null) {
35908 if (newOptions.scaling.min !== undefined) {
35909 parentOptions.scaling.min = newOptions.scaling.min;
35910 }
35911
35912 if (newOptions.scaling.max !== undefined) {
35913 parentOptions.scaling.max = newOptions.scaling.max;
35914 }
35915
35916 mergeOptions(parentOptions.scaling, newOptions.scaling, 'label', globalOptions.scaling);
35917 } else if (allowDeletion === true && newOptions.scaling === null) {
35918 parentOptions.scaling = Object.create(globalOptions.scaling); // this sets the pointer of the option back to the global option.
35919 } // handle multiple input cases for arrows
35920
35921
35922 if (newOptions.arrows !== undefined && newOptions.arrows !== null) {
35923 if (typeof newOptions.arrows === 'string') {
35924 var arrows = newOptions.arrows.toLowerCase();
35925 parentOptions.arrows.to.enabled = arrows.indexOf("to") != -1;
35926 parentOptions.arrows.middle.enabled = arrows.indexOf("middle") != -1;
35927 parentOptions.arrows.from.enabled = arrows.indexOf("from") != -1;
35928 } else if (_typeof$1(newOptions.arrows) === 'object') {
35929 mergeOptions(parentOptions.arrows, newOptions.arrows, 'to', globalOptions.arrows);
35930 mergeOptions(parentOptions.arrows, newOptions.arrows, 'middle', globalOptions.arrows);
35931 mergeOptions(parentOptions.arrows, newOptions.arrows, 'from', globalOptions.arrows);
35932 } else {
35933 throw new Error("The arrow newOptions can only be an object or a string. Refer to the documentation. You used:" + JSON.stringify(newOptions.arrows));
35934 }
35935 } else if (allowDeletion === true && newOptions.arrows === null) {
35936 parentOptions.arrows = Object.create(globalOptions.arrows); // this sets the pointer of the option back to the global option.
35937 } // handle multiple input cases for color
35938
35939
35940 if (newOptions.color !== undefined && newOptions.color !== null) {
35941 var fromColor = isString(newOptions.color) ? {
35942 color: newOptions.color,
35943 highlight: newOptions.color,
35944 hover: newOptions.color,
35945 inherit: false,
35946 opacity: 1
35947 } : newOptions.color;
35948 var toColor = parentOptions.color; // If passed, fill in values from default options - required in the case of no prototype bridging
35949
35950 if (copyFromGlobals) {
35951 deepExtend(toColor, globalOptions.color, false, allowDeletion);
35952 } else {
35953 // Clear local properties - need to do it like this in order to retain prototype bridges
35954 for (var i in toColor) {
35955 if (toColor.hasOwnProperty(i)) {
35956 delete toColor[i];
35957 }
35958 }
35959 }
35960
35961 if (isString(toColor)) {
35962 toColor.color = toColor;
35963 toColor.highlight = toColor;
35964 toColor.hover = toColor;
35965 toColor.inherit = false;
35966
35967 if (fromColor.opacity === undefined) {
35968 toColor.opacity = 1.0; // set default
35969 }
35970 } else {
35971 var colorsDefined = false;
35972
35973 if (fromColor.color !== undefined) {
35974 toColor.color = fromColor.color;
35975 colorsDefined = true;
35976 }
35977
35978 if (fromColor.highlight !== undefined) {
35979 toColor.highlight = fromColor.highlight;
35980 colorsDefined = true;
35981 }
35982
35983 if (fromColor.hover !== undefined) {
35984 toColor.hover = fromColor.hover;
35985 colorsDefined = true;
35986 }
35987
35988 if (fromColor.inherit !== undefined) {
35989 toColor.inherit = fromColor.inherit;
35990 }
35991
35992 if (fromColor.opacity !== undefined) {
35993 toColor.opacity = Math.min(1, Math.max(0, fromColor.opacity));
35994 }
35995
35996 if (colorsDefined === true) {
35997 toColor.inherit = false;
35998 } else {
35999 if (toColor.inherit === undefined) {
36000 toColor.inherit = 'from'; // Set default
36001 }
36002 }
36003 }
36004 } else if (allowDeletion === true && newOptions.color === null) {
36005 parentOptions.color = bridgeObject(globalOptions.color); // set the object back to the global options
36006 }
36007
36008 if (allowDeletion === true && newOptions.font === null) {
36009 parentOptions.font = bridgeObject(globalOptions.font); // set the object back to the global options
36010 }
36011 }
36012 }]);
36013
36014 return Edge;
36015 }();
36016
36017 /**
36018 * Handler for Edges
36019 */
36020
36021 var EdgesHandler =
36022 /*#__PURE__*/
36023 function () {
36024 /**
36025 * @param {Object} body
36026 * @param {Array.<Image>} images
36027 * @param {Array.<Group>} groups
36028 */
36029 function EdgesHandler(body, images, groups) {
36030 var _this = this;
36031
36032 _classCallCheck(this, EdgesHandler);
36033
36034 this.body = body;
36035 this.images = images;
36036 this.groups = groups; // create the edge API in the body container
36037
36038 this.body.functions.createEdge = this.create.bind(this);
36039 this.edgesListeners = {
36040 add: function add(event, params) {
36041 _this.add(params.items);
36042 },
36043 update: function update(event, params) {
36044 _this.update(params.items);
36045 },
36046 remove: function remove(event, params) {
36047 _this.remove(params.items);
36048 }
36049 };
36050 this.options = {};
36051 this.defaultOptions = {
36052 arrows: {
36053 to: {
36054 enabled: false,
36055 scaleFactor: 1,
36056 type: 'arrow'
36057 },
36058 // boolean / {arrowScaleFactor:1} / {enabled: false, arrowScaleFactor:1}
36059 middle: {
36060 enabled: false,
36061 scaleFactor: 1,
36062 type: 'arrow'
36063 },
36064 from: {
36065 enabled: false,
36066 scaleFactor: 1,
36067 type: 'arrow'
36068 }
36069 },
36070 arrowStrikethrough: true,
36071 color: {
36072 color: '#848484',
36073 highlight: '#848484',
36074 hover: '#848484',
36075 inherit: 'from',
36076 opacity: 1.0
36077 },
36078 dashes: false,
36079 font: {
36080 color: '#343434',
36081 size: 14,
36082 // px
36083 face: 'arial',
36084 background: 'none',
36085 strokeWidth: 2,
36086 // px
36087 strokeColor: '#ffffff',
36088 align: 'horizontal',
36089 multi: false,
36090 vadjust: 0,
36091 bold: {
36092 mod: 'bold'
36093 },
36094 boldital: {
36095 mod: 'bold italic'
36096 },
36097 ital: {
36098 mod: 'italic'
36099 },
36100 mono: {
36101 mod: '',
36102 size: 15,
36103 // px
36104 face: 'courier new',
36105 vadjust: 2
36106 }
36107 },
36108 hidden: false,
36109 hoverWidth: 1.5,
36110 label: undefined,
36111 labelHighlightBold: true,
36112 length: undefined,
36113 physics: true,
36114 scaling: {
36115 min: 1,
36116 max: 15,
36117 label: {
36118 enabled: true,
36119 min: 14,
36120 max: 30,
36121 maxVisible: 30,
36122 drawThreshold: 5
36123 },
36124 customScalingFunction: function customScalingFunction(min, max, total, value) {
36125 if (max === min) {
36126 return 0.5;
36127 } else {
36128 var scale = 1 / (max - min);
36129 return Math.max(0, (value - min) * scale);
36130 }
36131 }
36132 },
36133 selectionWidth: 1.5,
36134 selfReferenceSize: 20,
36135 shadow: {
36136 enabled: false,
36137 color: 'rgba(0,0,0,0.5)',
36138 size: 10,
36139 x: 5,
36140 y: 5
36141 },
36142 background: {
36143 enabled: false,
36144 color: 'rgba(111,111,111,1)',
36145 size: 10,
36146 dashes: false
36147 },
36148 smooth: {
36149 enabled: true,
36150 type: "dynamic",
36151 forceDirection: 'none',
36152 roundness: 0.5
36153 },
36154 title: undefined,
36155 width: 1,
36156 value: undefined
36157 };
36158 deepExtend(this.options, this.defaultOptions);
36159 this.bindEventListeners();
36160 }
36161 /**
36162 * Binds event listeners
36163 */
36164
36165
36166 _createClass(EdgesHandler, [{
36167 key: "bindEventListeners",
36168 value: function bindEventListeners() {
36169 var _this2 = this;
36170
36171 // this allows external modules to force all dynamic curves to turn static.
36172 this.body.emitter.on("_forceDisableDynamicCurves", function (type) {
36173 var emit = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
36174
36175 if (type === 'dynamic') {
36176 type = 'continuous';
36177 }
36178
36179 var dataChanged = false;
36180
36181 for (var edgeId in _this2.body.edges) {
36182 if (_this2.body.edges.hasOwnProperty(edgeId)) {
36183 var edge = _this2.body.edges[edgeId];
36184 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.
36185 // this is because a change in the global would not affect these curves.
36186
36187 if (edgeData !== undefined) {
36188 var smoothOptions = edgeData.smooth;
36189
36190 if (smoothOptions !== undefined) {
36191 if (smoothOptions.enabled === true && smoothOptions.type === 'dynamic') {
36192 if (type === undefined) {
36193 edge.setOptions({
36194 smooth: false
36195 });
36196 } else {
36197 edge.setOptions({
36198 smooth: {
36199 type: type
36200 }
36201 });
36202 }
36203
36204 dataChanged = true;
36205 }
36206 }
36207 }
36208 }
36209 }
36210
36211 if (emit === true && dataChanged === true) {
36212 _this2.body.emitter.emit("_dataChanged");
36213 }
36214 }); // this is called when options of EXISTING nodes or edges have changed.
36215 //
36216 // NOTE: Not true, called when options have NOT changed, for both existing as well as new nodes.
36217 // See update() for logic.
36218 // TODO: Verify and examine the consequences of this. It might still trigger when
36219 // non-option fields have changed, but then reconnecting edges is still useless.
36220 // Alternatively, it might also be called when edges are removed.
36221 //
36222
36223 this.body.emitter.on("_dataUpdated", function () {
36224 _this2.reconnectEdges();
36225 }); // refresh the edges. Used when reverting from hierarchical layout
36226
36227 this.body.emitter.on("refreshEdges", this.refresh.bind(this));
36228 this.body.emitter.on("refresh", this.refresh.bind(this));
36229 this.body.emitter.on("destroy", function () {
36230 forEach(_this2.edgesListeners, function (callback, event) {
36231 if (_this2.body.data.edges) _this2.body.data.edges.off(event, callback);
36232 });
36233 delete _this2.body.functions.createEdge;
36234 delete _this2.edgesListeners.add;
36235 delete _this2.edgesListeners.update;
36236 delete _this2.edgesListeners.remove;
36237 delete _this2.edgesListeners;
36238 });
36239 }
36240 /**
36241 *
36242 * @param {Object} options
36243 */
36244
36245 }, {
36246 key: "setOptions",
36247 value: function setOptions(options) {
36248 if (options !== undefined) {
36249 // use the parser from the Edge class to fill in all shorthand notations
36250 Edge.parseOptions(this.options, options, true, this.defaultOptions, true); // update smooth settings in all edges
36251
36252 var dataChanged = false;
36253
36254 if (options.smooth !== undefined) {
36255 for (var edgeId in this.body.edges) {
36256 if (this.body.edges.hasOwnProperty(edgeId)) {
36257 dataChanged = this.body.edges[edgeId].updateEdgeType() || dataChanged;
36258 }
36259 }
36260 } // update fonts in all edges
36261
36262
36263 if (options.font !== undefined) {
36264 for (var _edgeId in this.body.edges) {
36265 if (this.body.edges.hasOwnProperty(_edgeId)) {
36266 this.body.edges[_edgeId].updateLabelModule();
36267 }
36268 }
36269 } // update the state of the variables if needed
36270
36271
36272 if (options.hidden !== undefined || options.physics !== undefined || dataChanged === true) {
36273 this.body.emitter.emit('_dataChanged');
36274 }
36275 }
36276 }
36277 /**
36278 * Load edges by reading the data table
36279 * @param {Array | DataSet | DataView} edges The data containing the edges.
36280 * @param {boolean} [doNotEmit=false]
36281 * @private
36282 */
36283
36284 }, {
36285 key: "setData",
36286 value: function setData(edges) {
36287 var _this3 = this;
36288
36289 var doNotEmit = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
36290 var oldEdgesData = this.body.data.edges;
36291
36292 if (edges instanceof DataSet || edges instanceof DataView$2) {
36293 this.body.data.edges = edges;
36294 } else if (Array.isArray(edges)) {
36295 this.body.data.edges = new DataSet();
36296 this.body.data.edges.add(edges);
36297 } else if (!edges) {
36298 this.body.data.edges = new DataSet();
36299 } else {
36300 throw new TypeError('Array or DataSet expected');
36301 } // TODO: is this null or undefined or false?
36302
36303
36304 if (oldEdgesData) {
36305 // unsubscribe from old dataset
36306 forEach(this.edgesListeners, function (callback, event) {
36307 oldEdgesData.off(event, callback);
36308 });
36309 } // remove drawn edges
36310
36311
36312 this.body.edges = {}; // TODO: is this null or undefined or false?
36313
36314 if (this.body.data.edges) {
36315 // subscribe to new dataset
36316 forEach(this.edgesListeners, function (callback, event) {
36317 _this3.body.data.edges.on(event, callback);
36318 }); // draw all new nodes
36319
36320 var ids = this.body.data.edges.getIds();
36321 this.add(ids, true);
36322 }
36323
36324 this.body.emitter.emit('_adjustEdgesForHierarchicalLayout');
36325
36326 if (doNotEmit === false) {
36327 this.body.emitter.emit("_dataChanged");
36328 }
36329 }
36330 /**
36331 * Add edges
36332 * @param {number[] | string[]} ids
36333 * @param {boolean} [doNotEmit=false]
36334 * @private
36335 */
36336
36337 }, {
36338 key: "add",
36339 value: function add(ids) {
36340 var doNotEmit = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
36341 var edges = this.body.edges;
36342 var edgesData = this.body.data.edges;
36343
36344 for (var i = 0; i < ids.length; i++) {
36345 var id = ids[i];
36346 var oldEdge = edges[id];
36347
36348 if (oldEdge) {
36349 oldEdge.disconnect();
36350 }
36351
36352 var data = edgesData.get(id, {
36353 "showInternalIds": true
36354 });
36355 edges[id] = this.create(data);
36356 }
36357
36358 this.body.emitter.emit('_adjustEdgesForHierarchicalLayout');
36359
36360 if (doNotEmit === false) {
36361 this.body.emitter.emit("_dataChanged");
36362 }
36363 }
36364 /**
36365 * Update existing edges, or create them when not yet existing
36366 * @param {number[] | string[]} ids
36367 * @private
36368 */
36369
36370 }, {
36371 key: "update",
36372 value: function update(ids) {
36373 var edges = this.body.edges;
36374 var edgesData = this.body.data.edges;
36375 var dataChanged = false;
36376
36377 for (var i = 0; i < ids.length; i++) {
36378 var id = ids[i];
36379 var data = edgesData.get(id);
36380 var edge = edges[id];
36381
36382 if (edge !== undefined) {
36383 // update edge
36384 edge.disconnect();
36385 dataChanged = edge.setOptions(data) || dataChanged; // if a support node is added, data can be changed.
36386
36387 edge.connect();
36388 } else {
36389 // create edge
36390 this.body.edges[id] = this.create(data);
36391 dataChanged = true;
36392 }
36393 }
36394
36395 if (dataChanged === true) {
36396 this.body.emitter.emit('_adjustEdgesForHierarchicalLayout');
36397 this.body.emitter.emit("_dataChanged");
36398 } else {
36399 this.body.emitter.emit("_dataUpdated");
36400 }
36401 }
36402 /**
36403 * Remove existing edges. Non existing ids will be ignored
36404 * @param {number[] | string[]} ids
36405 * @param {boolean} [emit=true]
36406 * @private
36407 */
36408
36409 }, {
36410 key: "remove",
36411 value: function remove(ids) {
36412 var emit = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
36413 if (ids.length === 0) return; // early out
36414
36415 var edges = this.body.edges;
36416 forEach(ids, function (id) {
36417 var edge = edges[id];
36418
36419 if (edge !== undefined) {
36420 edge.remove();
36421 }
36422 });
36423
36424 if (emit) {
36425 this.body.emitter.emit("_dataChanged");
36426 }
36427 }
36428 /**
36429 * Refreshes Edge Handler
36430 */
36431
36432 }, {
36433 key: "refresh",
36434 value: function refresh() {
36435 var _this4 = this;
36436
36437 forEach(this.body.edges, function (edge, edgeId) {
36438 var data = _this4.body.data.edges._data[edgeId];
36439
36440 if (data !== undefined) {
36441 edge.setOptions(data);
36442 }
36443 });
36444 }
36445 /**
36446 *
36447 * @param {Object} properties
36448 * @returns {Edge}
36449 */
36450
36451 }, {
36452 key: "create",
36453 value: function create(properties) {
36454 return new Edge(properties, this.body, this.images, this.options, this.defaultOptions);
36455 }
36456 /**
36457 * Reconnect all edges
36458 * @private
36459 */
36460
36461 }, {
36462 key: "reconnectEdges",
36463 value: function reconnectEdges() {
36464 var id;
36465 var nodes = this.body.nodes;
36466 var edges = this.body.edges;
36467
36468 for (id in nodes) {
36469 if (nodes.hasOwnProperty(id)) {
36470 nodes[id].edges = [];
36471 }
36472 }
36473
36474 for (id in edges) {
36475 if (edges.hasOwnProperty(id)) {
36476 var edge = edges[id];
36477 edge.from = null;
36478 edge.to = null;
36479 edge.connect();
36480 }
36481 }
36482 }
36483 /**
36484 *
36485 * @param {Edge.id} edgeId
36486 * @returns {Array}
36487 */
36488
36489 }, {
36490 key: "getConnectedNodes",
36491 value: function getConnectedNodes(edgeId) {
36492 var nodeList = [];
36493
36494 if (this.body.edges[edgeId] !== undefined) {
36495 var edge = this.body.edges[edgeId];
36496
36497 if (edge.fromId !== undefined) {
36498 nodeList.push(edge.fromId);
36499 }
36500
36501 if (edge.toId !== undefined) {
36502 nodeList.push(edge.toId);
36503 }
36504 }
36505
36506 return nodeList;
36507 }
36508 /**
36509 * There is no direct relation between the nodes and the edges DataSet,
36510 * so the right place to do call this is in the handler for event `_dataUpdated`.
36511 */
36512
36513 }, {
36514 key: "_updateState",
36515 value: function _updateState() {
36516 this._addMissingEdges();
36517
36518 this._removeInvalidEdges();
36519 }
36520 /**
36521 * Scan for missing nodes and remove corresponding edges, if any.
36522 * @private
36523 */
36524
36525 }, {
36526 key: "_removeInvalidEdges",
36527 value: function _removeInvalidEdges() {
36528 var _this5 = this;
36529
36530 var edgesToDelete = [];
36531 forEach(this.body.edges, function (edge, id) {
36532 var toNode = _this5.body.nodes[edge.toId];
36533 var fromNode = _this5.body.nodes[edge.fromId]; // Skip clustering edges here, let the Clustering module handle those
36534
36535 if (toNode !== undefined && toNode.isCluster === true || fromNode !== undefined && fromNode.isCluster === true) {
36536 return;
36537 }
36538
36539 if (toNode === undefined || fromNode === undefined) {
36540 edgesToDelete.push(id);
36541 }
36542 });
36543 this.remove(edgesToDelete, false);
36544 }
36545 /**
36546 * add all edges from dataset that are not in the cached state
36547 * @private
36548 */
36549
36550 }, {
36551 key: "_addMissingEdges",
36552 value: function _addMissingEdges() {
36553 var edgesData = this.body.data.edges;
36554
36555 if (edgesData === undefined || edgesData === null) {
36556 return; // No edges DataSet yet; can happen on startup
36557 }
36558
36559 var edges = this.body.edges;
36560 var addIds = [];
36561 edgesData.forEach(function (edgeData, edgeId) {
36562 var edge = edges[edgeId];
36563
36564 if (edge === undefined) {
36565 addIds.push(edgeId);
36566 }
36567 });
36568 this.add(addIds, true);
36569 }
36570 }]);
36571
36572 return EdgesHandler;
36573 }();
36574
36575 /**
36576 * Barnes Hut Solver
36577 */
36578 var BarnesHutSolver =
36579 /*#__PURE__*/
36580 function () {
36581 /**
36582 * @param {Object} body
36583 * @param {{physicsNodeIndices: Array, physicsEdgeIndices: Array, forces: {}, velocities: {}}} physicsBody
36584 * @param {Object} options
36585 */
36586 function BarnesHutSolver(body, physicsBody, options) {
36587 _classCallCheck(this, BarnesHutSolver);
36588
36589 this.body = body;
36590 this.physicsBody = physicsBody;
36591 this.barnesHutTree;
36592 this.setOptions(options);
36593 this.randomSeed = 5; // debug: show grid
36594 // this.body.emitter.on("afterDrawing", (ctx) => {this._debug(ctx,'#ff0000')})
36595 }
36596 /**
36597 *
36598 * @param {Object} options
36599 */
36600
36601
36602 _createClass(BarnesHutSolver, [{
36603 key: "setOptions",
36604 value: function setOptions(options) {
36605 this.options = options;
36606 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
36607
36608 this.overlapAvoidanceFactor = 1 - Math.max(0, Math.min(1, this.options.avoidOverlap));
36609 }
36610 /**
36611 *
36612 * @returns {number} random integer
36613 */
36614
36615 }, {
36616 key: "seededRandom",
36617 value: function seededRandom() {
36618 var x = Math.sin(this.randomSeed++) * 10000;
36619 return x - Math.floor(x);
36620 }
36621 /**
36622 * This function calculates the forces the nodes apply on each other based on a gravitational model.
36623 * The Barnes Hut method is used to speed up this N-body simulation.
36624 *
36625 * @private
36626 */
36627
36628 }, {
36629 key: "solve",
36630 value: function solve() {
36631 if (this.options.gravitationalConstant !== 0 && this.physicsBody.physicsNodeIndices.length > 0) {
36632 var node;
36633 var nodes = this.body.nodes;
36634 var nodeIndices = this.physicsBody.physicsNodeIndices;
36635 var nodeCount = nodeIndices.length; // create the tree
36636
36637 var barnesHutTree = this._formBarnesHutTree(nodes, nodeIndices); // for debugging
36638
36639
36640 this.barnesHutTree = barnesHutTree; // place the nodes one by one recursively
36641
36642 for (var i = 0; i < nodeCount; i++) {
36643 node = nodes[nodeIndices[i]];
36644
36645 if (node.options.mass > 0) {
36646 // starting with root is irrelevant, it never passes the BarnesHutSolver condition
36647 this._getForceContributions(barnesHutTree.root, node);
36648 }
36649 }
36650 }
36651 }
36652 /**
36653 * @param {Object} parentBranch
36654 * @param {Node} node
36655 * @private
36656 */
36657
36658 }, {
36659 key: "_getForceContributions",
36660 value: function _getForceContributions(parentBranch, node) {
36661 this._getForceContribution(parentBranch.children.NW, node);
36662
36663 this._getForceContribution(parentBranch.children.NE, node);
36664
36665 this._getForceContribution(parentBranch.children.SW, node);
36666
36667 this._getForceContribution(parentBranch.children.SE, node);
36668 }
36669 /**
36670 * This function traverses the barnesHutTree. It checks when it can approximate distant nodes with their center of mass.
36671 * If a region contains a single node, we check if it is not itself, then we apply the force.
36672 *
36673 * @param {Object} parentBranch
36674 * @param {Node} node
36675 * @private
36676 */
36677
36678 }, {
36679 key: "_getForceContribution",
36680 value: function _getForceContribution(parentBranch, node) {
36681 // we get no force contribution from an empty region
36682 if (parentBranch.childrenCount > 0) {
36683 var dx, dy, distance; // get the distance from the center of mass to the node.
36684
36685 dx = parentBranch.centerOfMass.x - node.x;
36686 dy = parentBranch.centerOfMass.y - node.y;
36687 distance = Math.sqrt(dx * dx + dy * dy); // BarnesHutSolver condition
36688 // original condition : s/d < theta = passed === d/s > 1/theta = passed
36689 // calcSize = 1/s --> d * 1/s > 1/theta = passed
36690
36691 if (distance * parentBranch.calcSize > this.thetaInversed) {
36692 this._calculateForces(distance, dx, dy, node, parentBranch);
36693 } else {
36694 // Did not pass the condition, go into children if available
36695 if (parentBranch.childrenCount === 4) {
36696 this._getForceContributions(parentBranch, node);
36697 } else {
36698 // parentBranch must have only one node, if it was empty we wouldnt be here
36699 if (parentBranch.children.data.id != node.id) {
36700 // if it is not self
36701 this._calculateForces(distance, dx, dy, node, parentBranch);
36702 }
36703 }
36704 }
36705 }
36706 }
36707 /**
36708 * Calculate the forces based on the distance.
36709 *
36710 * @param {number} distance
36711 * @param {number} dx
36712 * @param {number} dy
36713 * @param {Node} node
36714 * @param {Object} parentBranch
36715 * @private
36716 */
36717
36718 }, {
36719 key: "_calculateForces",
36720 value: function _calculateForces(distance, dx, dy, node, parentBranch) {
36721 if (distance === 0) {
36722 distance = 0.1;
36723 dx = distance;
36724 }
36725
36726 if (this.overlapAvoidanceFactor < 1 && node.shape.radius) {
36727 distance = Math.max(0.1 + this.overlapAvoidanceFactor * node.shape.radius, distance - node.shape.radius);
36728 } // the dividing by the distance cubed instead of squared allows us to get the fx and fy components without sines and cosines
36729 // it is shorthand for gravityforce with distance squared and fx = dx/distance * gravityForce
36730
36731
36732 var gravityForce = this.options.gravitationalConstant * parentBranch.mass * node.options.mass / Math.pow(distance, 3);
36733 var fx = dx * gravityForce;
36734 var fy = dy * gravityForce;
36735 this.physicsBody.forces[node.id].x += fx;
36736 this.physicsBody.forces[node.id].y += fy;
36737 }
36738 /**
36739 * This function constructs the barnesHut tree recursively. It creates the root, splits it and starts placing the nodes.
36740 *
36741 * @param {Array.<Node>} nodes
36742 * @param {Array.<number>} nodeIndices
36743 * @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
36744 * @private
36745 */
36746
36747 }, {
36748 key: "_formBarnesHutTree",
36749 value: function _formBarnesHutTree(nodes, nodeIndices) {
36750 var node;
36751 var nodeCount = nodeIndices.length;
36752 var minX = nodes[nodeIndices[0]].x;
36753 var minY = nodes[nodeIndices[0]].y;
36754 var maxX = nodes[nodeIndices[0]].x;
36755 var maxY = nodes[nodeIndices[0]].y; // get the range of the nodes
36756
36757 for (var i = 1; i < nodeCount; i++) {
36758 var _node = nodes[nodeIndices[i]];
36759 var x = _node.x;
36760 var y = _node.y;
36761
36762 if (_node.options.mass > 0) {
36763 if (x < minX) {
36764 minX = x;
36765 }
36766
36767 if (x > maxX) {
36768 maxX = x;
36769 }
36770
36771 if (y < minY) {
36772 minY = y;
36773 }
36774
36775 if (y > maxY) {
36776 maxY = y;
36777 }
36778 }
36779 } // make the range a square
36780
36781
36782 var sizeDiff = Math.abs(maxX - minX) - Math.abs(maxY - minY); // difference between X and Y
36783
36784 if (sizeDiff > 0) {
36785 minY -= 0.5 * sizeDiff;
36786 maxY += 0.5 * sizeDiff;
36787 } // xSize > ySize
36788 else {
36789 minX += 0.5 * sizeDiff;
36790 maxX -= 0.5 * sizeDiff;
36791 } // xSize < ySize
36792
36793
36794 var minimumTreeSize = 1e-5;
36795 var rootSize = Math.max(minimumTreeSize, Math.abs(maxX - minX));
36796 var halfRootSize = 0.5 * rootSize;
36797 var centerX = 0.5 * (minX + maxX),
36798 centerY = 0.5 * (minY + maxY); // construct the barnesHutTree
36799
36800 var barnesHutTree = {
36801 root: {
36802 centerOfMass: {
36803 x: 0,
36804 y: 0
36805 },
36806 mass: 0,
36807 range: {
36808 minX: centerX - halfRootSize,
36809 maxX: centerX + halfRootSize,
36810 minY: centerY - halfRootSize,
36811 maxY: centerY + halfRootSize
36812 },
36813 size: rootSize,
36814 calcSize: 1 / rootSize,
36815 children: {
36816 data: null
36817 },
36818 maxWidth: 0,
36819 level: 0,
36820 childrenCount: 4
36821 }
36822 };
36823
36824 this._splitBranch(barnesHutTree.root); // place the nodes one by one recursively
36825
36826
36827 for (var _i = 0; _i < nodeCount; _i++) {
36828 node = nodes[nodeIndices[_i]];
36829
36830 if (node.options.mass > 0) {
36831 this._placeInTree(barnesHutTree.root, node);
36832 }
36833 } // make global
36834
36835
36836 return barnesHutTree;
36837 }
36838 /**
36839 * this updates the mass of a branch. this is increased by adding a node.
36840 *
36841 * @param {Object} parentBranch
36842 * @param {Node} node
36843 * @private
36844 */
36845
36846 }, {
36847 key: "_updateBranchMass",
36848 value: function _updateBranchMass(parentBranch, node) {
36849 var centerOfMass = parentBranch.centerOfMass;
36850 var totalMass = parentBranch.mass + node.options.mass;
36851 var totalMassInv = 1 / totalMass;
36852 centerOfMass.x = centerOfMass.x * parentBranch.mass + node.x * node.options.mass;
36853 centerOfMass.x *= totalMassInv;
36854 centerOfMass.y = centerOfMass.y * parentBranch.mass + node.y * node.options.mass;
36855 centerOfMass.y *= totalMassInv;
36856 parentBranch.mass = totalMass;
36857 var biggestSize = Math.max(Math.max(node.height, node.radius), node.width);
36858 parentBranch.maxWidth = parentBranch.maxWidth < biggestSize ? biggestSize : parentBranch.maxWidth;
36859 }
36860 /**
36861 * determine in which branch the node will be placed.
36862 *
36863 * @param {Object} parentBranch
36864 * @param {Node} node
36865 * @param {boolean} skipMassUpdate
36866 * @private
36867 */
36868
36869 }, {
36870 key: "_placeInTree",
36871 value: function _placeInTree(parentBranch, node, skipMassUpdate) {
36872 if (skipMassUpdate != true || skipMassUpdate === undefined) {
36873 // update the mass of the branch.
36874 this._updateBranchMass(parentBranch, node);
36875 }
36876
36877 var range = parentBranch.children.NW.range;
36878 var region;
36879
36880 if (range.maxX > node.x) {
36881 // in NW or SW
36882 if (range.maxY > node.y) {
36883 region = "NW";
36884 } else {
36885 region = "SW";
36886 }
36887 } else {
36888 // in NE or SE
36889 if (range.maxY > node.y) {
36890 region = "NE";
36891 } else {
36892 region = "SE";
36893 }
36894 }
36895
36896 this._placeInRegion(parentBranch, node, region);
36897 }
36898 /**
36899 * actually place the node in a region (or branch)
36900 *
36901 * @param {Object} parentBranch
36902 * @param {Node} node
36903 * @param {'NW'| 'NE' | 'SW' | 'SE'} region
36904 * @private
36905 */
36906
36907 }, {
36908 key: "_placeInRegion",
36909 value: function _placeInRegion(parentBranch, node, region) {
36910 var children = parentBranch.children[region];
36911
36912 switch (children.childrenCount) {
36913 case 0:
36914 // place node here
36915 children.children.data = node;
36916 children.childrenCount = 1;
36917
36918 this._updateBranchMass(children, node);
36919
36920 break;
36921
36922 case 1:
36923 // convert into children
36924 // if there are two nodes exactly overlapping (on init, on opening of cluster etc.)
36925 // we move one node a little bit and we do not put it in the tree.
36926 if (children.children.data.x === node.x && children.children.data.y === node.y) {
36927 node.x += this.seededRandom();
36928 node.y += this.seededRandom();
36929 } else {
36930 this._splitBranch(children);
36931
36932 this._placeInTree(children, node);
36933 }
36934
36935 break;
36936
36937 case 4:
36938 // place in branch
36939 this._placeInTree(children, node);
36940
36941 break;
36942 }
36943 }
36944 /**
36945 * this function splits a branch into 4 sub branches. If the branch contained a node, we place it in the subbranch
36946 * after the split is complete.
36947 *
36948 * @param {Object} parentBranch
36949 * @private
36950 */
36951
36952 }, {
36953 key: "_splitBranch",
36954 value: function _splitBranch(parentBranch) {
36955 // if the branch is shaded with a node, replace the node in the new subset.
36956 var containedNode = null;
36957
36958 if (parentBranch.childrenCount === 1) {
36959 containedNode = parentBranch.children.data;
36960 parentBranch.mass = 0;
36961 parentBranch.centerOfMass.x = 0;
36962 parentBranch.centerOfMass.y = 0;
36963 }
36964
36965 parentBranch.childrenCount = 4;
36966 parentBranch.children.data = null;
36967
36968 this._insertRegion(parentBranch, "NW");
36969
36970 this._insertRegion(parentBranch, "NE");
36971
36972 this._insertRegion(parentBranch, "SW");
36973
36974 this._insertRegion(parentBranch, "SE");
36975
36976 if (containedNode != null) {
36977 this._placeInTree(parentBranch, containedNode);
36978 }
36979 }
36980 /**
36981 * This function subdivides the region into four new segments.
36982 * Specifically, this inserts a single new segment.
36983 * It fills the children section of the parentBranch
36984 *
36985 * @param {Object} parentBranch
36986 * @param {'NW'| 'NE' | 'SW' | 'SE'} region
36987 * @private
36988 */
36989
36990 }, {
36991 key: "_insertRegion",
36992 value: function _insertRegion(parentBranch, region) {
36993 var minX, maxX, minY, maxY;
36994 var childSize = 0.5 * parentBranch.size;
36995
36996 switch (region) {
36997 case "NW":
36998 minX = parentBranch.range.minX;
36999 maxX = parentBranch.range.minX + childSize;
37000 minY = parentBranch.range.minY;
37001 maxY = parentBranch.range.minY + childSize;
37002 break;
37003
37004 case "NE":
37005 minX = parentBranch.range.minX + childSize;
37006 maxX = parentBranch.range.maxX;
37007 minY = parentBranch.range.minY;
37008 maxY = parentBranch.range.minY + childSize;
37009 break;
37010
37011 case "SW":
37012 minX = parentBranch.range.minX;
37013 maxX = parentBranch.range.minX + childSize;
37014 minY = parentBranch.range.minY + childSize;
37015 maxY = parentBranch.range.maxY;
37016 break;
37017
37018 case "SE":
37019 minX = parentBranch.range.minX + childSize;
37020 maxX = parentBranch.range.maxX;
37021 minY = parentBranch.range.minY + childSize;
37022 maxY = parentBranch.range.maxY;
37023 break;
37024 }
37025
37026 parentBranch.children[region] = {
37027 centerOfMass: {
37028 x: 0,
37029 y: 0
37030 },
37031 mass: 0,
37032 range: {
37033 minX: minX,
37034 maxX: maxX,
37035 minY: minY,
37036 maxY: maxY
37037 },
37038 size: 0.5 * parentBranch.size,
37039 calcSize: 2 * parentBranch.calcSize,
37040 children: {
37041 data: null
37042 },
37043 maxWidth: 0,
37044 level: parentBranch.level + 1,
37045 childrenCount: 0
37046 };
37047 } //--------------------------- DEBUGGING BELOW ---------------------------//
37048
37049 /**
37050 * This function is for debugging purposed, it draws the tree.
37051 *
37052 * @param {CanvasRenderingContext2D} ctx
37053 * @param {string} color
37054 * @private
37055 */
37056
37057 }, {
37058 key: "_debug",
37059 value: function _debug(ctx, color) {
37060 if (this.barnesHutTree !== undefined) {
37061 ctx.lineWidth = 1;
37062
37063 this._drawBranch(this.barnesHutTree.root, ctx, color);
37064 }
37065 }
37066 /**
37067 * This function is for debugging purposes. It draws the branches recursively.
37068 *
37069 * @param {Object} branch
37070 * @param {CanvasRenderingContext2D} ctx
37071 * @param {string} color
37072 * @private
37073 */
37074
37075 }, {
37076 key: "_drawBranch",
37077 value: function _drawBranch(branch, ctx, color) {
37078 if (color === undefined) {
37079 color = "#FF0000";
37080 }
37081
37082 if (branch.childrenCount === 4) {
37083 this._drawBranch(branch.children.NW, ctx);
37084
37085 this._drawBranch(branch.children.NE, ctx);
37086
37087 this._drawBranch(branch.children.SE, ctx);
37088
37089 this._drawBranch(branch.children.SW, ctx);
37090 }
37091
37092 ctx.strokeStyle = color;
37093 ctx.beginPath();
37094 ctx.moveTo(branch.range.minX, branch.range.minY);
37095 ctx.lineTo(branch.range.maxX, branch.range.minY);
37096 ctx.stroke();
37097 ctx.beginPath();
37098 ctx.moveTo(branch.range.maxX, branch.range.minY);
37099 ctx.lineTo(branch.range.maxX, branch.range.maxY);
37100 ctx.stroke();
37101 ctx.beginPath();
37102 ctx.moveTo(branch.range.maxX, branch.range.maxY);
37103 ctx.lineTo(branch.range.minX, branch.range.maxY);
37104 ctx.stroke();
37105 ctx.beginPath();
37106 ctx.moveTo(branch.range.minX, branch.range.maxY);
37107 ctx.lineTo(branch.range.minX, branch.range.minY);
37108 ctx.stroke();
37109 /*
37110 if (branch.mass > 0) {
37111 ctx.circle(branch.centerOfMass.x, branch.centerOfMass.y, 3*branch.mass);
37112 ctx.stroke();
37113 }
37114 */
37115 }
37116 }]);
37117
37118 return BarnesHutSolver;
37119 }();
37120
37121 /**
37122 * Repulsion Solver
37123 */
37124 var RepulsionSolver =
37125 /*#__PURE__*/
37126 function () {
37127 /**
37128 * @param {Object} body
37129 * @param {{physicsNodeIndices: Array, physicsEdgeIndices: Array, forces: {}, velocities: {}}} physicsBody
37130 * @param {Object} options
37131 */
37132 function RepulsionSolver(body, physicsBody, options) {
37133 _classCallCheck(this, RepulsionSolver);
37134
37135 this.body = body;
37136 this.physicsBody = physicsBody;
37137 this.setOptions(options);
37138 }
37139 /**
37140 *
37141 * @param {Object} options
37142 */
37143
37144
37145 _createClass(RepulsionSolver, [{
37146 key: "setOptions",
37147 value: function setOptions(options) {
37148 this.options = options;
37149 }
37150 /**
37151 * Calculate the forces the nodes apply on each other based on a repulsion field.
37152 * This field is linearly approximated.
37153 *
37154 * @private
37155 */
37156
37157 }, {
37158 key: "solve",
37159 value: function solve() {
37160 var dx, dy, distance, fx, fy, repulsingForce, node1, node2;
37161 var nodes = this.body.nodes;
37162 var nodeIndices = this.physicsBody.physicsNodeIndices;
37163 var forces = this.physicsBody.forces; // repulsing forces between nodes
37164
37165 var nodeDistance = this.options.nodeDistance; // approximation constants
37166
37167 var a = -2 / 3 / nodeDistance;
37168 var b = 4 / 3; // we loop from i over all but the last entree in the array
37169 // j loops from i+1 to the last. This way we do not double count any of the indices, nor i === j
37170
37171 for (var i = 0; i < nodeIndices.length - 1; i++) {
37172 node1 = nodes[nodeIndices[i]];
37173
37174 for (var j = i + 1; j < nodeIndices.length; j++) {
37175 node2 = nodes[nodeIndices[j]];
37176 dx = node2.x - node1.x;
37177 dy = node2.y - node1.y;
37178 distance = Math.sqrt(dx * dx + dy * dy); // same condition as BarnesHutSolver, making sure nodes are never 100% overlapping.
37179
37180 if (distance === 0) {
37181 distance = 0.1 * Math.random();
37182 dx = distance;
37183 }
37184
37185 if (distance < 2 * nodeDistance) {
37186 if (distance < 0.5 * nodeDistance) {
37187 repulsingForce = 1.0;
37188 } else {
37189 repulsingForce = a * distance + b; // linear approx of 1 / (1 + Math.exp((distance / nodeDistance - 1) * steepness))
37190 }
37191
37192 repulsingForce = repulsingForce / distance;
37193 fx = dx * repulsingForce;
37194 fy = dy * repulsingForce;
37195 forces[node1.id].x -= fx;
37196 forces[node1.id].y -= fy;
37197 forces[node2.id].x += fx;
37198 forces[node2.id].y += fy;
37199 }
37200 }
37201 }
37202 }
37203 }]);
37204
37205 return RepulsionSolver;
37206 }();
37207
37208 /**
37209 * Hierarchical Repulsion Solver
37210 */
37211 var HierarchicalRepulsionSolver =
37212 /*#__PURE__*/
37213 function () {
37214 /**
37215 * @param {Object} body
37216 * @param {{physicsNodeIndices: Array, physicsEdgeIndices: Array, forces: {}, velocities: {}}} physicsBody
37217 * @param {Object} options
37218 */
37219 function HierarchicalRepulsionSolver(body, physicsBody, options) {
37220 _classCallCheck(this, HierarchicalRepulsionSolver);
37221
37222 this.body = body;
37223 this.physicsBody = physicsBody;
37224 this.setOptions(options);
37225 }
37226 /**
37227 *
37228 * @param {Object} options
37229 */
37230
37231
37232 _createClass(HierarchicalRepulsionSolver, [{
37233 key: "setOptions",
37234 value: function setOptions(options) {
37235 this.options = options;
37236 this.overlapAvoidanceFactor = Math.max(0, Math.min(1, this.options.avoidOverlap || 0));
37237 }
37238 /**
37239 * Calculate the forces the nodes apply on each other based on a repulsion field.
37240 * This field is linearly approximated.
37241 *
37242 * @private
37243 */
37244
37245 }, {
37246 key: "solve",
37247 value: function solve() {
37248 var nodes = this.body.nodes;
37249 var nodeIndices = this.physicsBody.physicsNodeIndices;
37250 var forces = this.physicsBody.forces; // repulsing forces between nodes
37251
37252 var nodeDistance = this.options.nodeDistance; // we loop from i over all but the last entree in the array
37253 // j loops from i+1 to the last. This way we do not double count any of the indices, nor i === j
37254
37255 for (var i = 0; i < nodeIndices.length - 1; i++) {
37256 var node1 = nodes[nodeIndices[i]];
37257
37258 for (var j = i + 1; j < nodeIndices.length; j++) {
37259 var node2 = nodes[nodeIndices[j]]; // nodes only affect nodes on their level
37260
37261 if (node1.level === node2.level) {
37262 var theseNodesDistance = nodeDistance + this.overlapAvoidanceFactor * ((node1.shape.radius || 0) / 2 + (node2.shape.radius || 0) / 2);
37263 var dx = node2.x - node1.x;
37264 var dy = node2.y - node1.y;
37265 var distance = Math.sqrt(dx * dx + dy * dy);
37266 var steepness = 0.05;
37267 var repulsingForce = void 0;
37268
37269 if (distance < theseNodesDistance) {
37270 repulsingForce = -Math.pow(steepness * distance, 2) + Math.pow(steepness * theseNodesDistance, 2);
37271 } else {
37272 repulsingForce = 0;
37273 } // normalize force with
37274
37275
37276 if (distance === 0) {
37277 distance = (_readOnlyError("distance"), 0.01);
37278 } else {
37279 repulsingForce = repulsingForce / distance;
37280 }
37281
37282 var fx = dx * repulsingForce;
37283 var fy = dy * repulsingForce;
37284 forces[node1.id].x -= fx;
37285 forces[node1.id].y -= fy;
37286 forces[node2.id].x += fx;
37287 forces[node2.id].y += fy;
37288 }
37289 }
37290 }
37291 }
37292 }]);
37293
37294 return HierarchicalRepulsionSolver;
37295 }();
37296
37297 /**
37298 * Spring Solver
37299 */
37300 var SpringSolver =
37301 /*#__PURE__*/
37302 function () {
37303 /**
37304 * @param {Object} body
37305 * @param {{physicsNodeIndices: Array, physicsEdgeIndices: Array, forces: {}, velocities: {}}} physicsBody
37306 * @param {Object} options
37307 */
37308 function SpringSolver(body, physicsBody, options) {
37309 _classCallCheck(this, SpringSolver);
37310
37311 this.body = body;
37312 this.physicsBody = physicsBody;
37313 this.setOptions(options);
37314 }
37315 /**
37316 *
37317 * @param {Object} options
37318 */
37319
37320
37321 _createClass(SpringSolver, [{
37322 key: "setOptions",
37323 value: function setOptions(options) {
37324 this.options = options;
37325 }
37326 /**
37327 * This function calculates the springforces on the nodes, accounting for the support nodes.
37328 *
37329 * @private
37330 */
37331
37332 }, {
37333 key: "solve",
37334 value: function solve() {
37335 var edgeLength, edge;
37336 var edgeIndices = this.physicsBody.physicsEdgeIndices;
37337 var edges = this.body.edges;
37338 var node1, node2, node3; // forces caused by the edges, modelled as springs
37339
37340 for (var i = 0; i < edgeIndices.length; i++) {
37341 edge = edges[edgeIndices[i]];
37342
37343 if (edge.connected === true && edge.toId !== edge.fromId) {
37344 // only calculate forces if nodes are in the same sector
37345 if (this.body.nodes[edge.toId] !== undefined && this.body.nodes[edge.fromId] !== undefined) {
37346 if (edge.edgeType.via !== undefined) {
37347 edgeLength = edge.options.length === undefined ? this.options.springLength : edge.options.length;
37348 node1 = edge.to;
37349 node2 = edge.edgeType.via;
37350 node3 = edge.from;
37351
37352 this._calculateSpringForce(node1, node2, 0.5 * edgeLength);
37353
37354 this._calculateSpringForce(node2, node3, 0.5 * edgeLength);
37355 } else {
37356 // the * 1.5 is here so the edge looks as large as a smooth edge. It does not initially because the smooth edges use
37357 // the support nodes which exert a repulsive force on the to and from nodes, making the edge appear larger.
37358 edgeLength = edge.options.length === undefined ? this.options.springLength * 1.5 : edge.options.length;
37359
37360 this._calculateSpringForce(edge.from, edge.to, edgeLength);
37361 }
37362 }
37363 }
37364 }
37365 }
37366 /**
37367 * This is the code actually performing the calculation for the function above.
37368 *
37369 * @param {Node} node1
37370 * @param {Node} node2
37371 * @param {number} edgeLength
37372 * @private
37373 */
37374
37375 }, {
37376 key: "_calculateSpringForce",
37377 value: function _calculateSpringForce(node1, node2, edgeLength) {
37378 var dx = node1.x - node2.x;
37379 var dy = node1.y - node2.y;
37380 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.
37381
37382 var springForce = this.options.springConstant * (edgeLength - distance) / distance;
37383 var fx = dx * springForce;
37384 var fy = dy * springForce; // handle the case where one node is not part of the physcis
37385
37386 if (this.physicsBody.forces[node1.id] !== undefined) {
37387 this.physicsBody.forces[node1.id].x += fx;
37388 this.physicsBody.forces[node1.id].y += fy;
37389 }
37390
37391 if (this.physicsBody.forces[node2.id] !== undefined) {
37392 this.physicsBody.forces[node2.id].x -= fx;
37393 this.physicsBody.forces[node2.id].y -= fy;
37394 }
37395 }
37396 }]);
37397
37398 return SpringSolver;
37399 }();
37400
37401 /**
37402 * Hierarchical Spring Solver
37403 */
37404 var HierarchicalSpringSolver =
37405 /*#__PURE__*/
37406 function () {
37407 /**
37408 * @param {Object} body
37409 * @param {{physicsNodeIndices: Array, physicsEdgeIndices: Array, forces: {}, velocities: {}}} physicsBody
37410 * @param {Object} options
37411 */
37412 function HierarchicalSpringSolver(body, physicsBody, options) {
37413 _classCallCheck(this, HierarchicalSpringSolver);
37414
37415 this.body = body;
37416 this.physicsBody = physicsBody;
37417 this.setOptions(options);
37418 }
37419 /**
37420 *
37421 * @param {Object} options
37422 */
37423
37424
37425 _createClass(HierarchicalSpringSolver, [{
37426 key: "setOptions",
37427 value: function setOptions(options) {
37428 this.options = options;
37429 }
37430 /**
37431 * This function calculates the springforces on the nodes, accounting for the support nodes.
37432 *
37433 * @private
37434 */
37435
37436 }, {
37437 key: "solve",
37438 value: function solve() {
37439 var edgeLength, edge;
37440 var dx, dy, fx, fy, springForce, distance;
37441 var edges = this.body.edges;
37442 var factor = 0.5;
37443 var edgeIndices = this.physicsBody.physicsEdgeIndices;
37444 var nodeIndices = this.physicsBody.physicsNodeIndices;
37445 var forces = this.physicsBody.forces; // initialize the spring force counters
37446
37447 for (var i = 0; i < nodeIndices.length; i++) {
37448 var nodeId = nodeIndices[i];
37449 forces[nodeId].springFx = 0;
37450 forces[nodeId].springFy = 0;
37451 } // forces caused by the edges, modelled as springs
37452
37453
37454 for (var _i = 0; _i < edgeIndices.length; _i++) {
37455 edge = edges[edgeIndices[_i]];
37456
37457 if (edge.connected === true) {
37458 edgeLength = edge.options.length === undefined ? this.options.springLength : edge.options.length;
37459 dx = edge.from.x - edge.to.x;
37460 dy = edge.from.y - edge.to.y;
37461 distance = Math.sqrt(dx * dx + dy * dy);
37462 distance = distance === 0 ? 0.01 : distance; // the 1/distance is so the fx and fy can be calculated without sine or cosine.
37463
37464 springForce = this.options.springConstant * (edgeLength - distance) / distance;
37465 fx = dx * springForce;
37466 fy = dy * springForce;
37467
37468 if (edge.to.level != edge.from.level) {
37469 if (forces[edge.toId] !== undefined) {
37470 forces[edge.toId].springFx -= fx;
37471 forces[edge.toId].springFy -= fy;
37472 }
37473
37474 if (forces[edge.fromId] !== undefined) {
37475 forces[edge.fromId].springFx += fx;
37476 forces[edge.fromId].springFy += fy;
37477 }
37478 } else {
37479 if (forces[edge.toId] !== undefined) {
37480 forces[edge.toId].x -= factor * fx;
37481 forces[edge.toId].y -= factor * fy;
37482 }
37483
37484 if (forces[edge.fromId] !== undefined) {
37485 forces[edge.fromId].x += factor * fx;
37486 forces[edge.fromId].y += factor * fy;
37487 }
37488 }
37489 }
37490 } // normalize spring forces
37491
37492
37493 springForce = 1;
37494 var springFx, springFy;
37495
37496 for (var _i2 = 0; _i2 < nodeIndices.length; _i2++) {
37497 var _nodeId = nodeIndices[_i2];
37498 springFx = Math.min(springForce, Math.max(-springForce, forces[_nodeId].springFx));
37499 springFy = Math.min(springForce, Math.max(-springForce, forces[_nodeId].springFy));
37500 forces[_nodeId].x += springFx;
37501 forces[_nodeId].y += springFy;
37502 } // retain energy balance
37503
37504
37505 var totalFx = 0;
37506 var totalFy = 0;
37507
37508 for (var _i3 = 0; _i3 < nodeIndices.length; _i3++) {
37509 var _nodeId2 = nodeIndices[_i3];
37510 totalFx += forces[_nodeId2].x;
37511 totalFy += forces[_nodeId2].y;
37512 }
37513
37514 var correctionFx = totalFx / nodeIndices.length;
37515 var correctionFy = totalFy / nodeIndices.length;
37516
37517 for (var _i4 = 0; _i4 < nodeIndices.length; _i4++) {
37518 var _nodeId3 = nodeIndices[_i4];
37519 forces[_nodeId3].x -= correctionFx;
37520 forces[_nodeId3].y -= correctionFy;
37521 }
37522 }
37523 }]);
37524
37525 return HierarchicalSpringSolver;
37526 }();
37527
37528 /**
37529 * Central Gravity Solver
37530 */
37531 var CentralGravitySolver =
37532 /*#__PURE__*/
37533 function () {
37534 /**
37535 * @param {Object} body
37536 * @param {{physicsNodeIndices: Array, physicsEdgeIndices: Array, forces: {}, velocities: {}}} physicsBody
37537 * @param {Object} options
37538 */
37539 function CentralGravitySolver(body, physicsBody, options) {
37540 _classCallCheck(this, CentralGravitySolver);
37541
37542 this.body = body;
37543 this.physicsBody = physicsBody;
37544 this.setOptions(options);
37545 }
37546 /**
37547 *
37548 * @param {Object} options
37549 */
37550
37551
37552 _createClass(CentralGravitySolver, [{
37553 key: "setOptions",
37554 value: function setOptions(options) {
37555 this.options = options;
37556 }
37557 /**
37558 * Calculates forces for each node
37559 */
37560
37561 }, {
37562 key: "solve",
37563 value: function solve() {
37564 var dx, dy, distance, node;
37565 var nodes = this.body.nodes;
37566 var nodeIndices = this.physicsBody.physicsNodeIndices;
37567 var forces = this.physicsBody.forces;
37568
37569 for (var i = 0; i < nodeIndices.length; i++) {
37570 var nodeId = nodeIndices[i];
37571 node = nodes[nodeId];
37572 dx = -node.x;
37573 dy = -node.y;
37574 distance = Math.sqrt(dx * dx + dy * dy);
37575
37576 this._calculateForces(distance, dx, dy, forces, node);
37577 }
37578 }
37579 /**
37580 * Calculate the forces based on the distance.
37581 * @param {number} distance
37582 * @param {number} dx
37583 * @param {number} dy
37584 * @param {Object<Node.id, vis.Node>} forces
37585 * @param {Node} node
37586 * @private
37587 */
37588
37589 }, {
37590 key: "_calculateForces",
37591 value: function _calculateForces(distance, dx, dy, forces, node) {
37592 var gravityForce = distance === 0 ? 0 : this.options.centralGravity / distance;
37593 forces[node.id].x = dx * gravityForce;
37594 forces[node.id].y = dy * gravityForce;
37595 }
37596 }]);
37597
37598 return CentralGravitySolver;
37599 }();
37600
37601 /**
37602 * @extends BarnesHutSolver
37603 */
37604
37605 var ForceAtlas2BasedRepulsionSolver =
37606 /*#__PURE__*/
37607 function (_BarnesHutSolver) {
37608 _inherits(ForceAtlas2BasedRepulsionSolver, _BarnesHutSolver);
37609
37610 /**
37611 * @param {Object} body
37612 * @param {{physicsNodeIndices: Array, physicsEdgeIndices: Array, forces: {}, velocities: {}}} physicsBody
37613 * @param {Object} options
37614 */
37615 function ForceAtlas2BasedRepulsionSolver(body, physicsBody, options) {
37616 _classCallCheck(this, ForceAtlas2BasedRepulsionSolver);
37617
37618 return _possibleConstructorReturn(this, _getPrototypeOf(ForceAtlas2BasedRepulsionSolver).call(this, body, physicsBody, options));
37619 }
37620 /**
37621 * Calculate the forces based on the distance.
37622 *
37623 * @param {number} distance
37624 * @param {number} dx
37625 * @param {number} dy
37626 * @param {Node} node
37627 * @param {Object} parentBranch
37628 * @private
37629 */
37630
37631
37632 _createClass(ForceAtlas2BasedRepulsionSolver, [{
37633 key: "_calculateForces",
37634 value: function _calculateForces(distance, dx, dy, node, parentBranch) {
37635 if (distance === 0) {
37636 distance = 0.1 * Math.random();
37637 dx = distance;
37638 }
37639
37640 if (this.overlapAvoidanceFactor < 1 && node.shape.radius) {
37641 distance = Math.max(0.1 + this.overlapAvoidanceFactor * node.shape.radius, distance - node.shape.radius);
37642 }
37643
37644 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
37645 // it is shorthand for gravityforce with distance squared and fx = dx/distance * gravityForce
37646
37647 var gravityForce = this.options.gravitationalConstant * parentBranch.mass * node.options.mass * degree / Math.pow(distance, 2);
37648 var fx = dx * gravityForce;
37649 var fy = dy * gravityForce;
37650 this.physicsBody.forces[node.id].x += fx;
37651 this.physicsBody.forces[node.id].y += fy;
37652 }
37653 }]);
37654
37655 return ForceAtlas2BasedRepulsionSolver;
37656 }(BarnesHutSolver);
37657
37658 /**
37659 * @extends CentralGravitySolver
37660 */
37661
37662 var ForceAtlas2BasedCentralGravitySolver =
37663 /*#__PURE__*/
37664 function (_CentralGravitySolver) {
37665 _inherits(ForceAtlas2BasedCentralGravitySolver, _CentralGravitySolver);
37666
37667 /**
37668 * @param {Object} body
37669 * @param {{physicsNodeIndices: Array, physicsEdgeIndices: Array, forces: {}, velocities: {}}} physicsBody
37670 * @param {Object} options
37671 */
37672 function ForceAtlas2BasedCentralGravitySolver(body, physicsBody, options) {
37673 _classCallCheck(this, ForceAtlas2BasedCentralGravitySolver);
37674
37675 return _possibleConstructorReturn(this, _getPrototypeOf(ForceAtlas2BasedCentralGravitySolver).call(this, body, physicsBody, options));
37676 }
37677 /**
37678 * Calculate the forces based on the distance.
37679 *
37680 * @param {number} distance
37681 * @param {number} dx
37682 * @param {number} dy
37683 * @param {Object<Node.id, Node>} forces
37684 * @param {Node} node
37685 * @private
37686 */
37687
37688
37689 _createClass(ForceAtlas2BasedCentralGravitySolver, [{
37690 key: "_calculateForces",
37691 value: function _calculateForces(distance, dx, dy, forces, node) {
37692 if (distance > 0) {
37693 var degree = node.edges.length + 1;
37694 var gravityForce = this.options.centralGravity * degree * node.options.mass;
37695 forces[node.id].x = dx * gravityForce;
37696 forces[node.id].y = dy * gravityForce;
37697 }
37698 }
37699 }]);
37700
37701 return ForceAtlas2BasedCentralGravitySolver;
37702 }(CentralGravitySolver);
37703
37704 /**
37705 * The physics engine
37706 */
37707
37708 var PhysicsEngine =
37709 /*#__PURE__*/
37710 function () {
37711 /**
37712 * @param {Object} body
37713 */
37714 function PhysicsEngine(body) {
37715 _classCallCheck(this, PhysicsEngine);
37716
37717 this.body = body;
37718 this.physicsBody = {
37719 physicsNodeIndices: [],
37720 physicsEdgeIndices: [],
37721 forces: {},
37722 velocities: {}
37723 };
37724 this.physicsEnabled = true;
37725 this.simulationInterval = 1000 / 60;
37726 this.requiresTimeout = true;
37727 this.previousStates = {};
37728 this.referenceState = {};
37729 this.freezeCache = {};
37730 this.renderTimer = undefined; // parameters for the adaptive timestep
37731
37732 this.adaptiveTimestep = false;
37733 this.adaptiveTimestepEnabled = false;
37734 this.adaptiveCounter = 0;
37735 this.adaptiveInterval = 3;
37736 this.stabilized = false;
37737 this.startedStabilization = false;
37738 this.stabilizationIterations = 0;
37739 this.ready = false; // will be set to true if the stabilize
37740 // default options
37741
37742 this.options = {};
37743 this.defaultOptions = {
37744 enabled: true,
37745 barnesHut: {
37746 theta: 0.5,
37747 gravitationalConstant: -2000,
37748 centralGravity: 0.3,
37749 springLength: 95,
37750 springConstant: 0.04,
37751 damping: 0.09,
37752 avoidOverlap: 0
37753 },
37754 forceAtlas2Based: {
37755 theta: 0.5,
37756 gravitationalConstant: -50,
37757 centralGravity: 0.01,
37758 springConstant: 0.08,
37759 springLength: 100,
37760 damping: 0.4,
37761 avoidOverlap: 0
37762 },
37763 repulsion: {
37764 centralGravity: 0.2,
37765 springLength: 200,
37766 springConstant: 0.05,
37767 nodeDistance: 100,
37768 damping: 0.09,
37769 avoidOverlap: 0
37770 },
37771 hierarchicalRepulsion: {
37772 centralGravity: 0.0,
37773 springLength: 100,
37774 springConstant: 0.01,
37775 nodeDistance: 120,
37776 damping: 0.09
37777 },
37778 maxVelocity: 50,
37779 minVelocity: 0.75,
37780 // px/s
37781 solver: 'barnesHut',
37782 stabilization: {
37783 enabled: true,
37784 iterations: 1000,
37785 // maximum number of iteration to stabilize
37786 updateInterval: 50,
37787 onlyDynamicEdges: false,
37788 fit: true
37789 },
37790 timestep: 0.5,
37791 adaptiveTimestep: true
37792 };
37793 extend(this.options, this.defaultOptions);
37794 this.timestep = 0.5;
37795 this.layoutFailed = false;
37796 this.bindEventListeners();
37797 }
37798 /**
37799 * Binds event listeners
37800 */
37801
37802
37803 _createClass(PhysicsEngine, [{
37804 key: "bindEventListeners",
37805 value: function bindEventListeners() {
37806 var _this = this;
37807
37808 this.body.emitter.on('initPhysics', function () {
37809 _this.initPhysics();
37810 });
37811 this.body.emitter.on('_layoutFailed', function () {
37812 _this.layoutFailed = true;
37813 });
37814 this.body.emitter.on('resetPhysics', function () {
37815 _this.stopSimulation();
37816
37817 _this.ready = false;
37818 });
37819 this.body.emitter.on('disablePhysics', function () {
37820 _this.physicsEnabled = false;
37821
37822 _this.stopSimulation();
37823 });
37824 this.body.emitter.on('restorePhysics', function () {
37825 _this.setOptions(_this.options);
37826
37827 if (_this.ready === true) {
37828 _this.startSimulation();
37829 }
37830 });
37831 this.body.emitter.on('startSimulation', function () {
37832 if (_this.ready === true) {
37833 _this.startSimulation();
37834 }
37835 });
37836 this.body.emitter.on('stopSimulation', function () {
37837 _this.stopSimulation();
37838 });
37839 this.body.emitter.on('destroy', function () {
37840 _this.stopSimulation(false);
37841
37842 _this.body.emitter.off();
37843 });
37844 this.body.emitter.on("_dataChanged", function () {
37845 // Nodes and/or edges have been added or removed, update shortcut lists.
37846 _this.updatePhysicsData();
37847 }); // debug: show forces
37848 // this.body.emitter.on("afterDrawing", (ctx) => {this._drawForces(ctx);});
37849 }
37850 /**
37851 * set the physics options
37852 * @param {Object} options
37853 */
37854
37855 }, {
37856 key: "setOptions",
37857 value: function setOptions(options) {
37858 if (options !== undefined) {
37859 if (options === false) {
37860 this.options.enabled = false;
37861 this.physicsEnabled = false;
37862 this.stopSimulation();
37863 } else if (options === true) {
37864 this.options.enabled = true;
37865 this.physicsEnabled = true;
37866 this.startSimulation();
37867 } else {
37868 this.physicsEnabled = true;
37869 selectiveNotDeepExtend(['stabilization'], this.options, options);
37870 mergeOptions(this.options, options, 'stabilization');
37871
37872 if (options.enabled === undefined) {
37873 this.options.enabled = true;
37874 }
37875
37876 if (this.options.enabled === false) {
37877 this.physicsEnabled = false;
37878 this.stopSimulation();
37879 } // set the timestep
37880
37881
37882 this.timestep = this.options.timestep;
37883 }
37884 }
37885
37886 this.init();
37887 }
37888 /**
37889 * configure the engine.
37890 */
37891
37892 }, {
37893 key: "init",
37894 value: function init() {
37895 var options;
37896
37897 if (this.options.solver === 'forceAtlas2Based') {
37898 options = this.options.forceAtlas2Based;
37899 this.nodesSolver = new ForceAtlas2BasedRepulsionSolver(this.body, this.physicsBody, options);
37900 this.edgesSolver = new SpringSolver(this.body, this.physicsBody, options);
37901 this.gravitySolver = new ForceAtlas2BasedCentralGravitySolver(this.body, this.physicsBody, options);
37902 } else if (this.options.solver === 'repulsion') {
37903 options = this.options.repulsion;
37904 this.nodesSolver = new RepulsionSolver(this.body, this.physicsBody, options);
37905 this.edgesSolver = new SpringSolver(this.body, this.physicsBody, options);
37906 this.gravitySolver = new CentralGravitySolver(this.body, this.physicsBody, options);
37907 } else if (this.options.solver === 'hierarchicalRepulsion') {
37908 options = this.options.hierarchicalRepulsion;
37909 this.nodesSolver = new HierarchicalRepulsionSolver(this.body, this.physicsBody, options);
37910 this.edgesSolver = new HierarchicalSpringSolver(this.body, this.physicsBody, options);
37911 this.gravitySolver = new CentralGravitySolver(this.body, this.physicsBody, options);
37912 } else {
37913 // barnesHut
37914 options = this.options.barnesHut;
37915 this.nodesSolver = new BarnesHutSolver(this.body, this.physicsBody, options);
37916 this.edgesSolver = new SpringSolver(this.body, this.physicsBody, options);
37917 this.gravitySolver = new CentralGravitySolver(this.body, this.physicsBody, options);
37918 }
37919
37920 this.modelOptions = options;
37921 }
37922 /**
37923 * initialize the engine
37924 */
37925
37926 }, {
37927 key: "initPhysics",
37928 value: function initPhysics() {
37929 if (this.physicsEnabled === true && this.options.enabled === true) {
37930 if (this.options.stabilization.enabled === true) {
37931 this.stabilize();
37932 } else {
37933 this.stabilized = false;
37934 this.ready = true;
37935 this.body.emitter.emit('fit', {}, this.layoutFailed); // if the layout failed, we use the approximation for the zoom
37936
37937 this.startSimulation();
37938 }
37939 } else {
37940 this.ready = true;
37941 this.body.emitter.emit('fit');
37942 }
37943 }
37944 /**
37945 * Start the simulation
37946 */
37947
37948 }, {
37949 key: "startSimulation",
37950 value: function startSimulation() {
37951 if (this.physicsEnabled === true && this.options.enabled === true) {
37952 this.stabilized = false; // when visible, adaptivity is disabled.
37953
37954 this.adaptiveTimestep = false; // this sets the width of all nodes initially which could be required for the avoidOverlap
37955
37956 this.body.emitter.emit("_resizeNodes");
37957
37958 if (this.viewFunction === undefined) {
37959 this.viewFunction = this.simulationStep.bind(this);
37960 this.body.emitter.on('initRedraw', this.viewFunction);
37961 this.body.emitter.emit('_startRendering');
37962 }
37963 } else {
37964 this.body.emitter.emit('_redraw');
37965 }
37966 }
37967 /**
37968 * Stop the simulation, force stabilization.
37969 * @param {boolean} [emit=true]
37970 */
37971
37972 }, {
37973 key: "stopSimulation",
37974 value: function stopSimulation() {
37975 var emit = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
37976 this.stabilized = true;
37977
37978 if (emit === true) {
37979 this._emitStabilized();
37980 }
37981
37982 if (this.viewFunction !== undefined) {
37983 this.body.emitter.off('initRedraw', this.viewFunction);
37984 this.viewFunction = undefined;
37985
37986 if (emit === true) {
37987 this.body.emitter.emit('_stopRendering');
37988 }
37989 }
37990 }
37991 /**
37992 * The viewFunction inserts this step into each render loop. It calls the physics tick and handles the cleanup at stabilized.
37993 *
37994 */
37995
37996 }, {
37997 key: "simulationStep",
37998 value: function simulationStep() {
37999 // check if the physics have settled
38000 var startTime = Date.now();
38001 this.physicsTick();
38002 var physicsTime = Date.now() - startTime; // run double speed if it is a little graph
38003
38004 if ((physicsTime < 0.4 * this.simulationInterval || this.runDoubleSpeed === true) && this.stabilized === false) {
38005 this.physicsTick(); // this makes sure there is no jitter. The decision is taken once to run it at double speed.
38006
38007 this.runDoubleSpeed = true;
38008 }
38009
38010 if (this.stabilized === true) {
38011 this.stopSimulation();
38012 }
38013 }
38014 /**
38015 * trigger the stabilized event.
38016 *
38017 * @param {number} [amountOfIterations=this.stabilizationIterations]
38018 * @private
38019 */
38020
38021 }, {
38022 key: "_emitStabilized",
38023 value: function _emitStabilized() {
38024 var _this2 = this;
38025
38026 var amountOfIterations = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.stabilizationIterations;
38027
38028 if (this.stabilizationIterations > 1 || this.startedStabilization === true) {
38029 setTimeout(function () {
38030 _this2.body.emitter.emit('stabilized', {
38031 iterations: amountOfIterations
38032 });
38033
38034 _this2.startedStabilization = false;
38035 _this2.stabilizationIterations = 0;
38036 }, 0);
38037 }
38038 }
38039 /**
38040 * Calculate the forces for one physics iteration and move the nodes.
38041 * @private
38042 */
38043
38044 }, {
38045 key: "physicsStep",
38046 value: function physicsStep() {
38047 this.gravitySolver.solve();
38048 this.nodesSolver.solve();
38049 this.edgesSolver.solve();
38050 this.moveNodes();
38051 }
38052 /**
38053 * Make dynamic adjustments to the timestep, based on current state.
38054 *
38055 * Helper function for physicsTick().
38056 * @private
38057 */
38058
38059 }, {
38060 key: "adjustTimeStep",
38061 value: function adjustTimeStep() {
38062 var factor = 1.2; // Factor for increasing the timestep on success.
38063 // we compare the two steps. if it is acceptable we double the step.
38064
38065 if (this._evaluateStepQuality() === true) {
38066 this.timestep = factor * this.timestep;
38067 } else {
38068 // if not, we decrease the step to a minimum of the options timestep.
38069 // if the decreased timestep is smaller than the options step, we do not reset the counter
38070 // we assume that the options timestep is stable enough.
38071 if (this.timestep / factor < this.options.timestep) {
38072 this.timestep = this.options.timestep;
38073 } else {
38074 // if the timestep was larger than 2 times the option one we check the adaptivity again to ensure
38075 // that large instabilities do not form.
38076 this.adaptiveCounter = -1; // check again next iteration
38077
38078 this.timestep = Math.max(this.options.timestep, this.timestep / factor);
38079 }
38080 }
38081 }
38082 /**
38083 * A single simulation step (or 'tick') in the physics simulation
38084 *
38085 * @private
38086 */
38087
38088 }, {
38089 key: "physicsTick",
38090 value: function physicsTick() {
38091 this._startStabilizing(); // this ensures that there is no start event when the network is already stable.
38092
38093
38094 if (this.stabilized === true) return; // adaptivity means the timestep adapts to the situation, only applicable for stabilization
38095
38096 if (this.adaptiveTimestep === true && this.adaptiveTimestepEnabled === true) {
38097 // timestep remains stable for "interval" iterations.
38098 var doAdaptive = this.adaptiveCounter % this.adaptiveInterval === 0;
38099
38100 if (doAdaptive) {
38101 // first the big step and revert.
38102 this.timestep = 2 * this.timestep;
38103 this.physicsStep();
38104 this.revert(); // saves the reference state
38105 // now the normal step. Since this is the last step, it is the more stable one and we will take this.
38106
38107 this.timestep = 0.5 * this.timestep; // since it's half the step, we do it twice.
38108
38109 this.physicsStep();
38110 this.physicsStep();
38111 this.adjustTimeStep();
38112 } else {
38113 this.physicsStep(); // normal step, keeping timestep constant
38114 }
38115
38116 this.adaptiveCounter += 1;
38117 } else {
38118 // case for the static timestep, we reset it to the one in options and take a normal step.
38119 this.timestep = this.options.timestep;
38120 this.physicsStep();
38121 }
38122
38123 if (this.stabilized === true) this.revert();
38124 this.stabilizationIterations++;
38125 }
38126 /**
38127 * 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.
38128 *
38129 * @private
38130 */
38131
38132 }, {
38133 key: "updatePhysicsData",
38134 value: function updatePhysicsData() {
38135 this.physicsBody.forces = {};
38136 this.physicsBody.physicsNodeIndices = [];
38137 this.physicsBody.physicsEdgeIndices = [];
38138 var nodes = this.body.nodes;
38139 var edges = this.body.edges; // get node indices for physics
38140
38141 for (var nodeId in nodes) {
38142 if (nodes.hasOwnProperty(nodeId)) {
38143 if (nodes[nodeId].options.physics === true) {
38144 this.physicsBody.physicsNodeIndices.push(nodes[nodeId].id);
38145 }
38146 }
38147 } // get edge indices for physics
38148
38149
38150 for (var edgeId in edges) {
38151 if (edges.hasOwnProperty(edgeId)) {
38152 if (edges[edgeId].options.physics === true) {
38153 this.physicsBody.physicsEdgeIndices.push(edges[edgeId].id);
38154 }
38155 }
38156 } // get the velocity and the forces vector
38157
38158
38159 for (var i = 0; i < this.physicsBody.physicsNodeIndices.length; i++) {
38160 var _nodeId = this.physicsBody.physicsNodeIndices[i];
38161 this.physicsBody.forces[_nodeId] = {
38162 x: 0,
38163 y: 0
38164 }; // forces can be reset because they are recalculated. Velocities have to persist.
38165
38166 if (this.physicsBody.velocities[_nodeId] === undefined) {
38167 this.physicsBody.velocities[_nodeId] = {
38168 x: 0,
38169 y: 0
38170 };
38171 }
38172 } // clean deleted nodes from the velocity vector
38173
38174
38175 for (var _nodeId2 in this.physicsBody.velocities) {
38176 if (nodes[_nodeId2] === undefined) {
38177 delete this.physicsBody.velocities[_nodeId2];
38178 }
38179 }
38180 }
38181 /**
38182 * Revert the simulation one step. This is done so after stabilization, every new start of the simulation will also say stabilized.
38183 */
38184
38185 }, {
38186 key: "revert",
38187 value: function revert() {
38188 var nodeIds = Object.keys(this.previousStates);
38189 var nodes = this.body.nodes;
38190 var velocities = this.physicsBody.velocities;
38191 this.referenceState = {};
38192
38193 for (var i = 0; i < nodeIds.length; i++) {
38194 var nodeId = nodeIds[i];
38195
38196 if (nodes[nodeId] !== undefined) {
38197 if (nodes[nodeId].options.physics === true) {
38198 this.referenceState[nodeId] = {
38199 positions: {
38200 x: nodes[nodeId].x,
38201 y: nodes[nodeId].y
38202 }
38203 };
38204 velocities[nodeId].x = this.previousStates[nodeId].vx;
38205 velocities[nodeId].y = this.previousStates[nodeId].vy;
38206 nodes[nodeId].x = this.previousStates[nodeId].x;
38207 nodes[nodeId].y = this.previousStates[nodeId].y;
38208 }
38209 } else {
38210 delete this.previousStates[nodeId];
38211 }
38212 }
38213 }
38214 /**
38215 * This compares the reference state to the current state
38216 *
38217 * @returns {boolean}
38218 * @private
38219 */
38220
38221 }, {
38222 key: "_evaluateStepQuality",
38223 value: function _evaluateStepQuality() {
38224 var dx, dy, dpos;
38225 var nodes = this.body.nodes;
38226 var reference = this.referenceState;
38227 var posThreshold = 0.3;
38228
38229 for (var nodeId in this.referenceState) {
38230 if (this.referenceState.hasOwnProperty(nodeId) && nodes[nodeId] !== undefined) {
38231 dx = nodes[nodeId].x - reference[nodeId].positions.x;
38232 dy = nodes[nodeId].y - reference[nodeId].positions.y;
38233 dpos = Math.sqrt(Math.pow(dx, 2) + Math.pow(dy, 2));
38234
38235 if (dpos > posThreshold) {
38236 return false;
38237 }
38238 }
38239 }
38240
38241 return true;
38242 }
38243 /**
38244 * move the nodes one timestep and check if they are stabilized
38245 */
38246
38247 }, {
38248 key: "moveNodes",
38249 value: function moveNodes() {
38250 var nodeIndices = this.physicsBody.physicsNodeIndices;
38251 var maxNodeVelocity = 0;
38252 var averageNodeVelocity = 0; // the velocity threshold (energy in the system) for the adaptivity toggle
38253
38254 var velocityAdaptiveThreshold = 5;
38255
38256 for (var i = 0; i < nodeIndices.length; i++) {
38257 var nodeId = nodeIndices[i];
38258
38259 var nodeVelocity = this._performStep(nodeId); // stabilized is true if stabilized is true and velocity is smaller than vmin --> all nodes must be stabilized
38260
38261
38262 maxNodeVelocity = Math.max(maxNodeVelocity, nodeVelocity);
38263 averageNodeVelocity += nodeVelocity;
38264 } // evaluating the stabilized and adaptiveTimestepEnabled conditions
38265
38266
38267 this.adaptiveTimestepEnabled = averageNodeVelocity / nodeIndices.length < velocityAdaptiveThreshold;
38268 this.stabilized = maxNodeVelocity < this.options.minVelocity;
38269 }
38270 /**
38271 * Calculate new velocity for a coordinate direction
38272 *
38273 * @param {number} v velocity for current coordinate
38274 * @param {number} f regular force for current coordinate
38275 * @param {number} m mass of current node
38276 * @returns {number} new velocity for current coordinate
38277 * @private
38278 */
38279
38280 }, {
38281 key: "calculateComponentVelocity",
38282 value: function calculateComponentVelocity(v, f, m) {
38283 var df = this.modelOptions.damping * v; // damping force
38284
38285 var a = (f - df) / m; // acceleration
38286
38287 v += a * this.timestep; // Put a limit on the velocities if it is really high
38288
38289 var maxV = this.options.maxVelocity || 1e9;
38290
38291 if (Math.abs(v) > maxV) {
38292 v = v > 0 ? maxV : -maxV;
38293 }
38294
38295 return v;
38296 }
38297 /**
38298 * Perform the actual step
38299 *
38300 * @param {Node.id} nodeId
38301 * @returns {number} the new velocity of given node
38302 * @private
38303 */
38304
38305 }, {
38306 key: "_performStep",
38307 value: function _performStep(nodeId) {
38308 var node = this.body.nodes[nodeId];
38309 var force = this.physicsBody.forces[nodeId];
38310 var velocity = this.physicsBody.velocities[nodeId]; // store the state so we can revert
38311
38312 this.previousStates[nodeId] = {
38313 x: node.x,
38314 y: node.y,
38315 vx: velocity.x,
38316 vy: velocity.y
38317 };
38318
38319 if (node.options.fixed.x === false) {
38320 velocity.x = this.calculateComponentVelocity(velocity.x, force.x, node.options.mass);
38321 node.x += velocity.x * this.timestep;
38322 } else {
38323 force.x = 0;
38324 velocity.x = 0;
38325 }
38326
38327 if (node.options.fixed.y === false) {
38328 velocity.y = this.calculateComponentVelocity(velocity.y, force.y, node.options.mass);
38329 node.y += velocity.y * this.timestep;
38330 } else {
38331 force.y = 0;
38332 velocity.y = 0;
38333 }
38334
38335 var totalVelocity = Math.sqrt(Math.pow(velocity.x, 2) + Math.pow(velocity.y, 2));
38336 return totalVelocity;
38337 }
38338 /**
38339 * When initializing and stabilizing, we can freeze nodes with a predefined position.
38340 * This greatly speeds up stabilization because only the supportnodes for the smoothCurves have to settle.
38341 *
38342 * @private
38343 */
38344
38345 }, {
38346 key: "_freezeNodes",
38347 value: function _freezeNodes() {
38348 var nodes = this.body.nodes;
38349
38350 for (var id in nodes) {
38351 if (nodes.hasOwnProperty(id)) {
38352 if (nodes[id].x && nodes[id].y) {
38353 var fixed = nodes[id].options.fixed;
38354 this.freezeCache[id] = {
38355 x: fixed.x,
38356 y: fixed.y
38357 };
38358 fixed.x = true;
38359 fixed.y = true;
38360 }
38361 }
38362 }
38363 }
38364 /**
38365 * Unfreezes the nodes that have been frozen by _freezeDefinedNodes.
38366 *
38367 * @private
38368 */
38369
38370 }, {
38371 key: "_restoreFrozenNodes",
38372 value: function _restoreFrozenNodes() {
38373 var nodes = this.body.nodes;
38374
38375 for (var id in nodes) {
38376 if (nodes.hasOwnProperty(id)) {
38377 if (this.freezeCache[id] !== undefined) {
38378 nodes[id].options.fixed.x = this.freezeCache[id].x;
38379 nodes[id].options.fixed.y = this.freezeCache[id].y;
38380 }
38381 }
38382 }
38383
38384 this.freezeCache = {};
38385 }
38386 /**
38387 * Find a stable position for all nodes
38388 *
38389 * @param {number} [iterations=this.options.stabilization.iterations]
38390 */
38391
38392 }, {
38393 key: "stabilize",
38394 value: function stabilize() {
38395 var _this3 = this;
38396
38397 var iterations = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.options.stabilization.iterations;
38398
38399 if (typeof iterations !== 'number') {
38400 iterations = this.options.stabilization.iterations;
38401 console.log('The stabilize method needs a numeric amount of iterations. Switching to default: ', iterations);
38402 }
38403
38404 if (this.physicsBody.physicsNodeIndices.length === 0) {
38405 this.ready = true;
38406 return;
38407 } // enable adaptive timesteps
38408
38409
38410 this.adaptiveTimestep = this.options.adaptiveTimestep; // this sets the width of all nodes initially which could be required for the avoidOverlap
38411
38412 this.body.emitter.emit("_resizeNodes");
38413 this.stopSimulation(); // stop the render loop
38414
38415 this.stabilized = false; // block redraw requests
38416
38417 this.body.emitter.emit('_blockRedraw');
38418 this.targetIterations = iterations; // start the stabilization
38419
38420 if (this.options.stabilization.onlyDynamicEdges === true) {
38421 this._freezeNodes();
38422 }
38423
38424 this.stabilizationIterations = 0;
38425 setTimeout(function () {
38426 return _this3._stabilizationBatch();
38427 }, 0);
38428 }
38429 /**
38430 * If not already stabilizing, start it and emit a start event.
38431 *
38432 * @returns {boolean} true if stabilization started with this call
38433 * @private
38434 */
38435
38436 }, {
38437 key: "_startStabilizing",
38438 value: function _startStabilizing() {
38439 if (this.startedStabilization === true) return false;
38440 this.body.emitter.emit('startStabilizing');
38441 this.startedStabilization = true;
38442 return true;
38443 }
38444 /**
38445 * One batch of stabilization
38446 * @private
38447 */
38448
38449 }, {
38450 key: "_stabilizationBatch",
38451 value: function _stabilizationBatch() {
38452 var _this4 = this;
38453
38454 var running = function running() {
38455 return _this4.stabilized === false && _this4.stabilizationIterations < _this4.targetIterations;
38456 };
38457
38458 var sendProgress = function sendProgress() {
38459 _this4.body.emitter.emit('stabilizationProgress', {
38460 iterations: _this4.stabilizationIterations,
38461 total: _this4.targetIterations
38462 });
38463 };
38464
38465 if (this._startStabilizing()) {
38466 sendProgress(); // Ensure that there is at least one start event.
38467 }
38468
38469 var count = 0;
38470
38471 while (running() && count < this.options.stabilization.updateInterval) {
38472 this.physicsTick();
38473 count++;
38474 }
38475
38476 sendProgress();
38477
38478 if (running()) {
38479 setTimeout(this._stabilizationBatch.bind(this), 0);
38480 } else {
38481 this._finalizeStabilization();
38482 }
38483 }
38484 /**
38485 * Wrap up the stabilization, fit and emit the events.
38486 * @private
38487 */
38488
38489 }, {
38490 key: "_finalizeStabilization",
38491 value: function _finalizeStabilization() {
38492 this.body.emitter.emit('_allowRedraw');
38493
38494 if (this.options.stabilization.fit === true) {
38495 this.body.emitter.emit('fit');
38496 }
38497
38498 if (this.options.stabilization.onlyDynamicEdges === true) {
38499 this._restoreFrozenNodes();
38500 }
38501
38502 this.body.emitter.emit('stabilizationIterationsDone');
38503 this.body.emitter.emit('_requestRedraw');
38504
38505 if (this.stabilized === true) {
38506 this._emitStabilized();
38507 } else {
38508 this.startSimulation();
38509 }
38510
38511 this.ready = true;
38512 } //--------------------------- DEBUGGING BELOW ---------------------------//
38513
38514 /**
38515 * Debug function that display arrows for the forces currently active in the network.
38516 *
38517 * Use this when debugging only.
38518 *
38519 * @param {CanvasRenderingContext2D} ctx
38520 * @private
38521 */
38522
38523 }, {
38524 key: "_drawForces",
38525 value: function _drawForces(ctx) {
38526 for (var i = 0; i < this.physicsBody.physicsNodeIndices.length; i++) {
38527 var index = this.physicsBody.physicsNodeIndices[i];
38528 var node = this.body.nodes[index];
38529 var force = this.physicsBody.forces[index];
38530 var factor = 20;
38531 var colorFactor = 0.03;
38532 var forceSize = Math.sqrt(Math.pow(force.x, 2) + Math.pow(force.x, 2));
38533 var size = Math.min(Math.max(5, forceSize), 15);
38534 var arrowSize = 3 * size;
38535 var color = HSVToHex((180 - Math.min(1, Math.max(0, colorFactor * forceSize)) * 180) / 360, 1, 1);
38536 var point = {
38537 x: node.x + factor * force.x,
38538 y: node.y + factor * force.y
38539 };
38540 ctx.lineWidth = size;
38541 ctx.strokeStyle = color;
38542 ctx.beginPath();
38543 ctx.moveTo(node.x, node.y);
38544 ctx.lineTo(point.x, point.y);
38545 ctx.stroke();
38546 var angle = Math.atan2(force.y, force.x);
38547 ctx.fillStyle = color;
38548 EndPoints.draw(ctx, {
38549 type: 'arrow',
38550 point: point,
38551 angle: angle,
38552 length: arrowSize
38553 });
38554 ctx.fill();
38555 }
38556 }
38557 }]);
38558
38559 return PhysicsEngine;
38560 }();
38561
38562 var nativeReverse = [].reverse;
38563 var test$2 = [1, 2]; // `Array.prototype.reverse` method
38564 // https://tc39.github.io/ecma262/#sec-array.prototype.reverse
38565 // fix for Safari 12.0 bug
38566 // https://bugs.webkit.org/show_bug.cgi?id=188794
38567
38568 _export({
38569 target: 'Array',
38570 proto: true,
38571 forced: String(test$2) === String(test$2.reverse())
38572 }, {
38573 reverse: function reverse() {
38574 if (isArray(this)) this.length = this.length;
38575 return nativeReverse.call(this);
38576 }
38577 });
38578
38579 /**
38580 * Utility Class
38581 */
38582
38583 var NetworkUtil =
38584 /*#__PURE__*/
38585 function () {
38586 /**
38587 * @ignore
38588 */
38589 function NetworkUtil() {
38590 _classCallCheck(this, NetworkUtil);
38591 }
38592 /**
38593 * Find the center position of the network considering the bounding boxes
38594 *
38595 * @param {Array.<Node>} allNodes
38596 * @param {Array.<Node>} [specificNodes=[]]
38597 * @returns {{minX: number, maxX: number, minY: number, maxY: number}}
38598 * @static
38599 */
38600
38601
38602 _createClass(NetworkUtil, null, [{
38603 key: "getRange",
38604 value: function getRange(allNodes) {
38605 var specificNodes = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
38606 var minY = 1e9,
38607 maxY = -1e9,
38608 minX = 1e9,
38609 maxX = -1e9,
38610 node;
38611
38612 if (specificNodes.length > 0) {
38613 for (var i = 0; i < specificNodes.length; i++) {
38614 node = allNodes[specificNodes[i]];
38615
38616 if (minX > node.shape.boundingBox.left) {
38617 minX = node.shape.boundingBox.left;
38618 }
38619
38620 if (maxX < node.shape.boundingBox.right) {
38621 maxX = node.shape.boundingBox.right;
38622 }
38623
38624 if (minY > node.shape.boundingBox.top) {
38625 minY = node.shape.boundingBox.top;
38626 } // top is negative, bottom is positive
38627
38628
38629 if (maxY < node.shape.boundingBox.bottom) {
38630 maxY = node.shape.boundingBox.bottom;
38631 } // top is negative, bottom is positive
38632
38633 }
38634 }
38635
38636 if (minX === 1e9 && maxX === -1e9 && minY === 1e9 && maxY === -1e9) {
38637 minY = 0, maxY = 0, minX = 0, maxX = 0;
38638 }
38639
38640 return {
38641 minX: minX,
38642 maxX: maxX,
38643 minY: minY,
38644 maxY: maxY
38645 };
38646 }
38647 /**
38648 * Find the center position of the network
38649 *
38650 * @param {Array.<Node>} allNodes
38651 * @param {Array.<Node>} [specificNodes=[]]
38652 * @returns {{minX: number, maxX: number, minY: number, maxY: number}}
38653 * @static
38654 */
38655
38656 }, {
38657 key: "getRangeCore",
38658 value: function getRangeCore(allNodes) {
38659 var specificNodes = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
38660 var minY = 1e9,
38661 maxY = -1e9,
38662 minX = 1e9,
38663 maxX = -1e9,
38664 node;
38665
38666 if (specificNodes.length > 0) {
38667 for (var i = 0; i < specificNodes.length; i++) {
38668 node = allNodes[specificNodes[i]];
38669
38670 if (minX > node.x) {
38671 minX = node.x;
38672 }
38673
38674 if (maxX < node.x) {
38675 maxX = node.x;
38676 }
38677
38678 if (minY > node.y) {
38679 minY = node.y;
38680 } // top is negative, bottom is positive
38681
38682
38683 if (maxY < node.y) {
38684 maxY = node.y;
38685 } // top is negative, bottom is positive
38686
38687 }
38688 }
38689
38690 if (minX === 1e9 && maxX === -1e9 && minY === 1e9 && maxY === -1e9) {
38691 minY = 0, maxY = 0, minX = 0, maxX = 0;
38692 }
38693
38694 return {
38695 minX: minX,
38696 maxX: maxX,
38697 minY: minY,
38698 maxY: maxY
38699 };
38700 }
38701 /**
38702 * @param {object} range = {minX: minX, maxX: maxX, minY: minY, maxY: maxY};
38703 * @returns {{x: number, y: number}}
38704 * @static
38705 */
38706
38707 }, {
38708 key: "findCenter",
38709 value: function findCenter(range) {
38710 return {
38711 x: 0.5 * (range.maxX + range.minX),
38712 y: 0.5 * (range.maxY + range.minY)
38713 };
38714 }
38715 /**
38716 * 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.
38717 * @param {vis.Item} item
38718 * @param {'node'|undefined} type
38719 * @returns {{}}
38720 * @static
38721 */
38722
38723 }, {
38724 key: "cloneOptions",
38725 value: function cloneOptions(item, type) {
38726 var clonedOptions = {};
38727
38728 if (type === undefined || type === 'node') {
38729 deepExtend(clonedOptions, item.options, true);
38730 clonedOptions.x = item.x;
38731 clonedOptions.y = item.y;
38732 clonedOptions.amountOfConnections = item.edges.length;
38733 } else {
38734 deepExtend(clonedOptions, item.options, true);
38735 }
38736
38737 return clonedOptions;
38738 }
38739 }]);
38740
38741 return NetworkUtil;
38742 }();
38743
38744 /**
38745 * A Cluster is a special Node that allows a group of Nodes positioned closely together
38746 * to be represented by a single Cluster Node.
38747 *
38748 * @extends Node
38749 */
38750
38751 var Cluster =
38752 /*#__PURE__*/
38753 function (_Node) {
38754 _inherits(Cluster, _Node);
38755
38756 /**
38757 * @param {Object} options
38758 * @param {Object} body
38759 * @param {Array.<HTMLImageElement>}imagelist
38760 * @param {Array} grouplist
38761 * @param {Object} globalOptions
38762 * @param {Object} defaultOptions Global default options for nodes
38763 */
38764 function Cluster(options, body, imagelist, grouplist, globalOptions, defaultOptions) {
38765 var _this;
38766
38767 _classCallCheck(this, Cluster);
38768
38769 _this = _possibleConstructorReturn(this, _getPrototypeOf(Cluster).call(this, options, body, imagelist, grouplist, globalOptions, defaultOptions));
38770 _this.isCluster = true;
38771 _this.containedNodes = {};
38772 _this.containedEdges = {};
38773 return _this;
38774 }
38775 /**
38776 * Transfer child cluster data to current and disconnect the child cluster.
38777 *
38778 * Please consult the header comment in 'Clustering.js' for the fields set here.
38779 *
38780 * @param {string|number} childClusterId id of child cluster to open
38781 */
38782
38783
38784 _createClass(Cluster, [{
38785 key: "_openChildCluster",
38786 value: function _openChildCluster(childClusterId) {
38787 var _this2 = this;
38788
38789 var childCluster = this.body.nodes[childClusterId];
38790
38791 if (this.containedNodes[childClusterId] === undefined) {
38792 throw new Error('node with id: ' + childClusterId + ' not in current cluster');
38793 }
38794
38795 if (!childCluster.isCluster) {
38796 throw new Error('node with id: ' + childClusterId + ' is not a cluster');
38797 } // Disconnect child cluster from current cluster
38798
38799
38800 delete this.containedNodes[childClusterId];
38801 forEach(childCluster.edges, function (edge) {
38802 delete _this2.containedEdges[edge.id];
38803 }); // Transfer nodes and edges
38804
38805 forEach(childCluster.containedNodes, function (node, nodeId) {
38806 _this2.containedNodes[nodeId] = node;
38807 });
38808 childCluster.containedNodes = {};
38809 forEach(childCluster.containedEdges, function (edge, edgeId) {
38810 _this2.containedEdges[edgeId] = edge;
38811 });
38812 childCluster.containedEdges = {}; // Transfer edges within cluster edges which are clustered
38813
38814 forEach(childCluster.edges, function (clusterEdge) {
38815 forEach(_this2.edges, function (parentClusterEdge) {
38816 // Assumption: a clustered edge can only be present in a single clustering edge
38817 // Not tested here
38818 var index = parentClusterEdge.clusteringEdgeReplacingIds.indexOf(clusterEdge.id);
38819 if (index === -1) return;
38820 forEach(clusterEdge.clusteringEdgeReplacingIds, function (srcId) {
38821 parentClusterEdge.clusteringEdgeReplacingIds.push(srcId); // Maintain correct bookkeeping for transferred edge
38822
38823 _this2.body.edges[srcId].edgeReplacedById = parentClusterEdge.id;
38824 }); // Remove cluster edge from parent cluster edge
38825
38826 parentClusterEdge.clusteringEdgeReplacingIds.splice(index, 1);
38827 });
38828 });
38829 childCluster.edges = [];
38830 }
38831 }]);
38832
38833 return Cluster;
38834 }(Node);
38835
38836 /**
38837 * The clustering engine
38838 */
38839
38840 var ClusterEngine =
38841 /*#__PURE__*/
38842 function () {
38843 /**
38844 * @param {Object} body
38845 */
38846 function ClusterEngine(body) {
38847 var _this = this;
38848
38849 _classCallCheck(this, ClusterEngine);
38850
38851 this.body = body;
38852 this.clusteredNodes = {}; // key: node id, value: { clusterId: <id of cluster>, node: <node instance>}
38853
38854 this.clusteredEdges = {}; // key: edge id, value: restore information for given edge
38855
38856 this.options = {};
38857 this.defaultOptions = {};
38858 extend(this.options, this.defaultOptions);
38859 this.body.emitter.on('_resetData', function () {
38860 _this.clusteredNodes = {};
38861 _this.clusteredEdges = {};
38862 });
38863 }
38864 /**
38865 *
38866 * @param {number} hubsize
38867 * @param {Object} options
38868 */
38869
38870
38871 _createClass(ClusterEngine, [{
38872 key: "clusterByHubsize",
38873 value: function clusterByHubsize(hubsize, options) {
38874 if (hubsize === undefined) {
38875 hubsize = this._getHubSize();
38876 } else if (_typeof$1(hubsize) === "object") {
38877 options = this._checkOptions(hubsize);
38878 hubsize = this._getHubSize();
38879 }
38880
38881 var nodesToCluster = [];
38882
38883 for (var i = 0; i < this.body.nodeIndices.length; i++) {
38884 var node = this.body.nodes[this.body.nodeIndices[i]];
38885
38886 if (node.edges.length >= hubsize) {
38887 nodesToCluster.push(node.id);
38888 }
38889 }
38890
38891 for (var _i = 0; _i < nodesToCluster.length; _i++) {
38892 this.clusterByConnection(nodesToCluster[_i], options, true);
38893 }
38894
38895 this.body.emitter.emit('_dataChanged');
38896 }
38897 /**
38898 * loop over all nodes, check if they adhere to the condition and cluster if needed.
38899 * @param {Object} options
38900 * @param {boolean} [refreshData=true]
38901 */
38902
38903 }, {
38904 key: "cluster",
38905 value: function cluster() {
38906 var _this2 = this;
38907
38908 var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
38909 var refreshData = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
38910
38911 if (options.joinCondition === undefined) {
38912 throw new Error("Cannot call clusterByNodeData without a joinCondition function in the options.");
38913 } // check if the options object is fine, append if needed
38914
38915
38916 options = this._checkOptions(options);
38917 var childNodesObj = {};
38918 var childEdgesObj = {}; // collect the nodes that will be in the cluster
38919
38920 forEach(this.body.nodes, function (node, nodeId) {
38921 if (node.options && options.joinCondition(node.options) === true) {
38922 childNodesObj[nodeId] = node; // collect the edges that will be in the cluster
38923
38924 forEach(node.edges, function (edge) {
38925 if (_this2.clusteredEdges[edge.id] === undefined) {
38926 childEdgesObj[edge.id] = edge;
38927 }
38928 });
38929 }
38930 });
38931
38932 this._cluster(childNodesObj, childEdgesObj, options, refreshData);
38933 }
38934 /**
38935 * Cluster all nodes in the network that have only X edges
38936 * @param {number} edgeCount
38937 * @param {Object} options
38938 * @param {boolean} [refreshData=true]
38939 */
38940
38941 }, {
38942 key: "clusterByEdgeCount",
38943 value: function clusterByEdgeCount(edgeCount, options) {
38944 var _this3 = this;
38945
38946 var refreshData = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
38947 options = this._checkOptions(options);
38948 var clusters = [];
38949 var usedNodes = {};
38950 var edge, edges, relevantEdgeCount; // collect the nodes that will be in the cluster
38951
38952 var _loop = function _loop(i) {
38953 var childNodesObj = {};
38954 var childEdgesObj = {};
38955 var nodeId = _this3.body.nodeIndices[i];
38956 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.
38957
38958 if (usedNodes[nodeId] === undefined) {
38959 relevantEdgeCount = 0;
38960 edges = [];
38961
38962 for (var j = 0; j < node.edges.length; j++) {
38963 edge = node.edges[j];
38964
38965 if (_this3.clusteredEdges[edge.id] === undefined) {
38966 if (edge.toId !== edge.fromId) {
38967 relevantEdgeCount++;
38968 }
38969
38970 edges.push(edge);
38971 }
38972 } // this node qualifies, we collect its neighbours to start the clustering process.
38973
38974
38975 if (relevantEdgeCount === edgeCount) {
38976 checkJoinCondition = function checkJoinCondition(node) {
38977 if (options.joinCondition === undefined || options.joinCondition === null) {
38978 return true;
38979 }
38980
38981 var clonedOptions = NetworkUtil.cloneOptions(node);
38982 return options.joinCondition(clonedOptions);
38983 };
38984
38985 var gatheringSuccessful = true;
38986
38987 for (var _j = 0; _j < edges.length; _j++) {
38988 edge = edges[_j];
38989
38990 var childNodeId = _this3._getConnectedId(edge, nodeId); // add the nodes to the list by the join condition.
38991
38992
38993 if (checkJoinCondition(node)) {
38994 childEdgesObj[edge.id] = edge;
38995 childNodesObj[nodeId] = node;
38996 childNodesObj[childNodeId] = _this3.body.nodes[childNodeId];
38997 usedNodes[nodeId] = true;
38998 } else {
38999 // this node does not qualify after all.
39000 gatheringSuccessful = false;
39001 break;
39002 }
39003 } // add to the cluster queue
39004
39005
39006 if (Object.keys(childNodesObj).length > 0 && Object.keys(childEdgesObj).length > 0 && gatheringSuccessful === true) {
39007 /**
39008 * Search for cluster data that contains any of the node id's
39009 * @returns {Boolean} true if no joinCondition, otherwise return value of joinCondition
39010 */
39011 findClusterData = function findClusterData() {
39012 for (var n = 0; n < clusters.length; ++n) {
39013 // Search for a cluster containing any of the node id's
39014 for (var m in childNodesObj) {
39015 if (clusters[n].nodes[m] !== undefined) {
39016 return clusters[n];
39017 }
39018 }
39019 }
39020
39021 return undefined;
39022 }; // If any of the found nodes is part of a cluster found in this method,
39023 // add the current values to that cluster
39024
39025
39026 foundCluster = findClusterData();
39027
39028 if (foundCluster !== undefined) {
39029 // Add nodes to found cluster if not present
39030 for (var m in childNodesObj) {
39031 if (foundCluster.nodes[m] === undefined) {
39032 foundCluster.nodes[m] = childNodesObj[m];
39033 }
39034 } // Add edges to found cluster, if not present
39035
39036
39037 for (var _m in childEdgesObj) {
39038 if (foundCluster.edges[_m] === undefined) {
39039 foundCluster.edges[_m] = childEdgesObj[_m];
39040 }
39041 }
39042 } else {
39043 // Create a new cluster group
39044 clusters.push({
39045 nodes: childNodesObj,
39046 edges: childEdgesObj
39047 });
39048 }
39049 }
39050 }
39051 }
39052 };
39053
39054 for (var i = 0; i < this.body.nodeIndices.length; i++) {
39055 var checkJoinCondition;
39056 var findClusterData;
39057 var foundCluster;
39058
39059 _loop(i);
39060 }
39061
39062 for (var _i2 = 0; _i2 < clusters.length; _i2++) {
39063 this._cluster(clusters[_i2].nodes, clusters[_i2].edges, options, false);
39064 }
39065
39066 if (refreshData === true) {
39067 this.body.emitter.emit('_dataChanged');
39068 }
39069 }
39070 /**
39071 * Cluster all nodes in the network that have only 1 edge
39072 * @param {Object} options
39073 * @param {boolean} [refreshData=true]
39074 */
39075
39076 }, {
39077 key: "clusterOutliers",
39078 value: function clusterOutliers(options) {
39079 var refreshData = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
39080 this.clusterByEdgeCount(1, options, refreshData);
39081 }
39082 /**
39083 * Cluster all nodes in the network that have only 2 edge
39084 * @param {Object} options
39085 * @param {boolean} [refreshData=true]
39086 */
39087
39088 }, {
39089 key: "clusterBridges",
39090 value: function clusterBridges(options) {
39091 var refreshData = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
39092 this.clusterByEdgeCount(2, options, refreshData);
39093 }
39094 /**
39095 * suck all connected nodes of a node into the node.
39096 * @param {Node.id} nodeId
39097 * @param {Object} options
39098 * @param {boolean} [refreshData=true]
39099 */
39100
39101 }, {
39102 key: "clusterByConnection",
39103 value: function clusterByConnection(nodeId, options) {
39104 var refreshData = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
39105
39106 // kill conditions
39107 if (nodeId === undefined) {
39108 throw new Error("No nodeId supplied to clusterByConnection!");
39109 }
39110
39111 if (this.body.nodes[nodeId] === undefined) {
39112 throw new Error("The nodeId given to clusterByConnection does not exist!");
39113 }
39114
39115 var node = this.body.nodes[nodeId];
39116 options = this._checkOptions(options, node);
39117
39118 if (options.clusterNodeProperties.x === undefined) {
39119 options.clusterNodeProperties.x = node.x;
39120 }
39121
39122 if (options.clusterNodeProperties.y === undefined) {
39123 options.clusterNodeProperties.y = node.y;
39124 }
39125
39126 if (options.clusterNodeProperties.fixed === undefined) {
39127 options.clusterNodeProperties.fixed = {};
39128 options.clusterNodeProperties.fixed.x = node.options.fixed.x;
39129 options.clusterNodeProperties.fixed.y = node.options.fixed.y;
39130 }
39131
39132 var childNodesObj = {};
39133 var childEdgesObj = {};
39134 var parentNodeId = node.id;
39135 var parentClonedOptions = NetworkUtil.cloneOptions(node);
39136 childNodesObj[parentNodeId] = node; // collect the nodes that will be in the cluster
39137
39138 for (var i = 0; i < node.edges.length; i++) {
39139 var edge = node.edges[i];
39140
39141 if (this.clusteredEdges[edge.id] === undefined) {
39142 var childNodeId = this._getConnectedId(edge, parentNodeId); // if the child node is not in a cluster
39143
39144
39145 if (this.clusteredNodes[childNodeId] === undefined) {
39146 if (childNodeId !== parentNodeId) {
39147 if (options.joinCondition === undefined) {
39148 childEdgesObj[edge.id] = edge;
39149 childNodesObj[childNodeId] = this.body.nodes[childNodeId];
39150 } else {
39151 // clone the options and insert some additional parameters that could be interesting.
39152 var childClonedOptions = NetworkUtil.cloneOptions(this.body.nodes[childNodeId]);
39153
39154 if (options.joinCondition(parentClonedOptions, childClonedOptions) === true) {
39155 childEdgesObj[edge.id] = edge;
39156 childNodesObj[childNodeId] = this.body.nodes[childNodeId];
39157 }
39158 }
39159 } else {
39160 // swallow the edge if it is self-referencing.
39161 childEdgesObj[edge.id] = edge;
39162 }
39163 }
39164 }
39165 }
39166
39167 var childNodeIDs = Object.keys(childNodesObj).map(function (childNode) {
39168 return childNodesObj[childNode].id;
39169 });
39170
39171 for (childNode in childNodesObj) {
39172 if (!childNodesObj.hasOwnProperty(childNode)) continue;
39173 var childNode = childNodesObj[childNode];
39174
39175 for (var y = 0; y < childNode.edges.length; y++) {
39176 var childEdge = childNode.edges[y];
39177
39178 if (childNodeIDs.indexOf(this._getConnectedId(childEdge, childNode.id)) > -1) {
39179 childEdgesObj[childEdge.id] = childEdge;
39180 }
39181 }
39182 }
39183
39184 this._cluster(childNodesObj, childEdgesObj, options, refreshData);
39185 }
39186 /**
39187 * This function creates the edges that will be attached to the cluster
39188 * It looks for edges that are connected to the nodes from the "outside' of the cluster.
39189 *
39190 * @param {{Node.id: vis.Node}} childNodesObj
39191 * @param {{vis.Edge.id: vis.Edge}} childEdgesObj
39192 * @param {Object} clusterNodeProperties
39193 * @param {Object} clusterEdgeProperties
39194 * @private
39195 */
39196
39197 }, {
39198 key: "_createClusterEdges",
39199 value: function _createClusterEdges(childNodesObj, childEdgesObj, clusterNodeProperties, clusterEdgeProperties) {
39200 var edge, childNodeId, childNode, toId, fromId, otherNodeId; // loop over all child nodes and their edges to find edges going out of the cluster
39201 // these edges will be replaced by clusterEdges.
39202
39203 var childKeys = Object.keys(childNodesObj);
39204 var createEdges = [];
39205
39206 for (var i = 0; i < childKeys.length; i++) {
39207 childNodeId = childKeys[i];
39208 childNode = childNodesObj[childNodeId]; // construct new edges from the cluster to others
39209
39210 for (var j = 0; j < childNode.edges.length; j++) {
39211 edge = childNode.edges[j]; // we only handle edges that are visible to the system, not the disabled ones from the clustering process.
39212
39213 if (this.clusteredEdges[edge.id] === undefined) {
39214 // self-referencing edges will be added to the "hidden" list
39215 if (edge.toId == edge.fromId) {
39216 childEdgesObj[edge.id] = edge;
39217 } else {
39218 // set up the from and to.
39219 if (edge.toId == childNodeId) {
39220 // this is a double equals because ints and strings can be interchanged here.
39221 toId = clusterNodeProperties.id;
39222 fromId = edge.fromId;
39223 otherNodeId = fromId;
39224 } else {
39225 toId = edge.toId;
39226 fromId = clusterNodeProperties.id;
39227 otherNodeId = toId;
39228 }
39229 } // Only edges from the cluster outwards are being replaced.
39230
39231
39232 if (childNodesObj[otherNodeId] === undefined) {
39233 createEdges.push({
39234 edge: edge,
39235 fromId: fromId,
39236 toId: toId
39237 });
39238 }
39239 }
39240 }
39241 } //
39242 // Here we actually create the replacement edges.
39243 //
39244 // We could not do this in the loop above as the creation process
39245 // would add an edge to the edges array we are iterating over.
39246 //
39247 // NOTE: a clustered edge can have multiple base edges!
39248 //
39249
39250
39251 var newEdges = [];
39252 /**
39253 * Find a cluster edge which matches the given created edge.
39254 * @param {vis.Edge} createdEdge
39255 * @returns {vis.Edge}
39256 */
39257
39258 var getNewEdge = function getNewEdge(createdEdge) {
39259 for (var _j2 = 0; _j2 < newEdges.length; _j2++) {
39260 var newEdge = newEdges[_j2]; // We replace both to and from edges with a single cluster edge
39261
39262 var matchToDirection = createdEdge.fromId === newEdge.fromId && createdEdge.toId === newEdge.toId;
39263 var matchFromDirection = createdEdge.fromId === newEdge.toId && createdEdge.toId === newEdge.fromId;
39264
39265 if (matchToDirection || matchFromDirection) {
39266 return newEdge;
39267 }
39268 }
39269
39270 return null;
39271 };
39272
39273 for (var _j3 = 0; _j3 < createEdges.length; _j3++) {
39274 var createdEdge = createEdges[_j3];
39275 var _edge = createdEdge.edge;
39276 var newEdge = getNewEdge(createdEdge);
39277
39278 if (newEdge === null) {
39279 // Create a clustered edge for this connection
39280 newEdge = this._createClusteredEdge(createdEdge.fromId, createdEdge.toId, _edge, clusterEdgeProperties);
39281 newEdges.push(newEdge);
39282 } else {
39283 newEdge.clusteringEdgeReplacingIds.push(_edge.id);
39284 } // also reference the new edge in the old edge
39285
39286
39287 this.body.edges[_edge.id].edgeReplacedById = newEdge.id; // hide the replaced edge
39288
39289 this._backupEdgeOptions(_edge);
39290
39291 _edge.setOptions({
39292 physics: false
39293 });
39294 }
39295 }
39296 /**
39297 * This function checks the options that can be supplied to the different cluster functions
39298 * for certain fields and inserts defaults if needed
39299 * @param {Object} options
39300 * @returns {*}
39301 * @private
39302 */
39303
39304 }, {
39305 key: "_checkOptions",
39306 value: function _checkOptions() {
39307 var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
39308
39309 if (options.clusterEdgeProperties === undefined) {
39310 options.clusterEdgeProperties = {};
39311 }
39312
39313 if (options.clusterNodeProperties === undefined) {
39314 options.clusterNodeProperties = {};
39315 }
39316
39317 return options;
39318 }
39319 /**
39320 *
39321 * @param {Object} childNodesObj | object with node objects, id as keys, same as childNodes except it also contains a source node
39322 * @param {Object} childEdgesObj | object with edge objects, id as keys
39323 * @param {Array} options | object with {clusterNodeProperties, clusterEdgeProperties, processProperties}
39324 * @param {boolean} refreshData | when true, do not wrap up
39325 * @private
39326 */
39327
39328 }, {
39329 key: "_cluster",
39330 value: function _cluster(childNodesObj, childEdgesObj, options) {
39331 var refreshData = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : true;
39332 // Remove nodes which are already clustered
39333 var tmpNodesToRemove = [];
39334
39335 for (var nodeId in childNodesObj) {
39336 if (childNodesObj.hasOwnProperty(nodeId)) {
39337 if (this.clusteredNodes[nodeId] !== undefined) {
39338 tmpNodesToRemove.push(nodeId);
39339 }
39340 }
39341 }
39342
39343 for (var n = 0; n < tmpNodesToRemove.length; ++n) {
39344 delete childNodesObj[tmpNodesToRemove[n]];
39345 } // kill condition: no nodes don't bother
39346
39347
39348 if (Object.keys(childNodesObj).length == 0) {
39349 return;
39350 } // allow clusters of 1 if options allow
39351
39352
39353 if (Object.keys(childNodesObj).length == 1 && options.clusterNodeProperties.allowSingleNodeCluster != true) {
39354 return;
39355 }
39356
39357 var clusterNodeProperties = deepExtend({}, options.clusterNodeProperties); // construct the clusterNodeProperties
39358
39359 if (options.processProperties !== undefined) {
39360 // get the childNode options
39361 var childNodesOptions = [];
39362
39363 for (var _nodeId in childNodesObj) {
39364 if (childNodesObj.hasOwnProperty(_nodeId)) {
39365 var clonedOptions = NetworkUtil.cloneOptions(childNodesObj[_nodeId]);
39366 childNodesOptions.push(clonedOptions);
39367 }
39368 } // get cluster properties based on childNodes
39369
39370
39371 var childEdgesOptions = [];
39372
39373 for (var edgeId in childEdgesObj) {
39374 if (childEdgesObj.hasOwnProperty(edgeId)) {
39375 // these cluster edges will be removed on creation of the cluster.
39376 if (edgeId.substr(0, 12) !== "clusterEdge:") {
39377 var _clonedOptions = NetworkUtil.cloneOptions(childEdgesObj[edgeId], 'edge');
39378
39379 childEdgesOptions.push(_clonedOptions);
39380 }
39381 }
39382 }
39383
39384 clusterNodeProperties = options.processProperties(clusterNodeProperties, childNodesOptions, childEdgesOptions);
39385
39386 if (!clusterNodeProperties) {
39387 throw new Error("The processProperties function does not return properties!");
39388 }
39389 } // check if we have an unique id;
39390
39391
39392 if (clusterNodeProperties.id === undefined) {
39393 clusterNodeProperties.id = 'cluster:' + uuid4();
39394 }
39395
39396 var clusterId = clusterNodeProperties.id;
39397
39398 if (clusterNodeProperties.label === undefined) {
39399 clusterNodeProperties.label = 'cluster';
39400 } // give the clusterNode a position if it does not have one.
39401
39402
39403 var pos = undefined;
39404
39405 if (clusterNodeProperties.x === undefined) {
39406 pos = this._getClusterPosition(childNodesObj);
39407 clusterNodeProperties.x = pos.x;
39408 }
39409
39410 if (clusterNodeProperties.y === undefined) {
39411 if (pos === undefined) {
39412 pos = this._getClusterPosition(childNodesObj);
39413 }
39414
39415 clusterNodeProperties.y = pos.y;
39416 } // force the ID to remain the same
39417
39418
39419 clusterNodeProperties.id = clusterId; // create the cluster Node
39420 // Note that allowSingleNodeCluster, if present, is stored in the options as well
39421
39422 var clusterNode = this.body.functions.createNode(clusterNodeProperties, Cluster);
39423 clusterNode.containedNodes = childNodesObj;
39424 clusterNode.containedEdges = childEdgesObj; // cache a copy from the cluster edge properties if we have to reconnect others later on
39425
39426 clusterNode.clusterEdgeProperties = options.clusterEdgeProperties; // finally put the cluster node into global
39427
39428 this.body.nodes[clusterNodeProperties.id] = clusterNode;
39429
39430 this._clusterEdges(childNodesObj, childEdgesObj, clusterNodeProperties, options.clusterEdgeProperties); // set ID to undefined so no duplicates arise
39431
39432
39433 clusterNodeProperties.id = undefined; // wrap up
39434
39435 if (refreshData === true) {
39436 this.body.emitter.emit('_dataChanged');
39437 }
39438 }
39439 /**
39440 *
39441 * @param {Edge} edge
39442 * @private
39443 */
39444
39445 }, {
39446 key: "_backupEdgeOptions",
39447 value: function _backupEdgeOptions(edge) {
39448 if (this.clusteredEdges[edge.id] === undefined) {
39449 this.clusteredEdges[edge.id] = {
39450 physics: edge.options.physics
39451 };
39452 }
39453 }
39454 /**
39455 *
39456 * @param {Edge} edge
39457 * @private
39458 */
39459
39460 }, {
39461 key: "_restoreEdge",
39462 value: function _restoreEdge(edge) {
39463 var originalOptions = this.clusteredEdges[edge.id];
39464
39465 if (originalOptions !== undefined) {
39466 edge.setOptions({
39467 physics: originalOptions.physics
39468 });
39469 delete this.clusteredEdges[edge.id];
39470 }
39471 }
39472 /**
39473 * Check if a node is a cluster.
39474 * @param {Node.id} nodeId
39475 * @returns {*}
39476 */
39477
39478 }, {
39479 key: "isCluster",
39480 value: function isCluster(nodeId) {
39481 if (this.body.nodes[nodeId] !== undefined) {
39482 return this.body.nodes[nodeId].isCluster === true;
39483 } else {
39484 console.log("Node does not exist.");
39485 return false;
39486 }
39487 }
39488 /**
39489 * get the position of the cluster node based on what's inside
39490 * @param {object} childNodesObj | object with node objects, id as keys
39491 * @returns {{x: number, y: number}}
39492 * @private
39493 */
39494
39495 }, {
39496 key: "_getClusterPosition",
39497 value: function _getClusterPosition(childNodesObj) {
39498 var childKeys = Object.keys(childNodesObj);
39499 var minX = childNodesObj[childKeys[0]].x;
39500 var maxX = childNodesObj[childKeys[0]].x;
39501 var minY = childNodesObj[childKeys[0]].y;
39502 var maxY = childNodesObj[childKeys[0]].y;
39503 var node;
39504
39505 for (var i = 1; i < childKeys.length; i++) {
39506 node = childNodesObj[childKeys[i]];
39507 minX = node.x < minX ? node.x : minX;
39508 maxX = node.x > maxX ? node.x : maxX;
39509 minY = node.y < minY ? node.y : minY;
39510 maxY = node.y > maxY ? node.y : maxY;
39511 }
39512
39513 return {
39514 x: 0.5 * (minX + maxX),
39515 y: 0.5 * (minY + maxY)
39516 };
39517 }
39518 /**
39519 * Open a cluster by calling this function.
39520 * @param {vis.Edge.id} clusterNodeId | the ID of the cluster node
39521 * @param {Object} options
39522 * @param {boolean} refreshData | wrap up afterwards if not true
39523 */
39524
39525 }, {
39526 key: "openCluster",
39527 value: function openCluster(clusterNodeId, options) {
39528 var refreshData = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
39529
39530 // kill conditions
39531 if (clusterNodeId === undefined) {
39532 throw new Error("No clusterNodeId supplied to openCluster.");
39533 }
39534
39535 var clusterNode = this.body.nodes[clusterNodeId];
39536
39537 if (clusterNode === undefined) {
39538 throw new Error("The clusterNodeId supplied to openCluster does not exist.");
39539 }
39540
39541 if (clusterNode.isCluster !== true || clusterNode.containedNodes === undefined || clusterNode.containedEdges === undefined) {
39542 throw new Error("The node:" + clusterNodeId + " is not a valid cluster.");
39543 } // Check if current cluster is clustered itself
39544
39545
39546 var stack = this.findNode(clusterNodeId);
39547 var parentIndex = stack.indexOf(clusterNodeId) - 1;
39548
39549 if (parentIndex >= 0) {
39550 // Current cluster is clustered; transfer contained nodes and edges to parent
39551 var parentClusterNodeId = stack[parentIndex];
39552 var parentClusterNode = this.body.nodes[parentClusterNodeId]; // clustering.clusteredNodes and clustering.clusteredEdges remain unchanged
39553
39554 parentClusterNode._openChildCluster(clusterNodeId); // All components of child cluster node have been transferred. It can die now.
39555
39556
39557 delete this.body.nodes[clusterNodeId];
39558
39559 if (refreshData === true) {
39560 this.body.emitter.emit('_dataChanged');
39561 }
39562
39563 return;
39564 } // main body
39565
39566
39567 var containedNodes = clusterNode.containedNodes;
39568 var containedEdges = clusterNode.containedEdges; // allow the user to position the nodes after release.
39569
39570 if (options !== undefined && options.releaseFunction !== undefined && typeof options.releaseFunction === 'function') {
39571 var positions = {};
39572 var clusterPosition = {
39573 x: clusterNode.x,
39574 y: clusterNode.y
39575 };
39576
39577 for (var nodeId in containedNodes) {
39578 if (containedNodes.hasOwnProperty(nodeId)) {
39579 var containedNode = this.body.nodes[nodeId];
39580 positions[nodeId] = {
39581 x: containedNode.x,
39582 y: containedNode.y
39583 };
39584 }
39585 }
39586
39587 var newPositions = options.releaseFunction(clusterPosition, positions);
39588
39589 for (var _nodeId2 in containedNodes) {
39590 if (containedNodes.hasOwnProperty(_nodeId2)) {
39591 var _containedNode = this.body.nodes[_nodeId2];
39592
39593 if (newPositions[_nodeId2] !== undefined) {
39594 _containedNode.x = newPositions[_nodeId2].x === undefined ? clusterNode.x : newPositions[_nodeId2].x;
39595 _containedNode.y = newPositions[_nodeId2].y === undefined ? clusterNode.y : newPositions[_nodeId2].y;
39596 }
39597 }
39598 }
39599 } else {
39600 // copy the position from the cluster
39601 forEach(containedNodes, function (containedNode) {
39602 // inherit position
39603 if (containedNode.options.fixed.x === false) {
39604 containedNode.x = clusterNode.x;
39605 }
39606
39607 if (containedNode.options.fixed.y === false) {
39608 containedNode.y = clusterNode.y;
39609 }
39610 });
39611 } // release nodes
39612
39613
39614 for (var _nodeId3 in containedNodes) {
39615 if (containedNodes.hasOwnProperty(_nodeId3)) {
39616 var _containedNode2 = this.body.nodes[_nodeId3]; // inherit speed
39617
39618 _containedNode2.vx = clusterNode.vx;
39619 _containedNode2.vy = clusterNode.vy;
39620
39621 _containedNode2.setOptions({
39622 physics: true
39623 });
39624
39625 delete this.clusteredNodes[_nodeId3];
39626 }
39627 } // copy the clusterNode edges because we cannot iterate over an object that we add or remove from.
39628
39629
39630 var edgesToBeDeleted = [];
39631
39632 for (var i = 0; i < clusterNode.edges.length; i++) {
39633 edgesToBeDeleted.push(clusterNode.edges[i]);
39634 } // actually handling the deleting.
39635
39636
39637 for (var _i3 = 0; _i3 < edgesToBeDeleted.length; _i3++) {
39638 var edge = edgesToBeDeleted[_i3];
39639
39640 var otherNodeId = this._getConnectedId(edge, clusterNodeId);
39641
39642 var otherNode = this.clusteredNodes[otherNodeId];
39643
39644 for (var j = 0; j < edge.clusteringEdgeReplacingIds.length; j++) {
39645 var transferId = edge.clusteringEdgeReplacingIds[j];
39646 var transferEdge = this.body.edges[transferId];
39647 if (transferEdge === undefined) continue; // if the other node is in another cluster, we transfer ownership of this edge to the other cluster
39648
39649 if (otherNode !== undefined) {
39650 // transfer ownership:
39651 var otherCluster = this.body.nodes[otherNode.clusterId];
39652 otherCluster.containedEdges[transferEdge.id] = transferEdge; // delete local reference
39653
39654 delete containedEdges[transferEdge.id]; // get to and from
39655
39656 var fromId = transferEdge.fromId;
39657 var toId = transferEdge.toId;
39658
39659 if (transferEdge.toId == otherNodeId) {
39660 toId = otherNode.clusterId;
39661 } else {
39662 fromId = otherNode.clusterId;
39663 } // create new cluster edge from the otherCluster
39664
39665
39666 this._createClusteredEdge(fromId, toId, transferEdge, otherCluster.clusterEdgeProperties, {
39667 hidden: false,
39668 physics: true
39669 });
39670 } else {
39671 this._restoreEdge(transferEdge);
39672 }
39673 }
39674
39675 edge.remove();
39676 } // handle the releasing of the edges
39677
39678
39679 for (var edgeId in containedEdges) {
39680 if (containedEdges.hasOwnProperty(edgeId)) {
39681 this._restoreEdge(containedEdges[edgeId]);
39682 }
39683 } // remove clusterNode
39684
39685
39686 delete this.body.nodes[clusterNodeId];
39687
39688 if (refreshData === true) {
39689 this.body.emitter.emit('_dataChanged');
39690 }
39691 }
39692 /**
39693 *
39694 * @param {Cluster.id} clusterId
39695 * @returns {Array.<Node.id>}
39696 */
39697
39698 }, {
39699 key: "getNodesInCluster",
39700 value: function getNodesInCluster(clusterId) {
39701 var nodesArray = [];
39702
39703 if (this.isCluster(clusterId) === true) {
39704 var containedNodes = this.body.nodes[clusterId].containedNodes;
39705
39706 for (var nodeId in containedNodes) {
39707 if (containedNodes.hasOwnProperty(nodeId)) {
39708 nodesArray.push(this.body.nodes[nodeId].id);
39709 }
39710 }
39711 }
39712
39713 return nodesArray;
39714 }
39715 /**
39716 * Get the stack clusterId's that a certain node resides in. cluster A -> cluster B -> cluster C -> node
39717 *
39718 * If a node can't be found in the chain, return an empty array.
39719 *
39720 * @param {string|number} nodeId
39721 * @returns {Array}
39722 */
39723
39724 }, {
39725 key: "findNode",
39726 value: function findNode(nodeId) {
39727 var stack = [];
39728 var max = 100;
39729 var counter = 0;
39730 var node;
39731
39732 while (this.clusteredNodes[nodeId] !== undefined && counter < max) {
39733 node = this.body.nodes[nodeId];
39734 if (node === undefined) return [];
39735 stack.push(node.id);
39736 nodeId = this.clusteredNodes[nodeId].clusterId;
39737 counter++;
39738 }
39739
39740 node = this.body.nodes[nodeId];
39741 if (node === undefined) return [];
39742 stack.push(node.id);
39743 stack.reverse();
39744 return stack;
39745 }
39746 /**
39747 * Using a clustered nodeId, update with the new options
39748 * @param {vis.Edge.id} clusteredNodeId
39749 * @param {object} newOptions
39750 */
39751
39752 }, {
39753 key: "updateClusteredNode",
39754 value: function updateClusteredNode(clusteredNodeId, newOptions) {
39755 if (clusteredNodeId === undefined) {
39756 throw new Error("No clusteredNodeId supplied to updateClusteredNode.");
39757 }
39758
39759 if (newOptions === undefined) {
39760 throw new Error("No newOptions supplied to updateClusteredNode.");
39761 }
39762
39763 if (this.body.nodes[clusteredNodeId] === undefined) {
39764 throw new Error("The clusteredNodeId supplied to updateClusteredNode does not exist.");
39765 }
39766
39767 this.body.nodes[clusteredNodeId].setOptions(newOptions);
39768 this.body.emitter.emit('_dataChanged');
39769 }
39770 /**
39771 * Using a base edgeId, update all related clustered edges with the new options
39772 * @param {vis.Edge.id} startEdgeId
39773 * @param {object} newOptions
39774 */
39775
39776 }, {
39777 key: "updateEdge",
39778 value: function updateEdge(startEdgeId, newOptions) {
39779 if (startEdgeId === undefined) {
39780 throw new Error("No startEdgeId supplied to updateEdge.");
39781 }
39782
39783 if (newOptions === undefined) {
39784 throw new Error("No newOptions supplied to updateEdge.");
39785 }
39786
39787 if (this.body.edges[startEdgeId] === undefined) {
39788 throw new Error("The startEdgeId supplied to updateEdge does not exist.");
39789 }
39790
39791 var allEdgeIds = this.getClusteredEdges(startEdgeId);
39792
39793 for (var i = 0; i < allEdgeIds.length; i++) {
39794 var edge = this.body.edges[allEdgeIds[i]];
39795 edge.setOptions(newOptions);
39796 }
39797
39798 this.body.emitter.emit('_dataChanged');
39799 }
39800 /**
39801 * 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)
39802 * @param {vis.Edge.id} edgeId
39803 * @returns {Array.<vis.Edge.id>}
39804 */
39805
39806 }, {
39807 key: "getClusteredEdges",
39808 value: function getClusteredEdges(edgeId) {
39809 var stack = [];
39810 var max = 100;
39811 var counter = 0;
39812
39813 while (edgeId !== undefined && this.body.edges[edgeId] !== undefined && counter < max) {
39814 stack.push(this.body.edges[edgeId].id);
39815 edgeId = this.body.edges[edgeId].edgeReplacedById;
39816 counter++;
39817 }
39818
39819 stack.reverse();
39820 return stack;
39821 }
39822 /**
39823 * Get the base edge id of clusterEdgeId. cluster edge (clusteredEdgeId) -> cluster edge B -> cluster edge C -> base edge
39824 * @param {vis.Edge.id} clusteredEdgeId
39825 * @returns {vis.Edge.id} baseEdgeId
39826 *
39827 * TODO: deprecate in 5.0.0. Method getBaseEdges() is the correct one to use.
39828 */
39829
39830 }, {
39831 key: "getBaseEdge",
39832 value: function getBaseEdge(clusteredEdgeId) {
39833 // Just kludge this by returning the first base edge id found
39834 return this.getBaseEdges(clusteredEdgeId)[0];
39835 }
39836 /**
39837 * Get all regular edges for this clustered edge id.
39838 *
39839 * @param {vis.Edge.id} clusteredEdgeId
39840 * @returns {Array.<vis.Edge.id>} all baseEdgeId's under this clustered edge
39841 */
39842
39843 }, {
39844 key: "getBaseEdges",
39845 value: function getBaseEdges(clusteredEdgeId) {
39846 var IdsToHandle = [clusteredEdgeId];
39847 var doneIds = [];
39848 var foundIds = [];
39849 var max = 100;
39850 var counter = 0;
39851
39852 while (IdsToHandle.length > 0 && counter < max) {
39853 var nextId = IdsToHandle.pop();
39854 if (nextId === undefined) continue; // Paranoia here and onwards
39855
39856 var nextEdge = this.body.edges[nextId];
39857 if (nextEdge === undefined) continue;
39858 counter++;
39859 var replacingIds = nextEdge.clusteringEdgeReplacingIds;
39860
39861 if (replacingIds === undefined) {
39862 // nextId is a base id
39863 foundIds.push(nextId);
39864 } else {
39865 // Another cluster edge, unravel this one as well
39866 for (var i = 0; i < replacingIds.length; ++i) {
39867 var replacingId = replacingIds[i]; // Don't add if already handled
39868 // TODO: never triggers; find a test-case which does
39869
39870 if (IdsToHandle.indexOf(replacingIds) !== -1 || doneIds.indexOf(replacingIds) !== -1) {
39871 continue;
39872 }
39873
39874 IdsToHandle.push(replacingId);
39875 }
39876 }
39877
39878 doneIds.push(nextId);
39879 }
39880
39881 return foundIds;
39882 }
39883 /**
39884 * Get the Id the node is connected to
39885 * @param {vis.Edge} edge
39886 * @param {Node.id} nodeId
39887 * @returns {*}
39888 * @private
39889 */
39890
39891 }, {
39892 key: "_getConnectedId",
39893 value: function _getConnectedId(edge, nodeId) {
39894 if (edge.toId != nodeId) {
39895 return edge.toId;
39896 } else if (edge.fromId != nodeId) {
39897 return edge.fromId;
39898 } else {
39899 return edge.fromId;
39900 }
39901 }
39902 /**
39903 * We determine how many connections denote an important hub.
39904 * We take the mean + 2*std as the important hub size. (Assuming a normal distribution of data, ~2.2%)
39905 *
39906 * @returns {number}
39907 * @private
39908 */
39909
39910 }, {
39911 key: "_getHubSize",
39912 value: function _getHubSize() {
39913 var average = 0;
39914 var averageSquared = 0;
39915 var hubCounter = 0;
39916 var largestHub = 0;
39917
39918 for (var i = 0; i < this.body.nodeIndices.length; i++) {
39919 var node = this.body.nodes[this.body.nodeIndices[i]];
39920
39921 if (node.edges.length > largestHub) {
39922 largestHub = node.edges.length;
39923 }
39924
39925 average += node.edges.length;
39926 averageSquared += Math.pow(node.edges.length, 2);
39927 hubCounter += 1;
39928 }
39929
39930 average = average / hubCounter;
39931 averageSquared = averageSquared / hubCounter;
39932 var variance = averageSquared - Math.pow(average, 2);
39933 var standardDeviation = Math.sqrt(variance);
39934 var hubThreshold = Math.floor(average + 2 * standardDeviation); // always have at least one to cluster
39935
39936 if (hubThreshold > largestHub) {
39937 hubThreshold = largestHub;
39938 }
39939
39940 return hubThreshold;
39941 }
39942 /**
39943 * Create an edge for the cluster representation.
39944 *
39945 * @param {Node.id} fromId
39946 * @param {Node.id} toId
39947 * @param {vis.Edge} baseEdge
39948 * @param {Object} clusterEdgeProperties
39949 * @param {Object} extraOptions
39950 * @returns {Edge} newly created clustered edge
39951 * @private
39952 */
39953
39954 }, {
39955 key: "_createClusteredEdge",
39956 value: function _createClusteredEdge(fromId, toId, baseEdge, clusterEdgeProperties, extraOptions) {
39957 // copy the options of the edge we will replace
39958 var clonedOptions = NetworkUtil.cloneOptions(baseEdge, 'edge'); // make sure the properties of clusterEdges are superimposed on it
39959
39960 deepExtend(clonedOptions, clusterEdgeProperties); // set up the edge
39961
39962 clonedOptions.from = fromId;
39963 clonedOptions.to = toId;
39964 clonedOptions.id = 'clusterEdge:' + uuid4(); // apply the edge specific options to it if specified
39965
39966 if (extraOptions !== undefined) {
39967 deepExtend(clonedOptions, extraOptions);
39968 }
39969
39970 var newEdge = this.body.functions.createEdge(clonedOptions);
39971 newEdge.clusteringEdgeReplacingIds = [baseEdge.id];
39972 newEdge.connect(); // Register the new edge
39973
39974 this.body.edges[newEdge.id] = newEdge;
39975 return newEdge;
39976 }
39977 /**
39978 * Add the passed child nodes and edges to the given cluster node.
39979 *
39980 * @param {Object|Node} childNodes hash of nodes or single node to add in cluster
39981 * @param {Object|Edge} childEdges hash of edges or single edge to take into account when clustering
39982 * @param {Node} clusterNode cluster node to add nodes and edges to
39983 * @param {Object} [clusterEdgeProperties]
39984 * @private
39985 */
39986
39987 }, {
39988 key: "_clusterEdges",
39989 value: function _clusterEdges(childNodes, childEdges, clusterNode, clusterEdgeProperties) {
39990 if (childEdges instanceof Edge) {
39991 var edge = childEdges;
39992 var obj = {};
39993 obj[edge.id] = edge;
39994 childEdges = obj;
39995 }
39996
39997 if (childNodes instanceof Node) {
39998 var node = childNodes;
39999 var _obj = {};
40000 _obj[node.id] = node;
40001 childNodes = _obj;
40002 }
40003
40004 if (clusterNode === undefined || clusterNode === null) {
40005 throw new Error("_clusterEdges: parameter clusterNode required");
40006 }
40007
40008 if (clusterEdgeProperties === undefined) {
40009 // Take the required properties from the cluster node
40010 clusterEdgeProperties = clusterNode.clusterEdgeProperties;
40011 } // create the new edges that will connect to the cluster.
40012 // All self-referencing edges will be added to childEdges here.
40013
40014
40015 this._createClusterEdges(childNodes, childEdges, clusterNode, clusterEdgeProperties); // disable the childEdges
40016
40017
40018 for (var edgeId in childEdges) {
40019 if (childEdges.hasOwnProperty(edgeId)) {
40020 if (this.body.edges[edgeId] !== undefined) {
40021 var _edge2 = this.body.edges[edgeId]; // cache the options before changing
40022
40023 this._backupEdgeOptions(_edge2); // disable physics and hide the edge
40024
40025
40026 _edge2.setOptions({
40027 physics: false
40028 });
40029 }
40030 }
40031 } // disable the childNodes
40032
40033
40034 for (var nodeId in childNodes) {
40035 if (childNodes.hasOwnProperty(nodeId)) {
40036 this.clusteredNodes[nodeId] = {
40037 clusterId: clusterNode.id,
40038 node: this.body.nodes[nodeId]
40039 };
40040 this.body.nodes[nodeId].setOptions({
40041 physics: false
40042 });
40043 }
40044 }
40045 }
40046 /**
40047 * Determine in which cluster given nodeId resides.
40048 *
40049 * If not in cluster, return undefined.
40050 *
40051 * NOTE: If you know a cleaner way to do this, please enlighten me (wimrijnders).
40052 *
40053 * @param {Node.id} nodeId
40054 * @returns {Node|undefined} Node instance for cluster, if present
40055 * @private
40056 */
40057
40058 }, {
40059 key: "_getClusterNodeForNode",
40060 value: function _getClusterNodeForNode(nodeId) {
40061 if (nodeId === undefined) return undefined;
40062 var clusteredNode = this.clusteredNodes[nodeId]; // NOTE: If no cluster info found, it should actually be an error
40063
40064 if (clusteredNode === undefined) return undefined;
40065 var clusterId = clusteredNode.clusterId;
40066 if (clusterId === undefined) return undefined;
40067 return this.body.nodes[clusterId];
40068 }
40069 /**
40070 * Internal helper function for conditionally removing items in array
40071 *
40072 * Done like this because Array.filter() is not fully supported by all IE's.
40073 *
40074 * @param {Array} arr
40075 * @param {function} callback
40076 * @returns {Array}
40077 * @private
40078 */
40079
40080 }, {
40081 key: "_filter",
40082 value: function _filter(arr, callback) {
40083 var ret = [];
40084 forEach(arr, function (item) {
40085 if (callback(item)) {
40086 ret.push(item);
40087 }
40088 });
40089 return ret;
40090 }
40091 /**
40092 * Scan all edges for changes in clustering and adjust this if necessary.
40093 *
40094 * Call this (internally) after there has been a change in node or edge data.
40095 *
40096 * Pre: States of this.body.nodes and this.body.edges consistent
40097 * Pre: this.clusteredNodes and this.clusteredEdge consistent with containedNodes and containedEdges
40098 * of cluster nodes.
40099 */
40100
40101 }, {
40102 key: "_updateState",
40103 value: function _updateState() {
40104 var _this4 = this;
40105
40106 var nodeId;
40107 var deletedNodeIds = [];
40108 var deletedEdgeIds = {};
40109 /**
40110 * Utility function to iterate over clustering nodes only
40111 *
40112 * @param {Function} callback function to call for each cluster node
40113 */
40114
40115 var eachClusterNode = function eachClusterNode(callback) {
40116 forEach(_this4.body.nodes, function (node) {
40117 if (node.isCluster === true) {
40118 callback(node);
40119 }
40120 });
40121 }; //
40122 // Remove deleted regular nodes from clustering
40123 //
40124 // Determine the deleted nodes
40125
40126
40127 for (nodeId in this.clusteredNodes) {
40128 if (!this.clusteredNodes.hasOwnProperty(nodeId)) continue;
40129 var node = this.body.nodes[nodeId];
40130
40131 if (node === undefined) {
40132 deletedNodeIds.push(nodeId);
40133 }
40134 } // Remove nodes from cluster nodes
40135
40136
40137 eachClusterNode(function (clusterNode) {
40138 for (var n = 0; n < deletedNodeIds.length; n++) {
40139 delete clusterNode.containedNodes[deletedNodeIds[n]];
40140 }
40141 }); // Remove nodes from cluster list
40142
40143 for (var n = 0; n < deletedNodeIds.length; n++) {
40144 delete this.clusteredNodes[deletedNodeIds[n]];
40145 } //
40146 // Remove deleted edges from clustering
40147 //
40148 // Add the deleted clustered edges to the list
40149
40150
40151 forEach(this.clusteredEdges, function (edgeId) {
40152 var edge = _this4.body.edges[edgeId];
40153
40154 if (edge === undefined || !edge.endPointsValid()) {
40155 deletedEdgeIds[edgeId] = edgeId;
40156 }
40157 }); // Cluster nodes can also contain edges which are not clustered,
40158 // i.e. nodes 1-2 within cluster with an edge in between.
40159 // So the cluster nodes also need to be scanned for invalid edges
40160
40161 eachClusterNode(function (clusterNode) {
40162 forEach(clusterNode.containedEdges, function (edge, edgeId) {
40163 if (!edge.endPointsValid() && !deletedEdgeIds[edgeId]) {
40164 deletedEdgeIds[edgeId] = edgeId;
40165 }
40166 });
40167 }); // Also scan for cluster edges which need to be removed in the active list.
40168 // Regular edges have been removed beforehand, so this only picks up the cluster edges.
40169
40170 forEach(this.body.edges, function (edge, edgeId) {
40171 // Explicitly scan the contained edges for validity
40172 var isValid = true;
40173 var replacedIds = edge.clusteringEdgeReplacingIds;
40174
40175 if (replacedIds !== undefined) {
40176 var numValid = 0;
40177 forEach(replacedIds, function (containedEdgeId) {
40178 var containedEdge = _this4.body.edges[containedEdgeId];
40179
40180 if (containedEdge !== undefined && containedEdge.endPointsValid()) {
40181 numValid += 1;
40182 }
40183 });
40184 isValid = numValid > 0;
40185 }
40186
40187 if (!edge.endPointsValid() || !isValid) {
40188 deletedEdgeIds[edgeId] = edgeId;
40189 }
40190 }); // Remove edges from cluster nodes
40191
40192 eachClusterNode(function (clusterNode) {
40193 forEach(deletedEdgeIds, function (deletedEdgeId) {
40194 delete clusterNode.containedEdges[deletedEdgeId];
40195 forEach(clusterNode.edges, function (edge, m) {
40196 if (edge.id === deletedEdgeId) {
40197 clusterNode.edges[m] = null; // Don't want to directly delete here, because in the loop
40198
40199 return;
40200 }
40201
40202 edge.clusteringEdgeReplacingIds = _this4._filter(edge.clusteringEdgeReplacingIds, function (id) {
40203 return !deletedEdgeIds[id];
40204 });
40205 }); // Clean up the nulls
40206
40207 clusterNode.edges = _this4._filter(clusterNode.edges, function (item) {
40208 return item !== null;
40209 });
40210 });
40211 }); // Remove from cluster list
40212
40213 forEach(deletedEdgeIds, function (edgeId) {
40214 delete _this4.clusteredEdges[edgeId];
40215 }); // Remove cluster edges from active list (this.body.edges).
40216 // deletedEdgeIds still contains id of regular edges, but these should all
40217 // be gone when you reach here.
40218
40219 forEach(deletedEdgeIds, function (edgeId) {
40220 delete _this4.body.edges[edgeId];
40221 }); //
40222 // Check changed cluster state of edges
40223 //
40224 // Iterating over keys here, because edges may be removed in the loop
40225
40226 var ids = Object.keys(this.body.edges);
40227 forEach(ids, function (edgeId) {
40228 var edge = _this4.body.edges[edgeId];
40229
40230 var shouldBeClustered = _this4._isClusteredNode(edge.fromId) || _this4._isClusteredNode(edge.toId);
40231
40232 if (shouldBeClustered === _this4._isClusteredEdge(edge.id)) {
40233 return; // all is well
40234 }
40235
40236 if (shouldBeClustered) {
40237 // add edge to clustering
40238 var clusterFrom = _this4._getClusterNodeForNode(edge.fromId);
40239
40240 if (clusterFrom !== undefined) {
40241 _this4._clusterEdges(_this4.body.nodes[edge.fromId], edge, clusterFrom);
40242 }
40243
40244 var clusterTo = _this4._getClusterNodeForNode(edge.toId);
40245
40246 if (clusterTo !== undefined) {
40247 _this4._clusterEdges(_this4.body.nodes[edge.toId], edge, clusterTo);
40248 } // TODO: check that it works for both edges clustered
40249 // (This might be paranoia)
40250
40251 } else {
40252 delete _this4._clusterEdges[edgeId];
40253
40254 _this4._restoreEdge(edge); // This should not be happening, the state should
40255 // be properly updated at this point.
40256 //
40257 // If it *is* reached during normal operation, then we have to implement
40258 // undo clustering for this edge here.
40259 // throw new Error('remove edge from clustering not implemented!')
40260
40261 }
40262 }); // Clusters may be nested to any level. Keep on opening until nothing to open
40263
40264 var changed = false;
40265 var continueLoop = true;
40266
40267 var _loop2 = function _loop2() {
40268 var clustersToOpen = []; // Determine the id's of clusters that need opening
40269
40270 eachClusterNode(function (clusterNode) {
40271 var numNodes = Object.keys(clusterNode.containedNodes).length;
40272 var allowSingle = clusterNode.options.allowSingleNodeCluster === true;
40273
40274 if (allowSingle && numNodes < 1 || !allowSingle && numNodes < 2) {
40275 clustersToOpen.push(clusterNode.id);
40276 }
40277 }); // Open them
40278
40279 for (var _n = 0; _n < clustersToOpen.length; ++_n) {
40280 _this4.openCluster(clustersToOpen[_n], {}, false
40281 /* Don't refresh, we're in an refresh/update already */
40282 );
40283 }
40284
40285 continueLoop = clustersToOpen.length > 0;
40286 changed = changed || continueLoop;
40287 };
40288
40289 while (continueLoop) {
40290 _loop2();
40291 }
40292
40293 if (changed) {
40294 this._updateState(); // Redo this method (recursion possible! should be safe)
40295
40296 }
40297 }
40298 /**
40299 * Determine if node with given id is part of a cluster.
40300 *
40301 * @param {Node.id} nodeId
40302 * @return {boolean} true if part of a cluster.
40303 */
40304
40305 }, {
40306 key: "_isClusteredNode",
40307 value: function _isClusteredNode(nodeId) {
40308 return this.clusteredNodes[nodeId] !== undefined;
40309 }
40310 /**
40311 * Determine if edge with given id is not visible due to clustering.
40312 *
40313 * An edge is considered clustered if:
40314 * - it is directly replaced by a clustering edge
40315 * - any of its connecting nodes is in a cluster
40316 *
40317 * @param {vis.Edge.id} edgeId
40318 * @return {boolean} true if part of a cluster.
40319 */
40320
40321 }, {
40322 key: "_isClusteredEdge",
40323 value: function _isClusteredEdge(edgeId) {
40324 return this.clusteredEdges[edgeId] !== undefined;
40325 }
40326 }]);
40327
40328 return ClusterEngine;
40329 }();
40330
40331 /**
40332 * Initializes window.requestAnimationFrame() to a usable form.
40333 *
40334 * Specifically, set up this method for the case of running on node.js with jsdom enabled.
40335 *
40336 * NOTES:
40337 *
40338 * * On node.js, when calling this directly outside of this class, `window` is not defined.
40339 * This happens even if jsdom is used.
40340 * * For node.js + jsdom, `window` is available at the moment the constructor is called.
40341 * For this reason, the called is placed within the constructor.
40342 * * Even then, `window.requestAnimationFrame()` is not defined, so it still needs to be added.
40343 * * During unit testing, it happens that the window object is reset during execution, causing
40344 * a runtime error due to missing `requestAnimationFrame()`. This needs to be compensated for,
40345 * see `_requestNextFrame()`.
40346 * * Since this is a global object, it may affect other modules besides `Network`. With normal
40347 * usage, this does not cause any problems. During unit testing, errors may occur. These have
40348 * been compensated for, see comment block in _requestNextFrame().
40349 *
40350 * @private
40351 */
40352 function _initRequestAnimationFrame() {
40353 var func;
40354
40355 if (window !== undefined) {
40356 func = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;
40357 }
40358
40359 if (func === undefined) {
40360 // window or method not present, setting mock requestAnimationFrame
40361 window.requestAnimationFrame = function (callback) {
40362 //console.log("Called mock requestAnimationFrame");
40363 callback();
40364 };
40365 } else {
40366 window.requestAnimationFrame = func;
40367 }
40368 }
40369 /**
40370 * The canvas renderer
40371 */
40372
40373 var CanvasRenderer =
40374 /*#__PURE__*/
40375 function () {
40376 /**
40377 * @param {Object} body
40378 * @param {Canvas} canvas
40379 */
40380 function CanvasRenderer(body, canvas) {
40381 _classCallCheck(this, CanvasRenderer);
40382
40383 _initRequestAnimationFrame();
40384
40385 this.body = body;
40386 this.canvas = canvas;
40387 this.redrawRequested = false;
40388 this.renderTimer = undefined;
40389 this.requiresTimeout = true;
40390 this.renderingActive = false;
40391 this.renderRequests = 0;
40392 this.allowRedraw = true;
40393 this.dragging = false;
40394 this.zooming = false;
40395 this.options = {};
40396 this.defaultOptions = {
40397 hideEdgesOnDrag: false,
40398 hideEdgesOnZoom: false,
40399 hideNodesOnDrag: false
40400 };
40401 extend(this.options, this.defaultOptions);
40402
40403 this._determineBrowserMethod();
40404
40405 this.bindEventListeners();
40406 }
40407 /**
40408 * Binds event listeners
40409 */
40410
40411
40412 _createClass(CanvasRenderer, [{
40413 key: "bindEventListeners",
40414 value: function bindEventListeners() {
40415 var _this = this;
40416
40417 this.body.emitter.on("dragStart", function () {
40418 _this.dragging = true;
40419 });
40420 this.body.emitter.on("dragEnd", function () {
40421 _this.dragging = false;
40422 });
40423 this.body.emitter.on("zoom", function () {
40424 _this.zooming = true;
40425 window.clearTimeout(_this.zoomTimeoutId);
40426 _this.zoomTimeoutId = window.setTimeout(function () {
40427 _this.zooming = false;
40428
40429 _this._requestRedraw.bind(_this)();
40430 }, 250);
40431 });
40432 this.body.emitter.on("_resizeNodes", function () {
40433 _this._resizeNodes();
40434 });
40435 this.body.emitter.on("_redraw", function () {
40436 if (_this.renderingActive === false) {
40437 _this._redraw();
40438 }
40439 });
40440 this.body.emitter.on("_blockRedraw", function () {
40441 _this.allowRedraw = false;
40442 });
40443 this.body.emitter.on("_allowRedraw", function () {
40444 _this.allowRedraw = true;
40445 _this.redrawRequested = false;
40446 });
40447 this.body.emitter.on("_requestRedraw", this._requestRedraw.bind(this));
40448 this.body.emitter.on("_startRendering", function () {
40449 _this.renderRequests += 1;
40450 _this.renderingActive = true;
40451
40452 _this._startRendering();
40453 });
40454 this.body.emitter.on("_stopRendering", function () {
40455 _this.renderRequests -= 1;
40456 _this.renderingActive = _this.renderRequests > 0;
40457 _this.renderTimer = undefined;
40458 });
40459 this.body.emitter.on('destroy', function () {
40460 _this.renderRequests = 0;
40461 _this.allowRedraw = false;
40462 _this.renderingActive = false;
40463
40464 if (_this.requiresTimeout === true) {
40465 clearTimeout(_this.renderTimer);
40466 } else {
40467 window.cancelAnimationFrame(_this.renderTimer);
40468 }
40469
40470 _this.body.emitter.off();
40471 });
40472 }
40473 /**
40474 *
40475 * @param {Object} options
40476 */
40477
40478 }, {
40479 key: "setOptions",
40480 value: function setOptions(options) {
40481 if (options !== undefined) {
40482 var fields = ['hideEdgesOnDrag', 'hideEdgesOnZoom', 'hideNodesOnDrag'];
40483 selectiveDeepExtend(fields, this.options, options);
40484 }
40485 }
40486 /**
40487 * Prepare the drawing of the next frame.
40488 *
40489 * Calls the callback when the next frame can or will be drawn.
40490 *
40491 * @param {function} callback
40492 * @param {number} delay - timeout case only, wait this number of milliseconds
40493 * @returns {function|undefined}
40494 * @private
40495 */
40496
40497 }, {
40498 key: "_requestNextFrame",
40499 value: function _requestNextFrame(callback, delay) {
40500 // During unit testing, it happens that the mock window object is reset while
40501 // the next frame is still pending. Then, either 'window' is not present, or
40502 // 'requestAnimationFrame()' is not present because it is not defined on the
40503 // mock window object.
40504 //
40505 // As a consequence, unrelated unit tests may appear to fail, even if the problem
40506 // described happens in the current unit test.
40507 //
40508 // This is not something that will happen in normal operation, but we still need
40509 // to take it into account.
40510 //
40511 if (typeof window === 'undefined') return; // Doing `if (window === undefined)` does not work here!
40512
40513 var timer;
40514 var myWindow = window; // Grab a reference to reduce the possibility that 'window' is reset
40515 // while running this method.
40516
40517 if (this.requiresTimeout === true) {
40518 // wait given number of milliseconds and perform the animation step function
40519 timer = myWindow.setTimeout(callback, delay);
40520 } else {
40521 if (myWindow.requestAnimationFrame) {
40522 timer = myWindow.requestAnimationFrame(callback);
40523 }
40524 }
40525
40526 return timer;
40527 }
40528 /**
40529 *
40530 * @private
40531 */
40532
40533 }, {
40534 key: "_startRendering",
40535 value: function _startRendering() {
40536 if (this.renderingActive === true) {
40537 if (this.renderTimer === undefined) {
40538 this.renderTimer = this._requestNextFrame(this._renderStep.bind(this), this.simulationInterval);
40539 }
40540 }
40541 }
40542 /**
40543 *
40544 * @private
40545 */
40546
40547 }, {
40548 key: "_renderStep",
40549 value: function _renderStep() {
40550 if (this.renderingActive === true) {
40551 // reset the renderTimer so a new scheduled animation step can be set
40552 this.renderTimer = undefined;
40553
40554 if (this.requiresTimeout === true) {
40555 // this schedules a new simulation step
40556 this._startRendering();
40557 }
40558
40559 this._redraw();
40560
40561 if (this.requiresTimeout === false) {
40562 // this schedules a new simulation step
40563 this._startRendering();
40564 }
40565 }
40566 }
40567 /**
40568 * Redraw the network with the current data
40569 * chart will be resized too.
40570 */
40571
40572 }, {
40573 key: "redraw",
40574 value: function redraw() {
40575 this.body.emitter.emit('setSize');
40576
40577 this._redraw();
40578 }
40579 /**
40580 * Redraw the network with the current data
40581 * @private
40582 */
40583
40584 }, {
40585 key: "_requestRedraw",
40586 value: function _requestRedraw() {
40587 var _this2 = this;
40588
40589 if (this.redrawRequested !== true && this.renderingActive === false && this.allowRedraw === true) {
40590 this.redrawRequested = true;
40591
40592 this._requestNextFrame(function () {
40593 _this2._redraw(false);
40594 }, 0);
40595 }
40596 }
40597 /**
40598 * Redraw the network with the current data
40599 * @param {boolean} [hidden=false] | Used to get the first estimate of the node sizes.
40600 * Only the nodes are drawn after which they are quickly drawn over.
40601 * @private
40602 */
40603
40604 }, {
40605 key: "_redraw",
40606 value: function _redraw() {
40607 var hidden = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
40608
40609 if (this.allowRedraw === true) {
40610 this.body.emitter.emit("initRedraw");
40611 this.redrawRequested = false; // when the container div was hidden, this fixes it back up!
40612
40613 if (this.canvas.frame.canvas.width === 0 || this.canvas.frame.canvas.height === 0) {
40614 this.canvas.setSize();
40615 }
40616
40617 this.canvas.setTransform();
40618 var ctx = this.canvas.getContext(); // clear the canvas
40619
40620 var w = this.canvas.frame.canvas.clientWidth;
40621 var h = this.canvas.frame.canvas.clientHeight;
40622 ctx.clearRect(0, 0, w, h); // if the div is hidden, we stop the redraw here for performance.
40623
40624 if (this.canvas.frame.clientWidth === 0) {
40625 return;
40626 } // set scaling and translation
40627
40628
40629 ctx.save();
40630 ctx.translate(this.body.view.translation.x, this.body.view.translation.y);
40631 ctx.scale(this.body.view.scale, this.body.view.scale);
40632 ctx.beginPath();
40633 this.body.emitter.emit("beforeDrawing", ctx);
40634 ctx.closePath();
40635
40636 if (hidden === false) {
40637 if ((this.dragging === false || this.dragging === true && this.options.hideEdgesOnDrag === false) && (this.zooming === false || this.zooming === true && this.options.hideEdgesOnZoom === false)) {
40638 this._drawEdges(ctx);
40639 }
40640 }
40641
40642 if (this.dragging === false || this.dragging === true && this.options.hideNodesOnDrag === false) {
40643 this._drawNodes(ctx, hidden);
40644 }
40645
40646 ctx.beginPath();
40647 this.body.emitter.emit("afterDrawing", ctx);
40648 ctx.closePath(); // restore original scaling and translation
40649
40650 ctx.restore();
40651
40652 if (hidden === true) {
40653 ctx.clearRect(0, 0, w, h);
40654 }
40655 }
40656 }
40657 /**
40658 * Redraw all nodes
40659 *
40660 * @param {CanvasRenderingContext2D} ctx
40661 * @param {boolean} [alwaysShow]
40662 * @private
40663 */
40664
40665 }, {
40666 key: "_resizeNodes",
40667 value: function _resizeNodes() {
40668 this.canvas.setTransform();
40669 var ctx = this.canvas.getContext();
40670 ctx.save();
40671 ctx.translate(this.body.view.translation.x, this.body.view.translation.y);
40672 ctx.scale(this.body.view.scale, this.body.view.scale);
40673 var nodes = this.body.nodes;
40674 var node; // resize all nodes
40675
40676 for (var nodeId in nodes) {
40677 if (nodes.hasOwnProperty(nodeId)) {
40678 node = nodes[nodeId];
40679 node.resize(ctx);
40680 node.updateBoundingBox(ctx, node.selected);
40681 }
40682 } // restore original scaling and translation
40683
40684
40685 ctx.restore();
40686 }
40687 /**
40688 * Redraw all nodes
40689 *
40690 * @param {CanvasRenderingContext2D} ctx 2D context of a HTML canvas
40691 * @param {boolean} [alwaysShow]
40692 * @private
40693 */
40694
40695 }, {
40696 key: "_drawNodes",
40697 value: function _drawNodes(ctx) {
40698 var alwaysShow = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
40699 var nodes = this.body.nodes;
40700 var nodeIndices = this.body.nodeIndices;
40701 var node;
40702 var selected = [];
40703 var margin = 20;
40704 var topLeft = this.canvas.DOMtoCanvas({
40705 x: -margin,
40706 y: -margin
40707 });
40708 var bottomRight = this.canvas.DOMtoCanvas({
40709 x: this.canvas.frame.canvas.clientWidth + margin,
40710 y: this.canvas.frame.canvas.clientHeight + margin
40711 });
40712 var viewableArea = {
40713 top: topLeft.y,
40714 left: topLeft.x,
40715 bottom: bottomRight.y,
40716 right: bottomRight.x
40717 }; // draw unselected nodes;
40718
40719 for (var i = 0; i < nodeIndices.length; i++) {
40720 node = nodes[nodeIndices[i]]; // set selected nodes aside
40721
40722 if (node.isSelected()) {
40723 selected.push(nodeIndices[i]);
40724 } else {
40725 if (alwaysShow === true) {
40726 node.draw(ctx);
40727 } else if (node.isBoundingBoxOverlappingWith(viewableArea) === true) {
40728 node.draw(ctx);
40729 } else {
40730 node.updateBoundingBox(ctx, node.selected);
40731 }
40732 }
40733 } // draw the selected nodes on top
40734
40735
40736 for (var _i = 0; _i < selected.length; _i++) {
40737 node = nodes[selected[_i]];
40738 node.draw(ctx);
40739 }
40740 }
40741 /**
40742 * Redraw all edges
40743 * @param {CanvasRenderingContext2D} ctx 2D context of a HTML canvas
40744 * @private
40745 */
40746
40747 }, {
40748 key: "_drawEdges",
40749 value: function _drawEdges(ctx) {
40750 var edges = this.body.edges;
40751 var edgeIndices = this.body.edgeIndices;
40752 var edge;
40753
40754 for (var i = 0; i < edgeIndices.length; i++) {
40755 edge = edges[edgeIndices[i]];
40756
40757 if (edge.connected === true) {
40758 edge.draw(ctx);
40759 }
40760 }
40761 }
40762 /**
40763 * Determine if the browser requires a setTimeout or a requestAnimationFrame. This was required because
40764 * some implementations (safari and IE9) did not support requestAnimationFrame
40765 * @private
40766 */
40767
40768 }, {
40769 key: "_determineBrowserMethod",
40770 value: function _determineBrowserMethod() {
40771 if (typeof window !== 'undefined') {
40772 var browserType = navigator.userAgent.toLowerCase();
40773 this.requiresTimeout = false;
40774
40775 if (browserType.indexOf('msie 9.0') != -1) {
40776 // IE 9
40777 this.requiresTimeout = true;
40778 } else if (browserType.indexOf('safari') != -1) {
40779 // safari
40780 if (browserType.indexOf('chrome') <= -1) {
40781 this.requiresTimeout = true;
40782 }
40783 }
40784 } else {
40785 this.requiresTimeout = true;
40786 }
40787 }
40788 }]);
40789
40790 return CanvasRenderer;
40791 }();
40792
40793 var hammerUtil = createCommonjsModule(function (module, exports) {
40794 /**
40795 * Register a touch event, taking place before a gesture
40796 * @param {Hammer} hammer A hammer instance
40797 * @param {function} callback Callback, called as callback(event)
40798 */
40799 exports.onTouch = function (hammer, callback) {
40800 callback.inputHandler = function (event) {
40801 if (event.isFirst) {
40802 callback(event);
40803 }
40804 };
40805
40806 hammer.on('hammer.input', callback.inputHandler);
40807 };
40808 /**
40809 * Register a release event, taking place after a gesture
40810 * @param {Hammer} hammer A hammer instance
40811 * @param {function} callback Callback, called as callback(event)
40812 * @returns {*}
40813 */
40814
40815
40816 exports.onRelease = function (hammer, callback) {
40817 callback.inputHandler = function (event) {
40818 if (event.isFinal) {
40819 callback(event);
40820 }
40821 };
40822
40823 return hammer.on('hammer.input', callback.inputHandler);
40824 };
40825 /**
40826 * Unregister a touch event, taking place before a gesture
40827 * @param {Hammer} hammer A hammer instance
40828 * @param {function} callback Callback, called as callback(event)
40829 */
40830
40831
40832 exports.offTouch = function (hammer, callback) {
40833 hammer.off('hammer.input', callback.inputHandler);
40834 };
40835 /**
40836 * Unregister a release event, taking place before a gesture
40837 * @param {Hammer} hammer A hammer instance
40838 * @param {function} callback Callback, called as callback(event)
40839 */
40840
40841
40842 exports.offRelease = exports.offTouch;
40843 /**
40844 * Hack the PinchRecognizer such that it doesn't prevent default behavior
40845 * for vertical panning.
40846 *
40847 * Yeah ... this is quite a hack ... see https://github.com/hammerjs/hammer.js/issues/932
40848 *
40849 * @param {Hammer.Pinch} pinchRecognizer
40850 * @return {Hammer.Pinch} returns the pinchRecognizer
40851 */
40852
40853 exports.disablePreventDefaultVertically = function (pinchRecognizer) {
40854 var TOUCH_ACTION_PAN_Y = 'pan-y';
40855
40856 pinchRecognizer.getTouchAction = function () {
40857 // default method returns [TOUCH_ACTION_NONE]
40858 return [TOUCH_ACTION_PAN_Y];
40859 };
40860
40861 return pinchRecognizer;
40862 };
40863 });
40864 var hammerUtil_1 = hammerUtil.onTouch;
40865 var hammerUtil_2 = hammerUtil.onRelease;
40866 var hammerUtil_3 = hammerUtil.offTouch;
40867 var hammerUtil_4 = hammerUtil.offRelease;
40868 var hammerUtil_5 = hammerUtil.disablePreventDefaultVertically;
40869
40870 /**
40871 * Create the main frame for the Network.
40872 * This function is executed once when a Network object is created. The frame
40873 * contains a canvas, and this canvas contains all objects like the axis and
40874 * nodes.
40875 */
40876
40877 var Canvas =
40878 /*#__PURE__*/
40879 function () {
40880 /**
40881 * @param {Object} body
40882 */
40883 function Canvas(body) {
40884 _classCallCheck(this, Canvas);
40885
40886 this.body = body;
40887 this.pixelRatio = 1;
40888 this.resizeTimer = undefined;
40889 this.resizeFunction = this._onResize.bind(this);
40890 this.cameraState = {};
40891 this.initialized = false;
40892 this.canvasViewCenter = {};
40893 this.options = {};
40894 this.defaultOptions = {
40895 autoResize: true,
40896 height: '100%',
40897 width: '100%'
40898 };
40899 extend(this.options, this.defaultOptions);
40900 this.bindEventListeners();
40901 }
40902 /**
40903 * Binds event listeners
40904 */
40905
40906
40907 _createClass(Canvas, [{
40908 key: "bindEventListeners",
40909 value: function bindEventListeners() {
40910 var _this = this;
40911
40912 // bind the events
40913 this.body.emitter.once("resize", function (obj) {
40914 if (obj.width !== 0) {
40915 _this.body.view.translation.x = obj.width * 0.5;
40916 }
40917
40918 if (obj.height !== 0) {
40919 _this.body.view.translation.y = obj.height * 0.5;
40920 }
40921 });
40922 this.body.emitter.on("setSize", this.setSize.bind(this));
40923 this.body.emitter.on("destroy", function () {
40924 _this.hammerFrame.destroy();
40925
40926 _this.hammer.destroy();
40927
40928 _this._cleanUp();
40929 });
40930 }
40931 /**
40932 * @param {Object} options
40933 */
40934
40935 }, {
40936 key: "setOptions",
40937 value: function setOptions(options) {
40938 var _this2 = this;
40939
40940 if (options !== undefined) {
40941 var fields = ['width', 'height', 'autoResize'];
40942 selectiveDeepExtend(fields, this.options, options);
40943 }
40944
40945 if (this.options.autoResize === true) {
40946 // automatically adapt to a changing size of the browser.
40947 this._cleanUp();
40948
40949 this.resizeTimer = setInterval(function () {
40950 var changed = _this2.setSize();
40951
40952 if (changed === true) {
40953 _this2.body.emitter.emit("_requestRedraw");
40954 }
40955 }, 1000);
40956 this.resizeFunction = this._onResize.bind(this);
40957 addEventListener(window, 'resize', this.resizeFunction);
40958 }
40959 }
40960 /**
40961 * @private
40962 */
40963
40964 }, {
40965 key: "_cleanUp",
40966 value: function _cleanUp() {
40967 // automatically adapt to a changing size of the browser.
40968 if (this.resizeTimer !== undefined) {
40969 clearInterval(this.resizeTimer);
40970 }
40971
40972 removeEventListener(window, 'resize', this.resizeFunction);
40973 this.resizeFunction = undefined;
40974 }
40975 /**
40976 * @private
40977 */
40978
40979 }, {
40980 key: "_onResize",
40981 value: function _onResize() {
40982 this.setSize();
40983 this.body.emitter.emit("_redraw");
40984 }
40985 /**
40986 * Get and store the cameraState
40987 *
40988 * @param {number} [pixelRatio=this.pixelRatio]
40989 * @private
40990 */
40991
40992 }, {
40993 key: "_getCameraState",
40994 value: function _getCameraState() {
40995 var pixelRatio = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.pixelRatio;
40996
40997 if (this.initialized === true) {
40998 this.cameraState.previousWidth = this.frame.canvas.width / pixelRatio;
40999 this.cameraState.previousHeight = this.frame.canvas.height / pixelRatio;
41000 this.cameraState.scale = this.body.view.scale;
41001 this.cameraState.position = this.DOMtoCanvas({
41002 x: 0.5 * this.frame.canvas.width / pixelRatio,
41003 y: 0.5 * this.frame.canvas.height / pixelRatio
41004 });
41005 }
41006 }
41007 /**
41008 * Set the cameraState
41009 * @private
41010 */
41011
41012 }, {
41013 key: "_setCameraState",
41014 value: function _setCameraState() {
41015 if (this.cameraState.scale !== undefined && this.frame.canvas.clientWidth !== 0 && this.frame.canvas.clientHeight !== 0 && this.pixelRatio !== 0 && this.cameraState.previousWidth > 0) {
41016 var widthRatio = this.frame.canvas.width / this.pixelRatio / this.cameraState.previousWidth;
41017 var heightRatio = this.frame.canvas.height / this.pixelRatio / this.cameraState.previousHeight;
41018 var newScale = this.cameraState.scale;
41019
41020 if (widthRatio != 1 && heightRatio != 1) {
41021 newScale = this.cameraState.scale * 0.5 * (widthRatio + heightRatio);
41022 } else if (widthRatio != 1) {
41023 newScale = this.cameraState.scale * widthRatio;
41024 } else if (heightRatio != 1) {
41025 newScale = this.cameraState.scale * heightRatio;
41026 }
41027
41028 this.body.view.scale = newScale; // this comes from the view module.
41029
41030 var currentViewCenter = this.DOMtoCanvas({
41031 x: 0.5 * this.frame.canvas.clientWidth,
41032 y: 0.5 * this.frame.canvas.clientHeight
41033 });
41034 var distanceFromCenter = {
41035 // offset from view, distance view has to change by these x and y to center the node
41036 x: currentViewCenter.x - this.cameraState.position.x,
41037 y: currentViewCenter.y - this.cameraState.position.y
41038 };
41039 this.body.view.translation.x += distanceFromCenter.x * this.body.view.scale;
41040 this.body.view.translation.y += distanceFromCenter.y * this.body.view.scale;
41041 }
41042 }
41043 /**
41044 *
41045 * @param {number|string} value
41046 * @returns {string}
41047 * @private
41048 */
41049
41050 }, {
41051 key: "_prepareValue",
41052 value: function _prepareValue(value) {
41053 if (typeof value === 'number') {
41054 return value + 'px';
41055 } else if (typeof value === 'string') {
41056 if (value.indexOf('%') !== -1 || value.indexOf('px') !== -1) {
41057 return value;
41058 } else if (value.indexOf('%') === -1) {
41059 return value + 'px';
41060 }
41061 }
41062
41063 throw new Error('Could not use the value supplied for width or height:' + value);
41064 }
41065 /**
41066 * Create the HTML
41067 */
41068
41069 }, {
41070 key: "_create",
41071 value: function _create() {
41072 // remove all elements from the container element.
41073 while (this.body.container.hasChildNodes()) {
41074 this.body.container.removeChild(this.body.container.firstChild);
41075 }
41076
41077 this.frame = document.createElement('div');
41078 this.frame.className = 'vis-network';
41079 this.frame.style.position = 'relative';
41080 this.frame.style.overflow = 'hidden';
41081 this.frame.tabIndex = 900; // tab index is required for keycharm to bind keystrokes to the div instead of the window
41082 //////////////////////////////////////////////////////////////////
41083
41084 this.frame.canvas = document.createElement("canvas");
41085 this.frame.canvas.style.position = 'relative';
41086 this.frame.appendChild(this.frame.canvas);
41087
41088 if (!this.frame.canvas.getContext) {
41089 var noCanvas = document.createElement('DIV');
41090 noCanvas.style.color = 'red';
41091 noCanvas.style.fontWeight = 'bold';
41092 noCanvas.style.padding = '10px';
41093 noCanvas.innerHTML = 'Error: your browser does not support HTML canvas';
41094 this.frame.canvas.appendChild(noCanvas);
41095 } else {
41096 this._setPixelRatio();
41097
41098 this.setTransform();
41099 } // add the frame to the container element
41100
41101
41102 this.body.container.appendChild(this.frame);
41103 this.body.view.scale = 1;
41104 this.body.view.translation = {
41105 x: 0.5 * this.frame.canvas.clientWidth,
41106 y: 0.5 * this.frame.canvas.clientHeight
41107 };
41108
41109 this._bindHammer();
41110 }
41111 /**
41112 * This function binds hammer, it can be repeated over and over due to the uniqueness check.
41113 * @private
41114 */
41115
41116 }, {
41117 key: "_bindHammer",
41118 value: function _bindHammer() {
41119 var _this3 = this;
41120
41121 if (this.hammer !== undefined) {
41122 this.hammer.destroy();
41123 }
41124
41125 this.drag = {};
41126 this.pinch = {}; // init hammer
41127
41128 this.hammer = new hammer(this.frame.canvas);
41129 this.hammer.get('pinch').set({
41130 enable: true
41131 }); // enable to get better response, todo: test on mobile.
41132
41133 this.hammer.get('pan').set({
41134 threshold: 5,
41135 direction: hammer.DIRECTION_ALL
41136 });
41137 hammerUtil.onTouch(this.hammer, function (event) {
41138 _this3.body.eventListeners.onTouch(event);
41139 });
41140 this.hammer.on('tap', function (event) {
41141 _this3.body.eventListeners.onTap(event);
41142 });
41143 this.hammer.on('doubletap', function (event) {
41144 _this3.body.eventListeners.onDoubleTap(event);
41145 });
41146 this.hammer.on('press', function (event) {
41147 _this3.body.eventListeners.onHold(event);
41148 });
41149 this.hammer.on('panstart', function (event) {
41150 _this3.body.eventListeners.onDragStart(event);
41151 });
41152 this.hammer.on('panmove', function (event) {
41153 _this3.body.eventListeners.onDrag(event);
41154 });
41155 this.hammer.on('panend', function (event) {
41156 _this3.body.eventListeners.onDragEnd(event);
41157 });
41158 this.hammer.on('pinch', function (event) {
41159 _this3.body.eventListeners.onPinch(event);
41160 }); // TODO: neatly cleanup these handlers when re-creating the Canvas, IF these are done with hammer, event.stopPropagation will not work?
41161
41162 this.frame.canvas.addEventListener('wheel', function (event) {
41163 _this3.body.eventListeners.onMouseWheel(event);
41164 });
41165 this.frame.canvas.addEventListener('mousemove', function (event) {
41166 _this3.body.eventListeners.onMouseMove(event);
41167 });
41168 this.frame.canvas.addEventListener('contextmenu', function (event) {
41169 _this3.body.eventListeners.onContext(event);
41170 });
41171 this.hammerFrame = new hammer(this.frame);
41172 hammerUtil.onRelease(this.hammerFrame, function (event) {
41173 _this3.body.eventListeners.onRelease(event);
41174 });
41175 }
41176 /**
41177 * Set a new size for the network
41178 * @param {string} width Width in pixels or percentage (for example '800px'
41179 * or '50%')
41180 * @param {string} height Height in pixels or percentage (for example '400px'
41181 * or '30%')
41182 * @returns {boolean}
41183 */
41184
41185 }, {
41186 key: "setSize",
41187 value: function setSize() {
41188 var width = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.options.width;
41189 var height = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.options.height;
41190 width = this._prepareValue(width);
41191 height = this._prepareValue(height);
41192 var emitEvent = false;
41193 var oldWidth = this.frame.canvas.width;
41194 var oldHeight = this.frame.canvas.height; // update the pixel ratio
41195 //
41196 // NOTE: Comment in following is rather inconsistent; this is the ONLY place in the code
41197 // where it is assumed that the pixel ratio could change at runtime.
41198 // The only way I can think of this happening is a rotating screen or tablet; but then
41199 // there should be a mechanism for reloading the data (TODO: check if this is present).
41200 //
41201 // If the assumption is true (i.e. pixel ratio can change at runtime), then *all* usage
41202 // of pixel ratio must be overhauled for this.
41203 //
41204 // For the time being, I will humor the assumption here, and in the rest of the code assume it is
41205 // constant.
41206
41207 var previousRatio = this.pixelRatio; // we cache this because the camera state storage needs the old value
41208
41209 this._setPixelRatio();
41210
41211 if (width != this.options.width || height != this.options.height || this.frame.style.width != width || this.frame.style.height != height) {
41212 this._getCameraState(previousRatio);
41213
41214 this.frame.style.width = width;
41215 this.frame.style.height = height;
41216 this.frame.canvas.style.width = '100%';
41217 this.frame.canvas.style.height = '100%';
41218 this.frame.canvas.width = Math.round(this.frame.canvas.clientWidth * this.pixelRatio);
41219 this.frame.canvas.height = Math.round(this.frame.canvas.clientHeight * this.pixelRatio);
41220 this.options.width = width;
41221 this.options.height = height;
41222 this.canvasViewCenter = {
41223 x: 0.5 * this.frame.clientWidth,
41224 y: 0.5 * this.frame.clientHeight
41225 };
41226 emitEvent = true;
41227 } else {
41228 // this would adapt the width of the canvas to the width from 100% if and only if
41229 // there is a change.
41230 var newWidth = Math.round(this.frame.canvas.clientWidth * this.pixelRatio);
41231 var newHeight = Math.round(this.frame.canvas.clientHeight * this.pixelRatio); // store the camera if there is a change in size.
41232
41233 if (this.frame.canvas.width !== newWidth || this.frame.canvas.height !== newHeight) {
41234 this._getCameraState(previousRatio);
41235 }
41236
41237 if (this.frame.canvas.width !== newWidth) {
41238 this.frame.canvas.width = newWidth;
41239 emitEvent = true;
41240 }
41241
41242 if (this.frame.canvas.height !== newHeight) {
41243 this.frame.canvas.height = newHeight;
41244 emitEvent = true;
41245 }
41246 }
41247
41248 if (emitEvent === true) {
41249 this.body.emitter.emit('resize', {
41250 width: Math.round(this.frame.canvas.width / this.pixelRatio),
41251 height: Math.round(this.frame.canvas.height / this.pixelRatio),
41252 oldWidth: Math.round(oldWidth / this.pixelRatio),
41253 oldHeight: Math.round(oldHeight / this.pixelRatio)
41254 }); // restore the camera on change.
41255
41256 this._setCameraState();
41257 } // set initialized so the get and set camera will work from now on.
41258
41259
41260 this.initialized = true;
41261 return emitEvent;
41262 }
41263 /**
41264 *
41265 * @returns {CanvasRenderingContext2D}
41266 */
41267
41268 }, {
41269 key: "getContext",
41270 value: function getContext() {
41271 return this.frame.canvas.getContext("2d");
41272 }
41273 /**
41274 * Determine the pixel ratio for various browsers.
41275 *
41276 * @returns {number}
41277 * @private
41278 */
41279
41280 }, {
41281 key: "_determinePixelRatio",
41282 value: function _determinePixelRatio() {
41283 var ctx = this.getContext();
41284
41285 if (ctx === undefined) {
41286 throw new Error("Could not get canvax context");
41287 }
41288
41289 var numerator = 1;
41290
41291 if (typeof window !== 'undefined') {
41292 // (window !== undefined) doesn't work here!
41293 // Protection during unit tests, where 'window' can be missing
41294 numerator = window.devicePixelRatio || 1;
41295 }
41296
41297 var denominator = ctx.webkitBackingStorePixelRatio || ctx.mozBackingStorePixelRatio || ctx.msBackingStorePixelRatio || ctx.oBackingStorePixelRatio || ctx.backingStorePixelRatio || 1;
41298 return numerator / denominator;
41299 }
41300 /**
41301 * Lazy determination of pixel ratio.
41302 *
41303 * @private
41304 */
41305
41306 }, {
41307 key: "_setPixelRatio",
41308 value: function _setPixelRatio() {
41309 this.pixelRatio = this._determinePixelRatio();
41310 }
41311 /**
41312 * Set the transform in the contained context, based on its pixelRatio
41313 */
41314
41315 }, {
41316 key: "setTransform",
41317 value: function setTransform() {
41318 var ctx = this.getContext();
41319
41320 if (ctx === undefined) {
41321 throw new Error("Could not get canvax context");
41322 }
41323
41324 ctx.setTransform(this.pixelRatio, 0, 0, this.pixelRatio, 0, 0);
41325 }
41326 /**
41327 * Convert the X coordinate in DOM-space (coordinate point in browser relative to the container div) to
41328 * the X coordinate in canvas-space (the simulation sandbox, which the camera looks upon)
41329 * @param {number} x
41330 * @returns {number}
41331 * @private
41332 */
41333
41334 }, {
41335 key: "_XconvertDOMtoCanvas",
41336 value: function _XconvertDOMtoCanvas(x) {
41337 return (x - this.body.view.translation.x) / this.body.view.scale;
41338 }
41339 /**
41340 * Convert the X coordinate in canvas-space (the simulation sandbox, which the camera looks upon) to
41341 * the X coordinate in DOM-space (coordinate point in browser relative to the container div)
41342 * @param {number} x
41343 * @returns {number}
41344 * @private
41345 */
41346
41347 }, {
41348 key: "_XconvertCanvasToDOM",
41349 value: function _XconvertCanvasToDOM(x) {
41350 return x * this.body.view.scale + this.body.view.translation.x;
41351 }
41352 /**
41353 * Convert the Y coordinate in DOM-space (coordinate point in browser relative to the container div) to
41354 * the Y coordinate in canvas-space (the simulation sandbox, which the camera looks upon)
41355 * @param {number} y
41356 * @returns {number}
41357 * @private
41358 */
41359
41360 }, {
41361 key: "_YconvertDOMtoCanvas",
41362 value: function _YconvertDOMtoCanvas(y) {
41363 return (y - this.body.view.translation.y) / this.body.view.scale;
41364 }
41365 /**
41366 * Convert the Y coordinate in canvas-space (the simulation sandbox, which the camera looks upon) to
41367 * the Y coordinate in DOM-space (coordinate point in browser relative to the container div)
41368 * @param {number} y
41369 * @returns {number}
41370 * @private
41371 */
41372
41373 }, {
41374 key: "_YconvertCanvasToDOM",
41375 value: function _YconvertCanvasToDOM(y) {
41376 return y * this.body.view.scale + this.body.view.translation.y;
41377 }
41378 /**
41379 * @param {point} pos
41380 * @returns {point}
41381 */
41382
41383 }, {
41384 key: "canvasToDOM",
41385 value: function canvasToDOM(pos) {
41386 return {
41387 x: this._XconvertCanvasToDOM(pos.x),
41388 y: this._YconvertCanvasToDOM(pos.y)
41389 };
41390 }
41391 /**
41392 *
41393 * @param {point} pos
41394 * @returns {point}
41395 */
41396
41397 }, {
41398 key: "DOMtoCanvas",
41399 value: function DOMtoCanvas(pos) {
41400 return {
41401 x: this._XconvertDOMtoCanvas(pos.x),
41402 y: this._YconvertDOMtoCanvas(pos.y)
41403 };
41404 }
41405 }]);
41406
41407 return Canvas;
41408 }();
41409
41410 var globalIsFinite = global_1.isFinite; // `Number.isFinite` method
41411 // https://tc39.github.io/ecma262/#sec-number.isfinite
41412
41413 var numberIsFinite = Number.isFinite || function isFinite(it) {
41414 return typeof it == 'number' && globalIsFinite(it);
41415 };
41416
41417 // https://tc39.github.io/ecma262/#sec-number.isfinite
41418
41419 _export({
41420 target: 'Number',
41421 stat: true
41422 }, {
41423 isFinite: numberIsFinite
41424 });
41425
41426 /**
41427 * The view
41428 */
41429
41430 var View =
41431 /*#__PURE__*/
41432 function () {
41433 /**
41434 * @param {Object} body
41435 * @param {Canvas} canvas
41436 */
41437 function View(body, canvas) {
41438 var _this = this;
41439
41440 _classCallCheck(this, View);
41441
41442 this.body = body;
41443 this.canvas = canvas;
41444 this.animationSpeed = 1 / this.renderRefreshRate;
41445 this.animationEasingFunction = "easeInOutQuint";
41446 this.easingTime = 0;
41447 this.sourceScale = 0;
41448 this.targetScale = 0;
41449 this.sourceTranslation = 0;
41450 this.targetTranslation = 0;
41451 this.lockedOnNodeId = undefined;
41452 this.lockedOnNodeOffset = undefined;
41453 this.touchTime = 0;
41454 this.viewFunction = undefined;
41455 this.body.emitter.on("fit", this.fit.bind(this));
41456 this.body.emitter.on("animationFinished", function () {
41457 _this.body.emitter.emit("_stopRendering");
41458 });
41459 this.body.emitter.on("unlockNode", this.releaseNode.bind(this));
41460 }
41461 /**
41462 *
41463 * @param {Object} [options={}]
41464 */
41465
41466
41467 _createClass(View, [{
41468 key: "setOptions",
41469 value: function setOptions() {
41470 var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
41471 this.options = options;
41472 }
41473 /**
41474 * This function zooms out to fit all data on screen based on amount of nodes
41475 * @param {Object} [options={{nodes=Array}}]
41476 * @param {boolean} [initialZoom=false] | zoom based on fitted formula or range, true = fitted, default = false;
41477 */
41478
41479 }, {
41480 key: "fit",
41481 value: function fit() {
41482 var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {
41483 nodes: []
41484 };
41485 var initialZoom = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
41486 var range;
41487 var zoomLevel;
41488 options = Object.assign({}, options);
41489
41490 if (options.nodes === undefined || options.nodes.length === 0) {
41491 options.nodes = this.body.nodeIndices;
41492 }
41493
41494 if (initialZoom === true) {
41495 // check if more than half of the nodes have a predefined position. If so, we use the range, not the approximation.
41496 var positionDefined = 0;
41497
41498 for (var nodeId in this.body.nodes) {
41499 if (this.body.nodes.hasOwnProperty(nodeId)) {
41500 var node = this.body.nodes[nodeId];
41501
41502 if (node.predefinedPosition === true) {
41503 positionDefined += 1;
41504 }
41505 }
41506 }
41507
41508 if (positionDefined > 0.5 * this.body.nodeIndices.length) {
41509 this.fit(options, false);
41510 return;
41511 }
41512
41513 range = NetworkUtil.getRange(this.body.nodes, options.nodes);
41514 var numberOfNodes = this.body.nodeIndices.length;
41515 zoomLevel = 12.662 / (numberOfNodes + 7.4147) + 0.0964822; // this is obtained from fitting a dataset from 5 points with scale levels that looked good.
41516 // correct for larger canvasses.
41517
41518 var factor = Math.min(this.canvas.frame.canvas.clientWidth / 600, this.canvas.frame.canvas.clientHeight / 600);
41519 zoomLevel *= factor;
41520 } else {
41521 this.body.emitter.emit("_resizeNodes");
41522 range = NetworkUtil.getRange(this.body.nodes, options.nodes);
41523 var xDistance = Math.abs(range.maxX - range.minX) * 1.1;
41524 var yDistance = Math.abs(range.maxY - range.minY) * 1.1;
41525 var xZoomLevel = this.canvas.frame.canvas.clientWidth / xDistance;
41526 var yZoomLevel = this.canvas.frame.canvas.clientHeight / yDistance;
41527 zoomLevel = xZoomLevel <= yZoomLevel ? xZoomLevel : yZoomLevel;
41528 }
41529
41530 if (zoomLevel > 1.0) {
41531 zoomLevel = 1.0;
41532 } else if (zoomLevel === 0) {
41533 zoomLevel = 1.0;
41534 }
41535
41536 var center = NetworkUtil.findCenter(range);
41537 var animationOptions = {
41538 position: center,
41539 scale: zoomLevel,
41540 animation: options.animation
41541 };
41542 this.moveTo(animationOptions);
41543 } // animation
41544
41545 /**
41546 * Center a node in view.
41547 *
41548 * @param {number} nodeId
41549 * @param {number} [options]
41550 */
41551
41552 }, {
41553 key: "focus",
41554 value: function focus(nodeId) {
41555 var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
41556
41557 if (this.body.nodes[nodeId] !== undefined) {
41558 var nodePosition = {
41559 x: this.body.nodes[nodeId].x,
41560 y: this.body.nodes[nodeId].y
41561 };
41562 options.position = nodePosition;
41563 options.lockedOnNode = nodeId;
41564 this.moveTo(options);
41565 } else {
41566 console.log("Node: " + nodeId + " cannot be found.");
41567 }
41568 }
41569 /**
41570 *
41571 * @param {Object} options | options.offset = {x:number, y:number} // offset from the center in DOM pixels
41572 * | options.scale = number // scale to move to
41573 * | options.position = {x:number, y:number} // position to move to
41574 * | options.animation = {duration:number, easingFunction:String} || Boolean // position to move to
41575 */
41576
41577 }, {
41578 key: "moveTo",
41579 value: function moveTo(options) {
41580 if (options === undefined) {
41581 options = {};
41582 return;
41583 }
41584
41585 if (options.offset != null) {
41586 if (options.offset.x != null) {
41587 // Coerce and verify that x is valid.
41588 options.offset.x = +options.offset.x;
41589
41590 if (!Number.isFinite(options.offset.x)) {
41591 throw new TypeError('The option "offset.x" has to be a finite number.');
41592 }
41593 } else {
41594 options.offset.x = 0;
41595 }
41596
41597 if (options.offset.y != null) {
41598 // Coerce and verify that y is valid.
41599 options.offset.y = +options.offset.y;
41600
41601 if (!Number.isFinite(options.offset.y)) {
41602 throw new TypeError('The option "offset.y" has to be a finite number.');
41603 }
41604 } else {
41605 options.offset.x = 0;
41606 }
41607 } else {
41608 options.offset = {
41609 x: 0,
41610 y: 0
41611 };
41612 }
41613
41614 if (options.position != null) {
41615 if (options.position.x != null) {
41616 // Coerce and verify that x is valid.
41617 options.position.x = +options.position.x;
41618
41619 if (!Number.isFinite(options.position.x)) {
41620 throw new TypeError('The option "position.x" has to be a finite number.');
41621 }
41622 } else {
41623 options.position.x = 0;
41624 }
41625
41626 if (options.position.y != null) {
41627 // Coerce and verify that y is valid.
41628 options.position.y = +options.position.y;
41629
41630 if (!Number.isFinite(options.position.y)) {
41631 throw new TypeError('The option "position.y" has to be a finite number.');
41632 }
41633 } else {
41634 options.position.x = 0;
41635 }
41636 } else {
41637 options.position = this.getViewPosition();
41638 }
41639
41640 if (options.scale != null) {
41641 // Coerce and verify that the scale is valid.
41642 options.scale = +options.scale;
41643
41644 if (!(options.scale > 0)) {
41645 throw new TypeError('The option "scale" has to be a number greater than zero.');
41646 }
41647 } else {
41648 options.scale = this.body.view.scale;
41649 }
41650
41651 if (options.animation === undefined) {
41652 options.animation = {
41653 duration: 0
41654 };
41655 }
41656
41657 if (options.animation === false) {
41658 options.animation = {
41659 duration: 0
41660 };
41661 }
41662
41663 if (options.animation === true) {
41664 options.animation = {};
41665 }
41666
41667 if (options.animation.duration === undefined) {
41668 options.animation.duration = 1000;
41669 } // default duration
41670
41671
41672 if (options.animation.easingFunction === undefined) {
41673 options.animation.easingFunction = "easeInOutQuad";
41674 } // default easing function
41675
41676
41677 this.animateView(options);
41678 }
41679 /**
41680 *
41681 * @param {Object} options | options.offset = {x:number, y:number} // offset from the center in DOM pixels
41682 * | options.time = number // animation time in milliseconds
41683 * | options.scale = number // scale to animate to
41684 * | options.position = {x:number, y:number} // position to animate to
41685 * | options.easingFunction = String // linear, easeInQuad, easeOutQuad, easeInOutQuad,
41686 * // easeInCubic, easeOutCubic, easeInOutCubic,
41687 * // easeInQuart, easeOutQuart, easeInOutQuart,
41688 * // easeInQuint, easeOutQuint, easeInOutQuint
41689 */
41690
41691 }, {
41692 key: "animateView",
41693 value: function animateView(options) {
41694 if (options === undefined) {
41695 return;
41696 }
41697
41698 this.animationEasingFunction = options.animation.easingFunction; // release if something focussed on the node
41699
41700 this.releaseNode();
41701
41702 if (options.locked === true) {
41703 this.lockedOnNodeId = options.lockedOnNode;
41704 this.lockedOnNodeOffset = options.offset;
41705 } // forcefully complete the old animation if it was still running
41706
41707
41708 if (this.easingTime != 0) {
41709 this._transitionRedraw(true); // by setting easingtime to 1, we finish the animation.
41710
41711 }
41712
41713 this.sourceScale = this.body.view.scale;
41714 this.sourceTranslation = this.body.view.translation;
41715 this.targetScale = options.scale; // set the scale so the viewCenter is based on the correct zoom level. This is overridden in the transitionRedraw
41716 // but at least then we'll have the target transition
41717
41718 this.body.view.scale = this.targetScale;
41719 var viewCenter = this.canvas.DOMtoCanvas({
41720 x: 0.5 * this.canvas.frame.canvas.clientWidth,
41721 y: 0.5 * this.canvas.frame.canvas.clientHeight
41722 });
41723 var distanceFromCenter = {
41724 // offset from view, distance view has to change by these x and y to center the node
41725 x: viewCenter.x - options.position.x,
41726 y: viewCenter.y - options.position.y
41727 };
41728 this.targetTranslation = {
41729 x: this.sourceTranslation.x + distanceFromCenter.x * this.targetScale + options.offset.x,
41730 y: this.sourceTranslation.y + distanceFromCenter.y * this.targetScale + options.offset.y
41731 }; // if the time is set to 0, don't do an animation
41732
41733 if (options.animation.duration === 0) {
41734 if (this.lockedOnNodeId != undefined) {
41735 this.viewFunction = this._lockedRedraw.bind(this);
41736 this.body.emitter.on("initRedraw", this.viewFunction);
41737 } else {
41738 this.body.view.scale = this.targetScale;
41739 this.body.view.translation = this.targetTranslation;
41740 this.body.emitter.emit("_requestRedraw");
41741 }
41742 } else {
41743 this.animationSpeed = 1 / (60 * options.animation.duration * 0.001) || 1 / 60; // 60 for 60 seconds, 0.001 for milli's
41744
41745 this.animationEasingFunction = options.animation.easingFunction;
41746 this.viewFunction = this._transitionRedraw.bind(this);
41747 this.body.emitter.on("initRedraw", this.viewFunction);
41748 this.body.emitter.emit("_startRendering");
41749 }
41750 }
41751 /**
41752 * used to animate smoothly by hijacking the redraw function.
41753 * @private
41754 */
41755
41756 }, {
41757 key: "_lockedRedraw",
41758 value: function _lockedRedraw() {
41759 var nodePosition = {
41760 x: this.body.nodes[this.lockedOnNodeId].x,
41761 y: this.body.nodes[this.lockedOnNodeId].y
41762 };
41763 var viewCenter = this.canvas.DOMtoCanvas({
41764 x: 0.5 * this.canvas.frame.canvas.clientWidth,
41765 y: 0.5 * this.canvas.frame.canvas.clientHeight
41766 });
41767 var distanceFromCenter = {
41768 // offset from view, distance view has to change by these x and y to center the node
41769 x: viewCenter.x - nodePosition.x,
41770 y: viewCenter.y - nodePosition.y
41771 };
41772 var sourceTranslation = this.body.view.translation;
41773 var targetTranslation = {
41774 x: sourceTranslation.x + distanceFromCenter.x * this.body.view.scale + this.lockedOnNodeOffset.x,
41775 y: sourceTranslation.y + distanceFromCenter.y * this.body.view.scale + this.lockedOnNodeOffset.y
41776 };
41777 this.body.view.translation = targetTranslation;
41778 }
41779 /**
41780 * Resets state of a locked on Node
41781 */
41782
41783 }, {
41784 key: "releaseNode",
41785 value: function releaseNode() {
41786 if (this.lockedOnNodeId !== undefined && this.viewFunction !== undefined) {
41787 this.body.emitter.off("initRedraw", this.viewFunction);
41788 this.lockedOnNodeId = undefined;
41789 this.lockedOnNodeOffset = undefined;
41790 }
41791 }
41792 /**
41793 * @param {boolean} [finished=false]
41794 * @private
41795 */
41796
41797 }, {
41798 key: "_transitionRedraw",
41799 value: function _transitionRedraw() {
41800 var finished = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
41801 this.easingTime += this.animationSpeed;
41802 this.easingTime = finished === true ? 1.0 : this.easingTime;
41803 var progress = easingFunctions[this.animationEasingFunction](this.easingTime);
41804 this.body.view.scale = this.sourceScale + (this.targetScale - this.sourceScale) * progress;
41805 this.body.view.translation = {
41806 x: this.sourceTranslation.x + (this.targetTranslation.x - this.sourceTranslation.x) * progress,
41807 y: this.sourceTranslation.y + (this.targetTranslation.y - this.sourceTranslation.y) * progress
41808 }; // cleanup
41809
41810 if (this.easingTime >= 1.0) {
41811 this.body.emitter.off("initRedraw", this.viewFunction);
41812 this.easingTime = 0;
41813
41814 if (this.lockedOnNodeId != undefined) {
41815 this.viewFunction = this._lockedRedraw.bind(this);
41816 this.body.emitter.on("initRedraw", this.viewFunction);
41817 }
41818
41819 this.body.emitter.emit("animationFinished");
41820 }
41821 }
41822 /**
41823 *
41824 * @returns {number}
41825 */
41826
41827 }, {
41828 key: "getScale",
41829 value: function getScale() {
41830 return this.body.view.scale;
41831 }
41832 /**
41833 *
41834 * @returns {{x: number, y: number}}
41835 */
41836
41837 }, {
41838 key: "getViewPosition",
41839 value: function getViewPosition() {
41840 return this.canvas.DOMtoCanvas({
41841 x: 0.5 * this.canvas.frame.canvas.clientWidth,
41842 y: 0.5 * this.canvas.frame.canvas.clientHeight
41843 });
41844 }
41845 }]);
41846
41847 return View;
41848 }();
41849
41850 /**
41851 * Navigation Handler
41852 */
41853
41854 var NavigationHandler =
41855 /*#__PURE__*/
41856 function () {
41857 /**
41858 * @param {Object} body
41859 * @param {Canvas} canvas
41860 */
41861 function NavigationHandler(body, canvas) {
41862 var _this = this;
41863
41864 _classCallCheck(this, NavigationHandler);
41865
41866 this.body = body;
41867 this.canvas = canvas;
41868 this.iconsCreated = false;
41869 this.navigationHammers = [];
41870 this.boundFunctions = {};
41871 this.touchTime = 0;
41872 this.activated = false;
41873 this.body.emitter.on("activate", function () {
41874 _this.activated = true;
41875
41876 _this.configureKeyboardBindings();
41877 });
41878 this.body.emitter.on("deactivate", function () {
41879 _this.activated = false;
41880
41881 _this.configureKeyboardBindings();
41882 });
41883 this.body.emitter.on("destroy", function () {
41884 if (_this.keycharm !== undefined) {
41885 _this.keycharm.destroy();
41886 }
41887 });
41888 this.options = {};
41889 }
41890 /**
41891 *
41892 * @param {Object} options
41893 */
41894
41895
41896 _createClass(NavigationHandler, [{
41897 key: "setOptions",
41898 value: function setOptions(options) {
41899 if (options !== undefined) {
41900 this.options = options;
41901 this.create();
41902 }
41903 }
41904 /**
41905 * Creates or refreshes navigation and sets key bindings
41906 */
41907
41908 }, {
41909 key: "create",
41910 value: function create() {
41911 if (this.options.navigationButtons === true) {
41912 if (this.iconsCreated === false) {
41913 this.loadNavigationElements();
41914 }
41915 } else if (this.iconsCreated === true) {
41916 this.cleanNavigation();
41917 }
41918
41919 this.configureKeyboardBindings();
41920 }
41921 /**
41922 * Cleans up previous navigation items
41923 */
41924
41925 }, {
41926 key: "cleanNavigation",
41927 value: function cleanNavigation() {
41928 // clean hammer bindings
41929 if (this.navigationHammers.length != 0) {
41930 for (var i = 0; i < this.navigationHammers.length; i++) {
41931 this.navigationHammers[i].destroy();
41932 }
41933
41934 this.navigationHammers = [];
41935 } // clean up previous navigation items
41936
41937
41938 if (this.navigationDOM && this.navigationDOM['wrapper'] && this.navigationDOM['wrapper'].parentNode) {
41939 this.navigationDOM['wrapper'].parentNode.removeChild(this.navigationDOM['wrapper']);
41940 }
41941
41942 this.iconsCreated = false;
41943 }
41944 /**
41945 * Creation of the navigation controls nodes. They are drawn over the rest of the nodes and are not affected by scale and translation
41946 * they have a triggerFunction which is called on click. If the position of the navigation controls is dependent
41947 * on this.frame.canvas.clientWidth or this.frame.canvas.clientHeight, we flag horizontalAlignLeft and verticalAlignTop false.
41948 * This means that the location will be corrected by the _relocateNavigation function on a size change of the canvas.
41949 *
41950 * @private
41951 */
41952
41953 }, {
41954 key: "loadNavigationElements",
41955 value: function loadNavigationElements() {
41956 var _this2 = this;
41957
41958 this.cleanNavigation();
41959 this.navigationDOM = {};
41960 var navigationDivs = ['up', 'down', 'left', 'right', 'zoomIn', 'zoomOut', 'zoomExtends'];
41961 var navigationDivActions = ['_moveUp', '_moveDown', '_moveLeft', '_moveRight', '_zoomIn', '_zoomOut', '_fit'];
41962 this.navigationDOM['wrapper'] = document.createElement('div');
41963 this.navigationDOM['wrapper'].className = 'vis-navigation';
41964 this.canvas.frame.appendChild(this.navigationDOM['wrapper']);
41965
41966 for (var i = 0; i < navigationDivs.length; i++) {
41967 this.navigationDOM[navigationDivs[i]] = document.createElement('div');
41968 this.navigationDOM[navigationDivs[i]].className = 'vis-button vis-' + navigationDivs[i];
41969 this.navigationDOM['wrapper'].appendChild(this.navigationDOM[navigationDivs[i]]);
41970 var hammer$1 = new hammer(this.navigationDOM[navigationDivs[i]]);
41971
41972 if (navigationDivActions[i] === "_fit") {
41973 hammerUtil.onTouch(hammer$1, this._fit.bind(this));
41974 } else {
41975 hammerUtil.onTouch(hammer$1, this.bindToRedraw.bind(this, navigationDivActions[i]));
41976 }
41977
41978 this.navigationHammers.push(hammer$1);
41979 } // use a hammer for the release so we do not require the one used in the rest of the network
41980 // the one the rest uses can be overloaded by the manipulation system.
41981
41982
41983 var hammerFrame = new hammer(this.canvas.frame);
41984 hammerUtil.onRelease(hammerFrame, function () {
41985 _this2._stopMovement();
41986 });
41987 this.navigationHammers.push(hammerFrame);
41988 this.iconsCreated = true;
41989 }
41990 /**
41991 *
41992 * @param {string} action
41993 */
41994
41995 }, {
41996 key: "bindToRedraw",
41997 value: function bindToRedraw(action) {
41998 if (this.boundFunctions[action] === undefined) {
41999 this.boundFunctions[action] = this[action].bind(this);
42000 this.body.emitter.on("initRedraw", this.boundFunctions[action]);
42001 this.body.emitter.emit("_startRendering");
42002 }
42003 }
42004 /**
42005 *
42006 * @param {string} action
42007 */
42008
42009 }, {
42010 key: "unbindFromRedraw",
42011 value: function unbindFromRedraw(action) {
42012 if (this.boundFunctions[action] !== undefined) {
42013 this.body.emitter.off("initRedraw", this.boundFunctions[action]);
42014 this.body.emitter.emit("_stopRendering");
42015 delete this.boundFunctions[action];
42016 }
42017 }
42018 /**
42019 * this stops all movement induced by the navigation buttons
42020 *
42021 * @private
42022 */
42023
42024 }, {
42025 key: "_fit",
42026 value: function _fit() {
42027 if (new Date().valueOf() - this.touchTime > 700) {
42028 // TODO: fix ugly hack to avoid hammer's double fireing of event (because we use release?)
42029 this.body.emitter.emit("fit", {
42030 duration: 700
42031 });
42032 this.touchTime = new Date().valueOf();
42033 }
42034 }
42035 /**
42036 * this stops all movement induced by the navigation buttons
42037 *
42038 * @private
42039 */
42040
42041 }, {
42042 key: "_stopMovement",
42043 value: function _stopMovement() {
42044 for (var boundAction in this.boundFunctions) {
42045 if (this.boundFunctions.hasOwnProperty(boundAction)) {
42046 this.body.emitter.off("initRedraw", this.boundFunctions[boundAction]);
42047 this.body.emitter.emit("_stopRendering");
42048 }
42049 }
42050
42051 this.boundFunctions = {};
42052 }
42053 /**
42054 *
42055 * @private
42056 */
42057
42058 }, {
42059 key: "_moveUp",
42060 value: function _moveUp() {
42061 this.body.view.translation.y += this.options.keyboard.speed.y;
42062 }
42063 /**
42064 *
42065 * @private
42066 */
42067
42068 }, {
42069 key: "_moveDown",
42070 value: function _moveDown() {
42071 this.body.view.translation.y -= this.options.keyboard.speed.y;
42072 }
42073 /**
42074 *
42075 * @private
42076 */
42077
42078 }, {
42079 key: "_moveLeft",
42080 value: function _moveLeft() {
42081 this.body.view.translation.x += this.options.keyboard.speed.x;
42082 }
42083 /**
42084 *
42085 * @private
42086 */
42087
42088 }, {
42089 key: "_moveRight",
42090 value: function _moveRight() {
42091 this.body.view.translation.x -= this.options.keyboard.speed.x;
42092 }
42093 /**
42094 *
42095 * @private
42096 */
42097
42098 }, {
42099 key: "_zoomIn",
42100 value: function _zoomIn() {
42101 var scaleOld = this.body.view.scale;
42102 var scale = this.body.view.scale * (1 + this.options.keyboard.speed.zoom);
42103 var translation = this.body.view.translation;
42104 var scaleFrac = scale / scaleOld;
42105 var tx = (1 - scaleFrac) * this.canvas.canvasViewCenter.x + translation.x * scaleFrac;
42106 var ty = (1 - scaleFrac) * this.canvas.canvasViewCenter.y + translation.y * scaleFrac;
42107 this.body.view.scale = scale;
42108 this.body.view.translation = {
42109 x: tx,
42110 y: ty
42111 };
42112 this.body.emitter.emit('zoom', {
42113 direction: '+',
42114 scale: this.body.view.scale,
42115 pointer: null
42116 });
42117 }
42118 /**
42119 *
42120 * @private
42121 */
42122
42123 }, {
42124 key: "_zoomOut",
42125 value: function _zoomOut() {
42126 var scaleOld = this.body.view.scale;
42127 var scale = this.body.view.scale / (1 + this.options.keyboard.speed.zoom);
42128 var translation = this.body.view.translation;
42129 var scaleFrac = scale / scaleOld;
42130 var tx = (1 - scaleFrac) * this.canvas.canvasViewCenter.x + translation.x * scaleFrac;
42131 var ty = (1 - scaleFrac) * this.canvas.canvasViewCenter.y + translation.y * scaleFrac;
42132 this.body.view.scale = scale;
42133 this.body.view.translation = {
42134 x: tx,
42135 y: ty
42136 };
42137 this.body.emitter.emit('zoom', {
42138 direction: '-',
42139 scale: this.body.view.scale,
42140 pointer: null
42141 });
42142 }
42143 /**
42144 * bind all keys using keycharm.
42145 */
42146
42147 }, {
42148 key: "configureKeyboardBindings",
42149 value: function configureKeyboardBindings() {
42150 var _this3 = this;
42151
42152 if (this.keycharm !== undefined) {
42153 this.keycharm.destroy();
42154 }
42155
42156 if (this.options.keyboard.enabled === true) {
42157 if (this.options.keyboard.bindToWindow === true) {
42158 this.keycharm = keycharm({
42159 container: window,
42160 preventDefault: true
42161 });
42162 } else {
42163 this.keycharm = keycharm({
42164 container: this.canvas.frame,
42165 preventDefault: true
42166 });
42167 }
42168
42169 this.keycharm.reset();
42170
42171 if (this.activated === true) {
42172 this.keycharm.bind("up", function () {
42173 _this3.bindToRedraw("_moveUp");
42174 }, "keydown");
42175 this.keycharm.bind("down", function () {
42176 _this3.bindToRedraw("_moveDown");
42177 }, "keydown");
42178 this.keycharm.bind("left", function () {
42179 _this3.bindToRedraw("_moveLeft");
42180 }, "keydown");
42181 this.keycharm.bind("right", function () {
42182 _this3.bindToRedraw("_moveRight");
42183 }, "keydown");
42184 this.keycharm.bind("=", function () {
42185 _this3.bindToRedraw("_zoomIn");
42186 }, "keydown");
42187 this.keycharm.bind("num+", function () {
42188 _this3.bindToRedraw("_zoomIn");
42189 }, "keydown");
42190 this.keycharm.bind("num-", function () {
42191 _this3.bindToRedraw("_zoomOut");
42192 }, "keydown");
42193 this.keycharm.bind("-", function () {
42194 _this3.bindToRedraw("_zoomOut");
42195 }, "keydown");
42196 this.keycharm.bind("[", function () {
42197 _this3.bindToRedraw("_zoomOut");
42198 }, "keydown");
42199 this.keycharm.bind("]", function () {
42200 _this3.bindToRedraw("_zoomIn");
42201 }, "keydown");
42202 this.keycharm.bind("pageup", function () {
42203 _this3.bindToRedraw("_zoomIn");
42204 }, "keydown");
42205 this.keycharm.bind("pagedown", function () {
42206 _this3.bindToRedraw("_zoomOut");
42207 }, "keydown");
42208 this.keycharm.bind("up", function () {
42209 _this3.unbindFromRedraw("_moveUp");
42210 }, "keyup");
42211 this.keycharm.bind("down", function () {
42212 _this3.unbindFromRedraw("_moveDown");
42213 }, "keyup");
42214 this.keycharm.bind("left", function () {
42215 _this3.unbindFromRedraw("_moveLeft");
42216 }, "keyup");
42217 this.keycharm.bind("right", function () {
42218 _this3.unbindFromRedraw("_moveRight");
42219 }, "keyup");
42220 this.keycharm.bind("=", function () {
42221 _this3.unbindFromRedraw("_zoomIn");
42222 }, "keyup");
42223 this.keycharm.bind("num+", function () {
42224 _this3.unbindFromRedraw("_zoomIn");
42225 }, "keyup");
42226 this.keycharm.bind("num-", function () {
42227 _this3.unbindFromRedraw("_zoomOut");
42228 }, "keyup");
42229 this.keycharm.bind("-", function () {
42230 _this3.unbindFromRedraw("_zoomOut");
42231 }, "keyup");
42232 this.keycharm.bind("[", function () {
42233 _this3.unbindFromRedraw("_zoomOut");
42234 }, "keyup");
42235 this.keycharm.bind("]", function () {
42236 _this3.unbindFromRedraw("_zoomIn");
42237 }, "keyup");
42238 this.keycharm.bind("pageup", function () {
42239 _this3.unbindFromRedraw("_zoomIn");
42240 }, "keyup");
42241 this.keycharm.bind("pagedown", function () {
42242 _this3.unbindFromRedraw("_zoomOut");
42243 }, "keyup");
42244 }
42245 }
42246 }
42247 }]);
42248
42249 return NavigationHandler;
42250 }();
42251
42252 /**
42253 * Popup is a class to create a popup window with some text
42254 */
42255
42256 var Popup =
42257 /*#__PURE__*/
42258 function () {
42259 /**
42260 * @param {Element} container The container object.
42261 * @param {string} overflowMethod How the popup should act to overflowing ('flip' or 'cap')
42262 */
42263 function Popup(container, overflowMethod) {
42264 _classCallCheck(this, Popup);
42265
42266 this.container = container;
42267 this.overflowMethod = overflowMethod || 'cap';
42268 this.x = 0;
42269 this.y = 0;
42270 this.padding = 5;
42271 this.hidden = false; // create the frame
42272
42273 this.frame = document.createElement('div');
42274 this.frame.className = 'vis-tooltip';
42275 this.container.appendChild(this.frame);
42276 }
42277 /**
42278 * @param {number} x Horizontal position of the popup window
42279 * @param {number} y Vertical position of the popup window
42280 */
42281
42282
42283 _createClass(Popup, [{
42284 key: "setPosition",
42285 value: function setPosition(x, y) {
42286 this.x = parseInt(x);
42287 this.y = parseInt(y);
42288 }
42289 /**
42290 * Set the content for the popup window. This can be HTML code or text.
42291 * @param {string | Element} content
42292 */
42293
42294 }, {
42295 key: "setText",
42296 value: function setText(content) {
42297 if (content instanceof Element) {
42298 this.frame.innerHTML = '';
42299 this.frame.appendChild(content);
42300 } else {
42301 this.frame.innerHTML = content; // string containing text or HTML
42302 }
42303 }
42304 /**
42305 * Show the popup window
42306 * @param {boolean} [doShow] Show or hide the window
42307 */
42308
42309 }, {
42310 key: "show",
42311 value: function show(doShow) {
42312 if (doShow === undefined) {
42313 doShow = true;
42314 }
42315
42316 if (doShow === true) {
42317 var height = this.frame.clientHeight;
42318 var width = this.frame.clientWidth;
42319 var maxHeight = this.frame.parentNode.clientHeight;
42320 var maxWidth = this.frame.parentNode.clientWidth;
42321 var left = 0,
42322 top = 0;
42323
42324 if (this.overflowMethod == 'flip') {
42325 var isLeft = false,
42326 isTop = true; // Where around the position it's located
42327
42328 if (this.y - height < this.padding) {
42329 isTop = false;
42330 }
42331
42332 if (this.x + width > maxWidth - this.padding) {
42333 isLeft = true;
42334 }
42335
42336 if (isLeft) {
42337 left = this.x - width;
42338 } else {
42339 left = this.x;
42340 }
42341
42342 if (isTop) {
42343 top = this.y - height;
42344 } else {
42345 top = this.y;
42346 }
42347 } else {
42348 top = this.y - height;
42349
42350 if (top + height + this.padding > maxHeight) {
42351 top = maxHeight - height - this.padding;
42352 }
42353
42354 if (top < this.padding) {
42355 top = this.padding;
42356 }
42357
42358 left = this.x;
42359
42360 if (left + width + this.padding > maxWidth) {
42361 left = maxWidth - width - this.padding;
42362 }
42363
42364 if (left < this.padding) {
42365 left = this.padding;
42366 }
42367 }
42368
42369 this.frame.style.left = left + "px";
42370 this.frame.style.top = top + "px";
42371 this.frame.style.visibility = "visible";
42372 this.hidden = false;
42373 } else {
42374 this.hide();
42375 }
42376 }
42377 /**
42378 * Hide the popup window
42379 */
42380
42381 }, {
42382 key: "hide",
42383 value: function hide() {
42384 this.hidden = true;
42385 this.frame.style.left = "0";
42386 this.frame.style.top = "0";
42387 this.frame.style.visibility = "hidden";
42388 }
42389 /**
42390 * Remove the popup window
42391 */
42392
42393 }, {
42394 key: "destroy",
42395 value: function destroy() {
42396 this.frame.parentNode.removeChild(this.frame); // Remove element from DOM
42397 }
42398 }]);
42399
42400 return Popup;
42401 }();
42402
42403 /**
42404 * Handler for interactions
42405 */
42406
42407 var InteractionHandler =
42408 /*#__PURE__*/
42409 function () {
42410 /**
42411 * @param {Object} body
42412 * @param {Canvas} canvas
42413 * @param {SelectionHandler} selectionHandler
42414 */
42415 function InteractionHandler(body, canvas, selectionHandler) {
42416 _classCallCheck(this, InteractionHandler);
42417
42418 this.body = body;
42419 this.canvas = canvas;
42420 this.selectionHandler = selectionHandler;
42421 this.navigationHandler = new NavigationHandler(body, canvas); // bind the events from hammer to functions in this object
42422
42423 this.body.eventListeners.onTap = this.onTap.bind(this);
42424 this.body.eventListeners.onTouch = this.onTouch.bind(this);
42425 this.body.eventListeners.onDoubleTap = this.onDoubleTap.bind(this);
42426 this.body.eventListeners.onHold = this.onHold.bind(this);
42427 this.body.eventListeners.onDragStart = this.onDragStart.bind(this);
42428 this.body.eventListeners.onDrag = this.onDrag.bind(this);
42429 this.body.eventListeners.onDragEnd = this.onDragEnd.bind(this);
42430 this.body.eventListeners.onMouseWheel = this.onMouseWheel.bind(this);
42431 this.body.eventListeners.onPinch = this.onPinch.bind(this);
42432 this.body.eventListeners.onMouseMove = this.onMouseMove.bind(this);
42433 this.body.eventListeners.onRelease = this.onRelease.bind(this);
42434 this.body.eventListeners.onContext = this.onContext.bind(this);
42435 this.touchTime = 0;
42436 this.drag = {};
42437 this.pinch = {};
42438 this.popup = undefined;
42439 this.popupObj = undefined;
42440 this.popupTimer = undefined;
42441 this.body.functions.getPointer = this.getPointer.bind(this);
42442 this.options = {};
42443 this.defaultOptions = {
42444 dragNodes: true,
42445 dragView: true,
42446 hover: false,
42447 keyboard: {
42448 enabled: false,
42449 speed: {
42450 x: 10,
42451 y: 10,
42452 zoom: 0.02
42453 },
42454 bindToWindow: true
42455 },
42456 navigationButtons: false,
42457 tooltipDelay: 300,
42458 zoomView: true,
42459 zoomSpeed: 1
42460 };
42461 extend(this.options, this.defaultOptions);
42462 this.bindEventListeners();
42463 }
42464 /**
42465 * Binds event listeners
42466 */
42467
42468
42469 _createClass(InteractionHandler, [{
42470 key: "bindEventListeners",
42471 value: function bindEventListeners() {
42472 var _this = this;
42473
42474 this.body.emitter.on('destroy', function () {
42475 clearTimeout(_this.popupTimer);
42476 delete _this.body.functions.getPointer;
42477 });
42478 }
42479 /**
42480 *
42481 * @param {Object} options
42482 */
42483
42484 }, {
42485 key: "setOptions",
42486 value: function setOptions(options) {
42487 if (options !== undefined) {
42488 // extend all but the values in fields
42489 var fields = ['hideEdgesOnDrag', 'hideEdgesOnZoom', 'hideNodesOnDrag', 'keyboard', 'multiselect', 'selectable', 'selectConnectedEdges'];
42490 selectiveNotDeepExtend(fields, this.options, options); // merge the keyboard options in.
42491
42492 mergeOptions(this.options, options, 'keyboard');
42493
42494 if (options.tooltip) {
42495 extend(this.options.tooltip, options.tooltip);
42496
42497 if (options.tooltip.color) {
42498 this.options.tooltip.color = parseColor(options.tooltip.color);
42499 }
42500 }
42501 }
42502
42503 this.navigationHandler.setOptions(this.options);
42504 }
42505 /**
42506 * Get the pointer location from a touch location
42507 * @param {{x: number, y: number}} touch
42508 * @return {{x: number, y: number}} pointer
42509 * @private
42510 */
42511
42512 }, {
42513 key: "getPointer",
42514 value: function getPointer(touch) {
42515 return {
42516 x: touch.x - getAbsoluteLeft(this.canvas.frame.canvas),
42517 y: touch.y - getAbsoluteTop(this.canvas.frame.canvas)
42518 };
42519 }
42520 /**
42521 * On start of a touch gesture, store the pointer
42522 * @param {Event} event The event
42523 * @private
42524 */
42525
42526 }, {
42527 key: "onTouch",
42528 value: function onTouch(event) {
42529 if (new Date().valueOf() - this.touchTime > 50) {
42530 this.drag.pointer = this.getPointer(event.center);
42531 this.drag.pinched = false;
42532 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)
42533
42534 this.touchTime = new Date().valueOf();
42535 }
42536 }
42537 /**
42538 * handle tap/click event: select/unselect a node
42539 * @param {Event} event
42540 * @private
42541 */
42542
42543 }, {
42544 key: "onTap",
42545 value: function onTap(event) {
42546 var pointer = this.getPointer(event.center);
42547 var multiselect = this.selectionHandler.options.multiselect && (event.changedPointers[0].ctrlKey || event.changedPointers[0].metaKey);
42548 this.checkSelectionChanges(pointer, event, multiselect);
42549
42550 this.selectionHandler._generateClickEvent('click', event, pointer);
42551 }
42552 /**
42553 * handle doubletap event
42554 * @param {Event} event
42555 * @private
42556 */
42557
42558 }, {
42559 key: "onDoubleTap",
42560 value: function onDoubleTap(event) {
42561 var pointer = this.getPointer(event.center);
42562
42563 this.selectionHandler._generateClickEvent('doubleClick', event, pointer);
42564 }
42565 /**
42566 * handle long tap event: multi select nodes
42567 * @param {Event} event
42568 * @private
42569 */
42570
42571 }, {
42572 key: "onHold",
42573 value: function onHold(event) {
42574 var pointer = this.getPointer(event.center);
42575 var multiselect = this.selectionHandler.options.multiselect;
42576 this.checkSelectionChanges(pointer, event, multiselect);
42577
42578 this.selectionHandler._generateClickEvent('click', event, pointer);
42579
42580 this.selectionHandler._generateClickEvent('hold', event, pointer);
42581 }
42582 /**
42583 * handle the release of the screen
42584 *
42585 * @param {Event} event
42586 * @private
42587 */
42588
42589 }, {
42590 key: "onRelease",
42591 value: function onRelease(event) {
42592 if (new Date().valueOf() - this.touchTime > 10) {
42593 var pointer = this.getPointer(event.center);
42594
42595 this.selectionHandler._generateClickEvent('release', event, pointer); // to avoid double fireing of this event because we have two hammer instances. (on canvas and on frame)
42596
42597
42598 this.touchTime = new Date().valueOf();
42599 }
42600 }
42601 /**
42602 *
42603 * @param {Event} event
42604 */
42605
42606 }, {
42607 key: "onContext",
42608 value: function onContext(event) {
42609 var pointer = this.getPointer({
42610 x: event.clientX,
42611 y: event.clientY
42612 });
42613
42614 this.selectionHandler._generateClickEvent('oncontext', event, pointer);
42615 }
42616 /**
42617 * Select and deselect nodes depending current selection change.
42618 *
42619 * For changing nodes, select/deselect events are fired.
42620 *
42621 * NOTE: For a given edge, if one connecting node is deselected and with the same
42622 * click the other node is selected, no events for the edge will fire.
42623 * It was selected and it will remain selected.
42624 *
42625 * TODO: This is all SelectionHandler calls; the method should be moved to there.
42626 *
42627 * @param {{x: number, y: number}} pointer
42628 * @param {Event} event
42629 * @param {boolean} [add=false]
42630 */
42631
42632 }, {
42633 key: "checkSelectionChanges",
42634 value: function checkSelectionChanges(pointer, event) {
42635 var add = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
42636 var previousSelection = this.selectionHandler.getSelection();
42637 var selected = false;
42638
42639 if (add === true) {
42640 selected = this.selectionHandler.selectAdditionalOnPoint(pointer);
42641 } else {
42642 selected = this.selectionHandler.selectOnPoint(pointer);
42643 }
42644
42645 var currentSelection = this.selectionHandler.getSelection(); // See NOTE in method comment for the reason to do it like this
42646
42647 var deselectedItems = this._determineDifference(previousSelection, currentSelection);
42648
42649 var selectedItems = this._determineDifference(currentSelection, previousSelection);
42650
42651 if (deselectedItems.edges.length > 0) {
42652 this.selectionHandler._generateClickEvent('deselectEdge', event, pointer, previousSelection);
42653
42654 selected = true;
42655 }
42656
42657 if (deselectedItems.nodes.length > 0) {
42658 this.selectionHandler._generateClickEvent('deselectNode', event, pointer, previousSelection);
42659
42660 selected = true;
42661 }
42662
42663 if (selectedItems.nodes.length > 0) {
42664 this.selectionHandler._generateClickEvent('selectNode', event, pointer);
42665
42666 selected = true;
42667 }
42668
42669 if (selectedItems.edges.length > 0) {
42670 this.selectionHandler._generateClickEvent('selectEdge', event, pointer);
42671
42672 selected = true;
42673 } // fire the select event if anything has been selected or deselected
42674
42675
42676 if (selected === true) {
42677 // select or unselect
42678 this.selectionHandler._generateClickEvent('select', event, pointer);
42679 }
42680 }
42681 /**
42682 * Remove all node and edge id's from the first set that are present in the second one.
42683 *
42684 * @param {{nodes: Array.<Node>, edges: Array.<vis.Edge>}} firstSet
42685 * @param {{nodes: Array.<Node>, edges: Array.<vis.Edge>}} secondSet
42686 * @returns {{nodes: Array.<Node>, edges: Array.<vis.Edge>}}
42687 * @private
42688 */
42689
42690 }, {
42691 key: "_determineDifference",
42692 value: function _determineDifference(firstSet, secondSet) {
42693 var arrayDiff = function arrayDiff(firstArr, secondArr) {
42694 var result = [];
42695
42696 for (var i = 0; i < firstArr.length; i++) {
42697 var value = firstArr[i];
42698
42699 if (secondArr.indexOf(value) === -1) {
42700 result.push(value);
42701 }
42702 }
42703
42704 return result;
42705 };
42706
42707 return {
42708 nodes: arrayDiff(firstSet.nodes, secondSet.nodes),
42709 edges: arrayDiff(firstSet.edges, secondSet.edges)
42710 };
42711 }
42712 /**
42713 * This function is called by onDragStart.
42714 * It is separated out because we can then overload it for the datamanipulation system.
42715 *
42716 * @param {Event} event
42717 * @private
42718 */
42719
42720 }, {
42721 key: "onDragStart",
42722 value: function onDragStart(event) {
42723 //in case the touch event was triggered on an external div, do the initial touch now.
42724 if (this.drag.pointer === undefined) {
42725 this.onTouch(event);
42726 } // note: drag.pointer is set in onTouch to get the initial touch location
42727
42728
42729 var node = this.selectionHandler.getNodeAt(this.drag.pointer);
42730 this.drag.dragging = true;
42731 this.drag.selection = [];
42732 this.drag.translation = extend({}, this.body.view.translation); // copy the object
42733
42734 this.drag.nodeId = undefined;
42735
42736 if (node !== undefined && this.options.dragNodes === true) {
42737 this.drag.nodeId = node.id; // select the clicked node if not yet selected
42738
42739 if (node.isSelected() === false) {
42740 this.selectionHandler.unselectAll();
42741 this.selectionHandler.selectObject(node);
42742 } // after select to contain the node
42743
42744
42745 this.selectionHandler._generateClickEvent('dragStart', event, this.drag.pointer);
42746
42747 var selection = this.selectionHandler.selectionObj.nodes; // create an array with the selected nodes and their original location and status
42748
42749 for (var nodeId in selection) {
42750 if (selection.hasOwnProperty(nodeId)) {
42751 var object = selection[nodeId];
42752 var s = {
42753 id: object.id,
42754 node: object,
42755 // store original x, y, xFixed and yFixed, make the node temporarily Fixed
42756 x: object.x,
42757 y: object.y,
42758 xFixed: object.options.fixed.x,
42759 yFixed: object.options.fixed.y
42760 };
42761 object.options.fixed.x = true;
42762 object.options.fixed.y = true;
42763 this.drag.selection.push(s);
42764 }
42765 }
42766 } else {
42767 // fallback if no node is selected and thus the view is dragged.
42768 this.selectionHandler._generateClickEvent('dragStart', event, this.drag.pointer, undefined, true);
42769 }
42770 }
42771 /**
42772 * handle drag event
42773 * @param {Event} event
42774 * @private
42775 */
42776
42777 }, {
42778 key: "onDrag",
42779 value: function onDrag(event) {
42780 var _this2 = this;
42781
42782 if (this.drag.pinched === true) {
42783 return;
42784 } // remove the focus on node if it is focussed on by the focusOnNode
42785
42786
42787 this.body.emitter.emit('unlockNode');
42788 var pointer = this.getPointer(event.center);
42789 var selection = this.drag.selection;
42790
42791 if (selection && selection.length && this.options.dragNodes === true) {
42792 this.selectionHandler._generateClickEvent('dragging', event, pointer); // calculate delta's and new location
42793
42794
42795 var deltaX = pointer.x - this.drag.pointer.x;
42796 var deltaY = pointer.y - this.drag.pointer.y; // update position of all selected nodes
42797
42798 selection.forEach(function (selection) {
42799 var node = selection.node; // only move the node if it was not fixed initially
42800
42801 if (selection.xFixed === false) {
42802 node.x = _this2.canvas._XconvertDOMtoCanvas(_this2.canvas._XconvertCanvasToDOM(selection.x) + deltaX);
42803 } // only move the node if it was not fixed initially
42804
42805
42806 if (selection.yFixed === false) {
42807 node.y = _this2.canvas._YconvertDOMtoCanvas(_this2.canvas._YconvertCanvasToDOM(selection.y) + deltaY);
42808 }
42809 }); // start the simulation of the physics
42810
42811 this.body.emitter.emit('startSimulation');
42812 } else {
42813 // move the network
42814 if (this.options.dragView === true) {
42815 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.
42816
42817
42818 if (this.drag.pointer === undefined) {
42819 this.onDragStart(event);
42820 return;
42821 }
42822
42823 var diffX = pointer.x - this.drag.pointer.x;
42824 var diffY = pointer.y - this.drag.pointer.y;
42825 this.body.view.translation = {
42826 x: this.drag.translation.x + diffX,
42827 y: this.drag.translation.y + diffY
42828 };
42829 this.body.emitter.emit('_requestRedraw');
42830 }
42831 }
42832 }
42833 /**
42834 * handle drag start event
42835 * @param {Event} event
42836 * @private
42837 */
42838
42839 }, {
42840 key: "onDragEnd",
42841 value: function onDragEnd(event) {
42842 this.drag.dragging = false;
42843 var selection = this.drag.selection;
42844
42845 if (selection && selection.length) {
42846 selection.forEach(function (s) {
42847 // restore original xFixed and yFixed
42848 s.node.options.fixed.x = s.xFixed;
42849 s.node.options.fixed.y = s.yFixed;
42850 });
42851
42852 this.selectionHandler._generateClickEvent('dragEnd', event, this.getPointer(event.center));
42853
42854 this.body.emitter.emit('startSimulation');
42855 } else {
42856 this.selectionHandler._generateClickEvent('dragEnd', event, this.getPointer(event.center), undefined, true);
42857
42858 this.body.emitter.emit('_requestRedraw');
42859 }
42860 }
42861 /**
42862 * Handle pinch event
42863 * @param {Event} event The event
42864 * @private
42865 */
42866
42867 }, {
42868 key: "onPinch",
42869 value: function onPinch(event) {
42870 var pointer = this.getPointer(event.center);
42871 this.drag.pinched = true;
42872
42873 if (this.pinch['scale'] === undefined) {
42874 this.pinch.scale = 1;
42875 } // TODO: enabled moving while pinching?
42876
42877
42878 var scale = this.pinch.scale * event.scale;
42879 this.zoom(scale, pointer);
42880 }
42881 /**
42882 * Zoom the network in or out
42883 * @param {number} scale a number around 1, and between 0.01 and 10
42884 * @param {{x: number, y: number}} pointer Position on screen
42885 * @private
42886 */
42887
42888 }, {
42889 key: "zoom",
42890 value: function zoom(scale, pointer) {
42891 if (this.options.zoomView === true) {
42892 var scaleOld = this.body.view.scale;
42893
42894 if (scale < 0.00001) {
42895 scale = 0.00001;
42896 }
42897
42898 if (scale > 10) {
42899 scale = 10;
42900 }
42901
42902 var preScaleDragPointer = undefined;
42903
42904 if (this.drag !== undefined) {
42905 if (this.drag.dragging === true) {
42906 preScaleDragPointer = this.canvas.DOMtoCanvas(this.drag.pointer);
42907 }
42908 } // + this.canvas.frame.canvas.clientHeight / 2
42909
42910
42911 var translation = this.body.view.translation;
42912 var scaleFrac = scale / scaleOld;
42913 var tx = (1 - scaleFrac) * pointer.x + translation.x * scaleFrac;
42914 var ty = (1 - scaleFrac) * pointer.y + translation.y * scaleFrac;
42915 this.body.view.scale = scale;
42916 this.body.view.translation = {
42917 x: tx,
42918 y: ty
42919 };
42920
42921 if (preScaleDragPointer != undefined) {
42922 var postScaleDragPointer = this.canvas.canvasToDOM(preScaleDragPointer);
42923 this.drag.pointer.x = postScaleDragPointer.x;
42924 this.drag.pointer.y = postScaleDragPointer.y;
42925 }
42926
42927 this.body.emitter.emit('_requestRedraw');
42928
42929 if (scaleOld < scale) {
42930 this.body.emitter.emit('zoom', {
42931 direction: '+',
42932 scale: this.body.view.scale,
42933 pointer: pointer
42934 });
42935 } else {
42936 this.body.emitter.emit('zoom', {
42937 direction: '-',
42938 scale: this.body.view.scale,
42939 pointer: pointer
42940 });
42941 }
42942 }
42943 }
42944 /**
42945 * Event handler for mouse wheel event, used to zoom the timeline
42946 * See http://adomas.org/javascript-mouse-wheel/
42947 * https://github.com/EightMedia/hammer.js/issues/256
42948 * @param {MouseEvent} event
42949 * @private
42950 */
42951
42952 }, {
42953 key: "onMouseWheel",
42954 value: function onMouseWheel(event) {
42955 if (this.options.zoomView === true) {
42956 // If delta is nonzero, handle it.
42957 // Basically, delta is now positive if wheel was scrolled up,
42958 // and negative, if wheel was scrolled down.
42959 if (event.deltaY !== 0) {
42960 // calculate the new scale
42961 var scale = this.body.view.scale;
42962 scale *= 1 + (event.deltaY < 0 ? 1 : -1) * (this.options.zoomSpeed * 0.1); // calculate the pointer location
42963
42964 var pointer = this.getPointer({
42965 x: event.clientX,
42966 y: event.clientY
42967 }); // apply the new scale
42968
42969 this.zoom(scale, pointer);
42970 } // Prevent default actions caused by mouse wheel.
42971
42972
42973 event.preventDefault();
42974 }
42975 }
42976 /**
42977 * Mouse move handler for checking whether the title moves over a node with a title.
42978 * @param {Event} event
42979 * @private
42980 */
42981
42982 }, {
42983 key: "onMouseMove",
42984 value: function onMouseMove(event) {
42985 var _this3 = this;
42986
42987 var pointer = this.getPointer({
42988 x: event.clientX,
42989 y: event.clientY
42990 });
42991 var popupVisible = false; // check if the previously selected node is still selected
42992
42993 if (this.popup !== undefined) {
42994 if (this.popup.hidden === false) {
42995 this._checkHidePopup(pointer);
42996 } // if the popup was not hidden above
42997
42998
42999 if (this.popup.hidden === false) {
43000 popupVisible = true;
43001 this.popup.setPosition(pointer.x + 3, pointer.y - 5);
43002 this.popup.show();
43003 }
43004 } // if we bind the keyboard to the div, we have to highlight it to use it. This highlights it on mouse over.
43005
43006
43007 if (this.options.keyboard.bindToWindow === false && this.options.keyboard.enabled === true) {
43008 this.canvas.frame.focus();
43009 } // start a timeout that will check if the mouse is positioned above an element
43010
43011
43012 if (popupVisible === false) {
43013 if (this.popupTimer !== undefined) {
43014 clearInterval(this.popupTimer); // stop any running calculationTimer
43015
43016 this.popupTimer = undefined;
43017 }
43018
43019 if (!this.drag.dragging) {
43020 this.popupTimer = setTimeout(function () {
43021 return _this3._checkShowPopup(pointer);
43022 }, this.options.tooltipDelay);
43023 }
43024 } // adding hover highlights
43025
43026
43027 if (this.options.hover === true) {
43028 this.selectionHandler.hoverObject(event, pointer);
43029 }
43030 }
43031 /**
43032 * Check if there is an element on the given position in the network
43033 * (a node or edge). If so, and if this element has a title,
43034 * show a popup window with its title.
43035 *
43036 * @param {{x:number, y:number}} pointer
43037 * @private
43038 */
43039
43040 }, {
43041 key: "_checkShowPopup",
43042 value: function _checkShowPopup(pointer) {
43043 var x = this.canvas._XconvertDOMtoCanvas(pointer.x);
43044
43045 var y = this.canvas._YconvertDOMtoCanvas(pointer.y);
43046
43047 var pointerObj = {
43048 left: x,
43049 top: y,
43050 right: x,
43051 bottom: y
43052 };
43053 var previousPopupObjId = this.popupObj === undefined ? undefined : this.popupObj.id;
43054 var nodeUnderCursor = false;
43055 var popupType = 'node'; // check if a node is under the cursor.
43056
43057 if (this.popupObj === undefined) {
43058 // search the nodes for overlap, select the top one in case of multiple nodes
43059 var nodeIndices = this.body.nodeIndices;
43060 var nodes = this.body.nodes;
43061 var node;
43062 var overlappingNodes = [];
43063
43064 for (var i = 0; i < nodeIndices.length; i++) {
43065 node = nodes[nodeIndices[i]];
43066
43067 if (node.isOverlappingWith(pointerObj) === true) {
43068 nodeUnderCursor = true;
43069
43070 if (node.getTitle() !== undefined) {
43071 overlappingNodes.push(nodeIndices[i]);
43072 }
43073 }
43074 }
43075
43076 if (overlappingNodes.length > 0) {
43077 // if there are overlapping nodes, select the last one, this is the one which is drawn on top of the others
43078 this.popupObj = nodes[overlappingNodes[overlappingNodes.length - 1]]; // if you hover over a node, the title of the edge is not supposed to be shown.
43079
43080 nodeUnderCursor = true;
43081 }
43082 }
43083
43084 if (this.popupObj === undefined && nodeUnderCursor === false) {
43085 // search the edges for overlap
43086 var edgeIndices = this.body.edgeIndices;
43087 var edges = this.body.edges;
43088 var edge;
43089 var overlappingEdges = [];
43090
43091 for (var _i = 0; _i < edgeIndices.length; _i++) {
43092 edge = edges[edgeIndices[_i]];
43093
43094 if (edge.isOverlappingWith(pointerObj) === true) {
43095 if (edge.connected === true && edge.getTitle() !== undefined) {
43096 overlappingEdges.push(edgeIndices[_i]);
43097 }
43098 }
43099 }
43100
43101 if (overlappingEdges.length > 0) {
43102 this.popupObj = edges[overlappingEdges[overlappingEdges.length - 1]];
43103 popupType = 'edge';
43104 }
43105 }
43106
43107 if (this.popupObj !== undefined) {
43108 // show popup message window
43109 if (this.popupObj.id !== previousPopupObjId) {
43110 if (this.popup === undefined) {
43111 this.popup = new Popup(this.canvas.frame);
43112 }
43113
43114 this.popup.popupTargetType = popupType;
43115 this.popup.popupTargetId = this.popupObj.id; // adjust a small offset such that the mouse cursor is located in the
43116 // bottom left location of the popup, and you can easily move over the
43117 // popup area
43118
43119 this.popup.setPosition(pointer.x + 3, pointer.y - 5);
43120 this.popup.setText(this.popupObj.getTitle());
43121 this.popup.show();
43122 this.body.emitter.emit('showPopup', this.popupObj.id);
43123 }
43124 } else {
43125 if (this.popup !== undefined) {
43126 this.popup.hide();
43127 this.body.emitter.emit('hidePopup');
43128 }
43129 }
43130 }
43131 /**
43132 * Check if the popup must be hidden, which is the case when the mouse is no
43133 * longer hovering on the object
43134 * @param {{x:number, y:number}} pointer
43135 * @private
43136 */
43137
43138 }, {
43139 key: "_checkHidePopup",
43140 value: function _checkHidePopup(pointer) {
43141 var pointerObj = this.selectionHandler._pointerToPositionObject(pointer);
43142
43143 var stillOnObj = false;
43144
43145 if (this.popup.popupTargetType === 'node') {
43146 if (this.body.nodes[this.popup.popupTargetId] !== undefined) {
43147 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.
43148 // we initially only check stillOnObj because this is much faster.
43149
43150 if (stillOnObj === true) {
43151 var overNode = this.selectionHandler.getNodeAt(pointer);
43152 stillOnObj = overNode === undefined ? false : overNode.id === this.popup.popupTargetId;
43153 }
43154 }
43155 } else {
43156 if (this.selectionHandler.getNodeAt(pointer) === undefined) {
43157 if (this.body.edges[this.popup.popupTargetId] !== undefined) {
43158 stillOnObj = this.body.edges[this.popup.popupTargetId].isOverlappingWith(pointerObj);
43159 }
43160 }
43161 }
43162
43163 if (stillOnObj === false) {
43164 this.popupObj = undefined;
43165 this.popup.hide();
43166 this.body.emitter.emit('hidePopup');
43167 }
43168 }
43169 }]);
43170
43171 return InteractionHandler;
43172 }();
43173
43174 /**
43175 * The handler for selections
43176 */
43177
43178 var SelectionHandler =
43179 /*#__PURE__*/
43180 function () {
43181 /**
43182 * @param {Object} body
43183 * @param {Canvas} canvas
43184 */
43185 function SelectionHandler(body, canvas) {
43186 var _this = this;
43187
43188 _classCallCheck(this, SelectionHandler);
43189
43190 this.body = body;
43191 this.canvas = canvas;
43192 this.selectionObj = {
43193 nodes: [],
43194 edges: []
43195 };
43196 this.hoverObj = {
43197 nodes: {},
43198 edges: {}
43199 };
43200 this.options = {};
43201 this.defaultOptions = {
43202 multiselect: false,
43203 selectable: true,
43204 selectConnectedEdges: true,
43205 hoverConnectedEdges: true
43206 };
43207 extend(this.options, this.defaultOptions);
43208 this.body.emitter.on("_dataChanged", function () {
43209 _this.updateSelection();
43210 });
43211 }
43212 /**
43213 *
43214 * @param {Object} [options]
43215 */
43216
43217
43218 _createClass(SelectionHandler, [{
43219 key: "setOptions",
43220 value: function setOptions(options) {
43221 if (options !== undefined) {
43222 var fields = ['multiselect', 'hoverConnectedEdges', 'selectable', 'selectConnectedEdges'];
43223 selectiveDeepExtend(fields, this.options, options);
43224 }
43225 }
43226 /**
43227 * handles the selection part of the tap;
43228 *
43229 * @param {{x: number, y: number}} pointer
43230 * @returns {boolean}
43231 */
43232
43233 }, {
43234 key: "selectOnPoint",
43235 value: function selectOnPoint(pointer) {
43236 var selected = false;
43237
43238 if (this.options.selectable === true) {
43239 var obj = this.getNodeAt(pointer) || this.getEdgeAt(pointer); // unselect after getting the objects in order to restore width and height.
43240
43241 this.unselectAll();
43242
43243 if (obj !== undefined) {
43244 selected = this.selectObject(obj);
43245 }
43246
43247 this.body.emitter.emit("_requestRedraw");
43248 }
43249
43250 return selected;
43251 }
43252 /**
43253 *
43254 * @param {{x: number, y: number}} pointer
43255 * @returns {boolean}
43256 */
43257
43258 }, {
43259 key: "selectAdditionalOnPoint",
43260 value: function selectAdditionalOnPoint(pointer) {
43261 var selectionChanged = false;
43262
43263 if (this.options.selectable === true) {
43264 var obj = this.getNodeAt(pointer) || this.getEdgeAt(pointer);
43265
43266 if (obj !== undefined) {
43267 selectionChanged = true;
43268
43269 if (obj.isSelected() === true) {
43270 this.deselectObject(obj);
43271 } else {
43272 this.selectObject(obj);
43273 }
43274
43275 this.body.emitter.emit("_requestRedraw");
43276 }
43277 }
43278
43279 return selectionChanged;
43280 }
43281 /**
43282 * Create an object containing the standard fields for an event.
43283 *
43284 * @param {Event} event
43285 * @param {{x: number, y: number}} pointer Object with the x and y screen coordinates of the mouse
43286 * @returns {{}}
43287 * @private
43288 */
43289
43290 }, {
43291 key: "_initBaseEvent",
43292 value: function _initBaseEvent(event, pointer) {
43293 var properties = {};
43294 properties['pointer'] = {
43295 DOM: {
43296 x: pointer.x,
43297 y: pointer.y
43298 },
43299 canvas: this.canvas.DOMtoCanvas(pointer)
43300 };
43301 properties['event'] = event;
43302 return properties;
43303 }
43304 /**
43305 * Generate an event which the user can catch.
43306 *
43307 * This adds some extra data to the event with respect to cursor position and
43308 * selected nodes and edges.
43309 *
43310 * @param {string} eventType Name of event to send
43311 * @param {Event} event
43312 * @param {{x: number, y: number}} pointer Object with the x and y screen coordinates of the mouse
43313 * @param {Object|undefined} oldSelection If present, selection state before event occured
43314 * @param {boolean|undefined} [emptySelection=false] Indicate if selection data should be passed
43315 */
43316
43317 }, {
43318 key: "_generateClickEvent",
43319 value: function _generateClickEvent(eventType, event, pointer, oldSelection) {
43320 var emptySelection = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false;
43321
43322 var properties = this._initBaseEvent(event, pointer);
43323
43324 if (emptySelection === true) {
43325 properties.nodes = [];
43326 properties.edges = [];
43327 } else {
43328 var tmp = this.getSelection();
43329 properties.nodes = tmp.nodes;
43330 properties.edges = tmp.edges;
43331 }
43332
43333 if (oldSelection !== undefined) {
43334 properties['previousSelection'] = oldSelection;
43335 }
43336
43337 if (eventType == 'click') {
43338 // For the time being, restrict this functionality to
43339 // just the click event.
43340 properties.items = this.getClickedItems(pointer);
43341 }
43342
43343 if (event.controlEdge !== undefined) {
43344 properties.controlEdge = event.controlEdge;
43345 }
43346
43347 this.body.emitter.emit(eventType, properties);
43348 }
43349 /**
43350 *
43351 * @param {Object} obj
43352 * @param {boolean} [highlightEdges=this.options.selectConnectedEdges]
43353 * @returns {boolean}
43354 */
43355
43356 }, {
43357 key: "selectObject",
43358 value: function selectObject(obj) {
43359 var highlightEdges = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.options.selectConnectedEdges;
43360
43361 if (obj !== undefined) {
43362 if (obj instanceof Node) {
43363 if (highlightEdges === true) {
43364 this._selectConnectedEdges(obj);
43365 }
43366 }
43367
43368 obj.select();
43369
43370 this._addToSelection(obj);
43371
43372 return true;
43373 }
43374
43375 return false;
43376 }
43377 /**
43378 *
43379 * @param {Object} obj
43380 */
43381
43382 }, {
43383 key: "deselectObject",
43384 value: function deselectObject(obj) {
43385 if (obj.isSelected() === true) {
43386 obj.selected = false;
43387
43388 this._removeFromSelection(obj);
43389 }
43390 }
43391 /**
43392 * retrieve all nodes overlapping with given object
43393 * @param {Object} object An object with parameters left, top, right, bottom
43394 * @return {number[]} An array with id's of the overlapping nodes
43395 * @private
43396 */
43397
43398 }, {
43399 key: "_getAllNodesOverlappingWith",
43400 value: function _getAllNodesOverlappingWith(object) {
43401 var overlappingNodes = [];
43402 var nodes = this.body.nodes;
43403
43404 for (var i = 0; i < this.body.nodeIndices.length; i++) {
43405 var nodeId = this.body.nodeIndices[i];
43406
43407 if (nodes[nodeId].isOverlappingWith(object)) {
43408 overlappingNodes.push(nodeId);
43409 }
43410 }
43411
43412 return overlappingNodes;
43413 }
43414 /**
43415 * Return a position object in canvasspace from a single point in screenspace
43416 *
43417 * @param {{x: number, y: number}} pointer
43418 * @returns {{left: number, top: number, right: number, bottom: number}}
43419 * @private
43420 */
43421
43422 }, {
43423 key: "_pointerToPositionObject",
43424 value: function _pointerToPositionObject(pointer) {
43425 var canvasPos = this.canvas.DOMtoCanvas(pointer);
43426 return {
43427 left: canvasPos.x - 1,
43428 top: canvasPos.y + 1,
43429 right: canvasPos.x + 1,
43430 bottom: canvasPos.y - 1
43431 };
43432 }
43433 /**
43434 * Get the top node at the passed point (like a click)
43435 *
43436 * @param {{x: number, y: number}} pointer
43437 * @param {boolean} [returnNode=true]
43438 * @return {Node | undefined} node
43439 */
43440
43441 }, {
43442 key: "getNodeAt",
43443 value: function getNodeAt(pointer) {
43444 var returnNode = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
43445
43446 // we first check if this is an navigation controls element
43447 var positionObject = this._pointerToPositionObject(pointer);
43448
43449 var overlappingNodes = this._getAllNodesOverlappingWith(positionObject); // if there are overlapping nodes, select the last one, this is the
43450 // one which is drawn on top of the others
43451
43452
43453 if (overlappingNodes.length > 0) {
43454 if (returnNode === true) {
43455 return this.body.nodes[overlappingNodes[overlappingNodes.length - 1]];
43456 } else {
43457 return overlappingNodes[overlappingNodes.length - 1];
43458 }
43459 } else {
43460 return undefined;
43461 }
43462 }
43463 /**
43464 * retrieve all edges overlapping with given object, selector is around center
43465 * @param {Object} object An object with parameters left, top, right, bottom
43466 * @param {number[]} overlappingEdges An array with id's of the overlapping nodes
43467 * @private
43468 */
43469
43470 }, {
43471 key: "_getEdgesOverlappingWith",
43472 value: function _getEdgesOverlappingWith(object, overlappingEdges) {
43473 var edges = this.body.edges;
43474
43475 for (var i = 0; i < this.body.edgeIndices.length; i++) {
43476 var edgeId = this.body.edgeIndices[i];
43477
43478 if (edges[edgeId].isOverlappingWith(object)) {
43479 overlappingEdges.push(edgeId);
43480 }
43481 }
43482 }
43483 /**
43484 * retrieve all nodes overlapping with given object
43485 * @param {Object} object An object with parameters left, top, right, bottom
43486 * @return {number[]} An array with id's of the overlapping nodes
43487 * @private
43488 */
43489
43490 }, {
43491 key: "_getAllEdgesOverlappingWith",
43492 value: function _getAllEdgesOverlappingWith(object) {
43493 var overlappingEdges = [];
43494
43495 this._getEdgesOverlappingWith(object, overlappingEdges);
43496
43497 return overlappingEdges;
43498 }
43499 /**
43500 * Get the edges nearest to the passed point (like a click)
43501 *
43502 * @param {{x: number, y: number}} pointer
43503 * @param {boolean} [returnEdge=true]
43504 * @return {Edge | undefined} node
43505 */
43506
43507 }, {
43508 key: "getEdgeAt",
43509 value: function getEdgeAt(pointer) {
43510 var returnEdge = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
43511 // Iterate over edges, pick closest within 10
43512 var canvasPos = this.canvas.DOMtoCanvas(pointer);
43513 var mindist = 10;
43514 var overlappingEdge = null;
43515 var edges = this.body.edges;
43516
43517 for (var i = 0; i < this.body.edgeIndices.length; i++) {
43518 var edgeId = this.body.edgeIndices[i];
43519 var edge = edges[edgeId];
43520
43521 if (edge.connected) {
43522 var xFrom = edge.from.x;
43523 var yFrom = edge.from.y;
43524 var xTo = edge.to.x;
43525 var yTo = edge.to.y;
43526 var dist = edge.edgeType.getDistanceToEdge(xFrom, yFrom, xTo, yTo, canvasPos.x, canvasPos.y);
43527
43528 if (dist < mindist) {
43529 overlappingEdge = edgeId;
43530 mindist = dist;
43531 }
43532 }
43533 }
43534
43535 if (overlappingEdge !== null) {
43536 if (returnEdge === true) {
43537 return this.body.edges[overlappingEdge];
43538 } else {
43539 return overlappingEdge;
43540 }
43541 } else {
43542 return undefined;
43543 }
43544 }
43545 /**
43546 * Add object to the selection array.
43547 *
43548 * @param {Object} obj
43549 * @private
43550 */
43551
43552 }, {
43553 key: "_addToSelection",
43554 value: function _addToSelection(obj) {
43555 if (obj instanceof Node) {
43556 this.selectionObj.nodes[obj.id] = obj;
43557 } else {
43558 this.selectionObj.edges[obj.id] = obj;
43559 }
43560 }
43561 /**
43562 * Add object to the selection array.
43563 *
43564 * @param {Object} obj
43565 * @private
43566 */
43567
43568 }, {
43569 key: "_addToHover",
43570 value: function _addToHover(obj) {
43571 if (obj instanceof Node) {
43572 this.hoverObj.nodes[obj.id] = obj;
43573 } else {
43574 this.hoverObj.edges[obj.id] = obj;
43575 }
43576 }
43577 /**
43578 * Remove a single option from selection.
43579 *
43580 * @param {Object} obj
43581 * @private
43582 */
43583
43584 }, {
43585 key: "_removeFromSelection",
43586 value: function _removeFromSelection(obj) {
43587 if (obj instanceof Node) {
43588 delete this.selectionObj.nodes[obj.id];
43589
43590 this._unselectConnectedEdges(obj);
43591 } else {
43592 delete this.selectionObj.edges[obj.id];
43593 }
43594 }
43595 /**
43596 * Unselect all. The selectionObj is useful for this.
43597 */
43598
43599 }, {
43600 key: "unselectAll",
43601 value: function unselectAll() {
43602 for (var nodeId in this.selectionObj.nodes) {
43603 if (this.selectionObj.nodes.hasOwnProperty(nodeId)) {
43604 this.selectionObj.nodes[nodeId].unselect();
43605 }
43606 }
43607
43608 for (var edgeId in this.selectionObj.edges) {
43609 if (this.selectionObj.edges.hasOwnProperty(edgeId)) {
43610 this.selectionObj.edges[edgeId].unselect();
43611 }
43612 }
43613
43614 this.selectionObj = {
43615 nodes: {},
43616 edges: {}
43617 };
43618 }
43619 /**
43620 * return the number of selected nodes
43621 *
43622 * @returns {number}
43623 * @private
43624 */
43625
43626 }, {
43627 key: "_getSelectedNodeCount",
43628 value: function _getSelectedNodeCount() {
43629 var count = 0;
43630
43631 for (var nodeId in this.selectionObj.nodes) {
43632 if (this.selectionObj.nodes.hasOwnProperty(nodeId)) {
43633 count += 1;
43634 }
43635 }
43636
43637 return count;
43638 }
43639 /**
43640 * return the selected node
43641 *
43642 * @returns {number}
43643 * @private
43644 */
43645
43646 }, {
43647 key: "_getSelectedNode",
43648 value: function _getSelectedNode() {
43649 for (var nodeId in this.selectionObj.nodes) {
43650 if (this.selectionObj.nodes.hasOwnProperty(nodeId)) {
43651 return this.selectionObj.nodes[nodeId];
43652 }
43653 }
43654
43655 return undefined;
43656 }
43657 /**
43658 * return the selected edge
43659 *
43660 * @returns {number}
43661 * @private
43662 */
43663
43664 }, {
43665 key: "_getSelectedEdge",
43666 value: function _getSelectedEdge() {
43667 for (var edgeId in this.selectionObj.edges) {
43668 if (this.selectionObj.edges.hasOwnProperty(edgeId)) {
43669 return this.selectionObj.edges[edgeId];
43670 }
43671 }
43672
43673 return undefined;
43674 }
43675 /**
43676 * return the number of selected edges
43677 *
43678 * @returns {number}
43679 * @private
43680 */
43681
43682 }, {
43683 key: "_getSelectedEdgeCount",
43684 value: function _getSelectedEdgeCount() {
43685 var count = 0;
43686
43687 for (var edgeId in this.selectionObj.edges) {
43688 if (this.selectionObj.edges.hasOwnProperty(edgeId)) {
43689 count += 1;
43690 }
43691 }
43692
43693 return count;
43694 }
43695 /**
43696 * return the number of selected objects.
43697 *
43698 * @returns {number}
43699 * @private
43700 */
43701
43702 }, {
43703 key: "_getSelectedObjectCount",
43704 value: function _getSelectedObjectCount() {
43705 var count = 0;
43706
43707 for (var nodeId in this.selectionObj.nodes) {
43708 if (this.selectionObj.nodes.hasOwnProperty(nodeId)) {
43709 count += 1;
43710 }
43711 }
43712
43713 for (var edgeId in this.selectionObj.edges) {
43714 if (this.selectionObj.edges.hasOwnProperty(edgeId)) {
43715 count += 1;
43716 }
43717 }
43718
43719 return count;
43720 }
43721 /**
43722 * Check if anything is selected
43723 *
43724 * @returns {boolean}
43725 * @private
43726 */
43727
43728 }, {
43729 key: "_selectionIsEmpty",
43730 value: function _selectionIsEmpty() {
43731 for (var nodeId in this.selectionObj.nodes) {
43732 if (this.selectionObj.nodes.hasOwnProperty(nodeId)) {
43733 return false;
43734 }
43735 }
43736
43737 for (var edgeId in this.selectionObj.edges) {
43738 if (this.selectionObj.edges.hasOwnProperty(edgeId)) {
43739 return false;
43740 }
43741 }
43742
43743 return true;
43744 }
43745 /**
43746 * check if one of the selected nodes is a cluster.
43747 *
43748 * @returns {boolean}
43749 * @private
43750 */
43751
43752 }, {
43753 key: "_clusterInSelection",
43754 value: function _clusterInSelection() {
43755 for (var nodeId in this.selectionObj.nodes) {
43756 if (this.selectionObj.nodes.hasOwnProperty(nodeId)) {
43757 if (this.selectionObj.nodes[nodeId].clusterSize > 1) {
43758 return true;
43759 }
43760 }
43761 }
43762
43763 return false;
43764 }
43765 /**
43766 * select the edges connected to the node that is being selected
43767 *
43768 * @param {Node} node
43769 * @private
43770 */
43771
43772 }, {
43773 key: "_selectConnectedEdges",
43774 value: function _selectConnectedEdges(node) {
43775 for (var i = 0; i < node.edges.length; i++) {
43776 var edge = node.edges[i];
43777 edge.select();
43778
43779 this._addToSelection(edge);
43780 }
43781 }
43782 /**
43783 * select the edges connected to the node that is being selected
43784 *
43785 * @param {Node} node
43786 * @private
43787 */
43788
43789 }, {
43790 key: "_hoverConnectedEdges",
43791 value: function _hoverConnectedEdges(node) {
43792 for (var i = 0; i < node.edges.length; i++) {
43793 var edge = node.edges[i];
43794 edge.hover = true;
43795
43796 this._addToHover(edge);
43797 }
43798 }
43799 /**
43800 * unselect the edges connected to the node that is being selected
43801 *
43802 * @param {Node} node
43803 * @private
43804 */
43805
43806 }, {
43807 key: "_unselectConnectedEdges",
43808 value: function _unselectConnectedEdges(node) {
43809 for (var i = 0; i < node.edges.length; i++) {
43810 var edge = node.edges[i];
43811 edge.unselect();
43812
43813 this._removeFromSelection(edge);
43814 }
43815 }
43816 /**
43817 * Remove the highlight from a node or edge, in response to mouse movement
43818 *
43819 * @param {Event} event
43820 * @param {{x: number, y: number}} pointer object with the x and y screen coordinates of the mouse
43821 * @param {Node|vis.Edge} object
43822 * @private
43823 */
43824
43825 }, {
43826 key: "emitBlurEvent",
43827 value: function emitBlurEvent(event, pointer, object) {
43828 var properties = this._initBaseEvent(event, pointer);
43829
43830 if (object.hover === true) {
43831 object.hover = false;
43832
43833 if (object instanceof Node) {
43834 properties.node = object.id;
43835 this.body.emitter.emit("blurNode", properties);
43836 } else {
43837 properties.edge = object.id;
43838 this.body.emitter.emit("blurEdge", properties);
43839 }
43840 }
43841 }
43842 /**
43843 * Create the highlight for a node or edge, in response to mouse movement
43844 *
43845 * @param {Event} event
43846 * @param {{x: number, y: number}} pointer object with the x and y screen coordinates of the mouse
43847 * @param {Node|vis.Edge} object
43848 * @returns {boolean} hoverChanged
43849 * @private
43850 */
43851
43852 }, {
43853 key: "emitHoverEvent",
43854 value: function emitHoverEvent(event, pointer, object) {
43855 var properties = this._initBaseEvent(event, pointer);
43856
43857 var hoverChanged = false;
43858
43859 if (object.hover === false) {
43860 object.hover = true;
43861
43862 this._addToHover(object);
43863
43864 hoverChanged = true;
43865
43866 if (object instanceof Node) {
43867 properties.node = object.id;
43868 this.body.emitter.emit("hoverNode", properties);
43869 } else {
43870 properties.edge = object.id;
43871 this.body.emitter.emit("hoverEdge", properties);
43872 }
43873 }
43874
43875 return hoverChanged;
43876 }
43877 /**
43878 * Perform actions in response to a mouse movement.
43879 *
43880 * @param {Event} event
43881 * @param {{x: number, y: number}} pointer | object with the x and y screen coordinates of the mouse
43882 */
43883
43884 }, {
43885 key: "hoverObject",
43886 value: function hoverObject(event, pointer) {
43887 var object = this.getNodeAt(pointer);
43888
43889 if (object === undefined) {
43890 object = this.getEdgeAt(pointer);
43891 }
43892
43893 var hoverChanged = false; // remove all node hover highlights
43894
43895 for (var nodeId in this.hoverObj.nodes) {
43896 if (this.hoverObj.nodes.hasOwnProperty(nodeId)) {
43897 if (object === undefined || object instanceof Node && object.id != nodeId || object instanceof Edge) {
43898 this.emitBlurEvent(event, pointer, this.hoverObj.nodes[nodeId]);
43899 delete this.hoverObj.nodes[nodeId];
43900 hoverChanged = true;
43901 }
43902 }
43903 } // removing all edge hover highlights
43904
43905
43906 for (var edgeId in this.hoverObj.edges) {
43907 if (this.hoverObj.edges.hasOwnProperty(edgeId)) {
43908 // if the hover has been changed here it means that the node has been hovered over or off
43909 // we then do not use the emitBlurEvent method here.
43910 if (hoverChanged === true) {
43911 this.hoverObj.edges[edgeId].hover = false;
43912 delete this.hoverObj.edges[edgeId];
43913 } // if the blur remains the same and the object is undefined (mouse off) or another
43914 // edge has been hovered, or another node has been hovered we blur the edge.
43915 else if (object === undefined || object instanceof Edge && object.id != edgeId || object instanceof Node && !object.hover) {
43916 this.emitBlurEvent(event, pointer, this.hoverObj.edges[edgeId]);
43917 delete this.hoverObj.edges[edgeId];
43918 hoverChanged = true;
43919 }
43920 }
43921 }
43922
43923 if (object !== undefined) {
43924 var hoveredEdgesCount = Object.keys(this.hoverObj.edges).length;
43925 var hoveredNodesCount = Object.keys(this.hoverObj.nodes).length;
43926 var newOnlyHoveredEdge = object instanceof Edge && hoveredEdgesCount === 0 && hoveredNodesCount === 0;
43927 var newOnlyHoveredNode = object instanceof Node && hoveredEdgesCount === 0 && hoveredNodesCount === 0;
43928
43929 if (hoverChanged || newOnlyHoveredEdge || newOnlyHoveredNode) {
43930 hoverChanged = this.emitHoverEvent(event, pointer, object);
43931 }
43932
43933 if (object instanceof Node && this.options.hoverConnectedEdges === true) {
43934 this._hoverConnectedEdges(object);
43935 }
43936 }
43937
43938 if (hoverChanged === true) {
43939 this.body.emitter.emit('_requestRedraw');
43940 }
43941 }
43942 /**
43943 *
43944 * retrieve the currently selected objects
43945 * @return {{nodes: Array.<string>, edges: Array.<string>}} selection
43946 */
43947
43948 }, {
43949 key: "getSelection",
43950 value: function getSelection() {
43951 var nodeIds = this.getSelectedNodes();
43952 var edgeIds = this.getSelectedEdges();
43953 return {
43954 nodes: nodeIds,
43955 edges: edgeIds
43956 };
43957 }
43958 /**
43959 *
43960 * retrieve the currently selected nodes
43961 * @return {string[]} selection An array with the ids of the
43962 * selected nodes.
43963 */
43964
43965 }, {
43966 key: "getSelectedNodes",
43967 value: function getSelectedNodes() {
43968 var idArray = [];
43969
43970 if (this.options.selectable === true) {
43971 for (var nodeId in this.selectionObj.nodes) {
43972 if (this.selectionObj.nodes.hasOwnProperty(nodeId)) {
43973 idArray.push(this.selectionObj.nodes[nodeId].id);
43974 }
43975 }
43976 }
43977
43978 return idArray;
43979 }
43980 /**
43981 *
43982 * retrieve the currently selected edges
43983 * @return {Array} selection An array with the ids of the
43984 * selected nodes.
43985 */
43986
43987 }, {
43988 key: "getSelectedEdges",
43989 value: function getSelectedEdges() {
43990 var idArray = [];
43991
43992 if (this.options.selectable === true) {
43993 for (var edgeId in this.selectionObj.edges) {
43994 if (this.selectionObj.edges.hasOwnProperty(edgeId)) {
43995 idArray.push(this.selectionObj.edges[edgeId].id);
43996 }
43997 }
43998 }
43999
44000 return idArray;
44001 }
44002 /**
44003 * Updates the current selection
44004 * @param {{nodes: Array.<string>, edges: Array.<string>}} selection
44005 * @param {Object} options Options
44006 */
44007
44008 }, {
44009 key: "setSelection",
44010 value: function setSelection(selection) {
44011 var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
44012 var i, id;
44013 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
44014
44015 if (options.unselectAll || options.unselectAll === undefined) {
44016 this.unselectAll();
44017 }
44018
44019 if (selection.nodes) {
44020 for (i = 0; i < selection.nodes.length; i++) {
44021 id = selection.nodes[i];
44022 var node = this.body.nodes[id];
44023
44024 if (!node) {
44025 throw new RangeError('Node with id "' + id + '" not found');
44026 } // don't select edges with it
44027
44028
44029 this.selectObject(node, options.highlightEdges);
44030 }
44031 }
44032
44033 if (selection.edges) {
44034 for (i = 0; i < selection.edges.length; i++) {
44035 id = selection.edges[i];
44036 var edge = this.body.edges[id];
44037
44038 if (!edge) {
44039 throw new RangeError('Edge with id "' + id + '" not found');
44040 }
44041
44042 this.selectObject(edge);
44043 }
44044 }
44045
44046 this.body.emitter.emit('_requestRedraw');
44047 }
44048 /**
44049 * select zero or more nodes with the option to highlight edges
44050 * @param {number[] | string[]} selection An array with the ids of the
44051 * selected nodes.
44052 * @param {boolean} [highlightEdges]
44053 */
44054
44055 }, {
44056 key: "selectNodes",
44057 value: function selectNodes(selection) {
44058 var highlightEdges = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
44059 if (!selection || selection.length === undefined) throw 'Selection must be an array with ids';
44060 this.setSelection({
44061 nodes: selection
44062 }, {
44063 highlightEdges: highlightEdges
44064 });
44065 }
44066 /**
44067 * select zero or more edges
44068 * @param {number[] | string[]} selection An array with the ids of the
44069 * selected nodes.
44070 */
44071
44072 }, {
44073 key: "selectEdges",
44074 value: function selectEdges(selection) {
44075 if (!selection || selection.length === undefined) throw 'Selection must be an array with ids';
44076 this.setSelection({
44077 edges: selection
44078 });
44079 }
44080 /**
44081 * Validate the selection: remove ids of nodes which no longer exist
44082 * @private
44083 */
44084
44085 }, {
44086 key: "updateSelection",
44087 value: function updateSelection() {
44088 for (var nodeId in this.selectionObj.nodes) {
44089 if (this.selectionObj.nodes.hasOwnProperty(nodeId)) {
44090 if (!this.body.nodes.hasOwnProperty(nodeId)) {
44091 delete this.selectionObj.nodes[nodeId];
44092 }
44093 }
44094 }
44095
44096 for (var edgeId in this.selectionObj.edges) {
44097 if (this.selectionObj.edges.hasOwnProperty(edgeId)) {
44098 if (!this.body.edges.hasOwnProperty(edgeId)) {
44099 delete this.selectionObj.edges[edgeId];
44100 }
44101 }
44102 }
44103 }
44104 /**
44105 * Determine all the visual elements clicked which are on the given point.
44106 *
44107 * All elements are returned; this includes nodes, edges and their labels.
44108 * The order returned is from highest to lowest, i.e. element 0 of the return
44109 * value is the topmost item clicked on.
44110 *
44111 * The return value consists of an array of the following possible elements:
44112 *
44113 * - `{nodeId:number}` - node with given id clicked on
44114 * - `{nodeId:number, labelId:0}` - label of node with given id clicked on
44115 * - `{edgeId:number}` - edge with given id clicked on
44116 * - `{edge:number, labelId:0}` - label of edge with given id clicked on
44117 *
44118 * ## NOTES
44119 *
44120 * - Currently, there is only one label associated with a node or an edge,
44121 * but this is expected to change somewhere in the future.
44122 * - Since there is no z-indexing yet, it is not really possible to set the nodes and
44123 * edges in the correct order. For the time being, nodes come first.
44124 *
44125 * @param {point} pointer mouse position in screen coordinates
44126 * @returns {Array.<nodeClickItem|nodeLabelClickItem|edgeClickItem|edgeLabelClickItem>}
44127 * @private
44128 */
44129
44130 }, {
44131 key: "getClickedItems",
44132 value: function getClickedItems(pointer) {
44133 var point = this.canvas.DOMtoCanvas(pointer);
44134 var items = []; // Note reverse order; we want the topmost clicked items to be first in the array
44135 // Also note that selected nodes are disregarded here; these normally display on top
44136
44137 var nodeIndices = this.body.nodeIndices;
44138 var nodes = this.body.nodes;
44139
44140 for (var i = nodeIndices.length - 1; i >= 0; i--) {
44141 var node = nodes[nodeIndices[i]];
44142 var ret = node.getItemsOnPoint(point);
44143 items.push.apply(items, ret); // Append the return value to the running list.
44144 }
44145
44146 var edgeIndices = this.body.edgeIndices;
44147 var edges = this.body.edges;
44148
44149 for (var _i = edgeIndices.length - 1; _i >= 0; _i--) {
44150 var edge = edges[edgeIndices[_i]];
44151
44152 var _ret = edge.getItemsOnPoint(point);
44153
44154 items.push.apply(items, _ret); // Append the return value to the running list.
44155 }
44156
44157 return items;
44158 }
44159 }]);
44160
44161 return SelectionHandler;
44162 }();
44163
44164 var nativeSort = [].sort;
44165 var test$3 = [1, 2, 3]; // IE8-
44166
44167 var FAILS_ON_UNDEFINED = fails(function () {
44168 test$3.sort(undefined);
44169 }); // V8 bug
44170
44171 var FAILS_ON_NULL = fails(function () {
44172 test$3.sort(null);
44173 }); // Old WebKit
44174
44175 var SLOPPY_METHOD$2 = sloppyArrayMethod('sort');
44176 var FORCED$3 = FAILS_ON_UNDEFINED || !FAILS_ON_NULL || SLOPPY_METHOD$2; // `Array.prototype.sort` method
44177 // https://tc39.github.io/ecma262/#sec-array.prototype.sort
44178
44179 _export({
44180 target: 'Array',
44181 proto: true,
44182 forced: FORCED$3
44183 }, {
44184 sort: function sort(comparefn) {
44185 return comparefn === undefined ? nativeSort.call(toObject(this)) : nativeSort.call(toObject(this), aFunction$1(comparefn));
44186 }
44187 });
44188
44189 var timsort = createCommonjsModule(function (module, exports) {
44190 /****
44191 * The MIT License
44192 *
44193 * Copyright (c) 2015 Marco Ziccardi
44194 *
44195 * Permission is hereby granted, free of charge, to any person obtaining a copy
44196 * of this software and associated documentation files (the "Software"), to deal
44197 * in the Software without restriction, including without limitation the rights
44198 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
44199 * copies of the Software, and to permit persons to whom the Software is
44200 * furnished to do so, subject to the following conditions:
44201 *
44202 * The above copyright notice and this permission notice shall be included in
44203 * all copies or substantial portions of the Software.
44204 *
44205 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
44206 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
44207 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
44208 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
44209 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
44210 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
44211 * THE SOFTWARE.
44212 *
44213 ****/
44214 (function (global, factory) {
44215 {
44216 factory(exports);
44217 }
44218 })(commonjsGlobal, function (exports) {
44219
44220 exports.__esModule = true;
44221 exports.sort = sort;
44222
44223 function _classCallCheck(instance, Constructor) {
44224 if (!(instance instanceof Constructor)) {
44225 throw new TypeError('Cannot call a class as a function');
44226 }
44227 }
44228
44229 var DEFAULT_MIN_MERGE = 32;
44230 var DEFAULT_MIN_GALLOPING = 7;
44231 var DEFAULT_TMP_STORAGE_LENGTH = 256;
44232 var POWERS_OF_TEN = [1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9];
44233
44234 function log10(x) {
44235 if (x < 1e5) {
44236 if (x < 1e2) {
44237 return x < 1e1 ? 0 : 1;
44238 }
44239
44240 if (x < 1e4) {
44241 return x < 1e3 ? 2 : 3;
44242 }
44243
44244 return 4;
44245 }
44246
44247 if (x < 1e7) {
44248 return x < 1e6 ? 5 : 6;
44249 }
44250
44251 if (x < 1e9) {
44252 return x < 1e8 ? 7 : 8;
44253 }
44254
44255 return 9;
44256 }
44257
44258 function alphabeticalCompare(a, b) {
44259 if (a === b) {
44260 return 0;
44261 }
44262
44263 if (~~a === a && ~~b === b) {
44264 if (a === 0 || b === 0) {
44265 return a < b ? -1 : 1;
44266 }
44267
44268 if (a < 0 || b < 0) {
44269 if (b >= 0) {
44270 return -1;
44271 }
44272
44273 if (a >= 0) {
44274 return 1;
44275 }
44276
44277 a = -a;
44278 b = -b;
44279 }
44280
44281 var al = log10(a);
44282 var bl = log10(b);
44283 var t = 0;
44284
44285 if (al < bl) {
44286 a *= POWERS_OF_TEN[bl - al - 1];
44287 b /= 10;
44288 t = -1;
44289 } else if (al > bl) {
44290 b *= POWERS_OF_TEN[al - bl - 1];
44291 a /= 10;
44292 t = 1;
44293 }
44294
44295 if (a === b) {
44296 return t;
44297 }
44298
44299 return a < b ? -1 : 1;
44300 }
44301
44302 var aStr = String(a);
44303 var bStr = String(b);
44304
44305 if (aStr === bStr) {
44306 return 0;
44307 }
44308
44309 return aStr < bStr ? -1 : 1;
44310 }
44311
44312 function minRunLength(n) {
44313 var r = 0;
44314
44315 while (n >= DEFAULT_MIN_MERGE) {
44316 r |= n & 1;
44317 n >>= 1;
44318 }
44319
44320 return n + r;
44321 }
44322
44323 function makeAscendingRun(array, lo, hi, compare) {
44324 var runHi = lo + 1;
44325
44326 if (runHi === hi) {
44327 return 1;
44328 }
44329
44330 if (compare(array[runHi++], array[lo]) < 0) {
44331 while (runHi < hi && compare(array[runHi], array[runHi - 1]) < 0) {
44332 runHi++;
44333 }
44334
44335 reverseRun(array, lo, runHi);
44336 } else {
44337 while (runHi < hi && compare(array[runHi], array[runHi - 1]) >= 0) {
44338 runHi++;
44339 }
44340 }
44341
44342 return runHi - lo;
44343 }
44344
44345 function reverseRun(array, lo, hi) {
44346 hi--;
44347
44348 while (lo < hi) {
44349 var t = array[lo];
44350 array[lo++] = array[hi];
44351 array[hi--] = t;
44352 }
44353 }
44354
44355 function binaryInsertionSort(array, lo, hi, start, compare) {
44356 if (start === lo) {
44357 start++;
44358 }
44359
44360 for (; start < hi; start++) {
44361 var pivot = array[start];
44362 var left = lo;
44363 var right = start;
44364
44365 while (left < right) {
44366 var mid = left + right >>> 1;
44367
44368 if (compare(pivot, array[mid]) < 0) {
44369 right = mid;
44370 } else {
44371 left = mid + 1;
44372 }
44373 }
44374
44375 var n = start - left;
44376
44377 switch (n) {
44378 case 3:
44379 array[left + 3] = array[left + 2];
44380
44381 case 2:
44382 array[left + 2] = array[left + 1];
44383
44384 case 1:
44385 array[left + 1] = array[left];
44386 break;
44387
44388 default:
44389 while (n > 0) {
44390 array[left + n] = array[left + n - 1];
44391 n--;
44392 }
44393
44394 }
44395
44396 array[left] = pivot;
44397 }
44398 }
44399
44400 function gallopLeft(value, array, start, length, hint, compare) {
44401 var lastOffset = 0;
44402 var maxOffset = 0;
44403 var offset = 1;
44404
44405 if (compare(value, array[start + hint]) > 0) {
44406 maxOffset = length - hint;
44407
44408 while (offset < maxOffset && compare(value, array[start + hint + offset]) > 0) {
44409 lastOffset = offset;
44410 offset = (offset << 1) + 1;
44411
44412 if (offset <= 0) {
44413 offset = maxOffset;
44414 }
44415 }
44416
44417 if (offset > maxOffset) {
44418 offset = maxOffset;
44419 }
44420
44421 lastOffset += hint;
44422 offset += hint;
44423 } else {
44424 maxOffset = hint + 1;
44425
44426 while (offset < maxOffset && compare(value, array[start + hint - offset]) <= 0) {
44427 lastOffset = offset;
44428 offset = (offset << 1) + 1;
44429
44430 if (offset <= 0) {
44431 offset = maxOffset;
44432 }
44433 }
44434
44435 if (offset > maxOffset) {
44436 offset = maxOffset;
44437 }
44438
44439 var tmp = lastOffset;
44440 lastOffset = hint - offset;
44441 offset = hint - tmp;
44442 }
44443
44444 lastOffset++;
44445
44446 while (lastOffset < offset) {
44447 var m = lastOffset + (offset - lastOffset >>> 1);
44448
44449 if (compare(value, array[start + m]) > 0) {
44450 lastOffset = m + 1;
44451 } else {
44452 offset = m;
44453 }
44454 }
44455
44456 return offset;
44457 }
44458
44459 function gallopRight(value, array, start, length, hint, compare) {
44460 var lastOffset = 0;
44461 var maxOffset = 0;
44462 var offset = 1;
44463
44464 if (compare(value, array[start + hint]) < 0) {
44465 maxOffset = hint + 1;
44466
44467 while (offset < maxOffset && compare(value, array[start + hint - offset]) < 0) {
44468 lastOffset = offset;
44469 offset = (offset << 1) + 1;
44470
44471 if (offset <= 0) {
44472 offset = maxOffset;
44473 }
44474 }
44475
44476 if (offset > maxOffset) {
44477 offset = maxOffset;
44478 }
44479
44480 var tmp = lastOffset;
44481 lastOffset = hint - offset;
44482 offset = hint - tmp;
44483 } else {
44484 maxOffset = length - hint;
44485
44486 while (offset < maxOffset && compare(value, array[start + hint + offset]) >= 0) {
44487 lastOffset = offset;
44488 offset = (offset << 1) + 1;
44489
44490 if (offset <= 0) {
44491 offset = maxOffset;
44492 }
44493 }
44494
44495 if (offset > maxOffset) {
44496 offset = maxOffset;
44497 }
44498
44499 lastOffset += hint;
44500 offset += hint;
44501 }
44502
44503 lastOffset++;
44504
44505 while (lastOffset < offset) {
44506 var m = lastOffset + (offset - lastOffset >>> 1);
44507
44508 if (compare(value, array[start + m]) < 0) {
44509 offset = m;
44510 } else {
44511 lastOffset = m + 1;
44512 }
44513 }
44514
44515 return offset;
44516 }
44517
44518 var TimSort = function () {
44519 function TimSort(array, compare) {
44520 _classCallCheck(this, TimSort);
44521
44522 this.array = null;
44523 this.compare = null;
44524 this.minGallop = DEFAULT_MIN_GALLOPING;
44525 this.length = 0;
44526 this.tmpStorageLength = DEFAULT_TMP_STORAGE_LENGTH;
44527 this.stackLength = 0;
44528 this.runStart = null;
44529 this.runLength = null;
44530 this.stackSize = 0;
44531 this.array = array;
44532 this.compare = compare;
44533 this.length = array.length;
44534
44535 if (this.length < 2 * DEFAULT_TMP_STORAGE_LENGTH) {
44536 this.tmpStorageLength = this.length >>> 1;
44537 }
44538
44539 this.tmp = new Array(this.tmpStorageLength);
44540 this.stackLength = this.length < 120 ? 5 : this.length < 1542 ? 10 : this.length < 119151 ? 19 : 40;
44541 this.runStart = new Array(this.stackLength);
44542 this.runLength = new Array(this.stackLength);
44543 }
44544
44545 TimSort.prototype.pushRun = function pushRun(runStart, runLength) {
44546 this.runStart[this.stackSize] = runStart;
44547 this.runLength[this.stackSize] = runLength;
44548 this.stackSize += 1;
44549 };
44550
44551 TimSort.prototype.mergeRuns = function mergeRuns() {
44552 while (this.stackSize > 1) {
44553 var n = this.stackSize - 2;
44554
44555 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]) {
44556 if (this.runLength[n - 1] < this.runLength[n + 1]) {
44557 n--;
44558 }
44559 } else if (this.runLength[n] > this.runLength[n + 1]) {
44560 break;
44561 }
44562
44563 this.mergeAt(n);
44564 }
44565 };
44566
44567 TimSort.prototype.forceMergeRuns = function forceMergeRuns() {
44568 while (this.stackSize > 1) {
44569 var n = this.stackSize - 2;
44570
44571 if (n > 0 && this.runLength[n - 1] < this.runLength[n + 1]) {
44572 n--;
44573 }
44574
44575 this.mergeAt(n);
44576 }
44577 };
44578
44579 TimSort.prototype.mergeAt = function mergeAt(i) {
44580 var compare = this.compare;
44581 var array = this.array;
44582 var start1 = this.runStart[i];
44583 var length1 = this.runLength[i];
44584 var start2 = this.runStart[i + 1];
44585 var length2 = this.runLength[i + 1];
44586 this.runLength[i] = length1 + length2;
44587
44588 if (i === this.stackSize - 3) {
44589 this.runStart[i + 1] = this.runStart[i + 2];
44590 this.runLength[i + 1] = this.runLength[i + 2];
44591 }
44592
44593 this.stackSize--;
44594 var k = gallopRight(array[start2], array, start1, length1, 0, compare);
44595 start1 += k;
44596 length1 -= k;
44597
44598 if (length1 === 0) {
44599 return;
44600 }
44601
44602 length2 = gallopLeft(array[start1 + length1 - 1], array, start2, length2, length2 - 1, compare);
44603
44604 if (length2 === 0) {
44605 return;
44606 }
44607
44608 if (length1 <= length2) {
44609 this.mergeLow(start1, length1, start2, length2);
44610 } else {
44611 this.mergeHigh(start1, length1, start2, length2);
44612 }
44613 };
44614
44615 TimSort.prototype.mergeLow = function mergeLow(start1, length1, start2, length2) {
44616 var compare = this.compare;
44617 var array = this.array;
44618 var tmp = this.tmp;
44619 var i = 0;
44620
44621 for (i = 0; i < length1; i++) {
44622 tmp[i] = array[start1 + i];
44623 }
44624
44625 var cursor1 = 0;
44626 var cursor2 = start2;
44627 var dest = start1;
44628 array[dest++] = array[cursor2++];
44629
44630 if (--length2 === 0) {
44631 for (i = 0; i < length1; i++) {
44632 array[dest + i] = tmp[cursor1 + i];
44633 }
44634
44635 return;
44636 }
44637
44638 if (length1 === 1) {
44639 for (i = 0; i < length2; i++) {
44640 array[dest + i] = array[cursor2 + i];
44641 }
44642
44643 array[dest + length2] = tmp[cursor1];
44644 return;
44645 }
44646
44647 var minGallop = this.minGallop;
44648
44649 while (true) {
44650 var count1 = 0;
44651 var count2 = 0;
44652 var exit = false;
44653
44654 do {
44655 if (compare(array[cursor2], tmp[cursor1]) < 0) {
44656 array[dest++] = array[cursor2++];
44657 count2++;
44658 count1 = 0;
44659
44660 if (--length2 === 0) {
44661 exit = true;
44662 break;
44663 }
44664 } else {
44665 array[dest++] = tmp[cursor1++];
44666 count1++;
44667 count2 = 0;
44668
44669 if (--length1 === 1) {
44670 exit = true;
44671 break;
44672 }
44673 }
44674 } while ((count1 | count2) < minGallop);
44675
44676 if (exit) {
44677 break;
44678 }
44679
44680 do {
44681 count1 = gallopRight(array[cursor2], tmp, cursor1, length1, 0, compare);
44682
44683 if (count1 !== 0) {
44684 for (i = 0; i < count1; i++) {
44685 array[dest + i] = tmp[cursor1 + i];
44686 }
44687
44688 dest += count1;
44689 cursor1 += count1;
44690 length1 -= count1;
44691
44692 if (length1 <= 1) {
44693 exit = true;
44694 break;
44695 }
44696 }
44697
44698 array[dest++] = array[cursor2++];
44699
44700 if (--length2 === 0) {
44701 exit = true;
44702 break;
44703 }
44704
44705 count2 = gallopLeft(tmp[cursor1], array, cursor2, length2, 0, compare);
44706
44707 if (count2 !== 0) {
44708 for (i = 0; i < count2; i++) {
44709 array[dest + i] = array[cursor2 + i];
44710 }
44711
44712 dest += count2;
44713 cursor2 += count2;
44714 length2 -= count2;
44715
44716 if (length2 === 0) {
44717 exit = true;
44718 break;
44719 }
44720 }
44721
44722 array[dest++] = tmp[cursor1++];
44723
44724 if (--length1 === 1) {
44725 exit = true;
44726 break;
44727 }
44728
44729 minGallop--;
44730 } while (count1 >= DEFAULT_MIN_GALLOPING || count2 >= DEFAULT_MIN_GALLOPING);
44731
44732 if (exit) {
44733 break;
44734 }
44735
44736 if (minGallop < 0) {
44737 minGallop = 0;
44738 }
44739
44740 minGallop += 2;
44741 }
44742
44743 this.minGallop = minGallop;
44744
44745 if (minGallop < 1) {
44746 this.minGallop = 1;
44747 }
44748
44749 if (length1 === 1) {
44750 for (i = 0; i < length2; i++) {
44751 array[dest + i] = array[cursor2 + i];
44752 }
44753
44754 array[dest + length2] = tmp[cursor1];
44755 } else if (length1 === 0) {
44756 throw new Error('mergeLow preconditions were not respected');
44757 } else {
44758 for (i = 0; i < length1; i++) {
44759 array[dest + i] = tmp[cursor1 + i];
44760 }
44761 }
44762 };
44763
44764 TimSort.prototype.mergeHigh = function mergeHigh(start1, length1, start2, length2) {
44765 var compare = this.compare;
44766 var array = this.array;
44767 var tmp = this.tmp;
44768 var i = 0;
44769
44770 for (i = 0; i < length2; i++) {
44771 tmp[i] = array[start2 + i];
44772 }
44773
44774 var cursor1 = start1 + length1 - 1;
44775 var cursor2 = length2 - 1;
44776 var dest = start2 + length2 - 1;
44777 var customCursor = 0;
44778 var customDest = 0;
44779 array[dest--] = array[cursor1--];
44780
44781 if (--length1 === 0) {
44782 customCursor = dest - (length2 - 1);
44783
44784 for (i = 0; i < length2; i++) {
44785 array[customCursor + i] = tmp[i];
44786 }
44787
44788 return;
44789 }
44790
44791 if (length2 === 1) {
44792 dest -= length1;
44793 cursor1 -= length1;
44794 customDest = dest + 1;
44795 customCursor = cursor1 + 1;
44796
44797 for (i = length1 - 1; i >= 0; i--) {
44798 array[customDest + i] = array[customCursor + i];
44799 }
44800
44801 array[dest] = tmp[cursor2];
44802 return;
44803 }
44804
44805 var minGallop = this.minGallop;
44806
44807 while (true) {
44808 var count1 = 0;
44809 var count2 = 0;
44810 var exit = false;
44811
44812 do {
44813 if (compare(tmp[cursor2], array[cursor1]) < 0) {
44814 array[dest--] = array[cursor1--];
44815 count1++;
44816 count2 = 0;
44817
44818 if (--length1 === 0) {
44819 exit = true;
44820 break;
44821 }
44822 } else {
44823 array[dest--] = tmp[cursor2--];
44824 count2++;
44825 count1 = 0;
44826
44827 if (--length2 === 1) {
44828 exit = true;
44829 break;
44830 }
44831 }
44832 } while ((count1 | count2) < minGallop);
44833
44834 if (exit) {
44835 break;
44836 }
44837
44838 do {
44839 count1 = length1 - gallopRight(tmp[cursor2], array, start1, length1, length1 - 1, compare);
44840
44841 if (count1 !== 0) {
44842 dest -= count1;
44843 cursor1 -= count1;
44844 length1 -= count1;
44845 customDest = dest + 1;
44846 customCursor = cursor1 + 1;
44847
44848 for (i = count1 - 1; i >= 0; i--) {
44849 array[customDest + i] = array[customCursor + i];
44850 }
44851
44852 if (length1 === 0) {
44853 exit = true;
44854 break;
44855 }
44856 }
44857
44858 array[dest--] = tmp[cursor2--];
44859
44860 if (--length2 === 1) {
44861 exit = true;
44862 break;
44863 }
44864
44865 count2 = length2 - gallopLeft(array[cursor1], tmp, 0, length2, length2 - 1, compare);
44866
44867 if (count2 !== 0) {
44868 dest -= count2;
44869 cursor2 -= count2;
44870 length2 -= count2;
44871 customDest = dest + 1;
44872 customCursor = cursor2 + 1;
44873
44874 for (i = 0; i < count2; i++) {
44875 array[customDest + i] = tmp[customCursor + i];
44876 }
44877
44878 if (length2 <= 1) {
44879 exit = true;
44880 break;
44881 }
44882 }
44883
44884 array[dest--] = array[cursor1--];
44885
44886 if (--length1 === 0) {
44887 exit = true;
44888 break;
44889 }
44890
44891 minGallop--;
44892 } while (count1 >= DEFAULT_MIN_GALLOPING || count2 >= DEFAULT_MIN_GALLOPING);
44893
44894 if (exit) {
44895 break;
44896 }
44897
44898 if (minGallop < 0) {
44899 minGallop = 0;
44900 }
44901
44902 minGallop += 2;
44903 }
44904
44905 this.minGallop = minGallop;
44906
44907 if (minGallop < 1) {
44908 this.minGallop = 1;
44909 }
44910
44911 if (length2 === 1) {
44912 dest -= length1;
44913 cursor1 -= length1;
44914 customDest = dest + 1;
44915 customCursor = cursor1 + 1;
44916
44917 for (i = length1 - 1; i >= 0; i--) {
44918 array[customDest + i] = array[customCursor + i];
44919 }
44920
44921 array[dest] = tmp[cursor2];
44922 } else if (length2 === 0) {
44923 throw new Error('mergeHigh preconditions were not respected');
44924 } else {
44925 customCursor = dest - (length2 - 1);
44926
44927 for (i = 0; i < length2; i++) {
44928 array[customCursor + i] = tmp[i];
44929 }
44930 }
44931 };
44932
44933 return TimSort;
44934 }();
44935
44936 function sort(array, compare, lo, hi) {
44937 if (!Array.isArray(array)) {
44938 throw new TypeError('Can only sort arrays');
44939 }
44940
44941 if (!compare) {
44942 compare = alphabeticalCompare;
44943 } else if (typeof compare !== 'function') {
44944 hi = lo;
44945 lo = compare;
44946 compare = alphabeticalCompare;
44947 }
44948
44949 if (!lo) {
44950 lo = 0;
44951 }
44952
44953 if (!hi) {
44954 hi = array.length;
44955 }
44956
44957 var remaining = hi - lo;
44958
44959 if (remaining < 2) {
44960 return;
44961 }
44962
44963 var runLength = 0;
44964
44965 if (remaining < DEFAULT_MIN_MERGE) {
44966 runLength = makeAscendingRun(array, lo, hi, compare);
44967 binaryInsertionSort(array, lo, hi, lo + runLength, compare);
44968 return;
44969 }
44970
44971 var ts = new TimSort(array, compare);
44972 var minRun = minRunLength(remaining);
44973
44974 do {
44975 runLength = makeAscendingRun(array, lo, hi, compare);
44976
44977 if (runLength < minRun) {
44978 var force = remaining;
44979
44980 if (force > minRun) {
44981 force = minRun;
44982 }
44983
44984 binaryInsertionSort(array, lo, lo + force, lo + runLength, compare);
44985 runLength = force;
44986 }
44987
44988 ts.pushRun(lo, runLength);
44989 ts.mergeRuns();
44990 remaining -= runLength;
44991 lo += runLength;
44992 } while (remaining !== 0);
44993
44994 ts.forceMergeRuns();
44995 }
44996 });
44997 });
44998 unwrapExports(timsort);
44999
45000 var timsort$1 = timsort;
45001 var timsort_1 = timsort$1.sort;
45002
45003 /**
45004 * Interface definition for direction strategy classes.
45005 *
45006 * This class describes the interface for the Strategy
45007 * pattern classes used to differentiate horizontal and vertical
45008 * direction of hierarchical results.
45009 *
45010 * For a given direction, one coordinate will be 'fixed', meaning that it is
45011 * determined by level.
45012 * The other coordinate is 'unfixed', meaning that the nodes on a given level
45013 * can still move along that coordinate. So:
45014 *
45015 * - `vertical` layout: `x` unfixed, `y` fixed per level
45016 * - `horizontal` layout: `x` fixed per level, `y` unfixed
45017 *
45018 * The local methods are stubs and should be regarded as abstract.
45019 * Derived classes **must** implement all the methods themselves.
45020 *
45021 * @private
45022 */
45023
45024 var DirectionInterface =
45025 /*#__PURE__*/
45026 function () {
45027 function DirectionInterface() {
45028 _classCallCheck(this, DirectionInterface);
45029 }
45030
45031 _createClass(DirectionInterface, [{
45032 key: "abstract",
45033
45034 /** @ignore **/
45035 value: function abstract() {
45036 throw new Error("Can't instantiate abstract class!");
45037 }
45038 /**
45039 * This is a dummy call which is used to suppress the jsdoc errors of type:
45040 *
45041 * "'param' is assigned a value but never used"
45042 *
45043 * @ignore
45044 **/
45045
45046 }, {
45047 key: "fake_use",
45048 value: function fake_use() {} // Do nothing special
45049
45050 /**
45051 * Type to use to translate dynamic curves to, in the case of hierarchical layout.
45052 * Dynamic curves do not work for these.
45053 *
45054 * The value should be perpendicular to the actual direction of the layout.
45055 *
45056 * @return {string} Direction, either 'vertical' or 'horizontal'
45057 */
45058
45059 }, {
45060 key: "curveType",
45061 value: function curveType() {
45062 return this.abstract();
45063 }
45064 /**
45065 * Return the value of the coordinate that is not fixed for this direction.
45066 *
45067 * @param {Node} node The node to read
45068 * @return {number} Value of the unfixed coordinate
45069 */
45070
45071 }, {
45072 key: "getPosition",
45073 value: function getPosition(node) {
45074 this.fake_use(node);
45075 return this.abstract();
45076 }
45077 /**
45078 * Set the value of the coordinate that is not fixed for this direction.
45079 *
45080 * @param {Node} node The node to adjust
45081 * @param {number} position
45082 * @param {number} [level] if specified, the hierarchy level that this node should be fixed to
45083 */
45084
45085 }, {
45086 key: "setPosition",
45087 value: function setPosition(node, position) {
45088 var level = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : undefined;
45089 this.fake_use(node, position, level);
45090 this.abstract();
45091 }
45092 /**
45093 * Get the width of a tree.
45094 *
45095 * A `tree` here is a subset of nodes within the network which are not connected to other nodes,
45096 * only among themselves. In essence, it is a sub-network.
45097 *
45098 * @param {number} index The index number of a tree
45099 * @return {number} the width of a tree in the view coordinates
45100 */
45101
45102 }, {
45103 key: "getTreeSize",
45104 value: function getTreeSize(index) {
45105 this.fake_use(index);
45106 return this.abstract();
45107 }
45108 /**
45109 * Sort array of nodes on the unfixed coordinates.
45110 *
45111 * **Note:** chrome has non-stable sorting implementation, which
45112 * has a tendency to change the order of the array items,
45113 * even if the custom sort function returns 0.
45114 *
45115 * For this reason, an external sort implementation is used,
45116 * which has the added benefit of being faster than the standard
45117 * platforms implementation. This has been verified on `node.js`,
45118 * `firefox` and `chrome` (all linux).
45119 *
45120 * @param {Array.<Node>} nodeArray array of nodes to sort
45121 */
45122
45123 }, {
45124 key: "sort",
45125 value: function sort(nodeArray) {
45126 this.fake_use(nodeArray);
45127 this.abstract();
45128 }
45129 /**
45130 * Assign the fixed coordinate of the node to the given level
45131 *
45132 * @param {Node} node The node to adjust
45133 * @param {number} level The level to fix to
45134 */
45135
45136 }, {
45137 key: "fix",
45138 value: function fix(node, level) {
45139 this.fake_use(node, level);
45140 this.abstract();
45141 }
45142 /**
45143 * Add an offset to the unfixed coordinate of the given node.
45144 *
45145 * @param {NodeId} nodeId Id of the node to adjust
45146 * @param {number} diff Offset to add to the unfixed coordinate
45147 */
45148
45149 }, {
45150 key: "shift",
45151 value: function shift(nodeId, diff) {
45152 this.fake_use(nodeId, diff);
45153 this.abstract();
45154 }
45155 }]);
45156
45157 return DirectionInterface;
45158 }();
45159 /**
45160 * Vertical Strategy
45161 *
45162 * Coordinate `y` is fixed on levels, coordinate `x` is unfixed.
45163 *
45164 * @extends DirectionInterface
45165 * @private
45166 */
45167
45168
45169 var VerticalStrategy =
45170 /*#__PURE__*/
45171 function (_DirectionInterface) {
45172 _inherits(VerticalStrategy, _DirectionInterface);
45173
45174 /**
45175 * Constructor
45176 *
45177 * @param {Object} layout reference to the parent LayoutEngine instance.
45178 */
45179 function VerticalStrategy(layout) {
45180 var _this;
45181
45182 _classCallCheck(this, VerticalStrategy);
45183
45184 _this = _possibleConstructorReturn(this, _getPrototypeOf(VerticalStrategy).call(this));
45185 _this.layout = layout;
45186 return _this;
45187 }
45188 /** @inheritdoc */
45189
45190
45191 _createClass(VerticalStrategy, [{
45192 key: "curveType",
45193 value: function curveType() {
45194 return 'horizontal';
45195 }
45196 /** @inheritdoc */
45197
45198 }, {
45199 key: "getPosition",
45200 value: function getPosition(node) {
45201 return node.x;
45202 }
45203 /** @inheritdoc */
45204
45205 }, {
45206 key: "setPosition",
45207 value: function setPosition(node, position) {
45208 var level = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : undefined;
45209
45210 if (level !== undefined) {
45211 this.layout.hierarchical.addToOrdering(node, level);
45212 }
45213
45214 node.x = position;
45215 }
45216 /** @inheritdoc */
45217
45218 }, {
45219 key: "getTreeSize",
45220 value: function getTreeSize(index) {
45221 var res = this.layout.hierarchical.getTreeSize(this.layout.body.nodes, index);
45222 return {
45223 min: res.min_x,
45224 max: res.max_x
45225 };
45226 }
45227 /** @inheritdoc */
45228
45229 }, {
45230 key: "sort",
45231 value: function sort(nodeArray) {
45232 timsort_1(nodeArray, function (a, b) {
45233 return a.x - b.x;
45234 });
45235 }
45236 /** @inheritdoc */
45237
45238 }, {
45239 key: "fix",
45240 value: function fix(node, level) {
45241 node.y = this.layout.options.hierarchical.levelSeparation * level;
45242 node.options.fixed.y = true;
45243 }
45244 /** @inheritdoc */
45245
45246 }, {
45247 key: "shift",
45248 value: function shift(nodeId, diff) {
45249 this.layout.body.nodes[nodeId].x += diff;
45250 }
45251 }]);
45252
45253 return VerticalStrategy;
45254 }(DirectionInterface);
45255 /**
45256 * Horizontal Strategy
45257 *
45258 * Coordinate `x` is fixed on levels, coordinate `y` is unfixed.
45259 *
45260 * @extends DirectionInterface
45261 * @private
45262 */
45263
45264
45265 var HorizontalStrategy =
45266 /*#__PURE__*/
45267 function (_DirectionInterface2) {
45268 _inherits(HorizontalStrategy, _DirectionInterface2);
45269
45270 /**
45271 * Constructor
45272 *
45273 * @param {Object} layout reference to the parent LayoutEngine instance.
45274 */
45275 function HorizontalStrategy(layout) {
45276 var _this2;
45277
45278 _classCallCheck(this, HorizontalStrategy);
45279
45280 _this2 = _possibleConstructorReturn(this, _getPrototypeOf(HorizontalStrategy).call(this));
45281 _this2.layout = layout;
45282 return _this2;
45283 }
45284 /** @inheritdoc */
45285
45286
45287 _createClass(HorizontalStrategy, [{
45288 key: "curveType",
45289 value: function curveType() {
45290 return 'vertical';
45291 }
45292 /** @inheritdoc */
45293
45294 }, {
45295 key: "getPosition",
45296 value: function getPosition(node) {
45297 return node.y;
45298 }
45299 /** @inheritdoc */
45300
45301 }, {
45302 key: "setPosition",
45303 value: function setPosition(node, position) {
45304 var level = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : undefined;
45305
45306 if (level !== undefined) {
45307 this.layout.hierarchical.addToOrdering(node, level);
45308 }
45309
45310 node.y = position;
45311 }
45312 /** @inheritdoc */
45313
45314 }, {
45315 key: "getTreeSize",
45316 value: function getTreeSize(index) {
45317 var res = this.layout.hierarchical.getTreeSize(this.layout.body.nodes, index);
45318 return {
45319 min: res.min_y,
45320 max: res.max_y
45321 };
45322 }
45323 /** @inheritdoc */
45324
45325 }, {
45326 key: "sort",
45327 value: function sort(nodeArray) {
45328 timsort_1(nodeArray, function (a, b) {
45329 return a.y - b.y;
45330 });
45331 }
45332 /** @inheritdoc */
45333
45334 }, {
45335 key: "fix",
45336 value: function fix(node, level) {
45337 node.x = this.layout.options.hierarchical.levelSeparation * level;
45338 node.options.fixed.x = true;
45339 }
45340 /** @inheritdoc */
45341
45342 }, {
45343 key: "shift",
45344 value: function shift(nodeId, diff) {
45345 this.layout.body.nodes[nodeId].y += diff;
45346 }
45347 }]);
45348
45349 return HorizontalStrategy;
45350 }(DirectionInterface);
45351
45352 var nativeGetOwnPropertyNames = objectGetOwnPropertyNames.f;
45353 var toString$2 = {}.toString;
45354 var windowNames$1 = typeof window == 'object' && window && Object.getOwnPropertyNames ? Object.getOwnPropertyNames(window) : [];
45355
45356 var getWindowNames$1 = function (it) {
45357 try {
45358 return nativeGetOwnPropertyNames(it);
45359 } catch (error) {
45360 return windowNames$1.slice();
45361 }
45362 }; // fallback for IE11 buggy Object.getOwnPropertyNames with iframe and window
45363
45364
45365 var f$7 = function getOwnPropertyNames(it) {
45366 return windowNames$1 && toString$2.call(it) == '[object Window]' ? getWindowNames$1(it) : nativeGetOwnPropertyNames(toIndexedObject(it));
45367 };
45368
45369 var objectGetOwnPropertyNamesExternal = {
45370 f: f$7
45371 };
45372
45373 var f$8 = wellKnownSymbol;
45374 var wrappedWellKnownSymbol = {
45375 f: f$8
45376 };
45377
45378 var defineProperty$8 = objectDefineProperty.f;
45379
45380 var defineWellKnownSymbol = function (NAME) {
45381 var Symbol = path.Symbol || (path.Symbol = {});
45382 if (!has(Symbol, NAME)) defineProperty$8(Symbol, NAME, {
45383 value: wrappedWellKnownSymbol.f(NAME)
45384 });
45385 };
45386
45387 var $forEach$1 = arrayIteration.forEach;
45388 var HIDDEN$1 = sharedKey('hidden');
45389 var SYMBOL = 'Symbol';
45390 var PROTOTYPE$4 = 'prototype';
45391 var TO_PRIMITIVE$1 = wellKnownSymbol('toPrimitive');
45392 var setInternalState$2 = internalState.set;
45393 var getInternalState$2 = internalState.getterFor(SYMBOL);
45394 var ObjectPrototype$3 = Object[PROTOTYPE$4];
45395 var $Symbol$1 = global_1.Symbol;
45396 var JSON$1 = global_1.JSON;
45397 var nativeJSONStringify = JSON$1 && JSON$1.stringify;
45398 var nativeGetOwnPropertyDescriptor$1 = objectGetOwnPropertyDescriptor.f;
45399 var nativeDefineProperty$1 = objectDefineProperty.f;
45400 var nativeGetOwnPropertyNames$1 = objectGetOwnPropertyNamesExternal.f;
45401 var nativePropertyIsEnumerable$1 = objectPropertyIsEnumerable.f;
45402 var AllSymbols$1 = shared('symbols');
45403 var ObjectPrototypeSymbols = shared('op-symbols');
45404 var StringToSymbolRegistry = shared('string-to-symbol-registry');
45405 var SymbolToStringRegistry = shared('symbol-to-string-registry');
45406 var WellKnownSymbolsStore = shared('wks');
45407 var QObject$1 = global_1.QObject; // Don't use setters in Qt Script, https://github.com/zloirock/core-js/issues/173
45408
45409 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
45410
45411 var setSymbolDescriptor = descriptors && fails(function () {
45412 return objectCreate(nativeDefineProperty$1({}, 'a', {
45413 get: function () {
45414 return nativeDefineProperty$1(this, 'a', {
45415 value: 7
45416 }).a;
45417 }
45418 })).a != 7;
45419 }) ? function (O, P, Attributes) {
45420 var ObjectPrototypeDescriptor = nativeGetOwnPropertyDescriptor$1(ObjectPrototype$3, P);
45421 if (ObjectPrototypeDescriptor) delete ObjectPrototype$3[P];
45422 nativeDefineProperty$1(O, P, Attributes);
45423
45424 if (ObjectPrototypeDescriptor && O !== ObjectPrototype$3) {
45425 nativeDefineProperty$1(ObjectPrototype$3, P, ObjectPrototypeDescriptor);
45426 }
45427 } : nativeDefineProperty$1;
45428
45429 var wrap$1 = function (tag, description) {
45430 var symbol = AllSymbols$1[tag] = objectCreate($Symbol$1[PROTOTYPE$4]);
45431 setInternalState$2(symbol, {
45432 type: SYMBOL,
45433 tag: tag,
45434 description: description
45435 });
45436 if (!descriptors) symbol.description = description;
45437 return symbol;
45438 };
45439
45440 var isSymbol$1 = nativeSymbol && typeof $Symbol$1.iterator == 'symbol' ? function (it) {
45441 return typeof it == 'symbol';
45442 } : function (it) {
45443 return Object(it) instanceof $Symbol$1;
45444 };
45445
45446 var $defineProperty$1 = function defineProperty(O, P, Attributes) {
45447 if (O === ObjectPrototype$3) $defineProperty$1(ObjectPrototypeSymbols, P, Attributes);
45448 anObject(O);
45449 var key = toPrimitive(P, true);
45450 anObject(Attributes);
45451
45452 if (has(AllSymbols$1, key)) {
45453 if (!Attributes.enumerable) {
45454 if (!has(O, HIDDEN$1)) nativeDefineProperty$1(O, HIDDEN$1, createPropertyDescriptor(1, {}));
45455 O[HIDDEN$1][key] = true;
45456 } else {
45457 if (has(O, HIDDEN$1) && O[HIDDEN$1][key]) O[HIDDEN$1][key] = false;
45458 Attributes = objectCreate(Attributes, {
45459 enumerable: createPropertyDescriptor(0, false)
45460 });
45461 }
45462
45463 return setSymbolDescriptor(O, key, Attributes);
45464 }
45465
45466 return nativeDefineProperty$1(O, key, Attributes);
45467 };
45468
45469 var $defineProperties$1 = function defineProperties(O, Properties) {
45470 anObject(O);
45471 var properties = toIndexedObject(Properties);
45472 var keys = objectKeys(properties).concat($getOwnPropertySymbols$1(properties));
45473 $forEach$1(keys, function (key) {
45474 if (!descriptors || $propertyIsEnumerable$1.call(properties, key)) $defineProperty$1(O, key, properties[key]);
45475 });
45476 return O;
45477 };
45478
45479 var $create$1 = function create(O, Properties) {
45480 return Properties === undefined ? objectCreate(O) : $defineProperties$1(objectCreate(O), Properties);
45481 };
45482
45483 var $propertyIsEnumerable$1 = function propertyIsEnumerable(V) {
45484 var P = toPrimitive(V, true);
45485 var enumerable = nativePropertyIsEnumerable$1.call(this, P);
45486 if (this === ObjectPrototype$3 && has(AllSymbols$1, P) && !has(ObjectPrototypeSymbols, P)) return false;
45487 return enumerable || !has(this, P) || !has(AllSymbols$1, P) || has(this, HIDDEN$1) && this[HIDDEN$1][P] ? enumerable : true;
45488 };
45489
45490 var $getOwnPropertyDescriptor$1 = function getOwnPropertyDescriptor(O, P) {
45491 var it = toIndexedObject(O);
45492 var key = toPrimitive(P, true);
45493 if (it === ObjectPrototype$3 && has(AllSymbols$1, key) && !has(ObjectPrototypeSymbols, key)) return;
45494 var descriptor = nativeGetOwnPropertyDescriptor$1(it, key);
45495
45496 if (descriptor && has(AllSymbols$1, key) && !(has(it, HIDDEN$1) && it[HIDDEN$1][key])) {
45497 descriptor.enumerable = true;
45498 }
45499
45500 return descriptor;
45501 };
45502
45503 var $getOwnPropertyNames$1 = function getOwnPropertyNames(O) {
45504 var names = nativeGetOwnPropertyNames$1(toIndexedObject(O));
45505 var result = [];
45506 $forEach$1(names, function (key) {
45507 if (!has(AllSymbols$1, key) && !has(hiddenKeys, key)) result.push(key);
45508 });
45509 return result;
45510 };
45511
45512 var $getOwnPropertySymbols$1 = function getOwnPropertySymbols(O) {
45513 var IS_OBJECT_PROTOTYPE = O === ObjectPrototype$3;
45514 var names = nativeGetOwnPropertyNames$1(IS_OBJECT_PROTOTYPE ? ObjectPrototypeSymbols : toIndexedObject(O));
45515 var result = [];
45516 $forEach$1(names, function (key) {
45517 if (has(AllSymbols$1, key) && (!IS_OBJECT_PROTOTYPE || has(ObjectPrototype$3, key))) {
45518 result.push(AllSymbols$1[key]);
45519 }
45520 });
45521 return result;
45522 }; // `Symbol` constructor
45523 // https://tc39.github.io/ecma262/#sec-symbol-constructor
45524
45525
45526 if (!nativeSymbol) {
45527 $Symbol$1 = function Symbol() {
45528 if (this instanceof $Symbol$1) throw TypeError('Symbol is not a constructor');
45529 var description = !arguments.length || arguments[0] === undefined ? undefined : String(arguments[0]);
45530 var tag = uid(description);
45531
45532 var setter = function (value) {
45533 if (this === ObjectPrototype$3) setter.call(ObjectPrototypeSymbols, value);
45534 if (has(this, HIDDEN$1) && has(this[HIDDEN$1], tag)) this[HIDDEN$1][tag] = false;
45535 setSymbolDescriptor(this, tag, createPropertyDescriptor(1, value));
45536 };
45537
45538 if (descriptors && USE_SETTER) setSymbolDescriptor(ObjectPrototype$3, tag, {
45539 configurable: true,
45540 set: setter
45541 });
45542 return wrap$1(tag, description);
45543 };
45544
45545 redefine($Symbol$1[PROTOTYPE$4], 'toString', function toString() {
45546 return getInternalState$2(this).tag;
45547 });
45548 objectPropertyIsEnumerable.f = $propertyIsEnumerable$1;
45549 objectDefineProperty.f = $defineProperty$1;
45550 objectGetOwnPropertyDescriptor.f = $getOwnPropertyDescriptor$1;
45551 objectGetOwnPropertyNames.f = objectGetOwnPropertyNamesExternal.f = $getOwnPropertyNames$1;
45552 objectGetOwnPropertySymbols.f = $getOwnPropertySymbols$1;
45553
45554 if (descriptors) {
45555 // https://github.com/tc39/proposal-Symbol-description
45556 nativeDefineProperty$1($Symbol$1[PROTOTYPE$4], 'description', {
45557 configurable: true,
45558 get: function description() {
45559 return getInternalState$2(this).description;
45560 }
45561 });
45562
45563 {
45564 redefine(ObjectPrototype$3, 'propertyIsEnumerable', $propertyIsEnumerable$1, {
45565 unsafe: true
45566 });
45567 }
45568 }
45569
45570 wrappedWellKnownSymbol.f = function (name) {
45571 return wrap$1(wellKnownSymbol(name), name);
45572 };
45573 }
45574
45575 _export({
45576 global: true,
45577 wrap: true,
45578 forced: !nativeSymbol,
45579 sham: !nativeSymbol
45580 }, {
45581 Symbol: $Symbol$1
45582 });
45583 $forEach$1(objectKeys(WellKnownSymbolsStore), function (name) {
45584 defineWellKnownSymbol(name);
45585 });
45586 _export({
45587 target: SYMBOL,
45588 stat: true,
45589 forced: !nativeSymbol
45590 }, {
45591 // `Symbol.for` method
45592 // https://tc39.github.io/ecma262/#sec-symbol.for
45593 'for': function (key) {
45594 var string = String(key);
45595 if (has(StringToSymbolRegistry, string)) return StringToSymbolRegistry[string];
45596 var symbol = $Symbol$1(string);
45597 StringToSymbolRegistry[string] = symbol;
45598 SymbolToStringRegistry[symbol] = string;
45599 return symbol;
45600 },
45601 // `Symbol.keyFor` method
45602 // https://tc39.github.io/ecma262/#sec-symbol.keyfor
45603 keyFor: function keyFor(sym) {
45604 if (!isSymbol$1(sym)) throw TypeError(sym + ' is not a symbol');
45605 if (has(SymbolToStringRegistry, sym)) return SymbolToStringRegistry[sym];
45606 },
45607 useSetter: function () {
45608 USE_SETTER = true;
45609 },
45610 useSimple: function () {
45611 USE_SETTER = false;
45612 }
45613 });
45614 _export({
45615 target: 'Object',
45616 stat: true,
45617 forced: !nativeSymbol,
45618 sham: !descriptors
45619 }, {
45620 // `Object.create` method
45621 // https://tc39.github.io/ecma262/#sec-object.create
45622 create: $create$1,
45623 // `Object.defineProperty` method
45624 // https://tc39.github.io/ecma262/#sec-object.defineproperty
45625 defineProperty: $defineProperty$1,
45626 // `Object.defineProperties` method
45627 // https://tc39.github.io/ecma262/#sec-object.defineproperties
45628 defineProperties: $defineProperties$1,
45629 // `Object.getOwnPropertyDescriptor` method
45630 // https://tc39.github.io/ecma262/#sec-object.getownpropertydescriptors
45631 getOwnPropertyDescriptor: $getOwnPropertyDescriptor$1
45632 });
45633 _export({
45634 target: 'Object',
45635 stat: true,
45636 forced: !nativeSymbol
45637 }, {
45638 // `Object.getOwnPropertyNames` method
45639 // https://tc39.github.io/ecma262/#sec-object.getownpropertynames
45640 getOwnPropertyNames: $getOwnPropertyNames$1,
45641 // `Object.getOwnPropertySymbols` method
45642 // https://tc39.github.io/ecma262/#sec-object.getownpropertysymbols
45643 getOwnPropertySymbols: $getOwnPropertySymbols$1
45644 }); // Chrome 38 and 39 `Object.getOwnPropertySymbols` fails on primitives
45645 // https://bugs.chromium.org/p/v8/issues/detail?id=3443
45646
45647 _export({
45648 target: 'Object',
45649 stat: true,
45650 forced: fails(function () {
45651 objectGetOwnPropertySymbols.f(1);
45652 })
45653 }, {
45654 getOwnPropertySymbols: function getOwnPropertySymbols(it) {
45655 return objectGetOwnPropertySymbols.f(toObject(it));
45656 }
45657 }); // `JSON.stringify` method behavior with symbols
45658 // https://tc39.github.io/ecma262/#sec-json.stringify
45659
45660 JSON$1 && _export({
45661 target: 'JSON',
45662 stat: true,
45663 forced: !nativeSymbol || fails(function () {
45664 var symbol = $Symbol$1(); // MS Edge converts symbol values to JSON as {}
45665
45666 return nativeJSONStringify([symbol]) != '[null]' // WebKit converts symbol values to JSON as null
45667 || nativeJSONStringify({
45668 a: symbol
45669 }) != '{}' // V8 throws on boxed symbols
45670 || nativeJSONStringify(Object(symbol)) != '{}';
45671 })
45672 }, {
45673 stringify: function stringify(it) {
45674 var args = [it];
45675 var index = 1;
45676 var replacer, $replacer;
45677
45678 while (arguments.length > index) args.push(arguments[index++]);
45679
45680 $replacer = replacer = args[1];
45681 if (!isObject(replacer) && it === undefined || isSymbol$1(it)) return; // IE8 returns string on undefined
45682
45683 if (!isArray(replacer)) replacer = function (key, value) {
45684 if (typeof $replacer == 'function') value = $replacer.call(this, key, value);
45685 if (!isSymbol$1(value)) return value;
45686 };
45687 args[1] = replacer;
45688 return nativeJSONStringify.apply(JSON$1, args);
45689 }
45690 }); // `Symbol.prototype[@@toPrimitive]` method
45691 // https://tc39.github.io/ecma262/#sec-symbol.prototype-@@toprimitive
45692
45693 if (!$Symbol$1[PROTOTYPE$4][TO_PRIMITIVE$1]) {
45694 createNonEnumerableProperty($Symbol$1[PROTOTYPE$4], TO_PRIMITIVE$1, $Symbol$1[PROTOTYPE$4].valueOf);
45695 } // `Symbol.prototype[@@toStringTag]` property
45696 // https://tc39.github.io/ecma262/#sec-symbol.prototype-@@tostringtag
45697
45698
45699 setToStringTag($Symbol$1, SYMBOL);
45700 hiddenKeys[HIDDEN$1] = true;
45701
45702 var defineProperty$9 = objectDefineProperty.f;
45703 var NativeSymbol = global_1.Symbol;
45704
45705 if (descriptors && typeof NativeSymbol == 'function' && (!('description' in NativeSymbol.prototype) || // Safari 12 bug
45706 NativeSymbol().description !== undefined)) {
45707 var EmptyStringDescriptionStore = {}; // wrap Symbol constructor for correct work with undefined description
45708
45709 var SymbolWrapper = function Symbol() {
45710 var description = arguments.length < 1 || arguments[0] === undefined ? undefined : String(arguments[0]);
45711 var result = this instanceof SymbolWrapper ? new NativeSymbol(description) // in Edge 13, String(Symbol(undefined)) === 'Symbol(undefined)'
45712 : description === undefined ? NativeSymbol() : NativeSymbol(description);
45713 if (description === '') EmptyStringDescriptionStore[result] = true;
45714 return result;
45715 };
45716
45717 copyConstructorProperties(SymbolWrapper, NativeSymbol);
45718 var symbolPrototype = SymbolWrapper.prototype = NativeSymbol.prototype;
45719 symbolPrototype.constructor = SymbolWrapper;
45720 var symbolToString = symbolPrototype.toString;
45721 var native = String(NativeSymbol('test')) == 'Symbol(test)';
45722 var regexp = /^Symbol\((.*)\)[^)]+$/;
45723 defineProperty$9(symbolPrototype, 'description', {
45724 configurable: true,
45725 get: function description() {
45726 var symbol = isObject(this) ? this.valueOf() : this;
45727 var string = symbolToString.call(symbol);
45728 if (has(EmptyStringDescriptionStore, symbol)) return '';
45729 var desc = native ? string.slice(7, -1) : string.replace(regexp, '$1');
45730 return desc === '' ? undefined : desc;
45731 }
45732 });
45733 _export({
45734 global: true,
45735 forced: true
45736 }, {
45737 Symbol: SymbolWrapper
45738 });
45739 }
45740
45741 // https://tc39.github.io/ecma262/#sec-symbol.iterator
45742
45743 defineWellKnownSymbol('iterator');
45744
45745 var $every = arrayIteration.every; // `Array.prototype.every` method
45746 // https://tc39.github.io/ecma262/#sec-array.prototype.every
45747
45748 _export({
45749 target: 'Array',
45750 proto: true,
45751 forced: sloppyArrayMethod('every')
45752 }, {
45753 every: function every(callbackfn
45754 /* , thisArg */
45755 ) {
45756 return $every(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined);
45757 }
45758 });
45759
45760 var $filter = arrayIteration.filter; // `Array.prototype.filter` method
45761 // https://tc39.github.io/ecma262/#sec-array.prototype.filter
45762 // with adding support of @@species
45763
45764 _export({
45765 target: 'Array',
45766 proto: true,
45767 forced: !arrayMethodHasSpeciesSupport('filter')
45768 }, {
45769 filter: function filter(callbackfn
45770 /* , thisArg */
45771 ) {
45772 return $filter(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined);
45773 }
45774 });
45775
45776 var freezing = !fails(function () {
45777 return Object.isExtensible(Object.preventExtensions({}));
45778 });
45779
45780 var internalMetadata = createCommonjsModule(function (module) {
45781 var defineProperty = objectDefineProperty.f;
45782 var METADATA = uid('meta');
45783 var id = 0;
45784
45785 var isExtensible = Object.isExtensible || function () {
45786 return true;
45787 };
45788
45789 var setMetadata = function (it) {
45790 defineProperty(it, METADATA, {
45791 value: {
45792 objectID: 'O' + ++id,
45793 // object ID
45794 weakData: {} // weak collections IDs
45795
45796 }
45797 });
45798 };
45799
45800 var fastKey = function (it, create) {
45801 // return a primitive with prefix
45802 if (!isObject(it)) return typeof it == 'symbol' ? it : (typeof it == 'string' ? 'S' : 'P') + it;
45803
45804 if (!has(it, METADATA)) {
45805 // can't set metadata to uncaught frozen object
45806 if (!isExtensible(it)) return 'F'; // not necessary to add metadata
45807
45808 if (!create) return 'E'; // add missing metadata
45809
45810 setMetadata(it); // return object ID
45811 }
45812
45813 return it[METADATA].objectID;
45814 };
45815
45816 var getWeakData = function (it, create) {
45817 if (!has(it, METADATA)) {
45818 // can't set metadata to uncaught frozen object
45819 if (!isExtensible(it)) return true; // not necessary to add metadata
45820
45821 if (!create) return false; // add missing metadata
45822
45823 setMetadata(it); // return the store of weak collections IDs
45824 }
45825
45826 return it[METADATA].weakData;
45827 }; // add metadata on freeze-family methods calling
45828
45829
45830 var onFreeze = function (it) {
45831 if (freezing && meta.REQUIRED && isExtensible(it) && !has(it, METADATA)) setMetadata(it);
45832 return it;
45833 };
45834
45835 var meta = module.exports = {
45836 REQUIRED: false,
45837 fastKey: fastKey,
45838 getWeakData: getWeakData,
45839 onFreeze: onFreeze
45840 };
45841 hiddenKeys[METADATA] = true;
45842 });
45843 var internalMetadata_1 = internalMetadata.REQUIRED;
45844 var internalMetadata_2 = internalMetadata.fastKey;
45845 var internalMetadata_3 = internalMetadata.getWeakData;
45846 var internalMetadata_4 = internalMetadata.onFreeze;
45847
45848 var ITERATOR$5 = wellKnownSymbol('iterator');
45849 var ArrayPrototype$1 = Array.prototype; // check on default Array iterator
45850
45851 var isArrayIteratorMethod = function (it) {
45852 return it !== undefined && (iterators.Array === it || ArrayPrototype$1[ITERATOR$5] === it);
45853 };
45854
45855 var ITERATOR$6 = wellKnownSymbol('iterator');
45856
45857 var getIteratorMethod = function (it) {
45858 if (it != undefined) return it[ITERATOR$6] || it['@@iterator'] || iterators[classof(it)];
45859 };
45860
45861 var callWithSafeIterationClosing = function (iterator, fn, value, ENTRIES) {
45862 try {
45863 return ENTRIES ? fn(anObject(value)[0], value[1]) : fn(value); // 7.4.6 IteratorClose(iterator, completion)
45864 } catch (error) {
45865 var returnMethod = iterator['return'];
45866 if (returnMethod !== undefined) anObject(returnMethod.call(iterator));
45867 throw error;
45868 }
45869 };
45870
45871 var iterate_1 = createCommonjsModule(function (module) {
45872 var Result = function (stopped, result) {
45873 this.stopped = stopped;
45874 this.result = result;
45875 };
45876
45877 var iterate = module.exports = function (iterable, fn, that, AS_ENTRIES, IS_ITERATOR) {
45878 var boundFunction = bindContext(fn, that, AS_ENTRIES ? 2 : 1);
45879 var iterator, iterFn, index, length, result, next, step;
45880
45881 if (IS_ITERATOR) {
45882 iterator = iterable;
45883 } else {
45884 iterFn = getIteratorMethod(iterable);
45885 if (typeof iterFn != 'function') throw TypeError('Target is not iterable'); // optimisation for array iterators
45886
45887 if (isArrayIteratorMethod(iterFn)) {
45888 for (index = 0, length = toLength(iterable.length); length > index; index++) {
45889 result = AS_ENTRIES ? boundFunction(anObject(step = iterable[index])[0], step[1]) : boundFunction(iterable[index]);
45890 if (result && result instanceof Result) return result;
45891 }
45892
45893 return new Result(false);
45894 }
45895
45896 iterator = iterFn.call(iterable);
45897 }
45898
45899 next = iterator.next;
45900
45901 while (!(step = next.call(iterator)).done) {
45902 result = callWithSafeIterationClosing(iterator, boundFunction, step.value, AS_ENTRIES);
45903 if (typeof result == 'object' && result && result instanceof Result) return result;
45904 }
45905
45906 return new Result(false);
45907 };
45908
45909 iterate.stop = function (result) {
45910 return new Result(true, result);
45911 };
45912 });
45913
45914 var ITERATOR$7 = wellKnownSymbol('iterator');
45915 var SAFE_CLOSING = false;
45916
45917 try {
45918 var called = 0;
45919 var iteratorWithReturn = {
45920 next: function () {
45921 return {
45922 done: !!called++
45923 };
45924 },
45925 'return': function () {
45926 SAFE_CLOSING = true;
45927 }
45928 };
45929
45930 iteratorWithReturn[ITERATOR$7] = function () {
45931 return this;
45932 }; // eslint-disable-next-line no-throw-literal
45933
45934
45935 Array.from(iteratorWithReturn, function () {
45936 throw 2;
45937 });
45938 } catch (error) {
45939 /* empty */
45940 }
45941
45942 var checkCorrectnessOfIteration = function (exec, SKIP_CLOSING) {
45943 if (!SKIP_CLOSING && !SAFE_CLOSING) return false;
45944 var ITERATION_SUPPORT = false;
45945
45946 try {
45947 var object = {};
45948
45949 object[ITERATOR$7] = function () {
45950 return {
45951 next: function () {
45952 return {
45953 done: ITERATION_SUPPORT = true
45954 };
45955 }
45956 };
45957 };
45958
45959 exec(object);
45960 } catch (error) {
45961 /* empty */
45962 }
45963
45964 return ITERATION_SUPPORT;
45965 };
45966
45967 var collection = function (CONSTRUCTOR_NAME, wrapper, common, IS_MAP, IS_WEAK) {
45968 var NativeConstructor = global_1[CONSTRUCTOR_NAME];
45969 var NativePrototype = NativeConstructor && NativeConstructor.prototype;
45970 var Constructor = NativeConstructor;
45971 var ADDER = IS_MAP ? 'set' : 'add';
45972 var exported = {};
45973
45974 var fixMethod = function (KEY) {
45975 var nativeMethod = NativePrototype[KEY];
45976 redefine(NativePrototype, KEY, KEY == 'add' ? function add(value) {
45977 nativeMethod.call(this, value === 0 ? 0 : value);
45978 return this;
45979 } : KEY == 'delete' ? function (key) {
45980 return IS_WEAK && !isObject(key) ? false : nativeMethod.call(this, key === 0 ? 0 : key);
45981 } : KEY == 'get' ? function get(key) {
45982 return IS_WEAK && !isObject(key) ? undefined : nativeMethod.call(this, key === 0 ? 0 : key);
45983 } : KEY == 'has' ? function has(key) {
45984 return IS_WEAK && !isObject(key) ? false : nativeMethod.call(this, key === 0 ? 0 : key);
45985 } : function set(key, value) {
45986 nativeMethod.call(this, key === 0 ? 0 : key, value);
45987 return this;
45988 });
45989 }; // eslint-disable-next-line max-len
45990
45991
45992 if (isForced_1(CONSTRUCTOR_NAME, typeof NativeConstructor != 'function' || !(IS_WEAK || NativePrototype.forEach && !fails(function () {
45993 new NativeConstructor().entries().next();
45994 })))) {
45995 // create collection constructor
45996 Constructor = common.getConstructor(wrapper, CONSTRUCTOR_NAME, IS_MAP, ADDER);
45997 internalMetadata.REQUIRED = true;
45998 } else if (isForced_1(CONSTRUCTOR_NAME, true)) {
45999 var instance = new Constructor(); // early implementations not supports chaining
46000
46001 var HASNT_CHAINING = instance[ADDER](IS_WEAK ? {} : -0, 1) != instance; // V8 ~ Chromium 40- weak-collections throws on primitives, but should return false
46002
46003 var THROWS_ON_PRIMITIVES = fails(function () {
46004 instance.has(1);
46005 }); // most early implementations doesn't supports iterables, most modern - not close it correctly
46006 // eslint-disable-next-line no-new
46007
46008 var ACCEPT_ITERABLES = checkCorrectnessOfIteration(function (iterable) {
46009 new NativeConstructor(iterable);
46010 }); // for early implementations -0 and +0 not the same
46011
46012 var BUGGY_ZERO = !IS_WEAK && fails(function () {
46013 // V8 ~ Chromium 42- fails only with 5+ elements
46014 var $instance = new NativeConstructor();
46015 var index = 5;
46016
46017 while (index--) $instance[ADDER](index, index);
46018
46019 return !$instance.has(-0);
46020 });
46021
46022 if (!ACCEPT_ITERABLES) {
46023 Constructor = wrapper(function (dummy, iterable) {
46024 anInstance(dummy, Constructor, CONSTRUCTOR_NAME);
46025 var that = inheritIfRequired(new NativeConstructor(), dummy, Constructor);
46026 if (iterable != undefined) iterate_1(iterable, that[ADDER], that, IS_MAP);
46027 return that;
46028 });
46029 Constructor.prototype = NativePrototype;
46030 NativePrototype.constructor = Constructor;
46031 }
46032
46033 if (THROWS_ON_PRIMITIVES || BUGGY_ZERO) {
46034 fixMethod('delete');
46035 fixMethod('has');
46036 IS_MAP && fixMethod('get');
46037 }
46038
46039 if (BUGGY_ZERO || HASNT_CHAINING) fixMethod(ADDER); // weak collections should not contains .clear method
46040
46041 if (IS_WEAK && NativePrototype.clear) delete NativePrototype.clear;
46042 }
46043
46044 exported[CONSTRUCTOR_NAME] = Constructor;
46045 _export({
46046 global: true,
46047 forced: Constructor != NativeConstructor
46048 }, exported);
46049 setToStringTag(Constructor, CONSTRUCTOR_NAME);
46050 if (!IS_WEAK) common.setStrong(Constructor, CONSTRUCTOR_NAME, IS_MAP);
46051 return Constructor;
46052 };
46053
46054 var defineProperty$a = objectDefineProperty.f;
46055 var fastKey = internalMetadata.fastKey;
46056 var setInternalState$3 = internalState.set;
46057 var internalStateGetterFor = internalState.getterFor;
46058 var collectionStrong = {
46059 getConstructor: function (wrapper, CONSTRUCTOR_NAME, IS_MAP, ADDER) {
46060 var C = wrapper(function (that, iterable) {
46061 anInstance(that, C, CONSTRUCTOR_NAME);
46062 setInternalState$3(that, {
46063 type: CONSTRUCTOR_NAME,
46064 index: objectCreate(null),
46065 first: undefined,
46066 last: undefined,
46067 size: 0
46068 });
46069 if (!descriptors) that.size = 0;
46070 if (iterable != undefined) iterate_1(iterable, that[ADDER], that, IS_MAP);
46071 });
46072 var getInternalState = internalStateGetterFor(CONSTRUCTOR_NAME);
46073
46074 var define = function (that, key, value) {
46075 var state = getInternalState(that);
46076 var entry = getEntry(that, key);
46077 var previous, index; // change existing entry
46078
46079 if (entry) {
46080 entry.value = value; // create new entry
46081 } else {
46082 state.last = entry = {
46083 index: index = fastKey(key, true),
46084 key: key,
46085 value: value,
46086 previous: previous = state.last,
46087 next: undefined,
46088 removed: false
46089 };
46090 if (!state.first) state.first = entry;
46091 if (previous) previous.next = entry;
46092 if (descriptors) state.size++;else that.size++; // add to index
46093
46094 if (index !== 'F') state.index[index] = entry;
46095 }
46096
46097 return that;
46098 };
46099
46100 var getEntry = function (that, key) {
46101 var state = getInternalState(that); // fast case
46102
46103 var index = fastKey(key);
46104 var entry;
46105 if (index !== 'F') return state.index[index]; // frozen object case
46106
46107 for (entry = state.first; entry; entry = entry.next) {
46108 if (entry.key == key) return entry;
46109 }
46110 };
46111
46112 redefineAll(C.prototype, {
46113 // 23.1.3.1 Map.prototype.clear()
46114 // 23.2.3.2 Set.prototype.clear()
46115 clear: function clear() {
46116 var that = this;
46117 var state = getInternalState(that);
46118 var data = state.index;
46119 var entry = state.first;
46120
46121 while (entry) {
46122 entry.removed = true;
46123 if (entry.previous) entry.previous = entry.previous.next = undefined;
46124 delete data[entry.index];
46125 entry = entry.next;
46126 }
46127
46128 state.first = state.last = undefined;
46129 if (descriptors) state.size = 0;else that.size = 0;
46130 },
46131 // 23.1.3.3 Map.prototype.delete(key)
46132 // 23.2.3.4 Set.prototype.delete(value)
46133 'delete': function (key) {
46134 var that = this;
46135 var state = getInternalState(that);
46136 var entry = getEntry(that, key);
46137
46138 if (entry) {
46139 var next = entry.next;
46140 var prev = entry.previous;
46141 delete state.index[entry.index];
46142 entry.removed = true;
46143 if (prev) prev.next = next;
46144 if (next) next.previous = prev;
46145 if (state.first == entry) state.first = next;
46146 if (state.last == entry) state.last = prev;
46147 if (descriptors) state.size--;else that.size--;
46148 }
46149
46150 return !!entry;
46151 },
46152 // 23.2.3.6 Set.prototype.forEach(callbackfn, thisArg = undefined)
46153 // 23.1.3.5 Map.prototype.forEach(callbackfn, thisArg = undefined)
46154 forEach: function forEach(callbackfn
46155 /* , that = undefined */
46156 ) {
46157 var state = getInternalState(this);
46158 var boundFunction = bindContext(callbackfn, arguments.length > 1 ? arguments[1] : undefined, 3);
46159 var entry;
46160
46161 while (entry = entry ? entry.next : state.first) {
46162 boundFunction(entry.value, entry.key, this); // revert to the last existing entry
46163
46164 while (entry && entry.removed) entry = entry.previous;
46165 }
46166 },
46167 // 23.1.3.7 Map.prototype.has(key)
46168 // 23.2.3.7 Set.prototype.has(value)
46169 has: function has(key) {
46170 return !!getEntry(this, key);
46171 }
46172 });
46173 redefineAll(C.prototype, IS_MAP ? {
46174 // 23.1.3.6 Map.prototype.get(key)
46175 get: function get(key) {
46176 var entry = getEntry(this, key);
46177 return entry && entry.value;
46178 },
46179 // 23.1.3.9 Map.prototype.set(key, value)
46180 set: function set(key, value) {
46181 return define(this, key === 0 ? 0 : key, value);
46182 }
46183 } : {
46184 // 23.2.3.1 Set.prototype.add(value)
46185 add: function add(value) {
46186 return define(this, value = value === 0 ? 0 : value, value);
46187 }
46188 });
46189 if (descriptors) defineProperty$a(C.prototype, 'size', {
46190 get: function () {
46191 return getInternalState(this).size;
46192 }
46193 });
46194 return C;
46195 },
46196 setStrong: function (C, CONSTRUCTOR_NAME, IS_MAP) {
46197 var ITERATOR_NAME = CONSTRUCTOR_NAME + ' Iterator';
46198 var getInternalCollectionState = internalStateGetterFor(CONSTRUCTOR_NAME);
46199 var getInternalIteratorState = internalStateGetterFor(ITERATOR_NAME); // add .keys, .values, .entries, [@@iterator]
46200 // 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
46201
46202 defineIterator(C, CONSTRUCTOR_NAME, function (iterated, kind) {
46203 setInternalState$3(this, {
46204 type: ITERATOR_NAME,
46205 target: iterated,
46206 state: getInternalCollectionState(iterated),
46207 kind: kind,
46208 last: undefined
46209 });
46210 }, function () {
46211 var state = getInternalIteratorState(this);
46212 var kind = state.kind;
46213 var entry = state.last; // revert to the last existing entry
46214
46215 while (entry && entry.removed) entry = entry.previous; // get next entry
46216
46217
46218 if (!state.target || !(state.last = entry = entry ? entry.next : state.state.first)) {
46219 // or finish the iteration
46220 state.target = undefined;
46221 return {
46222 value: undefined,
46223 done: true
46224 };
46225 } // return step by kind
46226
46227
46228 if (kind == 'keys') return {
46229 value: entry.key,
46230 done: false
46231 };
46232 if (kind == 'values') return {
46233 value: entry.value,
46234 done: false
46235 };
46236 return {
46237 value: [entry.key, entry.value],
46238 done: false
46239 };
46240 }, IS_MAP ? 'entries' : 'values', !IS_MAP, true); // add [@@species], 23.1.2.2, 23.2.2.2
46241
46242 setSpecies(CONSTRUCTOR_NAME);
46243 }
46244 };
46245
46246 // https://tc39.github.io/ecma262/#sec-set-objects
46247
46248
46249 var es_set = collection('Set', function (get) {
46250 return function Set() {
46251 return get(this, arguments.length ? arguments[0] : undefined);
46252 };
46253 }, collectionStrong);
46254
46255 var charAt$1 = stringMultibyte.charAt;
46256 var STRING_ITERATOR = 'String Iterator';
46257 var setInternalState$4 = internalState.set;
46258 var getInternalState$3 = internalState.getterFor(STRING_ITERATOR); // `String.prototype[@@iterator]` method
46259 // https://tc39.github.io/ecma262/#sec-string.prototype-@@iterator
46260
46261 defineIterator(String, 'String', function (iterated) {
46262 setInternalState$4(this, {
46263 type: STRING_ITERATOR,
46264 string: String(iterated),
46265 index: 0
46266 }); // `%StringIteratorPrototype%.next` method
46267 // https://tc39.github.io/ecma262/#sec-%stringiteratorprototype%.next
46268 }, function next() {
46269 var state = getInternalState$3(this);
46270 var string = state.string;
46271 var index = state.index;
46272 var point;
46273 if (index >= string.length) return {
46274 value: undefined,
46275 done: true
46276 };
46277 point = charAt$1(string, index);
46278 state.index += point.length;
46279 return {
46280 value: point,
46281 done: false
46282 };
46283 });
46284
46285 /**
46286 * Try to assign levels to nodes according to their positions in the cyclic “hierarchy”.
46287 *
46288 * @param nodes - Nodes of the graph.
46289 * @param levels - If present levels will be added to it, if not a new object will be created.
46290 *
46291 * @returns Populated node levels.
46292 */
46293 function fillLevelsByDirectionCyclic(nodes, levels) {
46294 var edges = new Set();
46295 nodes.forEach(function (node) {
46296 node.edges.forEach(function (edge) {
46297 if (edge.connected) {
46298 edges.add(edge);
46299 }
46300 });
46301 });
46302 edges.forEach(function (edge) {
46303 var fromId = edge.from.id;
46304 var toId = edge.to.id;
46305
46306 if (levels[fromId] == null) {
46307 levels[fromId] = 0;
46308 }
46309
46310 if (levels[toId] == null || levels[fromId] >= levels[toId]) {
46311 levels[toId] = levels[fromId] + 1;
46312 }
46313 });
46314 return levels;
46315 }
46316 /**
46317 * 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.
46318 *
46319 * @param nodes - Nodes of the graph.
46320 * @param levels - If present levels will be added to it, if not a new object will be created.
46321 *
46322 * @returns Populated node levels.
46323 */
46324
46325
46326 function fillLevelsByDirectionLeaves(nodes) {
46327 var levels = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : Object.create(null);
46328 return fillLevelsByDirection( // Pick only leaves (nodes without children).
46329 function (node) {
46330 return !node.edges.every(function (edge) {
46331 return edge.to === node;
46332 });
46333 }, // Use the lowest level.
46334 function (newLevel, oldLevel) {
46335 return oldLevel > newLevel;
46336 }, // Go against the direction of the edges.
46337 "from", nodes, levels);
46338 }
46339 /**
46340 * 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.
46341 *
46342 * @param nodes - Nodes of the graph.
46343 * @param levels - If present levels will be added to it, if not a new object will be created.
46344 *
46345 * @returns Populated node levels.
46346 */
46347
46348 function fillLevelsByDirectionRoots(nodes) {
46349 var levels = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : Object.create(null);
46350 return fillLevelsByDirection( // Pick only roots (nodes without parents).
46351 function (node) {
46352 return !node.edges.every(function (edge) {
46353 return edge.from === node;
46354 });
46355 }, // Use the highest level.
46356 function (newLevel, oldLevel) {
46357 return oldLevel < newLevel;
46358 }, // Go in the direction of the edges.
46359 "to", nodes, levels);
46360 }
46361 /**
46362 * Assign levels to nodes according to their positions in the hierarchy.
46363 *
46364 * @param isEntryNode - Checks and return true if the graph should be traversed from this node.
46365 * @param shouldLevelBeReplaced - Checks and returns true if the level of given node should be updated to the new value.
46366 * @param direction - Wheter the graph should be traversed in the direction of the edges `"to"` or in the other way `"from"`.
46367 * @param nodes - Nodes of the graph.
46368 * @param levels - If present levels will be added to it, if not a new object will be created.
46369 *
46370 * @returns Populated node levels.
46371 */
46372
46373 function fillLevelsByDirection(isEntryNode, shouldLevelBeReplaced, direction, nodes, levels) {
46374 var limit = nodes.length;
46375 var edgeIdProp = direction + "Id";
46376 var newLevelDiff = direction === "to" ? 1 : -1;
46377 var _iteratorNormalCompletion = true;
46378 var _didIteratorError = false;
46379 var _iteratorError = undefined;
46380
46381 try {
46382 var _loop = function _loop() {
46383 var entryNode = _step.value;
46384
46385 if (isEntryNode(entryNode)) {
46386 return "continue";
46387 } // Line up all the entry nodes on level 0.
46388
46389
46390 levels[entryNode.id] = 0;
46391 var stack = [entryNode];
46392 var done = 0;
46393 var node = void 0;
46394
46395 var _loop2 = function _loop2() {
46396 var newLevel = levels[node.id] + newLevelDiff;
46397 node.edges.filter(function (edge) {
46398 return (// Ignore disconnected edges.
46399 edge.connected && // Ignore circular edges.
46400 edge.to !== edge.from && // Ignore edges leading to the node that's currently being processed.
46401 edge[direction] !== node
46402 );
46403 }).forEach(function (edge) {
46404 var targetNodeId = edge[edgeIdProp];
46405 var oldLevel = levels[targetNodeId];
46406
46407 if (oldLevel == null || shouldLevelBeReplaced(newLevel, oldLevel)) {
46408 levels[targetNodeId] = newLevel;
46409 stack.push(edge[direction]);
46410 }
46411 });
46412
46413 if (done > limit) {
46414 // This would run forever on a cyclic graph.
46415 return {
46416 v: {
46417 v: fillLevelsByDirectionCyclic(nodes, levels)
46418 }
46419 };
46420 } else {
46421 ++done;
46422 }
46423 };
46424
46425 while (node = stack.pop()) {
46426 var _ret2 = _loop2();
46427
46428 if (_typeof$1(_ret2) === "object") return _ret2.v;
46429 }
46430 };
46431
46432 for (var _iterator = nodes[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
46433 var _ret = _loop();
46434
46435 switch (_ret) {
46436 case "continue":
46437 continue;
46438
46439 default:
46440 if (_typeof$1(_ret) === "object") return _ret.v;
46441 }
46442 }
46443 } catch (err) {
46444 _didIteratorError = true;
46445 _iteratorError = err;
46446 } finally {
46447 try {
46448 if (!_iteratorNormalCompletion && _iterator.return != null) {
46449 _iterator.return();
46450 }
46451 } finally {
46452 if (_didIteratorError) {
46453 throw _iteratorError;
46454 }
46455 }
46456 }
46457
46458 return levels;
46459 }
46460
46461 /**
46462 * There's a mix-up with terms in the code. Following are the formal definitions:
46463 *
46464 * tree - a strict hierarchical network, i.e. every node has at most one parent
46465 * forest - a collection of trees. These distinct trees are thus not connected.
46466 *
46467 * So:
46468 * - in a network that is not a tree, there exist nodes with multiple parents.
46469 * - a network consisting of unconnected sub-networks, of which at least one
46470 * is not a tree, is not a forest.
46471 *
46472 * In the code, the definitions are:
46473 *
46474 * tree - any disconnected sub-network, strict hierarchical or not.
46475 * forest - a bunch of these sub-networks
46476 *
46477 * The difference between tree and not-tree is important in the code, notably within
46478 * to the block-shifting algorithm. The algorithm assumes formal trees and fails
46479 * for not-trees, often in a spectacular manner (search for 'exploding network' in the issues).
46480 *
46481 * In order to distinguish the definitions in the following code, the adjective 'formal' is
46482 * used. If 'formal' is absent, you must assume the non-formal definition.
46483 *
46484 * ----------------------------------------------------------------------------------
46485 * NOTES
46486 * =====
46487 *
46488 * A hierarchical layout is a different thing from a hierarchical network.
46489 * The layout is a way to arrange the nodes in the view; this can be done
46490 * on non-hierarchical networks as well. The converse is also possible.
46491 */
46492 /**
46493 * Container for derived data on current network, relating to hierarchy.
46494 *
46495 * @private
46496 */
46497
46498 var HierarchicalStatus =
46499 /*#__PURE__*/
46500 function () {
46501 /**
46502 * @ignore
46503 */
46504 function HierarchicalStatus() {
46505 _classCallCheck(this, HierarchicalStatus);
46506
46507 this.childrenReference = {}; // child id's per node id
46508
46509 this.parentReference = {}; // parent id's per node id
46510
46511 this.trees = {}; // tree id per node id; i.e. to which tree does given node id belong
46512
46513 this.distributionOrdering = {}; // The nodes per level, in the display order
46514
46515 this.levels = {}; // hierarchy level per node id
46516
46517 this.distributionIndex = {}; // The position of the node in the level sorting order, per node id.
46518
46519 this.isTree = false; // True if current network is a formal tree
46520
46521 this.treeIndex = -1; // Highest tree id in current network.
46522 }
46523 /**
46524 * Add the relation between given nodes to the current state.
46525 *
46526 * @param {Node.id} parentNodeId
46527 * @param {Node.id} childNodeId
46528 */
46529
46530
46531 _createClass(HierarchicalStatus, [{
46532 key: "addRelation",
46533 value: function addRelation(parentNodeId, childNodeId) {
46534 if (this.childrenReference[parentNodeId] === undefined) {
46535 this.childrenReference[parentNodeId] = [];
46536 }
46537
46538 this.childrenReference[parentNodeId].push(childNodeId);
46539
46540 if (this.parentReference[childNodeId] === undefined) {
46541 this.parentReference[childNodeId] = [];
46542 }
46543
46544 this.parentReference[childNodeId].push(parentNodeId);
46545 }
46546 /**
46547 * Check if the current state is for a formal tree or formal forest.
46548 *
46549 * This is the case if every node has at most one parent.
46550 *
46551 * Pre: parentReference init'ed properly for current network
46552 */
46553
46554 }, {
46555 key: "checkIfTree",
46556 value: function checkIfTree() {
46557 for (var i in this.parentReference) {
46558 if (this.parentReference[i].length > 1) {
46559 this.isTree = false;
46560 return;
46561 }
46562 }
46563
46564 this.isTree = true;
46565 }
46566 /**
46567 * Return the number of separate trees in the current network.
46568 * @returns {number}
46569 */
46570
46571 }, {
46572 key: "numTrees",
46573 value: function numTrees() {
46574 return this.treeIndex + 1; // This assumes the indexes are assigned consecitively
46575 }
46576 /**
46577 * Assign a tree id to a node
46578 * @param {Node} node
46579 * @param {string|number} treeId
46580 */
46581
46582 }, {
46583 key: "setTreeIndex",
46584 value: function setTreeIndex(node, treeId) {
46585 if (treeId === undefined) return; // Don't bother
46586
46587 if (this.trees[node.id] === undefined) {
46588 this.trees[node.id] = treeId;
46589 this.treeIndex = Math.max(treeId, this.treeIndex);
46590 }
46591 }
46592 /**
46593 * Ensure level for given id is defined.
46594 *
46595 * Sets level to zero for given node id if not already present
46596 *
46597 * @param {Node.id} nodeId
46598 */
46599
46600 }, {
46601 key: "ensureLevel",
46602 value: function ensureLevel(nodeId) {
46603 if (this.levels[nodeId] === undefined) {
46604 this.levels[nodeId] = 0;
46605 }
46606 }
46607 /**
46608 * get the maximum level of a branch.
46609 *
46610 * TODO: Never entered; find a test case to test this!
46611 * @param {Node.id} nodeId
46612 * @returns {number}
46613 */
46614
46615 }, {
46616 key: "getMaxLevel",
46617 value: function getMaxLevel(nodeId) {
46618 var _this = this;
46619
46620 var accumulator = {};
46621
46622 var _getMaxLevel = function _getMaxLevel(nodeId) {
46623 if (accumulator[nodeId] !== undefined) {
46624 return accumulator[nodeId];
46625 }
46626
46627 var level = _this.levels[nodeId];
46628
46629 if (_this.childrenReference[nodeId]) {
46630 var children = _this.childrenReference[nodeId];
46631
46632 if (children.length > 0) {
46633 for (var i = 0; i < children.length; i++) {
46634 level = Math.max(level, _getMaxLevel(children[i]));
46635 }
46636 }
46637 }
46638
46639 accumulator[nodeId] = level;
46640 return level;
46641 };
46642
46643 return _getMaxLevel(nodeId);
46644 }
46645 /**
46646 *
46647 * @param {Node} nodeA
46648 * @param {Node} nodeB
46649 */
46650
46651 }, {
46652 key: "levelDownstream",
46653 value: function levelDownstream(nodeA, nodeB) {
46654 if (this.levels[nodeB.id] === undefined) {
46655 // set initial level
46656 if (this.levels[nodeA.id] === undefined) {
46657 this.levels[nodeA.id] = 0;
46658 } // set level
46659
46660
46661 this.levels[nodeB.id] = this.levels[nodeA.id] + 1;
46662 }
46663 }
46664 /**
46665 * Small util method to set the minimum levels of the nodes to zero.
46666 *
46667 * @param {Array.<Node>} nodes
46668 */
46669
46670 }, {
46671 key: "setMinLevelToZero",
46672 value: function setMinLevelToZero(nodes) {
46673 var minLevel = 1e9; // get the minimum level
46674
46675 for (var nodeId in nodes) {
46676 if (nodes.hasOwnProperty(nodeId)) {
46677 if (this.levels[nodeId] !== undefined) {
46678 minLevel = Math.min(this.levels[nodeId], minLevel);
46679 }
46680 }
46681 } // subtract the minimum from the set so we have a range starting from 0
46682
46683
46684 for (var _nodeId in nodes) {
46685 if (nodes.hasOwnProperty(_nodeId)) {
46686 if (this.levels[_nodeId] !== undefined) {
46687 this.levels[_nodeId] -= minLevel;
46688 }
46689 }
46690 }
46691 }
46692 /**
46693 * Get the min and max xy-coordinates of a given tree
46694 *
46695 * @param {Array.<Node>} nodes
46696 * @param {number} index
46697 * @returns {{min_x: number, max_x: number, min_y: number, max_y: number}}
46698 */
46699
46700 }, {
46701 key: "getTreeSize",
46702 value: function getTreeSize(nodes, index) {
46703 var min_x = 1e9;
46704 var max_x = -1e9;
46705 var min_y = 1e9;
46706 var max_y = -1e9;
46707
46708 for (var nodeId in this.trees) {
46709 if (this.trees.hasOwnProperty(nodeId)) {
46710 if (this.trees[nodeId] === index) {
46711 var node = nodes[nodeId];
46712 min_x = Math.min(node.x, min_x);
46713 max_x = Math.max(node.x, max_x);
46714 min_y = Math.min(node.y, min_y);
46715 max_y = Math.max(node.y, max_y);
46716 }
46717 }
46718 }
46719
46720 return {
46721 min_x: min_x,
46722 max_x: max_x,
46723 min_y: min_y,
46724 max_y: max_y
46725 };
46726 }
46727 /**
46728 * Check if two nodes have the same parent(s)
46729 *
46730 * @param {Node} node1
46731 * @param {Node} node2
46732 * @return {boolean} true if the two nodes have a same ancestor node, false otherwise
46733 */
46734
46735 }, {
46736 key: "hasSameParent",
46737 value: function hasSameParent(node1, node2) {
46738 var parents1 = this.parentReference[node1.id];
46739 var parents2 = this.parentReference[node2.id];
46740
46741 if (parents1 === undefined || parents2 === undefined) {
46742 return false;
46743 }
46744
46745 for (var i = 0; i < parents1.length; i++) {
46746 for (var j = 0; j < parents2.length; j++) {
46747 if (parents1[i] == parents2[j]) {
46748 return true;
46749 }
46750 }
46751 }
46752
46753 return false;
46754 }
46755 /**
46756 * Check if two nodes are in the same tree.
46757 *
46758 * @param {Node} node1
46759 * @param {Node} node2
46760 * @return {Boolean} true if this is so, false otherwise
46761 */
46762
46763 }, {
46764 key: "inSameSubNetwork",
46765 value: function inSameSubNetwork(node1, node2) {
46766 return this.trees[node1.id] === this.trees[node2.id];
46767 }
46768 /**
46769 * Get a list of the distinct levels in the current network
46770 *
46771 * @returns {Array}
46772 */
46773
46774 }, {
46775 key: "getLevels",
46776 value: function getLevels() {
46777 return Object.keys(this.distributionOrdering);
46778 }
46779 /**
46780 * Add a node to the ordering per level
46781 *
46782 * @param {Node} node
46783 * @param {number} level
46784 */
46785
46786 }, {
46787 key: "addToOrdering",
46788 value: function addToOrdering(node, level) {
46789 if (this.distributionOrdering[level] === undefined) {
46790 this.distributionOrdering[level] = [];
46791 }
46792
46793 var isPresent = false;
46794 var curLevel = this.distributionOrdering[level];
46795
46796 for (var n in curLevel) {
46797 //if (curLevel[n].id === node.id) {
46798 if (curLevel[n] === node) {
46799 isPresent = true;
46800 break;
46801 }
46802 }
46803
46804 if (!isPresent) {
46805 this.distributionOrdering[level].push(node);
46806 this.distributionIndex[node.id] = this.distributionOrdering[level].length - 1;
46807 }
46808 }
46809 }]);
46810
46811 return HierarchicalStatus;
46812 }();
46813 /**
46814 * The Layout Engine
46815 */
46816
46817
46818 var LayoutEngine =
46819 /*#__PURE__*/
46820 function () {
46821 /**
46822 * @param {Object} body
46823 */
46824 function LayoutEngine(body) {
46825 _classCallCheck(this, LayoutEngine);
46826
46827 this.body = body;
46828 this.initialRandomSeed = Math.round(Math.random() * 1000000);
46829 this.randomSeed = this.initialRandomSeed;
46830 this.setPhysics = false;
46831 this.options = {};
46832 this.optionsBackup = {
46833 physics: {}
46834 };
46835 this.defaultOptions = {
46836 randomSeed: undefined,
46837 improvedLayout: true,
46838 clusterThreshold: 150,
46839 hierarchical: {
46840 enabled: false,
46841 levelSeparation: 150,
46842 nodeSpacing: 100,
46843 treeSpacing: 200,
46844 blockShifting: true,
46845 edgeMinimization: true,
46846 parentCentralization: true,
46847 direction: 'UD',
46848 // UD, DU, LR, RL
46849 sortMethod: 'hubsize' // hubsize, directed
46850
46851 }
46852 };
46853 extend(this.options, this.defaultOptions);
46854 this.bindEventListeners();
46855 }
46856 /**
46857 * Binds event listeners
46858 */
46859
46860
46861 _createClass(LayoutEngine, [{
46862 key: "bindEventListeners",
46863 value: function bindEventListeners() {
46864 var _this2 = this;
46865
46866 this.body.emitter.on('_dataChanged', function () {
46867 _this2.setupHierarchicalLayout();
46868 });
46869 this.body.emitter.on('_dataLoaded', function () {
46870 _this2.layoutNetwork();
46871 });
46872 this.body.emitter.on('_resetHierarchicalLayout', function () {
46873 _this2.setupHierarchicalLayout();
46874 });
46875 this.body.emitter.on('_adjustEdgesForHierarchicalLayout', function () {
46876 if (_this2.options.hierarchical.enabled !== true) {
46877 return;
46878 } // get the type of static smooth curve in case it is required
46879
46880
46881 var type = _this2.direction.curveType(); // force all edges into static smooth curves.
46882
46883
46884 _this2.body.emitter.emit('_forceDisableDynamicCurves', type, false);
46885 });
46886 }
46887 /**
46888 *
46889 * @param {Object} options
46890 * @param {Object} allOptions
46891 * @returns {Object}
46892 */
46893
46894 }, {
46895 key: "setOptions",
46896 value: function setOptions(options, allOptions) {
46897 if (options !== undefined) {
46898 var hierarchical = this.options.hierarchical;
46899 var prevHierarchicalState = hierarchical.enabled;
46900 selectiveDeepExtend(["randomSeed", "improvedLayout", "clusterThreshold"], this.options, options);
46901 mergeOptions(this.options, options, 'hierarchical');
46902
46903 if (options.randomSeed !== undefined) {
46904 this.initialRandomSeed = options.randomSeed;
46905 }
46906
46907 if (hierarchical.enabled === true) {
46908 if (prevHierarchicalState === true) {
46909 // refresh the overridden options for nodes and edges.
46910 this.body.emitter.emit('refresh', true);
46911 } // make sure the level separation is the right way up
46912
46913
46914 if (hierarchical.direction === 'RL' || hierarchical.direction === 'DU') {
46915 if (hierarchical.levelSeparation > 0) {
46916 hierarchical.levelSeparation *= -1;
46917 }
46918 } else {
46919 if (hierarchical.levelSeparation < 0) {
46920 hierarchical.levelSeparation *= -1;
46921 }
46922 }
46923
46924 this.setDirectionStrategy();
46925 this.body.emitter.emit('_resetHierarchicalLayout'); // because the hierarchical system needs it's own physics and smooth curve settings,
46926 // we adapt the other options if needed.
46927
46928 return this.adaptAllOptionsForHierarchicalLayout(allOptions);
46929 } else {
46930 if (prevHierarchicalState === true) {
46931 // refresh the overridden options for nodes and edges.
46932 this.body.emitter.emit('refresh');
46933 return deepExtend(allOptions, this.optionsBackup);
46934 }
46935 }
46936 }
46937
46938 return allOptions;
46939 }
46940 /**
46941 *
46942 * @param {Object} allOptions
46943 * @returns {Object}
46944 */
46945
46946 }, {
46947 key: "adaptAllOptionsForHierarchicalLayout",
46948 value: function adaptAllOptionsForHierarchicalLayout(allOptions) {
46949 if (this.options.hierarchical.enabled === true) {
46950 var backupPhysics = this.optionsBackup.physics; // set the physics
46951
46952 if (allOptions.physics === undefined || allOptions.physics === true) {
46953 allOptions.physics = {
46954 enabled: backupPhysics.enabled === undefined ? true : backupPhysics.enabled,
46955 solver: 'hierarchicalRepulsion'
46956 };
46957 backupPhysics.enabled = backupPhysics.enabled === undefined ? true : backupPhysics.enabled;
46958 backupPhysics.solver = backupPhysics.solver || 'barnesHut';
46959 } else if (_typeof$1(allOptions.physics) === 'object') {
46960 backupPhysics.enabled = allOptions.physics.enabled === undefined ? true : allOptions.physics.enabled;
46961 backupPhysics.solver = allOptions.physics.solver || 'barnesHut';
46962 allOptions.physics.solver = 'hierarchicalRepulsion';
46963 } else if (allOptions.physics !== false) {
46964 backupPhysics.solver = 'barnesHut';
46965 allOptions.physics = {
46966 solver: 'hierarchicalRepulsion'
46967 };
46968 } // get the type of static smooth curve in case it is required
46969
46970
46971 var type = this.direction.curveType(); // disable smooth curves if nothing is defined. If smooth curves have been turned on,
46972 // turn them into static smooth curves.
46973
46974 if (allOptions.edges === undefined) {
46975 this.optionsBackup.edges = {
46976 smooth: {
46977 enabled: true,
46978 type: 'dynamic'
46979 }
46980 };
46981 allOptions.edges = {
46982 smooth: false
46983 };
46984 } else if (allOptions.edges.smooth === undefined) {
46985 this.optionsBackup.edges = {
46986 smooth: {
46987 enabled: true,
46988 type: 'dynamic'
46989 }
46990 };
46991 allOptions.edges.smooth = false;
46992 } else {
46993 if (typeof allOptions.edges.smooth === 'boolean') {
46994 this.optionsBackup.edges = {
46995 smooth: allOptions.edges.smooth
46996 };
46997 allOptions.edges.smooth = {
46998 enabled: allOptions.edges.smooth,
46999 type: type
47000 };
47001 } else {
47002 var smooth = allOptions.edges.smooth; // allow custom types except for dynamic
47003
47004 if (smooth.type !== undefined && smooth.type !== 'dynamic') {
47005 type = smooth.type;
47006 } // TODO: this is options merging; see if the standard routines can be used here.
47007
47008
47009 this.optionsBackup.edges = {
47010 smooth: smooth.enabled === undefined ? true : smooth.enabled,
47011 type: smooth.type === undefined ? 'dynamic' : smooth.type,
47012 roundness: smooth.roundness === undefined ? 0.5 : smooth.roundness,
47013 forceDirection: smooth.forceDirection === undefined ? false : smooth.forceDirection
47014 }; // NOTE: Copying an object to self; this is basically setting defaults for undefined variables
47015
47016 allOptions.edges.smooth = {
47017 enabled: smooth.enabled === undefined ? true : smooth.enabled,
47018 type: type,
47019 roundness: smooth.roundness === undefined ? 0.5 : smooth.roundness,
47020 forceDirection: smooth.forceDirection === undefined ? false : smooth.forceDirection
47021 };
47022 }
47023 } // Force all edges into static smooth curves.
47024 // Only applies to edges that do not use the global options for smooth.
47025
47026
47027 this.body.emitter.emit('_forceDisableDynamicCurves', type);
47028 }
47029
47030 return allOptions;
47031 }
47032 /**
47033 *
47034 * @returns {number}
47035 */
47036
47037 }, {
47038 key: "seededRandom",
47039 value: function seededRandom() {
47040 var x = Math.sin(this.randomSeed++) * 10000;
47041 return x - Math.floor(x);
47042 }
47043 /**
47044 *
47045 * @param {Array.<Node>} nodesArray
47046 */
47047
47048 }, {
47049 key: "positionInitially",
47050 value: function positionInitially(nodesArray) {
47051 if (this.options.hierarchical.enabled !== true) {
47052 this.randomSeed = this.initialRandomSeed;
47053 var radius = nodesArray.length + 50;
47054
47055 for (var i = 0; i < nodesArray.length; i++) {
47056 var node = nodesArray[i];
47057 var angle = 2 * Math.PI * this.seededRandom();
47058
47059 if (node.x === undefined) {
47060 node.x = radius * Math.cos(angle);
47061 }
47062
47063 if (node.y === undefined) {
47064 node.y = radius * Math.sin(angle);
47065 }
47066 }
47067 }
47068 }
47069 /**
47070 * Use Kamada Kawai to position nodes. This is quite a heavy algorithm so if there are a lot of nodes we
47071 * cluster them first to reduce the amount.
47072 */
47073
47074 }, {
47075 key: "layoutNetwork",
47076 value: function layoutNetwork() {
47077 if (this.options.hierarchical.enabled !== true && this.options.improvedLayout === true) {
47078 var indices = this.body.nodeIndices; // first check if we should Kamada Kawai to layout. The threshold is if less than half of the visible
47079 // nodes have predefined positions we use this.
47080
47081 var positionDefined = 0;
47082
47083 for (var i = 0; i < indices.length; i++) {
47084 var node = this.body.nodes[indices[i]];
47085
47086 if (node.predefinedPosition === true) {
47087 positionDefined += 1;
47088 }
47089 } // if less than half of the nodes have a predefined position we continue
47090
47091
47092 if (positionDefined < 0.5 * indices.length) {
47093 var MAX_LEVELS = 10;
47094 var level = 0;
47095 var clusterThreshold = this.options.clusterThreshold; //
47096 // Define the options for the hidden cluster nodes
47097 // These options don't propagate outside the clustering phase.
47098 //
47099 // Some options are explicitly disabled, because they may be set in group or default node options.
47100 // The clusters are never displayed, so most explicit settings here serve as performance optimizations.
47101 //
47102 // The explicit setting of 'shape' is to avoid `shape: 'image'`; images are not passed to the hidden
47103 // cluster nodes, leading to an exception on creation.
47104 //
47105 // All settings here are performance related, except when noted otherwise.
47106 //
47107
47108 var clusterOptions = {
47109 clusterNodeProperties: {
47110 shape: 'ellipse',
47111 // Bugfix: avoid type 'image', no images supplied
47112 label: '',
47113 // avoid label handling
47114 group: '',
47115 // avoid group handling
47116 font: {
47117 multi: false
47118 } // avoid font propagation
47119
47120 },
47121 clusterEdgeProperties: {
47122 label: '',
47123 // avoid label handling
47124 font: {
47125 multi: false
47126 },
47127 // avoid font propagation
47128 smooth: {
47129 enabled: false // avoid drawing penalty for complex edges
47130
47131 }
47132 }
47133 }; // if there are a lot of nodes, we cluster before we run the algorithm.
47134 // NOTE: this part fails to find clusters for large scale-free networks, which should
47135 // be easily clusterable.
47136 // TODO: examine why this is so
47137
47138 if (indices.length > clusterThreshold) {
47139 var startLength = indices.length;
47140
47141 while (indices.length > clusterThreshold && level <= MAX_LEVELS) {
47142 //console.time("clustering")
47143 level += 1;
47144 var before = indices.length; // if there are many nodes we do a hubsize cluster
47145
47146 if (level % 3 === 0) {
47147 this.body.modules.clustering.clusterBridges(clusterOptions);
47148 } else {
47149 this.body.modules.clustering.clusterOutliers(clusterOptions);
47150 }
47151
47152 var after = indices.length;
47153
47154 if (before == after && level % 3 !== 0) {
47155 this._declusterAll();
47156
47157 this.body.emitter.emit("_layoutFailed");
47158 console.info("This network could not be positioned by this version of the improved layout algorithm." + " Please disable improvedLayout for better performance.");
47159 return;
47160 } //console.timeEnd("clustering")
47161 //console.log(before,level,after);
47162
47163 } // increase the size of the edges
47164
47165
47166 this.body.modules.kamadaKawai.setOptions({
47167 springLength: Math.max(150, 2 * startLength)
47168 });
47169 }
47170
47171 if (level > MAX_LEVELS) {
47172 console.info("The clustering didn't succeed within the amount of interations allowed," + " progressing with partial result.");
47173 } // position the system for these nodes and edges
47174
47175
47176 this.body.modules.kamadaKawai.solve(indices, this.body.edgeIndices, true); // shift to center point
47177
47178 this._shiftToCenter(); // perturb the nodes a little bit to force the physics to kick in
47179
47180
47181 var offset = 70;
47182
47183 for (var _i = 0; _i < indices.length; _i++) {
47184 // Only perturb the nodes that aren't fixed
47185 var _node = this.body.nodes[indices[_i]];
47186
47187 if (_node.predefinedPosition === false) {
47188 _node.x += (0.5 - this.seededRandom()) * offset;
47189 _node.y += (0.5 - this.seededRandom()) * offset;
47190 }
47191 } // uncluster all clusters
47192
47193
47194 this._declusterAll(); // reposition all bezier nodes.
47195
47196
47197 this.body.emitter.emit("_repositionBezierNodes");
47198 }
47199 }
47200 }
47201 /**
47202 * Move all the nodes towards to the center so gravitational pull wil not move the nodes away from view
47203 * @private
47204 */
47205
47206 }, {
47207 key: "_shiftToCenter",
47208 value: function _shiftToCenter() {
47209 var range = NetworkUtil.getRangeCore(this.body.nodes, this.body.nodeIndices);
47210 var center = NetworkUtil.findCenter(range);
47211
47212 for (var i = 0; i < this.body.nodeIndices.length; i++) {
47213 var node = this.body.nodes[this.body.nodeIndices[i]];
47214 node.x -= center.x;
47215 node.y -= center.y;
47216 }
47217 }
47218 /**
47219 * Expands all clusters
47220 * @private
47221 */
47222
47223 }, {
47224 key: "_declusterAll",
47225 value: function _declusterAll() {
47226 var clustersPresent = true;
47227
47228 while (clustersPresent === true) {
47229 clustersPresent = false;
47230
47231 for (var i = 0; i < this.body.nodeIndices.length; i++) {
47232 if (this.body.nodes[this.body.nodeIndices[i]].isCluster === true) {
47233 clustersPresent = true;
47234 this.body.modules.clustering.openCluster(this.body.nodeIndices[i], {}, false);
47235 }
47236 }
47237
47238 if (clustersPresent === true) {
47239 this.body.emitter.emit('_dataChanged');
47240 }
47241 }
47242 }
47243 /**
47244 *
47245 * @returns {number|*}
47246 */
47247
47248 }, {
47249 key: "getSeed",
47250 value: function getSeed() {
47251 return this.initialRandomSeed;
47252 }
47253 /**
47254 * This is the main function to layout the nodes in a hierarchical way.
47255 * It checks if the node details are supplied correctly
47256 *
47257 * @private
47258 */
47259
47260 }, {
47261 key: "setupHierarchicalLayout",
47262 value: function setupHierarchicalLayout() {
47263 if (this.options.hierarchical.enabled === true && this.body.nodeIndices.length > 0) {
47264 // get the size of the largest hubs and check if the user has defined a level for a node.
47265 var node, nodeId;
47266 var definedLevel = false;
47267 var undefinedLevel = false;
47268 this.lastNodeOnLevel = {};
47269 this.hierarchical = new HierarchicalStatus();
47270
47271 for (nodeId in this.body.nodes) {
47272 if (this.body.nodes.hasOwnProperty(nodeId)) {
47273 node = this.body.nodes[nodeId];
47274
47275 if (node.options.level !== undefined) {
47276 definedLevel = true;
47277 this.hierarchical.levels[nodeId] = node.options.level;
47278 } else {
47279 undefinedLevel = true;
47280 }
47281 }
47282 } // if the user defined some levels but not all, alert and run without hierarchical layout
47283
47284
47285 if (undefinedLevel === true && definedLevel === true) {
47286 throw new Error('To use the hierarchical layout, nodes require either no predefined levels' + ' or levels have to be defined for all nodes.');
47287 } else {
47288 // define levels if undefined by the users. Based on hubsize.
47289 if (undefinedLevel === true) {
47290 var sortMethod = this.options.hierarchical.sortMethod;
47291
47292 if (sortMethod === 'hubsize') {
47293 this._determineLevelsByHubsize();
47294 } else if (sortMethod === 'directed') {
47295 this._determineLevelsDirected();
47296 } else if (sortMethod === 'custom') {
47297 this._determineLevelsCustomCallback();
47298 }
47299 } // fallback for cases where there are nodes but no edges
47300
47301
47302 for (var _nodeId2 in this.body.nodes) {
47303 if (this.body.nodes.hasOwnProperty(_nodeId2)) {
47304 this.hierarchical.ensureLevel(_nodeId2);
47305 }
47306 } // check the distribution of the nodes per level.
47307
47308
47309 var distribution = this._getDistribution(); // get the parent children relations.
47310
47311
47312 this._generateMap(); // place the nodes on the canvas.
47313
47314
47315 this._placeNodesByHierarchy(distribution); // condense the whitespace.
47316
47317
47318 this._condenseHierarchy(); // shift to center so gravity does not have to do much
47319
47320
47321 this._shiftToCenter();
47322 }
47323 }
47324 }
47325 /**
47326 * @private
47327 */
47328
47329 }, {
47330 key: "_condenseHierarchy",
47331 value: function _condenseHierarchy() {
47332 var _this3 = this;
47333
47334 // Global var in this scope to define when the movement has stopped.
47335 var stillShifting = false;
47336 var branches = {}; // first we have some methods to help shifting trees around.
47337 // the main method to shift the trees
47338
47339 var shiftTrees = function shiftTrees() {
47340 var treeSizes = getTreeSizes();
47341 var shiftBy = 0;
47342
47343 for (var i = 0; i < treeSizes.length - 1; i++) {
47344 var diff = treeSizes[i].max - treeSizes[i + 1].min;
47345 shiftBy += diff + _this3.options.hierarchical.treeSpacing;
47346 shiftTree(i + 1, shiftBy);
47347 }
47348 }; // shift a single tree by an offset
47349
47350
47351 var shiftTree = function shiftTree(index, offset) {
47352 var trees = _this3.hierarchical.trees;
47353
47354 for (var nodeId in trees) {
47355 if (trees.hasOwnProperty(nodeId)) {
47356 if (trees[nodeId] === index) {
47357 _this3.direction.shift(nodeId, offset);
47358 }
47359 }
47360 }
47361 }; // get the width of all trees
47362
47363
47364 var getTreeSizes = function getTreeSizes() {
47365 var treeWidths = [];
47366
47367 for (var i = 0; i < _this3.hierarchical.numTrees(); i++) {
47368 treeWidths.push(_this3.direction.getTreeSize(i));
47369 }
47370
47371 return treeWidths;
47372 }; // get a map of all nodes in this branch
47373
47374
47375 var getBranchNodes = function getBranchNodes(source, map) {
47376 if (map[source.id]) {
47377 return;
47378 }
47379
47380 map[source.id] = true;
47381
47382 if (_this3.hierarchical.childrenReference[source.id]) {
47383 var children = _this3.hierarchical.childrenReference[source.id];
47384
47385 if (children.length > 0) {
47386 for (var i = 0; i < children.length; i++) {
47387 getBranchNodes(_this3.body.nodes[children[i]], map);
47388 }
47389 }
47390 }
47391 }; // get a min max width as well as the maximum movement space it has on either sides
47392 // we use min max terminology because width and height can interchange depending on the direction of the layout
47393
47394
47395 var getBranchBoundary = function getBranchBoundary(branchMap) {
47396 var maxLevel = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1e9;
47397 var minSpace = 1e9;
47398 var maxSpace = 1e9;
47399 var min = 1e9;
47400 var max = -1e9;
47401
47402 for (var branchNode in branchMap) {
47403 if (branchMap.hasOwnProperty(branchNode)) {
47404 var node = _this3.body.nodes[branchNode];
47405 var level = _this3.hierarchical.levels[node.id];
47406
47407 var position = _this3.direction.getPosition(node); // get the space around the node.
47408
47409
47410 var _this3$_getSpaceAroun = _this3._getSpaceAroundNode(node, branchMap),
47411 _this3$_getSpaceAroun2 = _slicedToArray(_this3$_getSpaceAroun, 2),
47412 minSpaceNode = _this3$_getSpaceAroun2[0],
47413 maxSpaceNode = _this3$_getSpaceAroun2[1];
47414
47415 minSpace = Math.min(minSpaceNode, minSpace);
47416 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.
47417
47418 if (level <= maxLevel) {
47419 min = Math.min(position, min);
47420 max = Math.max(position, max);
47421 }
47422 }
47423 }
47424
47425 return [min, max, minSpace, maxSpace];
47426 }; // check what the maximum level is these nodes have in common.
47427
47428
47429 var getCollisionLevel = function getCollisionLevel(node1, node2) {
47430 var maxLevel1 = _this3.hierarchical.getMaxLevel(node1.id);
47431
47432 var maxLevel2 = _this3.hierarchical.getMaxLevel(node2.id);
47433
47434 return Math.min(maxLevel1, maxLevel2);
47435 };
47436 /**
47437 * Condense elements. These can be nodes or branches depending on the callback.
47438 *
47439 * @param {function} callback
47440 * @param {Array.<number>} levels
47441 * @param {*} centerParents
47442 */
47443
47444
47445 var shiftElementsCloser = function shiftElementsCloser(callback, levels, centerParents) {
47446 var hier = _this3.hierarchical;
47447
47448 for (var i = 0; i < levels.length; i++) {
47449 var level = levels[i];
47450 var levelNodes = hier.distributionOrdering[level];
47451
47452 if (levelNodes.length > 1) {
47453 for (var j = 0; j < levelNodes.length - 1; j++) {
47454 var node1 = levelNodes[j];
47455 var node2 = levelNodes[j + 1]; // NOTE: logic maintained as it was; if nodes have same ancestor,
47456 // then of course they are in the same sub-network.
47457
47458 if (hier.hasSameParent(node1, node2) && hier.inSameSubNetwork(node1, node2)) {
47459 callback(node1, node2, centerParents);
47460 }
47461 }
47462 }
47463 }
47464 }; // callback for shifting branches
47465
47466
47467 var branchShiftCallback = function branchShiftCallback(node1, node2) {
47468 var centerParent = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
47469
47470 //window.CALLBACKS.push(() => {
47471 var pos1 = _this3.direction.getPosition(node1);
47472
47473 var pos2 = _this3.direction.getPosition(node2);
47474
47475 var diffAbs = Math.abs(pos2 - pos1);
47476 var nodeSpacing = _this3.options.hierarchical.nodeSpacing; //console.log("NOW CHECKING:", node1.id, node2.id, diffAbs);
47477
47478 if (diffAbs > nodeSpacing) {
47479 var branchNodes1 = {};
47480 var branchNodes2 = {};
47481 getBranchNodes(node1, branchNodes1);
47482 getBranchNodes(node2, branchNodes2); // check the largest distance between the branches
47483
47484 var maxLevel = getCollisionLevel(node1, node2);
47485 var branchNodeBoundary1 = getBranchBoundary(branchNodes1, maxLevel);
47486 var branchNodeBoundary2 = getBranchBoundary(branchNodes2, maxLevel);
47487 var max1 = branchNodeBoundary1[1];
47488 var min2 = branchNodeBoundary2[0];
47489 var minSpace2 = branchNodeBoundary2[2]; //console.log(node1.id, getBranchBoundary(branchNodes1, maxLevel), node2.id,
47490 // getBranchBoundary(branchNodes2, maxLevel), maxLevel);
47491
47492 var diffBranch = Math.abs(max1 - min2);
47493
47494 if (diffBranch > nodeSpacing) {
47495 var offset = max1 - min2 + nodeSpacing;
47496
47497 if (offset < -minSpace2 + nodeSpacing) {
47498 offset = -minSpace2 + nodeSpacing; //console.log("RESETTING OFFSET", max1 - min2 + this.options.hierarchical.nodeSpacing, -minSpace2, offset);
47499 }
47500
47501 if (offset < 0) {
47502 //console.log("SHIFTING", node2.id, offset);
47503 _this3._shiftBlock(node2.id, offset);
47504
47505 stillShifting = true;
47506 if (centerParent === true) _this3._centerParent(node2);
47507 }
47508 }
47509 } //this.body.emitter.emit("_redraw");})
47510
47511 };
47512
47513 var minimizeEdgeLength = function minimizeEdgeLength(iterations, node) {
47514 //window.CALLBACKS.push(() => {
47515 // console.log("ts",node.id);
47516 var nodeId = node.id;
47517 var allEdges = node.edges;
47518 var nodeLevel = _this3.hierarchical.levels[node.id]; // gather constants
47519
47520 var C2 = _this3.options.hierarchical.levelSeparation * _this3.options.hierarchical.levelSeparation;
47521 var referenceNodes = {};
47522 var aboveEdges = [];
47523
47524 for (var i = 0; i < allEdges.length; i++) {
47525 var edge = allEdges[i];
47526
47527 if (edge.toId != edge.fromId) {
47528 var otherNode = edge.toId == nodeId ? edge.from : edge.to;
47529 referenceNodes[allEdges[i].id] = otherNode;
47530
47531 if (_this3.hierarchical.levels[otherNode.id] < nodeLevel) {
47532 aboveEdges.push(edge);
47533 }
47534 }
47535 } // differentiated sum of lengths based on only moving one node over one axis
47536
47537
47538 var getFx = function getFx(point, edges) {
47539 var sum = 0;
47540
47541 for (var _i2 = 0; _i2 < edges.length; _i2++) {
47542 if (referenceNodes[edges[_i2].id] !== undefined) {
47543 var a = _this3.direction.getPosition(referenceNodes[edges[_i2].id]) - point;
47544 sum += a / Math.sqrt(a * a + C2);
47545 }
47546 }
47547
47548 return sum;
47549 }; // doubly differentiated sum of lengths based on only moving one node over one axis
47550
47551
47552 var getDFx = function getDFx(point, edges) {
47553 var sum = 0;
47554
47555 for (var _i3 = 0; _i3 < edges.length; _i3++) {
47556 if (referenceNodes[edges[_i3].id] !== undefined) {
47557 var a = _this3.direction.getPosition(referenceNodes[edges[_i3].id]) - point;
47558 sum -= C2 * Math.pow(a * a + C2, -1.5);
47559 }
47560 }
47561
47562 return sum;
47563 };
47564
47565 var getGuess = function getGuess(iterations, edges) {
47566 var guess = _this3.direction.getPosition(node); // Newton's method for optimization
47567
47568
47569 var guessMap = {};
47570
47571 for (var _i4 = 0; _i4 < iterations; _i4++) {
47572 var fx = getFx(guess, edges);
47573 var dfx = getDFx(guess, edges); // we limit the movement to avoid instability.
47574
47575 var limit = 40;
47576 var ratio = Math.max(-limit, Math.min(limit, Math.round(fx / dfx)));
47577 guess = guess - ratio; // reduce duplicates
47578
47579 if (guessMap[guess] !== undefined) {
47580 break;
47581 }
47582
47583 guessMap[guess] = _i4;
47584 }
47585
47586 return guess;
47587 };
47588
47589 var moveBranch = function moveBranch(guess) {
47590 // position node if there is space
47591 var nodePosition = _this3.direction.getPosition(node); // check movable area of the branch
47592
47593
47594 if (branches[node.id] === undefined) {
47595 var branchNodes = {};
47596 getBranchNodes(node, branchNodes);
47597 branches[node.id] = branchNodes;
47598 }
47599
47600 var branchBoundary = getBranchBoundary(branches[node.id]);
47601 var minSpaceBranch = branchBoundary[2];
47602 var maxSpaceBranch = branchBoundary[3];
47603 var diff = guess - nodePosition; // check if we are allowed to move the node:
47604
47605 var branchOffset = 0;
47606
47607 if (diff > 0) {
47608 branchOffset = Math.min(diff, maxSpaceBranch - _this3.options.hierarchical.nodeSpacing);
47609 } else if (diff < 0) {
47610 branchOffset = -Math.min(-diff, minSpaceBranch - _this3.options.hierarchical.nodeSpacing);
47611 }
47612
47613 if (branchOffset != 0) {
47614 //console.log("moving branch:",branchOffset, maxSpaceBranch, minSpaceBranch)
47615 _this3._shiftBlock(node.id, branchOffset); //this.body.emitter.emit("_redraw");
47616
47617
47618 stillShifting = true;
47619 }
47620 };
47621
47622 var moveNode = function moveNode(guess) {
47623 var nodePosition = _this3.direction.getPosition(node); // position node if there is space
47624
47625
47626 var _this3$_getSpaceAroun3 = _this3._getSpaceAroundNode(node),
47627 _this3$_getSpaceAroun4 = _slicedToArray(_this3$_getSpaceAroun3, 2),
47628 minSpace = _this3$_getSpaceAroun4[0],
47629 maxSpace = _this3$_getSpaceAroun4[1];
47630
47631 var diff = guess - nodePosition; // check if we are allowed to move the node:
47632
47633 var newPosition = nodePosition;
47634
47635 if (diff > 0) {
47636 newPosition = Math.min(nodePosition + (maxSpace - _this3.options.hierarchical.nodeSpacing), guess);
47637 } else if (diff < 0) {
47638 newPosition = Math.max(nodePosition - (minSpace - _this3.options.hierarchical.nodeSpacing), guess);
47639 }
47640
47641 if (newPosition !== nodePosition) {
47642 //console.log("moving Node:",diff, minSpace, maxSpace);
47643 _this3.direction.setPosition(node, newPosition); //this.body.emitter.emit("_redraw");
47644
47645
47646 stillShifting = true;
47647 }
47648 };
47649
47650 var guess = getGuess(iterations, aboveEdges);
47651 moveBranch(guess);
47652 guess = getGuess(iterations, allEdges);
47653 moveNode(guess); //})
47654 }; // method to remove whitespace between branches. Because we do bottom up, we can center the parents.
47655
47656
47657 var minimizeEdgeLengthBottomUp = function minimizeEdgeLengthBottomUp(iterations) {
47658 var levels = _this3.hierarchical.getLevels();
47659
47660 levels = levels.reverse();
47661
47662 for (var i = 0; i < iterations; i++) {
47663 stillShifting = false;
47664
47665 for (var j = 0; j < levels.length; j++) {
47666 var level = levels[j];
47667 var levelNodes = _this3.hierarchical.distributionOrdering[level];
47668
47669 for (var k = 0; k < levelNodes.length; k++) {
47670 minimizeEdgeLength(1000, levelNodes[k]);
47671 }
47672 }
47673
47674 if (stillShifting !== true) {
47675 //console.log("FINISHED minimizeEdgeLengthBottomUp IN " + i);
47676 break;
47677 }
47678 }
47679 }; // method to remove whitespace between branches. Because we do bottom up, we can center the parents.
47680
47681
47682 var shiftBranchesCloserBottomUp = function shiftBranchesCloserBottomUp(iterations) {
47683 var levels = _this3.hierarchical.getLevels();
47684
47685 levels = levels.reverse();
47686
47687 for (var i = 0; i < iterations; i++) {
47688 stillShifting = false;
47689 shiftElementsCloser(branchShiftCallback, levels, true);
47690
47691 if (stillShifting !== true) {
47692 //console.log("FINISHED shiftBranchesCloserBottomUp IN " + (i+1));
47693 break;
47694 }
47695 }
47696 }; // center all parents
47697
47698
47699 var centerAllParents = function centerAllParents() {
47700 for (var nodeId in _this3.body.nodes) {
47701 if (_this3.body.nodes.hasOwnProperty(nodeId)) _this3._centerParent(_this3.body.nodes[nodeId]);
47702 }
47703 }; // center all parents
47704
47705
47706 var centerAllParentsBottomUp = function centerAllParentsBottomUp() {
47707 var levels = _this3.hierarchical.getLevels();
47708
47709 levels = levels.reverse();
47710
47711 for (var i = 0; i < levels.length; i++) {
47712 var level = levels[i];
47713 var levelNodes = _this3.hierarchical.distributionOrdering[level];
47714
47715 for (var j = 0; j < levelNodes.length; j++) {
47716 _this3._centerParent(levelNodes[j]);
47717 }
47718 }
47719 }; // the actual work is done here.
47720
47721
47722 if (this.options.hierarchical.blockShifting === true) {
47723 shiftBranchesCloserBottomUp(5);
47724 centerAllParents();
47725 } // minimize edge length
47726
47727
47728 if (this.options.hierarchical.edgeMinimization === true) {
47729 minimizeEdgeLengthBottomUp(20);
47730 }
47731
47732 if (this.options.hierarchical.parentCentralization === true) {
47733 centerAllParentsBottomUp();
47734 }
47735
47736 shiftTrees();
47737 }
47738 /**
47739 * This gives the space around the node. IF a map is supplied, it will only check against nodes NOT in the map.
47740 * This is used to only get the distances to nodes outside of a branch.
47741 * @param {Node} node
47742 * @param {{Node.id: vis.Node}} map
47743 * @returns {number[]}
47744 * @private
47745 */
47746
47747 }, {
47748 key: "_getSpaceAroundNode",
47749 value: function _getSpaceAroundNode(node, map) {
47750 var useMap = true;
47751
47752 if (map === undefined) {
47753 useMap = false;
47754 }
47755
47756 var level = this.hierarchical.levels[node.id];
47757
47758 if (level !== undefined) {
47759 var index = this.hierarchical.distributionIndex[node.id];
47760 var position = this.direction.getPosition(node);
47761 var ordering = this.hierarchical.distributionOrdering[level];
47762 var minSpace = 1e9;
47763 var maxSpace = 1e9;
47764
47765 if (index !== 0) {
47766 var prevNode = ordering[index - 1];
47767
47768 if (useMap === true && map[prevNode.id] === undefined || useMap === false) {
47769 var prevPos = this.direction.getPosition(prevNode);
47770 minSpace = position - prevPos;
47771 }
47772 }
47773
47774 if (index != ordering.length - 1) {
47775 var nextNode = ordering[index + 1];
47776
47777 if (useMap === true && map[nextNode.id] === undefined || useMap === false) {
47778 var nextPos = this.direction.getPosition(nextNode);
47779 maxSpace = Math.min(maxSpace, nextPos - position);
47780 }
47781 }
47782
47783 return [minSpace, maxSpace];
47784 } else {
47785 return [0, 0];
47786 }
47787 }
47788 /**
47789 * We use this method to center a parent node and check if it does not cross other nodes when it does.
47790 * @param {Node} node
47791 * @private
47792 */
47793
47794 }, {
47795 key: "_centerParent",
47796 value: function _centerParent(node) {
47797 if (this.hierarchical.parentReference[node.id]) {
47798 var parents = this.hierarchical.parentReference[node.id];
47799
47800 for (var i = 0; i < parents.length; i++) {
47801 var parentId = parents[i];
47802 var parentNode = this.body.nodes[parentId];
47803 var children = this.hierarchical.childrenReference[parentId];
47804
47805 if (children !== undefined) {
47806 // get the range of the children
47807 var newPosition = this._getCenterPosition(children);
47808
47809 var position = this.direction.getPosition(parentNode);
47810
47811 var _this$_getSpaceAround = this._getSpaceAroundNode(parentNode),
47812 _this$_getSpaceAround2 = _slicedToArray(_this$_getSpaceAround, 2),
47813 minSpace = _this$_getSpaceAround2[0],
47814 maxSpace = _this$_getSpaceAround2[1];
47815
47816 var diff = position - newPosition;
47817
47818 if (diff < 0 && Math.abs(diff) < maxSpace - this.options.hierarchical.nodeSpacing || diff > 0 && Math.abs(diff) < minSpace - this.options.hierarchical.nodeSpacing) {
47819 this.direction.setPosition(parentNode, newPosition);
47820 }
47821 }
47822 }
47823 }
47824 }
47825 /**
47826 * This function places the nodes on the canvas based on the hierarchial distribution.
47827 *
47828 * @param {Object} distribution | obtained by the function this._getDistribution()
47829 * @private
47830 */
47831
47832 }, {
47833 key: "_placeNodesByHierarchy",
47834 value: function _placeNodesByHierarchy(distribution) {
47835 this.positionedNodes = {}; // start placing all the level 0 nodes first. Then recursively position their branches.
47836
47837 for (var level in distribution) {
47838 if (distribution.hasOwnProperty(level)) {
47839 // sort nodes in level by position:
47840 var nodeArray = Object.keys(distribution[level]);
47841 nodeArray = this._indexArrayToNodes(nodeArray);
47842 this.direction.sort(nodeArray);
47843 var handledNodeCount = 0;
47844
47845 for (var i = 0; i < nodeArray.length; i++) {
47846 var node = nodeArray[i];
47847
47848 if (this.positionedNodes[node.id] === undefined) {
47849 var spacing = this.options.hierarchical.nodeSpacing;
47850 var pos = spacing * handledNodeCount; // We get the X or Y values we need and store them in pos and previousPos.
47851 // The get and set make sure we get X or Y
47852
47853 if (handledNodeCount > 0) {
47854 pos = this.direction.getPosition(nodeArray[i - 1]) + spacing;
47855 }
47856
47857 this.direction.setPosition(node, pos, level);
47858
47859 this._validatePositionAndContinue(node, level, pos);
47860
47861 handledNodeCount++;
47862 }
47863 }
47864 }
47865 }
47866 }
47867 /**
47868 * This is a recursively called function to enumerate the branches from the largest hubs and place the nodes
47869 * on a X position that ensures there will be no overlap.
47870 *
47871 * @param {Node.id} parentId
47872 * @param {number} parentLevel
47873 * @private
47874 */
47875
47876 }, {
47877 key: "_placeBranchNodes",
47878 value: function _placeBranchNodes(parentId, parentLevel) {
47879 var childRef = this.hierarchical.childrenReference[parentId]; // if this is not a parent, cancel the placing. This can happen with multiple parents to one child.
47880
47881 if (childRef === undefined) {
47882 return;
47883 } // get a list of childNodes
47884
47885
47886 var childNodes = [];
47887
47888 for (var i = 0; i < childRef.length; i++) {
47889 childNodes.push(this.body.nodes[childRef[i]]);
47890 } // use the positions to order the nodes.
47891
47892
47893 this.direction.sort(childNodes); // position the childNodes
47894
47895 for (var _i5 = 0; _i5 < childNodes.length; _i5++) {
47896 var childNode = childNodes[_i5];
47897 var childNodeLevel = this.hierarchical.levels[childNode.id]; // check if the child node is below the parent node and if it has already been positioned.
47898
47899 if (childNodeLevel > parentLevel && this.positionedNodes[childNode.id] === undefined) {
47900 // get the amount of space required for this node. If parent the width is based on the amount of children.
47901 var spacing = this.options.hierarchical.nodeSpacing;
47902 var pos = void 0; // we get the X or Y values we need and store them in pos and previousPos.
47903 // The get and set make sure we get X or Y
47904
47905 if (_i5 === 0) {
47906 pos = this.direction.getPosition(this.body.nodes[parentId]);
47907 } else {
47908 pos = this.direction.getPosition(childNodes[_i5 - 1]) + spacing;
47909 }
47910
47911 this.direction.setPosition(childNode, pos, childNodeLevel);
47912
47913 this._validatePositionAndContinue(childNode, childNodeLevel, pos);
47914 } else {
47915 return;
47916 }
47917 } // center the parent nodes.
47918
47919
47920 var center = this._getCenterPosition(childNodes);
47921
47922 this.direction.setPosition(this.body.nodes[parentId], center, parentLevel);
47923 }
47924 /**
47925 * This method checks for overlap and if required shifts the branch. It also keeps records of positioned nodes.
47926 * Finally it will call _placeBranchNodes to place the branch nodes.
47927 * @param {Node} node
47928 * @param {number} level
47929 * @param {number} pos
47930 * @private
47931 */
47932
47933 }, {
47934 key: "_validatePositionAndContinue",
47935 value: function _validatePositionAndContinue(node, level, pos) {
47936 // This method only works for formal trees and formal forests
47937 // Early exit if this is not the case
47938 if (!this.hierarchical.isTree) return; // if overlap has been detected, we shift the branch
47939
47940 if (this.lastNodeOnLevel[level] !== undefined) {
47941 var previousPos = this.direction.getPosition(this.body.nodes[this.lastNodeOnLevel[level]]);
47942
47943 if (pos - previousPos < this.options.hierarchical.nodeSpacing) {
47944 var diff = previousPos + this.options.hierarchical.nodeSpacing - pos;
47945
47946 var sharedParent = this._findCommonParent(this.lastNodeOnLevel[level], node.id);
47947
47948 this._shiftBlock(sharedParent.withChild, diff);
47949 }
47950 }
47951
47952 this.lastNodeOnLevel[level] = node.id; // store change in position.
47953
47954 this.positionedNodes[node.id] = true;
47955
47956 this._placeBranchNodes(node.id, level);
47957 }
47958 /**
47959 * Receives an array with node indices and returns an array with the actual node references.
47960 * Used for sorting based on node properties.
47961 * @param {Array.<Node.id>} idArray
47962 * @returns {Array.<Node>}
47963 */
47964
47965 }, {
47966 key: "_indexArrayToNodes",
47967 value: function _indexArrayToNodes(idArray) {
47968 var array = [];
47969
47970 for (var i = 0; i < idArray.length; i++) {
47971 array.push(this.body.nodes[idArray[i]]);
47972 }
47973
47974 return array;
47975 }
47976 /**
47977 * This function get the distribution of levels based on hubsize
47978 *
47979 * @returns {Object}
47980 * @private
47981 */
47982
47983 }, {
47984 key: "_getDistribution",
47985 value: function _getDistribution() {
47986 var distribution = {};
47987 var nodeId, node; // we fix Y because the hierarchy is vertical,
47988 // we fix X so we do not give a node an x position for a second time.
47989 // the fix of X is removed after the x value has been set.
47990
47991 for (nodeId in this.body.nodes) {
47992 if (this.body.nodes.hasOwnProperty(nodeId)) {
47993 node = this.body.nodes[nodeId];
47994 var level = this.hierarchical.levels[nodeId] === undefined ? 0 : this.hierarchical.levels[nodeId];
47995 this.direction.fix(node, level);
47996
47997 if (distribution[level] === undefined) {
47998 distribution[level] = {};
47999 }
48000
48001 distribution[level][nodeId] = node;
48002 }
48003 }
48004
48005 return distribution;
48006 }
48007 /**
48008 * Return the active (i.e. visible) edges for this node
48009 *
48010 * @param {Node} node
48011 * @returns {Array.<vis.Edge>} Array of edge instances
48012 * @private
48013 */
48014
48015 }, {
48016 key: "_getActiveEdges",
48017 value: function _getActiveEdges(node) {
48018 var _this4 = this;
48019
48020 var result = [];
48021 forEach(node.edges, function (edge) {
48022 if (_this4.body.edgeIndices.indexOf(edge.id) !== -1) {
48023 result.push(edge);
48024 }
48025 });
48026 return result;
48027 }
48028 /**
48029 * Get the hubsizes for all active nodes.
48030 *
48031 * @returns {number}
48032 * @private
48033 */
48034
48035 }, {
48036 key: "_getHubSizes",
48037 value: function _getHubSizes() {
48038 var _this5 = this;
48039
48040 var hubSizes = {};
48041 var nodeIds = this.body.nodeIndices;
48042 forEach(nodeIds, function (nodeId) {
48043 var node = _this5.body.nodes[nodeId];
48044
48045 var hubSize = _this5._getActiveEdges(node).length;
48046
48047 hubSizes[hubSize] = true;
48048 }); // Make an array of the size sorted descending
48049
48050 var result = [];
48051 forEach(hubSizes, function (size) {
48052 result.push(Number(size));
48053 });
48054 timsort$1.sort(result, function (a, b) {
48055 return b - a;
48056 });
48057 return result;
48058 }
48059 /**
48060 * this function allocates nodes in levels based on the recursive branching from the largest hubs.
48061 *
48062 * @private
48063 */
48064
48065 }, {
48066 key: "_determineLevelsByHubsize",
48067 value: function _determineLevelsByHubsize() {
48068 var _this6 = this;
48069
48070 var levelDownstream = function levelDownstream(nodeA, nodeB) {
48071 _this6.hierarchical.levelDownstream(nodeA, nodeB);
48072 };
48073
48074 var hubSizes = this._getHubSizes();
48075
48076 var _loop = function _loop(i) {
48077 var hubSize = hubSizes[i];
48078 if (hubSize === 0) return "break";
48079 forEach(_this6.body.nodeIndices, function (nodeId) {
48080 var node = _this6.body.nodes[nodeId];
48081
48082 if (hubSize === _this6._getActiveEdges(node).length) {
48083 _this6._crawlNetwork(levelDownstream, nodeId);
48084 }
48085 });
48086 };
48087
48088 for (var i = 0; i < hubSizes.length; ++i) {
48089 var _ret = _loop(i);
48090
48091 if (_ret === "break") break;
48092 }
48093 }
48094 /**
48095 * TODO: release feature
48096 * TODO: Determine if this feature is needed at all
48097 *
48098 * @private
48099 */
48100
48101 }, {
48102 key: "_determineLevelsCustomCallback",
48103 value: function _determineLevelsCustomCallback() {
48104 var _this7 = this;
48105
48106 var minLevel = 100000; // TODO: this should come from options.
48107
48108 var customCallback = function customCallback(nodeA, nodeB, edge) {// eslint-disable-line no-unused-vars
48109 }; // TODO: perhaps move to HierarchicalStatus.
48110 // But I currently don't see the point, this method is not used.
48111
48112
48113 var levelByDirection = function levelByDirection(nodeA, nodeB, edge) {
48114 var levelA = _this7.hierarchical.levels[nodeA.id]; // set initial level
48115
48116 if (levelA === undefined) {
48117 levelA = _this7.hierarchical.levels[nodeA.id] = minLevel;
48118 }
48119
48120 var diff = customCallback(NetworkUtil.cloneOptions(nodeA, 'node'), NetworkUtil.cloneOptions(nodeB, 'node'), NetworkUtil.cloneOptions(edge, 'edge'));
48121 _this7.hierarchical.levels[nodeB.id] = levelA + diff;
48122 };
48123
48124 this._crawlNetwork(levelByDirection);
48125
48126 this.hierarchical.setMinLevelToZero(this.body.nodes);
48127 }
48128 /**
48129 * Allocate nodes in levels based on the direction of the edges.
48130 *
48131 * @private
48132 */
48133
48134 }, {
48135 key: "_determineLevelsDirected",
48136 value: function _determineLevelsDirected() {
48137 var _this8 = this;
48138
48139 var nodes = this.body.nodeIndices.map(function (id) {
48140 return _this8.body.nodes[id];
48141 });
48142 var levels = this.hierarchical.levels;
48143
48144 if (this.options.hierarchical.shakeTowards === "roots") {
48145 this.hierarchical.levels = fillLevelsByDirectionRoots(nodes, this.hierarchical.levels);
48146 } else {
48147 this.hierarchical.levels = fillLevelsByDirectionLeaves(nodes, this.hierarchical.levels);
48148 }
48149
48150 this.hierarchical.setMinLevelToZero(this.body.nodes);
48151 }
48152 /**
48153 * Update the bookkeeping of parent and child.
48154 * @private
48155 */
48156
48157 }, {
48158 key: "_generateMap",
48159 value: function _generateMap() {
48160 var _this9 = this;
48161
48162 var fillInRelations = function fillInRelations(parentNode, childNode) {
48163 if (_this9.hierarchical.levels[childNode.id] > _this9.hierarchical.levels[parentNode.id]) {
48164 _this9.hierarchical.addRelation(parentNode.id, childNode.id);
48165 }
48166 };
48167
48168 this._crawlNetwork(fillInRelations);
48169
48170 this.hierarchical.checkIfTree();
48171 }
48172 /**
48173 * Crawl over the entire network and use a callback on each node couple that is connected to each other.
48174 * @param {function} [callback=function(){}] | will receive nodeA, nodeB and the connecting edge. A and B are distinct.
48175 * @param {Node.id} startingNodeId
48176 * @private
48177 */
48178
48179 }, {
48180 key: "_crawlNetwork",
48181 value: function _crawlNetwork() {
48182 var _this10 = this;
48183
48184 var callback = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : function () {};
48185 var startingNodeId = arguments.length > 1 ? arguments[1] : undefined;
48186 var progress = {};
48187
48188 var crawler = function crawler(node, tree) {
48189 if (progress[node.id] === undefined) {
48190 _this10.hierarchical.setTreeIndex(node, tree);
48191
48192 progress[node.id] = true;
48193 var childNode;
48194
48195 var edges = _this10._getActiveEdges(node);
48196
48197 for (var i = 0; i < edges.length; i++) {
48198 var edge = edges[i];
48199
48200 if (edge.connected === true) {
48201 if (edge.toId == node.id) {
48202 // Not '===' because id's can be string and numeric
48203 childNode = edge.from;
48204 } else {
48205 childNode = edge.to;
48206 }
48207
48208 if (node.id != childNode.id) {
48209 // Not '!==' because id's can be string and numeric
48210 callback(node, childNode, edge);
48211 crawler(childNode, tree);
48212 }
48213 }
48214 }
48215 }
48216 };
48217
48218 if (startingNodeId === undefined) {
48219 // Crawl over all nodes
48220 var treeIndex = 0; // Serves to pass a unique id for the current distinct tree
48221
48222 for (var i = 0; i < this.body.nodeIndices.length; i++) {
48223 var nodeId = this.body.nodeIndices[i];
48224
48225 if (progress[nodeId] === undefined) {
48226 var node = this.body.nodes[nodeId];
48227 crawler(node, treeIndex);
48228 treeIndex += 1;
48229 }
48230 }
48231 } else {
48232 // Crawl from the given starting node
48233 var _node2 = this.body.nodes[startingNodeId];
48234
48235 if (_node2 === undefined) {
48236 console.error("Node not found:", startingNodeId);
48237 return;
48238 }
48239
48240 crawler(_node2);
48241 }
48242 }
48243 /**
48244 * Shift a branch a certain distance
48245 * @param {Node.id} parentId
48246 * @param {number} diff
48247 * @private
48248 */
48249
48250 }, {
48251 key: "_shiftBlock",
48252 value: function _shiftBlock(parentId, diff) {
48253 var _this11 = this;
48254
48255 var progress = {};
48256
48257 var shifter = function shifter(parentId) {
48258 if (progress[parentId]) {
48259 return;
48260 }
48261
48262 progress[parentId] = true;
48263
48264 _this11.direction.shift(parentId, diff);
48265
48266 var childRef = _this11.hierarchical.childrenReference[parentId];
48267
48268 if (childRef !== undefined) {
48269 for (var i = 0; i < childRef.length; i++) {
48270 shifter(childRef[i]);
48271 }
48272 }
48273 };
48274
48275 shifter(parentId);
48276 }
48277 /**
48278 * Find a common parent between branches.
48279 * @param {Node.id} childA
48280 * @param {Node.id} childB
48281 * @returns {{foundParent, withChild}}
48282 * @private
48283 */
48284
48285 }, {
48286 key: "_findCommonParent",
48287 value: function _findCommonParent(childA, childB) {
48288 var _this12 = this;
48289
48290 var parents = {};
48291
48292 var iterateParents = function iterateParents(parents, child) {
48293 var parentRef = _this12.hierarchical.parentReference[child];
48294
48295 if (parentRef !== undefined) {
48296 for (var i = 0; i < parentRef.length; i++) {
48297 var parent = parentRef[i];
48298 parents[parent] = true;
48299 iterateParents(parents, parent);
48300 }
48301 }
48302 };
48303
48304 var findParent = function findParent(parents, child) {
48305 var parentRef = _this12.hierarchical.parentReference[child];
48306
48307 if (parentRef !== undefined) {
48308 for (var i = 0; i < parentRef.length; i++) {
48309 var parent = parentRef[i];
48310
48311 if (parents[parent] !== undefined) {
48312 return {
48313 foundParent: parent,
48314 withChild: child
48315 };
48316 }
48317
48318 var branch = findParent(parents, parent);
48319
48320 if (branch.foundParent !== null) {
48321 return branch;
48322 }
48323 }
48324 }
48325
48326 return {
48327 foundParent: null,
48328 withChild: child
48329 };
48330 };
48331
48332 iterateParents(parents, childA);
48333 return findParent(parents, childB);
48334 }
48335 /**
48336 * Set the strategy pattern for handling the coordinates given the current direction.
48337 *
48338 * The individual instances contain all the operations and data specific to a layout direction.
48339 *
48340 * @param {Node} node
48341 * @param {{x: number, y: number}} position
48342 * @param {number} level
48343 * @param {boolean} [doNotUpdate=false]
48344 * @private
48345 */
48346
48347 }, {
48348 key: "setDirectionStrategy",
48349 value: function setDirectionStrategy() {
48350 var isVertical = this.options.hierarchical.direction === 'UD' || this.options.hierarchical.direction === 'DU';
48351
48352 if (isVertical) {
48353 this.direction = new VerticalStrategy(this);
48354 } else {
48355 this.direction = new HorizontalStrategy(this);
48356 }
48357 }
48358 /**
48359 * Determine the center position of a branch from the passed list of child nodes
48360 *
48361 * This takes into account the positions of all the child nodes.
48362 * @param {Array.<Node|vis.Node.id>} childNodes Array of either child nodes or node id's
48363 * @return {number}
48364 * @private
48365 */
48366
48367 }, {
48368 key: "_getCenterPosition",
48369 value: function _getCenterPosition(childNodes) {
48370 var minPos = 1e9;
48371 var maxPos = -1e9;
48372
48373 for (var i = 0; i < childNodes.length; i++) {
48374 var childNode = void 0;
48375
48376 if (childNodes[i].id !== undefined) {
48377 childNode = childNodes[i];
48378 } else {
48379 var childNodeId = childNodes[i];
48380 childNode = this.body.nodes[childNodeId];
48381 }
48382
48383 var position = this.direction.getPosition(childNode);
48384 minPos = Math.min(minPos, position);
48385 maxPos = Math.max(maxPos, position);
48386 }
48387
48388 return 0.5 * (minPos + maxPos);
48389 }
48390 }]);
48391
48392 return LayoutEngine;
48393 }();
48394
48395 /**
48396 * Clears the toolbar div element of children
48397 *
48398 * @private
48399 */
48400
48401 var ManipulationSystem =
48402 /*#__PURE__*/
48403 function () {
48404 /**
48405 * @param {Object} body
48406 * @param {Canvas} canvas
48407 * @param {SelectionHandler} selectionHandler
48408 */
48409 function ManipulationSystem(body, canvas, selectionHandler, interactionHandler) {
48410 var _this = this;
48411
48412 _classCallCheck(this, ManipulationSystem);
48413
48414 this.body = body;
48415 this.canvas = canvas;
48416 this.selectionHandler = selectionHandler;
48417 this.interactionHandler = interactionHandler;
48418 this.editMode = false;
48419 this.manipulationDiv = undefined;
48420 this.editModeDiv = undefined;
48421 this.closeDiv = undefined;
48422 this.manipulationHammers = [];
48423 this.temporaryUIFunctions = {};
48424 this.temporaryEventFunctions = [];
48425 this.touchTime = 0;
48426 this.temporaryIds = {
48427 nodes: [],
48428 edges: []
48429 };
48430 this.guiEnabled = false;
48431 this.inMode = false;
48432 this.selectedControlNode = undefined;
48433 this.options = {};
48434 this.defaultOptions = {
48435 enabled: false,
48436 initiallyActive: false,
48437 addNode: true,
48438 addEdge: true,
48439 editNode: undefined,
48440 editEdge: true,
48441 deleteNode: true,
48442 deleteEdge: true,
48443 controlNodeStyle: {
48444 shape: 'dot',
48445 size: 6,
48446 color: {
48447 background: '#ff0000',
48448 border: '#3c3c3c',
48449 highlight: {
48450 background: '#07f968',
48451 border: '#3c3c3c'
48452 }
48453 },
48454 borderWidth: 2,
48455 borderWidthSelected: 2
48456 }
48457 };
48458 extend(this.options, this.defaultOptions);
48459 this.body.emitter.on('destroy', function () {
48460 _this._clean();
48461 });
48462 this.body.emitter.on('_dataChanged', this._restore.bind(this));
48463 this.body.emitter.on('_resetData', this._restore.bind(this));
48464 }
48465 /**
48466 * If something changes in the data during editing, switch back to the initial datamanipulation state and close all edit modes.
48467 * @private
48468 */
48469
48470
48471 _createClass(ManipulationSystem, [{
48472 key: "_restore",
48473 value: function _restore() {
48474 if (this.inMode !== false) {
48475 if (this.options.initiallyActive === true) {
48476 this.enableEditMode();
48477 } else {
48478 this.disableEditMode();
48479 }
48480 }
48481 }
48482 /**
48483 * Set the Options
48484 *
48485 * @param {Object} options
48486 * @param {Object} allOptions
48487 * @param {Object} globalOptions
48488 */
48489
48490 }, {
48491 key: "setOptions",
48492 value: function setOptions(options, allOptions, globalOptions) {
48493 if (allOptions !== undefined) {
48494 if (allOptions.locale !== undefined) {
48495 this.options.locale = allOptions.locale;
48496 } else {
48497 this.options.locale = globalOptions.locale;
48498 }
48499
48500 if (allOptions.locales !== undefined) {
48501 this.options.locales = allOptions.locales;
48502 } else {
48503 this.options.locales = globalOptions.locales;
48504 }
48505 }
48506
48507 if (options !== undefined) {
48508 if (typeof options === 'boolean') {
48509 this.options.enabled = options;
48510 } else {
48511 this.options.enabled = true;
48512 deepExtend(this.options, options);
48513 }
48514
48515 if (this.options.initiallyActive === true) {
48516 this.editMode = true;
48517 }
48518
48519 this._setup();
48520 }
48521 }
48522 /**
48523 * Enable or disable edit-mode. Draws the DOM required and cleans up after itself.
48524 *
48525 * @private
48526 */
48527
48528 }, {
48529 key: "toggleEditMode",
48530 value: function toggleEditMode() {
48531 if (this.editMode === true) {
48532 this.disableEditMode();
48533 } else {
48534 this.enableEditMode();
48535 }
48536 }
48537 /**
48538 * Enables Edit Mode
48539 */
48540
48541 }, {
48542 key: "enableEditMode",
48543 value: function enableEditMode() {
48544 this.editMode = true;
48545
48546 this._clean();
48547
48548 if (this.guiEnabled === true) {
48549 this.manipulationDiv.style.display = 'block';
48550 this.closeDiv.style.display = 'block';
48551 this.editModeDiv.style.display = 'none';
48552 this.showManipulatorToolbar();
48553 }
48554 }
48555 /**
48556 * Disables Edit Mode
48557 */
48558
48559 }, {
48560 key: "disableEditMode",
48561 value: function disableEditMode() {
48562 this.editMode = false;
48563
48564 this._clean();
48565
48566 if (this.guiEnabled === true) {
48567 this.manipulationDiv.style.display = 'none';
48568 this.closeDiv.style.display = 'none';
48569 this.editModeDiv.style.display = 'block';
48570
48571 this._createEditButton();
48572 }
48573 }
48574 /**
48575 * Creates the main toolbar. Removes functions bound to the select event. Binds all the buttons of the toolbar.
48576 *
48577 * @private
48578 */
48579
48580 }, {
48581 key: "showManipulatorToolbar",
48582 value: function showManipulatorToolbar() {
48583 // restore the state of any bound functions or events, remove control nodes, restore physics
48584 this._clean(); // reset global variables
48585
48586
48587 this.manipulationDOM = {}; // if the gui is enabled, draw all elements.
48588
48589 if (this.guiEnabled === true) {
48590 // a _restore will hide these menus
48591 this.editMode = true;
48592 this.manipulationDiv.style.display = 'block';
48593 this.closeDiv.style.display = 'block';
48594
48595 var selectedNodeCount = this.selectionHandler._getSelectedNodeCount();
48596
48597 var selectedEdgeCount = this.selectionHandler._getSelectedEdgeCount();
48598
48599 var selectedTotalCount = selectedNodeCount + selectedEdgeCount;
48600 var locale = this.options.locales[this.options.locale];
48601 var needSeperator = false;
48602
48603 if (this.options.addNode !== false) {
48604 this._createAddNodeButton(locale);
48605
48606 needSeperator = true;
48607 }
48608
48609 if (this.options.addEdge !== false) {
48610 if (needSeperator === true) {
48611 this._createSeperator(1);
48612 } else {
48613 needSeperator = true;
48614 }
48615
48616 this._createAddEdgeButton(locale);
48617 }
48618
48619 if (selectedNodeCount === 1 && typeof this.options.editNode === 'function') {
48620 if (needSeperator === true) {
48621 this._createSeperator(2);
48622 } else {
48623 needSeperator = true;
48624 }
48625
48626 this._createEditNodeButton(locale);
48627 } else if (selectedEdgeCount === 1 && selectedNodeCount === 0 && this.options.editEdge !== false) {
48628 if (needSeperator === true) {
48629 this._createSeperator(3);
48630 } else {
48631 needSeperator = true;
48632 }
48633
48634 this._createEditEdgeButton(locale);
48635 } // remove buttons
48636
48637
48638 if (selectedTotalCount !== 0) {
48639 if (selectedNodeCount > 0 && this.options.deleteNode !== false) {
48640 if (needSeperator === true) {
48641 this._createSeperator(4);
48642 }
48643
48644 this._createDeleteButton(locale);
48645 } else if (selectedNodeCount === 0 && this.options.deleteEdge !== false) {
48646 if (needSeperator === true) {
48647 this._createSeperator(4);
48648 }
48649
48650 this._createDeleteButton(locale);
48651 }
48652 } // bind the close button
48653
48654
48655 this._bindHammerToDiv(this.closeDiv, this.toggleEditMode.bind(this)); // refresh this bar based on what has been selected
48656
48657
48658 this._temporaryBindEvent('select', this.showManipulatorToolbar.bind(this));
48659 } // redraw to show any possible changes
48660
48661
48662 this.body.emitter.emit('_redraw');
48663 }
48664 /**
48665 * Create the toolbar for adding Nodes
48666 */
48667
48668 }, {
48669 key: "addNodeMode",
48670 value: function addNodeMode() {
48671 // when using the gui, enable edit mode if it wasnt already.
48672 if (this.editMode !== true) {
48673 this.enableEditMode();
48674 } // restore the state of any bound functions or events, remove control nodes, restore physics
48675
48676
48677 this._clean();
48678
48679 this.inMode = 'addNode';
48680
48681 if (this.guiEnabled === true) {
48682 var locale = this.options.locales[this.options.locale];
48683 this.manipulationDOM = {};
48684
48685 this._createBackButton(locale);
48686
48687 this._createSeperator();
48688
48689 this._createDescription(locale['addDescription'] || this.options.locales['en']['addDescription']); // bind the close button
48690
48691
48692 this._bindHammerToDiv(this.closeDiv, this.toggleEditMode.bind(this));
48693 }
48694
48695 this._temporaryBindEvent('click', this._performAddNode.bind(this));
48696 }
48697 /**
48698 * call the bound function to handle the editing of the node. The node has to be selected.
48699 */
48700
48701 }, {
48702 key: "editNode",
48703 value: function editNode() {
48704 var _this2 = this;
48705
48706 // when using the gui, enable edit mode if it wasnt already.
48707 if (this.editMode !== true) {
48708 this.enableEditMode();
48709 } // restore the state of any bound functions or events, remove control nodes, restore physics
48710
48711
48712 this._clean();
48713
48714 var node = this.selectionHandler._getSelectedNode();
48715
48716 if (node !== undefined) {
48717 this.inMode = 'editNode';
48718
48719 if (typeof this.options.editNode === 'function') {
48720 if (node.isCluster !== true) {
48721 var data = deepExtend({}, node.options, false);
48722 data.x = node.x;
48723 data.y = node.y;
48724
48725 if (this.options.editNode.length === 2) {
48726 this.options.editNode(data, function (finalizedData) {
48727 if (finalizedData !== null && finalizedData !== undefined && _this2.inMode === 'editNode') {
48728 // if for whatever reason the mode has changes (due to dataset change) disregard the callback) {
48729 _this2.body.data.nodes.getDataSet().update(finalizedData);
48730 }
48731
48732 _this2.showManipulatorToolbar();
48733 });
48734 } else {
48735 throw new Error('The function for edit does not support two arguments (data, callback)');
48736 }
48737 } else {
48738 alert(this.options.locales[this.options.locale]['editClusterError'] || this.options.locales['en']['editClusterError']);
48739 }
48740 } else {
48741 throw new Error('No function has been configured to handle the editing of nodes.');
48742 }
48743 } else {
48744 this.showManipulatorToolbar();
48745 }
48746 }
48747 /**
48748 * create the toolbar to connect nodes
48749 */
48750
48751 }, {
48752 key: "addEdgeMode",
48753 value: function addEdgeMode() {
48754 // when using the gui, enable edit mode if it wasnt already.
48755 if (this.editMode !== true) {
48756 this.enableEditMode();
48757 } // restore the state of any bound functions or events, remove control nodes, restore physics
48758
48759
48760 this._clean();
48761
48762 this.inMode = 'addEdge';
48763
48764 if (this.guiEnabled === true) {
48765 var locale = this.options.locales[this.options.locale];
48766 this.manipulationDOM = {};
48767
48768 this._createBackButton(locale);
48769
48770 this._createSeperator();
48771
48772 this._createDescription(locale['edgeDescription'] || this.options.locales['en']['edgeDescription']); // bind the close button
48773
48774
48775 this._bindHammerToDiv(this.closeDiv, this.toggleEditMode.bind(this));
48776 } // temporarily overload functions
48777
48778
48779 this._temporaryBindUI('onTouch', this._handleConnect.bind(this));
48780
48781 this._temporaryBindUI('onDragEnd', this._finishConnect.bind(this));
48782
48783 this._temporaryBindUI('onDrag', this._dragControlNode.bind(this));
48784
48785 this._temporaryBindUI('onRelease', this._finishConnect.bind(this));
48786
48787 this._temporaryBindUI('onDragStart', this._dragStartEdge.bind(this));
48788
48789 this._temporaryBindUI('onHold', function () {});
48790 }
48791 /**
48792 * create the toolbar to edit edges
48793 */
48794
48795 }, {
48796 key: "editEdgeMode",
48797 value: function editEdgeMode() {
48798 // when using the gui, enable edit mode if it wasn't already.
48799 if (this.editMode !== true) {
48800 this.enableEditMode();
48801 } // restore the state of any bound functions or events, remove control nodes, restore physics
48802
48803
48804 this._clean();
48805
48806 this.inMode = 'editEdge';
48807
48808 if (_typeof$1(this.options.editEdge) === 'object' && typeof this.options.editEdge.editWithoutDrag === "function") {
48809 this.edgeBeingEditedId = this.selectionHandler.getSelectedEdges()[0];
48810
48811 if (this.edgeBeingEditedId !== undefined) {
48812 var edge = this.body.edges[this.edgeBeingEditedId];
48813
48814 this._performEditEdge(edge.from.id, edge.to.id);
48815
48816 return;
48817 }
48818 }
48819
48820 if (this.guiEnabled === true) {
48821 var locale = this.options.locales[this.options.locale];
48822 this.manipulationDOM = {};
48823
48824 this._createBackButton(locale);
48825
48826 this._createSeperator();
48827
48828 this._createDescription(locale['editEdgeDescription'] || this.options.locales['en']['editEdgeDescription']); // bind the close button
48829
48830
48831 this._bindHammerToDiv(this.closeDiv, this.toggleEditMode.bind(this));
48832 }
48833
48834 this.edgeBeingEditedId = this.selectionHandler.getSelectedEdges()[0];
48835
48836 if (this.edgeBeingEditedId !== undefined) {
48837 var _edge = this.body.edges[this.edgeBeingEditedId]; // create control nodes
48838
48839 var controlNodeFrom = this._getNewTargetNode(_edge.from.x, _edge.from.y);
48840
48841 var controlNodeTo = this._getNewTargetNode(_edge.to.x, _edge.to.y);
48842
48843 this.temporaryIds.nodes.push(controlNodeFrom.id);
48844 this.temporaryIds.nodes.push(controlNodeTo.id);
48845 this.body.nodes[controlNodeFrom.id] = controlNodeFrom;
48846 this.body.nodeIndices.push(controlNodeFrom.id);
48847 this.body.nodes[controlNodeTo.id] = controlNodeTo;
48848 this.body.nodeIndices.push(controlNodeTo.id); // temporarily overload UI functions, cleaned up automatically because of _temporaryBindUI
48849
48850 this._temporaryBindUI('onTouch', this._controlNodeTouch.bind(this)); // used to get the position
48851
48852
48853 this._temporaryBindUI('onTap', function () {}); // disabled
48854
48855
48856 this._temporaryBindUI('onHold', function () {}); // disabled
48857
48858
48859 this._temporaryBindUI('onDragStart', this._controlNodeDragStart.bind(this)); // used to select control node
48860
48861
48862 this._temporaryBindUI('onDrag', this._controlNodeDrag.bind(this)); // used to drag control node
48863
48864
48865 this._temporaryBindUI('onDragEnd', this._controlNodeDragEnd.bind(this)); // used to connect or revert control nodes
48866
48867
48868 this._temporaryBindUI('onMouseMove', function () {}); // disabled
48869 // create function to position control nodes correctly on movement
48870 // automatically cleaned up because we use the temporary bind
48871
48872
48873 this._temporaryBindEvent('beforeDrawing', function (ctx) {
48874 var positions = _edge.edgeType.findBorderPositions(ctx);
48875
48876 if (controlNodeFrom.selected === false) {
48877 controlNodeFrom.x = positions.from.x;
48878 controlNodeFrom.y = positions.from.y;
48879 }
48880
48881 if (controlNodeTo.selected === false) {
48882 controlNodeTo.x = positions.to.x;
48883 controlNodeTo.y = positions.to.y;
48884 }
48885 });
48886
48887 this.body.emitter.emit('_redraw');
48888 } else {
48889 this.showManipulatorToolbar();
48890 }
48891 }
48892 /**
48893 * delete everything in the selection
48894 */
48895
48896 }, {
48897 key: "deleteSelected",
48898 value: function deleteSelected() {
48899 var _this3 = this;
48900
48901 // when using the gui, enable edit mode if it wasnt already.
48902 if (this.editMode !== true) {
48903 this.enableEditMode();
48904 } // restore the state of any bound functions or events, remove control nodes, restore physics
48905
48906
48907 this._clean();
48908
48909 this.inMode = 'delete';
48910 var selectedNodes = this.selectionHandler.getSelectedNodes();
48911 var selectedEdges = this.selectionHandler.getSelectedEdges();
48912 var deleteFunction = undefined;
48913
48914 if (selectedNodes.length > 0) {
48915 for (var i = 0; i < selectedNodes.length; i++) {
48916 if (this.body.nodes[selectedNodes[i]].isCluster === true) {
48917 alert(this.options.locales[this.options.locale]['deleteClusterError'] || this.options.locales['en']['deleteClusterError']);
48918 return;
48919 }
48920 }
48921
48922 if (typeof this.options.deleteNode === 'function') {
48923 deleteFunction = this.options.deleteNode;
48924 }
48925 } else if (selectedEdges.length > 0) {
48926 if (typeof this.options.deleteEdge === 'function') {
48927 deleteFunction = this.options.deleteEdge;
48928 }
48929 }
48930
48931 if (typeof deleteFunction === 'function') {
48932 var data = {
48933 nodes: selectedNodes,
48934 edges: selectedEdges
48935 };
48936
48937 if (deleteFunction.length === 2) {
48938 deleteFunction(data, function (finalizedData) {
48939 if (finalizedData !== null && finalizedData !== undefined && _this3.inMode === 'delete') {
48940 // if for whatever reason the mode has changes (due to dataset change) disregard the callback) {
48941 _this3.body.data.edges.getDataSet().remove(finalizedData.edges);
48942
48943 _this3.body.data.nodes.getDataSet().remove(finalizedData.nodes);
48944
48945 _this3.body.emitter.emit('startSimulation');
48946
48947 _this3.showManipulatorToolbar();
48948 } else {
48949 _this3.body.emitter.emit('startSimulation');
48950
48951 _this3.showManipulatorToolbar();
48952 }
48953 });
48954 } else {
48955 throw new Error('The function for delete does not support two arguments (data, callback)');
48956 }
48957 } else {
48958 this.body.data.edges.getDataSet().remove(selectedEdges);
48959 this.body.data.nodes.getDataSet().remove(selectedNodes);
48960 this.body.emitter.emit('startSimulation');
48961 this.showManipulatorToolbar();
48962 }
48963 } //********************************************** PRIVATE ***************************************//
48964
48965 /**
48966 * draw or remove the DOM
48967 * @private
48968 */
48969
48970 }, {
48971 key: "_setup",
48972 value: function _setup() {
48973 if (this.options.enabled === true) {
48974 // Enable the GUI
48975 this.guiEnabled = true;
48976
48977 this._createWrappers();
48978
48979 if (this.editMode === false) {
48980 this._createEditButton();
48981 } else {
48982 this.showManipulatorToolbar();
48983 }
48984 } else {
48985 this._removeManipulationDOM(); // disable the gui
48986
48987
48988 this.guiEnabled = false;
48989 }
48990 }
48991 /**
48992 * create the div overlays that contain the DOM
48993 * @private
48994 */
48995
48996 }, {
48997 key: "_createWrappers",
48998 value: function _createWrappers() {
48999 // load the manipulator HTML elements. All styling done in css.
49000 if (this.manipulationDiv === undefined) {
49001 this.manipulationDiv = document.createElement('div');
49002 this.manipulationDiv.className = 'vis-manipulation';
49003
49004 if (this.editMode === true) {
49005 this.manipulationDiv.style.display = 'block';
49006 } else {
49007 this.manipulationDiv.style.display = 'none';
49008 }
49009
49010 this.canvas.frame.appendChild(this.manipulationDiv);
49011 } // container for the edit button.
49012
49013
49014 if (this.editModeDiv === undefined) {
49015 this.editModeDiv = document.createElement('div');
49016 this.editModeDiv.className = 'vis-edit-mode';
49017
49018 if (this.editMode === true) {
49019 this.editModeDiv.style.display = 'none';
49020 } else {
49021 this.editModeDiv.style.display = 'block';
49022 }
49023
49024 this.canvas.frame.appendChild(this.editModeDiv);
49025 } // container for the close div button
49026
49027
49028 if (this.closeDiv === undefined) {
49029 this.closeDiv = document.createElement('div');
49030 this.closeDiv.className = 'vis-close';
49031 this.closeDiv.style.display = this.manipulationDiv.style.display;
49032 this.canvas.frame.appendChild(this.closeDiv);
49033 }
49034 }
49035 /**
49036 * generate a new target node. Used for creating new edges and editing edges
49037 *
49038 * @param {number} x
49039 * @param {number} y
49040 * @returns {Node}
49041 * @private
49042 */
49043
49044 }, {
49045 key: "_getNewTargetNode",
49046 value: function _getNewTargetNode(x, y) {
49047 var controlNodeStyle = deepExtend({}, this.options.controlNodeStyle);
49048 controlNodeStyle.id = 'targetNode' + uuid4();
49049 controlNodeStyle.hidden = false;
49050 controlNodeStyle.physics = false;
49051 controlNodeStyle.x = x;
49052 controlNodeStyle.y = y; // we have to define the bounding box in order for the nodes to be drawn immediately
49053
49054 var node = this.body.functions.createNode(controlNodeStyle);
49055 node.shape.boundingBox = {
49056 left: x,
49057 right: x,
49058 top: y,
49059 bottom: y
49060 };
49061 return node;
49062 }
49063 /**
49064 * Create the edit button
49065 */
49066
49067 }, {
49068 key: "_createEditButton",
49069 value: function _createEditButton() {
49070 // restore everything to it's original state (if applicable)
49071 this._clean(); // reset the manipulationDOM
49072
49073
49074 this.manipulationDOM = {}; // empty the editModeDiv
49075
49076 recursiveDOMDelete(this.editModeDiv); // create the contents for the editMode button
49077
49078 var locale = this.options.locales[this.options.locale];
49079
49080 var button = this._createButton('editMode', 'vis-button vis-edit vis-edit-mode', locale['edit'] || this.options.locales['en']['edit']);
49081
49082 this.editModeDiv.appendChild(button); // bind a hammer listener to the button, calling the function toggleEditMode.
49083
49084 this._bindHammerToDiv(button, this.toggleEditMode.bind(this));
49085 }
49086 /**
49087 * this function cleans up after everything this module does. Temporary elements, functions and events are removed, physics restored, hammers removed.
49088 * @private
49089 */
49090
49091 }, {
49092 key: "_clean",
49093 value: function _clean() {
49094 // not in mode
49095 this.inMode = false; // _clean the divs
49096
49097 if (this.guiEnabled === true) {
49098 recursiveDOMDelete(this.editModeDiv);
49099 recursiveDOMDelete(this.manipulationDiv); // removes all the bindings and overloads
49100
49101 this._cleanManipulatorHammers();
49102 } // remove temporary nodes and edges
49103
49104
49105 this._cleanupTemporaryNodesAndEdges(); // restore overloaded UI functions
49106
49107
49108 this._unbindTemporaryUIs(); // remove the temporaryEventFunctions
49109
49110
49111 this._unbindTemporaryEvents(); // restore the physics if required
49112
49113
49114 this.body.emitter.emit('restorePhysics');
49115 }
49116 /**
49117 * Each dom element has it's own hammer. They are stored in this.manipulationHammers. This cleans them up.
49118 * @private
49119 */
49120
49121 }, {
49122 key: "_cleanManipulatorHammers",
49123 value: function _cleanManipulatorHammers() {
49124 // _clean hammer bindings
49125 if (this.manipulationHammers.length != 0) {
49126 for (var i = 0; i < this.manipulationHammers.length; i++) {
49127 this.manipulationHammers[i].destroy();
49128 }
49129
49130 this.manipulationHammers = [];
49131 }
49132 }
49133 /**
49134 * Remove all DOM elements created by this module.
49135 * @private
49136 */
49137
49138 }, {
49139 key: "_removeManipulationDOM",
49140 value: function _removeManipulationDOM() {
49141 // removes all the bindings and overloads
49142 this._clean(); // empty the manipulation divs
49143
49144
49145 recursiveDOMDelete(this.manipulationDiv);
49146 recursiveDOMDelete(this.editModeDiv);
49147 recursiveDOMDelete(this.closeDiv); // remove the manipulation divs
49148
49149 if (this.manipulationDiv) {
49150 this.canvas.frame.removeChild(this.manipulationDiv);
49151 }
49152
49153 if (this.editModeDiv) {
49154 this.canvas.frame.removeChild(this.editModeDiv);
49155 }
49156
49157 if (this.closeDiv) {
49158 this.canvas.frame.removeChild(this.closeDiv);
49159 } // set the references to undefined
49160
49161
49162 this.manipulationDiv = undefined;
49163 this.editModeDiv = undefined;
49164 this.closeDiv = undefined;
49165 }
49166 /**
49167 * create a seperator line. the index is to differentiate in the manipulation dom
49168 * @param {number} [index=1]
49169 * @private
49170 */
49171
49172 }, {
49173 key: "_createSeperator",
49174 value: function _createSeperator() {
49175 var index = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1;
49176 this.manipulationDOM['seperatorLineDiv' + index] = document.createElement('div');
49177 this.manipulationDOM['seperatorLineDiv' + index].className = 'vis-separator-line';
49178 this.manipulationDiv.appendChild(this.manipulationDOM['seperatorLineDiv' + index]);
49179 } // ---------------------- DOM functions for buttons --------------------------//
49180
49181 /**
49182 *
49183 * @param {Locale} locale
49184 * @private
49185 */
49186
49187 }, {
49188 key: "_createAddNodeButton",
49189 value: function _createAddNodeButton(locale) {
49190 var button = this._createButton('addNode', 'vis-button vis-add', locale['addNode'] || this.options.locales['en']['addNode']);
49191
49192 this.manipulationDiv.appendChild(button);
49193
49194 this._bindHammerToDiv(button, this.addNodeMode.bind(this));
49195 }
49196 /**
49197 *
49198 * @param {Locale} locale
49199 * @private
49200 */
49201
49202 }, {
49203 key: "_createAddEdgeButton",
49204 value: function _createAddEdgeButton(locale) {
49205 var button = this._createButton('addEdge', 'vis-button vis-connect', locale['addEdge'] || this.options.locales['en']['addEdge']);
49206
49207 this.manipulationDiv.appendChild(button);
49208
49209 this._bindHammerToDiv(button, this.addEdgeMode.bind(this));
49210 }
49211 /**
49212 *
49213 * @param {Locale} locale
49214 * @private
49215 */
49216
49217 }, {
49218 key: "_createEditNodeButton",
49219 value: function _createEditNodeButton(locale) {
49220 var button = this._createButton('editNode', 'vis-button vis-edit', locale['editNode'] || this.options.locales['en']['editNode']);
49221
49222 this.manipulationDiv.appendChild(button);
49223
49224 this._bindHammerToDiv(button, this.editNode.bind(this));
49225 }
49226 /**
49227 *
49228 * @param {Locale} locale
49229 * @private
49230 */
49231
49232 }, {
49233 key: "_createEditEdgeButton",
49234 value: function _createEditEdgeButton(locale) {
49235 var button = this._createButton('editEdge', 'vis-button vis-edit', locale['editEdge'] || this.options.locales['en']['editEdge']);
49236
49237 this.manipulationDiv.appendChild(button);
49238
49239 this._bindHammerToDiv(button, this.editEdgeMode.bind(this));
49240 }
49241 /**
49242 *
49243 * @param {Locale} locale
49244 * @private
49245 */
49246
49247 }, {
49248 key: "_createDeleteButton",
49249 value: function _createDeleteButton(locale) {
49250 var deleteBtnClass;
49251
49252 if (this.options.rtl) {
49253 deleteBtnClass = 'vis-button vis-delete-rtl';
49254 } else {
49255 deleteBtnClass = 'vis-button vis-delete';
49256 }
49257
49258 var button = this._createButton('delete', deleteBtnClass, locale['del'] || this.options.locales['en']['del']);
49259
49260 this.manipulationDiv.appendChild(button);
49261
49262 this._bindHammerToDiv(button, this.deleteSelected.bind(this));
49263 }
49264 /**
49265 *
49266 * @param {Locale} locale
49267 * @private
49268 */
49269
49270 }, {
49271 key: "_createBackButton",
49272 value: function _createBackButton(locale) {
49273 var button = this._createButton('back', 'vis-button vis-back', locale['back'] || this.options.locales['en']['back']);
49274
49275 this.manipulationDiv.appendChild(button);
49276
49277 this._bindHammerToDiv(button, this.showManipulatorToolbar.bind(this));
49278 }
49279 /**
49280 *
49281 * @param {number|string} id
49282 * @param {string} className
49283 * @param {label} label
49284 * @param {string} labelClassName
49285 * @returns {HTMLElement}
49286 * @private
49287 */
49288
49289 }, {
49290 key: "_createButton",
49291 value: function _createButton(id, className, label) {
49292 var labelClassName = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 'vis-label';
49293 this.manipulationDOM[id + 'Div'] = document.createElement('div');
49294 this.manipulationDOM[id + 'Div'].className = className;
49295 this.manipulationDOM[id + 'Label'] = document.createElement('div');
49296 this.manipulationDOM[id + 'Label'].className = labelClassName;
49297 this.manipulationDOM[id + 'Label'].innerHTML = label;
49298 this.manipulationDOM[id + 'Div'].appendChild(this.manipulationDOM[id + 'Label']);
49299 return this.manipulationDOM[id + 'Div'];
49300 }
49301 /**
49302 *
49303 * @param {Label} label
49304 * @private
49305 */
49306
49307 }, {
49308 key: "_createDescription",
49309 value: function _createDescription(label) {
49310 this.manipulationDiv.appendChild(this._createButton('description', 'vis-button vis-none', label));
49311 } // -------------------------- End of DOM functions for buttons ------------------------------//
49312
49313 /**
49314 * this binds an event until cleanup by the clean functions.
49315 * @param {Event} event The event
49316 * @param {function} newFunction
49317 * @private
49318 */
49319
49320 }, {
49321 key: "_temporaryBindEvent",
49322 value: function _temporaryBindEvent(event, newFunction) {
49323 this.temporaryEventFunctions.push({
49324 event: event,
49325 boundFunction: newFunction
49326 });
49327 this.body.emitter.on(event, newFunction);
49328 }
49329 /**
49330 * this overrides an UI function until cleanup by the clean function
49331 * @param {string} UIfunctionName
49332 * @param {function} newFunction
49333 * @private
49334 */
49335
49336 }, {
49337 key: "_temporaryBindUI",
49338 value: function _temporaryBindUI(UIfunctionName, newFunction) {
49339 if (this.body.eventListeners[UIfunctionName] !== undefined) {
49340 this.temporaryUIFunctions[UIfunctionName] = this.body.eventListeners[UIfunctionName];
49341 this.body.eventListeners[UIfunctionName] = newFunction;
49342 } else {
49343 throw new Error('This UI function does not exist. Typo? You tried: ' + UIfunctionName + ' possible are: ' + JSON.stringify(Object.keys(this.body.eventListeners)));
49344 }
49345 }
49346 /**
49347 * Restore the overridden UI functions to their original state.
49348 *
49349 * @private
49350 */
49351
49352 }, {
49353 key: "_unbindTemporaryUIs",
49354 value: function _unbindTemporaryUIs() {
49355 for (var functionName in this.temporaryUIFunctions) {
49356 if (this.temporaryUIFunctions.hasOwnProperty(functionName)) {
49357 this.body.eventListeners[functionName] = this.temporaryUIFunctions[functionName];
49358 delete this.temporaryUIFunctions[functionName];
49359 }
49360 }
49361
49362 this.temporaryUIFunctions = {};
49363 }
49364 /**
49365 * Unbind the events created by _temporaryBindEvent
49366 * @private
49367 */
49368
49369 }, {
49370 key: "_unbindTemporaryEvents",
49371 value: function _unbindTemporaryEvents() {
49372 for (var i = 0; i < this.temporaryEventFunctions.length; i++) {
49373 var eventName = this.temporaryEventFunctions[i].event;
49374 var boundFunction = this.temporaryEventFunctions[i].boundFunction;
49375 this.body.emitter.off(eventName, boundFunction);
49376 }
49377
49378 this.temporaryEventFunctions = [];
49379 }
49380 /**
49381 * Bind an hammer instance to a DOM element.
49382 *
49383 * @param {Element} domElement
49384 * @param {function} boundFunction
49385 */
49386
49387 }, {
49388 key: "_bindHammerToDiv",
49389 value: function _bindHammerToDiv(domElement, boundFunction) {
49390 var hammer$1 = new hammer(domElement, {});
49391 hammerUtil.onTouch(hammer$1, boundFunction);
49392 this.manipulationHammers.push(hammer$1);
49393 }
49394 /**
49395 * Neatly clean up temporary edges and nodes
49396 * @private
49397 */
49398
49399 }, {
49400 key: "_cleanupTemporaryNodesAndEdges",
49401 value: function _cleanupTemporaryNodesAndEdges() {
49402 // _clean temporary edges
49403 for (var i = 0; i < this.temporaryIds.edges.length; i++) {
49404 this.body.edges[this.temporaryIds.edges[i]].disconnect();
49405 delete this.body.edges[this.temporaryIds.edges[i]];
49406 var indexTempEdge = this.body.edgeIndices.indexOf(this.temporaryIds.edges[i]);
49407
49408 if (indexTempEdge !== -1) {
49409 this.body.edgeIndices.splice(indexTempEdge, 1);
49410 }
49411 } // _clean temporary nodes
49412
49413
49414 for (var _i = 0; _i < this.temporaryIds.nodes.length; _i++) {
49415 delete this.body.nodes[this.temporaryIds.nodes[_i]];
49416 var indexTempNode = this.body.nodeIndices.indexOf(this.temporaryIds.nodes[_i]);
49417
49418 if (indexTempNode !== -1) {
49419 this.body.nodeIndices.splice(indexTempNode, 1);
49420 }
49421 }
49422
49423 this.temporaryIds = {
49424 nodes: [],
49425 edges: []
49426 };
49427 } // ------------------------------------------ EDIT EDGE FUNCTIONS -----------------------------------------//
49428
49429 /**
49430 * the touch is used to get the position of the initial click
49431 * @param {Event} event The event
49432 * @private
49433 */
49434
49435 }, {
49436 key: "_controlNodeTouch",
49437 value: function _controlNodeTouch(event) {
49438 this.selectionHandler.unselectAll();
49439 this.lastTouch = this.body.functions.getPointer(event.center);
49440 this.lastTouch.translation = extend({}, this.body.view.translation); // copy the object
49441 }
49442 /**
49443 * the drag start is used to mark one of the control nodes as selected.
49444 * @param {Event} event The event
49445 * @private
49446 */
49447
49448 }, {
49449 key: "_controlNodeDragStart",
49450 value: function _controlNodeDragStart(event) {
49451 // eslint-disable-line no-unused-vars
49452 var pointer = this.lastTouch;
49453
49454 var pointerObj = this.selectionHandler._pointerToPositionObject(pointer);
49455
49456 var from = this.body.nodes[this.temporaryIds.nodes[0]];
49457 var to = this.body.nodes[this.temporaryIds.nodes[1]];
49458 var edge = this.body.edges[this.edgeBeingEditedId];
49459 this.selectedControlNode = undefined;
49460 var fromSelect = from.isOverlappingWith(pointerObj);
49461 var toSelect = to.isOverlappingWith(pointerObj);
49462
49463 if (fromSelect === true) {
49464 this.selectedControlNode = from;
49465 edge.edgeType.from = from;
49466 } else if (toSelect === true) {
49467 this.selectedControlNode = to;
49468 edge.edgeType.to = to;
49469 } // we use the selection to find the node that is being dragged. We explicitly select it here.
49470
49471
49472 if (this.selectedControlNode !== undefined) {
49473 this.selectionHandler.selectObject(this.selectedControlNode);
49474 }
49475
49476 this.body.emitter.emit('_redraw');
49477 }
49478 /**
49479 * dragging the control nodes or the canvas
49480 * @param {Event} event The event
49481 * @private
49482 */
49483
49484 }, {
49485 key: "_controlNodeDrag",
49486 value: function _controlNodeDrag(event) {
49487 this.body.emitter.emit('disablePhysics');
49488 var pointer = this.body.functions.getPointer(event.center);
49489 var pos = this.canvas.DOMtoCanvas(pointer);
49490
49491 if (this.selectedControlNode !== undefined) {
49492 this.selectedControlNode.x = pos.x;
49493 this.selectedControlNode.y = pos.y;
49494 } else {
49495 this.interactionHandler.onDrag(event);
49496 }
49497
49498 this.body.emitter.emit('_redraw');
49499 }
49500 /**
49501 * connecting or restoring the control nodes.
49502 * @param {Event} event The event
49503 * @private
49504 */
49505
49506 }, {
49507 key: "_controlNodeDragEnd",
49508 value: function _controlNodeDragEnd(event) {
49509 var pointer = this.body.functions.getPointer(event.center);
49510
49511 var pointerObj = this.selectionHandler._pointerToPositionObject(pointer);
49512
49513 var edge = this.body.edges[this.edgeBeingEditedId]; // if the node that was dragged is not a control node, return
49514
49515 if (this.selectedControlNode === undefined) {
49516 return;
49517 } // we use the selection to find the node that is being dragged. We explicitly DEselect the control node here.
49518
49519
49520 this.selectionHandler.unselectAll();
49521
49522 var overlappingNodeIds = this.selectionHandler._getAllNodesOverlappingWith(pointerObj);
49523
49524 var node = undefined;
49525
49526 for (var i = overlappingNodeIds.length - 1; i >= 0; i--) {
49527 if (overlappingNodeIds[i] !== this.selectedControlNode.id) {
49528 node = this.body.nodes[overlappingNodeIds[i]];
49529 break;
49530 }
49531 } // perform the connection
49532
49533
49534 if (node !== undefined && this.selectedControlNode !== undefined) {
49535 if (node.isCluster === true) {
49536 alert(this.options.locales[this.options.locale]['createEdgeError'] || this.options.locales['en']['createEdgeError']);
49537 } else {
49538 var from = this.body.nodes[this.temporaryIds.nodes[0]];
49539
49540 if (this.selectedControlNode.id === from.id) {
49541 this._performEditEdge(node.id, edge.to.id);
49542 } else {
49543 this._performEditEdge(edge.from.id, node.id);
49544 }
49545 }
49546 } else {
49547 edge.updateEdgeType();
49548 this.body.emitter.emit('restorePhysics');
49549 }
49550
49551 this.body.emitter.emit('_redraw');
49552 } // ------------------------------------ END OF EDIT EDGE FUNCTIONS -----------------------------------------//
49553 // ------------------------------------------- ADD EDGE FUNCTIONS -----------------------------------------//
49554
49555 /**
49556 * the function bound to the selection event. It checks if you want to connect a cluster and changes the description
49557 * to walk the user through the process.
49558 *
49559 * @param {Event} event
49560 * @private
49561 */
49562
49563 }, {
49564 key: "_handleConnect",
49565 value: function _handleConnect(event) {
49566 // check to avoid double fireing of this function.
49567 if (new Date().valueOf() - this.touchTime > 100) {
49568 this.lastTouch = this.body.functions.getPointer(event.center);
49569 this.lastTouch.translation = extend({}, this.body.view.translation); // copy the object
49570
49571 var pointer = this.lastTouch;
49572 var node = this.selectionHandler.getNodeAt(pointer);
49573
49574 if (node !== undefined) {
49575 if (node.isCluster === true) {
49576 alert(this.options.locales[this.options.locale]['createEdgeError'] || this.options.locales['en']['createEdgeError']);
49577 } else {
49578 // create a node the temporary line can look at
49579 var targetNode = this._getNewTargetNode(node.x, node.y);
49580
49581 this.body.nodes[targetNode.id] = targetNode;
49582 this.body.nodeIndices.push(targetNode.id); // create a temporary edge
49583
49584 var connectionEdge = this.body.functions.createEdge({
49585 id: 'connectionEdge' + uuid4(),
49586 from: node.id,
49587 to: targetNode.id,
49588 physics: false,
49589 smooth: {
49590 enabled: true,
49591 type: 'continuous',
49592 roundness: 0.5
49593 }
49594 });
49595 this.body.edges[connectionEdge.id] = connectionEdge;
49596 this.body.edgeIndices.push(connectionEdge.id);
49597 this.temporaryIds.nodes.push(targetNode.id);
49598 this.temporaryIds.edges.push(connectionEdge.id);
49599 }
49600 }
49601
49602 this.touchTime = new Date().valueOf();
49603 }
49604 }
49605 /**
49606 *
49607 * @param {Event} event
49608 * @private
49609 */
49610
49611 }, {
49612 key: "_dragControlNode",
49613 value: function _dragControlNode(event) {
49614 var pointer = this.body.functions.getPointer(event.center);
49615
49616 var pointerObj = this.selectionHandler._pointerToPositionObject(pointer); // remember the edge id
49617
49618
49619 var connectFromId = undefined;
49620
49621 if (this.temporaryIds.edges[0] !== undefined) {
49622 connectFromId = this.body.edges[this.temporaryIds.edges[0]].fromId;
49623 } // get the overlapping node but NOT the temporary node;
49624
49625
49626 var overlappingNodeIds = this.selectionHandler._getAllNodesOverlappingWith(pointerObj);
49627
49628 var node = undefined;
49629
49630 for (var i = overlappingNodeIds.length - 1; i >= 0; i--) {
49631 // if the node id is NOT a temporary node, accept the node.
49632 if (this.temporaryIds.nodes.indexOf(overlappingNodeIds[i]) === -1) {
49633 node = this.body.nodes[overlappingNodeIds[i]];
49634 break;
49635 }
49636 }
49637
49638 event.controlEdge = {
49639 from: connectFromId,
49640 to: node ? node.id : undefined
49641 };
49642
49643 this.selectionHandler._generateClickEvent('controlNodeDragging', event, pointer);
49644
49645 if (this.temporaryIds.nodes[0] !== undefined) {
49646 var targetNode = this.body.nodes[this.temporaryIds.nodes[0]]; // there is only one temp node in the add edge mode.
49647
49648 targetNode.x = this.canvas._XconvertDOMtoCanvas(pointer.x);
49649 targetNode.y = this.canvas._YconvertDOMtoCanvas(pointer.y);
49650 this.body.emitter.emit('_redraw');
49651 } else {
49652 this.interactionHandler.onDrag(event);
49653 }
49654 }
49655 /**
49656 * Connect the new edge to the target if one exists, otherwise remove temp line
49657 * @param {Event} event The event
49658 * @private
49659 */
49660
49661 }, {
49662 key: "_finishConnect",
49663 value: function _finishConnect(event) {
49664 var pointer = this.body.functions.getPointer(event.center);
49665
49666 var pointerObj = this.selectionHandler._pointerToPositionObject(pointer); // remember the edge id
49667
49668
49669 var connectFromId = undefined;
49670
49671 if (this.temporaryIds.edges[0] !== undefined) {
49672 connectFromId = this.body.edges[this.temporaryIds.edges[0]].fromId;
49673 } // get the overlapping node but NOT the temporary node;
49674
49675
49676 var overlappingNodeIds = this.selectionHandler._getAllNodesOverlappingWith(pointerObj);
49677
49678 var node = undefined;
49679
49680 for (var i = overlappingNodeIds.length - 1; i >= 0; i--) {
49681 // if the node id is NOT a temporary node, accept the node.
49682 if (this.temporaryIds.nodes.indexOf(overlappingNodeIds[i]) === -1) {
49683 node = this.body.nodes[overlappingNodeIds[i]];
49684 break;
49685 }
49686 } // clean temporary nodes and edges.
49687
49688
49689 this._cleanupTemporaryNodesAndEdges(); // perform the connection
49690
49691
49692 if (node !== undefined) {
49693 if (node.isCluster === true) {
49694 alert(this.options.locales[this.options.locale]['createEdgeError'] || this.options.locales['en']['createEdgeError']);
49695 } else {
49696 if (this.body.nodes[connectFromId] !== undefined && this.body.nodes[node.id] !== undefined) {
49697 this._performAddEdge(connectFromId, node.id);
49698 }
49699 }
49700 }
49701
49702 event.controlEdge = {
49703 from: connectFromId,
49704 to: node ? node.id : undefined
49705 };
49706
49707 this.selectionHandler._generateClickEvent('controlNodeDragEnd', event, pointer); // No need to do _generateclickevent('dragEnd') here, the regular dragEnd event fires.
49708
49709
49710 this.body.emitter.emit('_redraw');
49711 }
49712 /**
49713 *
49714 * @param {Event} event
49715 * @private
49716 */
49717
49718 }, {
49719 key: "_dragStartEdge",
49720 value: function _dragStartEdge(event) {
49721 var pointer = this.lastTouch;
49722
49723 this.selectionHandler._generateClickEvent('dragStart', event, pointer, undefined, true);
49724 } // --------------------------------------- END OF ADD EDGE FUNCTIONS -------------------------------------//
49725 // ------------------------------ Performing all the actual data manipulation ------------------------//
49726
49727 /**
49728 * Adds a node on the specified location
49729 *
49730 * @param {Object} clickData
49731 * @private
49732 */
49733
49734 }, {
49735 key: "_performAddNode",
49736 value: function _performAddNode(clickData) {
49737 var _this4 = this;
49738
49739 var defaultData = {
49740 id: uuid4(),
49741 x: clickData.pointer.canvas.x,
49742 y: clickData.pointer.canvas.y,
49743 label: 'new'
49744 };
49745
49746 if (typeof this.options.addNode === 'function') {
49747 if (this.options.addNode.length === 2) {
49748 this.options.addNode(defaultData, function (finalizedData) {
49749 if (finalizedData !== null && finalizedData !== undefined && _this4.inMode === 'addNode') {
49750 // if for whatever reason the mode has changes (due to dataset change) disregard the callback
49751 _this4.body.data.nodes.getDataSet().add(finalizedData);
49752 }
49753
49754 _this4.showManipulatorToolbar();
49755 });
49756 } else {
49757 this.showManipulatorToolbar();
49758 throw new Error('The function for add does not support two arguments (data,callback)');
49759 }
49760 } else {
49761 this.body.data.nodes.getDataSet().add(defaultData);
49762 this.showManipulatorToolbar();
49763 }
49764 }
49765 /**
49766 * connect two nodes with a new edge.
49767 *
49768 * @param {Node.id} sourceNodeId
49769 * @param {Node.id} targetNodeId
49770 * @private
49771 */
49772
49773 }, {
49774 key: "_performAddEdge",
49775 value: function _performAddEdge(sourceNodeId, targetNodeId) {
49776 var _this5 = this;
49777
49778 var defaultData = {
49779 from: sourceNodeId,
49780 to: targetNodeId
49781 };
49782
49783 if (typeof this.options.addEdge === 'function') {
49784 if (this.options.addEdge.length === 2) {
49785 this.options.addEdge(defaultData, function (finalizedData) {
49786 if (finalizedData !== null && finalizedData !== undefined && _this5.inMode === 'addEdge') {
49787 // if for whatever reason the mode has changes (due to dataset change) disregard the callback
49788 _this5.body.data.edges.getDataSet().add(finalizedData);
49789
49790 _this5.selectionHandler.unselectAll();
49791
49792 _this5.showManipulatorToolbar();
49793 }
49794 });
49795 } else {
49796 throw new Error('The function for connect does not support two arguments (data,callback)');
49797 }
49798 } else {
49799 this.body.data.edges.getDataSet().add(defaultData);
49800 this.selectionHandler.unselectAll();
49801 this.showManipulatorToolbar();
49802 }
49803 }
49804 /**
49805 * connect two nodes with a new edge.
49806 *
49807 * @param {Node.id} sourceNodeId
49808 * @param {Node.id} targetNodeId
49809 * @private
49810 */
49811
49812 }, {
49813 key: "_performEditEdge",
49814 value: function _performEditEdge(sourceNodeId, targetNodeId) {
49815 var _this6 = this;
49816
49817 var defaultData = {
49818 id: this.edgeBeingEditedId,
49819 from: sourceNodeId,
49820 to: targetNodeId,
49821 label: this.body.data.edges._data[this.edgeBeingEditedId].label
49822 };
49823 var eeFunct = this.options.editEdge;
49824
49825 if (_typeof$1(eeFunct) === 'object') {
49826 eeFunct = eeFunct.editWithoutDrag;
49827 }
49828
49829 if (typeof eeFunct === 'function') {
49830 if (eeFunct.length === 2) {
49831 eeFunct(defaultData, function (finalizedData) {
49832 if (finalizedData === null || finalizedData === undefined || _this6.inMode !== 'editEdge') {
49833 // if for whatever reason the mode has changes (due to dataset change) disregard the callback) {
49834 _this6.body.edges[defaultData.id].updateEdgeType();
49835
49836 _this6.body.emitter.emit('_redraw');
49837
49838 _this6.showManipulatorToolbar();
49839 } else {
49840 _this6.body.data.edges.getDataSet().update(finalizedData);
49841
49842 _this6.selectionHandler.unselectAll();
49843
49844 _this6.showManipulatorToolbar();
49845 }
49846 });
49847 } else {
49848 throw new Error('The function for edit does not support two arguments (data, callback)');
49849 }
49850 } else {
49851 this.body.data.edges.getDataSet().update(defaultData);
49852 this.selectionHandler.unselectAll();
49853 this.showManipulatorToolbar();
49854 }
49855 }
49856 }]);
49857
49858 return ManipulationSystem;
49859 }();
49860
49861 var htmlColors = {
49862 black: '#000000',
49863 navy: '#000080',
49864 darkblue: '#00008B',
49865 mediumblue: '#0000CD',
49866 blue: '#0000FF',
49867 darkgreen: '#006400',
49868 green: '#008000',
49869 teal: '#008080',
49870 darkcyan: '#008B8B',
49871 deepskyblue: '#00BFFF',
49872 darkturquoise: '#00CED1',
49873 mediumspringgreen: '#00FA9A',
49874 lime: '#00FF00',
49875 springgreen: '#00FF7F',
49876 aqua: '#00FFFF',
49877 cyan: '#00FFFF',
49878 midnightblue: '#191970',
49879 dodgerblue: '#1E90FF',
49880 lightseagreen: '#20B2AA',
49881 forestgreen: '#228B22',
49882 seagreen: '#2E8B57',
49883 darkslategray: '#2F4F4F',
49884 limegreen: '#32CD32',
49885 mediumseagreen: '#3CB371',
49886 turquoise: '#40E0D0',
49887 royalblue: '#4169E1',
49888 steelblue: '#4682B4',
49889 darkslateblue: '#483D8B',
49890 mediumturquoise: '#48D1CC',
49891 indigo: '#4B0082',
49892 darkolivegreen: '#556B2F',
49893 cadetblue: '#5F9EA0',
49894 cornflowerblue: '#6495ED',
49895 mediumaquamarine: '#66CDAA',
49896 dimgray: '#696969',
49897 slateblue: '#6A5ACD',
49898 olivedrab: '#6B8E23',
49899 slategray: '#708090',
49900 lightslategray: '#778899',
49901 mediumslateblue: '#7B68EE',
49902 lawngreen: '#7CFC00',
49903 chartreuse: '#7FFF00',
49904 aquamarine: '#7FFFD4',
49905 maroon: '#800000',
49906 purple: '#800080',
49907 olive: '#808000',
49908 gray: '#808080',
49909 skyblue: '#87CEEB',
49910 lightskyblue: '#87CEFA',
49911 blueviolet: '#8A2BE2',
49912 darkred: '#8B0000',
49913 darkmagenta: '#8B008B',
49914 saddlebrown: '#8B4513',
49915 darkseagreen: '#8FBC8F',
49916 lightgreen: '#90EE90',
49917 mediumpurple: '#9370D8',
49918 darkviolet: '#9400D3',
49919 palegreen: '#98FB98',
49920 darkorchid: '#9932CC',
49921 yellowgreen: '#9ACD32',
49922 sienna: '#A0522D',
49923 brown: '#A52A2A',
49924 darkgray: '#A9A9A9',
49925 lightblue: '#ADD8E6',
49926 greenyellow: '#ADFF2F',
49927 paleturquoise: '#AFEEEE',
49928 lightsteelblue: '#B0C4DE',
49929 powderblue: '#B0E0E6',
49930 firebrick: '#B22222',
49931 darkgoldenrod: '#B8860B',
49932 mediumorchid: '#BA55D3',
49933 rosybrown: '#BC8F8F',
49934 darkkhaki: '#BDB76B',
49935 silver: '#C0C0C0',
49936 mediumvioletred: '#C71585',
49937 indianred: '#CD5C5C',
49938 peru: '#CD853F',
49939 chocolate: '#D2691E',
49940 tan: '#D2B48C',
49941 lightgrey: '#D3D3D3',
49942 palevioletred: '#D87093',
49943 thistle: '#D8BFD8',
49944 orchid: '#DA70D6',
49945 goldenrod: '#DAA520',
49946 crimson: '#DC143C',
49947 gainsboro: '#DCDCDC',
49948 plum: '#DDA0DD',
49949 burlywood: '#DEB887',
49950 lightcyan: '#E0FFFF',
49951 lavender: '#E6E6FA',
49952 darksalmon: '#E9967A',
49953 violet: '#EE82EE',
49954 palegoldenrod: '#EEE8AA',
49955 lightcoral: '#F08080',
49956 khaki: '#F0E68C',
49957 aliceblue: '#F0F8FF',
49958 honeydew: '#F0FFF0',
49959 azure: '#F0FFFF',
49960 sandybrown: '#F4A460',
49961 wheat: '#F5DEB3',
49962 beige: '#F5F5DC',
49963 whitesmoke: '#F5F5F5',
49964 mintcream: '#F5FFFA',
49965 ghostwhite: '#F8F8FF',
49966 salmon: '#FA8072',
49967 antiquewhite: '#FAEBD7',
49968 linen: '#FAF0E6',
49969 lightgoldenrodyellow: '#FAFAD2',
49970 oldlace: '#FDF5E6',
49971 red: '#FF0000',
49972 fuchsia: '#FF00FF',
49973 magenta: '#FF00FF',
49974 deeppink: '#FF1493',
49975 orangered: '#FF4500',
49976 tomato: '#FF6347',
49977 hotpink: '#FF69B4',
49978 coral: '#FF7F50',
49979 darkorange: '#FF8C00',
49980 lightsalmon: '#FFA07A',
49981 orange: '#FFA500',
49982 lightpink: '#FFB6C1',
49983 pink: '#FFC0CB',
49984 gold: '#FFD700',
49985 peachpuff: '#FFDAB9',
49986 navajowhite: '#FFDEAD',
49987 moccasin: '#FFE4B5',
49988 bisque: '#FFE4C4',
49989 mistyrose: '#FFE4E1',
49990 blanchedalmond: '#FFEBCD',
49991 papayawhip: '#FFEFD5',
49992 lavenderblush: '#FFF0F5',
49993 seashell: '#FFF5EE',
49994 cornsilk: '#FFF8DC',
49995 lemonchiffon: '#FFFACD',
49996 floralwhite: '#FFFAF0',
49997 snow: '#FFFAFA',
49998 yellow: '#FFFF00',
49999 lightyellow: '#FFFFE0',
50000 ivory: '#FFFFF0',
50001 white: '#FFFFFF'
50002 };
50003 /**
50004 * @param {number} [pixelRatio=1]
50005 */
50006
50007 var ColorPicker =
50008 /*#__PURE__*/
50009 function () {
50010 /**
50011 * @param {number} [pixelRatio=1]
50012 */
50013 function ColorPicker() {
50014 var pixelRatio = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1;
50015
50016 _classCallCheck(this, ColorPicker);
50017
50018 this.pixelRatio = pixelRatio;
50019 this.generated = false;
50020 this.centerCoordinates = {
50021 x: 289 / 2,
50022 y: 289 / 2
50023 };
50024 this.r = 289 * 0.49;
50025 this.color = {
50026 r: 255,
50027 g: 255,
50028 b: 255,
50029 a: 1.0
50030 };
50031 this.hueCircle = undefined;
50032 this.initialColor = {
50033 r: 255,
50034 g: 255,
50035 b: 255,
50036 a: 1.0
50037 };
50038 this.previousColor = undefined;
50039 this.applied = false; // bound by
50040
50041 this.updateCallback = function () {};
50042
50043 this.closeCallback = function () {}; // create all DOM elements
50044
50045
50046 this._create();
50047 }
50048 /**
50049 * this inserts the colorPicker into a div from the DOM
50050 * @param {Element} container
50051 */
50052
50053
50054 _createClass(ColorPicker, [{
50055 key: "insertTo",
50056 value: function insertTo(container) {
50057 if (this.hammer !== undefined) {
50058 this.hammer.destroy();
50059 this.hammer = undefined;
50060 }
50061
50062 this.container = container;
50063 this.container.appendChild(this.frame);
50064
50065 this._bindHammer();
50066
50067 this._setSize();
50068 }
50069 /**
50070 * the callback is executed on apply and save. Bind it to the application
50071 * @param {function} callback
50072 */
50073
50074 }, {
50075 key: "setUpdateCallback",
50076 value: function setUpdateCallback(callback) {
50077 if (typeof callback === 'function') {
50078 this.updateCallback = callback;
50079 } else {
50080 throw new Error("Function attempted to set as colorPicker update callback is not a function.");
50081 }
50082 }
50083 /**
50084 * the callback is executed on apply and save. Bind it to the application
50085 * @param {function} callback
50086 */
50087
50088 }, {
50089 key: "setCloseCallback",
50090 value: function setCloseCallback(callback) {
50091 if (typeof callback === 'function') {
50092 this.closeCallback = callback;
50093 } else {
50094 throw new Error("Function attempted to set as colorPicker closing callback is not a function.");
50095 }
50096 }
50097 /**
50098 *
50099 * @param {string} color
50100 * @returns {String}
50101 * @private
50102 */
50103
50104 }, {
50105 key: "_isColorString",
50106 value: function _isColorString(color) {
50107 if (typeof color === 'string') {
50108 return htmlColors[color];
50109 }
50110 }
50111 /**
50112 * Set the color of the colorPicker
50113 * Supported formats:
50114 * 'red' --> HTML color string
50115 * '#ffffff' --> hex string
50116 * 'rgb(255,255,255)' --> rgb string
50117 * 'rgba(255,255,255,1.0)' --> rgba string
50118 * {r:255,g:255,b:255} --> rgb object
50119 * {r:255,g:255,b:255,a:1.0} --> rgba object
50120 * @param {string|Object} color
50121 * @param {boolean} [setInitial=true]
50122 */
50123
50124 }, {
50125 key: "setColor",
50126 value: function setColor(color) {
50127 var setInitial = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
50128
50129 if (color === 'none') {
50130 return;
50131 }
50132
50133 var rgba; // if a html color shorthand is used, convert to hex
50134
50135 var htmlColor = this._isColorString(color);
50136
50137 if (htmlColor !== undefined) {
50138 color = htmlColor;
50139 } // check format
50140
50141
50142 if (isString(color) === true) {
50143 if (isValidRGB(color) === true) {
50144 var rgbaArray = color.substr(4).substr(0, color.length - 5).split(',');
50145 rgba = {
50146 r: rgbaArray[0],
50147 g: rgbaArray[1],
50148 b: rgbaArray[2],
50149 a: 1.0
50150 };
50151 } else if (isValidRGBA(color) === true) {
50152 var _rgbaArray = color.substr(5).substr(0, color.length - 6).split(',');
50153
50154 rgba = {
50155 r: _rgbaArray[0],
50156 g: _rgbaArray[1],
50157 b: _rgbaArray[2],
50158 a: _rgbaArray[3]
50159 };
50160 } else if (isValidHex(color) === true) {
50161 var rgbObj = hexToRGB(color);
50162 rgba = {
50163 r: rgbObj.r,
50164 g: rgbObj.g,
50165 b: rgbObj.b,
50166 a: 1.0
50167 };
50168 }
50169 } else {
50170 if (color instanceof Object) {
50171 if (color.r !== undefined && color.g !== undefined && color.b !== undefined) {
50172 var alpha = color.a !== undefined ? color.a : '1.0';
50173 rgba = {
50174 r: color.r,
50175 g: color.g,
50176 b: color.b,
50177 a: alpha
50178 };
50179 }
50180 }
50181 } // set color
50182
50183
50184 if (rgba === undefined) {
50185 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));
50186 } else {
50187 this._setColor(rgba, setInitial);
50188 }
50189 }
50190 /**
50191 * this shows the color picker.
50192 * The hue circle is constructed once and stored.
50193 */
50194
50195 }, {
50196 key: "show",
50197 value: function show() {
50198 if (this.closeCallback !== undefined) {
50199 this.closeCallback();
50200 this.closeCallback = undefined;
50201 }
50202
50203 this.applied = false;
50204 this.frame.style.display = 'block';
50205
50206 this._generateHueCircle();
50207 } // ------------------------------------------ PRIVATE ----------------------------- //
50208
50209 /**
50210 * Hide the picker. Is called by the cancel button.
50211 * Optional boolean to store the previous color for easy access later on.
50212 * @param {boolean} [storePrevious=true]
50213 * @private
50214 */
50215
50216 }, {
50217 key: "_hide",
50218 value: function _hide() {
50219 var _this = this;
50220
50221 var storePrevious = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
50222
50223 // store the previous color for next time;
50224 if (storePrevious === true) {
50225 this.previousColor = extend({}, this.color);
50226 }
50227
50228 if (this.applied === true) {
50229 this.updateCallback(this.initialColor);
50230 }
50231
50232 this.frame.style.display = 'none'; // call the closing callback, restoring the onclick method.
50233 // this is in a setTimeout because it will trigger the show again before the click is done.
50234
50235 setTimeout(function () {
50236 if (_this.closeCallback !== undefined) {
50237 _this.closeCallback();
50238
50239 _this.closeCallback = undefined;
50240 }
50241 }, 0);
50242 }
50243 /**
50244 * bound to the save button. Saves and hides.
50245 * @private
50246 */
50247
50248 }, {
50249 key: "_save",
50250 value: function _save() {
50251 this.updateCallback(this.color);
50252 this.applied = false;
50253
50254 this._hide();
50255 }
50256 /**
50257 * Bound to apply button. Saves but does not close. Is undone by the cancel button.
50258 * @private
50259 */
50260
50261 }, {
50262 key: "_apply",
50263 value: function _apply() {
50264 this.applied = true;
50265 this.updateCallback(this.color);
50266
50267 this._updatePicker(this.color);
50268 }
50269 /**
50270 * load the color from the previous session.
50271 * @private
50272 */
50273
50274 }, {
50275 key: "_loadLast",
50276 value: function _loadLast() {
50277 if (this.previousColor !== undefined) {
50278 this.setColor(this.previousColor, false);
50279 } else {
50280 alert("There is no last color to load...");
50281 }
50282 }
50283 /**
50284 * set the color, place the picker
50285 * @param {Object} rgba
50286 * @param {boolean} [setInitial=true]
50287 * @private
50288 */
50289
50290 }, {
50291 key: "_setColor",
50292 value: function _setColor(rgba) {
50293 var setInitial = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
50294
50295 // store the initial color
50296 if (setInitial === true) {
50297 this.initialColor = extend({}, rgba);
50298 }
50299
50300 this.color = rgba;
50301 var hsv = RGBToHSV(rgba.r, rgba.g, rgba.b);
50302 var angleConvert = 2 * Math.PI;
50303 var radius = this.r * hsv.s;
50304 var x = this.centerCoordinates.x + radius * Math.sin(angleConvert * hsv.h);
50305 var y = this.centerCoordinates.y + radius * Math.cos(angleConvert * hsv.h);
50306 this.colorPickerSelector.style.left = x - 0.5 * this.colorPickerSelector.clientWidth + 'px';
50307 this.colorPickerSelector.style.top = y - 0.5 * this.colorPickerSelector.clientHeight + 'px';
50308
50309 this._updatePicker(rgba);
50310 }
50311 /**
50312 * bound to opacity control
50313 * @param {number} value
50314 * @private
50315 */
50316
50317 }, {
50318 key: "_setOpacity",
50319 value: function _setOpacity(value) {
50320 this.color.a = value / 100;
50321
50322 this._updatePicker(this.color);
50323 }
50324 /**
50325 * bound to brightness control
50326 * @param {number} value
50327 * @private
50328 */
50329
50330 }, {
50331 key: "_setBrightness",
50332 value: function _setBrightness(value) {
50333 var hsv = RGBToHSV(this.color.r, this.color.g, this.color.b);
50334 hsv.v = value / 100;
50335 var rgba = HSVToRGB(hsv.h, hsv.s, hsv.v);
50336 rgba['a'] = this.color.a;
50337 this.color = rgba;
50338
50339 this._updatePicker();
50340 }
50341 /**
50342 * update the color picker. A black circle overlays the hue circle to mimic the brightness decreasing.
50343 * @param {Object} rgba
50344 * @private
50345 */
50346
50347 }, {
50348 key: "_updatePicker",
50349 value: function _updatePicker() {
50350 var rgba = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.color;
50351 var hsv = RGBToHSV(rgba.r, rgba.g, rgba.b);
50352 var ctx = this.colorPickerCanvas.getContext('2d');
50353
50354 if (this.pixelRation === undefined) {
50355 this.pixelRatio = (window.devicePixelRatio || 1) / (ctx.webkitBackingStorePixelRatio || ctx.mozBackingStorePixelRatio || ctx.msBackingStorePixelRatio || ctx.oBackingStorePixelRatio || ctx.backingStorePixelRatio || 1);
50356 }
50357
50358 ctx.setTransform(this.pixelRatio, 0, 0, this.pixelRatio, 0, 0); // clear the canvas
50359
50360 var w = this.colorPickerCanvas.clientWidth;
50361 var h = this.colorPickerCanvas.clientHeight;
50362 ctx.clearRect(0, 0, w, h);
50363 ctx.putImageData(this.hueCircle, 0, 0);
50364 ctx.fillStyle = 'rgba(0,0,0,' + (1 - hsv.v) + ')';
50365 ctx.circle(this.centerCoordinates.x, this.centerCoordinates.y, this.r);
50366 ctx.fill();
50367 this.brightnessRange.value = 100 * hsv.v;
50368 this.opacityRange.value = 100 * rgba.a;
50369 this.initialColorDiv.style.backgroundColor = 'rgba(' + this.initialColor.r + ',' + this.initialColor.g + ',' + this.initialColor.b + ',' + this.initialColor.a + ')';
50370 this.newColorDiv.style.backgroundColor = 'rgba(' + this.color.r + ',' + this.color.g + ',' + this.color.b + ',' + this.color.a + ')';
50371 }
50372 /**
50373 * used by create to set the size of the canvas.
50374 * @private
50375 */
50376
50377 }, {
50378 key: "_setSize",
50379 value: function _setSize() {
50380 this.colorPickerCanvas.style.width = '100%';
50381 this.colorPickerCanvas.style.height = '100%';
50382 this.colorPickerCanvas.width = 289 * this.pixelRatio;
50383 this.colorPickerCanvas.height = 289 * this.pixelRatio;
50384 }
50385 /**
50386 * create all dom elements
50387 * TODO: cleanup, lots of similar dom elements
50388 * @private
50389 */
50390
50391 }, {
50392 key: "_create",
50393 value: function _create() {
50394 this.frame = document.createElement('div');
50395 this.frame.className = 'vis-color-picker';
50396 this.colorPickerDiv = document.createElement('div');
50397 this.colorPickerSelector = document.createElement('div');
50398 this.colorPickerSelector.className = 'vis-selector';
50399 this.colorPickerDiv.appendChild(this.colorPickerSelector);
50400 this.colorPickerCanvas = document.createElement('canvas');
50401 this.colorPickerDiv.appendChild(this.colorPickerCanvas);
50402
50403 if (!this.colorPickerCanvas.getContext) {
50404 var noCanvas = document.createElement('DIV');
50405 noCanvas.style.color = 'red';
50406 noCanvas.style.fontWeight = 'bold';
50407 noCanvas.style.padding = '10px';
50408 noCanvas.innerHTML = 'Error: your browser does not support HTML canvas';
50409 this.colorPickerCanvas.appendChild(noCanvas);
50410 } else {
50411 var ctx = this.colorPickerCanvas.getContext("2d");
50412 this.pixelRatio = (window.devicePixelRatio || 1) / (ctx.webkitBackingStorePixelRatio || ctx.mozBackingStorePixelRatio || ctx.msBackingStorePixelRatio || ctx.oBackingStorePixelRatio || ctx.backingStorePixelRatio || 1);
50413 this.colorPickerCanvas.getContext("2d").setTransform(this.pixelRatio, 0, 0, this.pixelRatio, 0, 0);
50414 }
50415
50416 this.colorPickerDiv.className = 'vis-color';
50417 this.opacityDiv = document.createElement('div');
50418 this.opacityDiv.className = 'vis-opacity';
50419 this.brightnessDiv = document.createElement('div');
50420 this.brightnessDiv.className = 'vis-brightness';
50421 this.arrowDiv = document.createElement('div');
50422 this.arrowDiv.className = 'vis-arrow';
50423 this.opacityRange = document.createElement('input');
50424
50425 try {
50426 this.opacityRange.type = 'range'; // Not supported on IE9
50427
50428 this.opacityRange.min = '0';
50429 this.opacityRange.max = '100';
50430 } // TODO: Add some error handling and remove this lint exception
50431 catch (err) {} // eslint-disable-line no-empty
50432
50433
50434 this.opacityRange.value = '100';
50435 this.opacityRange.className = 'vis-range';
50436 this.brightnessRange = document.createElement('input');
50437
50438 try {
50439 this.brightnessRange.type = 'range'; // Not supported on IE9
50440
50441 this.brightnessRange.min = '0';
50442 this.brightnessRange.max = '100';
50443 } // TODO: Add some error handling and remove this lint exception
50444 catch (err) {} // eslint-disable-line no-empty
50445
50446
50447 this.brightnessRange.value = '100';
50448 this.brightnessRange.className = 'vis-range';
50449 this.opacityDiv.appendChild(this.opacityRange);
50450 this.brightnessDiv.appendChild(this.brightnessRange);
50451 var me = this;
50452
50453 this.opacityRange.onchange = function () {
50454 me._setOpacity(this.value);
50455 };
50456
50457 this.opacityRange.oninput = function () {
50458 me._setOpacity(this.value);
50459 };
50460
50461 this.brightnessRange.onchange = function () {
50462 me._setBrightness(this.value);
50463 };
50464
50465 this.brightnessRange.oninput = function () {
50466 me._setBrightness(this.value);
50467 };
50468
50469 this.brightnessLabel = document.createElement("div");
50470 this.brightnessLabel.className = "vis-label vis-brightness";
50471 this.brightnessLabel.innerHTML = 'brightness:';
50472 this.opacityLabel = document.createElement("div");
50473 this.opacityLabel.className = "vis-label vis-opacity";
50474 this.opacityLabel.innerHTML = 'opacity:';
50475 this.newColorDiv = document.createElement("div");
50476 this.newColorDiv.className = "vis-new-color";
50477 this.newColorDiv.innerHTML = 'new';
50478 this.initialColorDiv = document.createElement("div");
50479 this.initialColorDiv.className = "vis-initial-color";
50480 this.initialColorDiv.innerHTML = 'initial';
50481 this.cancelButton = document.createElement("div");
50482 this.cancelButton.className = "vis-button vis-cancel";
50483 this.cancelButton.innerHTML = 'cancel';
50484 this.cancelButton.onclick = this._hide.bind(this, false);
50485 this.applyButton = document.createElement("div");
50486 this.applyButton.className = "vis-button vis-apply";
50487 this.applyButton.innerHTML = 'apply';
50488 this.applyButton.onclick = this._apply.bind(this);
50489 this.saveButton = document.createElement("div");
50490 this.saveButton.className = "vis-button vis-save";
50491 this.saveButton.innerHTML = 'save';
50492 this.saveButton.onclick = this._save.bind(this);
50493 this.loadButton = document.createElement("div");
50494 this.loadButton.className = "vis-button vis-load";
50495 this.loadButton.innerHTML = 'load last';
50496 this.loadButton.onclick = this._loadLast.bind(this);
50497 this.frame.appendChild(this.colorPickerDiv);
50498 this.frame.appendChild(this.arrowDiv);
50499 this.frame.appendChild(this.brightnessLabel);
50500 this.frame.appendChild(this.brightnessDiv);
50501 this.frame.appendChild(this.opacityLabel);
50502 this.frame.appendChild(this.opacityDiv);
50503 this.frame.appendChild(this.newColorDiv);
50504 this.frame.appendChild(this.initialColorDiv);
50505 this.frame.appendChild(this.cancelButton);
50506 this.frame.appendChild(this.applyButton);
50507 this.frame.appendChild(this.saveButton);
50508 this.frame.appendChild(this.loadButton);
50509 }
50510 /**
50511 * bind hammer to the color picker
50512 * @private
50513 */
50514
50515 }, {
50516 key: "_bindHammer",
50517 value: function _bindHammer() {
50518 var _this2 = this;
50519
50520 this.drag = {};
50521 this.pinch = {};
50522 this.hammer = new hammer(this.colorPickerCanvas);
50523 this.hammer.get('pinch').set({
50524 enable: true
50525 });
50526 hammerUtil.onTouch(this.hammer, function (event) {
50527 _this2._moveSelector(event);
50528 });
50529 this.hammer.on('tap', function (event) {
50530 _this2._moveSelector(event);
50531 });
50532 this.hammer.on('panstart', function (event) {
50533 _this2._moveSelector(event);
50534 });
50535 this.hammer.on('panmove', function (event) {
50536 _this2._moveSelector(event);
50537 });
50538 this.hammer.on('panend', function (event) {
50539 _this2._moveSelector(event);
50540 });
50541 }
50542 /**
50543 * generate the hue circle. This is relatively heavy (200ms) and is done only once on the first time it is shown.
50544 * @private
50545 */
50546
50547 }, {
50548 key: "_generateHueCircle",
50549 value: function _generateHueCircle() {
50550 if (this.generated === false) {
50551 var ctx = this.colorPickerCanvas.getContext('2d');
50552
50553 if (this.pixelRation === undefined) {
50554 this.pixelRatio = (window.devicePixelRatio || 1) / (ctx.webkitBackingStorePixelRatio || ctx.mozBackingStorePixelRatio || ctx.msBackingStorePixelRatio || ctx.oBackingStorePixelRatio || ctx.backingStorePixelRatio || 1);
50555 }
50556
50557 ctx.setTransform(this.pixelRatio, 0, 0, this.pixelRatio, 0, 0); // clear the canvas
50558
50559 var w = this.colorPickerCanvas.clientWidth;
50560 var h = this.colorPickerCanvas.clientHeight;
50561 ctx.clearRect(0, 0, w, h); // draw hue circle
50562
50563 var x, y, hue, sat;
50564 this.centerCoordinates = {
50565 x: w * 0.5,
50566 y: h * 0.5
50567 };
50568 this.r = 0.49 * w;
50569 var angleConvert = 2 * Math.PI / 360;
50570 var hfac = 1 / 360;
50571 var sfac = 1 / this.r;
50572 var rgb;
50573
50574 for (hue = 0; hue < 360; hue++) {
50575 for (sat = 0; sat < this.r; sat++) {
50576 x = this.centerCoordinates.x + sat * Math.sin(angleConvert * hue);
50577 y = this.centerCoordinates.y + sat * Math.cos(angleConvert * hue);
50578 rgb = HSVToRGB(hue * hfac, sat * sfac, 1);
50579 ctx.fillStyle = 'rgb(' + rgb.r + ',' + rgb.g + ',' + rgb.b + ')';
50580 ctx.fillRect(x - 0.5, y - 0.5, 2, 2);
50581 }
50582 }
50583
50584 ctx.strokeStyle = 'rgba(0,0,0,1)';
50585 ctx.circle(this.centerCoordinates.x, this.centerCoordinates.y, this.r);
50586 ctx.stroke();
50587 this.hueCircle = ctx.getImageData(0, 0, w, h);
50588 }
50589
50590 this.generated = true;
50591 }
50592 /**
50593 * move the selector. This is called by hammer functions.
50594 *
50595 * @param {Event} event The event
50596 * @private
50597 */
50598
50599 }, {
50600 key: "_moveSelector",
50601 value: function _moveSelector(event) {
50602 var rect = this.colorPickerDiv.getBoundingClientRect();
50603 var left = event.center.x - rect.left;
50604 var top = event.center.y - rect.top;
50605 var centerY = 0.5 * this.colorPickerDiv.clientHeight;
50606 var centerX = 0.5 * this.colorPickerDiv.clientWidth;
50607 var x = left - centerX;
50608 var y = top - centerY;
50609 var angle = Math.atan2(x, y);
50610 var radius = 0.98 * Math.min(Math.sqrt(x * x + y * y), centerX);
50611 var newTop = Math.cos(angle) * radius + centerY;
50612 var newLeft = Math.sin(angle) * radius + centerX;
50613 this.colorPickerSelector.style.top = newTop - 0.5 * this.colorPickerSelector.clientHeight + 'px';
50614 this.colorPickerSelector.style.left = newLeft - 0.5 * this.colorPickerSelector.clientWidth + 'px'; // set color
50615
50616 var h = angle / (2 * Math.PI);
50617 h = h < 0 ? h + 1 : h;
50618 var s = radius / this.r;
50619 var hsv = RGBToHSV(this.color.r, this.color.g, this.color.b);
50620 hsv.h = h;
50621 hsv.s = s;
50622 var rgba = HSVToRGB(hsv.h, hsv.s, hsv.v);
50623 rgba['a'] = this.color.a;
50624 this.color = rgba; // update previews
50625
50626 this.initialColorDiv.style.backgroundColor = 'rgba(' + this.initialColor.r + ',' + this.initialColor.g + ',' + this.initialColor.b + ',' + this.initialColor.a + ')';
50627 this.newColorDiv.style.backgroundColor = 'rgba(' + this.color.r + ',' + this.color.g + ',' + this.color.b + ',' + this.color.a + ')';
50628 }
50629 }]);
50630
50631 return ColorPicker;
50632 }();
50633
50634 /**
50635 * 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.
50636 * Boolean options are recognised as Boolean
50637 * Number options should be written as array: [default value, min value, max value, stepsize]
50638 * Colors should be written as array: ['color', '#ffffff']
50639 * Strings with should be written as array: [option1, option2, option3, ..]
50640 *
50641 * The options are matched with their counterparts in each of the modules and the values used in the configuration are
50642 */
50643
50644 var Configurator =
50645 /*#__PURE__*/
50646 function () {
50647 /**
50648 * @param {Object} parentModule | the location where parentModule.setOptions() can be called
50649 * @param {Object} defaultContainer | the default container of the module
50650 * @param {Object} configureOptions | the fully configured and predefined options set found in allOptions.js
50651 * @param {number} pixelRatio | canvas pixel ratio
50652 */
50653 function Configurator(parentModule, defaultContainer, configureOptions) {
50654 var pixelRatio = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 1;
50655
50656 _classCallCheck(this, Configurator);
50657
50658 this.parent = parentModule;
50659 this.changedOptions = [];
50660 this.container = defaultContainer;
50661 this.allowCreation = false;
50662 this.options = {};
50663 this.initialized = false;
50664 this.popupCounter = 0;
50665 this.defaultOptions = {
50666 enabled: false,
50667 filter: true,
50668 container: undefined,
50669 showButton: true
50670 };
50671 extend(this.options, this.defaultOptions);
50672 this.configureOptions = configureOptions;
50673 this.moduleOptions = {};
50674 this.domElements = [];
50675 this.popupDiv = {};
50676 this.popupLimit = 5;
50677 this.popupHistory = {};
50678 this.colorPicker = new ColorPicker(pixelRatio);
50679 this.wrapper = undefined;
50680 }
50681 /**
50682 * refresh all options.
50683 * Because all modules parse their options by themselves, we just use their options. We copy them here.
50684 *
50685 * @param {Object} options
50686 */
50687
50688
50689 _createClass(Configurator, [{
50690 key: "setOptions",
50691 value: function setOptions(options) {
50692 if (options !== undefined) {
50693 // reset the popup history because the indices may have been changed.
50694 this.popupHistory = {};
50695
50696 this._removePopup();
50697
50698 var enabled = true;
50699
50700 if (typeof options === 'string') {
50701 this.options.filter = options;
50702 } else if (options instanceof Array) {
50703 this.options.filter = options.join();
50704 } else if (_typeof$1(options) === 'object') {
50705 if (options == null) {
50706 throw new TypeError('options cannot be null');
50707 }
50708
50709 if (options.container !== undefined) {
50710 this.options.container = options.container;
50711 }
50712
50713 if (options.filter !== undefined) {
50714 this.options.filter = options.filter;
50715 }
50716
50717 if (options.showButton !== undefined) {
50718 this.options.showButton = options.showButton;
50719 }
50720
50721 if (options.enabled !== undefined) {
50722 enabled = options.enabled;
50723 }
50724 } else if (typeof options === 'boolean') {
50725 this.options.filter = true;
50726 enabled = options;
50727 } else if (typeof options === 'function') {
50728 this.options.filter = options;
50729 enabled = true;
50730 }
50731
50732 if (this.options.filter === false) {
50733 enabled = false;
50734 }
50735
50736 this.options.enabled = enabled;
50737 }
50738
50739 this._clean();
50740 }
50741 /**
50742 *
50743 * @param {Object} moduleOptions
50744 */
50745
50746 }, {
50747 key: "setModuleOptions",
50748 value: function setModuleOptions(moduleOptions) {
50749 this.moduleOptions = moduleOptions;
50750
50751 if (this.options.enabled === true) {
50752 this._clean();
50753
50754 if (this.options.container !== undefined) {
50755 this.container = this.options.container;
50756 }
50757
50758 this._create();
50759 }
50760 }
50761 /**
50762 * Create all DOM elements
50763 * @private
50764 */
50765
50766 }, {
50767 key: "_create",
50768 value: function _create() {
50769 this._clean();
50770
50771 this.changedOptions = [];
50772 var filter = this.options.filter;
50773 var counter = 0;
50774 var show = false;
50775
50776 for (var option in this.configureOptions) {
50777 if (this.configureOptions.hasOwnProperty(option)) {
50778 this.allowCreation = false;
50779 show = false;
50780
50781 if (typeof filter === 'function') {
50782 show = filter(option, []);
50783 show = show || this._handleObject(this.configureOptions[option], [option], true);
50784 } else if (filter === true || filter.indexOf(option) !== -1) {
50785 show = true;
50786 }
50787
50788 if (show !== false) {
50789 this.allowCreation = true; // linebreak between categories
50790
50791 if (counter > 0) {
50792 this._makeItem([]);
50793 } // a header for the category
50794
50795
50796 this._makeHeader(option); // get the sub options
50797
50798
50799 this._handleObject(this.configureOptions[option], [option]);
50800 }
50801
50802 counter++;
50803 }
50804 }
50805
50806 this._makeButton();
50807
50808 this._push(); //~ this.colorPicker.insertTo(this.container);
50809
50810 }
50811 /**
50812 * draw all DOM elements on the screen
50813 * @private
50814 */
50815
50816 }, {
50817 key: "_push",
50818 value: function _push() {
50819 this.wrapper = document.createElement('div');
50820 this.wrapper.className = 'vis-configuration-wrapper';
50821 this.container.appendChild(this.wrapper);
50822
50823 for (var i = 0; i < this.domElements.length; i++) {
50824 this.wrapper.appendChild(this.domElements[i]);
50825 }
50826
50827 this._showPopupIfNeeded();
50828 }
50829 /**
50830 * delete all DOM elements
50831 * @private
50832 */
50833
50834 }, {
50835 key: "_clean",
50836 value: function _clean() {
50837 for (var i = 0; i < this.domElements.length; i++) {
50838 this.wrapper.removeChild(this.domElements[i]);
50839 }
50840
50841 if (this.wrapper !== undefined) {
50842 this.container.removeChild(this.wrapper);
50843 this.wrapper = undefined;
50844 }
50845
50846 this.domElements = [];
50847
50848 this._removePopup();
50849 }
50850 /**
50851 * get the value from the actualOptions if it exists
50852 * @param {array} path | where to look for the actual option
50853 * @returns {*}
50854 * @private
50855 */
50856
50857 }, {
50858 key: "_getValue",
50859 value: function _getValue(path) {
50860 var base = this.moduleOptions;
50861
50862 for (var i = 0; i < path.length; i++) {
50863 if (base[path[i]] !== undefined) {
50864 base = base[path[i]];
50865 } else {
50866 base = undefined;
50867 break;
50868 }
50869 }
50870
50871 return base;
50872 }
50873 /**
50874 * all option elements are wrapped in an item
50875 * @param {Array} path | where to look for the actual option
50876 * @param {Array.<Element>} domElements
50877 * @returns {number}
50878 * @private
50879 */
50880
50881 }, {
50882 key: "_makeItem",
50883 value: function _makeItem(path) {
50884 if (this.allowCreation === true) {
50885 var item = document.createElement('div');
50886 item.className = 'vis-configuration vis-config-item vis-config-s' + path.length;
50887
50888 for (var _len = arguments.length, domElements = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
50889 domElements[_key - 1] = arguments[_key];
50890 }
50891
50892 domElements.forEach(function (element) {
50893 item.appendChild(element);
50894 });
50895 this.domElements.push(item);
50896 return this.domElements.length;
50897 }
50898
50899 return 0;
50900 }
50901 /**
50902 * header for major subjects
50903 * @param {string} name
50904 * @private
50905 */
50906
50907 }, {
50908 key: "_makeHeader",
50909 value: function _makeHeader(name) {
50910 var div = document.createElement('div');
50911 div.className = 'vis-configuration vis-config-header';
50912 div.innerHTML = name;
50913
50914 this._makeItem([], div);
50915 }
50916 /**
50917 * make a label, if it is an object label, it gets different styling.
50918 * @param {string} name
50919 * @param {array} path | where to look for the actual option
50920 * @param {string} objectLabel
50921 * @returns {HTMLElement}
50922 * @private
50923 */
50924
50925 }, {
50926 key: "_makeLabel",
50927 value: function _makeLabel(name, path) {
50928 var objectLabel = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
50929 var div = document.createElement('div');
50930 div.className = 'vis-configuration vis-config-label vis-config-s' + path.length;
50931
50932 if (objectLabel === true) {
50933 div.innerHTML = '<i><b>' + name + ':</b></i>';
50934 } else {
50935 div.innerHTML = name + ':';
50936 }
50937
50938 return div;
50939 }
50940 /**
50941 * make a dropdown list for multiple possible string optoins
50942 * @param {Array.<number>} arr
50943 * @param {number} value
50944 * @param {array} path | where to look for the actual option
50945 * @private
50946 */
50947
50948 }, {
50949 key: "_makeDropdown",
50950 value: function _makeDropdown(arr, value, path) {
50951 var select = document.createElement('select');
50952 select.className = 'vis-configuration vis-config-select';
50953 var selectedValue = 0;
50954
50955 if (value !== undefined) {
50956 if (arr.indexOf(value) !== -1) {
50957 selectedValue = arr.indexOf(value);
50958 }
50959 }
50960
50961 for (var i = 0; i < arr.length; i++) {
50962 var option = document.createElement('option');
50963 option.value = arr[i];
50964
50965 if (i === selectedValue) {
50966 option.selected = 'selected';
50967 }
50968
50969 option.innerHTML = arr[i];
50970 select.appendChild(option);
50971 }
50972
50973 var me = this;
50974
50975 select.onchange = function () {
50976 me._update(this.value, path);
50977 };
50978
50979 var label = this._makeLabel(path[path.length - 1], path);
50980
50981 this._makeItem(path, label, select);
50982 }
50983 /**
50984 * make a range object for numeric options
50985 * @param {Array.<number>} arr
50986 * @param {number} value
50987 * @param {array} path | where to look for the actual option
50988 * @private
50989 */
50990
50991 }, {
50992 key: "_makeRange",
50993 value: function _makeRange(arr, value, path) {
50994 var defaultValue = arr[0];
50995 var min = arr[1];
50996 var max = arr[2];
50997 var step = arr[3];
50998 var range = document.createElement('input');
50999 range.className = 'vis-configuration vis-config-range';
51000
51001 try {
51002 range.type = 'range'; // not supported on IE9
51003
51004 range.min = min;
51005 range.max = max;
51006 } // TODO: Add some error handling and remove this lint exception
51007 catch (err) {} // eslint-disable-line no-empty
51008
51009
51010 range.step = step; // set up the popup settings in case they are needed.
51011
51012 var popupString = '';
51013 var popupValue = 0;
51014
51015 if (value !== undefined) {
51016 var factor = 1.20;
51017
51018 if (value < 0 && value * factor < min) {
51019 range.min = Math.ceil(value * factor);
51020 popupValue = range.min;
51021 popupString = 'range increased';
51022 } else if (value / factor < min) {
51023 range.min = Math.ceil(value / factor);
51024 popupValue = range.min;
51025 popupString = 'range increased';
51026 }
51027
51028 if (value * factor > max && max !== 1) {
51029 range.max = Math.ceil(value * factor);
51030 popupValue = range.max;
51031 popupString = 'range increased';
51032 }
51033
51034 range.value = value;
51035 } else {
51036 range.value = defaultValue;
51037 }
51038
51039 var input = document.createElement('input');
51040 input.className = 'vis-configuration vis-config-rangeinput';
51041 input.value = range.value;
51042 var me = this;
51043
51044 range.onchange = function () {
51045 input.value = this.value;
51046
51047 me._update(Number(this.value), path);
51048 };
51049
51050 range.oninput = function () {
51051 input.value = this.value;
51052 };
51053
51054 var label = this._makeLabel(path[path.length - 1], path);
51055
51056 var itemIndex = this._makeItem(path, label, range, input); // if a popup is needed AND it has not been shown for this value, show it.
51057
51058
51059 if (popupString !== '' && this.popupHistory[itemIndex] !== popupValue) {
51060 this.popupHistory[itemIndex] = popupValue;
51061
51062 this._setupPopup(popupString, itemIndex);
51063 }
51064 }
51065 /**
51066 * make a button object
51067 * @private
51068 */
51069
51070 }, {
51071 key: "_makeButton",
51072 value: function _makeButton() {
51073 var _this = this;
51074
51075 if (this.options.showButton === true) {
51076 var generateButton = document.createElement('div');
51077 generateButton.className = 'vis-configuration vis-config-button';
51078 generateButton.innerHTML = 'generate options';
51079
51080 generateButton.onclick = function () {
51081 _this._printOptions();
51082 };
51083
51084 generateButton.onmouseover = function () {
51085 generateButton.className = 'vis-configuration vis-config-button hover';
51086 };
51087
51088 generateButton.onmouseout = function () {
51089 generateButton.className = 'vis-configuration vis-config-button';
51090 };
51091
51092 this.optionsContainer = document.createElement('div');
51093 this.optionsContainer.className = 'vis-configuration vis-config-option-container';
51094 this.domElements.push(this.optionsContainer);
51095 this.domElements.push(generateButton);
51096 }
51097 }
51098 /**
51099 * prepare the popup
51100 * @param {string} string
51101 * @param {number} index
51102 * @private
51103 */
51104
51105 }, {
51106 key: "_setupPopup",
51107 value: function _setupPopup(string, index) {
51108 var _this2 = this;
51109
51110 if (this.initialized === true && this.allowCreation === true && this.popupCounter < this.popupLimit) {
51111 var div = document.createElement("div");
51112 div.id = "vis-configuration-popup";
51113 div.className = "vis-configuration-popup";
51114 div.innerHTML = string;
51115
51116 div.onclick = function () {
51117 _this2._removePopup();
51118 };
51119
51120 this.popupCounter += 1;
51121 this.popupDiv = {
51122 html: div,
51123 index: index
51124 };
51125 }
51126 }
51127 /**
51128 * remove the popup from the dom
51129 * @private
51130 */
51131
51132 }, {
51133 key: "_removePopup",
51134 value: function _removePopup() {
51135 if (this.popupDiv.html !== undefined) {
51136 this.popupDiv.html.parentNode.removeChild(this.popupDiv.html);
51137 clearTimeout(this.popupDiv.hideTimeout);
51138 clearTimeout(this.popupDiv.deleteTimeout);
51139 this.popupDiv = {};
51140 }
51141 }
51142 /**
51143 * Show the popup if it is needed.
51144 * @private
51145 */
51146
51147 }, {
51148 key: "_showPopupIfNeeded",
51149 value: function _showPopupIfNeeded() {
51150 var _this3 = this;
51151
51152 if (this.popupDiv.html !== undefined) {
51153 var correspondingElement = this.domElements[this.popupDiv.index];
51154 var rect = correspondingElement.getBoundingClientRect();
51155 this.popupDiv.html.style.left = rect.left + "px";
51156 this.popupDiv.html.style.top = rect.top - 30 + "px"; // 30 is the height;
51157
51158 document.body.appendChild(this.popupDiv.html);
51159 this.popupDiv.hideTimeout = setTimeout(function () {
51160 _this3.popupDiv.html.style.opacity = 0;
51161 }, 1500);
51162 this.popupDiv.deleteTimeout = setTimeout(function () {
51163 _this3._removePopup();
51164 }, 1800);
51165 }
51166 }
51167 /**
51168 * make a checkbox for boolean options.
51169 * @param {number} defaultValue
51170 * @param {number} value
51171 * @param {array} path | where to look for the actual option
51172 * @private
51173 */
51174
51175 }, {
51176 key: "_makeCheckbox",
51177 value: function _makeCheckbox(defaultValue, value, path) {
51178 var checkbox = document.createElement('input');
51179 checkbox.type = 'checkbox';
51180 checkbox.className = 'vis-configuration vis-config-checkbox';
51181 checkbox.checked = defaultValue;
51182
51183 if (value !== undefined) {
51184 checkbox.checked = value;
51185
51186 if (value !== defaultValue) {
51187 if (_typeof$1(defaultValue) === 'object') {
51188 if (value !== defaultValue.enabled) {
51189 this.changedOptions.push({
51190 path: path,
51191 value: value
51192 });
51193 }
51194 } else {
51195 this.changedOptions.push({
51196 path: path,
51197 value: value
51198 });
51199 }
51200 }
51201 }
51202
51203 var me = this;
51204
51205 checkbox.onchange = function () {
51206 me._update(this.checked, path);
51207 };
51208
51209 var label = this._makeLabel(path[path.length - 1], path);
51210
51211 this._makeItem(path, label, checkbox);
51212 }
51213 /**
51214 * make a text input field for string options.
51215 * @param {number} defaultValue
51216 * @param {number} value
51217 * @param {array} path | where to look for the actual option
51218 * @private
51219 */
51220
51221 }, {
51222 key: "_makeTextInput",
51223 value: function _makeTextInput(defaultValue, value, path) {
51224 var checkbox = document.createElement('input');
51225 checkbox.type = 'text';
51226 checkbox.className = 'vis-configuration vis-config-text';
51227 checkbox.value = value;
51228
51229 if (value !== defaultValue) {
51230 this.changedOptions.push({
51231 path: path,
51232 value: value
51233 });
51234 }
51235
51236 var me = this;
51237
51238 checkbox.onchange = function () {
51239 me._update(this.value, path);
51240 };
51241
51242 var label = this._makeLabel(path[path.length - 1], path);
51243
51244 this._makeItem(path, label, checkbox);
51245 }
51246 /**
51247 * make a color field with a color picker for color fields
51248 * @param {Array.<number>} arr
51249 * @param {number} value
51250 * @param {array} path | where to look for the actual option
51251 * @private
51252 */
51253
51254 }, {
51255 key: "_makeColorField",
51256 value: function _makeColorField(arr, value, path) {
51257 var _this4 = this;
51258
51259 var defaultColor = arr[1];
51260 var div = document.createElement('div');
51261 value = value === undefined ? defaultColor : value;
51262
51263 if (value !== 'none') {
51264 div.className = 'vis-configuration vis-config-colorBlock';
51265 div.style.backgroundColor = value;
51266 } else {
51267 div.className = 'vis-configuration vis-config-colorBlock none';
51268 }
51269
51270 value = value === undefined ? defaultColor : value;
51271
51272 div.onclick = function () {
51273 _this4._showColorPicker(value, div, path);
51274 };
51275
51276 var label = this._makeLabel(path[path.length - 1], path);
51277
51278 this._makeItem(path, label, div);
51279 }
51280 /**
51281 * used by the color buttons to call the color picker.
51282 * @param {number} value
51283 * @param {HTMLElement} div
51284 * @param {array} path | where to look for the actual option
51285 * @private
51286 */
51287
51288 }, {
51289 key: "_showColorPicker",
51290 value: function _showColorPicker(value, div, path) {
51291 var _this5 = this;
51292
51293 // clear the callback from this div
51294 div.onclick = function () {};
51295
51296 this.colorPicker.insertTo(div);
51297 this.colorPicker.show();
51298 this.colorPicker.setColor(value);
51299 this.colorPicker.setUpdateCallback(function (color) {
51300 var colorString = 'rgba(' + color.r + ',' + color.g + ',' + color.b + ',' + color.a + ')';
51301 div.style.backgroundColor = colorString;
51302
51303 _this5._update(colorString, path);
51304 }); // on close of the colorpicker, restore the callback.
51305
51306 this.colorPicker.setCloseCallback(function () {
51307 div.onclick = function () {
51308 _this5._showColorPicker(value, div, path);
51309 };
51310 });
51311 }
51312 /**
51313 * parse an object and draw the correct items
51314 * @param {Object} obj
51315 * @param {array} [path=[]] | where to look for the actual option
51316 * @param {boolean} [checkOnly=false]
51317 * @returns {boolean}
51318 * @private
51319 */
51320
51321 }, {
51322 key: "_handleObject",
51323 value: function _handleObject(obj) {
51324 var path = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
51325 var checkOnly = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
51326 var show = false;
51327 var filter = this.options.filter;
51328 var visibleInSet = false;
51329
51330 for (var subObj in obj) {
51331 if (obj.hasOwnProperty(subObj)) {
51332 show = true;
51333 var item = obj[subObj];
51334 var newPath = copyAndExtendArray(path, subObj);
51335
51336 if (typeof filter === 'function') {
51337 show = filter(subObj, path); // if needed we must go deeper into the object.
51338
51339 if (show === false) {
51340 if (!(item instanceof Array) && typeof item !== 'string' && typeof item !== 'boolean' && item instanceof Object) {
51341 this.allowCreation = false;
51342 show = this._handleObject(item, newPath, true);
51343 this.allowCreation = checkOnly === false;
51344 }
51345 }
51346 }
51347
51348 if (show !== false) {
51349 visibleInSet = true;
51350
51351 var value = this._getValue(newPath);
51352
51353 if (item instanceof Array) {
51354 this._handleArray(item, value, newPath);
51355 } else if (typeof item === 'string') {
51356 this._makeTextInput(item, value, newPath);
51357 } else if (typeof item === 'boolean') {
51358 this._makeCheckbox(item, value, newPath);
51359 } else if (item instanceof Object) {
51360 // collapse the physics options that are not enabled
51361 var draw = true;
51362
51363 if (path.indexOf('physics') !== -1) {
51364 if (this.moduleOptions.physics.solver !== subObj) {
51365 draw = false;
51366 }
51367 }
51368
51369 if (draw === true) {
51370 // initially collapse options with an disabled enabled option.
51371 if (item.enabled !== undefined) {
51372 var enabledPath = copyAndExtendArray(newPath, 'enabled');
51373
51374 var enabledValue = this._getValue(enabledPath);
51375
51376 if (enabledValue === true) {
51377 var label = this._makeLabel(subObj, newPath, true);
51378
51379 this._makeItem(newPath, label);
51380
51381 visibleInSet = this._handleObject(item, newPath) || visibleInSet;
51382 } else {
51383 this._makeCheckbox(item, enabledValue, newPath);
51384 }
51385 } else {
51386 var _label = this._makeLabel(subObj, newPath, true);
51387
51388 this._makeItem(newPath, _label);
51389
51390 visibleInSet = this._handleObject(item, newPath) || visibleInSet;
51391 }
51392 }
51393 } else {
51394 console.error('dont know how to handle', item, subObj, newPath);
51395 }
51396 }
51397 }
51398 }
51399
51400 return visibleInSet;
51401 }
51402 /**
51403 * handle the array type of option
51404 * @param {Array.<number>} arr
51405 * @param {number} value
51406 * @param {array} path | where to look for the actual option
51407 * @private
51408 */
51409
51410 }, {
51411 key: "_handleArray",
51412 value: function _handleArray(arr, value, path) {
51413 if (typeof arr[0] === 'string' && arr[0] === 'color') {
51414 this._makeColorField(arr, value, path);
51415
51416 if (arr[1] !== value) {
51417 this.changedOptions.push({
51418 path: path,
51419 value: value
51420 });
51421 }
51422 } else if (typeof arr[0] === 'string') {
51423 this._makeDropdown(arr, value, path);
51424
51425 if (arr[0] !== value) {
51426 this.changedOptions.push({
51427 path: path,
51428 value: value
51429 });
51430 }
51431 } else if (typeof arr[0] === 'number') {
51432 this._makeRange(arr, value, path);
51433
51434 if (arr[0] !== value) {
51435 this.changedOptions.push({
51436 path: path,
51437 value: Number(value)
51438 });
51439 }
51440 }
51441 }
51442 /**
51443 * called to update the network with the new settings.
51444 * @param {number} value
51445 * @param {array} path | where to look for the actual option
51446 * @private
51447 */
51448
51449 }, {
51450 key: "_update",
51451 value: function _update(value, path) {
51452 var options = this._constructOptions(value, path);
51453
51454 if (this.parent.body && this.parent.body.emitter && this.parent.body.emitter.emit) {
51455 this.parent.body.emitter.emit("configChange", options);
51456 }
51457
51458 this.initialized = true;
51459 this.parent.setOptions(options);
51460 }
51461 /**
51462 *
51463 * @param {string|Boolean} value
51464 * @param {Array.<string>} path
51465 * @param {{}} optionsObj
51466 * @returns {{}}
51467 * @private
51468 */
51469
51470 }, {
51471 key: "_constructOptions",
51472 value: function _constructOptions(value, path) {
51473 var optionsObj = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
51474 var pointer = optionsObj; // when dropdown boxes can be string or boolean, we typecast it into correct types
51475
51476 value = value === 'true' ? true : value;
51477 value = value === 'false' ? false : value;
51478
51479 for (var i = 0; i < path.length; i++) {
51480 if (path[i] !== 'global') {
51481 if (pointer[path[i]] === undefined) {
51482 pointer[path[i]] = {};
51483 }
51484
51485 if (i !== path.length - 1) {
51486 pointer = pointer[path[i]];
51487 } else {
51488 pointer[path[i]] = value;
51489 }
51490 }
51491 }
51492
51493 return optionsObj;
51494 }
51495 /**
51496 * @private
51497 */
51498
51499 }, {
51500 key: "_printOptions",
51501 value: function _printOptions() {
51502 var options = this.getOptions();
51503 this.optionsContainer.innerHTML = '<pre>var options = ' + JSON.stringify(options, null, 2) + '</pre>';
51504 }
51505 /**
51506 *
51507 * @returns {{}} options
51508 */
51509
51510 }, {
51511 key: "getOptions",
51512 value: function getOptions() {
51513 var options = {};
51514
51515 for (var i = 0; i < this.changedOptions.length; i++) {
51516 this._constructOptions(this.changedOptions[i].value, this.changedOptions[i].path, options);
51517 }
51518
51519 return options;
51520 }
51521 }]);
51522
51523 return Configurator;
51524 }();
51525
51526 /**
51527 * This object contains all possible options. It will check if the types are correct, if required if the option is one
51528 * of the allowed values.
51529 *
51530 * __any__ means that the name of the property does not matter.
51531 * __type__ is a required field for all objects and contains the allowed types of all objects
51532 */
51533 var string = 'string';
51534 var bool = 'boolean';
51535 var number = 'number';
51536 var array = 'array';
51537 var object = 'object'; // should only be in a __type__ property
51538
51539 var dom = 'dom';
51540 var any = 'any'; // List of endpoints
51541
51542 var endPoints = ["arrow", "bar", "box", "circle", "crow", "curve", "diamond", "image", "inv_curve", "inv_triangle", "triangle", "vee"];
51543 var allOptions$1 = {
51544 configure: {
51545 enabled: {
51546 boolean: bool
51547 },
51548 filter: {
51549 boolean: bool,
51550 string: string,
51551 array: array,
51552 'function': 'function'
51553 },
51554 container: {
51555 dom: dom
51556 },
51557 showButton: {
51558 boolean: bool
51559 },
51560 __type__: {
51561 object: object,
51562 boolean: bool,
51563 string: string,
51564 array: array,
51565 'function': 'function'
51566 }
51567 },
51568 edges: {
51569 arrows: {
51570 to: {
51571 enabled: {
51572 boolean: bool
51573 },
51574 scaleFactor: {
51575 number: number
51576 },
51577 type: {
51578 string: endPoints
51579 },
51580 imageHeight: {
51581 number: number
51582 },
51583 imageWidth: {
51584 number: number
51585 },
51586 src: {
51587 string: string
51588 },
51589 __type__: {
51590 object: object,
51591 boolean: bool
51592 }
51593 },
51594 middle: {
51595 enabled: {
51596 boolean: bool
51597 },
51598 scaleFactor: {
51599 number: number
51600 },
51601 type: {
51602 string: endPoints
51603 },
51604 imageWidth: {
51605 number: number
51606 },
51607 imageHeight: {
51608 number: number
51609 },
51610 src: {
51611 string: string
51612 },
51613 __type__: {
51614 object: object,
51615 boolean: bool
51616 }
51617 },
51618 from: {
51619 enabled: {
51620 boolean: bool
51621 },
51622 scaleFactor: {
51623 number: number
51624 },
51625 type: {
51626 string: endPoints
51627 },
51628 imageWidth: {
51629 number: number
51630 },
51631 imageHeight: {
51632 number: number
51633 },
51634 src: {
51635 string: string
51636 },
51637 __type__: {
51638 object: object,
51639 boolean: bool
51640 }
51641 },
51642 __type__: {
51643 string: ["from", "to", "middle"],
51644 object: object
51645 }
51646 },
51647 arrowStrikethrough: {
51648 boolean: bool
51649 },
51650 background: {
51651 enabled: {
51652 boolean: bool
51653 },
51654 color: {
51655 string: string
51656 },
51657 size: {
51658 number: number
51659 },
51660 dashes: {
51661 boolean: bool,
51662 array: array
51663 },
51664 __type__: {
51665 object: object,
51666 boolean: bool
51667 }
51668 },
51669 chosen: {
51670 label: {
51671 boolean: bool,
51672 'function': 'function'
51673 },
51674 edge: {
51675 boolean: bool,
51676 'function': 'function'
51677 },
51678 __type__: {
51679 object: object,
51680 boolean: bool
51681 }
51682 },
51683 color: {
51684 color: {
51685 string: string
51686 },
51687 highlight: {
51688 string: string
51689 },
51690 hover: {
51691 string: string
51692 },
51693 inherit: {
51694 string: ['from', 'to', 'both'],
51695 boolean: bool
51696 },
51697 opacity: {
51698 number: number
51699 },
51700 __type__: {
51701 object: object,
51702 string: string
51703 }
51704 },
51705 dashes: {
51706 boolean: bool,
51707 array: array
51708 },
51709 font: {
51710 color: {
51711 string: string
51712 },
51713 size: {
51714 number: number
51715 },
51716 // px
51717 face: {
51718 string: string
51719 },
51720 background: {
51721 string: string
51722 },
51723 strokeWidth: {
51724 number: number
51725 },
51726 // px
51727 strokeColor: {
51728 string: string
51729 },
51730 align: {
51731 string: ['horizontal', 'top', 'middle', 'bottom']
51732 },
51733 vadjust: {
51734 number: number
51735 },
51736 multi: {
51737 boolean: bool,
51738 string: string
51739 },
51740 bold: {
51741 color: {
51742 string: string
51743 },
51744 size: {
51745 number: number
51746 },
51747 // px
51748 face: {
51749 string: string
51750 },
51751 mod: {
51752 string: string
51753 },
51754 vadjust: {
51755 number: number
51756 },
51757 __type__: {
51758 object: object,
51759 string: string
51760 }
51761 },
51762 boldital: {
51763 color: {
51764 string: string
51765 },
51766 size: {
51767 number: number
51768 },
51769 // px
51770 face: {
51771 string: string
51772 },
51773 mod: {
51774 string: string
51775 },
51776 vadjust: {
51777 number: number
51778 },
51779 __type__: {
51780 object: object,
51781 string: string
51782 }
51783 },
51784 ital: {
51785 color: {
51786 string: string
51787 },
51788 size: {
51789 number: number
51790 },
51791 // px
51792 face: {
51793 string: string
51794 },
51795 mod: {
51796 string: string
51797 },
51798 vadjust: {
51799 number: number
51800 },
51801 __type__: {
51802 object: object,
51803 string: string
51804 }
51805 },
51806 mono: {
51807 color: {
51808 string: string
51809 },
51810 size: {
51811 number: number
51812 },
51813 // px
51814 face: {
51815 string: string
51816 },
51817 mod: {
51818 string: string
51819 },
51820 vadjust: {
51821 number: number
51822 },
51823 __type__: {
51824 object: object,
51825 string: string
51826 }
51827 },
51828 __type__: {
51829 object: object,
51830 string: string
51831 }
51832 },
51833 hidden: {
51834 boolean: bool
51835 },
51836 hoverWidth: {
51837 'function': 'function',
51838 number: number
51839 },
51840 label: {
51841 string: string,
51842 'undefined': 'undefined'
51843 },
51844 labelHighlightBold: {
51845 boolean: bool
51846 },
51847 length: {
51848 number: number,
51849 'undefined': 'undefined'
51850 },
51851 physics: {
51852 boolean: bool
51853 },
51854 scaling: {
51855 min: {
51856 number: number
51857 },
51858 max: {
51859 number: number
51860 },
51861 label: {
51862 enabled: {
51863 boolean: bool
51864 },
51865 min: {
51866 number: number
51867 },
51868 max: {
51869 number: number
51870 },
51871 maxVisible: {
51872 number: number
51873 },
51874 drawThreshold: {
51875 number: number
51876 },
51877 __type__: {
51878 object: object,
51879 boolean: bool
51880 }
51881 },
51882 customScalingFunction: {
51883 'function': 'function'
51884 },
51885 __type__: {
51886 object: object
51887 }
51888 },
51889 selectionWidth: {
51890 'function': 'function',
51891 number: number
51892 },
51893 selfReferenceSize: {
51894 number: number
51895 },
51896 shadow: {
51897 enabled: {
51898 boolean: bool
51899 },
51900 color: {
51901 string: string
51902 },
51903 size: {
51904 number: number
51905 },
51906 x: {
51907 number: number
51908 },
51909 y: {
51910 number: number
51911 },
51912 __type__: {
51913 object: object,
51914 boolean: bool
51915 }
51916 },
51917 smooth: {
51918 enabled: {
51919 boolean: bool
51920 },
51921 type: {
51922 string: ['dynamic', 'continuous', 'discrete', 'diagonalCross', 'straightCross', 'horizontal', 'vertical', 'curvedCW', 'curvedCCW', 'cubicBezier']
51923 },
51924 roundness: {
51925 number: number
51926 },
51927 forceDirection: {
51928 string: ['horizontal', 'vertical', 'none'],
51929 boolean: bool
51930 },
51931 __type__: {
51932 object: object,
51933 boolean: bool
51934 }
51935 },
51936 title: {
51937 string: string,
51938 'undefined': 'undefined'
51939 },
51940 width: {
51941 number: number
51942 },
51943 widthConstraint: {
51944 maximum: {
51945 number: number
51946 },
51947 __type__: {
51948 object: object,
51949 boolean: bool,
51950 number: number
51951 }
51952 },
51953 value: {
51954 number: number,
51955 'undefined': 'undefined'
51956 },
51957 __type__: {
51958 object: object
51959 }
51960 },
51961 groups: {
51962 useDefaultGroups: {
51963 boolean: bool
51964 },
51965 __any__: 'get from nodes, will be overwritten below',
51966 __type__: {
51967 object: object
51968 }
51969 },
51970 interaction: {
51971 dragNodes: {
51972 boolean: bool
51973 },
51974 dragView: {
51975 boolean: bool
51976 },
51977 hideEdgesOnDrag: {
51978 boolean: bool
51979 },
51980 hideEdgesOnZoom: {
51981 boolean: bool
51982 },
51983 hideNodesOnDrag: {
51984 boolean: bool
51985 },
51986 hover: {
51987 boolean: bool
51988 },
51989 keyboard: {
51990 enabled: {
51991 boolean: bool
51992 },
51993 speed: {
51994 x: {
51995 number: number
51996 },
51997 y: {
51998 number: number
51999 },
52000 zoom: {
52001 number: number
52002 },
52003 __type__: {
52004 object: object
52005 }
52006 },
52007 bindToWindow: {
52008 boolean: bool
52009 },
52010 __type__: {
52011 object: object,
52012 boolean: bool
52013 }
52014 },
52015 multiselect: {
52016 boolean: bool
52017 },
52018 navigationButtons: {
52019 boolean: bool
52020 },
52021 selectable: {
52022 boolean: bool
52023 },
52024 selectConnectedEdges: {
52025 boolean: bool
52026 },
52027 hoverConnectedEdges: {
52028 boolean: bool
52029 },
52030 tooltipDelay: {
52031 number: number
52032 },
52033 zoomView: {
52034 boolean: bool
52035 },
52036 zoomSpeed: {
52037 number: number
52038 },
52039 __type__: {
52040 object: object
52041 }
52042 },
52043 layout: {
52044 randomSeed: {
52045 'undefined': 'undefined',
52046 number: number
52047 },
52048 improvedLayout: {
52049 boolean: bool
52050 },
52051 clusterThreshold: {
52052 number: number
52053 },
52054 hierarchical: {
52055 enabled: {
52056 boolean: bool
52057 },
52058 levelSeparation: {
52059 number: number
52060 },
52061 nodeSpacing: {
52062 number: number
52063 },
52064 treeSpacing: {
52065 number: number
52066 },
52067 blockShifting: {
52068 boolean: bool
52069 },
52070 edgeMinimization: {
52071 boolean: bool
52072 },
52073 parentCentralization: {
52074 boolean: bool
52075 },
52076 direction: {
52077 string: ['UD', 'DU', 'LR', 'RL']
52078 },
52079 // UD, DU, LR, RL
52080 sortMethod: {
52081 string: ['hubsize', 'directed']
52082 },
52083 // hubsize, directed
52084 shakeTowards: {
52085 string: ['leaves', 'roots']
52086 },
52087 // leaves, roots
52088 __type__: {
52089 object: object,
52090 boolean: bool
52091 }
52092 },
52093 __type__: {
52094 object: object
52095 }
52096 },
52097 manipulation: {
52098 enabled: {
52099 boolean: bool
52100 },
52101 initiallyActive: {
52102 boolean: bool
52103 },
52104 addNode: {
52105 boolean: bool,
52106 'function': 'function'
52107 },
52108 addEdge: {
52109 boolean: bool,
52110 'function': 'function'
52111 },
52112 editNode: {
52113 'function': 'function'
52114 },
52115 editEdge: {
52116 editWithoutDrag: {
52117 'function': 'function'
52118 },
52119 __type__: {
52120 object: object,
52121 boolean: bool,
52122 'function': 'function'
52123 }
52124 },
52125 deleteNode: {
52126 boolean: bool,
52127 'function': 'function'
52128 },
52129 deleteEdge: {
52130 boolean: bool,
52131 'function': 'function'
52132 },
52133 controlNodeStyle: 'get from nodes, will be overwritten below',
52134 __type__: {
52135 object: object,
52136 boolean: bool
52137 }
52138 },
52139 nodes: {
52140 borderWidth: {
52141 number: number
52142 },
52143 borderWidthSelected: {
52144 number: number,
52145 'undefined': 'undefined'
52146 },
52147 brokenImage: {
52148 string: string,
52149 'undefined': 'undefined'
52150 },
52151 chosen: {
52152 label: {
52153 boolean: bool,
52154 'function': 'function'
52155 },
52156 node: {
52157 boolean: bool,
52158 'function': 'function'
52159 },
52160 __type__: {
52161 object: object,
52162 boolean: bool
52163 }
52164 },
52165 color: {
52166 border: {
52167 string: string
52168 },
52169 background: {
52170 string: string
52171 },
52172 highlight: {
52173 border: {
52174 string: string
52175 },
52176 background: {
52177 string: string
52178 },
52179 __type__: {
52180 object: object,
52181 string: string
52182 }
52183 },
52184 hover: {
52185 border: {
52186 string: string
52187 },
52188 background: {
52189 string: string
52190 },
52191 __type__: {
52192 object: object,
52193 string: string
52194 }
52195 },
52196 __type__: {
52197 object: object,
52198 string: string
52199 }
52200 },
52201 fixed: {
52202 x: {
52203 boolean: bool
52204 },
52205 y: {
52206 boolean: bool
52207 },
52208 __type__: {
52209 object: object,
52210 boolean: bool
52211 }
52212 },
52213 font: {
52214 align: {
52215 string: string
52216 },
52217 color: {
52218 string: string
52219 },
52220 size: {
52221 number: number
52222 },
52223 // px
52224 face: {
52225 string: string
52226 },
52227 background: {
52228 string: string
52229 },
52230 strokeWidth: {
52231 number: number
52232 },
52233 // px
52234 strokeColor: {
52235 string: string
52236 },
52237 vadjust: {
52238 number: number
52239 },
52240 multi: {
52241 boolean: bool,
52242 string: string
52243 },
52244 bold: {
52245 color: {
52246 string: string
52247 },
52248 size: {
52249 number: number
52250 },
52251 // px
52252 face: {
52253 string: string
52254 },
52255 mod: {
52256 string: string
52257 },
52258 vadjust: {
52259 number: number
52260 },
52261 __type__: {
52262 object: object,
52263 string: string
52264 }
52265 },
52266 boldital: {
52267 color: {
52268 string: string
52269 },
52270 size: {
52271 number: number
52272 },
52273 // px
52274 face: {
52275 string: string
52276 },
52277 mod: {
52278 string: string
52279 },
52280 vadjust: {
52281 number: number
52282 },
52283 __type__: {
52284 object: object,
52285 string: string
52286 }
52287 },
52288 ital: {
52289 color: {
52290 string: string
52291 },
52292 size: {
52293 number: number
52294 },
52295 // px
52296 face: {
52297 string: string
52298 },
52299 mod: {
52300 string: string
52301 },
52302 vadjust: {
52303 number: number
52304 },
52305 __type__: {
52306 object: object,
52307 string: string
52308 }
52309 },
52310 mono: {
52311 color: {
52312 string: string
52313 },
52314 size: {
52315 number: number
52316 },
52317 // px
52318 face: {
52319 string: string
52320 },
52321 mod: {
52322 string: string
52323 },
52324 vadjust: {
52325 number: number
52326 },
52327 __type__: {
52328 object: object,
52329 string: string
52330 }
52331 },
52332 __type__: {
52333 object: object,
52334 string: string
52335 }
52336 },
52337 group: {
52338 string: string,
52339 number: number,
52340 'undefined': 'undefined'
52341 },
52342 heightConstraint: {
52343 minimum: {
52344 number: number
52345 },
52346 valign: {
52347 string: string
52348 },
52349 __type__: {
52350 object: object,
52351 boolean: bool,
52352 number: number
52353 }
52354 },
52355 hidden: {
52356 boolean: bool
52357 },
52358 icon: {
52359 face: {
52360 string: string
52361 },
52362 code: {
52363 string: string
52364 },
52365 //'\uf007',
52366 size: {
52367 number: number
52368 },
52369 //50,
52370 color: {
52371 string: string
52372 },
52373 weight: {
52374 string: string,
52375 number: number
52376 },
52377 __type__: {
52378 object: object
52379 }
52380 },
52381 id: {
52382 string: string,
52383 number: number
52384 },
52385 image: {
52386 selected: {
52387 string: string,
52388 'undefined': 'undefined'
52389 },
52390 // --> URL
52391 unselected: {
52392 string: string,
52393 'undefined': 'undefined'
52394 },
52395 // --> URL
52396 __type__: {
52397 object: object,
52398 string: string
52399 }
52400 },
52401 imagePadding: {
52402 top: {
52403 number: number
52404 },
52405 right: {
52406 number: number
52407 },
52408 bottom: {
52409 number: number
52410 },
52411 left: {
52412 number: number
52413 },
52414 __type__: {
52415 object: object,
52416 number: number
52417 }
52418 },
52419 label: {
52420 string: string,
52421 'undefined': 'undefined'
52422 },
52423 labelHighlightBold: {
52424 boolean: bool
52425 },
52426 level: {
52427 number: number,
52428 'undefined': 'undefined'
52429 },
52430 margin: {
52431 top: {
52432 number: number
52433 },
52434 right: {
52435 number: number
52436 },
52437 bottom: {
52438 number: number
52439 },
52440 left: {
52441 number: number
52442 },
52443 __type__: {
52444 object: object,
52445 number: number
52446 }
52447 },
52448 mass: {
52449 number: number
52450 },
52451 physics: {
52452 boolean: bool
52453 },
52454 scaling: {
52455 min: {
52456 number: number
52457 },
52458 max: {
52459 number: number
52460 },
52461 label: {
52462 enabled: {
52463 boolean: bool
52464 },
52465 min: {
52466 number: number
52467 },
52468 max: {
52469 number: number
52470 },
52471 maxVisible: {
52472 number: number
52473 },
52474 drawThreshold: {
52475 number: number
52476 },
52477 __type__: {
52478 object: object,
52479 boolean: bool
52480 }
52481 },
52482 customScalingFunction: {
52483 'function': 'function'
52484 },
52485 __type__: {
52486 object: object
52487 }
52488 },
52489 shadow: {
52490 enabled: {
52491 boolean: bool
52492 },
52493 color: {
52494 string: string
52495 },
52496 size: {
52497 number: number
52498 },
52499 x: {
52500 number: number
52501 },
52502 y: {
52503 number: number
52504 },
52505 __type__: {
52506 object: object,
52507 boolean: bool
52508 }
52509 },
52510 shape: {
52511 string: ['ellipse', 'circle', 'database', 'box', 'text', 'image', 'circularImage', 'diamond', 'dot', 'star', 'triangle', 'triangleDown', 'square', 'icon', 'hexagon']
52512 },
52513 shapeProperties: {
52514 borderDashes: {
52515 boolean: bool,
52516 array: array
52517 },
52518 borderRadius: {
52519 number: number
52520 },
52521 interpolation: {
52522 boolean: bool
52523 },
52524 useImageSize: {
52525 boolean: bool
52526 },
52527 useBorderWithImage: {
52528 boolean: bool
52529 },
52530 __type__: {
52531 object: object
52532 }
52533 },
52534 size: {
52535 number: number
52536 },
52537 title: {
52538 string: string,
52539 dom: dom,
52540 'undefined': 'undefined'
52541 },
52542 value: {
52543 number: number,
52544 'undefined': 'undefined'
52545 },
52546 widthConstraint: {
52547 minimum: {
52548 number: number
52549 },
52550 maximum: {
52551 number: number
52552 },
52553 __type__: {
52554 object: object,
52555 boolean: bool,
52556 number: number
52557 }
52558 },
52559 x: {
52560 number: number
52561 },
52562 y: {
52563 number: number
52564 },
52565 __type__: {
52566 object: object
52567 }
52568 },
52569 physics: {
52570 enabled: {
52571 boolean: bool
52572 },
52573 barnesHut: {
52574 gravitationalConstant: {
52575 number: number
52576 },
52577 centralGravity: {
52578 number: number
52579 },
52580 springLength: {
52581 number: number
52582 },
52583 springConstant: {
52584 number: number
52585 },
52586 damping: {
52587 number: number
52588 },
52589 avoidOverlap: {
52590 number: number
52591 },
52592 __type__: {
52593 object: object
52594 }
52595 },
52596 forceAtlas2Based: {
52597 gravitationalConstant: {
52598 number: number
52599 },
52600 centralGravity: {
52601 number: number
52602 },
52603 springLength: {
52604 number: number
52605 },
52606 springConstant: {
52607 number: number
52608 },
52609 damping: {
52610 number: number
52611 },
52612 avoidOverlap: {
52613 number: number
52614 },
52615 __type__: {
52616 object: object
52617 }
52618 },
52619 repulsion: {
52620 centralGravity: {
52621 number: number
52622 },
52623 springLength: {
52624 number: number
52625 },
52626 springConstant: {
52627 number: number
52628 },
52629 nodeDistance: {
52630 number: number
52631 },
52632 damping: {
52633 number: number
52634 },
52635 __type__: {
52636 object: object
52637 }
52638 },
52639 hierarchicalRepulsion: {
52640 centralGravity: {
52641 number: number
52642 },
52643 springLength: {
52644 number: number
52645 },
52646 springConstant: {
52647 number: number
52648 },
52649 nodeDistance: {
52650 number: number
52651 },
52652 damping: {
52653 number: number
52654 },
52655 avoidOverlap: {
52656 number: number
52657 },
52658 __type__: {
52659 object: object
52660 }
52661 },
52662 maxVelocity: {
52663 number: number
52664 },
52665 minVelocity: {
52666 number: number
52667 },
52668 // px/s
52669 solver: {
52670 string: ['barnesHut', 'repulsion', 'hierarchicalRepulsion', 'forceAtlas2Based']
52671 },
52672 stabilization: {
52673 enabled: {
52674 boolean: bool
52675 },
52676 iterations: {
52677 number: number
52678 },
52679 // maximum number of iteration to stabilize
52680 updateInterval: {
52681 number: number
52682 },
52683 onlyDynamicEdges: {
52684 boolean: bool
52685 },
52686 fit: {
52687 boolean: bool
52688 },
52689 __type__: {
52690 object: object,
52691 boolean: bool
52692 }
52693 },
52694 timestep: {
52695 number: number
52696 },
52697 adaptiveTimestep: {
52698 boolean: bool
52699 },
52700 __type__: {
52701 object: object,
52702 boolean: bool
52703 }
52704 },
52705 //globals :
52706 autoResize: {
52707 boolean: bool
52708 },
52709 clickToUse: {
52710 boolean: bool
52711 },
52712 locale: {
52713 string: string
52714 },
52715 locales: {
52716 __any__: {
52717 any: any
52718 },
52719 __type__: {
52720 object: object
52721 }
52722 },
52723 height: {
52724 string: string
52725 },
52726 width: {
52727 string: string
52728 },
52729 __type__: {
52730 object: object
52731 }
52732 };
52733 allOptions$1.groups.__any__ = allOptions$1.nodes;
52734 allOptions$1.manipulation.controlNodeStyle = allOptions$1.nodes;
52735 var configureOptions = {
52736 nodes: {
52737 borderWidth: [1, 0, 10, 1],
52738 borderWidthSelected: [2, 0, 10, 1],
52739 color: {
52740 border: ['color', '#2B7CE9'],
52741 background: ['color', '#97C2FC'],
52742 highlight: {
52743 border: ['color', '#2B7CE9'],
52744 background: ['color', '#D2E5FF']
52745 },
52746 hover: {
52747 border: ['color', '#2B7CE9'],
52748 background: ['color', '#D2E5FF']
52749 }
52750 },
52751 fixed: {
52752 x: false,
52753 y: false
52754 },
52755 font: {
52756 color: ['color', '#343434'],
52757 size: [14, 0, 100, 1],
52758 // px
52759 face: ['arial', 'verdana', 'tahoma'],
52760 background: ['color', 'none'],
52761 strokeWidth: [0, 0, 50, 1],
52762 // px
52763 strokeColor: ['color', '#ffffff']
52764 },
52765 //group: 'string',
52766 hidden: false,
52767 labelHighlightBold: true,
52768 //icon: {
52769 // face: 'string', //'FontAwesome',
52770 // code: 'string', //'\uf007',
52771 // size: [50, 0, 200, 1], //50,
52772 // color: ['color','#2B7CE9'] //'#aa00ff'
52773 //},
52774 //image: 'string', // --> URL
52775 physics: true,
52776 scaling: {
52777 min: [10, 0, 200, 1],
52778 max: [30, 0, 200, 1],
52779 label: {
52780 enabled: false,
52781 min: [14, 0, 200, 1],
52782 max: [30, 0, 200, 1],
52783 maxVisible: [30, 0, 200, 1],
52784 drawThreshold: [5, 0, 20, 1]
52785 }
52786 },
52787 shadow: {
52788 enabled: false,
52789 color: 'rgba(0,0,0,0.5)',
52790 size: [10, 0, 20, 1],
52791 x: [5, -30, 30, 1],
52792 y: [5, -30, 30, 1]
52793 },
52794 shape: ['ellipse', 'box', 'circle', 'database', 'diamond', 'dot', 'square', 'star', 'text', 'triangle', 'triangleDown', 'hexagon'],
52795 shapeProperties: {
52796 borderDashes: false,
52797 borderRadius: [6, 0, 20, 1],
52798 interpolation: true,
52799 useImageSize: false
52800 },
52801 size: [25, 0, 200, 1]
52802 },
52803 edges: {
52804 arrows: {
52805 to: {
52806 enabled: false,
52807 scaleFactor: [1, 0, 3, 0.05],
52808 type: 'arrow'
52809 },
52810 middle: {
52811 enabled: false,
52812 scaleFactor: [1, 0, 3, 0.05],
52813 type: 'arrow'
52814 },
52815 from: {
52816 enabled: false,
52817 scaleFactor: [1, 0, 3, 0.05],
52818 type: 'arrow'
52819 }
52820 },
52821 arrowStrikethrough: true,
52822 color: {
52823 color: ['color', '#848484'],
52824 highlight: ['color', '#848484'],
52825 hover: ['color', '#848484'],
52826 inherit: ['from', 'to', 'both', true, false],
52827 opacity: [1, 0, 1, 0.05]
52828 },
52829 dashes: false,
52830 font: {
52831 color: ['color', '#343434'],
52832 size: [14, 0, 100, 1],
52833 // px
52834 face: ['arial', 'verdana', 'tahoma'],
52835 background: ['color', 'none'],
52836 strokeWidth: [2, 0, 50, 1],
52837 // px
52838 strokeColor: ['color', '#ffffff'],
52839 align: ['horizontal', 'top', 'middle', 'bottom']
52840 },
52841 hidden: false,
52842 hoverWidth: [1.5, 0, 5, 0.1],
52843 labelHighlightBold: true,
52844 physics: true,
52845 scaling: {
52846 min: [1, 0, 100, 1],
52847 max: [15, 0, 100, 1],
52848 label: {
52849 enabled: true,
52850 min: [14, 0, 200, 1],
52851 max: [30, 0, 200, 1],
52852 maxVisible: [30, 0, 200, 1],
52853 drawThreshold: [5, 0, 20, 1]
52854 }
52855 },
52856 selectionWidth: [1.5, 0, 5, 0.1],
52857 selfReferenceSize: [20, 0, 200, 1],
52858 shadow: {
52859 enabled: false,
52860 color: 'rgba(0,0,0,0.5)',
52861 size: [10, 0, 20, 1],
52862 x: [5, -30, 30, 1],
52863 y: [5, -30, 30, 1]
52864 },
52865 smooth: {
52866 enabled: true,
52867 type: ['dynamic', 'continuous', 'discrete', 'diagonalCross', 'straightCross', 'horizontal', 'vertical', 'curvedCW', 'curvedCCW', 'cubicBezier'],
52868 forceDirection: ['horizontal', 'vertical', 'none'],
52869 roundness: [0.5, 0, 1, 0.05]
52870 },
52871 width: [1, 0, 30, 1]
52872 },
52873 layout: {
52874 //randomSeed: [0, 0, 500, 1],
52875 //improvedLayout: true,
52876 hierarchical: {
52877 enabled: false,
52878 levelSeparation: [150, 20, 500, 5],
52879 nodeSpacing: [100, 20, 500, 5],
52880 treeSpacing: [200, 20, 500, 5],
52881 blockShifting: true,
52882 edgeMinimization: true,
52883 parentCentralization: true,
52884 direction: ['UD', 'DU', 'LR', 'RL'],
52885 // UD, DU, LR, RL
52886 sortMethod: ['hubsize', 'directed'],
52887 // hubsize, directed
52888 shakeTowards: ['leaves', 'roots'] // leaves, roots
52889
52890 }
52891 },
52892 interaction: {
52893 dragNodes: true,
52894 dragView: true,
52895 hideEdgesOnDrag: false,
52896 hideEdgesOnZoom: false,
52897 hideNodesOnDrag: false,
52898 hover: false,
52899 keyboard: {
52900 enabled: false,
52901 speed: {
52902 x: [10, 0, 40, 1],
52903 y: [10, 0, 40, 1],
52904 zoom: [0.02, 0, 0.1, 0.005]
52905 },
52906 bindToWindow: true
52907 },
52908 multiselect: false,
52909 navigationButtons: false,
52910 selectable: true,
52911 selectConnectedEdges: true,
52912 hoverConnectedEdges: true,
52913 tooltipDelay: [300, 0, 1000, 25],
52914 zoomView: true,
52915 zoomSpeed: [1, 1, 1, 1]
52916 },
52917 manipulation: {
52918 enabled: false,
52919 initiallyActive: false
52920 },
52921 physics: {
52922 enabled: true,
52923 barnesHut: {
52924 //theta: [0.5, 0.1, 1, 0.05],
52925 gravitationalConstant: [-2000, -30000, 0, 50],
52926 centralGravity: [0.3, 0, 10, 0.05],
52927 springLength: [95, 0, 500, 5],
52928 springConstant: [0.04, 0, 1.2, 0.005],
52929 damping: [0.09, 0, 1, 0.01],
52930 avoidOverlap: [0, 0, 1, 0.01]
52931 },
52932 forceAtlas2Based: {
52933 //theta: [0.5, 0.1, 1, 0.05],
52934 gravitationalConstant: [-50, -500, 0, 1],
52935 centralGravity: [0.01, 0, 1, 0.005],
52936 springLength: [95, 0, 500, 5],
52937 springConstant: [0.08, 0, 1.2, 0.005],
52938 damping: [0.4, 0, 1, 0.01],
52939 avoidOverlap: [0, 0, 1, 0.01]
52940 },
52941 repulsion: {
52942 centralGravity: [0.2, 0, 10, 0.05],
52943 springLength: [200, 0, 500, 5],
52944 springConstant: [0.05, 0, 1.2, 0.005],
52945 nodeDistance: [100, 0, 500, 5],
52946 damping: [0.09, 0, 1, 0.01]
52947 },
52948 hierarchicalRepulsion: {
52949 centralGravity: [0.2, 0, 10, 0.05],
52950 springLength: [100, 0, 500, 5],
52951 springConstant: [0.01, 0, 1.2, 0.005],
52952 nodeDistance: [120, 0, 500, 5],
52953 damping: [0.09, 0, 1, 0.01],
52954 avoidOverlap: [0, 0, 1, 0.01]
52955 },
52956 maxVelocity: [50, 0, 150, 1],
52957 minVelocity: [0.1, 0.01, 0.5, 0.01],
52958 solver: ['barnesHut', 'forceAtlas2Based', 'repulsion', 'hierarchicalRepulsion'],
52959 timestep: [0.5, 0.01, 1, 0.01] //adaptiveTimestep: true
52960
52961 }
52962 };
52963
52964 var allOptions$2 = /*#__PURE__*/Object.freeze({
52965 __proto__: null,
52966 allOptions: allOptions$1,
52967 configureOptions: configureOptions
52968 });
52969
52970 /**
52971 * The Floyd–Warshall algorithm is an algorithm for finding shortest paths in
52972 * a weighted graph with positive or negative edge weights (but with no negative
52973 * cycles). - https://en.wikipedia.org/wiki/Floyd–Warshall_algorithm
52974 */
52975 var FloydWarshall =
52976 /*#__PURE__*/
52977 function () {
52978 /**
52979 * @ignore
52980 */
52981 function FloydWarshall() {
52982 _classCallCheck(this, FloydWarshall);
52983 }
52984 /**
52985 *
52986 * @param {Object} body
52987 * @param {Array.<Node>} nodesArray
52988 * @param {Array.<Edge>} edgesArray
52989 * @returns {{}}
52990 */
52991
52992
52993 _createClass(FloydWarshall, [{
52994 key: "getDistances",
52995 value: function getDistances(body, nodesArray, edgesArray) {
52996 var D_matrix = {};
52997 var edges = body.edges; // prepare matrix with large numbers
52998
52999 for (var i = 0; i < nodesArray.length; i++) {
53000 var node = nodesArray[i];
53001 var cell = {};
53002 D_matrix[node] = cell;
53003
53004 for (var j = 0; j < nodesArray.length; j++) {
53005 cell[nodesArray[j]] = i == j ? 0 : 1e9;
53006 }
53007 } // put the weights for the edges in. This assumes unidirectionality.
53008
53009
53010 for (var _i = 0; _i < edgesArray.length; _i++) {
53011 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
53012
53013 if (edge.connected === true && D_matrix[edge.fromId] !== undefined && D_matrix[edge.toId] !== undefined) {
53014 D_matrix[edge.fromId][edge.toId] = 1;
53015 D_matrix[edge.toId][edge.fromId] = 1;
53016 }
53017 }
53018
53019 var nodeCount = nodesArray.length; // Adapted FloydWarshall based on unidirectionality to greatly reduce complexity.
53020
53021 for (var k = 0; k < nodeCount; k++) {
53022 var knode = nodesArray[k];
53023 var kcolm = D_matrix[knode];
53024
53025 for (var _i2 = 0; _i2 < nodeCount - 1; _i2++) {
53026 var inode = nodesArray[_i2];
53027 var icolm = D_matrix[inode];
53028
53029 for (var _j = _i2 + 1; _j < nodeCount; _j++) {
53030 var jnode = nodesArray[_j];
53031 var jcolm = D_matrix[jnode];
53032 var val = Math.min(icolm[jnode], icolm[knode] + kcolm[jnode]);
53033 icolm[jnode] = val;
53034 jcolm[inode] = val;
53035 }
53036 }
53037 }
53038
53039 return D_matrix;
53040 }
53041 }]);
53042
53043 return FloydWarshall;
53044 }();
53045
53046 /**
53047 * KamadaKawai positions the nodes initially based on
53048 *
53049 * "AN ALGORITHM FOR DRAWING GENERAL UNDIRECTED GRAPHS"
53050 * -- Tomihisa KAMADA and Satoru KAWAI in 1989
53051 *
53052 * Possible optimizations in the distance calculation can be implemented.
53053 */
53054
53055 var KamadaKawai =
53056 /*#__PURE__*/
53057 function () {
53058 /**
53059 * @param {Object} body
53060 * @param {number} edgeLength
53061 * @param {number} edgeStrength
53062 */
53063 function KamadaKawai(body, edgeLength, edgeStrength) {
53064 _classCallCheck(this, KamadaKawai);
53065
53066 this.body = body;
53067 this.springLength = edgeLength;
53068 this.springConstant = edgeStrength;
53069 this.distanceSolver = new FloydWarshall();
53070 }
53071 /**
53072 * Not sure if needed but can be used to update the spring length and spring constant
53073 * @param {Object} options
53074 */
53075
53076
53077 _createClass(KamadaKawai, [{
53078 key: "setOptions",
53079 value: function setOptions(options) {
53080 if (options) {
53081 if (options.springLength) {
53082 this.springLength = options.springLength;
53083 }
53084
53085 if (options.springConstant) {
53086 this.springConstant = options.springConstant;
53087 }
53088 }
53089 }
53090 /**
53091 * Position the system
53092 * @param {Array.<Node>} nodesArray
53093 * @param {Array.<vis.Edge>} edgesArray
53094 * @param {boolean} [ignoreClusters=false]
53095 */
53096
53097 }, {
53098 key: "solve",
53099 value: function solve(nodesArray, edgesArray) {
53100 var ignoreClusters = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
53101 // get distance matrix
53102 var D_matrix = this.distanceSolver.getDistances(this.body, nodesArray, edgesArray); // distance matrix
53103 // get the L Matrix
53104
53105 this._createL_matrix(D_matrix); // get the K Matrix
53106
53107
53108 this._createK_matrix(D_matrix); // initial E Matrix
53109
53110
53111 this._createE_matrix(); // calculate positions
53112
53113
53114 var threshold = 0.01;
53115 var innerThreshold = 1;
53116 var iterations = 0;
53117 var maxIterations = Math.max(1000, Math.min(10 * this.body.nodeIndices.length, 6000));
53118 var maxInnerIterations = 5;
53119 var maxEnergy = 1e9;
53120 var highE_nodeId = 0,
53121 dE_dx = 0,
53122 dE_dy = 0,
53123 delta_m = 0,
53124 subIterations = 0;
53125
53126 while (maxEnergy > threshold && iterations < maxIterations) {
53127 iterations += 1;
53128
53129 var _this$_getHighestEner = this._getHighestEnergyNode(ignoreClusters);
53130
53131 var _this$_getHighestEner2 = _slicedToArray(_this$_getHighestEner, 4);
53132
53133 highE_nodeId = _this$_getHighestEner2[0];
53134 maxEnergy = _this$_getHighestEner2[1];
53135 dE_dx = _this$_getHighestEner2[2];
53136 dE_dy = _this$_getHighestEner2[3];
53137 delta_m = maxEnergy;
53138 subIterations = 0;
53139
53140 while (delta_m > innerThreshold && subIterations < maxInnerIterations) {
53141 subIterations += 1;
53142
53143 this._moveNode(highE_nodeId, dE_dx, dE_dy);
53144
53145 var _this$_getEnergy = this._getEnergy(highE_nodeId);
53146
53147 var _this$_getEnergy2 = _slicedToArray(_this$_getEnergy, 3);
53148
53149 delta_m = _this$_getEnergy2[0];
53150 dE_dx = _this$_getEnergy2[1];
53151 dE_dy = _this$_getEnergy2[2];
53152 }
53153 }
53154 }
53155 /**
53156 * get the node with the highest energy
53157 * @param {boolean} ignoreClusters
53158 * @returns {number[]}
53159 * @private
53160 */
53161
53162 }, {
53163 key: "_getHighestEnergyNode",
53164 value: function _getHighestEnergyNode(ignoreClusters) {
53165 var nodesArray = this.body.nodeIndices;
53166 var nodes = this.body.nodes;
53167 var maxEnergy = 0;
53168 var maxEnergyNodeId = nodesArray[0];
53169 var dE_dx_max = 0,
53170 dE_dy_max = 0;
53171
53172 for (var nodeIdx = 0; nodeIdx < nodesArray.length; nodeIdx++) {
53173 var m = nodesArray[nodeIdx]; // by not evaluating nodes with predefined positions we should only move nodes that have no positions.
53174
53175 if (nodes[m].predefinedPosition === false || nodes[m].isCluster === true && ignoreClusters === true || nodes[m].options.fixed.x === true || nodes[m].options.fixed.y === true) {
53176 var _this$_getEnergy3 = this._getEnergy(m),
53177 _this$_getEnergy4 = _slicedToArray(_this$_getEnergy3, 3),
53178 delta_m = _this$_getEnergy4[0],
53179 dE_dx = _this$_getEnergy4[1],
53180 dE_dy = _this$_getEnergy4[2];
53181
53182 if (maxEnergy < delta_m) {
53183 maxEnergy = delta_m;
53184 maxEnergyNodeId = m;
53185 dE_dx_max = dE_dx;
53186 dE_dy_max = dE_dy;
53187 }
53188 }
53189 }
53190
53191 return [maxEnergyNodeId, maxEnergy, dE_dx_max, dE_dy_max];
53192 }
53193 /**
53194 * calculate the energy of a single node
53195 * @param {Node.id} m
53196 * @returns {number[]}
53197 * @private
53198 */
53199
53200 }, {
53201 key: "_getEnergy",
53202 value: function _getEnergy(m) {
53203 var _this$E_sums$m = _slicedToArray(this.E_sums[m], 2),
53204 dE_dx = _this$E_sums$m[0],
53205 dE_dy = _this$E_sums$m[1];
53206
53207 var delta_m = Math.sqrt(Math.pow(dE_dx, 2) + Math.pow(dE_dy, 2));
53208 return [delta_m, dE_dx, dE_dy];
53209 }
53210 /**
53211 * move the node based on it's energy
53212 * the dx and dy are calculated from the linear system proposed by Kamada and Kawai
53213 * @param {number} m
53214 * @param {number} dE_dx
53215 * @param {number} dE_dy
53216 * @private
53217 */
53218
53219 }, {
53220 key: "_moveNode",
53221 value: function _moveNode(m, dE_dx, dE_dy) {
53222 var nodesArray = this.body.nodeIndices;
53223 var nodes = this.body.nodes;
53224 var d2E_dx2 = 0;
53225 var d2E_dxdy = 0;
53226 var d2E_dy2 = 0;
53227 var x_m = nodes[m].x;
53228 var y_m = nodes[m].y;
53229 var km = this.K_matrix[m];
53230 var lm = this.L_matrix[m];
53231
53232 for (var iIdx = 0; iIdx < nodesArray.length; iIdx++) {
53233 var i = nodesArray[iIdx];
53234
53235 if (i !== m) {
53236 var x_i = nodes[i].x;
53237 var y_i = nodes[i].y;
53238 var kmat = km[i];
53239 var lmat = lm[i];
53240 var denominator = 1.0 / Math.pow(Math.pow(x_m - x_i, 2) + Math.pow(y_m - y_i, 2), 1.5);
53241 d2E_dx2 += kmat * (1 - lmat * Math.pow(y_m - y_i, 2) * denominator);
53242 d2E_dxdy += kmat * (lmat * (x_m - x_i) * (y_m - y_i) * denominator);
53243 d2E_dy2 += kmat * (1 - lmat * Math.pow(x_m - x_i, 2) * denominator);
53244 }
53245 } // make the variable names easier to make the solving of the linear system easier to read
53246
53247
53248 var A = d2E_dx2,
53249 B = d2E_dxdy,
53250 C = dE_dx,
53251 D = d2E_dy2,
53252 E = dE_dy; // solve the linear system for dx and dy
53253
53254 var dy = (C / A + E / B) / (B / A - D / B);
53255 var dx = -(B * dy + C) / A; // move the node
53256
53257 nodes[m].x += dx;
53258 nodes[m].y += dy; // Recalculate E_matrix (should be incremental)
53259
53260 this._updateE_matrix(m);
53261 }
53262 /**
53263 * Create the L matrix: edge length times shortest path
53264 * @param {Object} D_matrix
53265 * @private
53266 */
53267
53268 }, {
53269 key: "_createL_matrix",
53270 value: function _createL_matrix(D_matrix) {
53271 var nodesArray = this.body.nodeIndices;
53272 var edgeLength = this.springLength;
53273 this.L_matrix = [];
53274
53275 for (var i = 0; i < nodesArray.length; i++) {
53276 this.L_matrix[nodesArray[i]] = {};
53277
53278 for (var j = 0; j < nodesArray.length; j++) {
53279 this.L_matrix[nodesArray[i]][nodesArray[j]] = edgeLength * D_matrix[nodesArray[i]][nodesArray[j]];
53280 }
53281 }
53282 }
53283 /**
53284 * Create the K matrix: spring constants times shortest path
53285 * @param {Object} D_matrix
53286 * @private
53287 */
53288
53289 }, {
53290 key: "_createK_matrix",
53291 value: function _createK_matrix(D_matrix) {
53292 var nodesArray = this.body.nodeIndices;
53293 var edgeStrength = this.springConstant;
53294 this.K_matrix = [];
53295
53296 for (var i = 0; i < nodesArray.length; i++) {
53297 this.K_matrix[nodesArray[i]] = {};
53298
53299 for (var j = 0; j < nodesArray.length; j++) {
53300 this.K_matrix[nodesArray[i]][nodesArray[j]] = edgeStrength * Math.pow(D_matrix[nodesArray[i]][nodesArray[j]], -2);
53301 }
53302 }
53303 }
53304 /**
53305 * Create matrix with all energies between nodes
53306 * @private
53307 */
53308
53309 }, {
53310 key: "_createE_matrix",
53311 value: function _createE_matrix() {
53312 var nodesArray = this.body.nodeIndices;
53313 var nodes = this.body.nodes;
53314 this.E_matrix = {};
53315 this.E_sums = {};
53316
53317 for (var mIdx = 0; mIdx < nodesArray.length; mIdx++) {
53318 this.E_matrix[nodesArray[mIdx]] = [];
53319 }
53320
53321 for (var _mIdx = 0; _mIdx < nodesArray.length; _mIdx++) {
53322 var m = nodesArray[_mIdx];
53323 var x_m = nodes[m].x;
53324 var y_m = nodes[m].y;
53325 var dE_dx = 0;
53326 var dE_dy = 0;
53327
53328 for (var iIdx = _mIdx; iIdx < nodesArray.length; iIdx++) {
53329 var i = nodesArray[iIdx];
53330
53331 if (i !== m) {
53332 var x_i = nodes[i].x;
53333 var y_i = nodes[i].y;
53334 var denominator = 1.0 / Math.sqrt(Math.pow(x_m - x_i, 2) + Math.pow(y_m - y_i, 2));
53335 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)];
53336 this.E_matrix[i][_mIdx] = this.E_matrix[m][iIdx];
53337 dE_dx += this.E_matrix[m][iIdx][0];
53338 dE_dy += this.E_matrix[m][iIdx][1];
53339 }
53340 } //Store sum
53341
53342
53343 this.E_sums[m] = [dE_dx, dE_dy];
53344 }
53345 }
53346 /**
53347 * Update method, just doing single column (rows are auto-updated) (update all sums)
53348 *
53349 * @param {number} m
53350 * @private
53351 */
53352
53353 }, {
53354 key: "_updateE_matrix",
53355 value: function _updateE_matrix(m) {
53356 var nodesArray = this.body.nodeIndices;
53357 var nodes = this.body.nodes;
53358 var colm = this.E_matrix[m];
53359 var kcolm = this.K_matrix[m];
53360 var lcolm = this.L_matrix[m];
53361 var x_m = nodes[m].x;
53362 var y_m = nodes[m].y;
53363 var dE_dx = 0;
53364 var dE_dy = 0;
53365
53366 for (var iIdx = 0; iIdx < nodesArray.length; iIdx++) {
53367 var i = nodesArray[iIdx];
53368
53369 if (i !== m) {
53370 //Keep old energy value for sum modification below
53371 var cell = colm[iIdx];
53372 var oldDx = cell[0];
53373 var oldDy = cell[1]; //Calc new energy:
53374
53375 var x_i = nodes[i].x;
53376 var y_i = nodes[i].y;
53377 var denominator = 1.0 / Math.sqrt(Math.pow(x_m - x_i, 2) + Math.pow(y_m - y_i, 2));
53378 var dx = kcolm[i] * (x_m - x_i - lcolm[i] * (x_m - x_i) * denominator);
53379 var dy = kcolm[i] * (y_m - y_i - lcolm[i] * (y_m - y_i) * denominator);
53380 colm[iIdx] = [dx, dy];
53381 dE_dx += dx;
53382 dE_dy += dy; //add new energy to sum of each column
53383
53384 var sum = this.E_sums[i];
53385 sum[0] += dx - oldDx;
53386 sum[1] += dy - oldDy;
53387 }
53388 } //Store sum at -1 index
53389
53390
53391 this.E_sums[m] = [dE_dx, dE_dy];
53392 }
53393 }]);
53394
53395 return KamadaKawai;
53396 }();
53397
53398 // Load custom shapes into CanvasRenderingContext2D
53399 /**
53400 * Create a network visualization, displaying nodes and edges.
53401 *
53402 * @param {Element} container The DOM element in which the Network will
53403 * be created. Normally a div element.
53404 * @param {Object} data An object containing parameters
53405 * {Array} nodes
53406 * {Array} edges
53407 * @param {Object} options Options
53408 * @constructor Network
53409 */
53410
53411 function Network(container, data, options) {
53412 var _this = this;
53413
53414 if (!(this instanceof Network)) {
53415 throw new SyntaxError('Constructor must be called with the new operator');
53416 } // set constant values
53417
53418
53419 this.options = {};
53420 this.defaultOptions = {
53421 locale: 'en',
53422 locales: locales,
53423 clickToUse: false
53424 };
53425 extend(this.options, this.defaultOptions);
53426 /**
53427 * Containers for nodes and edges.
53428 *
53429 * 'edges' and 'nodes' contain the full definitions of all the network elements.
53430 * 'nodeIndices' and 'edgeIndices' contain the id's of the active elements.
53431 *
53432 * The distinction is important, because a defined node need not be active, i.e.
53433 * visible on the canvas. This happens in particular when clusters are defined, in
53434 * that case there will be nodes and edges not displayed.
53435 * The bottom line is that all code with actions related to visibility, *must* use
53436 * 'nodeIndices' and 'edgeIndices', not 'nodes' and 'edges' directly.
53437 */
53438
53439 this.body = {
53440 container: container,
53441 // See comment above for following fields
53442 nodes: {},
53443 nodeIndices: [],
53444 edges: {},
53445 edgeIndices: [],
53446 emitter: {
53447 on: this.on.bind(this),
53448 off: this.off.bind(this),
53449 emit: this.emit.bind(this),
53450 once: this.once.bind(this)
53451 },
53452 eventListeners: {
53453 onTap: function onTap() {},
53454 onTouch: function onTouch() {},
53455 onDoubleTap: function onDoubleTap() {},
53456 onHold: function onHold() {},
53457 onDragStart: function onDragStart() {},
53458 onDrag: function onDrag() {},
53459 onDragEnd: function onDragEnd() {},
53460 onMouseWheel: function onMouseWheel() {},
53461 onPinch: function onPinch() {},
53462 onMouseMove: function onMouseMove() {},
53463 onRelease: function onRelease() {},
53464 onContext: function onContext() {}
53465 },
53466 data: {
53467 nodes: null,
53468 // A DataSet or DataView
53469 edges: null // A DataSet or DataView
53470
53471 },
53472 functions: {
53473 createNode: function createNode() {},
53474 createEdge: function createEdge() {},
53475 getPointer: function getPointer() {}
53476 },
53477 modules: {},
53478 view: {
53479 scale: 1,
53480 translation: {
53481 x: 0,
53482 y: 0
53483 }
53484 }
53485 }; // bind the event listeners
53486
53487 this.bindEventListeners(); // setting up all modules
53488
53489 this.images = new Images(function () {
53490 return _this.body.emitter.emit("_requestRedraw");
53491 }); // object with images
53492
53493 this.groups = new Groups(); // object with groups
53494
53495 this.canvas = new Canvas(this.body); // DOM handler
53496
53497 this.selectionHandler = new SelectionHandler(this.body, this.canvas); // Selection handler
53498
53499 this.interactionHandler = new InteractionHandler(this.body, this.canvas, this.selectionHandler); // Interaction handler handles all the hammer bindings (that are bound by canvas), key
53500
53501 this.view = new View(this.body, this.canvas); // camera handler, does animations and zooms
53502
53503 this.renderer = new CanvasRenderer(this.body, this.canvas); // renderer, starts renderloop, has events that modules can hook into
53504
53505 this.physics = new PhysicsEngine(this.body); // physics engine, does all the simulations
53506
53507 this.layoutEngine = new LayoutEngine(this.body); // layout engine for inital layout and hierarchical layout
53508
53509 this.clustering = new ClusterEngine(this.body); // clustering api
53510
53511 this.manipulation = new ManipulationSystem(this.body, this.canvas, this.selectionHandler, this.interactionHandler); // data manipulation system
53512
53513 this.nodesHandler = new NodesHandler(this.body, this.images, this.groups, this.layoutEngine); // Handle adding, deleting and updating of nodes as well as global options
53514
53515 this.edgesHandler = new EdgesHandler(this.body, this.images, this.groups); // Handle adding, deleting and updating of edges as well as global options
53516
53517 this.body.modules["kamadaKawai"] = new KamadaKawai(this.body, 150, 0.05); // Layouting algorithm.
53518
53519 this.body.modules["clustering"] = this.clustering; // create the DOM elements
53520
53521 this.canvas._create(); // apply options
53522
53523
53524 this.setOptions(options); // load data (the disable start variable will be the same as the enabled clustering)
53525
53526 this.setData(data);
53527 } // Extend Network with an Emitter mixin
53528
53529 componentEmitter(Network.prototype);
53530 /**
53531 * Set options
53532 * @param {Object} options
53533 */
53534
53535 Network.prototype.setOptions = function (options) {
53536 var _this2 = this;
53537
53538 if (options === null) {
53539 options = undefined; // This ensures that options handling doesn't crash in the handling
53540 }
53541
53542 if (options !== undefined) {
53543 var errorFound = Validator.validate(options, allOptions$1);
53544
53545 if (errorFound === true) {
53546 console.log('%cErrors have been found in the supplied options object.', printStyle);
53547 } // copy the global fields over
53548
53549
53550 var fields = ['locale', 'locales', 'clickToUse'];
53551 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.
53552
53553 options = this.layoutEngine.setOptions(options.layout, options);
53554 this.canvas.setOptions(options); // options for canvas are in globals
53555 // pass the options to the modules
53556
53557 this.groups.setOptions(options.groups);
53558 this.nodesHandler.setOptions(options.nodes);
53559 this.edgesHandler.setOptions(options.edges);
53560 this.physics.setOptions(options.physics);
53561 this.manipulation.setOptions(options.manipulation, options, this.options); // manipulation uses the locales in the globals
53562
53563 this.interactionHandler.setOptions(options.interaction);
53564 this.renderer.setOptions(options.interaction); // options for rendering are in interaction
53565
53566 this.selectionHandler.setOptions(options.interaction); // options for selection are in interaction
53567 // reload the settings of the nodes to apply changes in groups that are not referenced by pointer.
53568
53569 if (options.groups !== undefined) {
53570 this.body.emitter.emit("refreshNodes");
53571 } // these two do not have options at the moment, here for completeness
53572 //this.view.setOptions(options.view);
53573 //this.clustering.setOptions(options.clustering);
53574
53575
53576 if ('configure' in options) {
53577 if (!this.configurator) {
53578 this.configurator = new Configurator(this, this.body.container, configureOptions, this.canvas.pixelRatio);
53579 }
53580
53581 this.configurator.setOptions(options.configure);
53582 } // if the configuration system is enabled, copy all options and put them into the config system
53583
53584
53585 if (this.configurator && this.configurator.options.enabled === true) {
53586 var networkOptions = {
53587 nodes: {},
53588 edges: {},
53589 layout: {},
53590 interaction: {},
53591 manipulation: {},
53592 physics: {},
53593 global: {}
53594 };
53595 deepExtend(networkOptions.nodes, this.nodesHandler.options);
53596 deepExtend(networkOptions.edges, this.edgesHandler.options);
53597 deepExtend(networkOptions.layout, this.layoutEngine.options); // load the selectionHandler and render default options in to the interaction group
53598
53599 deepExtend(networkOptions.interaction, this.selectionHandler.options);
53600 deepExtend(networkOptions.interaction, this.renderer.options);
53601 deepExtend(networkOptions.interaction, this.interactionHandler.options);
53602 deepExtend(networkOptions.manipulation, this.manipulation.options);
53603 deepExtend(networkOptions.physics, this.physics.options); // load globals into the global object
53604
53605 deepExtend(networkOptions.global, this.canvas.options);
53606 deepExtend(networkOptions.global, this.options);
53607 this.configurator.setModuleOptions(networkOptions);
53608 } // handle network global options
53609
53610
53611 if (options.clickToUse !== undefined) {
53612 if (options.clickToUse === true) {
53613 if (this.activator === undefined) {
53614 this.activator = new Activator_1(this.canvas.frame);
53615 this.activator.on('change', function () {
53616 _this2.body.emitter.emit("activate");
53617 });
53618 }
53619 } else {
53620 if (this.activator !== undefined) {
53621 this.activator.destroy();
53622 delete this.activator;
53623 }
53624
53625 this.body.emitter.emit("activate");
53626 }
53627 } else {
53628 this.body.emitter.emit("activate");
53629 }
53630
53631 this.canvas.setSize(); // start the physics simulation. Can be safely called multiple times.
53632
53633 this.body.emitter.emit("startSimulation");
53634 }
53635 };
53636 /**
53637 * Update the visible nodes and edges list with the most recent node state.
53638 *
53639 * Visible nodes are stored in this.body.nodeIndices.
53640 * Visible edges are stored in this.body.edgeIndices.
53641 * A node or edges is visible if it is not hidden or clustered.
53642 *
53643 * @private
53644 */
53645
53646
53647 Network.prototype._updateVisibleIndices = function () {
53648 var nodes = this.body.nodes;
53649 var edges = this.body.edges;
53650 this.body.nodeIndices = [];
53651 this.body.edgeIndices = [];
53652
53653 for (var nodeId in nodes) {
53654 if (nodes.hasOwnProperty(nodeId)) {
53655 if (!this.clustering._isClusteredNode(nodeId) && nodes[nodeId].options.hidden === false) {
53656 this.body.nodeIndices.push(nodes[nodeId].id);
53657 }
53658 }
53659 }
53660
53661 for (var edgeId in edges) {
53662 if (edges.hasOwnProperty(edgeId)) {
53663 var edge = edges[edgeId]; // It can happen that this is executed *after* a node edge has been removed,
53664 // but *before* the edge itself has been removed. Taking this into account.
53665
53666 var fromNode = nodes[edge.fromId];
53667 var toNode = nodes[edge.toId];
53668 var edgeNodesPresent = fromNode !== undefined && toNode !== undefined;
53669 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
53670 && toNode.options.hidden === false; // idem
53671
53672 if (isVisible) {
53673 this.body.edgeIndices.push(edge.id);
53674 }
53675 }
53676 }
53677 };
53678 /**
53679 * Bind all events
53680 */
53681
53682
53683 Network.prototype.bindEventListeners = function () {
53684 var _this3 = this;
53685
53686 // This event will trigger a rebuilding of the cache everything.
53687 // Used when nodes or edges have been added or removed.
53688 this.body.emitter.on("_dataChanged", function () {
53689 _this3.edgesHandler._updateState();
53690
53691 _this3.body.emitter.emit("_dataUpdated");
53692 }); // this is called when options of EXISTING nodes or edges have changed.
53693
53694 this.body.emitter.on("_dataUpdated", function () {
53695 // Order important in following block
53696 _this3.clustering._updateState();
53697
53698 _this3._updateVisibleIndices();
53699
53700 _this3._updateValueRange(_this3.body.nodes);
53701
53702 _this3._updateValueRange(_this3.body.edges); // start simulation (can be called safely, even if already running)
53703
53704
53705 _this3.body.emitter.emit("startSimulation");
53706
53707 _this3.body.emitter.emit("_requestRedraw");
53708 });
53709 };
53710 /**
53711 * Set nodes and edges, and optionally options as well.
53712 *
53713 * @param {Object} data Object containing parameters:
53714 * {Array | DataSet | DataView} [nodes] Array with nodes
53715 * {Array | DataSet | DataView} [edges] Array with edges
53716 * {String} [dot] String containing data in DOT format
53717 * {String} [gephi] String containing data in gephi JSON format
53718 * {Options} [options] Object with options
53719 */
53720
53721
53722 Network.prototype.setData = function (data) {
53723 // reset the physics engine.
53724 this.body.emitter.emit("resetPhysics");
53725 this.body.emitter.emit("_resetData"); // unselect all to ensure no selections from old data are carried over.
53726
53727 this.selectionHandler.unselectAll();
53728
53729 if (data && data.dot && (data.nodes || data.edges)) {
53730 throw new SyntaxError('Data must contain either parameter "dot" or ' + ' parameter pair "nodes" and "edges", but not both.');
53731 } // set options
53732
53733
53734 this.setOptions(data && data.options); // set all data
53735
53736 if (data && data.dot) {
53737 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
53738
53739 var dotData = dotparser.DOTToGraph(data.dot);
53740 this.setData(dotData);
53741 return;
53742 } else if (data && data.gephi) {
53743 // parse DOT file
53744 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);');
53745 var gephiData = parseGephi(data.gephi);
53746 this.setData(gephiData);
53747 return;
53748 } else {
53749 this.nodesHandler.setData(data && data.nodes, true);
53750 this.edgesHandler.setData(data && data.edges, true);
53751 } // emit change in data
53752
53753
53754 this.body.emitter.emit("_dataChanged"); // emit data loaded
53755
53756 this.body.emitter.emit("_dataLoaded"); // find a stable position or start animating to a stable position
53757
53758 this.body.emitter.emit("initPhysics");
53759 };
53760 /**
53761 * Cleans up all bindings of the network, removing it fully from the memory IF the variable is set to null after calling this function.
53762 * var network = new vis.Network(..);
53763 * network.destroy();
53764 * network = null;
53765 */
53766
53767
53768 Network.prototype.destroy = function () {
53769 this.body.emitter.emit("destroy"); // clear events
53770
53771 this.body.emitter.off();
53772 this.off(); // delete modules
53773
53774 delete this.groups;
53775 delete this.canvas;
53776 delete this.selectionHandler;
53777 delete this.interactionHandler;
53778 delete this.view;
53779 delete this.renderer;
53780 delete this.physics;
53781 delete this.layoutEngine;
53782 delete this.clustering;
53783 delete this.manipulation;
53784 delete this.nodesHandler;
53785 delete this.edgesHandler;
53786 delete this.configurator;
53787 delete this.images;
53788
53789 for (var nodeId in this.body.nodes) {
53790 if (!this.body.nodes.hasOwnProperty(nodeId)) continue;
53791 delete this.body.nodes[nodeId];
53792 }
53793
53794 for (var edgeId in this.body.edges) {
53795 if (!this.body.edges.hasOwnProperty(edgeId)) continue;
53796 delete this.body.edges[edgeId];
53797 } // remove the container and everything inside it recursively
53798
53799
53800 recursiveDOMDelete(this.body.container);
53801 };
53802 /**
53803 * Update the values of all object in the given array according to the current
53804 * value range of the objects in the array.
53805 * @param {Object} obj An object containing a set of Edges or Nodes
53806 * The objects must have a method getValue() and
53807 * setValueRange(min, max).
53808 * @private
53809 */
53810
53811
53812 Network.prototype._updateValueRange = function (obj) {
53813 var id; // determine the range of the objects
53814
53815 var valueMin = undefined;
53816 var valueMax = undefined;
53817 var valueTotal = 0;
53818
53819 for (id in obj) {
53820 if (obj.hasOwnProperty(id)) {
53821 var value = obj[id].getValue();
53822
53823 if (value !== undefined) {
53824 valueMin = valueMin === undefined ? value : Math.min(value, valueMin);
53825 valueMax = valueMax === undefined ? value : Math.max(value, valueMax);
53826 valueTotal += value;
53827 }
53828 }
53829 } // adjust the range of all objects
53830
53831
53832 if (valueMin !== undefined && valueMax !== undefined) {
53833 for (id in obj) {
53834 if (obj.hasOwnProperty(id)) {
53835 obj[id].setValueRange(valueMin, valueMax, valueTotal);
53836 }
53837 }
53838 }
53839 };
53840 /**
53841 * Returns true when the Network is active.
53842 * @returns {boolean}
53843 */
53844
53845
53846 Network.prototype.isActive = function () {
53847 return !this.activator || this.activator.active;
53848 };
53849
53850 Network.prototype.setSize = function () {
53851 return this.canvas.setSize.apply(this.canvas, arguments);
53852 };
53853
53854 Network.prototype.canvasToDOM = function () {
53855 return this.canvas.canvasToDOM.apply(this.canvas, arguments);
53856 };
53857
53858 Network.prototype.DOMtoCanvas = function () {
53859 return this.canvas.DOMtoCanvas.apply(this.canvas, arguments);
53860 };
53861 /**
53862 * Nodes can be in clusters. Clusters can also be in clusters. This function returns and array of
53863 * nodeIds showing where the node is.
53864 *
53865 * If any nodeId in the chain, especially the first passed in as a parameter, is not present in
53866 * the current nodes list, an empty array is returned.
53867 *
53868 * Example:
53869 * cluster 'A' contains cluster 'B',
53870 * cluster 'B' contains cluster 'C',
53871 * cluster 'C' contains node 'fred'.
53872 * `jsnetwork.clustering.findNode('fred')` will return `['A','B','C','fred']`.
53873 *
53874 * @param {string|number} nodeId
53875 * @returns {Array}
53876 */
53877
53878
53879 Network.prototype.findNode = function () {
53880 return this.clustering.findNode.apply(this.clustering, arguments);
53881 };
53882
53883 Network.prototype.isCluster = function () {
53884 return this.clustering.isCluster.apply(this.clustering, arguments);
53885 };
53886
53887 Network.prototype.openCluster = function () {
53888 return this.clustering.openCluster.apply(this.clustering, arguments);
53889 };
53890
53891 Network.prototype.cluster = function () {
53892 return this.clustering.cluster.apply(this.clustering, arguments);
53893 };
53894
53895 Network.prototype.getNodesInCluster = function () {
53896 return this.clustering.getNodesInCluster.apply(this.clustering, arguments);
53897 };
53898
53899 Network.prototype.clusterByConnection = function () {
53900 return this.clustering.clusterByConnection.apply(this.clustering, arguments);
53901 };
53902
53903 Network.prototype.clusterByHubsize = function () {
53904 return this.clustering.clusterByHubsize.apply(this.clustering, arguments);
53905 };
53906 /**
53907 * This method will cluster all nodes with 1 edge with their respective connected node.
53908 * The options object is explained in full <a data-scroll="" data-options="{ &quot;easing&quot;: &quot;easeInCubic&quot; }" href="#optionsObject">below</a>.
53909 *
53910 * @param {object} [options]
53911 * @returns {undefined}
53912 */
53913
53914
53915 Network.prototype.clusterOutliers = function () {
53916 return this.clustering.clusterOutliers.apply(this.clustering, arguments);
53917 };
53918
53919 Network.prototype.getSeed = function () {
53920 return this.layoutEngine.getSeed.apply(this.layoutEngine, arguments);
53921 };
53922
53923 Network.prototype.enableEditMode = function () {
53924 return this.manipulation.enableEditMode.apply(this.manipulation, arguments);
53925 };
53926
53927 Network.prototype.disableEditMode = function () {
53928 return this.manipulation.disableEditMode.apply(this.manipulation, arguments);
53929 };
53930
53931 Network.prototype.addNodeMode = function () {
53932 return this.manipulation.addNodeMode.apply(this.manipulation, arguments);
53933 };
53934
53935 Network.prototype.editNode = function () {
53936 return this.manipulation.editNode.apply(this.manipulation, arguments);
53937 };
53938
53939 Network.prototype.editNodeMode = function () {
53940 console.log("Deprecated: Please use editNode instead of editNodeMode.");
53941 return this.manipulation.editNode.apply(this.manipulation, arguments);
53942 };
53943
53944 Network.prototype.addEdgeMode = function () {
53945 return this.manipulation.addEdgeMode.apply(this.manipulation, arguments);
53946 };
53947
53948 Network.prototype.editEdgeMode = function () {
53949 return this.manipulation.editEdgeMode.apply(this.manipulation, arguments);
53950 };
53951
53952 Network.prototype.deleteSelected = function () {
53953 return this.manipulation.deleteSelected.apply(this.manipulation, arguments);
53954 };
53955
53956 Network.prototype.getPositions = function () {
53957 return this.nodesHandler.getPositions.apply(this.nodesHandler, arguments);
53958 };
53959
53960 Network.prototype.storePositions = function () {
53961 return this.nodesHandler.storePositions.apply(this.nodesHandler, arguments);
53962 };
53963
53964 Network.prototype.moveNode = function () {
53965 return this.nodesHandler.moveNode.apply(this.nodesHandler, arguments);
53966 };
53967
53968 Network.prototype.getBoundingBox = function () {
53969 return this.nodesHandler.getBoundingBox.apply(this.nodesHandler, arguments);
53970 };
53971
53972 Network.prototype.getConnectedNodes = function (objectId) {
53973 if (this.body.nodes[objectId] !== undefined) {
53974 return this.nodesHandler.getConnectedNodes.apply(this.nodesHandler, arguments);
53975 } else {
53976 return this.edgesHandler.getConnectedNodes.apply(this.edgesHandler, arguments);
53977 }
53978 };
53979
53980 Network.prototype.getConnectedEdges = function () {
53981 return this.nodesHandler.getConnectedEdges.apply(this.nodesHandler, arguments);
53982 };
53983
53984 Network.prototype.startSimulation = function () {
53985 return this.physics.startSimulation.apply(this.physics, arguments);
53986 };
53987
53988 Network.prototype.stopSimulation = function () {
53989 return this.physics.stopSimulation.apply(this.physics, arguments);
53990 };
53991
53992 Network.prototype.stabilize = function () {
53993 return this.physics.stabilize.apply(this.physics, arguments);
53994 };
53995
53996 Network.prototype.getSelection = function () {
53997 return this.selectionHandler.getSelection.apply(this.selectionHandler, arguments);
53998 };
53999
54000 Network.prototype.setSelection = function () {
54001 return this.selectionHandler.setSelection.apply(this.selectionHandler, arguments);
54002 };
54003
54004 Network.prototype.getSelectedNodes = function () {
54005 return this.selectionHandler.getSelectedNodes.apply(this.selectionHandler, arguments);
54006 };
54007
54008 Network.prototype.getSelectedEdges = function () {
54009 return this.selectionHandler.getSelectedEdges.apply(this.selectionHandler, arguments);
54010 };
54011
54012 Network.prototype.getNodeAt = function () {
54013 var node = this.selectionHandler.getNodeAt.apply(this.selectionHandler, arguments);
54014
54015 if (node !== undefined && node.id !== undefined) {
54016 return node.id;
54017 }
54018
54019 return node;
54020 };
54021
54022 Network.prototype.getEdgeAt = function () {
54023 var edge = this.selectionHandler.getEdgeAt.apply(this.selectionHandler, arguments);
54024
54025 if (edge !== undefined && edge.id !== undefined) {
54026 return edge.id;
54027 }
54028
54029 return edge;
54030 };
54031
54032 Network.prototype.selectNodes = function () {
54033 return this.selectionHandler.selectNodes.apply(this.selectionHandler, arguments);
54034 };
54035
54036 Network.prototype.selectEdges = function () {
54037 return this.selectionHandler.selectEdges.apply(this.selectionHandler, arguments);
54038 };
54039
54040 Network.prototype.unselectAll = function () {
54041 this.selectionHandler.unselectAll.apply(this.selectionHandler, arguments);
54042 this.redraw();
54043 };
54044
54045 Network.prototype.redraw = function () {
54046 return this.renderer.redraw.apply(this.renderer, arguments);
54047 };
54048
54049 Network.prototype.getScale = function () {
54050 return this.view.getScale.apply(this.view, arguments);
54051 };
54052
54053 Network.prototype.getViewPosition = function () {
54054 return this.view.getViewPosition.apply(this.view, arguments);
54055 };
54056
54057 Network.prototype.fit = function () {
54058 return this.view.fit.apply(this.view, arguments);
54059 };
54060
54061 Network.prototype.moveTo = function () {
54062 return this.view.moveTo.apply(this.view, arguments);
54063 };
54064
54065 Network.prototype.focus = function () {
54066 return this.view.focus.apply(this.view, arguments);
54067 };
54068
54069 Network.prototype.releaseNode = function () {
54070 return this.view.releaseNode.apply(this.view, arguments);
54071 };
54072
54073 Network.prototype.getOptionsFromConfigurator = function () {
54074 var options = {};
54075
54076 if (this.configurator) {
54077 options = this.configurator.getOptions.apply(this.configurator);
54078 }
54079
54080 return options;
54081 };
54082
54083 var DOMutil = createCommonjsModule(function (module, exports) {
54084 // DOM utility methods
54085
54086 /**
54087 * this prepares the JSON container for allocating SVG elements
54088 * @param {Object} JSONcontainer
54089 * @private
54090 */
54091 exports.prepareElements = function (JSONcontainer) {
54092 // cleanup the redundant svgElements;
54093 for (var elementType in JSONcontainer) {
54094 if (JSONcontainer.hasOwnProperty(elementType)) {
54095 JSONcontainer[elementType].redundant = JSONcontainer[elementType].used;
54096 JSONcontainer[elementType].used = [];
54097 }
54098 }
54099 };
54100 /**
54101 * this cleans up all the unused SVG elements. By asking for the parentNode, we only need to supply the JSON container from
54102 * which to remove the redundant elements.
54103 *
54104 * @param {Object} JSONcontainer
54105 * @private
54106 */
54107
54108
54109 exports.cleanupElements = function (JSONcontainer) {
54110 // cleanup the redundant svgElements;
54111 for (var elementType in JSONcontainer) {
54112 if (JSONcontainer.hasOwnProperty(elementType)) {
54113 if (JSONcontainer[elementType].redundant) {
54114 for (var i = 0; i < JSONcontainer[elementType].redundant.length; i++) {
54115 JSONcontainer[elementType].redundant[i].parentNode.removeChild(JSONcontainer[elementType].redundant[i]);
54116 }
54117
54118 JSONcontainer[elementType].redundant = [];
54119 }
54120 }
54121 }
54122 };
54123 /**
54124 * Ensures that all elements are removed first up so they can be recreated cleanly
54125 * @param {Object} JSONcontainer
54126 */
54127
54128
54129 exports.resetElements = function (JSONcontainer) {
54130 exports.prepareElements(JSONcontainer);
54131 exports.cleanupElements(JSONcontainer);
54132 exports.prepareElements(JSONcontainer);
54133 };
54134 /**
54135 * Allocate or generate an SVG element if needed. Store a reference to it in the JSON container and draw it in the svgContainer
54136 * the JSON container and the SVG container have to be supplied so other svg containers (like the legend) can use this.
54137 *
54138 * @param {string} elementType
54139 * @param {Object} JSONcontainer
54140 * @param {Object} svgContainer
54141 * @returns {Element}
54142 * @private
54143 */
54144
54145
54146 exports.getSVGElement = function (elementType, JSONcontainer, svgContainer) {
54147 var element; // allocate SVG element, if it doesnt yet exist, create one.
54148
54149 if (JSONcontainer.hasOwnProperty(elementType)) {
54150 // this element has been created before
54151 // check if there is an redundant element
54152 if (JSONcontainer[elementType].redundant.length > 0) {
54153 element = JSONcontainer[elementType].redundant[0];
54154 JSONcontainer[elementType].redundant.shift();
54155 } else {
54156 // create a new element and add it to the SVG
54157 element = document.createElementNS('http://www.w3.org/2000/svg', elementType);
54158 svgContainer.appendChild(element);
54159 }
54160 } else {
54161 // create a new element and add it to the SVG, also create a new object in the svgElements to keep track of it.
54162 element = document.createElementNS('http://www.w3.org/2000/svg', elementType);
54163 JSONcontainer[elementType] = {
54164 used: [],
54165 redundant: []
54166 };
54167 svgContainer.appendChild(element);
54168 }
54169
54170 JSONcontainer[elementType].used.push(element);
54171 return element;
54172 };
54173 /**
54174 * Allocate or generate an SVG element if needed. Store a reference to it in the JSON container and draw it in the svgContainer
54175 * the JSON container and the SVG container have to be supplied so other svg containers (like the legend) can use this.
54176 *
54177 * @param {string} elementType
54178 * @param {Object} JSONcontainer
54179 * @param {Element} DOMContainer
54180 * @param {Element} insertBefore
54181 * @returns {*}
54182 */
54183
54184
54185 exports.getDOMElement = function (elementType, JSONcontainer, DOMContainer, insertBefore) {
54186 var element; // allocate DOM element, if it doesnt yet exist, create one.
54187
54188 if (JSONcontainer.hasOwnProperty(elementType)) {
54189 // this element has been created before
54190 // check if there is an redundant element
54191 if (JSONcontainer[elementType].redundant.length > 0) {
54192 element = JSONcontainer[elementType].redundant[0];
54193 JSONcontainer[elementType].redundant.shift();
54194 } else {
54195 // create a new element and add it to the SVG
54196 element = document.createElement(elementType);
54197
54198 if (insertBefore !== undefined) {
54199 DOMContainer.insertBefore(element, insertBefore);
54200 } else {
54201 DOMContainer.appendChild(element);
54202 }
54203 }
54204 } else {
54205 // create a new element and add it to the SVG, also create a new object in the svgElements to keep track of it.
54206 element = document.createElement(elementType);
54207 JSONcontainer[elementType] = {
54208 used: [],
54209 redundant: []
54210 };
54211
54212 if (insertBefore !== undefined) {
54213 DOMContainer.insertBefore(element, insertBefore);
54214 } else {
54215 DOMContainer.appendChild(element);
54216 }
54217 }
54218
54219 JSONcontainer[elementType].used.push(element);
54220 return element;
54221 };
54222 /**
54223 * Draw a point object. This is a separate function because it can also be called by the legend.
54224 * The reason the JSONcontainer and the target SVG svgContainer have to be supplied is so the legend can use these functions
54225 * as well.
54226 *
54227 * @param {number} x
54228 * @param {number} y
54229 * @param {Object} groupTemplate: A template containing the necessary information to draw the datapoint e.g., {style: 'circle', size: 5, className: 'className' }
54230 * @param {Object} JSONcontainer
54231 * @param {Object} svgContainer
54232 * @param {Object} labelObj
54233 * @returns {vis.PointItem}
54234 */
54235
54236
54237 exports.drawPoint = function (x, y, groupTemplate, JSONcontainer, svgContainer, labelObj) {
54238 var point;
54239
54240 if (groupTemplate.style == 'circle') {
54241 point = exports.getSVGElement('circle', JSONcontainer, svgContainer);
54242 point.setAttributeNS(null, "cx", x);
54243 point.setAttributeNS(null, "cy", y);
54244 point.setAttributeNS(null, "r", 0.5 * groupTemplate.size);
54245 } else {
54246 point = exports.getSVGElement('rect', JSONcontainer, svgContainer);
54247 point.setAttributeNS(null, "x", x - 0.5 * groupTemplate.size);
54248 point.setAttributeNS(null, "y", y - 0.5 * groupTemplate.size);
54249 point.setAttributeNS(null, "width", groupTemplate.size);
54250 point.setAttributeNS(null, "height", groupTemplate.size);
54251 }
54252
54253 if (groupTemplate.styles !== undefined) {
54254 point.setAttributeNS(null, "style", groupTemplate.styles);
54255 }
54256
54257 point.setAttributeNS(null, "class", groupTemplate.className + " vis-point"); //handle label
54258
54259 if (labelObj) {
54260 var label = exports.getSVGElement('text', JSONcontainer, svgContainer);
54261
54262 if (labelObj.xOffset) {
54263 x = x + labelObj.xOffset;
54264 }
54265
54266 if (labelObj.yOffset) {
54267 y = y + labelObj.yOffset;
54268 }
54269
54270 if (labelObj.content) {
54271 label.textContent = labelObj.content;
54272 }
54273
54274 if (labelObj.className) {
54275 label.setAttributeNS(null, "class", labelObj.className + " vis-label");
54276 }
54277
54278 label.setAttributeNS(null, "x", x);
54279 label.setAttributeNS(null, "y", y);
54280 }
54281
54282 return point;
54283 };
54284 /**
54285 * draw a bar SVG element centered on the X coordinate
54286 *
54287 * @param {number} x
54288 * @param {number} y
54289 * @param {number} width
54290 * @param {number} height
54291 * @param {string} className
54292 * @param {Object} JSONcontainer
54293 * @param {Object} svgContainer
54294 * @param {string} style
54295 */
54296
54297
54298 exports.drawBar = function (x, y, width, height, className, JSONcontainer, svgContainer, style) {
54299 if (height != 0) {
54300 if (height < 0) {
54301 height *= -1;
54302 y -= height;
54303 }
54304
54305 var rect = exports.getSVGElement('rect', JSONcontainer, svgContainer);
54306 rect.setAttributeNS(null, "x", x - 0.5 * width);
54307 rect.setAttributeNS(null, "y", y);
54308 rect.setAttributeNS(null, "width", width);
54309 rect.setAttributeNS(null, "height", height);
54310 rect.setAttributeNS(null, "class", className);
54311
54312 if (style) {
54313 rect.setAttributeNS(null, "style", style);
54314 }
54315 }
54316 };
54317 });
54318 var DOMutil_1 = DOMutil.prepareElements;
54319 var DOMutil_2 = DOMutil.cleanupElements;
54320 var DOMutil_3 = DOMutil.resetElements;
54321 var DOMutil_4 = DOMutil.getSVGElement;
54322 var DOMutil_5 = DOMutil.getDOMElement;
54323 var DOMutil_6 = DOMutil.drawPoint;
54324 var DOMutil_7 = DOMutil.drawBar;
54325
54326 var DOMutil$1 = /*#__PURE__*/Object.freeze({
54327 __proto__: null,
54328 'default': DOMutil,
54329 __moduleExports: DOMutil,
54330 prepareElements: DOMutil_1,
54331 cleanupElements: DOMutil_2,
54332 resetElements: DOMutil_3,
54333 getSVGElement: DOMutil_4,
54334 getDOMElement: DOMutil_5,
54335 drawPoint: DOMutil_6,
54336 drawBar: DOMutil_7
54337 });
54338
54339 var moment$2 = createCommonjsModule(function (module, exports) {
54340
54341 (function (global, factory) {
54342 module.exports = factory() ;
54343 })(commonjsGlobal, function () {
54344
54345 var hookCallback;
54346
54347 function hooks() {
54348 return hookCallback.apply(null, arguments);
54349 } // This is done to register the method called with moment()
54350 // without creating circular dependencies.
54351
54352
54353 function setHookCallback(callback) {
54354 hookCallback = callback;
54355 }
54356
54357 function isArray(input) {
54358 return input instanceof Array || Object.prototype.toString.call(input) === '[object Array]';
54359 }
54360
54361 function isObject(input) {
54362 // IE8 will treat undefined and null as object if it wasn't for
54363 // input != null
54364 return input != null && Object.prototype.toString.call(input) === '[object Object]';
54365 }
54366
54367 function isObjectEmpty(obj) {
54368 if (Object.getOwnPropertyNames) {
54369 return Object.getOwnPropertyNames(obj).length === 0;
54370 } else {
54371 var k;
54372
54373 for (k in obj) {
54374 if (obj.hasOwnProperty(k)) {
54375 return false;
54376 }
54377 }
54378
54379 return true;
54380 }
54381 }
54382
54383 function isUndefined(input) {
54384 return input === void 0;
54385 }
54386
54387 function isNumber(input) {
54388 return typeof input === 'number' || Object.prototype.toString.call(input) === '[object Number]';
54389 }
54390
54391 function isDate(input) {
54392 return input instanceof Date || Object.prototype.toString.call(input) === '[object Date]';
54393 }
54394
54395 function map(arr, fn) {
54396 var res = [],
54397 i;
54398
54399 for (i = 0; i < arr.length; ++i) {
54400 res.push(fn(arr[i], i));
54401 }
54402
54403 return res;
54404 }
54405
54406 function hasOwnProp(a, b) {
54407 return Object.prototype.hasOwnProperty.call(a, b);
54408 }
54409
54410 function extend(a, b) {
54411 for (var i in b) {
54412 if (hasOwnProp(b, i)) {
54413 a[i] = b[i];
54414 }
54415 }
54416
54417 if (hasOwnProp(b, 'toString')) {
54418 a.toString = b.toString;
54419 }
54420
54421 if (hasOwnProp(b, 'valueOf')) {
54422 a.valueOf = b.valueOf;
54423 }
54424
54425 return a;
54426 }
54427
54428 function createUTC(input, format, locale, strict) {
54429 return createLocalOrUTC(input, format, locale, strict, true).utc();
54430 }
54431
54432 function defaultParsingFlags() {
54433 // We need to deep clone this object.
54434 return {
54435 empty: false,
54436 unusedTokens: [],
54437 unusedInput: [],
54438 overflow: -2,
54439 charsLeftOver: 0,
54440 nullInput: false,
54441 invalidMonth: null,
54442 invalidFormat: false,
54443 userInvalidated: false,
54444 iso: false,
54445 parsedDateParts: [],
54446 meridiem: null,
54447 rfc2822: false,
54448 weekdayMismatch: false
54449 };
54450 }
54451
54452 function getParsingFlags(m) {
54453 if (m._pf == null) {
54454 m._pf = defaultParsingFlags();
54455 }
54456
54457 return m._pf;
54458 }
54459
54460 var some;
54461
54462 if (Array.prototype.some) {
54463 some = Array.prototype.some;
54464 } else {
54465 some = function (fun) {
54466 var t = Object(this);
54467 var len = t.length >>> 0;
54468
54469 for (var i = 0; i < len; i++) {
54470 if (i in t && fun.call(this, t[i], i, t)) {
54471 return true;
54472 }
54473 }
54474
54475 return false;
54476 };
54477 }
54478
54479 function isValid(m) {
54480 if (m._isValid == null) {
54481 var flags = getParsingFlags(m);
54482 var parsedParts = some.call(flags.parsedDateParts, function (i) {
54483 return i != null;
54484 });
54485 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);
54486
54487 if (m._strict) {
54488 isNowValid = isNowValid && flags.charsLeftOver === 0 && flags.unusedTokens.length === 0 && flags.bigHour === undefined;
54489 }
54490
54491 if (Object.isFrozen == null || !Object.isFrozen(m)) {
54492 m._isValid = isNowValid;
54493 } else {
54494 return isNowValid;
54495 }
54496 }
54497
54498 return m._isValid;
54499 }
54500
54501 function createInvalid(flags) {
54502 var m = createUTC(NaN);
54503
54504 if (flags != null) {
54505 extend(getParsingFlags(m), flags);
54506 } else {
54507 getParsingFlags(m).userInvalidated = true;
54508 }
54509
54510 return m;
54511 } // Plugins that add properties should also add the key here (null value),
54512 // so we can properly clone ourselves.
54513
54514
54515 var momentProperties = hooks.momentProperties = [];
54516
54517 function copyConfig(to, from) {
54518 var i, prop, val;
54519
54520 if (!isUndefined(from._isAMomentObject)) {
54521 to._isAMomentObject = from._isAMomentObject;
54522 }
54523
54524 if (!isUndefined(from._i)) {
54525 to._i = from._i;
54526 }
54527
54528 if (!isUndefined(from._f)) {
54529 to._f = from._f;
54530 }
54531
54532 if (!isUndefined(from._l)) {
54533 to._l = from._l;
54534 }
54535
54536 if (!isUndefined(from._strict)) {
54537 to._strict = from._strict;
54538 }
54539
54540 if (!isUndefined(from._tzm)) {
54541 to._tzm = from._tzm;
54542 }
54543
54544 if (!isUndefined(from._isUTC)) {
54545 to._isUTC = from._isUTC;
54546 }
54547
54548 if (!isUndefined(from._offset)) {
54549 to._offset = from._offset;
54550 }
54551
54552 if (!isUndefined(from._pf)) {
54553 to._pf = getParsingFlags(from);
54554 }
54555
54556 if (!isUndefined(from._locale)) {
54557 to._locale = from._locale;
54558 }
54559
54560 if (momentProperties.length > 0) {
54561 for (i = 0; i < momentProperties.length; i++) {
54562 prop = momentProperties[i];
54563 val = from[prop];
54564
54565 if (!isUndefined(val)) {
54566 to[prop] = val;
54567 }
54568 }
54569 }
54570
54571 return to;
54572 }
54573
54574 var updateInProgress = false; // Moment prototype object
54575
54576 function Moment(config) {
54577 copyConfig(this, config);
54578 this._d = new Date(config._d != null ? config._d.getTime() : NaN);
54579
54580 if (!this.isValid()) {
54581 this._d = new Date(NaN);
54582 } // Prevent infinite loop in case updateOffset creates new moment
54583 // objects.
54584
54585
54586 if (updateInProgress === false) {
54587 updateInProgress = true;
54588 hooks.updateOffset(this);
54589 updateInProgress = false;
54590 }
54591 }
54592
54593 function isMoment(obj) {
54594 return obj instanceof Moment || obj != null && obj._isAMomentObject != null;
54595 }
54596
54597 function absFloor(number) {
54598 if (number < 0) {
54599 // -0 -> 0
54600 return Math.ceil(number) || 0;
54601 } else {
54602 return Math.floor(number);
54603 }
54604 }
54605
54606 function toInt(argumentForCoercion) {
54607 var coercedNumber = +argumentForCoercion,
54608 value = 0;
54609
54610 if (coercedNumber !== 0 && isFinite(coercedNumber)) {
54611 value = absFloor(coercedNumber);
54612 }
54613
54614 return value;
54615 } // compare two arrays, return the number of differences
54616
54617
54618 function compareArrays(array1, array2, dontConvert) {
54619 var len = Math.min(array1.length, array2.length),
54620 lengthDiff = Math.abs(array1.length - array2.length),
54621 diffs = 0,
54622 i;
54623
54624 for (i = 0; i < len; i++) {
54625 if (dontConvert && array1[i] !== array2[i] || !dontConvert && toInt(array1[i]) !== toInt(array2[i])) {
54626 diffs++;
54627 }
54628 }
54629
54630 return diffs + lengthDiff;
54631 }
54632
54633 function warn(msg) {
54634 if (hooks.suppressDeprecationWarnings === false && typeof console !== 'undefined' && console.warn) {
54635 console.warn('Deprecation warning: ' + msg);
54636 }
54637 }
54638
54639 function deprecate(msg, fn) {
54640 var firstTime = true;
54641 return extend(function () {
54642 if (hooks.deprecationHandler != null) {
54643 hooks.deprecationHandler(null, msg);
54644 }
54645
54646 if (firstTime) {
54647 var args = [];
54648 var arg;
54649
54650 for (var i = 0; i < arguments.length; i++) {
54651 arg = '';
54652
54653 if (typeof arguments[i] === 'object') {
54654 arg += '\n[' + i + '] ';
54655
54656 for (var key in arguments[0]) {
54657 arg += key + ': ' + arguments[0][key] + ', ';
54658 }
54659
54660 arg = arg.slice(0, -2); // Remove trailing comma and space
54661 } else {
54662 arg = arguments[i];
54663 }
54664
54665 args.push(arg);
54666 }
54667
54668 warn(msg + '\nArguments: ' + Array.prototype.slice.call(args).join('') + '\n' + new Error().stack);
54669 firstTime = false;
54670 }
54671
54672 return fn.apply(this, arguments);
54673 }, fn);
54674 }
54675
54676 var deprecations = {};
54677
54678 function deprecateSimple(name, msg) {
54679 if (hooks.deprecationHandler != null) {
54680 hooks.deprecationHandler(name, msg);
54681 }
54682
54683 if (!deprecations[name]) {
54684 warn(msg);
54685 deprecations[name] = true;
54686 }
54687 }
54688
54689 hooks.suppressDeprecationWarnings = false;
54690 hooks.deprecationHandler = null;
54691
54692 function isFunction(input) {
54693 return input instanceof Function || Object.prototype.toString.call(input) === '[object Function]';
54694 }
54695
54696 function set(config) {
54697 var prop, i;
54698
54699 for (i in config) {
54700 prop = config[i];
54701
54702 if (isFunction(prop)) {
54703 this[i] = prop;
54704 } else {
54705 this['_' + i] = prop;
54706 }
54707 }
54708
54709 this._config = config; // Lenient ordinal parsing accepts just a number in addition to
54710 // number + (possibly) stuff coming from _dayOfMonthOrdinalParse.
54711 // TODO: Remove "ordinalParse" fallback in next major release.
54712
54713 this._dayOfMonthOrdinalParseLenient = new RegExp((this._dayOfMonthOrdinalParse.source || this._ordinalParse.source) + '|' + /\d{1,2}/.source);
54714 }
54715
54716 function mergeConfigs(parentConfig, childConfig) {
54717 var res = extend({}, parentConfig),
54718 prop;
54719
54720 for (prop in childConfig) {
54721 if (hasOwnProp(childConfig, prop)) {
54722 if (isObject(parentConfig[prop]) && isObject(childConfig[prop])) {
54723 res[prop] = {};
54724 extend(res[prop], parentConfig[prop]);
54725 extend(res[prop], childConfig[prop]);
54726 } else if (childConfig[prop] != null) {
54727 res[prop] = childConfig[prop];
54728 } else {
54729 delete res[prop];
54730 }
54731 }
54732 }
54733
54734 for (prop in parentConfig) {
54735 if (hasOwnProp(parentConfig, prop) && !hasOwnProp(childConfig, prop) && isObject(parentConfig[prop])) {
54736 // make sure changes to properties don't modify parent config
54737 res[prop] = extend({}, res[prop]);
54738 }
54739 }
54740
54741 return res;
54742 }
54743
54744 function Locale(config) {
54745 if (config != null) {
54746 this.set(config);
54747 }
54748 }
54749
54750 var keys;
54751
54752 if (Object.keys) {
54753 keys = Object.keys;
54754 } else {
54755 keys = function (obj) {
54756 var i,
54757 res = [];
54758
54759 for (i in obj) {
54760 if (hasOwnProp(obj, i)) {
54761 res.push(i);
54762 }
54763 }
54764
54765 return res;
54766 };
54767 }
54768
54769 var defaultCalendar = {
54770 sameDay: '[Today at] LT',
54771 nextDay: '[Tomorrow at] LT',
54772 nextWeek: 'dddd [at] LT',
54773 lastDay: '[Yesterday at] LT',
54774 lastWeek: '[Last] dddd [at] LT',
54775 sameElse: 'L'
54776 };
54777
54778 function calendar(key, mom, now) {
54779 var output = this._calendar[key] || this._calendar['sameElse'];
54780 return isFunction(output) ? output.call(mom, now) : output;
54781 }
54782
54783 var defaultLongDateFormat = {
54784 LTS: 'h:mm:ss A',
54785 LT: 'h:mm A',
54786 L: 'MM/DD/YYYY',
54787 LL: 'MMMM D, YYYY',
54788 LLL: 'MMMM D, YYYY h:mm A',
54789 LLLL: 'dddd, MMMM D, YYYY h:mm A'
54790 };
54791
54792 function longDateFormat(key) {
54793 var format = this._longDateFormat[key],
54794 formatUpper = this._longDateFormat[key.toUpperCase()];
54795
54796 if (format || !formatUpper) {
54797 return format;
54798 }
54799
54800 this._longDateFormat[key] = formatUpper.replace(/MMMM|MM|DD|dddd/g, function (val) {
54801 return val.slice(1);
54802 });
54803 return this._longDateFormat[key];
54804 }
54805
54806 var defaultInvalidDate = 'Invalid date';
54807
54808 function invalidDate() {
54809 return this._invalidDate;
54810 }
54811
54812 var defaultOrdinal = '%d';
54813 var defaultDayOfMonthOrdinalParse = /\d{1,2}/;
54814
54815 function ordinal(number) {
54816 return this._ordinal.replace('%d', number);
54817 }
54818
54819 var defaultRelativeTime = {
54820 future: 'in %s',
54821 past: '%s ago',
54822 s: 'a few seconds',
54823 ss: '%d seconds',
54824 m: 'a minute',
54825 mm: '%d minutes',
54826 h: 'an hour',
54827 hh: '%d hours',
54828 d: 'a day',
54829 dd: '%d days',
54830 M: 'a month',
54831 MM: '%d months',
54832 y: 'a year',
54833 yy: '%d years'
54834 };
54835
54836 function relativeTime(number, withoutSuffix, string, isFuture) {
54837 var output = this._relativeTime[string];
54838 return isFunction(output) ? output(number, withoutSuffix, string, isFuture) : output.replace(/%d/i, number);
54839 }
54840
54841 function pastFuture(diff, output) {
54842 var format = this._relativeTime[diff > 0 ? 'future' : 'past'];
54843 return isFunction(format) ? format(output) : format.replace(/%s/i, output);
54844 }
54845
54846 var aliases = {};
54847
54848 function addUnitAlias(unit, shorthand) {
54849 var lowerCase = unit.toLowerCase();
54850 aliases[lowerCase] = aliases[lowerCase + 's'] = aliases[shorthand] = unit;
54851 }
54852
54853 function normalizeUnits(units) {
54854 return typeof units === 'string' ? aliases[units] || aliases[units.toLowerCase()] : undefined;
54855 }
54856
54857 function normalizeObjectUnits(inputObject) {
54858 var normalizedInput = {},
54859 normalizedProp,
54860 prop;
54861
54862 for (prop in inputObject) {
54863 if (hasOwnProp(inputObject, prop)) {
54864 normalizedProp = normalizeUnits(prop);
54865
54866 if (normalizedProp) {
54867 normalizedInput[normalizedProp] = inputObject[prop];
54868 }
54869 }
54870 }
54871
54872 return normalizedInput;
54873 }
54874
54875 var priorities = {};
54876
54877 function addUnitPriority(unit, priority) {
54878 priorities[unit] = priority;
54879 }
54880
54881 function getPrioritizedUnits(unitsObj) {
54882 var units = [];
54883
54884 for (var u in unitsObj) {
54885 units.push({
54886 unit: u,
54887 priority: priorities[u]
54888 });
54889 }
54890
54891 units.sort(function (a, b) {
54892 return a.priority - b.priority;
54893 });
54894 return units;
54895 }
54896
54897 function zeroFill(number, targetLength, forceSign) {
54898 var absNumber = '' + Math.abs(number),
54899 zerosToFill = targetLength - absNumber.length,
54900 sign = number >= 0;
54901 return (sign ? forceSign ? '+' : '' : '-') + Math.pow(10, Math.max(0, zerosToFill)).toString().substr(1) + absNumber;
54902 }
54903
54904 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;
54905 var localFormattingTokens = /(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g;
54906 var formatFunctions = {};
54907 var formatTokenFunctions = {}; // token: 'M'
54908 // padded: ['MM', 2]
54909 // ordinal: 'Mo'
54910 // callback: function () { this.month() + 1 }
54911
54912 function addFormatToken(token, padded, ordinal, callback) {
54913 var func = callback;
54914
54915 if (typeof callback === 'string') {
54916 func = function () {
54917 return this[callback]();
54918 };
54919 }
54920
54921 if (token) {
54922 formatTokenFunctions[token] = func;
54923 }
54924
54925 if (padded) {
54926 formatTokenFunctions[padded[0]] = function () {
54927 return zeroFill(func.apply(this, arguments), padded[1], padded[2]);
54928 };
54929 }
54930
54931 if (ordinal) {
54932 formatTokenFunctions[ordinal] = function () {
54933 return this.localeData().ordinal(func.apply(this, arguments), token);
54934 };
54935 }
54936 }
54937
54938 function removeFormattingTokens(input) {
54939 if (input.match(/\[[\s\S]/)) {
54940 return input.replace(/^\[|\]$/g, '');
54941 }
54942
54943 return input.replace(/\\/g, '');
54944 }
54945
54946 function makeFormatFunction(format) {
54947 var array = format.match(formattingTokens),
54948 i,
54949 length;
54950
54951 for (i = 0, length = array.length; i < length; i++) {
54952 if (formatTokenFunctions[array[i]]) {
54953 array[i] = formatTokenFunctions[array[i]];
54954 } else {
54955 array[i] = removeFormattingTokens(array[i]);
54956 }
54957 }
54958
54959 return function (mom) {
54960 var output = '',
54961 i;
54962
54963 for (i = 0; i < length; i++) {
54964 output += isFunction(array[i]) ? array[i].call(mom, format) : array[i];
54965 }
54966
54967 return output;
54968 };
54969 } // format date using native date object
54970
54971
54972 function formatMoment(m, format) {
54973 if (!m.isValid()) {
54974 return m.localeData().invalidDate();
54975 }
54976
54977 format = expandFormat(format, m.localeData());
54978 formatFunctions[format] = formatFunctions[format] || makeFormatFunction(format);
54979 return formatFunctions[format](m);
54980 }
54981
54982 function expandFormat(format, locale) {
54983 var i = 5;
54984
54985 function replaceLongDateFormatTokens(input) {
54986 return locale.longDateFormat(input) || input;
54987 }
54988
54989 localFormattingTokens.lastIndex = 0;
54990
54991 while (i >= 0 && localFormattingTokens.test(format)) {
54992 format = format.replace(localFormattingTokens, replaceLongDateFormatTokens);
54993 localFormattingTokens.lastIndex = 0;
54994 i -= 1;
54995 }
54996
54997 return format;
54998 }
54999
55000 var match1 = /\d/; // 0 - 9
55001
55002 var match2 = /\d\d/; // 00 - 99
55003
55004 var match3 = /\d{3}/; // 000 - 999
55005
55006 var match4 = /\d{4}/; // 0000 - 9999
55007
55008 var match6 = /[+-]?\d{6}/; // -999999 - 999999
55009
55010 var match1to2 = /\d\d?/; // 0 - 99
55011
55012 var match3to4 = /\d\d\d\d?/; // 999 - 9999
55013
55014 var match5to6 = /\d\d\d\d\d\d?/; // 99999 - 999999
55015
55016 var match1to3 = /\d{1,3}/; // 0 - 999
55017
55018 var match1to4 = /\d{1,4}/; // 0 - 9999
55019
55020 var match1to6 = /[+-]?\d{1,6}/; // -999999 - 999999
55021
55022 var matchUnsigned = /\d+/; // 0 - inf
55023
55024 var matchSigned = /[+-]?\d+/; // -inf - inf
55025
55026 var matchOffset = /Z|[+-]\d\d:?\d\d/gi; // +00:00 -00:00 +0000 -0000 or Z
55027
55028 var matchShortOffset = /Z|[+-]\d\d(?::?\d\d)?/gi; // +00 -00 +00:00 -00:00 +0000 -0000 or Z
55029
55030 var matchTimestamp = /[+-]?\d+(\.\d{1,3})?/; // 123456789 123456789.123
55031 // any word (or two) characters or numbers including two/three word month in arabic.
55032 // includes scottish gaelic two word and hyphenated months
55033
55034 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;
55035 var regexes = {};
55036
55037 function addRegexToken(token, regex, strictRegex) {
55038 regexes[token] = isFunction(regex) ? regex : function (isStrict, localeData) {
55039 return isStrict && strictRegex ? strictRegex : regex;
55040 };
55041 }
55042
55043 function getParseRegexForToken(token, config) {
55044 if (!hasOwnProp(regexes, token)) {
55045 return new RegExp(unescapeFormat(token));
55046 }
55047
55048 return regexes[token](config._strict, config._locale);
55049 } // Code from http://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript
55050
55051
55052 function unescapeFormat(s) {
55053 return regexEscape(s.replace('\\', '').replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g, function (matched, p1, p2, p3, p4) {
55054 return p1 || p2 || p3 || p4;
55055 }));
55056 }
55057
55058 function regexEscape(s) {
55059 return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
55060 }
55061
55062 var tokens = {};
55063
55064 function addParseToken(token, callback) {
55065 var i,
55066 func = callback;
55067
55068 if (typeof token === 'string') {
55069 token = [token];
55070 }
55071
55072 if (isNumber(callback)) {
55073 func = function (input, array) {
55074 array[callback] = toInt(input);
55075 };
55076 }
55077
55078 for (i = 0; i < token.length; i++) {
55079 tokens[token[i]] = func;
55080 }
55081 }
55082
55083 function addWeekParseToken(token, callback) {
55084 addParseToken(token, function (input, array, config, token) {
55085 config._w = config._w || {};
55086 callback(input, config._w, config, token);
55087 });
55088 }
55089
55090 function addTimeToArrayFromToken(token, input, config) {
55091 if (input != null && hasOwnProp(tokens, token)) {
55092 tokens[token](input, config._a, config, token);
55093 }
55094 }
55095
55096 var YEAR = 0;
55097 var MONTH = 1;
55098 var DATE = 2;
55099 var HOUR = 3;
55100 var MINUTE = 4;
55101 var SECOND = 5;
55102 var MILLISECOND = 6;
55103 var WEEK = 7;
55104 var WEEKDAY = 8; // FORMATTING
55105
55106 addFormatToken('Y', 0, 0, function () {
55107 var y = this.year();
55108 return y <= 9999 ? '' + y : '+' + y;
55109 });
55110 addFormatToken(0, ['YY', 2], 0, function () {
55111 return this.year() % 100;
55112 });
55113 addFormatToken(0, ['YYYY', 4], 0, 'year');
55114 addFormatToken(0, ['YYYYY', 5], 0, 'year');
55115 addFormatToken(0, ['YYYYYY', 6, true], 0, 'year'); // ALIASES
55116
55117 addUnitAlias('year', 'y'); // PRIORITIES
55118
55119 addUnitPriority('year', 1); // PARSING
55120
55121 addRegexToken('Y', matchSigned);
55122 addRegexToken('YY', match1to2, match2);
55123 addRegexToken('YYYY', match1to4, match4);
55124 addRegexToken('YYYYY', match1to6, match6);
55125 addRegexToken('YYYYYY', match1to6, match6);
55126 addParseToken(['YYYYY', 'YYYYYY'], YEAR);
55127 addParseToken('YYYY', function (input, array) {
55128 array[YEAR] = input.length === 2 ? hooks.parseTwoDigitYear(input) : toInt(input);
55129 });
55130 addParseToken('YY', function (input, array) {
55131 array[YEAR] = hooks.parseTwoDigitYear(input);
55132 });
55133 addParseToken('Y', function (input, array) {
55134 array[YEAR] = parseInt(input, 10);
55135 }); // HELPERS
55136
55137 function daysInYear(year) {
55138 return isLeapYear(year) ? 366 : 365;
55139 }
55140
55141 function isLeapYear(year) {
55142 return year % 4 === 0 && year % 100 !== 0 || year % 400 === 0;
55143 } // HOOKS
55144
55145
55146 hooks.parseTwoDigitYear = function (input) {
55147 return toInt(input) + (toInt(input) > 68 ? 1900 : 2000);
55148 }; // MOMENTS
55149
55150
55151 var getSetYear = makeGetSet('FullYear', true);
55152
55153 function getIsLeapYear() {
55154 return isLeapYear(this.year());
55155 }
55156
55157 function makeGetSet(unit, keepTime) {
55158 return function (value) {
55159 if (value != null) {
55160 set$1(this, unit, value);
55161 hooks.updateOffset(this, keepTime);
55162 return this;
55163 } else {
55164 return get(this, unit);
55165 }
55166 };
55167 }
55168
55169 function get(mom, unit) {
55170 return mom.isValid() ? mom._d['get' + (mom._isUTC ? 'UTC' : '') + unit]() : NaN;
55171 }
55172
55173 function set$1(mom, unit, value) {
55174 if (mom.isValid() && !isNaN(value)) {
55175 if (unit === 'FullYear' && isLeapYear(mom.year()) && mom.month() === 1 && mom.date() === 29) {
55176 mom._d['set' + (mom._isUTC ? 'UTC' : '') + unit](value, mom.month(), daysInMonth(value, mom.month()));
55177 } else {
55178 mom._d['set' + (mom._isUTC ? 'UTC' : '') + unit](value);
55179 }
55180 }
55181 } // MOMENTS
55182
55183
55184 function stringGet(units) {
55185 units = normalizeUnits(units);
55186
55187 if (isFunction(this[units])) {
55188 return this[units]();
55189 }
55190
55191 return this;
55192 }
55193
55194 function stringSet(units, value) {
55195 if (typeof units === 'object') {
55196 units = normalizeObjectUnits(units);
55197 var prioritized = getPrioritizedUnits(units);
55198
55199 for (var i = 0; i < prioritized.length; i++) {
55200 this[prioritized[i].unit](units[prioritized[i].unit]);
55201 }
55202 } else {
55203 units = normalizeUnits(units);
55204
55205 if (isFunction(this[units])) {
55206 return this[units](value);
55207 }
55208 }
55209
55210 return this;
55211 }
55212
55213 function mod(n, x) {
55214 return (n % x + x) % x;
55215 }
55216
55217 var indexOf;
55218
55219 if (Array.prototype.indexOf) {
55220 indexOf = Array.prototype.indexOf;
55221 } else {
55222 indexOf = function (o) {
55223 // I know
55224 var i;
55225
55226 for (i = 0; i < this.length; ++i) {
55227 if (this[i] === o) {
55228 return i;
55229 }
55230 }
55231
55232 return -1;
55233 };
55234 }
55235
55236 function daysInMonth(year, month) {
55237 if (isNaN(year) || isNaN(month)) {
55238 return NaN;
55239 }
55240
55241 var modMonth = mod(month, 12);
55242 year += (month - modMonth) / 12;
55243 return modMonth === 1 ? isLeapYear(year) ? 29 : 28 : 31 - modMonth % 7 % 2;
55244 } // FORMATTING
55245
55246
55247 addFormatToken('M', ['MM', 2], 'Mo', function () {
55248 return this.month() + 1;
55249 });
55250 addFormatToken('MMM', 0, 0, function (format) {
55251 return this.localeData().monthsShort(this, format);
55252 });
55253 addFormatToken('MMMM', 0, 0, function (format) {
55254 return this.localeData().months(this, format);
55255 }); // ALIASES
55256
55257 addUnitAlias('month', 'M'); // PRIORITY
55258
55259 addUnitPriority('month', 8); // PARSING
55260
55261 addRegexToken('M', match1to2);
55262 addRegexToken('MM', match1to2, match2);
55263 addRegexToken('MMM', function (isStrict, locale) {
55264 return locale.monthsShortRegex(isStrict);
55265 });
55266 addRegexToken('MMMM', function (isStrict, locale) {
55267 return locale.monthsRegex(isStrict);
55268 });
55269 addParseToken(['M', 'MM'], function (input, array) {
55270 array[MONTH] = toInt(input) - 1;
55271 });
55272 addParseToken(['MMM', 'MMMM'], function (input, array, config, token) {
55273 var month = config._locale.monthsParse(input, token, config._strict); // if we didn't find a month name, mark the date as invalid.
55274
55275
55276 if (month != null) {
55277 array[MONTH] = month;
55278 } else {
55279 getParsingFlags(config).invalidMonth = input;
55280 }
55281 }); // LOCALES
55282
55283 var MONTHS_IN_FORMAT = /D[oD]?(\[[^\[\]]*\]|\s)+MMMM?/;
55284 var defaultLocaleMonths = 'January_February_March_April_May_June_July_August_September_October_November_December'.split('_');
55285
55286 function localeMonths(m, format) {
55287 if (!m) {
55288 return isArray(this._months) ? this._months : this._months['standalone'];
55289 }
55290
55291 return isArray(this._months) ? this._months[m.month()] : this._months[(this._months.isFormat || MONTHS_IN_FORMAT).test(format) ? 'format' : 'standalone'][m.month()];
55292 }
55293
55294 var defaultLocaleMonthsShort = 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_');
55295
55296 function localeMonthsShort(m, format) {
55297 if (!m) {
55298 return isArray(this._monthsShort) ? this._monthsShort : this._monthsShort['standalone'];
55299 }
55300
55301 return isArray(this._monthsShort) ? this._monthsShort[m.month()] : this._monthsShort[MONTHS_IN_FORMAT.test(format) ? 'format' : 'standalone'][m.month()];
55302 }
55303
55304 function handleStrictParse(monthName, format, strict) {
55305 var i,
55306 ii,
55307 mom,
55308 llc = monthName.toLocaleLowerCase();
55309
55310 if (!this._monthsParse) {
55311 // this is not used
55312 this._monthsParse = [];
55313 this._longMonthsParse = [];
55314 this._shortMonthsParse = [];
55315
55316 for (i = 0; i < 12; ++i) {
55317 mom = createUTC([2000, i]);
55318 this._shortMonthsParse[i] = this.monthsShort(mom, '').toLocaleLowerCase();
55319 this._longMonthsParse[i] = this.months(mom, '').toLocaleLowerCase();
55320 }
55321 }
55322
55323 if (strict) {
55324 if (format === 'MMM') {
55325 ii = indexOf.call(this._shortMonthsParse, llc);
55326 return ii !== -1 ? ii : null;
55327 } else {
55328 ii = indexOf.call(this._longMonthsParse, llc);
55329 return ii !== -1 ? ii : null;
55330 }
55331 } else {
55332 if (format === 'MMM') {
55333 ii = indexOf.call(this._shortMonthsParse, llc);
55334
55335 if (ii !== -1) {
55336 return ii;
55337 }
55338
55339 ii = indexOf.call(this._longMonthsParse, llc);
55340 return ii !== -1 ? ii : null;
55341 } else {
55342 ii = indexOf.call(this._longMonthsParse, llc);
55343
55344 if (ii !== -1) {
55345 return ii;
55346 }
55347
55348 ii = indexOf.call(this._shortMonthsParse, llc);
55349 return ii !== -1 ? ii : null;
55350 }
55351 }
55352 }
55353
55354 function localeMonthsParse(monthName, format, strict) {
55355 var i, mom, regex;
55356
55357 if (this._monthsParseExact) {
55358 return handleStrictParse.call(this, monthName, format, strict);
55359 }
55360
55361 if (!this._monthsParse) {
55362 this._monthsParse = [];
55363 this._longMonthsParse = [];
55364 this._shortMonthsParse = [];
55365 } // TODO: add sorting
55366 // Sorting makes sure if one month (or abbr) is a prefix of another
55367 // see sorting in computeMonthsParse
55368
55369
55370 for (i = 0; i < 12; i++) {
55371 // make the regex if we don't have it already
55372 mom = createUTC([2000, i]);
55373
55374 if (strict && !this._longMonthsParse[i]) {
55375 this._longMonthsParse[i] = new RegExp('^' + this.months(mom, '').replace('.', '') + '$', 'i');
55376 this._shortMonthsParse[i] = new RegExp('^' + this.monthsShort(mom, '').replace('.', '') + '$', 'i');
55377 }
55378
55379 if (!strict && !this._monthsParse[i]) {
55380 regex = '^' + this.months(mom, '') + '|^' + this.monthsShort(mom, '');
55381 this._monthsParse[i] = new RegExp(regex.replace('.', ''), 'i');
55382 } // test the regex
55383
55384
55385 if (strict && format === 'MMMM' && this._longMonthsParse[i].test(monthName)) {
55386 return i;
55387 } else if (strict && format === 'MMM' && this._shortMonthsParse[i].test(monthName)) {
55388 return i;
55389 } else if (!strict && this._monthsParse[i].test(monthName)) {
55390 return i;
55391 }
55392 }
55393 } // MOMENTS
55394
55395
55396 function setMonth(mom, value) {
55397 var dayOfMonth;
55398
55399 if (!mom.isValid()) {
55400 // No op
55401 return mom;
55402 }
55403
55404 if (typeof value === 'string') {
55405 if (/^\d+$/.test(value)) {
55406 value = toInt(value);
55407 } else {
55408 value = mom.localeData().monthsParse(value); // TODO: Another silent failure?
55409
55410 if (!isNumber(value)) {
55411 return mom;
55412 }
55413 }
55414 }
55415
55416 dayOfMonth = Math.min(mom.date(), daysInMonth(mom.year(), value));
55417
55418 mom._d['set' + (mom._isUTC ? 'UTC' : '') + 'Month'](value, dayOfMonth);
55419
55420 return mom;
55421 }
55422
55423 function getSetMonth(value) {
55424 if (value != null) {
55425 setMonth(this, value);
55426 hooks.updateOffset(this, true);
55427 return this;
55428 } else {
55429 return get(this, 'Month');
55430 }
55431 }
55432
55433 function getDaysInMonth() {
55434 return daysInMonth(this.year(), this.month());
55435 }
55436
55437 var defaultMonthsShortRegex = matchWord;
55438
55439 function monthsShortRegex(isStrict) {
55440 if (this._monthsParseExact) {
55441 if (!hasOwnProp(this, '_monthsRegex')) {
55442 computeMonthsParse.call(this);
55443 }
55444
55445 if (isStrict) {
55446 return this._monthsShortStrictRegex;
55447 } else {
55448 return this._monthsShortRegex;
55449 }
55450 } else {
55451 if (!hasOwnProp(this, '_monthsShortRegex')) {
55452 this._monthsShortRegex = defaultMonthsShortRegex;
55453 }
55454
55455 return this._monthsShortStrictRegex && isStrict ? this._monthsShortStrictRegex : this._monthsShortRegex;
55456 }
55457 }
55458
55459 var defaultMonthsRegex = matchWord;
55460
55461 function monthsRegex(isStrict) {
55462 if (this._monthsParseExact) {
55463 if (!hasOwnProp(this, '_monthsRegex')) {
55464 computeMonthsParse.call(this);
55465 }
55466
55467 if (isStrict) {
55468 return this._monthsStrictRegex;
55469 } else {
55470 return this._monthsRegex;
55471 }
55472 } else {
55473 if (!hasOwnProp(this, '_monthsRegex')) {
55474 this._monthsRegex = defaultMonthsRegex;
55475 }
55476
55477 return this._monthsStrictRegex && isStrict ? this._monthsStrictRegex : this._monthsRegex;
55478 }
55479 }
55480
55481 function computeMonthsParse() {
55482 function cmpLenRev(a, b) {
55483 return b.length - a.length;
55484 }
55485
55486 var shortPieces = [],
55487 longPieces = [],
55488 mixedPieces = [],
55489 i,
55490 mom;
55491
55492 for (i = 0; i < 12; i++) {
55493 // make the regex if we don't have it already
55494 mom = createUTC([2000, i]);
55495 shortPieces.push(this.monthsShort(mom, ''));
55496 longPieces.push(this.months(mom, ''));
55497 mixedPieces.push(this.months(mom, ''));
55498 mixedPieces.push(this.monthsShort(mom, ''));
55499 } // Sorting makes sure if one month (or abbr) is a prefix of another it
55500 // will match the longer piece.
55501
55502
55503 shortPieces.sort(cmpLenRev);
55504 longPieces.sort(cmpLenRev);
55505 mixedPieces.sort(cmpLenRev);
55506
55507 for (i = 0; i < 12; i++) {
55508 shortPieces[i] = regexEscape(shortPieces[i]);
55509 longPieces[i] = regexEscape(longPieces[i]);
55510 }
55511
55512 for (i = 0; i < 24; i++) {
55513 mixedPieces[i] = regexEscape(mixedPieces[i]);
55514 }
55515
55516 this._monthsRegex = new RegExp('^(' + mixedPieces.join('|') + ')', 'i');
55517 this._monthsShortRegex = this._monthsRegex;
55518 this._monthsStrictRegex = new RegExp('^(' + longPieces.join('|') + ')', 'i');
55519 this._monthsShortStrictRegex = new RegExp('^(' + shortPieces.join('|') + ')', 'i');
55520 }
55521
55522 function createDate(y, m, d, h, M, s, ms) {
55523 // can't just apply() to create a date:
55524 // https://stackoverflow.com/q/181348
55525 var date; // the date constructor remaps years 0-99 to 1900-1999
55526
55527 if (y < 100 && y >= 0) {
55528 // preserve leap years using a full 400 year cycle, then reset
55529 date = new Date(y + 400, m, d, h, M, s, ms);
55530
55531 if (isFinite(date.getFullYear())) {
55532 date.setFullYear(y);
55533 }
55534 } else {
55535 date = new Date(y, m, d, h, M, s, ms);
55536 }
55537
55538 return date;
55539 }
55540
55541 function createUTCDate(y) {
55542 var date; // the Date.UTC function remaps years 0-99 to 1900-1999
55543
55544 if (y < 100 && y >= 0) {
55545 var args = Array.prototype.slice.call(arguments); // preserve leap years using a full 400 year cycle, then reset
55546
55547 args[0] = y + 400;
55548 date = new Date(Date.UTC.apply(null, args));
55549
55550 if (isFinite(date.getUTCFullYear())) {
55551 date.setUTCFullYear(y);
55552 }
55553 } else {
55554 date = new Date(Date.UTC.apply(null, arguments));
55555 }
55556
55557 return date;
55558 } // start-of-first-week - start-of-year
55559
55560
55561 function firstWeekOffset(year, dow, doy) {
55562 var // first-week day -- which january is always in the first week (4 for iso, 1 for other)
55563 fwd = 7 + dow - doy,
55564 // first-week day local weekday -- which local weekday is fwd
55565 fwdlw = (7 + createUTCDate(year, 0, fwd).getUTCDay() - dow) % 7;
55566 return -fwdlw + fwd - 1;
55567 } // https://en.wikipedia.org/wiki/ISO_week_date#Calculating_a_date_given_the_year.2C_week_number_and_weekday
55568
55569
55570 function dayOfYearFromWeeks(year, week, weekday, dow, doy) {
55571 var localWeekday = (7 + weekday - dow) % 7,
55572 weekOffset = firstWeekOffset(year, dow, doy),
55573 dayOfYear = 1 + 7 * (week - 1) + localWeekday + weekOffset,
55574 resYear,
55575 resDayOfYear;
55576
55577 if (dayOfYear <= 0) {
55578 resYear = year - 1;
55579 resDayOfYear = daysInYear(resYear) + dayOfYear;
55580 } else if (dayOfYear > daysInYear(year)) {
55581 resYear = year + 1;
55582 resDayOfYear = dayOfYear - daysInYear(year);
55583 } else {
55584 resYear = year;
55585 resDayOfYear = dayOfYear;
55586 }
55587
55588 return {
55589 year: resYear,
55590 dayOfYear: resDayOfYear
55591 };
55592 }
55593
55594 function weekOfYear(mom, dow, doy) {
55595 var weekOffset = firstWeekOffset(mom.year(), dow, doy),
55596 week = Math.floor((mom.dayOfYear() - weekOffset - 1) / 7) + 1,
55597 resWeek,
55598 resYear;
55599
55600 if (week < 1) {
55601 resYear = mom.year() - 1;
55602 resWeek = week + weeksInYear(resYear, dow, doy);
55603 } else if (week > weeksInYear(mom.year(), dow, doy)) {
55604 resWeek = week - weeksInYear(mom.year(), dow, doy);
55605 resYear = mom.year() + 1;
55606 } else {
55607 resYear = mom.year();
55608 resWeek = week;
55609 }
55610
55611 return {
55612 week: resWeek,
55613 year: resYear
55614 };
55615 }
55616
55617 function weeksInYear(year, dow, doy) {
55618 var weekOffset = firstWeekOffset(year, dow, doy),
55619 weekOffsetNext = firstWeekOffset(year + 1, dow, doy);
55620 return (daysInYear(year) - weekOffset + weekOffsetNext) / 7;
55621 } // FORMATTING
55622
55623
55624 addFormatToken('w', ['ww', 2], 'wo', 'week');
55625 addFormatToken('W', ['WW', 2], 'Wo', 'isoWeek'); // ALIASES
55626
55627 addUnitAlias('week', 'w');
55628 addUnitAlias('isoWeek', 'W'); // PRIORITIES
55629
55630 addUnitPriority('week', 5);
55631 addUnitPriority('isoWeek', 5); // PARSING
55632
55633 addRegexToken('w', match1to2);
55634 addRegexToken('ww', match1to2, match2);
55635 addRegexToken('W', match1to2);
55636 addRegexToken('WW', match1to2, match2);
55637 addWeekParseToken(['w', 'ww', 'W', 'WW'], function (input, week, config, token) {
55638 week[token.substr(0, 1)] = toInt(input);
55639 }); // HELPERS
55640 // LOCALES
55641
55642 function localeWeek(mom) {
55643 return weekOfYear(mom, this._week.dow, this._week.doy).week;
55644 }
55645
55646 var defaultLocaleWeek = {
55647 dow: 0,
55648 // Sunday is the first day of the week.
55649 doy: 6 // The week that contains Jan 6th is the first week of the year.
55650
55651 };
55652
55653 function localeFirstDayOfWeek() {
55654 return this._week.dow;
55655 }
55656
55657 function localeFirstDayOfYear() {
55658 return this._week.doy;
55659 } // MOMENTS
55660
55661
55662 function getSetWeek(input) {
55663 var week = this.localeData().week(this);
55664 return input == null ? week : this.add((input - week) * 7, 'd');
55665 }
55666
55667 function getSetISOWeek(input) {
55668 var week = weekOfYear(this, 1, 4).week;
55669 return input == null ? week : this.add((input - week) * 7, 'd');
55670 } // FORMATTING
55671
55672
55673 addFormatToken('d', 0, 'do', 'day');
55674 addFormatToken('dd', 0, 0, function (format) {
55675 return this.localeData().weekdaysMin(this, format);
55676 });
55677 addFormatToken('ddd', 0, 0, function (format) {
55678 return this.localeData().weekdaysShort(this, format);
55679 });
55680 addFormatToken('dddd', 0, 0, function (format) {
55681 return this.localeData().weekdays(this, format);
55682 });
55683 addFormatToken('e', 0, 0, 'weekday');
55684 addFormatToken('E', 0, 0, 'isoWeekday'); // ALIASES
55685
55686 addUnitAlias('day', 'd');
55687 addUnitAlias('weekday', 'e');
55688 addUnitAlias('isoWeekday', 'E'); // PRIORITY
55689
55690 addUnitPriority('day', 11);
55691 addUnitPriority('weekday', 11);
55692 addUnitPriority('isoWeekday', 11); // PARSING
55693
55694 addRegexToken('d', match1to2);
55695 addRegexToken('e', match1to2);
55696 addRegexToken('E', match1to2);
55697 addRegexToken('dd', function (isStrict, locale) {
55698 return locale.weekdaysMinRegex(isStrict);
55699 });
55700 addRegexToken('ddd', function (isStrict, locale) {
55701 return locale.weekdaysShortRegex(isStrict);
55702 });
55703 addRegexToken('dddd', function (isStrict, locale) {
55704 return locale.weekdaysRegex(isStrict);
55705 });
55706 addWeekParseToken(['dd', 'ddd', 'dddd'], function (input, week, config, token) {
55707 var weekday = config._locale.weekdaysParse(input, token, config._strict); // if we didn't get a weekday name, mark the date as invalid
55708
55709
55710 if (weekday != null) {
55711 week.d = weekday;
55712 } else {
55713 getParsingFlags(config).invalidWeekday = input;
55714 }
55715 });
55716 addWeekParseToken(['d', 'e', 'E'], function (input, week, config, token) {
55717 week[token] = toInt(input);
55718 }); // HELPERS
55719
55720 function parseWeekday(input, locale) {
55721 if (typeof input !== 'string') {
55722 return input;
55723 }
55724
55725 if (!isNaN(input)) {
55726 return parseInt(input, 10);
55727 }
55728
55729 input = locale.weekdaysParse(input);
55730
55731 if (typeof input === 'number') {
55732 return input;
55733 }
55734
55735 return null;
55736 }
55737
55738 function parseIsoWeekday(input, locale) {
55739 if (typeof input === 'string') {
55740 return locale.weekdaysParse(input) % 7 || 7;
55741 }
55742
55743 return isNaN(input) ? null : input;
55744 } // LOCALES
55745
55746
55747 function shiftWeekdays(ws, n) {
55748 return ws.slice(n, 7).concat(ws.slice(0, n));
55749 }
55750
55751 var defaultLocaleWeekdays = 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_');
55752
55753 function localeWeekdays(m, format) {
55754 var weekdays = isArray(this._weekdays) ? this._weekdays : this._weekdays[m && m !== true && this._weekdays.isFormat.test(format) ? 'format' : 'standalone'];
55755 return m === true ? shiftWeekdays(weekdays, this._week.dow) : m ? weekdays[m.day()] : weekdays;
55756 }
55757
55758 var defaultLocaleWeekdaysShort = 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_');
55759
55760 function localeWeekdaysShort(m) {
55761 return m === true ? shiftWeekdays(this._weekdaysShort, this._week.dow) : m ? this._weekdaysShort[m.day()] : this._weekdaysShort;
55762 }
55763
55764 var defaultLocaleWeekdaysMin = 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_');
55765
55766 function localeWeekdaysMin(m) {
55767 return m === true ? shiftWeekdays(this._weekdaysMin, this._week.dow) : m ? this._weekdaysMin[m.day()] : this._weekdaysMin;
55768 }
55769
55770 function handleStrictParse$1(weekdayName, format, strict) {
55771 var i,
55772 ii,
55773 mom,
55774 llc = weekdayName.toLocaleLowerCase();
55775
55776 if (!this._weekdaysParse) {
55777 this._weekdaysParse = [];
55778 this._shortWeekdaysParse = [];
55779 this._minWeekdaysParse = [];
55780
55781 for (i = 0; i < 7; ++i) {
55782 mom = createUTC([2000, 1]).day(i);
55783 this._minWeekdaysParse[i] = this.weekdaysMin(mom, '').toLocaleLowerCase();
55784 this._shortWeekdaysParse[i] = this.weekdaysShort(mom, '').toLocaleLowerCase();
55785 this._weekdaysParse[i] = this.weekdays(mom, '').toLocaleLowerCase();
55786 }
55787 }
55788
55789 if (strict) {
55790 if (format === 'dddd') {
55791 ii = indexOf.call(this._weekdaysParse, llc);
55792 return ii !== -1 ? ii : null;
55793 } else if (format === 'ddd') {
55794 ii = indexOf.call(this._shortWeekdaysParse, llc);
55795 return ii !== -1 ? ii : null;
55796 } else {
55797 ii = indexOf.call(this._minWeekdaysParse, llc);
55798 return ii !== -1 ? ii : null;
55799 }
55800 } else {
55801 if (format === 'dddd') {
55802 ii = indexOf.call(this._weekdaysParse, llc);
55803
55804 if (ii !== -1) {
55805 return ii;
55806 }
55807
55808 ii = indexOf.call(this._shortWeekdaysParse, llc);
55809
55810 if (ii !== -1) {
55811 return ii;
55812 }
55813
55814 ii = indexOf.call(this._minWeekdaysParse, llc);
55815 return ii !== -1 ? ii : null;
55816 } else if (format === 'ddd') {
55817 ii = indexOf.call(this._shortWeekdaysParse, llc);
55818
55819 if (ii !== -1) {
55820 return ii;
55821 }
55822
55823 ii = indexOf.call(this._weekdaysParse, llc);
55824
55825 if (ii !== -1) {
55826 return ii;
55827 }
55828
55829 ii = indexOf.call(this._minWeekdaysParse, llc);
55830 return ii !== -1 ? ii : null;
55831 } else {
55832 ii = indexOf.call(this._minWeekdaysParse, llc);
55833
55834 if (ii !== -1) {
55835 return ii;
55836 }
55837
55838 ii = indexOf.call(this._weekdaysParse, llc);
55839
55840 if (ii !== -1) {
55841 return ii;
55842 }
55843
55844 ii = indexOf.call(this._shortWeekdaysParse, llc);
55845 return ii !== -1 ? ii : null;
55846 }
55847 }
55848 }
55849
55850 function localeWeekdaysParse(weekdayName, format, strict) {
55851 var i, mom, regex;
55852
55853 if (this._weekdaysParseExact) {
55854 return handleStrictParse$1.call(this, weekdayName, format, strict);
55855 }
55856
55857 if (!this._weekdaysParse) {
55858 this._weekdaysParse = [];
55859 this._minWeekdaysParse = [];
55860 this._shortWeekdaysParse = [];
55861 this._fullWeekdaysParse = [];
55862 }
55863
55864 for (i = 0; i < 7; i++) {
55865 // make the regex if we don't have it already
55866 mom = createUTC([2000, 1]).day(i);
55867
55868 if (strict && !this._fullWeekdaysParse[i]) {
55869 this._fullWeekdaysParse[i] = new RegExp('^' + this.weekdays(mom, '').replace('.', '\\.?') + '$', 'i');
55870 this._shortWeekdaysParse[i] = new RegExp('^' + this.weekdaysShort(mom, '').replace('.', '\\.?') + '$', 'i');
55871 this._minWeekdaysParse[i] = new RegExp('^' + this.weekdaysMin(mom, '').replace('.', '\\.?') + '$', 'i');
55872 }
55873
55874 if (!this._weekdaysParse[i]) {
55875 regex = '^' + this.weekdays(mom, '') + '|^' + this.weekdaysShort(mom, '') + '|^' + this.weekdaysMin(mom, '');
55876 this._weekdaysParse[i] = new RegExp(regex.replace('.', ''), 'i');
55877 } // test the regex
55878
55879
55880 if (strict && format === 'dddd' && this._fullWeekdaysParse[i].test(weekdayName)) {
55881 return i;
55882 } else if (strict && format === 'ddd' && this._shortWeekdaysParse[i].test(weekdayName)) {
55883 return i;
55884 } else if (strict && format === 'dd' && this._minWeekdaysParse[i].test(weekdayName)) {
55885 return i;
55886 } else if (!strict && this._weekdaysParse[i].test(weekdayName)) {
55887 return i;
55888 }
55889 }
55890 } // MOMENTS
55891
55892
55893 function getSetDayOfWeek(input) {
55894 if (!this.isValid()) {
55895 return input != null ? this : NaN;
55896 }
55897
55898 var day = this._isUTC ? this._d.getUTCDay() : this._d.getDay();
55899
55900 if (input != null) {
55901 input = parseWeekday(input, this.localeData());
55902 return this.add(input - day, 'd');
55903 } else {
55904 return day;
55905 }
55906 }
55907
55908 function getSetLocaleDayOfWeek(input) {
55909 if (!this.isValid()) {
55910 return input != null ? this : NaN;
55911 }
55912
55913 var weekday = (this.day() + 7 - this.localeData()._week.dow) % 7;
55914 return input == null ? weekday : this.add(input - weekday, 'd');
55915 }
55916
55917 function getSetISODayOfWeek(input) {
55918 if (!this.isValid()) {
55919 return input != null ? this : NaN;
55920 } // behaves the same as moment#day except
55921 // as a getter, returns 7 instead of 0 (1-7 range instead of 0-6)
55922 // as a setter, sunday should belong to the previous week.
55923
55924
55925 if (input != null) {
55926 var weekday = parseIsoWeekday(input, this.localeData());
55927 return this.day(this.day() % 7 ? weekday : weekday - 7);
55928 } else {
55929 return this.day() || 7;
55930 }
55931 }
55932
55933 var defaultWeekdaysRegex = matchWord;
55934
55935 function weekdaysRegex(isStrict) {
55936 if (this._weekdaysParseExact) {
55937 if (!hasOwnProp(this, '_weekdaysRegex')) {
55938 computeWeekdaysParse.call(this);
55939 }
55940
55941 if (isStrict) {
55942 return this._weekdaysStrictRegex;
55943 } else {
55944 return this._weekdaysRegex;
55945 }
55946 } else {
55947 if (!hasOwnProp(this, '_weekdaysRegex')) {
55948 this._weekdaysRegex = defaultWeekdaysRegex;
55949 }
55950
55951 return this._weekdaysStrictRegex && isStrict ? this._weekdaysStrictRegex : this._weekdaysRegex;
55952 }
55953 }
55954
55955 var defaultWeekdaysShortRegex = matchWord;
55956
55957 function weekdaysShortRegex(isStrict) {
55958 if (this._weekdaysParseExact) {
55959 if (!hasOwnProp(this, '_weekdaysRegex')) {
55960 computeWeekdaysParse.call(this);
55961 }
55962
55963 if (isStrict) {
55964 return this._weekdaysShortStrictRegex;
55965 } else {
55966 return this._weekdaysShortRegex;
55967 }
55968 } else {
55969 if (!hasOwnProp(this, '_weekdaysShortRegex')) {
55970 this._weekdaysShortRegex = defaultWeekdaysShortRegex;
55971 }
55972
55973 return this._weekdaysShortStrictRegex && isStrict ? this._weekdaysShortStrictRegex : this._weekdaysShortRegex;
55974 }
55975 }
55976
55977 var defaultWeekdaysMinRegex = matchWord;
55978
55979 function weekdaysMinRegex(isStrict) {
55980 if (this._weekdaysParseExact) {
55981 if (!hasOwnProp(this, '_weekdaysRegex')) {
55982 computeWeekdaysParse.call(this);
55983 }
55984
55985 if (isStrict) {
55986 return this._weekdaysMinStrictRegex;
55987 } else {
55988 return this._weekdaysMinRegex;
55989 }
55990 } else {
55991 if (!hasOwnProp(this, '_weekdaysMinRegex')) {
55992 this._weekdaysMinRegex = defaultWeekdaysMinRegex;
55993 }
55994
55995 return this._weekdaysMinStrictRegex && isStrict ? this._weekdaysMinStrictRegex : this._weekdaysMinRegex;
55996 }
55997 }
55998
55999 function computeWeekdaysParse() {
56000 function cmpLenRev(a, b) {
56001 return b.length - a.length;
56002 }
56003
56004 var minPieces = [],
56005 shortPieces = [],
56006 longPieces = [],
56007 mixedPieces = [],
56008 i,
56009 mom,
56010 minp,
56011 shortp,
56012 longp;
56013
56014 for (i = 0; i < 7; i++) {
56015 // make the regex if we don't have it already
56016 mom = createUTC([2000, 1]).day(i);
56017 minp = this.weekdaysMin(mom, '');
56018 shortp = this.weekdaysShort(mom, '');
56019 longp = this.weekdays(mom, '');
56020 minPieces.push(minp);
56021 shortPieces.push(shortp);
56022 longPieces.push(longp);
56023 mixedPieces.push(minp);
56024 mixedPieces.push(shortp);
56025 mixedPieces.push(longp);
56026 } // Sorting makes sure if one weekday (or abbr) is a prefix of another it
56027 // will match the longer piece.
56028
56029
56030 minPieces.sort(cmpLenRev);
56031 shortPieces.sort(cmpLenRev);
56032 longPieces.sort(cmpLenRev);
56033 mixedPieces.sort(cmpLenRev);
56034
56035 for (i = 0; i < 7; i++) {
56036 shortPieces[i] = regexEscape(shortPieces[i]);
56037 longPieces[i] = regexEscape(longPieces[i]);
56038 mixedPieces[i] = regexEscape(mixedPieces[i]);
56039 }
56040
56041 this._weekdaysRegex = new RegExp('^(' + mixedPieces.join('|') + ')', 'i');
56042 this._weekdaysShortRegex = this._weekdaysRegex;
56043 this._weekdaysMinRegex = this._weekdaysRegex;
56044 this._weekdaysStrictRegex = new RegExp('^(' + longPieces.join('|') + ')', 'i');
56045 this._weekdaysShortStrictRegex = new RegExp('^(' + shortPieces.join('|') + ')', 'i');
56046 this._weekdaysMinStrictRegex = new RegExp('^(' + minPieces.join('|') + ')', 'i');
56047 } // FORMATTING
56048
56049
56050 function hFormat() {
56051 return this.hours() % 12 || 12;
56052 }
56053
56054 function kFormat() {
56055 return this.hours() || 24;
56056 }
56057
56058 addFormatToken('H', ['HH', 2], 0, 'hour');
56059 addFormatToken('h', ['hh', 2], 0, hFormat);
56060 addFormatToken('k', ['kk', 2], 0, kFormat);
56061 addFormatToken('hmm', 0, 0, function () {
56062 return '' + hFormat.apply(this) + zeroFill(this.minutes(), 2);
56063 });
56064 addFormatToken('hmmss', 0, 0, function () {
56065 return '' + hFormat.apply(this) + zeroFill(this.minutes(), 2) + zeroFill(this.seconds(), 2);
56066 });
56067 addFormatToken('Hmm', 0, 0, function () {
56068 return '' + this.hours() + zeroFill(this.minutes(), 2);
56069 });
56070 addFormatToken('Hmmss', 0, 0, function () {
56071 return '' + this.hours() + zeroFill(this.minutes(), 2) + zeroFill(this.seconds(), 2);
56072 });
56073
56074 function meridiem(token, lowercase) {
56075 addFormatToken(token, 0, 0, function () {
56076 return this.localeData().meridiem(this.hours(), this.minutes(), lowercase);
56077 });
56078 }
56079
56080 meridiem('a', true);
56081 meridiem('A', false); // ALIASES
56082
56083 addUnitAlias('hour', 'h'); // PRIORITY
56084
56085 addUnitPriority('hour', 13); // PARSING
56086
56087 function matchMeridiem(isStrict, locale) {
56088 return locale._meridiemParse;
56089 }
56090
56091 addRegexToken('a', matchMeridiem);
56092 addRegexToken('A', matchMeridiem);
56093 addRegexToken('H', match1to2);
56094 addRegexToken('h', match1to2);
56095 addRegexToken('k', match1to2);
56096 addRegexToken('HH', match1to2, match2);
56097 addRegexToken('hh', match1to2, match2);
56098 addRegexToken('kk', match1to2, match2);
56099 addRegexToken('hmm', match3to4);
56100 addRegexToken('hmmss', match5to6);
56101 addRegexToken('Hmm', match3to4);
56102 addRegexToken('Hmmss', match5to6);
56103 addParseToken(['H', 'HH'], HOUR);
56104 addParseToken(['k', 'kk'], function (input, array, config) {
56105 var kInput = toInt(input);
56106 array[HOUR] = kInput === 24 ? 0 : kInput;
56107 });
56108 addParseToken(['a', 'A'], function (input, array, config) {
56109 config._isPm = config._locale.isPM(input);
56110 config._meridiem = input;
56111 });
56112 addParseToken(['h', 'hh'], function (input, array, config) {
56113 array[HOUR] = toInt(input);
56114 getParsingFlags(config).bigHour = true;
56115 });
56116 addParseToken('hmm', function (input, array, config) {
56117 var pos = input.length - 2;
56118 array[HOUR] = toInt(input.substr(0, pos));
56119 array[MINUTE] = toInt(input.substr(pos));
56120 getParsingFlags(config).bigHour = true;
56121 });
56122 addParseToken('hmmss', function (input, array, config) {
56123 var pos1 = input.length - 4;
56124 var pos2 = input.length - 2;
56125 array[HOUR] = toInt(input.substr(0, pos1));
56126 array[MINUTE] = toInt(input.substr(pos1, 2));
56127 array[SECOND] = toInt(input.substr(pos2));
56128 getParsingFlags(config).bigHour = true;
56129 });
56130 addParseToken('Hmm', function (input, array, config) {
56131 var pos = input.length - 2;
56132 array[HOUR] = toInt(input.substr(0, pos));
56133 array[MINUTE] = toInt(input.substr(pos));
56134 });
56135 addParseToken('Hmmss', function (input, array, config) {
56136 var pos1 = input.length - 4;
56137 var pos2 = input.length - 2;
56138 array[HOUR] = toInt(input.substr(0, pos1));
56139 array[MINUTE] = toInt(input.substr(pos1, 2));
56140 array[SECOND] = toInt(input.substr(pos2));
56141 }); // LOCALES
56142
56143 function localeIsPM(input) {
56144 // IE8 Quirks Mode & IE7 Standards Mode do not allow accessing strings like arrays
56145 // Using charAt should be more compatible.
56146 return (input + '').toLowerCase().charAt(0) === 'p';
56147 }
56148
56149 var defaultLocaleMeridiemParse = /[ap]\.?m?\.?/i;
56150
56151 function localeMeridiem(hours, minutes, isLower) {
56152 if (hours > 11) {
56153 return isLower ? 'pm' : 'PM';
56154 } else {
56155 return isLower ? 'am' : 'AM';
56156 }
56157 } // MOMENTS
56158 // Setting the hour should keep the time, because the user explicitly
56159 // specified which hour they want. So trying to maintain the same hour (in
56160 // a new timezone) makes sense. Adding/subtracting hours does not follow
56161 // this rule.
56162
56163
56164 var getSetHour = makeGetSet('Hours', true);
56165 var baseConfig = {
56166 calendar: defaultCalendar,
56167 longDateFormat: defaultLongDateFormat,
56168 invalidDate: defaultInvalidDate,
56169 ordinal: defaultOrdinal,
56170 dayOfMonthOrdinalParse: defaultDayOfMonthOrdinalParse,
56171 relativeTime: defaultRelativeTime,
56172 months: defaultLocaleMonths,
56173 monthsShort: defaultLocaleMonthsShort,
56174 week: defaultLocaleWeek,
56175 weekdays: defaultLocaleWeekdays,
56176 weekdaysMin: defaultLocaleWeekdaysMin,
56177 weekdaysShort: defaultLocaleWeekdaysShort,
56178 meridiemParse: defaultLocaleMeridiemParse
56179 }; // internal storage for locale config files
56180
56181 var locales = {};
56182 var localeFamilies = {};
56183 var globalLocale;
56184
56185 function normalizeLocale(key) {
56186 return key ? key.toLowerCase().replace('_', '-') : key;
56187 } // pick the locale from the array
56188 // try ['en-au', 'en-gb'] as 'en-au', 'en-gb', 'en', as in move through the list trying each
56189 // substring from most specific to least, but move to the next array item if it's a more specific variant than the current root
56190
56191
56192 function chooseLocale(names) {
56193 var i = 0,
56194 j,
56195 next,
56196 locale,
56197 split;
56198
56199 while (i < names.length) {
56200 split = normalizeLocale(names[i]).split('-');
56201 j = split.length;
56202 next = normalizeLocale(names[i + 1]);
56203 next = next ? next.split('-') : null;
56204
56205 while (j > 0) {
56206 locale = loadLocale(split.slice(0, j).join('-'));
56207
56208 if (locale) {
56209 return locale;
56210 }
56211
56212 if (next && next.length >= j && compareArrays(split, next, true) >= j - 1) {
56213 //the next array item is better than a shallower substring of this one
56214 break;
56215 }
56216
56217 j--;
56218 }
56219
56220 i++;
56221 }
56222
56223 return globalLocale;
56224 }
56225
56226 function loadLocale(name) {
56227 var oldLocale = null; // TODO: Find a better way to register and load all the locales in Node
56228
56229 if (!locales[name] && 'object' !== 'undefined' && module && module.exports) {
56230 try {
56231 oldLocale = globalLocale._abbr;
56232 var aliasedRequire = commonjsRequire;
56233 aliasedRequire('./locale/' + name);
56234 getSetGlobalLocale(oldLocale);
56235 } catch (e) {}
56236 }
56237
56238 return locales[name];
56239 } // This function will load locale and then set the global locale. If
56240 // no arguments are passed in, it will simply return the current global
56241 // locale key.
56242
56243
56244 function getSetGlobalLocale(key, values) {
56245 var data;
56246
56247 if (key) {
56248 if (isUndefined(values)) {
56249 data = getLocale(key);
56250 } else {
56251 data = defineLocale(key, values);
56252 }
56253
56254 if (data) {
56255 // moment.duration._locale = moment._locale = data;
56256 globalLocale = data;
56257 } else {
56258 if (typeof console !== 'undefined' && console.warn) {
56259 //warn user if arguments are passed but the locale could not be set
56260 console.warn('Locale ' + key + ' not found. Did you forget to load it?');
56261 }
56262 }
56263 }
56264
56265 return globalLocale._abbr;
56266 }
56267
56268 function defineLocale(name, config) {
56269 if (config !== null) {
56270 var locale,
56271 parentConfig = baseConfig;
56272 config.abbr = name;
56273
56274 if (locales[name] != null) {
56275 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.');
56276 parentConfig = locales[name]._config;
56277 } else if (config.parentLocale != null) {
56278 if (locales[config.parentLocale] != null) {
56279 parentConfig = locales[config.parentLocale]._config;
56280 } else {
56281 locale = loadLocale(config.parentLocale);
56282
56283 if (locale != null) {
56284 parentConfig = locale._config;
56285 } else {
56286 if (!localeFamilies[config.parentLocale]) {
56287 localeFamilies[config.parentLocale] = [];
56288 }
56289
56290 localeFamilies[config.parentLocale].push({
56291 name: name,
56292 config: config
56293 });
56294 return null;
56295 }
56296 }
56297 }
56298
56299 locales[name] = new Locale(mergeConfigs(parentConfig, config));
56300
56301 if (localeFamilies[name]) {
56302 localeFamilies[name].forEach(function (x) {
56303 defineLocale(x.name, x.config);
56304 });
56305 } // backwards compat for now: also set the locale
56306 // make sure we set the locale AFTER all child locales have been
56307 // created, so we won't end up with the child locale set.
56308
56309
56310 getSetGlobalLocale(name);
56311 return locales[name];
56312 } else {
56313 // useful for testing
56314 delete locales[name];
56315 return null;
56316 }
56317 }
56318
56319 function updateLocale(name, config) {
56320 if (config != null) {
56321 var locale,
56322 tmpLocale,
56323 parentConfig = baseConfig; // MERGE
56324
56325 tmpLocale = loadLocale(name);
56326
56327 if (tmpLocale != null) {
56328 parentConfig = tmpLocale._config;
56329 }
56330
56331 config = mergeConfigs(parentConfig, config);
56332 locale = new Locale(config);
56333 locale.parentLocale = locales[name];
56334 locales[name] = locale; // backwards compat for now: also set the locale
56335
56336 getSetGlobalLocale(name);
56337 } else {
56338 // pass null for config to unupdate, useful for tests
56339 if (locales[name] != null) {
56340 if (locales[name].parentLocale != null) {
56341 locales[name] = locales[name].parentLocale;
56342 } else if (locales[name] != null) {
56343 delete locales[name];
56344 }
56345 }
56346 }
56347
56348 return locales[name];
56349 } // returns locale data
56350
56351
56352 function getLocale(key) {
56353 var locale;
56354
56355 if (key && key._locale && key._locale._abbr) {
56356 key = key._locale._abbr;
56357 }
56358
56359 if (!key) {
56360 return globalLocale;
56361 }
56362
56363 if (!isArray(key)) {
56364 //short-circuit everything else
56365 locale = loadLocale(key);
56366
56367 if (locale) {
56368 return locale;
56369 }
56370
56371 key = [key];
56372 }
56373
56374 return chooseLocale(key);
56375 }
56376
56377 function listLocales() {
56378 return keys(locales);
56379 }
56380
56381 function checkOverflow(m) {
56382 var overflow;
56383 var a = m._a;
56384
56385 if (a && getParsingFlags(m).overflow === -2) {
56386 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;
56387
56388 if (getParsingFlags(m)._overflowDayOfYear && (overflow < YEAR || overflow > DATE)) {
56389 overflow = DATE;
56390 }
56391
56392 if (getParsingFlags(m)._overflowWeeks && overflow === -1) {
56393 overflow = WEEK;
56394 }
56395
56396 if (getParsingFlags(m)._overflowWeekday && overflow === -1) {
56397 overflow = WEEKDAY;
56398 }
56399
56400 getParsingFlags(m).overflow = overflow;
56401 }
56402
56403 return m;
56404 } // Pick the first defined of two or three arguments.
56405
56406
56407 function defaults(a, b, c) {
56408 if (a != null) {
56409 return a;
56410 }
56411
56412 if (b != null) {
56413 return b;
56414 }
56415
56416 return c;
56417 }
56418
56419 function currentDateArray(config) {
56420 // hooks is actually the exported moment object
56421 var nowValue = new Date(hooks.now());
56422
56423 if (config._useUTC) {
56424 return [nowValue.getUTCFullYear(), nowValue.getUTCMonth(), nowValue.getUTCDate()];
56425 }
56426
56427 return [nowValue.getFullYear(), nowValue.getMonth(), nowValue.getDate()];
56428 } // convert an array to a date.
56429 // the array should mirror the parameters below
56430 // note: all values past the year are optional and will default to the lowest possible value.
56431 // [year, month, day , hour, minute, second, millisecond]
56432
56433
56434 function configFromArray(config) {
56435 var i,
56436 date,
56437 input = [],
56438 currentDate,
56439 expectedWeekday,
56440 yearToUse;
56441
56442 if (config._d) {
56443 return;
56444 }
56445
56446 currentDate = currentDateArray(config); //compute day of the year from weeks and weekdays
56447
56448 if (config._w && config._a[DATE] == null && config._a[MONTH] == null) {
56449 dayOfYearFromWeekInfo(config);
56450 } //if the day of the year is set, figure out what it is
56451
56452
56453 if (config._dayOfYear != null) {
56454 yearToUse = defaults(config._a[YEAR], currentDate[YEAR]);
56455
56456 if (config._dayOfYear > daysInYear(yearToUse) || config._dayOfYear === 0) {
56457 getParsingFlags(config)._overflowDayOfYear = true;
56458 }
56459
56460 date = createUTCDate(yearToUse, 0, config._dayOfYear);
56461 config._a[MONTH] = date.getUTCMonth();
56462 config._a[DATE] = date.getUTCDate();
56463 } // Default to current date.
56464 // * if no year, month, day of month are given, default to today
56465 // * if day of month is given, default month and year
56466 // * if month is given, default only year
56467 // * if year is given, don't default anything
56468
56469
56470 for (i = 0; i < 3 && config._a[i] == null; ++i) {
56471 config._a[i] = input[i] = currentDate[i];
56472 } // Zero out whatever was not defaulted, including time
56473
56474
56475 for (; i < 7; i++) {
56476 config._a[i] = input[i] = config._a[i] == null ? i === 2 ? 1 : 0 : config._a[i];
56477 } // Check for 24:00:00.000
56478
56479
56480 if (config._a[HOUR] === 24 && config._a[MINUTE] === 0 && config._a[SECOND] === 0 && config._a[MILLISECOND] === 0) {
56481 config._nextDay = true;
56482 config._a[HOUR] = 0;
56483 }
56484
56485 config._d = (config._useUTC ? createUTCDate : createDate).apply(null, input);
56486 expectedWeekday = config._useUTC ? config._d.getUTCDay() : config._d.getDay(); // Apply timezone offset from input. The actual utcOffset can be changed
56487 // with parseZone.
56488
56489 if (config._tzm != null) {
56490 config._d.setUTCMinutes(config._d.getUTCMinutes() - config._tzm);
56491 }
56492
56493 if (config._nextDay) {
56494 config._a[HOUR] = 24;
56495 } // check for mismatching day of week
56496
56497
56498 if (config._w && typeof config._w.d !== 'undefined' && config._w.d !== expectedWeekday) {
56499 getParsingFlags(config).weekdayMismatch = true;
56500 }
56501 }
56502
56503 function dayOfYearFromWeekInfo(config) {
56504 var w, weekYear, week, weekday, dow, doy, temp, weekdayOverflow;
56505 w = config._w;
56506
56507 if (w.GG != null || w.W != null || w.E != null) {
56508 dow = 1;
56509 doy = 4; // TODO: We need to take the current isoWeekYear, but that depends on
56510 // how we interpret now (local, utc, fixed offset). So create
56511 // a now version of current config (take local/utc/offset flags, and
56512 // create now).
56513
56514 weekYear = defaults(w.GG, config._a[YEAR], weekOfYear(createLocal(), 1, 4).year);
56515 week = defaults(w.W, 1);
56516 weekday = defaults(w.E, 1);
56517
56518 if (weekday < 1 || weekday > 7) {
56519 weekdayOverflow = true;
56520 }
56521 } else {
56522 dow = config._locale._week.dow;
56523 doy = config._locale._week.doy;
56524 var curWeek = weekOfYear(createLocal(), dow, doy);
56525 weekYear = defaults(w.gg, config._a[YEAR], curWeek.year); // Default to current week.
56526
56527 week = defaults(w.w, curWeek.week);
56528
56529 if (w.d != null) {
56530 // weekday -- low day numbers are considered next week
56531 weekday = w.d;
56532
56533 if (weekday < 0 || weekday > 6) {
56534 weekdayOverflow = true;
56535 }
56536 } else if (w.e != null) {
56537 // local weekday -- counting starts from beginning of week
56538 weekday = w.e + dow;
56539
56540 if (w.e < 0 || w.e > 6) {
56541 weekdayOverflow = true;
56542 }
56543 } else {
56544 // default to beginning of week
56545 weekday = dow;
56546 }
56547 }
56548
56549 if (week < 1 || week > weeksInYear(weekYear, dow, doy)) {
56550 getParsingFlags(config)._overflowWeeks = true;
56551 } else if (weekdayOverflow != null) {
56552 getParsingFlags(config)._overflowWeekday = true;
56553 } else {
56554 temp = dayOfYearFromWeeks(weekYear, week, weekday, dow, doy);
56555 config._a[YEAR] = temp.year;
56556 config._dayOfYear = temp.dayOfYear;
56557 }
56558 } // iso 8601 regex
56559 // 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)
56560
56561
56562 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)?)?$/;
56563 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)?)?$/;
56564 var tzRegex = /Z|[+-]\d\d(?::?\d\d)?/;
56565 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
56566 ['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
56567
56568 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/]];
56569 var aspNetJsonRegex = /^\/?Date\((\-?\d+)/i; // date from iso format
56570
56571 function configFromISO(config) {
56572 var i,
56573 l,
56574 string = config._i,
56575 match = extendedIsoRegex.exec(string) || basicIsoRegex.exec(string),
56576 allowTime,
56577 dateFormat,
56578 timeFormat,
56579 tzFormat;
56580
56581 if (match) {
56582 getParsingFlags(config).iso = true;
56583
56584 for (i = 0, l = isoDates.length; i < l; i++) {
56585 if (isoDates[i][1].exec(match[1])) {
56586 dateFormat = isoDates[i][0];
56587 allowTime = isoDates[i][2] !== false;
56588 break;
56589 }
56590 }
56591
56592 if (dateFormat == null) {
56593 config._isValid = false;
56594 return;
56595 }
56596
56597 if (match[3]) {
56598 for (i = 0, l = isoTimes.length; i < l; i++) {
56599 if (isoTimes[i][1].exec(match[3])) {
56600 // match[2] should be 'T' or space
56601 timeFormat = (match[2] || ' ') + isoTimes[i][0];
56602 break;
56603 }
56604 }
56605
56606 if (timeFormat == null) {
56607 config._isValid = false;
56608 return;
56609 }
56610 }
56611
56612 if (!allowTime && timeFormat != null) {
56613 config._isValid = false;
56614 return;
56615 }
56616
56617 if (match[4]) {
56618 if (tzRegex.exec(match[4])) {
56619 tzFormat = 'Z';
56620 } else {
56621 config._isValid = false;
56622 return;
56623 }
56624 }
56625
56626 config._f = dateFormat + (timeFormat || '') + (tzFormat || '');
56627 configFromStringAndFormat(config);
56628 } else {
56629 config._isValid = false;
56630 }
56631 } // RFC 2822 regex: For details see https://tools.ietf.org/html/rfc2822#section-3.3
56632
56633
56634 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}))$/;
56635
56636 function extractFromRFC2822Strings(yearStr, monthStr, dayStr, hourStr, minuteStr, secondStr) {
56637 var result = [untruncateYear(yearStr), defaultLocaleMonthsShort.indexOf(monthStr), parseInt(dayStr, 10), parseInt(hourStr, 10), parseInt(minuteStr, 10)];
56638
56639 if (secondStr) {
56640 result.push(parseInt(secondStr, 10));
56641 }
56642
56643 return result;
56644 }
56645
56646 function untruncateYear(yearStr) {
56647 var year = parseInt(yearStr, 10);
56648
56649 if (year <= 49) {
56650 return 2000 + year;
56651 } else if (year <= 999) {
56652 return 1900 + year;
56653 }
56654
56655 return year;
56656 }
56657
56658 function preprocessRFC2822(s) {
56659 // Remove comments and folding whitespace and replace multiple-spaces with a single space
56660 return s.replace(/\([^)]*\)|[\n\t]/g, ' ').replace(/(\s\s+)/g, ' ').replace(/^\s\s*/, '').replace(/\s\s*$/, '');
56661 }
56662
56663 function checkWeekday(weekdayStr, parsedInput, config) {
56664 if (weekdayStr) {
56665 // TODO: Replace the vanilla JS Date object with an indepentent day-of-week check.
56666 var weekdayProvided = defaultLocaleWeekdaysShort.indexOf(weekdayStr),
56667 weekdayActual = new Date(parsedInput[0], parsedInput[1], parsedInput[2]).getDay();
56668
56669 if (weekdayProvided !== weekdayActual) {
56670 getParsingFlags(config).weekdayMismatch = true;
56671 config._isValid = false;
56672 return false;
56673 }
56674 }
56675
56676 return true;
56677 }
56678
56679 var obsOffsets = {
56680 UT: 0,
56681 GMT: 0,
56682 EDT: -4 * 60,
56683 EST: -5 * 60,
56684 CDT: -5 * 60,
56685 CST: -6 * 60,
56686 MDT: -6 * 60,
56687 MST: -7 * 60,
56688 PDT: -7 * 60,
56689 PST: -8 * 60
56690 };
56691
56692 function calculateOffset(obsOffset, militaryOffset, numOffset) {
56693 if (obsOffset) {
56694 return obsOffsets[obsOffset];
56695 } else if (militaryOffset) {
56696 // the only allowed military tz is Z
56697 return 0;
56698 } else {
56699 var hm = parseInt(numOffset, 10);
56700 var m = hm % 100,
56701 h = (hm - m) / 100;
56702 return h * 60 + m;
56703 }
56704 } // date and time from ref 2822 format
56705
56706
56707 function configFromRFC2822(config) {
56708 var match = rfc2822.exec(preprocessRFC2822(config._i));
56709
56710 if (match) {
56711 var parsedArray = extractFromRFC2822Strings(match[4], match[3], match[2], match[5], match[6], match[7]);
56712
56713 if (!checkWeekday(match[1], parsedArray, config)) {
56714 return;
56715 }
56716
56717 config._a = parsedArray;
56718 config._tzm = calculateOffset(match[8], match[9], match[10]);
56719 config._d = createUTCDate.apply(null, config._a);
56720
56721 config._d.setUTCMinutes(config._d.getUTCMinutes() - config._tzm);
56722
56723 getParsingFlags(config).rfc2822 = true;
56724 } else {
56725 config._isValid = false;
56726 }
56727 } // date from iso format or fallback
56728
56729
56730 function configFromString(config) {
56731 var matched = aspNetJsonRegex.exec(config._i);
56732
56733 if (matched !== null) {
56734 config._d = new Date(+matched[1]);
56735 return;
56736 }
56737
56738 configFromISO(config);
56739
56740 if (config._isValid === false) {
56741 delete config._isValid;
56742 } else {
56743 return;
56744 }
56745
56746 configFromRFC2822(config);
56747
56748 if (config._isValid === false) {
56749 delete config._isValid;
56750 } else {
56751 return;
56752 } // Final attempt, use Input Fallback
56753
56754
56755 hooks.createFromInputFallback(config);
56756 }
56757
56758 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) {
56759 config._d = new Date(config._i + (config._useUTC ? ' UTC' : ''));
56760 }); // constant that refers to the ISO standard
56761
56762 hooks.ISO_8601 = function () {}; // constant that refers to the RFC 2822 form
56763
56764
56765 hooks.RFC_2822 = function () {}; // date from string and format string
56766
56767
56768 function configFromStringAndFormat(config) {
56769 // TODO: Move this to another part of the creation flow to prevent circular deps
56770 if (config._f === hooks.ISO_8601) {
56771 configFromISO(config);
56772 return;
56773 }
56774
56775 if (config._f === hooks.RFC_2822) {
56776 configFromRFC2822(config);
56777 return;
56778 }
56779
56780 config._a = [];
56781 getParsingFlags(config).empty = true; // This array is used to make a Date, either with `new Date` or `Date.UTC`
56782
56783 var string = '' + config._i,
56784 i,
56785 parsedInput,
56786 tokens,
56787 token,
56788 skipped,
56789 stringLength = string.length,
56790 totalParsedInputLength = 0;
56791 tokens = expandFormat(config._f, config._locale).match(formattingTokens) || [];
56792
56793 for (i = 0; i < tokens.length; i++) {
56794 token = tokens[i];
56795 parsedInput = (string.match(getParseRegexForToken(token, config)) || [])[0]; // console.log('token', token, 'parsedInput', parsedInput,
56796 // 'regex', getParseRegexForToken(token, config));
56797
56798 if (parsedInput) {
56799 skipped = string.substr(0, string.indexOf(parsedInput));
56800
56801 if (skipped.length > 0) {
56802 getParsingFlags(config).unusedInput.push(skipped);
56803 }
56804
56805 string = string.slice(string.indexOf(parsedInput) + parsedInput.length);
56806 totalParsedInputLength += parsedInput.length;
56807 } // don't parse if it's not a known token
56808
56809
56810 if (formatTokenFunctions[token]) {
56811 if (parsedInput) {
56812 getParsingFlags(config).empty = false;
56813 } else {
56814 getParsingFlags(config).unusedTokens.push(token);
56815 }
56816
56817 addTimeToArrayFromToken(token, parsedInput, config);
56818 } else if (config._strict && !parsedInput) {
56819 getParsingFlags(config).unusedTokens.push(token);
56820 }
56821 } // add remaining unparsed input length to the string
56822
56823
56824 getParsingFlags(config).charsLeftOver = stringLength - totalParsedInputLength;
56825
56826 if (string.length > 0) {
56827 getParsingFlags(config).unusedInput.push(string);
56828 } // clear _12h flag if hour is <= 12
56829
56830
56831 if (config._a[HOUR] <= 12 && getParsingFlags(config).bigHour === true && config._a[HOUR] > 0) {
56832 getParsingFlags(config).bigHour = undefined;
56833 }
56834
56835 getParsingFlags(config).parsedDateParts = config._a.slice(0);
56836 getParsingFlags(config).meridiem = config._meridiem; // handle meridiem
56837
56838 config._a[HOUR] = meridiemFixWrap(config._locale, config._a[HOUR], config._meridiem);
56839 configFromArray(config);
56840 checkOverflow(config);
56841 }
56842
56843 function meridiemFixWrap(locale, hour, meridiem) {
56844 var isPm;
56845
56846 if (meridiem == null) {
56847 // nothing to do
56848 return hour;
56849 }
56850
56851 if (locale.meridiemHour != null) {
56852 return locale.meridiemHour(hour, meridiem);
56853 } else if (locale.isPM != null) {
56854 // Fallback
56855 isPm = locale.isPM(meridiem);
56856
56857 if (isPm && hour < 12) {
56858 hour += 12;
56859 }
56860
56861 if (!isPm && hour === 12) {
56862 hour = 0;
56863 }
56864
56865 return hour;
56866 } else {
56867 // this is not supposed to happen
56868 return hour;
56869 }
56870 } // date from string and array of format strings
56871
56872
56873 function configFromStringAndArray(config) {
56874 var tempConfig, bestMoment, scoreToBeat, i, currentScore;
56875
56876 if (config._f.length === 0) {
56877 getParsingFlags(config).invalidFormat = true;
56878 config._d = new Date(NaN);
56879 return;
56880 }
56881
56882 for (i = 0; i < config._f.length; i++) {
56883 currentScore = 0;
56884 tempConfig = copyConfig({}, config);
56885
56886 if (config._useUTC != null) {
56887 tempConfig._useUTC = config._useUTC;
56888 }
56889
56890 tempConfig._f = config._f[i];
56891 configFromStringAndFormat(tempConfig);
56892
56893 if (!isValid(tempConfig)) {
56894 continue;
56895 } // if there is any input that was not parsed add a penalty for that format
56896
56897
56898 currentScore += getParsingFlags(tempConfig).charsLeftOver; //or tokens
56899
56900 currentScore += getParsingFlags(tempConfig).unusedTokens.length * 10;
56901 getParsingFlags(tempConfig).score = currentScore;
56902
56903 if (scoreToBeat == null || currentScore < scoreToBeat) {
56904 scoreToBeat = currentScore;
56905 bestMoment = tempConfig;
56906 }
56907 }
56908
56909 extend(config, bestMoment || tempConfig);
56910 }
56911
56912 function configFromObject(config) {
56913 if (config._d) {
56914 return;
56915 }
56916
56917 var i = normalizeObjectUnits(config._i);
56918 config._a = map([i.year, i.month, i.day || i.date, i.hour, i.minute, i.second, i.millisecond], function (obj) {
56919 return obj && parseInt(obj, 10);
56920 });
56921 configFromArray(config);
56922 }
56923
56924 function createFromConfig(config) {
56925 var res = new Moment(checkOverflow(prepareConfig(config)));
56926
56927 if (res._nextDay) {
56928 // Adding is smart enough around DST
56929 res.add(1, 'd');
56930 res._nextDay = undefined;
56931 }
56932
56933 return res;
56934 }
56935
56936 function prepareConfig(config) {
56937 var input = config._i,
56938 format = config._f;
56939 config._locale = config._locale || getLocale(config._l);
56940
56941 if (input === null || format === undefined && input === '') {
56942 return createInvalid({
56943 nullInput: true
56944 });
56945 }
56946
56947 if (typeof input === 'string') {
56948 config._i = input = config._locale.preparse(input);
56949 }
56950
56951 if (isMoment(input)) {
56952 return new Moment(checkOverflow(input));
56953 } else if (isDate(input)) {
56954 config._d = input;
56955 } else if (isArray(format)) {
56956 configFromStringAndArray(config);
56957 } else if (format) {
56958 configFromStringAndFormat(config);
56959 } else {
56960 configFromInput(config);
56961 }
56962
56963 if (!isValid(config)) {
56964 config._d = null;
56965 }
56966
56967 return config;
56968 }
56969
56970 function configFromInput(config) {
56971 var input = config._i;
56972
56973 if (isUndefined(input)) {
56974 config._d = new Date(hooks.now());
56975 } else if (isDate(input)) {
56976 config._d = new Date(input.valueOf());
56977 } else if (typeof input === 'string') {
56978 configFromString(config);
56979 } else if (isArray(input)) {
56980 config._a = map(input.slice(0), function (obj) {
56981 return parseInt(obj, 10);
56982 });
56983 configFromArray(config);
56984 } else if (isObject(input)) {
56985 configFromObject(config);
56986 } else if (isNumber(input)) {
56987 // from milliseconds
56988 config._d = new Date(input);
56989 } else {
56990 hooks.createFromInputFallback(config);
56991 }
56992 }
56993
56994 function createLocalOrUTC(input, format, locale, strict, isUTC) {
56995 var c = {};
56996
56997 if (locale === true || locale === false) {
56998 strict = locale;
56999 locale = undefined;
57000 }
57001
57002 if (isObject(input) && isObjectEmpty(input) || isArray(input) && input.length === 0) {
57003 input = undefined;
57004 } // object construction must be done this way.
57005 // https://github.com/moment/moment/issues/1423
57006
57007
57008 c._isAMomentObject = true;
57009 c._useUTC = c._isUTC = isUTC;
57010 c._l = locale;
57011 c._i = input;
57012 c._f = format;
57013 c._strict = strict;
57014 return createFromConfig(c);
57015 }
57016
57017 function createLocal(input, format, locale, strict) {
57018 return createLocalOrUTC(input, format, locale, strict, false);
57019 }
57020
57021 var prototypeMin = deprecate('moment().min is deprecated, use moment.max instead. http://momentjs.com/guides/#/warnings/min-max/', function () {
57022 var other = createLocal.apply(null, arguments);
57023
57024 if (this.isValid() && other.isValid()) {
57025 return other < this ? this : other;
57026 } else {
57027 return createInvalid();
57028 }
57029 });
57030 var prototypeMax = deprecate('moment().max is deprecated, use moment.min instead. http://momentjs.com/guides/#/warnings/min-max/', function () {
57031 var other = createLocal.apply(null, arguments);
57032
57033 if (this.isValid() && other.isValid()) {
57034 return other > this ? this : other;
57035 } else {
57036 return createInvalid();
57037 }
57038 }); // Pick a moment m from moments so that m[fn](other) is true for all
57039 // other. This relies on the function fn to be transitive.
57040 //
57041 // moments should either be an array of moment objects or an array, whose
57042 // first element is an array of moment objects.
57043
57044 function pickBy(fn, moments) {
57045 var res, i;
57046
57047 if (moments.length === 1 && isArray(moments[0])) {
57048 moments = moments[0];
57049 }
57050
57051 if (!moments.length) {
57052 return createLocal();
57053 }
57054
57055 res = moments[0];
57056
57057 for (i = 1; i < moments.length; ++i) {
57058 if (!moments[i].isValid() || moments[i][fn](res)) {
57059 res = moments[i];
57060 }
57061 }
57062
57063 return res;
57064 } // TODO: Use [].sort instead?
57065
57066
57067 function min() {
57068 var args = [].slice.call(arguments, 0);
57069 return pickBy('isBefore', args);
57070 }
57071
57072 function max() {
57073 var args = [].slice.call(arguments, 0);
57074 return pickBy('isAfter', args);
57075 }
57076
57077 var now = function () {
57078 return Date.now ? Date.now() : +new Date();
57079 };
57080
57081 var ordering = ['year', 'quarter', 'month', 'week', 'day', 'hour', 'minute', 'second', 'millisecond'];
57082
57083 function isDurationValid(m) {
57084 for (var key in m) {
57085 if (!(indexOf.call(ordering, key) !== -1 && (m[key] == null || !isNaN(m[key])))) {
57086 return false;
57087 }
57088 }
57089
57090 var unitHasDecimal = false;
57091
57092 for (var i = 0; i < ordering.length; ++i) {
57093 if (m[ordering[i]]) {
57094 if (unitHasDecimal) {
57095 return false; // only allow non-integers for smallest unit
57096 }
57097
57098 if (parseFloat(m[ordering[i]]) !== toInt(m[ordering[i]])) {
57099 unitHasDecimal = true;
57100 }
57101 }
57102 }
57103
57104 return true;
57105 }
57106
57107 function isValid$1() {
57108 return this._isValid;
57109 }
57110
57111 function createInvalid$1() {
57112 return createDuration(NaN);
57113 }
57114
57115 function Duration(duration) {
57116 var normalizedInput = normalizeObjectUnits(duration),
57117 years = normalizedInput.year || 0,
57118 quarters = normalizedInput.quarter || 0,
57119 months = normalizedInput.month || 0,
57120 weeks = normalizedInput.week || normalizedInput.isoWeek || 0,
57121 days = normalizedInput.day || 0,
57122 hours = normalizedInput.hour || 0,
57123 minutes = normalizedInput.minute || 0,
57124 seconds = normalizedInput.second || 0,
57125 milliseconds = normalizedInput.millisecond || 0;
57126 this._isValid = isDurationValid(normalizedInput); // representation for dateAddRemove
57127
57128 this._milliseconds = +milliseconds + seconds * 1e3 + // 1000
57129 minutes * 6e4 + // 1000 * 60
57130 hours * 1000 * 60 * 60; //using 1000 * 60 * 60 instead of 36e5 to avoid floating point rounding errors https://github.com/moment/moment/issues/2978
57131 // Because of dateAddRemove treats 24 hours as different from a
57132 // day when working around DST, we need to store them separately
57133
57134 this._days = +days + weeks * 7; // It is impossible to translate months into days without knowing
57135 // which months you are are talking about, so we have to store
57136 // it separately.
57137
57138 this._months = +months + quarters * 3 + years * 12;
57139 this._data = {};
57140 this._locale = getLocale();
57141
57142 this._bubble();
57143 }
57144
57145 function isDuration(obj) {
57146 return obj instanceof Duration;
57147 }
57148
57149 function absRound(number) {
57150 if (number < 0) {
57151 return Math.round(-1 * number) * -1;
57152 } else {
57153 return Math.round(number);
57154 }
57155 } // FORMATTING
57156
57157
57158 function offset(token, separator) {
57159 addFormatToken(token, 0, 0, function () {
57160 var offset = this.utcOffset();
57161 var sign = '+';
57162
57163 if (offset < 0) {
57164 offset = -offset;
57165 sign = '-';
57166 }
57167
57168 return sign + zeroFill(~~(offset / 60), 2) + separator + zeroFill(~~offset % 60, 2);
57169 });
57170 }
57171
57172 offset('Z', ':');
57173 offset('ZZ', ''); // PARSING
57174
57175 addRegexToken('Z', matchShortOffset);
57176 addRegexToken('ZZ', matchShortOffset);
57177 addParseToken(['Z', 'ZZ'], function (input, array, config) {
57178 config._useUTC = true;
57179 config._tzm = offsetFromString(matchShortOffset, input);
57180 }); // HELPERS
57181 // timezone chunker
57182 // '+10:00' > ['10', '00']
57183 // '-1530' > ['-15', '30']
57184
57185 var chunkOffset = /([\+\-]|\d\d)/gi;
57186
57187 function offsetFromString(matcher, string) {
57188 var matches = (string || '').match(matcher);
57189
57190 if (matches === null) {
57191 return null;
57192 }
57193
57194 var chunk = matches[matches.length - 1] || [];
57195 var parts = (chunk + '').match(chunkOffset) || ['-', 0, 0];
57196 var minutes = +(parts[1] * 60) + toInt(parts[2]);
57197 return minutes === 0 ? 0 : parts[0] === '+' ? minutes : -minutes;
57198 } // Return a moment from input, that is local/utc/zone equivalent to model.
57199
57200
57201 function cloneWithOffset(input, model) {
57202 var res, diff;
57203
57204 if (model._isUTC) {
57205 res = model.clone();
57206 diff = (isMoment(input) || isDate(input) ? input.valueOf() : createLocal(input).valueOf()) - res.valueOf(); // Use low-level api, because this fn is low-level api.
57207
57208 res._d.setTime(res._d.valueOf() + diff);
57209
57210 hooks.updateOffset(res, false);
57211 return res;
57212 } else {
57213 return createLocal(input).local();
57214 }
57215 }
57216
57217 function getDateOffset(m) {
57218 // On Firefox.24 Date#getTimezoneOffset returns a floating point.
57219 // https://github.com/moment/moment/pull/1871
57220 return -Math.round(m._d.getTimezoneOffset() / 15) * 15;
57221 } // HOOKS
57222 // This function will be called whenever a moment is mutated.
57223 // It is intended to keep the offset in sync with the timezone.
57224
57225
57226 hooks.updateOffset = function () {}; // MOMENTS
57227 // keepLocalTime = true means only change the timezone, without
57228 // affecting the local hour. So 5:31:26 +0300 --[utcOffset(2, true)]-->
57229 // 5:31:26 +0200 It is possible that 5:31:26 doesn't exist with offset
57230 // +0200, so we adjust the time as needed, to be valid.
57231 //
57232 // Keeping the time actually adds/subtracts (one hour)
57233 // from the actual represented time. That is why we call updateOffset
57234 // a second time. In case it wants us to change the offset again
57235 // _changeInProgress == true case, then we have to adjust, because
57236 // there is no such time in the given timezone.
57237
57238
57239 function getSetOffset(input, keepLocalTime, keepMinutes) {
57240 var offset = this._offset || 0,
57241 localAdjust;
57242
57243 if (!this.isValid()) {
57244 return input != null ? this : NaN;
57245 }
57246
57247 if (input != null) {
57248 if (typeof input === 'string') {
57249 input = offsetFromString(matchShortOffset, input);
57250
57251 if (input === null) {
57252 return this;
57253 }
57254 } else if (Math.abs(input) < 16 && !keepMinutes) {
57255 input = input * 60;
57256 }
57257
57258 if (!this._isUTC && keepLocalTime) {
57259 localAdjust = getDateOffset(this);
57260 }
57261
57262 this._offset = input;
57263 this._isUTC = true;
57264
57265 if (localAdjust != null) {
57266 this.add(localAdjust, 'm');
57267 }
57268
57269 if (offset !== input) {
57270 if (!keepLocalTime || this._changeInProgress) {
57271 addSubtract(this, createDuration(input - offset, 'm'), 1, false);
57272 } else if (!this._changeInProgress) {
57273 this._changeInProgress = true;
57274 hooks.updateOffset(this, true);
57275 this._changeInProgress = null;
57276 }
57277 }
57278
57279 return this;
57280 } else {
57281 return this._isUTC ? offset : getDateOffset(this);
57282 }
57283 }
57284
57285 function getSetZone(input, keepLocalTime) {
57286 if (input != null) {
57287 if (typeof input !== 'string') {
57288 input = -input;
57289 }
57290
57291 this.utcOffset(input, keepLocalTime);
57292 return this;
57293 } else {
57294 return -this.utcOffset();
57295 }
57296 }
57297
57298 function setOffsetToUTC(keepLocalTime) {
57299 return this.utcOffset(0, keepLocalTime);
57300 }
57301
57302 function setOffsetToLocal(keepLocalTime) {
57303 if (this._isUTC) {
57304 this.utcOffset(0, keepLocalTime);
57305 this._isUTC = false;
57306
57307 if (keepLocalTime) {
57308 this.subtract(getDateOffset(this), 'm');
57309 }
57310 }
57311
57312 return this;
57313 }
57314
57315 function setOffsetToParsedOffset() {
57316 if (this._tzm != null) {
57317 this.utcOffset(this._tzm, false, true);
57318 } else if (typeof this._i === 'string') {
57319 var tZone = offsetFromString(matchOffset, this._i);
57320
57321 if (tZone != null) {
57322 this.utcOffset(tZone);
57323 } else {
57324 this.utcOffset(0, true);
57325 }
57326 }
57327
57328 return this;
57329 }
57330
57331 function hasAlignedHourOffset(input) {
57332 if (!this.isValid()) {
57333 return false;
57334 }
57335
57336 input = input ? createLocal(input).utcOffset() : 0;
57337 return (this.utcOffset() - input) % 60 === 0;
57338 }
57339
57340 function isDaylightSavingTime() {
57341 return this.utcOffset() > this.clone().month(0).utcOffset() || this.utcOffset() > this.clone().month(5).utcOffset();
57342 }
57343
57344 function isDaylightSavingTimeShifted() {
57345 if (!isUndefined(this._isDSTShifted)) {
57346 return this._isDSTShifted;
57347 }
57348
57349 var c = {};
57350 copyConfig(c, this);
57351 c = prepareConfig(c);
57352
57353 if (c._a) {
57354 var other = c._isUTC ? createUTC(c._a) : createLocal(c._a);
57355 this._isDSTShifted = this.isValid() && compareArrays(c._a, other.toArray()) > 0;
57356 } else {
57357 this._isDSTShifted = false;
57358 }
57359
57360 return this._isDSTShifted;
57361 }
57362
57363 function isLocal() {
57364 return this.isValid() ? !this._isUTC : false;
57365 }
57366
57367 function isUtcOffset() {
57368 return this.isValid() ? this._isUTC : false;
57369 }
57370
57371 function isUtc() {
57372 return this.isValid() ? this._isUTC && this._offset === 0 : false;
57373 } // ASP.NET json date format regex
57374
57375
57376 var aspNetRegex = /^(\-|\+)?(?:(\d*)[. ])?(\d+)\:(\d+)(?:\:(\d+)(\.\d*)?)?$/; // from http://docs.closure-library.googlecode.com/git/closure_goog_date_date.js.source.html
57377 // somewhat more in line with 4.4.3.2 2004 spec, but allows decimal anywhere
57378 // and further modified to allow for strings containing both week and day
57379
57380 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)?)?$/;
57381
57382 function createDuration(input, key) {
57383 var duration = input,
57384 // matching against regexp is expensive, do it on demand
57385 match = null,
57386 sign,
57387 ret,
57388 diffRes;
57389
57390 if (isDuration(input)) {
57391 duration = {
57392 ms: input._milliseconds,
57393 d: input._days,
57394 M: input._months
57395 };
57396 } else if (isNumber(input)) {
57397 duration = {};
57398
57399 if (key) {
57400 duration[key] = input;
57401 } else {
57402 duration.milliseconds = input;
57403 }
57404 } else if (!!(match = aspNetRegex.exec(input))) {
57405 sign = match[1] === '-' ? -1 : 1;
57406 duration = {
57407 y: 0,
57408 d: toInt(match[DATE]) * sign,
57409 h: toInt(match[HOUR]) * sign,
57410 m: toInt(match[MINUTE]) * sign,
57411 s: toInt(match[SECOND]) * sign,
57412 ms: toInt(absRound(match[MILLISECOND] * 1000)) * sign // the millisecond decimal point is included in the match
57413
57414 };
57415 } else if (!!(match = isoRegex.exec(input))) {
57416 sign = match[1] === '-' ? -1 : 1;
57417 duration = {
57418 y: parseIso(match[2], sign),
57419 M: parseIso(match[3], sign),
57420 w: parseIso(match[4], sign),
57421 d: parseIso(match[5], sign),
57422 h: parseIso(match[6], sign),
57423 m: parseIso(match[7], sign),
57424 s: parseIso(match[8], sign)
57425 };
57426 } else if (duration == null) {
57427 // checks for null or undefined
57428 duration = {};
57429 } else if (typeof duration === 'object' && ('from' in duration || 'to' in duration)) {
57430 diffRes = momentsDifference(createLocal(duration.from), createLocal(duration.to));
57431 duration = {};
57432 duration.ms = diffRes.milliseconds;
57433 duration.M = diffRes.months;
57434 }
57435
57436 ret = new Duration(duration);
57437
57438 if (isDuration(input) && hasOwnProp(input, '_locale')) {
57439 ret._locale = input._locale;
57440 }
57441
57442 return ret;
57443 }
57444
57445 createDuration.fn = Duration.prototype;
57446 createDuration.invalid = createInvalid$1;
57447
57448 function parseIso(inp, sign) {
57449 // We'd normally use ~~inp for this, but unfortunately it also
57450 // converts floats to ints.
57451 // inp may be undefined, so careful calling replace on it.
57452 var res = inp && parseFloat(inp.replace(',', '.')); // apply sign while we're at it
57453
57454 return (isNaN(res) ? 0 : res) * sign;
57455 }
57456
57457 function positiveMomentsDifference(base, other) {
57458 var res = {};
57459 res.months = other.month() - base.month() + (other.year() - base.year()) * 12;
57460
57461 if (base.clone().add(res.months, 'M').isAfter(other)) {
57462 --res.months;
57463 }
57464
57465 res.milliseconds = +other - +base.clone().add(res.months, 'M');
57466 return res;
57467 }
57468
57469 function momentsDifference(base, other) {
57470 var res;
57471
57472 if (!(base.isValid() && other.isValid())) {
57473 return {
57474 milliseconds: 0,
57475 months: 0
57476 };
57477 }
57478
57479 other = cloneWithOffset(other, base);
57480
57481 if (base.isBefore(other)) {
57482 res = positiveMomentsDifference(base, other);
57483 } else {
57484 res = positiveMomentsDifference(other, base);
57485 res.milliseconds = -res.milliseconds;
57486 res.months = -res.months;
57487 }
57488
57489 return res;
57490 } // TODO: remove 'name' arg after deprecation is removed
57491
57492
57493 function createAdder(direction, name) {
57494 return function (val, period) {
57495 var dur, tmp; //invert the arguments, but complain about it
57496
57497 if (period !== null && !isNaN(+period)) {
57498 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.');
57499 tmp = val;
57500 val = period;
57501 period = tmp;
57502 }
57503
57504 val = typeof val === 'string' ? +val : val;
57505 dur = createDuration(val, period);
57506 addSubtract(this, dur, direction);
57507 return this;
57508 };
57509 }
57510
57511 function addSubtract(mom, duration, isAdding, updateOffset) {
57512 var milliseconds = duration._milliseconds,
57513 days = absRound(duration._days),
57514 months = absRound(duration._months);
57515
57516 if (!mom.isValid()) {
57517 // No op
57518 return;
57519 }
57520
57521 updateOffset = updateOffset == null ? true : updateOffset;
57522
57523 if (months) {
57524 setMonth(mom, get(mom, 'Month') + months * isAdding);
57525 }
57526
57527 if (days) {
57528 set$1(mom, 'Date', get(mom, 'Date') + days * isAdding);
57529 }
57530
57531 if (milliseconds) {
57532 mom._d.setTime(mom._d.valueOf() + milliseconds * isAdding);
57533 }
57534
57535 if (updateOffset) {
57536 hooks.updateOffset(mom, days || months);
57537 }
57538 }
57539
57540 var add = createAdder(1, 'add');
57541 var subtract = createAdder(-1, 'subtract');
57542
57543 function getCalendarFormat(myMoment, now) {
57544 var diff = myMoment.diff(now, 'days', true);
57545 return diff < -6 ? 'sameElse' : diff < -1 ? 'lastWeek' : diff < 0 ? 'lastDay' : diff < 1 ? 'sameDay' : diff < 2 ? 'nextDay' : diff < 7 ? 'nextWeek' : 'sameElse';
57546 }
57547
57548 function calendar$1(time, formats) {
57549 // We want to compare the start of today, vs this.
57550 // Getting start-of-today depends on whether we're local/utc/offset or not.
57551 var now = time || createLocal(),
57552 sod = cloneWithOffset(now, this).startOf('day'),
57553 format = hooks.calendarFormat(this, sod) || 'sameElse';
57554 var output = formats && (isFunction(formats[format]) ? formats[format].call(this, now) : formats[format]);
57555 return this.format(output || this.localeData().calendar(format, this, createLocal(now)));
57556 }
57557
57558 function clone() {
57559 return new Moment(this);
57560 }
57561
57562 function isAfter(input, units) {
57563 var localInput = isMoment(input) ? input : createLocal(input);
57564
57565 if (!(this.isValid() && localInput.isValid())) {
57566 return false;
57567 }
57568
57569 units = normalizeUnits(units) || 'millisecond';
57570
57571 if (units === 'millisecond') {
57572 return this.valueOf() > localInput.valueOf();
57573 } else {
57574 return localInput.valueOf() < this.clone().startOf(units).valueOf();
57575 }
57576 }
57577
57578 function isBefore(input, units) {
57579 var localInput = isMoment(input) ? input : createLocal(input);
57580
57581 if (!(this.isValid() && localInput.isValid())) {
57582 return false;
57583 }
57584
57585 units = normalizeUnits(units) || 'millisecond';
57586
57587 if (units === 'millisecond') {
57588 return this.valueOf() < localInput.valueOf();
57589 } else {
57590 return this.clone().endOf(units).valueOf() < localInput.valueOf();
57591 }
57592 }
57593
57594 function isBetween(from, to, units, inclusivity) {
57595 var localFrom = isMoment(from) ? from : createLocal(from),
57596 localTo = isMoment(to) ? to : createLocal(to);
57597
57598 if (!(this.isValid() && localFrom.isValid() && localTo.isValid())) {
57599 return false;
57600 }
57601
57602 inclusivity = inclusivity || '()';
57603 return (inclusivity[0] === '(' ? this.isAfter(localFrom, units) : !this.isBefore(localFrom, units)) && (inclusivity[1] === ')' ? this.isBefore(localTo, units) : !this.isAfter(localTo, units));
57604 }
57605
57606 function isSame(input, units) {
57607 var localInput = isMoment(input) ? input : createLocal(input),
57608 inputMs;
57609
57610 if (!(this.isValid() && localInput.isValid())) {
57611 return false;
57612 }
57613
57614 units = normalizeUnits(units) || 'millisecond';
57615
57616 if (units === 'millisecond') {
57617 return this.valueOf() === localInput.valueOf();
57618 } else {
57619 inputMs = localInput.valueOf();
57620 return this.clone().startOf(units).valueOf() <= inputMs && inputMs <= this.clone().endOf(units).valueOf();
57621 }
57622 }
57623
57624 function isSameOrAfter(input, units) {
57625 return this.isSame(input, units) || this.isAfter(input, units);
57626 }
57627
57628 function isSameOrBefore(input, units) {
57629 return this.isSame(input, units) || this.isBefore(input, units);
57630 }
57631
57632 function diff(input, units, asFloat) {
57633 var that, zoneDelta, output;
57634
57635 if (!this.isValid()) {
57636 return NaN;
57637 }
57638
57639 that = cloneWithOffset(input, this);
57640
57641 if (!that.isValid()) {
57642 return NaN;
57643 }
57644
57645 zoneDelta = (that.utcOffset() - this.utcOffset()) * 6e4;
57646 units = normalizeUnits(units);
57647
57648 switch (units) {
57649 case 'year':
57650 output = monthDiff(this, that) / 12;
57651 break;
57652
57653 case 'month':
57654 output = monthDiff(this, that);
57655 break;
57656
57657 case 'quarter':
57658 output = monthDiff(this, that) / 3;
57659 break;
57660
57661 case 'second':
57662 output = (this - that) / 1e3;
57663 break;
57664 // 1000
57665
57666 case 'minute':
57667 output = (this - that) / 6e4;
57668 break;
57669 // 1000 * 60
57670
57671 case 'hour':
57672 output = (this - that) / 36e5;
57673 break;
57674 // 1000 * 60 * 60
57675
57676 case 'day':
57677 output = (this - that - zoneDelta) / 864e5;
57678 break;
57679 // 1000 * 60 * 60 * 24, negate dst
57680
57681 case 'week':
57682 output = (this - that - zoneDelta) / 6048e5;
57683 break;
57684 // 1000 * 60 * 60 * 24 * 7, negate dst
57685
57686 default:
57687 output = this - that;
57688 }
57689
57690 return asFloat ? output : absFloor(output);
57691 }
57692
57693 function monthDiff(a, b) {
57694 // difference in months
57695 var wholeMonthDiff = (b.year() - a.year()) * 12 + (b.month() - a.month()),
57696 // b is in (anchor - 1 month, anchor + 1 month)
57697 anchor = a.clone().add(wholeMonthDiff, 'months'),
57698 anchor2,
57699 adjust;
57700
57701 if (b - anchor < 0) {
57702 anchor2 = a.clone().add(wholeMonthDiff - 1, 'months'); // linear across the month
57703
57704 adjust = (b - anchor) / (anchor - anchor2);
57705 } else {
57706 anchor2 = a.clone().add(wholeMonthDiff + 1, 'months'); // linear across the month
57707
57708 adjust = (b - anchor) / (anchor2 - anchor);
57709 } //check for negative zero, return zero if negative zero
57710
57711
57712 return -(wholeMonthDiff + adjust) || 0;
57713 }
57714
57715 hooks.defaultFormat = 'YYYY-MM-DDTHH:mm:ssZ';
57716 hooks.defaultFormatUtc = 'YYYY-MM-DDTHH:mm:ss[Z]';
57717
57718 function toString() {
57719 return this.clone().locale('en').format('ddd MMM DD YYYY HH:mm:ss [GMT]ZZ');
57720 }
57721
57722 function toISOString(keepOffset) {
57723 if (!this.isValid()) {
57724 return null;
57725 }
57726
57727 var utc = keepOffset !== true;
57728 var m = utc ? this.clone().utc() : this;
57729
57730 if (m.year() < 0 || m.year() > 9999) {
57731 return formatMoment(m, utc ? 'YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]' : 'YYYYYY-MM-DD[T]HH:mm:ss.SSSZ');
57732 }
57733
57734 if (isFunction(Date.prototype.toISOString)) {
57735 // native implementation is ~50x faster, use it when we can
57736 if (utc) {
57737 return this.toDate().toISOString();
57738 } else {
57739 return new Date(this.valueOf() + this.utcOffset() * 60 * 1000).toISOString().replace('Z', formatMoment(m, 'Z'));
57740 }
57741 }
57742
57743 return formatMoment(m, utc ? 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]' : 'YYYY-MM-DD[T]HH:mm:ss.SSSZ');
57744 }
57745 /**
57746 * Return a human readable representation of a moment that can
57747 * also be evaluated to get a new moment which is the same
57748 *
57749 * @link https://nodejs.org/dist/latest/docs/api/util.html#util_custom_inspect_function_on_objects
57750 */
57751
57752
57753 function inspect() {
57754 if (!this.isValid()) {
57755 return 'moment.invalid(/* ' + this._i + ' */)';
57756 }
57757
57758 var func = 'moment';
57759 var zone = '';
57760
57761 if (!this.isLocal()) {
57762 func = this.utcOffset() === 0 ? 'moment.utc' : 'moment.parseZone';
57763 zone = 'Z';
57764 }
57765
57766 var prefix = '[' + func + '("]';
57767 var year = 0 <= this.year() && this.year() <= 9999 ? 'YYYY' : 'YYYYYY';
57768 var datetime = '-MM-DD[T]HH:mm:ss.SSS';
57769 var suffix = zone + '[")]';
57770 return this.format(prefix + year + datetime + suffix);
57771 }
57772
57773 function format(inputString) {
57774 if (!inputString) {
57775 inputString = this.isUtc() ? hooks.defaultFormatUtc : hooks.defaultFormat;
57776 }
57777
57778 var output = formatMoment(this, inputString);
57779 return this.localeData().postformat(output);
57780 }
57781
57782 function from(time, withoutSuffix) {
57783 if (this.isValid() && (isMoment(time) && time.isValid() || createLocal(time).isValid())) {
57784 return createDuration({
57785 to: this,
57786 from: time
57787 }).locale(this.locale()).humanize(!withoutSuffix);
57788 } else {
57789 return this.localeData().invalidDate();
57790 }
57791 }
57792
57793 function fromNow(withoutSuffix) {
57794 return this.from(createLocal(), withoutSuffix);
57795 }
57796
57797 function to(time, withoutSuffix) {
57798 if (this.isValid() && (isMoment(time) && time.isValid() || createLocal(time).isValid())) {
57799 return createDuration({
57800 from: this,
57801 to: time
57802 }).locale(this.locale()).humanize(!withoutSuffix);
57803 } else {
57804 return this.localeData().invalidDate();
57805 }
57806 }
57807
57808 function toNow(withoutSuffix) {
57809 return this.to(createLocal(), withoutSuffix);
57810 } // If passed a locale key, it will set the locale for this
57811 // instance. Otherwise, it will return the locale configuration
57812 // variables for this instance.
57813
57814
57815 function locale(key) {
57816 var newLocaleData;
57817
57818 if (key === undefined) {
57819 return this._locale._abbr;
57820 } else {
57821 newLocaleData = getLocale(key);
57822
57823 if (newLocaleData != null) {
57824 this._locale = newLocaleData;
57825 }
57826
57827 return this;
57828 }
57829 }
57830
57831 var lang = deprecate('moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.', function (key) {
57832 if (key === undefined) {
57833 return this.localeData();
57834 } else {
57835 return this.locale(key);
57836 }
57837 });
57838
57839 function localeData() {
57840 return this._locale;
57841 }
57842
57843 var MS_PER_SECOND = 1000;
57844 var MS_PER_MINUTE = 60 * MS_PER_SECOND;
57845 var MS_PER_HOUR = 60 * MS_PER_MINUTE;
57846 var MS_PER_400_YEARS = (365 * 400 + 97) * 24 * MS_PER_HOUR; // actual modulo - handles negative numbers (for dates before 1970):
57847
57848 function mod$1(dividend, divisor) {
57849 return (dividend % divisor + divisor) % divisor;
57850 }
57851
57852 function localStartOfDate(y, m, d) {
57853 // the date constructor remaps years 0-99 to 1900-1999
57854 if (y < 100 && y >= 0) {
57855 // preserve leap years using a full 400 year cycle, then reset
57856 return new Date(y + 400, m, d) - MS_PER_400_YEARS;
57857 } else {
57858 return new Date(y, m, d).valueOf();
57859 }
57860 }
57861
57862 function utcStartOfDate(y, m, d) {
57863 // Date.UTC remaps years 0-99 to 1900-1999
57864 if (y < 100 && y >= 0) {
57865 // preserve leap years using a full 400 year cycle, then reset
57866 return Date.UTC(y + 400, m, d) - MS_PER_400_YEARS;
57867 } else {
57868 return Date.UTC(y, m, d);
57869 }
57870 }
57871
57872 function startOf(units) {
57873 var time;
57874 units = normalizeUnits(units);
57875
57876 if (units === undefined || units === 'millisecond' || !this.isValid()) {
57877 return this;
57878 }
57879
57880 var startOfDate = this._isUTC ? utcStartOfDate : localStartOfDate;
57881
57882 switch (units) {
57883 case 'year':
57884 time = startOfDate(this.year(), 0, 1);
57885 break;
57886
57887 case 'quarter':
57888 time = startOfDate(this.year(), this.month() - this.month() % 3, 1);
57889 break;
57890
57891 case 'month':
57892 time = startOfDate(this.year(), this.month(), 1);
57893 break;
57894
57895 case 'week':
57896 time = startOfDate(this.year(), this.month(), this.date() - this.weekday());
57897 break;
57898
57899 case 'isoWeek':
57900 time = startOfDate(this.year(), this.month(), this.date() - (this.isoWeekday() - 1));
57901 break;
57902
57903 case 'day':
57904 case 'date':
57905 time = startOfDate(this.year(), this.month(), this.date());
57906 break;
57907
57908 case 'hour':
57909 time = this._d.valueOf();
57910 time -= mod$1(time + (this._isUTC ? 0 : this.utcOffset() * MS_PER_MINUTE), MS_PER_HOUR);
57911 break;
57912
57913 case 'minute':
57914 time = this._d.valueOf();
57915 time -= mod$1(time, MS_PER_MINUTE);
57916 break;
57917
57918 case 'second':
57919 time = this._d.valueOf();
57920 time -= mod$1(time, MS_PER_SECOND);
57921 break;
57922 }
57923
57924 this._d.setTime(time);
57925
57926 hooks.updateOffset(this, true);
57927 return this;
57928 }
57929
57930 function endOf(units) {
57931 var time;
57932 units = normalizeUnits(units);
57933
57934 if (units === undefined || units === 'millisecond' || !this.isValid()) {
57935 return this;
57936 }
57937
57938 var startOfDate = this._isUTC ? utcStartOfDate : localStartOfDate;
57939
57940 switch (units) {
57941 case 'year':
57942 time = startOfDate(this.year() + 1, 0, 1) - 1;
57943 break;
57944
57945 case 'quarter':
57946 time = startOfDate(this.year(), this.month() - this.month() % 3 + 3, 1) - 1;
57947 break;
57948
57949 case 'month':
57950 time = startOfDate(this.year(), this.month() + 1, 1) - 1;
57951 break;
57952
57953 case 'week':
57954 time = startOfDate(this.year(), this.month(), this.date() - this.weekday() + 7) - 1;
57955 break;
57956
57957 case 'isoWeek':
57958 time = startOfDate(this.year(), this.month(), this.date() - (this.isoWeekday() - 1) + 7) - 1;
57959 break;
57960
57961 case 'day':
57962 case 'date':
57963 time = startOfDate(this.year(), this.month(), this.date() + 1) - 1;
57964 break;
57965
57966 case 'hour':
57967 time = this._d.valueOf();
57968 time += MS_PER_HOUR - mod$1(time + (this._isUTC ? 0 : this.utcOffset() * MS_PER_MINUTE), MS_PER_HOUR) - 1;
57969 break;
57970
57971 case 'minute':
57972 time = this._d.valueOf();
57973 time += MS_PER_MINUTE - mod$1(time, MS_PER_MINUTE) - 1;
57974 break;
57975
57976 case 'second':
57977 time = this._d.valueOf();
57978 time += MS_PER_SECOND - mod$1(time, MS_PER_SECOND) - 1;
57979 break;
57980 }
57981
57982 this._d.setTime(time);
57983
57984 hooks.updateOffset(this, true);
57985 return this;
57986 }
57987
57988 function valueOf() {
57989 return this._d.valueOf() - (this._offset || 0) * 60000;
57990 }
57991
57992 function unix() {
57993 return Math.floor(this.valueOf() / 1000);
57994 }
57995
57996 function toDate() {
57997 return new Date(this.valueOf());
57998 }
57999
58000 function toArray() {
58001 var m = this;
58002 return [m.year(), m.month(), m.date(), m.hour(), m.minute(), m.second(), m.millisecond()];
58003 }
58004
58005 function toObject() {
58006 var m = this;
58007 return {
58008 years: m.year(),
58009 months: m.month(),
58010 date: m.date(),
58011 hours: m.hours(),
58012 minutes: m.minutes(),
58013 seconds: m.seconds(),
58014 milliseconds: m.milliseconds()
58015 };
58016 }
58017
58018 function toJSON() {
58019 // new Date(NaN).toJSON() === null
58020 return this.isValid() ? this.toISOString() : null;
58021 }
58022
58023 function isValid$2() {
58024 return isValid(this);
58025 }
58026
58027 function parsingFlags() {
58028 return extend({}, getParsingFlags(this));
58029 }
58030
58031 function invalidAt() {
58032 return getParsingFlags(this).overflow;
58033 }
58034
58035 function creationData() {
58036 return {
58037 input: this._i,
58038 format: this._f,
58039 locale: this._locale,
58040 isUTC: this._isUTC,
58041 strict: this._strict
58042 };
58043 } // FORMATTING
58044
58045
58046 addFormatToken(0, ['gg', 2], 0, function () {
58047 return this.weekYear() % 100;
58048 });
58049 addFormatToken(0, ['GG', 2], 0, function () {
58050 return this.isoWeekYear() % 100;
58051 });
58052
58053 function addWeekYearFormatToken(token, getter) {
58054 addFormatToken(0, [token, token.length], 0, getter);
58055 }
58056
58057 addWeekYearFormatToken('gggg', 'weekYear');
58058 addWeekYearFormatToken('ggggg', 'weekYear');
58059 addWeekYearFormatToken('GGGG', 'isoWeekYear');
58060 addWeekYearFormatToken('GGGGG', 'isoWeekYear'); // ALIASES
58061
58062 addUnitAlias('weekYear', 'gg');
58063 addUnitAlias('isoWeekYear', 'GG'); // PRIORITY
58064
58065 addUnitPriority('weekYear', 1);
58066 addUnitPriority('isoWeekYear', 1); // PARSING
58067
58068 addRegexToken('G', matchSigned);
58069 addRegexToken('g', matchSigned);
58070 addRegexToken('GG', match1to2, match2);
58071 addRegexToken('gg', match1to2, match2);
58072 addRegexToken('GGGG', match1to4, match4);
58073 addRegexToken('gggg', match1to4, match4);
58074 addRegexToken('GGGGG', match1to6, match6);
58075 addRegexToken('ggggg', match1to6, match6);
58076 addWeekParseToken(['gggg', 'ggggg', 'GGGG', 'GGGGG'], function (input, week, config, token) {
58077 week[token.substr(0, 2)] = toInt(input);
58078 });
58079 addWeekParseToken(['gg', 'GG'], function (input, week, config, token) {
58080 week[token] = hooks.parseTwoDigitYear(input);
58081 }); // MOMENTS
58082
58083 function getSetWeekYear(input) {
58084 return getSetWeekYearHelper.call(this, input, this.week(), this.weekday(), this.localeData()._week.dow, this.localeData()._week.doy);
58085 }
58086
58087 function getSetISOWeekYear(input) {
58088 return getSetWeekYearHelper.call(this, input, this.isoWeek(), this.isoWeekday(), 1, 4);
58089 }
58090
58091 function getISOWeeksInYear() {
58092 return weeksInYear(this.year(), 1, 4);
58093 }
58094
58095 function getWeeksInYear() {
58096 var weekInfo = this.localeData()._week;
58097
58098 return weeksInYear(this.year(), weekInfo.dow, weekInfo.doy);
58099 }
58100
58101 function getSetWeekYearHelper(input, week, weekday, dow, doy) {
58102 var weeksTarget;
58103
58104 if (input == null) {
58105 return weekOfYear(this, dow, doy).year;
58106 } else {
58107 weeksTarget = weeksInYear(input, dow, doy);
58108
58109 if (week > weeksTarget) {
58110 week = weeksTarget;
58111 }
58112
58113 return setWeekAll.call(this, input, week, weekday, dow, doy);
58114 }
58115 }
58116
58117 function setWeekAll(weekYear, week, weekday, dow, doy) {
58118 var dayOfYearData = dayOfYearFromWeeks(weekYear, week, weekday, dow, doy),
58119 date = createUTCDate(dayOfYearData.year, 0, dayOfYearData.dayOfYear);
58120 this.year(date.getUTCFullYear());
58121 this.month(date.getUTCMonth());
58122 this.date(date.getUTCDate());
58123 return this;
58124 } // FORMATTING
58125
58126
58127 addFormatToken('Q', 0, 'Qo', 'quarter'); // ALIASES
58128
58129 addUnitAlias('quarter', 'Q'); // PRIORITY
58130
58131 addUnitPriority('quarter', 7); // PARSING
58132
58133 addRegexToken('Q', match1);
58134 addParseToken('Q', function (input, array) {
58135 array[MONTH] = (toInt(input) - 1) * 3;
58136 }); // MOMENTS
58137
58138 function getSetQuarter(input) {
58139 return input == null ? Math.ceil((this.month() + 1) / 3) : this.month((input - 1) * 3 + this.month() % 3);
58140 } // FORMATTING
58141
58142
58143 addFormatToken('D', ['DD', 2], 'Do', 'date'); // ALIASES
58144
58145 addUnitAlias('date', 'D'); // PRIORITY
58146
58147 addUnitPriority('date', 9); // PARSING
58148
58149 addRegexToken('D', match1to2);
58150 addRegexToken('DD', match1to2, match2);
58151 addRegexToken('Do', function (isStrict, locale) {
58152 // TODO: Remove "ordinalParse" fallback in next major release.
58153 return isStrict ? locale._dayOfMonthOrdinalParse || locale._ordinalParse : locale._dayOfMonthOrdinalParseLenient;
58154 });
58155 addParseToken(['D', 'DD'], DATE);
58156 addParseToken('Do', function (input, array) {
58157 array[DATE] = toInt(input.match(match1to2)[0]);
58158 }); // MOMENTS
58159
58160 var getSetDayOfMonth = makeGetSet('Date', true); // FORMATTING
58161
58162 addFormatToken('DDD', ['DDDD', 3], 'DDDo', 'dayOfYear'); // ALIASES
58163
58164 addUnitAlias('dayOfYear', 'DDD'); // PRIORITY
58165
58166 addUnitPriority('dayOfYear', 4); // PARSING
58167
58168 addRegexToken('DDD', match1to3);
58169 addRegexToken('DDDD', match3);
58170 addParseToken(['DDD', 'DDDD'], function (input, array, config) {
58171 config._dayOfYear = toInt(input);
58172 }); // HELPERS
58173 // MOMENTS
58174
58175 function getSetDayOfYear(input) {
58176 var dayOfYear = Math.round((this.clone().startOf('day') - this.clone().startOf('year')) / 864e5) + 1;
58177 return input == null ? dayOfYear : this.add(input - dayOfYear, 'd');
58178 } // FORMATTING
58179
58180
58181 addFormatToken('m', ['mm', 2], 0, 'minute'); // ALIASES
58182
58183 addUnitAlias('minute', 'm'); // PRIORITY
58184
58185 addUnitPriority('minute', 14); // PARSING
58186
58187 addRegexToken('m', match1to2);
58188 addRegexToken('mm', match1to2, match2);
58189 addParseToken(['m', 'mm'], MINUTE); // MOMENTS
58190
58191 var getSetMinute = makeGetSet('Minutes', false); // FORMATTING
58192
58193 addFormatToken('s', ['ss', 2], 0, 'second'); // ALIASES
58194
58195 addUnitAlias('second', 's'); // PRIORITY
58196
58197 addUnitPriority('second', 15); // PARSING
58198
58199 addRegexToken('s', match1to2);
58200 addRegexToken('ss', match1to2, match2);
58201 addParseToken(['s', 'ss'], SECOND); // MOMENTS
58202
58203 var getSetSecond = makeGetSet('Seconds', false); // FORMATTING
58204
58205 addFormatToken('S', 0, 0, function () {
58206 return ~~(this.millisecond() / 100);
58207 });
58208 addFormatToken(0, ['SS', 2], 0, function () {
58209 return ~~(this.millisecond() / 10);
58210 });
58211 addFormatToken(0, ['SSS', 3], 0, 'millisecond');
58212 addFormatToken(0, ['SSSS', 4], 0, function () {
58213 return this.millisecond() * 10;
58214 });
58215 addFormatToken(0, ['SSSSS', 5], 0, function () {
58216 return this.millisecond() * 100;
58217 });
58218 addFormatToken(0, ['SSSSSS', 6], 0, function () {
58219 return this.millisecond() * 1000;
58220 });
58221 addFormatToken(0, ['SSSSSSS', 7], 0, function () {
58222 return this.millisecond() * 10000;
58223 });
58224 addFormatToken(0, ['SSSSSSSS', 8], 0, function () {
58225 return this.millisecond() * 100000;
58226 });
58227 addFormatToken(0, ['SSSSSSSSS', 9], 0, function () {
58228 return this.millisecond() * 1000000;
58229 }); // ALIASES
58230
58231 addUnitAlias('millisecond', 'ms'); // PRIORITY
58232
58233 addUnitPriority('millisecond', 16); // PARSING
58234
58235 addRegexToken('S', match1to3, match1);
58236 addRegexToken('SS', match1to3, match2);
58237 addRegexToken('SSS', match1to3, match3);
58238 var token;
58239
58240 for (token = 'SSSS'; token.length <= 9; token += 'S') {
58241 addRegexToken(token, matchUnsigned);
58242 }
58243
58244 function parseMs(input, array) {
58245 array[MILLISECOND] = toInt(('0.' + input) * 1000);
58246 }
58247
58248 for (token = 'S'; token.length <= 9; token += 'S') {
58249 addParseToken(token, parseMs);
58250 } // MOMENTS
58251
58252
58253 var getSetMillisecond = makeGetSet('Milliseconds', false); // FORMATTING
58254
58255 addFormatToken('z', 0, 0, 'zoneAbbr');
58256 addFormatToken('zz', 0, 0, 'zoneName'); // MOMENTS
58257
58258 function getZoneAbbr() {
58259 return this._isUTC ? 'UTC' : '';
58260 }
58261
58262 function getZoneName() {
58263 return this._isUTC ? 'Coordinated Universal Time' : '';
58264 }
58265
58266 var proto = Moment.prototype;
58267 proto.add = add;
58268 proto.calendar = calendar$1;
58269 proto.clone = clone;
58270 proto.diff = diff;
58271 proto.endOf = endOf;
58272 proto.format = format;
58273 proto.from = from;
58274 proto.fromNow = fromNow;
58275 proto.to = to;
58276 proto.toNow = toNow;
58277 proto.get = stringGet;
58278 proto.invalidAt = invalidAt;
58279 proto.isAfter = isAfter;
58280 proto.isBefore = isBefore;
58281 proto.isBetween = isBetween;
58282 proto.isSame = isSame;
58283 proto.isSameOrAfter = isSameOrAfter;
58284 proto.isSameOrBefore = isSameOrBefore;
58285 proto.isValid = isValid$2;
58286 proto.lang = lang;
58287 proto.locale = locale;
58288 proto.localeData = localeData;
58289 proto.max = prototypeMax;
58290 proto.min = prototypeMin;
58291 proto.parsingFlags = parsingFlags;
58292 proto.set = stringSet;
58293 proto.startOf = startOf;
58294 proto.subtract = subtract;
58295 proto.toArray = toArray;
58296 proto.toObject = toObject;
58297 proto.toDate = toDate;
58298 proto.toISOString = toISOString;
58299 proto.inspect = inspect;
58300 proto.toJSON = toJSON;
58301 proto.toString = toString;
58302 proto.unix = unix;
58303 proto.valueOf = valueOf;
58304 proto.creationData = creationData;
58305 proto.year = getSetYear;
58306 proto.isLeapYear = getIsLeapYear;
58307 proto.weekYear = getSetWeekYear;
58308 proto.isoWeekYear = getSetISOWeekYear;
58309 proto.quarter = proto.quarters = getSetQuarter;
58310 proto.month = getSetMonth;
58311 proto.daysInMonth = getDaysInMonth;
58312 proto.week = proto.weeks = getSetWeek;
58313 proto.isoWeek = proto.isoWeeks = getSetISOWeek;
58314 proto.weeksInYear = getWeeksInYear;
58315 proto.isoWeeksInYear = getISOWeeksInYear;
58316 proto.date = getSetDayOfMonth;
58317 proto.day = proto.days = getSetDayOfWeek;
58318 proto.weekday = getSetLocaleDayOfWeek;
58319 proto.isoWeekday = getSetISODayOfWeek;
58320 proto.dayOfYear = getSetDayOfYear;
58321 proto.hour = proto.hours = getSetHour;
58322 proto.minute = proto.minutes = getSetMinute;
58323 proto.second = proto.seconds = getSetSecond;
58324 proto.millisecond = proto.milliseconds = getSetMillisecond;
58325 proto.utcOffset = getSetOffset;
58326 proto.utc = setOffsetToUTC;
58327 proto.local = setOffsetToLocal;
58328 proto.parseZone = setOffsetToParsedOffset;
58329 proto.hasAlignedHourOffset = hasAlignedHourOffset;
58330 proto.isDST = isDaylightSavingTime;
58331 proto.isLocal = isLocal;
58332 proto.isUtcOffset = isUtcOffset;
58333 proto.isUtc = isUtc;
58334 proto.isUTC = isUtc;
58335 proto.zoneAbbr = getZoneAbbr;
58336 proto.zoneName = getZoneName;
58337 proto.dates = deprecate('dates accessor is deprecated. Use date instead.', getSetDayOfMonth);
58338 proto.months = deprecate('months accessor is deprecated. Use month instead', getSetMonth);
58339 proto.years = deprecate('years accessor is deprecated. Use year instead', getSetYear);
58340 proto.zone = deprecate('moment().zone is deprecated, use moment().utcOffset instead. http://momentjs.com/guides/#/warnings/zone/', getSetZone);
58341 proto.isDSTShifted = deprecate('isDSTShifted is deprecated. See http://momentjs.com/guides/#/warnings/dst-shifted/ for more information', isDaylightSavingTimeShifted);
58342
58343 function createUnix(input) {
58344 return createLocal(input * 1000);
58345 }
58346
58347 function createInZone() {
58348 return createLocal.apply(null, arguments).parseZone();
58349 }
58350
58351 function preParsePostFormat(string) {
58352 return string;
58353 }
58354
58355 var proto$1 = Locale.prototype;
58356 proto$1.calendar = calendar;
58357 proto$1.longDateFormat = longDateFormat;
58358 proto$1.invalidDate = invalidDate;
58359 proto$1.ordinal = ordinal;
58360 proto$1.preparse = preParsePostFormat;
58361 proto$1.postformat = preParsePostFormat;
58362 proto$1.relativeTime = relativeTime;
58363 proto$1.pastFuture = pastFuture;
58364 proto$1.set = set;
58365 proto$1.months = localeMonths;
58366 proto$1.monthsShort = localeMonthsShort;
58367 proto$1.monthsParse = localeMonthsParse;
58368 proto$1.monthsRegex = monthsRegex;
58369 proto$1.monthsShortRegex = monthsShortRegex;
58370 proto$1.week = localeWeek;
58371 proto$1.firstDayOfYear = localeFirstDayOfYear;
58372 proto$1.firstDayOfWeek = localeFirstDayOfWeek;
58373 proto$1.weekdays = localeWeekdays;
58374 proto$1.weekdaysMin = localeWeekdaysMin;
58375 proto$1.weekdaysShort = localeWeekdaysShort;
58376 proto$1.weekdaysParse = localeWeekdaysParse;
58377 proto$1.weekdaysRegex = weekdaysRegex;
58378 proto$1.weekdaysShortRegex = weekdaysShortRegex;
58379 proto$1.weekdaysMinRegex = weekdaysMinRegex;
58380 proto$1.isPM = localeIsPM;
58381 proto$1.meridiem = localeMeridiem;
58382
58383 function get$1(format, index, field, setter) {
58384 var locale = getLocale();
58385 var utc = createUTC().set(setter, index);
58386 return locale[field](utc, format);
58387 }
58388
58389 function listMonthsImpl(format, index, field) {
58390 if (isNumber(format)) {
58391 index = format;
58392 format = undefined;
58393 }
58394
58395 format = format || '';
58396
58397 if (index != null) {
58398 return get$1(format, index, field, 'month');
58399 }
58400
58401 var i;
58402 var out = [];
58403
58404 for (i = 0; i < 12; i++) {
58405 out[i] = get$1(format, i, field, 'month');
58406 }
58407
58408 return out;
58409 } // ()
58410 // (5)
58411 // (fmt, 5)
58412 // (fmt)
58413 // (true)
58414 // (true, 5)
58415 // (true, fmt, 5)
58416 // (true, fmt)
58417
58418
58419 function listWeekdaysImpl(localeSorted, format, index, field) {
58420 if (typeof localeSorted === 'boolean') {
58421 if (isNumber(format)) {
58422 index = format;
58423 format = undefined;
58424 }
58425
58426 format = format || '';
58427 } else {
58428 format = localeSorted;
58429 index = format;
58430 localeSorted = false;
58431
58432 if (isNumber(format)) {
58433 index = format;
58434 format = undefined;
58435 }
58436
58437 format = format || '';
58438 }
58439
58440 var locale = getLocale(),
58441 shift = localeSorted ? locale._week.dow : 0;
58442
58443 if (index != null) {
58444 return get$1(format, (index + shift) % 7, field, 'day');
58445 }
58446
58447 var i;
58448 var out = [];
58449
58450 for (i = 0; i < 7; i++) {
58451 out[i] = get$1(format, (i + shift) % 7, field, 'day');
58452 }
58453
58454 return out;
58455 }
58456
58457 function listMonths(format, index) {
58458 return listMonthsImpl(format, index, 'months');
58459 }
58460
58461 function listMonthsShort(format, index) {
58462 return listMonthsImpl(format, index, 'monthsShort');
58463 }
58464
58465 function listWeekdays(localeSorted, format, index) {
58466 return listWeekdaysImpl(localeSorted, format, index, 'weekdays');
58467 }
58468
58469 function listWeekdaysShort(localeSorted, format, index) {
58470 return listWeekdaysImpl(localeSorted, format, index, 'weekdaysShort');
58471 }
58472
58473 function listWeekdaysMin(localeSorted, format, index) {
58474 return listWeekdaysImpl(localeSorted, format, index, 'weekdaysMin');
58475 }
58476
58477 getSetGlobalLocale('en', {
58478 dayOfMonthOrdinalParse: /\d{1,2}(th|st|nd|rd)/,
58479 ordinal: function (number) {
58480 var b = number % 10,
58481 output = toInt(number % 100 / 10) === 1 ? 'th' : b === 1 ? 'st' : b === 2 ? 'nd' : b === 3 ? 'rd' : 'th';
58482 return number + output;
58483 }
58484 }); // Side effect imports
58485
58486 hooks.lang = deprecate('moment.lang is deprecated. Use moment.locale instead.', getSetGlobalLocale);
58487 hooks.langData = deprecate('moment.langData is deprecated. Use moment.localeData instead.', getLocale);
58488 var mathAbs = Math.abs;
58489
58490 function abs() {
58491 var data = this._data;
58492 this._milliseconds = mathAbs(this._milliseconds);
58493 this._days = mathAbs(this._days);
58494 this._months = mathAbs(this._months);
58495 data.milliseconds = mathAbs(data.milliseconds);
58496 data.seconds = mathAbs(data.seconds);
58497 data.minutes = mathAbs(data.minutes);
58498 data.hours = mathAbs(data.hours);
58499 data.months = mathAbs(data.months);
58500 data.years = mathAbs(data.years);
58501 return this;
58502 }
58503
58504 function addSubtract$1(duration, input, value, direction) {
58505 var other = createDuration(input, value);
58506 duration._milliseconds += direction * other._milliseconds;
58507 duration._days += direction * other._days;
58508 duration._months += direction * other._months;
58509 return duration._bubble();
58510 } // supports only 2.0-style add(1, 's') or add(duration)
58511
58512
58513 function add$1(input, value) {
58514 return addSubtract$1(this, input, value, 1);
58515 } // supports only 2.0-style subtract(1, 's') or subtract(duration)
58516
58517
58518 function subtract$1(input, value) {
58519 return addSubtract$1(this, input, value, -1);
58520 }
58521
58522 function absCeil(number) {
58523 if (number < 0) {
58524 return Math.floor(number);
58525 } else {
58526 return Math.ceil(number);
58527 }
58528 }
58529
58530 function bubble() {
58531 var milliseconds = this._milliseconds;
58532 var days = this._days;
58533 var months = this._months;
58534 var data = this._data;
58535 var seconds, minutes, hours, years, monthsFromDays; // if we have a mix of positive and negative values, bubble down first
58536 // check: https://github.com/moment/moment/issues/2166
58537
58538 if (!(milliseconds >= 0 && days >= 0 && months >= 0 || milliseconds <= 0 && days <= 0 && months <= 0)) {
58539 milliseconds += absCeil(monthsToDays(months) + days) * 864e5;
58540 days = 0;
58541 months = 0;
58542 } // The following code bubbles up values, see the tests for
58543 // examples of what that means.
58544
58545
58546 data.milliseconds = milliseconds % 1000;
58547 seconds = absFloor(milliseconds / 1000);
58548 data.seconds = seconds % 60;
58549 minutes = absFloor(seconds / 60);
58550 data.minutes = minutes % 60;
58551 hours = absFloor(minutes / 60);
58552 data.hours = hours % 24;
58553 days += absFloor(hours / 24); // convert days to months
58554
58555 monthsFromDays = absFloor(daysToMonths(days));
58556 months += monthsFromDays;
58557 days -= absCeil(monthsToDays(monthsFromDays)); // 12 months -> 1 year
58558
58559 years = absFloor(months / 12);
58560 months %= 12;
58561 data.days = days;
58562 data.months = months;
58563 data.years = years;
58564 return this;
58565 }
58566
58567 function daysToMonths(days) {
58568 // 400 years have 146097 days (taking into account leap year rules)
58569 // 400 years have 12 months === 4800
58570 return days * 4800 / 146097;
58571 }
58572
58573 function monthsToDays(months) {
58574 // the reverse of daysToMonths
58575 return months * 146097 / 4800;
58576 }
58577
58578 function as(units) {
58579 if (!this.isValid()) {
58580 return NaN;
58581 }
58582
58583 var days;
58584 var months;
58585 var milliseconds = this._milliseconds;
58586 units = normalizeUnits(units);
58587
58588 if (units === 'month' || units === 'quarter' || units === 'year') {
58589 days = this._days + milliseconds / 864e5;
58590 months = this._months + daysToMonths(days);
58591
58592 switch (units) {
58593 case 'month':
58594 return months;
58595
58596 case 'quarter':
58597 return months / 3;
58598
58599 case 'year':
58600 return months / 12;
58601 }
58602 } else {
58603 // handle milliseconds separately because of floating point math errors (issue #1867)
58604 days = this._days + Math.round(monthsToDays(this._months));
58605
58606 switch (units) {
58607 case 'week':
58608 return days / 7 + milliseconds / 6048e5;
58609
58610 case 'day':
58611 return days + milliseconds / 864e5;
58612
58613 case 'hour':
58614 return days * 24 + milliseconds / 36e5;
58615
58616 case 'minute':
58617 return days * 1440 + milliseconds / 6e4;
58618
58619 case 'second':
58620 return days * 86400 + milliseconds / 1000;
58621 // Math.floor prevents floating point math errors here
58622
58623 case 'millisecond':
58624 return Math.floor(days * 864e5) + milliseconds;
58625
58626 default:
58627 throw new Error('Unknown unit ' + units);
58628 }
58629 }
58630 } // TODO: Use this.as('ms')?
58631
58632
58633 function valueOf$1() {
58634 if (!this.isValid()) {
58635 return NaN;
58636 }
58637
58638 return this._milliseconds + this._days * 864e5 + this._months % 12 * 2592e6 + toInt(this._months / 12) * 31536e6;
58639 }
58640
58641 function makeAs(alias) {
58642 return function () {
58643 return this.as(alias);
58644 };
58645 }
58646
58647 var asMilliseconds = makeAs('ms');
58648 var asSeconds = makeAs('s');
58649 var asMinutes = makeAs('m');
58650 var asHours = makeAs('h');
58651 var asDays = makeAs('d');
58652 var asWeeks = makeAs('w');
58653 var asMonths = makeAs('M');
58654 var asQuarters = makeAs('Q');
58655 var asYears = makeAs('y');
58656
58657 function clone$1() {
58658 return createDuration(this);
58659 }
58660
58661 function get$2(units) {
58662 units = normalizeUnits(units);
58663 return this.isValid() ? this[units + 's']() : NaN;
58664 }
58665
58666 function makeGetter(name) {
58667 return function () {
58668 return this.isValid() ? this._data[name] : NaN;
58669 };
58670 }
58671
58672 var milliseconds = makeGetter('milliseconds');
58673 var seconds = makeGetter('seconds');
58674 var minutes = makeGetter('minutes');
58675 var hours = makeGetter('hours');
58676 var days = makeGetter('days');
58677 var months = makeGetter('months');
58678 var years = makeGetter('years');
58679
58680 function weeks() {
58681 return absFloor(this.days() / 7);
58682 }
58683
58684 var round = Math.round;
58685 var thresholds = {
58686 ss: 44,
58687 // a few seconds to seconds
58688 s: 45,
58689 // seconds to minute
58690 m: 45,
58691 // minutes to hour
58692 h: 22,
58693 // hours to day
58694 d: 26,
58695 // days to month
58696 M: 11 // months to year
58697
58698 }; // helper function for moment.fn.from, moment.fn.fromNow, and moment.duration.fn.humanize
58699
58700 function substituteTimeAgo(string, number, withoutSuffix, isFuture, locale) {
58701 return locale.relativeTime(number || 1, !!withoutSuffix, string, isFuture);
58702 }
58703
58704 function relativeTime$1(posNegDuration, withoutSuffix, locale) {
58705 var duration = createDuration(posNegDuration).abs();
58706 var seconds = round(duration.as('s'));
58707 var minutes = round(duration.as('m'));
58708 var hours = round(duration.as('h'));
58709 var days = round(duration.as('d'));
58710 var months = round(duration.as('M'));
58711 var years = round(duration.as('y'));
58712 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];
58713 a[2] = withoutSuffix;
58714 a[3] = +posNegDuration > 0;
58715 a[4] = locale;
58716 return substituteTimeAgo.apply(null, a);
58717 } // This function allows you to set the rounding function for relative time strings
58718
58719
58720 function getSetRelativeTimeRounding(roundingFunction) {
58721 if (roundingFunction === undefined) {
58722 return round;
58723 }
58724
58725 if (typeof roundingFunction === 'function') {
58726 round = roundingFunction;
58727 return true;
58728 }
58729
58730 return false;
58731 } // This function allows you to set a threshold for relative time strings
58732
58733
58734 function getSetRelativeTimeThreshold(threshold, limit) {
58735 if (thresholds[threshold] === undefined) {
58736 return false;
58737 }
58738
58739 if (limit === undefined) {
58740 return thresholds[threshold];
58741 }
58742
58743 thresholds[threshold] = limit;
58744
58745 if (threshold === 's') {
58746 thresholds.ss = limit - 1;
58747 }
58748
58749 return true;
58750 }
58751
58752 function humanize(withSuffix) {
58753 if (!this.isValid()) {
58754 return this.localeData().invalidDate();
58755 }
58756
58757 var locale = this.localeData();
58758 var output = relativeTime$1(this, !withSuffix, locale);
58759
58760 if (withSuffix) {
58761 output = locale.pastFuture(+this, output);
58762 }
58763
58764 return locale.postformat(output);
58765 }
58766
58767 var abs$1 = Math.abs;
58768
58769 function sign(x) {
58770 return (x > 0) - (x < 0) || +x;
58771 }
58772
58773 function toISOString$1() {
58774 // for ISO strings we do not use the normal bubbling rules:
58775 // * milliseconds bubble up until they become hours
58776 // * days do not bubble at all
58777 // * months bubble up until they become years
58778 // This is because there is no context-free conversion between hours and days
58779 // (think of clock changes)
58780 // and also not between days and months (28-31 days per month)
58781 if (!this.isValid()) {
58782 return this.localeData().invalidDate();
58783 }
58784
58785 var seconds = abs$1(this._milliseconds) / 1000;
58786 var days = abs$1(this._days);
58787 var months = abs$1(this._months);
58788 var minutes, hours, years; // 3600 seconds -> 60 minutes -> 1 hour
58789
58790 minutes = absFloor(seconds / 60);
58791 hours = absFloor(minutes / 60);
58792 seconds %= 60;
58793 minutes %= 60; // 12 months -> 1 year
58794
58795 years = absFloor(months / 12);
58796 months %= 12; // inspired by https://github.com/dordille/moment-isoduration/blob/master/moment.isoduration.js
58797
58798 var Y = years;
58799 var M = months;
58800 var D = days;
58801 var h = hours;
58802 var m = minutes;
58803 var s = seconds ? seconds.toFixed(3).replace(/\.?0+$/, '') : '';
58804 var total = this.asSeconds();
58805
58806 if (!total) {
58807 // this is the same as C#'s (Noda) and python (isodate)...
58808 // but not other JS (goog.date)
58809 return 'P0D';
58810 }
58811
58812 var totalSign = total < 0 ? '-' : '';
58813 var ymSign = sign(this._months) !== sign(total) ? '-' : '';
58814 var daysSign = sign(this._days) !== sign(total) ? '-' : '';
58815 var hmsSign = sign(this._milliseconds) !== sign(total) ? '-' : '';
58816 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' : '');
58817 }
58818
58819 var proto$2 = Duration.prototype;
58820 proto$2.isValid = isValid$1;
58821 proto$2.abs = abs;
58822 proto$2.add = add$1;
58823 proto$2.subtract = subtract$1;
58824 proto$2.as = as;
58825 proto$2.asMilliseconds = asMilliseconds;
58826 proto$2.asSeconds = asSeconds;
58827 proto$2.asMinutes = asMinutes;
58828 proto$2.asHours = asHours;
58829 proto$2.asDays = asDays;
58830 proto$2.asWeeks = asWeeks;
58831 proto$2.asMonths = asMonths;
58832 proto$2.asQuarters = asQuarters;
58833 proto$2.asYears = asYears;
58834 proto$2.valueOf = valueOf$1;
58835 proto$2._bubble = bubble;
58836 proto$2.clone = clone$1;
58837 proto$2.get = get$2;
58838 proto$2.milliseconds = milliseconds;
58839 proto$2.seconds = seconds;
58840 proto$2.minutes = minutes;
58841 proto$2.hours = hours;
58842 proto$2.days = days;
58843 proto$2.weeks = weeks;
58844 proto$2.months = months;
58845 proto$2.years = years;
58846 proto$2.humanize = humanize;
58847 proto$2.toISOString = toISOString$1;
58848 proto$2.toString = toISOString$1;
58849 proto$2.toJSON = toISOString$1;
58850 proto$2.locale = locale;
58851 proto$2.localeData = localeData;
58852 proto$2.toIsoString = deprecate('toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)', toISOString$1);
58853 proto$2.lang = lang; // Side effect imports
58854 // FORMATTING
58855
58856 addFormatToken('X', 0, 0, 'unix');
58857 addFormatToken('x', 0, 0, 'valueOf'); // PARSING
58858
58859 addRegexToken('x', matchSigned);
58860 addRegexToken('X', matchTimestamp);
58861 addParseToken('X', function (input, array, config) {
58862 config._d = new Date(parseFloat(input, 10) * 1000);
58863 });
58864 addParseToken('x', function (input, array, config) {
58865 config._d = new Date(toInt(input));
58866 }); // Side effect imports
58867
58868 hooks.version = '2.24.0';
58869 setHookCallback(createLocal);
58870 hooks.fn = proto;
58871 hooks.min = min;
58872 hooks.max = max;
58873 hooks.now = now;
58874 hooks.utc = createUTC;
58875 hooks.unix = createUnix;
58876 hooks.months = listMonths;
58877 hooks.isDate = isDate;
58878 hooks.locale = getSetGlobalLocale;
58879 hooks.invalid = createInvalid;
58880 hooks.duration = createDuration;
58881 hooks.isMoment = isMoment;
58882 hooks.weekdays = listWeekdays;
58883 hooks.parseZone = createInZone;
58884 hooks.localeData = getLocale;
58885 hooks.isDuration = isDuration;
58886 hooks.monthsShort = listMonthsShort;
58887 hooks.weekdaysMin = listWeekdaysMin;
58888 hooks.defineLocale = defineLocale;
58889 hooks.updateLocale = updateLocale;
58890 hooks.locales = listLocales;
58891 hooks.weekdaysShort = listWeekdaysShort;
58892 hooks.normalizeUnits = normalizeUnits;
58893 hooks.relativeTimeRounding = getSetRelativeTimeRounding;
58894 hooks.relativeTimeThreshold = getSetRelativeTimeThreshold;
58895 hooks.calendarFormat = getCalendarFormat;
58896 hooks.prototype = proto; // currently HTML5 input type only supports 24-hour formats
58897
58898 hooks.HTML5_FMT = {
58899 DATETIME_LOCAL: 'YYYY-MM-DDTHH:mm',
58900 // <input type="datetime-local" />
58901 DATETIME_LOCAL_SECONDS: 'YYYY-MM-DDTHH:mm:ss',
58902 // <input type="datetime-local" step="1" />
58903 DATETIME_LOCAL_MS: 'YYYY-MM-DDTHH:mm:ss.SSS',
58904 // <input type="datetime-local" step="0.001" />
58905 DATE: 'YYYY-MM-DD',
58906 // <input type="date" />
58907 TIME: 'HH:mm',
58908 // <input type="time" />
58909 TIME_SECONDS: 'HH:mm:ss',
58910 // <input type="time" step="1" />
58911 TIME_MS: 'HH:mm:ss.SSS',
58912 // <input type="time" step="0.001" />
58913 WEEK: 'GGGG-[W]WW',
58914 // <input type="week" />
58915 MONTH: 'YYYY-MM' // <input type="month" />
58916
58917 };
58918 return hooks;
58919 });
58920 });
58921
58922 // use this instance. Else, load via commonjs.
58923
58924 var moment$3 = typeof window !== 'undefined' && window['moment'] || moment$2;
58925
58926 var moment$4 = /*#__PURE__*/Object.freeze({
58927 __proto__: null,
58928 'default': moment$3,
58929 __moduleExports: moment$3
58930 });
58931
58932 var network = {
58933 Images: Images,
58934 dotparser: dotparser$1,
58935 gephiParser: gephiParser,
58936 allOptions: allOptions$2,
58937 convertDot: DOTToGraph_1,
58938 convertGephi: parseGephi
58939 }; // utils
58940
58941 var indexLegacy = /*#__PURE__*/Object.freeze({
58942 __proto__: null,
58943 network: network,
58944 DOMutil: DOMutil$1,
58945 util: esm,
58946 data: esm$1,
58947 moment: moment$4,
58948 Hammer: hammer$1,
58949 keycharm: keycharm$1,
58950 DataSet: DataSet,
58951 DataView: DataView$2,
58952 Queue: Queue,
58953 Network: Network
58954 });
58955
58956 exports.DOMutil = DOMutil$1;
58957 exports.DataSet = DataSet;
58958 exports.DataView = DataView$2;
58959 exports.Hammer = hammer$1;
58960 exports.Network = Network;
58961 exports.Queue = Queue;
58962 exports.data = esm$1;
58963 exports.default = indexLegacy;
58964 exports.keycharm = keycharm$1;
58965 exports.moment = moment$4;
58966 exports.network = network;
58967 exports.util = esm;
58968
58969 Object.defineProperty(exports, '__esModule', { value: true });
58970
58971})));
58972//# sourceMappingURL=vis-network.js.map