PageSourceSearch

https://icontrast.ru/tools/iexModal/iexModal.bundle.js

js icontrast.ru collected 2026-10-06 19:18:55 UTC 157,208 bytes, 4,503 lines download raw bytes

vendor: 5,430 bytes, lines 1-162
1(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
2/*
3 * anime.js v3.2.2
4 * (c) 2023 Julian Garnier
5 * Released under the MIT license
6 * animejs.com
7 */
8
9'use strict';
10
11// Defaults
12
13var defaultInstanceSettings = {
14  update: null,
15  begin: null,
16  loopBegin: null,
17  changeBegin: null,
18  change: null,
19  changeComplete: null,
20  loopComplete: null,
21  complete: null,
22  loop: 1,
23  direction: 'normal',
24  autoplay: true,
25  timelineOffset: 0
26};
27
28var defaultTweenSettings = {
29  duration: 1000,
30  delay: 0,
31  endDelay: 0,
32  easing: 'easeOutElastic(1, .5)',
33  round: 0
34};
35
36var validTransforms = ['translateX', 'translateY', 'translateZ', 'rotate', 'rotateX', 'rotateY', 'rotateZ', 'scale', 'scaleX', 'scaleY', 'scaleZ', 'skew', 'skewX', 'skewY', 'perspective', 'matrix', 'matrix3d'];
37
38// Caching
39
40var cache = {
41  CSS: {},
42  springs: {}
43};
44
45// Utils
46
47function minMax(val, min, max) {
48  return Math.min(Math.max(val, min), max);
49}
50
51function stringContains(str, text) {
52  return str.indexOf(text) > -1;
53}
54
55function applyArguments(func, args) {
56  return func.apply(null, args);
57}
58
59var is = {
60  arr: function (a) { return Array.isArray(a); },
61  obj: function (a) { return stringContains(Object.prototype.toString.call(a), 'Object'); },
62  pth: function (a) { return is.obj(a) && a.hasOwnProperty('totalLength'); },
63  svg: function (a) { return a instanceof SVGElement; },
64  inp: function (a) { return a instanceof HTMLInputElement; },
65  dom: function (a) { return a.nodeType || is.svg(a); },
66  str: function (a) { return typeof a === 'string'; },
67  fnc: function (a) { return typeof a === 'function'; },
68  und: function (a) { return typeof a === 'undefined'; },
69  nil: function (a) { return is.und(a) || a === null; },
70  hex: function (a) { return /(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(a); },
71  rgb: function (a) { return /^rgb/.test(a); },
72  hsl: function (a) { return /^hsl/.test(a); },
73  col: function (a) { return (is.hex(a) || is.rgb(a) || is.hsl(a)); },
74  key: function (a) { return !defaultInstanceSettings.hasOwnProperty(a) && !defaultTweenSettings.hasOwnProperty(a) && a !== 'targets' && a !== 'keyframes'; },
75};
76
77// Easings
78
79function parseEasingParameters(string) {
80  var match = /\(([^)]+)\)/.exec(string);
81  return match ? match[1].split(',').map(function (p) { return parseFloat(p); }) : [];
82}
83
84// Spring solver inspired by Webkit Copyright © 2016 Apple Inc. All rights reserved. https://webkit.org/demos/spring/spring.js
85
86function spring(string, duration) {
87
88  var params = parseEasingParameters(string);
89  var mass = minMax(is.und(params[0]) ? 1 : params[0], .1, 100);
90  var stiffness = minMax(is.und(params[1]) ? 100 : params[1], .1, 100);
91  var damping = minMax(is.und(params[2]) ? 10 : params[2], .1, 100);
92  var velocity =  minMax(is.und(params[3]) ? 0 : params[3], .1, 100);
93  var w0 = Math.sqrt(stiffness / mass);
94  var zeta = damping / (2 * Math.sqrt(stiffness * mass));
95  var wd = zeta < 1 ? w0 * Math.sqrt(1 - zeta * zeta) : 0;
96  var a = 1;
97  var b = zeta < 1 ? (zeta * w0 + -velocity) / wd : -velocity + w0;
98
99  function solver(t) {
100    var progress = duration ? (duration * t) / 1000 : t;
101    if (zeta < 1) {
102      progress = Math.exp(-progress * zeta * w0) * (a * Math.cos(wd * progress) + b * Math.sin(wd * progress));
103    } else {
104      progress = (a + b * progress) * Math.exp(-progress * w0);
105    }
106    if (t === 0 || t === 1) { return t; }
107    return 1 - progress;
108  }
109
110  function getDuration() {
111    var cached = cache.springs[string];
112    if (cached) { return cached; }
113    var frame = 1/6;
114    var elapsed = 0;
115    var rest = 0;
116    while(true) {
117      elapsed += frame;
118      if (solver(elapsed) === 1) {
119        rest++;
120        if (rest >= 16) { break; }
121      } else {
122        rest = 0;
123      }
124    }
125    var duration = elapsed * frame * 1000;
126    cache.springs[string] = duration;
127    return duration;
128  }
129
130  return duration ? solver : getDuration;
131
132}
133
134// Basic steps easing implementation https://developer.mozilla.org/fr/docs/Web/CSS/transition-timing-function
135
136function steps(steps) {
137  if ( steps === void 0 ) steps = 10;
138
139  return function (t) { return Math.ceil((minMax(t, 0.000001, 1)) * steps) * (1 / steps); };
140}
141
142// BezierEasing https://github.com/gre/bezier-easing
143
144var bezier = (function () {
145
146  var kSplineTableSize = 11;
147  var kSampleStepSize = 1.0 / (kSplineTableSize - 1.0);
148
149  function A(aA1, aA2) { return 1.0 - 3.0 * aA2 + 3.0 * aA1 }
150  function B(aA1, aA2) { return 3.0 * aA2 - 6.0 * aA1 }
151  function C(aA1)      { return 3.0 * aA1 }
152
153  function calcBezier(aT, aA1, aA2) { return ((A(aA1, aA2) * aT + B(aA1, aA2)) * aT + C(aA1)) * aT }
154  function getSlope(aT, aA1, aA2) { return 3.0 * A(aA1, aA2) * aT * aT + 2.0 * B(aA1, aA2) * aT + C(aA1) }
155
156  function binarySubdivide(aX, aA, aB, mX1, mX2) {
157    var currentX, currentT, i = 0;
158    do {
159      currentT = aA + (aB - aA) / 2.0;
160      currentX = calcBezier(currentT, mX1, mX2) - aX;
161      if (currentX > 0.0) { aB = currentT; } else { aA = currentT; }
162    } while (Math.abs(currentX) >
162 0.0000001 && ++i < 10);
163    return currentT;
164  }
165
166  function newtonRaphsonIterate(aX, aGuessT, mX1, mX2) {
167    for (var i = 0; i < 4; ++i) {
168      var currentSlope = getSlope(aGuessT, mX1, mX2);
169      if (currentSlope === 0.0) { return aGuessT; }
170      var currentX = calcBezier(aGuessT, mX1, mX2) - aX;
171      aGuessT -= currentX / currentSlope;
172    }
173    return aGuessT;
174  }
175
176  function bezier(mX1, mY1, mX2, mY2) {
177
178    if (!(0 <= mX1 && mX1 <= 1 && 0 <= mX2 && mX2 <= 1)) { return; }
179    var sampleValues = new Float32Array(kSplineTableSize);
180
181    if (mX1 !== mY1 || mX2 !== mY2) {
182      for (var i = 0; i < kSplineTableSize; ++i) {
183        sampleValues[i] = calcBezier(i * kSampleStepSize, mX1, mX2);
184      }
185    }
186
187    function getTForX(aX) {
188
189      var intervalStart = 0;
190      var currentSample = 1;
191      var lastSample = kSplineTableSize - 1;
192
193      for (; currentSample !== lastSample && sampleValues[currentSample] <= aX; ++currentSample) {
194        intervalStart += kSampleStepSize;
195      }
196
197      --currentSample;
198
199      var dist = (aX - sampleValues[currentSample]) / (sampleValues[currentSample + 1] - sampleValues[currentSample]);
200      var guessForT = intervalStart + dist * kSampleStepSize;
201      var initialSlope = getSlope(guessForT, mX1, mX2);
202
203      if (initialSlope >= 0.001) {
204        return newtonRaphsonIterate(aX, guessForT, mX1, mX2);
205      } else if (initialSlope === 0.0) {
206        return guessForT;
207      } else {
208        return binarySubdivide(aX, intervalStart, intervalStart + kSampleStepSize, mX1, mX2);
209      }
210
211    }
212
213    return function (x) {
214      if (mX1 === mY1 && mX2 === mY2) { return x; }
215      if (x === 0 || x === 1) { return x; }
216      return calcBezier(getTForX(x), mY1, mY2);
217    }
218
219  }
220
221  return bezier;
222
223})();
224
225var penner = (function () {
226
227  // Based on jQuery UI's implemenation of easing equations from Robert Penner (http://www.robertpenner.com/easing)
228
229  var eases = { linear: function () { return function (t) { return t; }; } };
230
231  var functionEasings = {
232    Sine: function () { return function (t) { return 1 - Math.cos(t * Math.PI / 2); }; },
233    Expo: function () { return function (t) { return t ? Math.pow(2, 10 * t - 10) : 0; }; },
234    Circ: function () { return function (t) { return 1 - Math.sqrt(1 - t * t); }; },
235    Back: function () { return function (t) { return t * t * (3 * t - 2); }; },
236    Bounce: function () { return function (t) {
237      var pow2, b = 4;
238      while (t < (( pow2 = Math.pow(2, --b)) - 1) / 11) {}
239      return 1 / Math.pow(4, 3 - b) - 7.5625 * Math.pow(( pow2 * 3 - 2 ) / 22 - t, 2)
240    }; },
241    Elastic: function (amplitude, period) {
242      if ( amplitude === void 0 ) amplitude = 1;
243      if ( period === void 0 ) period = .5;
244
245      var a = minMax(amplitude, 1, 10);
246      var p = minMax(period, .1, 2);
247      return function (t) {
248        return (t === 0 || t === 1) ? t : 
249          -a * Math.pow(2, 10 * (t - 1)) * Math.sin((((t - 1) - (p / (Math.PI * 2) * Math.asin(1 / a))) * (Math.PI * 2)) / p);
250      }
251    }
252  };
253
254  var baseEasings = ['Quad', 'Cubic', 'Quart', 'Quint'];
255
256  baseEasings.forEach(function (name, i) {
257    functionEasings[name] = function () { return function (t) { return Math.pow(t, i + 2); }; };
258  });
259
260  Object.keys(functionEasings).forEach(function (name) {
261    var easeIn = functionEasings[name];
262    eases['easeIn' + name] = easeIn;
263    eases['easeOut' + name] = function (a, b) { return function (t) { return 1 - easeIn(a, b)(1 - t); }; };
264    eases['easeInOut' + name] = function (a, b) { return function (t) { return t < 0.5 ? easeIn(a, b)(t * 2) / 2 : 
265      1 - easeIn(a, b)(t * -2 + 2) / 2; }; };
266    eases['easeOutIn' + name] = function (a, b) { return function (t) { return t < 0.5 ? (1 - easeIn(a, b)(1 - t * 2)) / 2 : 
267      (easeIn(a, b)(t * 2 - 1) + 1) / 2; }; };
268  });
269
270  return eases;
271
272})();
273
274function parseEasings(easing, duration) {
275  if (is.fnc(easing)) { return easing; }
276  var name = easing.split('(')[0];
277  var ease = penner[name];
278  var args = parseEasingParameters(easing);
279  switch (name) {
280    case 'spring' : return spring(easing, duration);
281    case 'cubicBezier' : return applyArguments(bezier, args);
282    case 'steps' : return applyArguments(steps, args);
283    default : return applyArguments(ease, args);
284  }
285}
286
287// Strings
288
289function selectString(str) {
290  try {
291    var nodes = document.querySelectorAll(str);
292    return nodes;
293  } catch(e) {
294    return;
295  }
296}
297
298// Arrays
299
300function filterArray(arr, callback) {
301  var len = arr.length;
302  var thisArg = arguments.length >= 2 ? arguments[1] : void 0;
303  var result = [];
304  for (var i = 0; i < len; i++) {
305    if (i in arr) {
306      var val = arr[i];
307      if (callback.call(thisArg, val, i, arr)) {
308        result.push(val);
309      }
310    }
311  }
312  return result;
313}
314
315function flattenArray(arr) {
316  return arr.reduce(function (a, b) { return a.concat(is.arr(b) ? flattenArray(b) : b); }, []);
317}
318
319function toArray(o) {
320  if (is.arr(o)) { return o; }
321  if (is.str(o)) { o = selectString(o) || o; }
322  if (o instanceof NodeList || o instanceof HTMLCollection) { return [].slice.call(o); }
323  return [o];
324}
325
326function arrayContains(arr, val) {
327  return arr.some(function (a) { return a === val; });
328}
329
330// Objects
331
332function cloneObject(o) {
333  var clone = {};
334  for (var p in o) { clone[p] = o[p]; }
335  return clone;
336}
337
338function replaceObjectProps(o1, o2) {
339  var o = cloneObject(o1);
340  for (var p in o1) { o[p] = o2.hasOwnProperty(p) ? o2[p] : o1[p]; }
341  return o;
342}
343
344function mergeObjects(o1, o2) {
345  var o = cloneObject(o1);
346  for (var p in o2) { o[p] = is.und(o1[p]) ? o2[p] : o1[p]; }
347  return o;
348}
349
350// Colors
351
352function rgbToRgba(rgbValue) {
353  var rgb = /rgb\((\d+,\s*[\d]+,\s*[\d]+)\)/g.exec(rgbValue);
354  return rgb ? ("rgba(" + (rgb[1]) + ",1)") : rgbValue;
355}
356
357function hexToRgba(hexValue) {
358  var rgx = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
359  var hex = hexValue.replace(rgx, function (m, r, g, b) { return r + r + g + g + b + b; } );
360  var rgb = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
361  var r = parseInt(rgb[1], 16);
362  var g = parseInt(rgb[2], 16);
363  var b = parseInt(rgb[3], 16);
364  return ("rgba(" + r + "," + g + "," + b + ",1)");
365}
366
367function hslToRgba(hslValue) {
368  var hsl = /hsl\((\d+),\s*([\d.]+)%,\s*([\d.]+)%\)/g.exec(hslValue) || /hsla\((\d+),\s*([\d.]+)%,\s*([\d.]+)%,\s*([\d.]+)\)/g.exec(hslValue);
369  var h = parseInt(hsl[1], 10) / 360;
370  var s = parseInt(hsl[2], 10) / 100;
371  var l = parseInt(hsl[3], 10) / 100;
372  var a = hsl[4] || 1;
373  function hue2rgb(p, q, t) {
374    if (t < 0) { t += 1; }
375    if (t > 1) { t -= 1; }
376    if (t < 1/6) { return p + (q - p) * 6 * t; }
377    if (t < 1/2) { return q; }
378    if (t < 2/3) { return p + (q - p) * (2/3 - t) * 6; }
379    return p;
380  }
381  var r, g, b;
382  if (s == 0) {
383    r = g = b = l;
384  } else {
385    var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
386    var p = 2 * l - q;
387    r = hue2rgb(p, q, h + 1/3);
388    g = hue2rgb(p, q, h);
389    b = hue2rgb(p, q, h - 1/3);
390  }
391  return ("rgba(" + (r * 255) + "," + (g * 255) + "," + (b * 255) + "," + a + ")");
392}
393
394function colorToRgb(val) {
395  if (is.rgb(val)) { return rgbToRgba(val); }
396  if (is.hex(val)) { return hexToRgba(val); }
397  if (is.hsl(val)) { return hslToRgba(val); }
398}
399
400// Units
401
402function getUnit(val) {
403  var split = /[+-]?\d*\.?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?(%|px|pt|em|rem|in|cm|mm|ex|ch|pc|vw|vh|vmin|vmax|deg|rad|turn)?$/.exec(val);
404  if (split) { return split[1]; }
405}
406
407function getTransformUnit(propName) {
408  if (stringContains(propName, 'translate') || propName === 'perspective') { return 'px'; }
409  if (stringContains(propName, 'rotate') || stringContains(propName, 'skew')) { return 'deg'; }
410}
411
412// Values
413
414function getFunctionValue(val, animatable) {
415  if (!is.fnc(val)) { return val; }
416  return val(animatable.target, animatable.id, animatable.total);
417}
418
419function getAttribute(el, prop) {
420  return el.getAttribute(prop);
421}
422
423function convertPxToUnit(el, value, unit) {
424  var valueUnit = getUnit(value);
425  if (arrayContains([unit, 'deg', 'rad', 'turn'], valueUnit)) { return value; }
426  var cached = cache.CSS[value + unit];
427  if (!is.und(cached)) { return cached; }
428  var baseline = 100;
429  var tempEl = document.createElement(el.tagName);
430  var parentEl = (el.parentNode && (el.parentNode !== document)) ? el.parentNode : document.body;
431  parentEl.appendChild(tempEl);
432  tempEl.style.position = 'absolute';
433  tempEl.style.width = baseline + unit;
434  var factor = baseline / tempEl.offsetWidth;
435  parentEl.removeChild(tempEl);
436  var convertedUnit = factor * parseFloat(value);
437  cache.CSS[value + unit] = convertedUnit;
438  return convertedUnit;
439}
440
441function getCSSValue(el, prop, unit) {
442  if (prop in el.style) {
443    var uppercasePropName = prop.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
444    var value = el.style[prop] || getComputedStyle(el).getPropertyValue(uppercasePropName) || '0';
445    return unit ? convertPxToUnit(el, value, unit) : value;
446  }
447}
448
449function getAnimationType(el, prop) {
450  if (is.dom(el) && !is.inp(el) && (!is.nil(getAttribute(el, prop)) || (is.svg(el) && el[prop]))) { return 'attribute'; }
451  if (is.dom(el) && arrayContains(validTransforms, prop)) { return 'transform'; }
452  if (is.dom(el) && (prop !== 'transform' && getCSSValue(el, prop))) { return 'css'; }
453  if (el[prop] != null) { return 'object'; }
454}
455
456function getElementTransforms(el) {
457  if (!is.dom(el)) { return; }
458  var str = el.style.transform || '';
459  var reg  = /(\w+)\(([^)]*)\)/g;
460  var transforms = new Map();
461  var m; while (m = reg.exec(str)) { transforms.set(m[1], m[2]); }
462  return transforms;
463}
464
465function getTransformValue(el, propName, animatable, unit) {
466  var defaultVal = stringContains(propName, 'scale') ? 1 : 0 + getTransformUnit(propName);
467  var value = getElementTransforms(el).get(propName) || defaultVal;
468  if (animatable) {
469    animatable.transforms.list.set(propName, value);
470    animatable.transforms['last'] = propName;
471  }
472  return unit ? convertPxToUnit(el, value, unit) : value;
473}
474
475function getOriginalTargetValue(target, propName, unit, animatable) {
476  switch (getAnimationType(target, propName)) {
477    case 'transform': return getTransformValue(target, propName, animatable, unit);
478    case 'css': return getCSSValue(target, propName, unit);
479    case 'attribute': return getAttribute(target, propName);
480    default: return target[propName] || 0;
481  }
482}
483
484function getRelativeValue(to, from) {
485  var operator = /^(\*=|\+=|-=)/.exec(to);
486  if (!operator) { return to; }
487  var u = getUnit(to) || 0;
488  var x = parseFloat(from);
489  var y = parseFloat(to.replace(operator[0], ''));
490  switch (operator[0][0]) {
491    case '+': return x + y + u;
492    case '-': return x - y + u;
493    case '*': return x * y + u;
494  }
495}
496
497function validateValue(val, unit) {
498  if (is.col(val)) { return colorToRgb(val); }
499  if (/\s/g.test(val)) { return val; }
500  var originalUnit = getUnit(val);
501  var unitLess = originalUnit ? val.substr(0, val.length - originalUnit.length) : val;
502  if (unit) { return unitLess + unit; }
503  return unitLess;
504}
505
506// getTotalLength() equivalent for circle, rect, polyline, polygon and line shapes
507// adapted from https://gist.github.com/SebLambla/3e0550c496c236709744
508
509function getDistance(p1, p2) {
510  return Math.sqrt(Math.pow(p2.x - p1.x, 2) + Math.pow(p2.y - p1.y, 2));
511}
512
513function getCircleLength(el) {
514  return Math.PI * 2 * getAttribute(el, 'r');
515}
516
517function getRectLength(el) {
518  return (getAttribute(el, 'width') * 2) + (getAttribute(el, 'height') * 2);
519}
520
521function getLineLength(el) {
522  return getDistance(
523    {x: getAttribute(el, 'x1'), y: getAttribute(el, 'y1')}, 
524    {x: getAttribute(el, 'x2'), y: getAttribute(el, 'y2')}
525  );
526}
527
528function getPolylineLength(el) {
529  var points = el.points;
530  var totalLength = 0;
531  var previousPos;
532  for (var i = 0 ; i < points.numberOfItems; i++) {
533    var currentPos = points.getItem(i);
534    if (i > 0) { totalLength += getDistance(previousPos, currentPos); }
535    previousPos = currentPos;
536  }
537  return totalLength;
538}
539
540function getPolygonLength(el) {
541  var points = el.points;
542  return getPolylineLength(el) + getDistance(points.getItem(points.numberOfItems - 1), points.getItem(0));
543}
544
545// Path animation
546
547function getTotalLength(el) {
548  if (el.getTotalLength) { return el.getTotalLength(); }
549  switch(el.tagName.toLowerCase()) {
550    case 'circle': return getCircleLength(el);
551    case 'rect': return getRectLength(el);
552    case 'line': return getLineLength(el);
553    case 'polyline': return getPolylineLength(el);
554    case 'polygon': return getPolygonLength(el);
555  }
556}
557
558function setDashoffset(el) {
559  var pathLength = getTotalLength(el);
560  el.setAttribute('stroke-dasharray', pathLength);
561  return pathLength;
562}
563
564// Motion path
565
566function getParentSvgEl(el) {
567  var parentEl = el.parentNode;
568  while (is.svg(parentEl)) {
569    if (!is.svg(parentEl.parentNode)) { break; }
570    parentEl = parentEl.parentNode;
571  }
572  return parentEl;
573}
574
575function getParentSvg(pathEl, svgData) {
576  var svg = svgData || {};
577  var parentSvgEl = svg.el || getParentSvgEl(pathEl);
578  var rect = parentSvgEl.getBoundingClientRect();
579  var viewBoxAttr = getAttribute(parentSvgEl, 'viewBox');
580  var width = rect.width;
581  var height = rect.height;
582  var viewBox = svg.viewBox || (viewBoxAttr ? viewBoxAttr.split(' ') : [0, 0, width, height]);
583  return {
584    el: parentSvgEl,
585    viewBox: viewBox,
586    x: viewBox[0] / 1,
587    y: viewBox[1] / 1,
588    w: width,
589    h: height,
590    vW: viewBox[2],
591    vH: viewBox[3]
592  }
593}
594
595function getPath(path, percent) {
596  var pathEl = is.str(path) ? selectString(path)[0] : path;
597  var p = percent || 100;
598  return function(property) {
599    return {
600      property: property,
601      el: pathEl,
602      svg: getParentSvg(pathEl),
603      totalLength: getTotalLength(pathEl) * (p / 100)
604    }
605  }
606}
607
608function getPathProgress(path, progress, isPathTargetInsideSVG) {
609  function point(offset) {
610    if ( offset === void 0 ) offset = 0;
611
612    var l = progress + offset >= 1 ? progress + offset : 0;
613    return path.el.getPointAtLength(l);
614  }
615  var svg = getParentSvg(path.el, path.svg);
616  var p = point();
617  var p0 = point(-1);
618  var p1 = point(+1);
619  var scaleX = isPathTargetInsideSVG ? 1 : svg.w / svg.vW;
620  var scaleY = isPathTargetInsideSVG ? 1 : svg.h / svg.vH;
621  switch (path.property) {
622    case 'x': return (p.x - svg.x) * scaleX;
623    case 'y': return (p.y - svg.y) * scaleY;
624    case 'angle': return Math.atan2(p1.y - p0.y, p1.x - p0.x) * 180 / Math.PI;
625  }
626}
627
628// Decompose value
629
630function decomposeValue(val, unit) {
631  // const rgx = /-?\d*\.?\d+/g; // handles basic numbers
632  // const rgx = /[+-]?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?/g; // handles exponents notation
633  var rgx = /[+-]?\d*\.?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?/g; // handles exponents notation
634  var value = validateValue((is.pth(val) ? val.totalLength : val), unit) + '';
635  return {
636    original: value,
637    numbers: value.match(rgx) ? value.match(rgx).map(Number) : [0],
638    strings: (is.str(val) || unit) ? value.split(rgx) : []
639  }
640}
641
642// Animatables
643
644function parseTargets(targets) {
645  var targetsArray = targets ? (flattenArray(is.arr(targets) ? targets.map(toArray) : toArray(targets))) : [];
646  return filterArray(targetsArray, function (item, pos, self) { return self.indexOf(item) === pos; });
647}
648
649function getAnimatables(targets) {
650  var parsed = parseTargets(targets);
651  return parsed.map(function (t, i) {
652    return {target: t, id: i, total: parsed.length, transforms: { list: getElementTransforms(t) } };
653  });
654}
655
656// Properties
657
658function normalizePropertyTweens(prop, tweenSettings) {
659  var settings = cloneObject(tweenSettings);
660  // Override duration if easing is a spring
661  if (/^spring/.test(settings.easing)) { settings.duration = spring(settings.easing); }
662  if (is.arr(prop)) {
663    var l = prop.length;
664    var isFromTo = (l === 2 && !is.obj(prop[0]));
665    if (!isFromTo) {
666      // Duration divided by the number of tweens
667      if (!is.fnc(tweenSettings.duration)) { settings.duration = tweenSettings.duration / l; }
668    } else {
669      // Transform [from, to] values shorthand to a valid tween value
670      prop = {value: prop};
671    }
672  }
673  var propArray = is.arr(prop) ? prop : [prop];
674  return propArray.map(function (v, i) {
675    var obj = (is.obj(v) && !is.pth(v)) ? v : {value: v};
676    // Default delay value should only be applied to the first tween
677    if (is.und(obj.delay)) { obj.delay = !i ? tweenSettings.delay : 0; }
678    // Default endDelay value should only be applied to the last tween
679    if (is.und(obj.endDelay)) { obj.endDelay = i === propArray.length - 1 ? tweenSettings.endDelay : 0; }
680    return obj;
681  }).map(function (k) { return mergeObjects(k, settings); });
682}
683
684
685function flattenKeyframes(keyframes) {
686  var propertyNames = filterArray(flattenArray(keyframes.map(function (key) { return Object.keys(key); })), function (p) { return is.key(p); })
687  .reduce(function (a,b) { if (a.indexOf(b) < 0) { a.push(b); } return a; }, []);
688  var properties = {};
689  var loop = function ( i ) {
690    var propName = propertyNames[i];
691    properties[propName] = keyframes.map(function (key) {
692      var newKey = {};
693      for (var p in key) {
694        if (is.key(p)) {
695          if (p == propName) { newKey.value = key[p]; }
696        } else {
697          newKey[p] = key[p];
698        }
699      }
700      return newKey;
701    });
702  };
703
704  for (var i = 0; i < propertyNames.length; i++) loop( i );
705  return properties;
706}
707
vendor: 4,382 bytes, lines 708-834
708function getProperties(tweenSettings, params) {
709  var properties = [];
710  var keyframes = params.keyframes;
711  if (keyframes) { params = mergeObjects(flattenKeyframes(keyframes), params); }
712  for (var p in params) {
713    if (is.key(p)) {
714      properties.push({
715        name: p,
716        tweens: normalizePropertyTweens(params[p], tweenSettings)
717      });
718    }
719  }
720  return properties;
721}
722
723// Tweens
724
725function normalizeTweenValues(tween, animatable) {
726  var t = {};
727  for (var p in tween) {
728    var value = getFunctionValue(tween[p], animatable);
729    if (is.arr(value)) {
730      value = value.map(function (v) { return getFunctionValue(v, animatable); });
731      if (value.length === 1) { value = value[0]; }
732    }
733    t[p] = value;
734  }
735  t.duration = parseFloat(t.duration);
736  t.delay = parseFloat(t.delay);
737  return t;
738}
739
740function normalizeTweens(prop, animatable) {
741  var previousTween;
742  return prop.tweens.map(function (t) {
743    var tween = normalizeTweenValues(t, animatable);
744    var tweenValue = tween.value;
745    var to = is.arr(tweenValue) ? tweenValue[1] : tweenValue;
746    var toUnit = getUnit(to);
747    var originalValue = getOriginalTargetValue(animatable.target, prop.name, toUnit, animatable);
748    var previousValue = previousTween ? previousTween.to.original : originalValue;
749    var from = is.arr(tweenValue) ? tweenValue[0] : previousValue;
750    var fromUnit = getUnit(from) || getUnit(originalValue);
751    var unit = toUnit || fromUnit;
752    if (is.und(to)) { to = previousValue; }
753    tween.from = decomposeValue(from, unit);
754    tween.to = decomposeValue(getRelativeValue(to, from), unit);
755    tween.start = previousTween ? previousTween.end : 0;
756    tween.end = tween.start + tween.delay + tween.duration + tween.endDelay;
757    tween.easing = parseEasings(tween.easing, tween.duration);
758    tween.isPath = is.pth(tweenValue);
759    tween.isPathTargetInsideSVG = tween.isPath && is.svg(animatable.target);
760    tween.isColor = is.col(tween.from.original);
761    if (tween.isColor) { tween.round = 1; }
762    previousTween = tween;
763    return tween;
764  });
765}
766
767// Tween progress
768
769var setProgressValue = {
770  css: function (t, p, v) { return t.style[p] = v; },
771  attribute: function (t, p, v) { return t.setAttribute(p, v); },
772  object: function (t, p, v) { return t[p] = v; },
773  transform: function (t, p, v, transforms, manual) {
774    transforms.list.set(p, v);
775    if (p === transforms.last || manual) {
776      var str = '';
777      transforms.list.forEach(function (value, prop) { str += prop + "(" + value + ") "; });
778      t.style.transform = str;
779    }
780  }
781};
782
783// Set Value helper
784
785function setTargetsValue(targets, properties) {
786  var animatables = getAnimatables(targets);
787  animatables.forEach(function (animatable) {
788    for (var property in properties) {
789      var value = getFunctionValue(properties[property], animatable);
790      var target = animatable.target;
791      var valueUnit = getUnit(value);
792      var originalValue = getOriginalTargetValue(target, property, valueUnit, animatable);
793      var unit = valueUnit || getUnit(originalValue);
794      var to = getRelativeValue(validateValue(value, unit), originalValue);
795      var animType = getAnimationType(target, property);
796      setProgressValue[animType](target, property, to, animatable.transforms, true);
797    }
798  });
799}
800
801// Animations
802
803function createAnimation(animatable, prop) {
804  var animType = getAnimationType(animatable.target, prop.name);
805  if (animType) {
806    var tweens = normalizeTweens(prop, animatable);
807    var lastTween = tweens[tweens.length - 1];
808    return {
809      type: animType,
810      property: prop.name,
811      animatable: animatable,
812      tweens: tweens,
813      duration: lastTween.end,
814      delay: tweens[0].delay,
815      endDelay: lastTween.endDelay
816    }
817  }
818}
819
820function getAnimations(animatables, properties) {
821  return filterArray(flattenArray(animatables.map(function (animatable) {
822    return properties.map(function (prop) {
823      return createAnimation(animatable, prop);
824    });
825  })), function (a) { return !is.und(a); });
826}
827
828// Create Instance
829
830function getInstanceTimings(animations, tweenSettings) {
831  var animLength = animations.length;
832  var getTlOffset = function (anim) { return anim.timelineOffset ? anim.timelineOffset : 0; };
833  var timings = {};
834  timings.duration = animLength ? Math.max.apply(Math, animations.map(function (anim) { return getTlOffset(anim) + anim.duration; }
834)) : tweenSettings.duration;
835  timings.delay = animLength ? Math.min.apply(Math, animations.map(function (anim) { return getTlOffset(anim) + anim.delay; })) : tweenSettings.delay;
836  timings.endDelay = animLength ? timings.duration - Math.max.apply(Math, animations.map(function (anim) { return getTlOffset(anim) + anim.duration - anim.endDelay; })) : tweenSettings.endDelay;
837  return timings;
838}
839
840var instanceID = 0;
841
842function createNewInstance(params) {
843  var instanceSettings = replaceObjectProps(defaultInstanceSettings, params);
844  var tweenSettings = replaceObjectProps(defaultTweenSettings, params);
845  var properties = getProperties(tweenSettings, params);
846  var animatables = getAnimatables(params.targets);
847  var animations = getAnimations(animatables, properties);
848  var timings = getInstanceTimings(animations, tweenSettings);
849  var id = instanceID;
850  instanceID++;
851  return mergeObjects(instanceSettings, {
852    id: id,
853    children: [],
854    animatables: animatables,
855    animations: animations,
856    duration: timings.duration,
857    delay: timings.delay,
858    endDelay: timings.endDelay
859  });
860}
861
862// Core
863
864var activeInstances = [];
865
866var engine = (function () {
867  var raf;
868
869  function play() {
870    if (!raf && (!isDocumentHidden() || !anime.suspendWhenDocumentHidden) && activeInstances.length > 0) {
871      raf = requestAnimationFrame(step);
872    }
873  }
874  function step(t) {
875    // memo on algorithm issue:
876    // dangerous iteration over mutable `activeInstances`
877    // (that collection may be updated from within callbacks of `tick`-ed animation instances)
878    var activeInstancesLength = activeInstances.length;
879    var i = 0;
880    while (i < activeInstancesLength) {
881      var activeInstance = activeInstances[i];
882      if (!activeInstance.paused) {
883        activeInstance.tick(t);
884        i++;
885      } else {
886        activeInstances.splice(i, 1);
887        activeInstancesLength--;
888      }
889    }
890    raf = i > 0 ? requestAnimationFrame(step) : undefined;
891  }
892
893  function handleVisibilityChange() {
894    if (!anime.suspendWhenDocumentHidden) { return; }
895
896    if (isDocumentHidden()) {
897      // suspend ticks
898      raf = cancelAnimationFrame(raf);
899    } else { // is back to active tab
900      // first adjust animations to consider the time that ticks were suspended
901      activeInstances.forEach(
902        function (instance) { return instance ._onDocumentVisibility(); }
903      );
904      engine();
905    }
906  }
907  if (typeof document !== 'undefined') {
908    document.addEventListener('visibilitychange', handleVisibilityChange);
909  }
910
911  return play;
912})();
913
914function isDocumentHidden() {
915  return !!document && document.hidden;
916}
917
918// Public Instance
919
920function anime(params) {
921  if ( params === void 0 ) params = {};
922
923
924  var startTime = 0, lastTime = 0, now = 0;
925  var children, childrenLength = 0;
926  var resolve = null;
927
928  function makePromise(instance) {
929    var promise = window.Promise && new Promise(function (_resolve) { return resolve = _resolve; });
930    instance.finished = promise;
931    return promise;
932  }
933
934  var instance = createNewInstance(params);
935  var promise = makePromise(instance);
936
937  function toggleInstanceDirection() {
938    var direction = instance.direction;
939    if (direction !== 'alternate') {
940      instance.direction = direction !== 'normal' ? 'normal' : 'reverse';
941    }
942    instance.reversed = !instance.reversed;
943    children.forEach(function (child) { return child.reversed = instance.reversed; });
944  }
945
946  function adjustTime(time) {
947    return instance.reversed ? instance.duration - time : time;
948  }
949
950  function resetTime() {
951    startTime = 0;
952    lastTime = adjustTime(instance.currentTime) * (1 / anime.speed);
953  }
954
955  function seekChild(time, child) {
956    if (child) { child.seek(time - child.timelineOffset); }
957  }
958
959  function syncInstanceChildren(time) {
960    if (!instance.reversePlayback) {
961      for (var i = 0; i < childrenLength; i++) { seekChild(time, children[i]); }
962    } else {
963      for (var i$1 = childrenLength; i$1--;) { seekChild(time, children[i$1]); }
964    }
965  }
966
967  function setAnimationsProgress(insTime) {
968    var i = 0;
969    var animations = instance.animations;
970    var animationsLength = animations.length;
971    while (i < animationsLength) {
972      var anim = animations[i];
973      var animatable = anim.animatable;
974      var tweens = anim.tweens;
975      var tweenLength = tweens.length - 1;
976      var tween = tweens[tweenLength];
977      // Only check for keyframes if there is more than one tween
978      if (tweenLength) { tween = filterArray(tweens, function (t) { return (insTime < t.end); })[0] || tween; }
979      var elapsed = minMax(insTime - tween.start - tween.delay, 0, tween.duration) / tween.duration;
980      var eased = isNaN(elapsed) ? 1 : tween.easing(elapsed);
981      var strings = tween.to.strings;
982      var round = tween.round;
983      var numbers = [];
984      var toNumbersLength = tween.to.numbers.length;
985      var progress = (void 0);
986      for (var n = 0; n < toNumbersLength; n++) {
987        var value = (void 0);
988        var toNumber = tween.to.numbers[n];
989        var fromNumber = tween.from.numbers[n] || 0;
990        if (!tween.isPath) {
991          value = fromNumber + (eased * (toNumber - fromNumber));
992        } else {
993          value = getPathProgress(tween.value, eased * toNumber, tween.isPathTargetInsideSVG);
994        }
995        if (round) {
996          if (!(tween.isColor && n > 2)) {
997            value = Math.round(value * round) / round;
998          }
999        }
1000        numbers.push(value);
1001      }
1002      // Manual Array.reduce for better performances
1003      var stringsLength = strings.length;
1004      if (!stringsLength) {
1005        progress = numbers[0];
1006      } else {
1007        progress = strings[0];
1008        for (var s = 0; s < stringsLength; s++) {
1009          var a = strings[s];
1010          var b = strings[s + 1];
1011          var n$1 = numbers[s];
1012          if (!isNaN(n$1)) {
1013            if (!b) {
1014              progress += n$1 + ' ';
1015            } else {
1016              progress += n$1 + b;
1017            }
1018          }
1019        }
1020      }
1021      setProgressValue[anim.type](animatable.target, anim.property, progress, animatable.transforms);
1022      anim.currentValue = progress;
1023      i++;
1024    }
1025  }
1026
1027  function setCallback(cb) {
1028    if (instance[cb] && !instance.passThrough) { instance[cb](instance); }
1029  }
1030
1031  function countIteration() {
1032    if (instance.remaining && instance.remaining !== true) {
1033      instance.remaining--;
1034    }
1035  }
1036
1037  function setInstanceProgress(engineTime) {
1038    var insDuration = instance.duration;
1039    var insDelay = instance.delay;
1040    var insEndDelay = insDuration - instance.endDelay;
1041    var insTime = adjustTime(engineTime);
1042    instance.progress = minMax((insTime / insDuration) * 100, 0, 100);
1043    instance.reversePlayback = insTime < instance.currentTime;
1044    if (children) { syncInstanceChildren(insTime); }
1045    if (!instance.began && instance.currentTime > 0) {
1046      instance.began = true;
1047      setCallback('begin');
1048    }
1049    if (!instance.loopBegan && instance.currentTime > 0) {
1050      instance.loopBegan = true;
1051      setCallback('loopBegin');
1052    }
1053    if (insTime <= insDelay && instance.currentTime !== 0) {
1054      setAnimationsProgress(0);
1055    }
1056    if ((insTime >= insEndDelay && instance.currentTime !== insDuration) || !insDuration) {
1057      setAnimationsProgress(insDuration);
1058    }
1059    if (insTime > insDelay && insTime < insEndDelay) {
1060      if (!instance.changeBegan) {
1061        instance.changeBegan = true;
1062        instance.changeCompleted = false;
1063        setCallback('changeBegin');
1064      }
1065      setCallback('change');
1066      setAnimationsProgress(insTime);
1067    } else {
1068      if (instance.changeBegan) {
1069        instance.changeCompleted = true;
1070        instance.changeBegan = false;
1071        setCallback('changeComplete');
1072      }
1073    }
1074    instance.currentTime = minMax(insTime, 0, insDuration);
1075    if (instance.began) { setCallback('update'); }
1076    if (engineTime >= insDuration) {
1077      lastTime = 0;
1078      countIteration();
1079      if (!instance.remaining) {
1080        instance.paused = true;
1081        if (!instance.completed) {
1082          instance.completed = true;
1083          setCallback('loopComplete');
1084          setCallback('complete');
1085          if (!instance.passThrough && 'Promise' in window) {
1086            resolve();
1087            promise = makePromise(instance);
1088          }
1089        }
1090      } else {
1091        startTime = now;
1092        setCallback('loopComplete');
1093        instance.loopBegan = false;
1094        if (instance.direction === 'alternate') {
1095          toggleInstanceDirection();
1096        }
1097      }
1098    }
1099  }
1100
1101  instance.reset = function() {
1102    var direction = instance.direction;
1103    instance.passThrough = false;
1104    instance.currentTime = 0;
1105    instance.progress = 0;
1106    instance.paused = true;
vendor: 5,548 bytes, lines 1107-1274
1107    instance.began = false;
1108    instance.loopBegan = false;
1109    instance.changeBegan = false;
1110    instance.completed = false;
1111    instance.changeCompleted = false;
1112    instance.reversePlayback = false;
1113    instance.reversed = direction === 'reverse';
1114    instance.remaining = instance.loop;
1115    children = instance.children;
1116    childrenLength = children.length;
1117    for (var i = childrenLength; i--;) { instance.children[i].reset(); }
1118    if (instance.reversed && instance.loop !== true || (direction === 'alternate' && instance.loop === 1)) { instance.remaining++; }
1119    setAnimationsProgress(instance.reversed ? instance.duration : 0);
1120  };
1121
1122  // internal method (for engine) to adjust animation timings before restoring engine ticks (rAF)
1123  instance._onDocumentVisibility = resetTime;
1124
1125  // Set Value helper
1126
1127  instance.set = function(targets, properties) {
1128    setTargetsValue(targets, properties);
1129    return instance;
1130  };
1131
1132  instance.tick = function(t) {
1133    now = t;
1134    if (!startTime) { startTime = now; }
1135    setInstanceProgress((now + (lastTime - startTime)) * anime.speed);
1136  };
1137
1138  instance.seek = function(time) {
1139    setInstanceProgress(adjustTime(time));
1140  };
1141
1142  instance.pause = function() {
1143    instance.paused = true;
1144    resetTime();
1145  };
1146
1147  instance.play = function() {
1148    if (!instance.paused) { return; }
1149    if (instance.completed) { instance.reset(); }
1150    instance.paused = false;
1151    activeInstances.push(instance);
1152    resetTime();
1153    engine();
1154  };
1155
1156  instance.reverse = function() {
1157    toggleInstanceDirection();
1158    instance.completed = instance.reversed ? false : true;
1159    resetTime();
1160  };
1161
1162  instance.restart = function() {
1163    instance.reset();
1164    instance.play();
1165  };
1166
1167  instance.remove = function(targets) {
1168    var targetsArray = parseTargets(targets);
1169    removeTargetsFromInstance(targetsArray, instance);
1170  };
1171
1172  instance.reset();
1173
1174  if (instance.autoplay) { instance.play(); }
1175
1176  return instance;
1177
1178}
1179
1180// Remove targets from animation
1181
1182function removeTargetsFromAnimations(targetsArray, animations) {
1183  for (var a = animations.length; a--;) {
1184    if (arrayContains(targetsArray, animations[a].animatable.target)) {
1185      animations.splice(a, 1);
1186    }
1187  }
1188}
1189
1190function removeTargetsFromInstance(targetsArray, instance) {
1191  var animations = instance.animations;
1192  var children = instance.children;
1193  removeTargetsFromAnimations(targetsArray, animations);
1194  for (var c = children.length; c--;) {
1195    var child = children[c];
1196    var childAnimations = child.animations;
1197    removeTargetsFromAnimations(targetsArray, childAnimations);
1198    if (!childAnimations.length && !child.children.length) { children.splice(c, 1); }
1199  }
1200  if (!animations.length && !children.length) { instance.pause(); }
1201}
1202
1203function removeTargetsFromActiveInstances(targets) {
1204  var targetsArray = parseTargets(targets);
1205  for (var i = activeInstances.length; i--;) {
1206    var instance = activeInstances[i];
1207    removeTargetsFromInstance(targetsArray, instance);
1208  }
1209}
1210
1211// Stagger helpers
1212
1213function stagger(val, params) {
1214  if ( params === void 0 ) params = {};
1215
1216  var direction = params.direction || 'normal';
1217  var easing = params.easing ? parseEasings(params.easing) : null;
1218  var grid = params.grid;
1219  var axis = params.axis;
1220  var fromIndex = params.from || 0;
1221  var fromFirst = fromIndex === 'first';
1222  var fromCenter = fromIndex === 'center';
1223  var fromLast = fromIndex === 'last';
1224  var isRange = is.arr(val);
1225  var val1 = isRange ? parseFloat(val[0]) : parseFloat(val);
1226  var val2 = isRange ? parseFloat(val[1]) : 0;
1227  var unit = getUnit(isRange ? val[1] : val) || 0;
1228  var start = params.start || 0 + (isRange ? val1 : 0);
1229  var values = [];
1230  var maxValue = 0;
1231  return function (el, i, t) {
1232    if (fromFirst) { fromIndex = 0; }
1233    if (fromCenter) { fromIndex = (t - 1) / 2; }
1234    if (fromLast) { fromIndex = t - 1; }
1235    if (!values.length) {
1236      for (var index = 0; index < t; index++) {
1237        if (!grid) {
1238          values.push(Math.abs(fromIndex - index));
1239        } else {
1240          var fromX = !fromCenter ? fromIndex%grid[0] : (grid[0]-1)/2;
1241          var fromY = !fromCenter ? Math.floor(fromIndex/grid[0]) : (grid[1]-1)/2;
1242          var toX = index%grid[0];
1243          var toY = Math.floor(index/grid[0]);
1244          var distanceX = fromX - toX;
1245          var distanceY = fromY - toY;
1246          var value = Math.sqrt(distanceX * distanceX + distanceY * distanceY);
1247          if (axis === 'x') { value = -distanceX; }
1248          if (axis === 'y') { value = -distanceY; }
1249          values.push(value);
1250        }
1251        maxValue = Math.max.apply(Math, values);
1252      }
1253      if (easing) { values = values.map(function (val) { return easing(val / maxValue) * maxValue; }); }
1254      if (direction === 'reverse') { values = values.map(function (val) { return axis ? (val < 0) ? val * -1 : -val : Math.abs(maxValue - val); }); }
1255    }
1256    var spacing = isRange ? (val2 - val1) / maxValue : val1;
1257    return start + (spacing * (Math.round(values[i] * 100) / 100)) + unit;
1258  }
1259}
1260
1261// Timeline
1262
1263function timeline(params) {
1264  if ( params === void 0 ) params = {};
1265
1266  var tl = anime(params);
1267  tl.duration = 0;
1268  tl.add = function(instanceParams, timelineOffset) {
1269    var tlIndex = activeInstances.indexOf(tl);
1270    var children = tl.children;
1271    if (tlIndex > -1) { activeInstances.splice(tlIndex, 1); }
1272    function passThrough(ins) { ins.passThrough = true; }
1273    for (var i = 0; i < children.length; i++) { passThrough(children[i]); }
1274    var insParams = mergeObjects(instanceParams, replaceObjectProps(defaultTweenSett
1274ings, params));
1275    insParams.targets = insParams.targets || params.targets;
1276    var tlDuration = tl.duration;
1277    insParams.autoplay = false;
1278    insParams.direction = tl.direction;
1279    insParams.timelineOffset = is.und(timelineOffset) ? tlDuration : getRelativeValue(timelineOffset, tlDuration);
1280    passThrough(tl);
1281    tl.seek(insParams.timelineOffset);
1282    var ins = anime(insParams);
1283    passThrough(ins);
1284    children.push(ins);
1285    var timings = getInstanceTimings(children, params);
1286    tl.delay = timings.delay;
1287    tl.endDelay = timings.endDelay;
1288    tl.duration = timings.duration;
1289    tl.seek(0);
1290    tl.reset();
1291    if (tl.autoplay) { tl.play(); }
1292    return tl;
1293  };
1294  return tl;
1295}
1296
1297anime.version = '3.2.2';
1298anime.speed = 1;
1299// TODO:#review: naming, documentation
1300anime.suspendWhenDocumentHidden = true;
1301anime.running = activeInstances;
1302anime.remove = removeTargetsFromActiveInstances;
1303anime.get = getOriginalTargetValue;
1304anime.set = setTargetsValue;
1305anime.convertPx = convertPxToUnit;
1306anime.path = getPath;
1307anime.setDashoffset = setDashoffset;
1308anime.stagger = stagger;
1309anime.timeline = timeline;
1310anime.easing = parseEasings;
1311anime.penner = penner;
1312anime.random = function (min, max) { return Math.floor(Math.random() * (max - min + 1)) + min; };
1313
1314module.exports = anime;
1315
1316},{}],2:[function(require,module,exports){
1317/**
1318 * iexModal
1319 * @constructor
1320 */
1321window.IexModal = function($){
1322    var app = this;
1323
1324    app.PerfectScrollbar = require('./perfect-srollbar.js');
1325    app.AnimeJs = require('./anime.js');
1326
1327    app.$window = $(window);
1328    app.$document = $(document);
1329    app.$html = $('html');
1330    app.$body = $('body');
1331
1332    app.classWrap = 'iexmodal';
1333
1334    // Классы элементов интерфейса
1335    app.classPopup = app.classWrap+'-popup';
1336    app.classClose = app.classWrap+'-close';
1337    app.classCloseAll = app.classWrap+'-close-all';
1338    app.classInner = app.classWrap+'-inner';
1339    app.classInnerWrap = app.classWrap+'-inner-wrap';
1340    app.classBtn = app.classWrap+'-show';
1341    app.classSprite = app.classWrap+'-sprite';
1342    app.classContent = app.classWrap+'-content';
1343    app.classContentWrap = app.classWrap+'-content-wrap';
1344    app.classDebugWrap = app.classWrap+'-debug-wrap';
1345    app.classDebugCode = app.classWrap+'-debug-code';
1346
1347    // Классы-модификаторы (классы состояния)
1348    app.classOpened = app.classWrap+'-opened';
1349    app.classOuterScroll = app.classWrap+'-outerscroll';
1350    app.classLoading = app.classWrap+'-loading';
1351    app.classBottom = app.classWrap+'-bottom';
1352    app.classOverflowY = app.classWrap+'-overflow-y';
1353    app.classOverflowX = app.classWrap+'-overflow-x';
1354
1355    app.popupWidthDefault = 450; // px
1356    // в качестве app.popupHeightDefault используется высота контента модала
1357    app.popupHeightDefaultForTopBottom = 250; // px
1358    app.popupIndentX = 10;
1359    app.popupIndentY = 10;
1360
1361    app.windowWidth = 0;
1362    app.windowHeight = 0;
1363
1364    app.fadeInTime = 500;
1365    app.fadeOutTime = 300;
1366    app.ajaxTimeOut = 25000;
1367
1368    app.errLogMsg = 'iexModal: Ошибка показа окна!';
1369    app.errAjaxMsg = 'iexModal: Ошибка загрузки контента!';
1370    app.errScriptLoadingMsg = 'iexModal: Отменена повторная инициализация скрипта! Уже загружена другая копия/версия iexModal, - ее настройки и состояние затронуты не были!';
1371    app.repAjaxMsg = 'iexModal: Отчет об ajax-запросе';
1372
1373    /**
1374     * Поддерживаемые варианты получения html-контента для показа в модальном окне
1375     * @type {string[]}
1376     */
1377    app.loadTypes = [ 
1378        'url',
1379        'html',
1380        'id',
1381        'selector', 
1382        'jquery'
1383    ];
1384
1385    /**
1386     * Атрибуты, которые разрешено считывать с кнопки/ссылки показа окна и враппера контента
1387     * и соответсвующие им параметры для app.show()
1388     */
1389    app.attrsAndParams = {
1390        'href':                          'url',
1391        'data-iexmodal-html':            'html',
1392        'data-iexmodal-selector':        'selector',
1393        'data-iexmodal-id':              'id',
1394        'data-iexmodal-mode':            'mode',
1395        'data-iexmodal-classes':         'classes',
1396        'data-iexmodal-width':           'width',
1397        'data-iexmodal-height':          'height',
1398        'data-iexmodal-overlay':         'overlay',
1399        'data-iexmodal-content-wrap':    'contentWrap',
1400        'data-iexmodal-content-scroll':  'contentScroll',
1401        'data-iexmodal-document-scroll': 'documentScroll',
1402        'data-iexmodal-outer-scroll':    'outerScroll',
1403        'data-iexmodal-timeout':         'timeout',
1404        'data-iexmodal-ajax-report':     'ajaxReport',
1405        'data-iexmodal-calc-zindex':     'calcZindex',
1406    };
1407
1408    /**
1409     * Атрибуты из app.attrsAndParams, которые разрешено использовать модулю iexForm на кнопках/ссылках показа всплывающих форм
1410     */
1411    app.iexFormAttrs = [
1412        'data-iexmodal-mode',
1413        'data-iexmodal-classes',
1414        'data-iexmodal-width',
1415        'data-iexmodal-height',
1416        'data-iexmodal-overlay',
1417        'data-iexmodal-content-scroll',
1418        'data-iexmodal-document-scroll',
1419        'data-iexmodal-outer-scroll',
1420        'data-iexmodal-timeout',
1421        'data-iexmodal-ajax-report',
1422        'data-iexmodal-calc-zindex',
1423    ];
1424
1425    /**
1426     * Названия разрешенных пользовательских коллбэÐ
1426ºÐ¾Ð²
1427     * @type {Array}
1428     */
1429    app.userCallbackNames = [
1430        'onBeforeShow',
1431        'onAfterContentLoad',
1432        'onAfterShow',
1433        'onBeforeClose',
1434        'onAfterClose'
1435    ];
1436
1437    /**
1438     * Массив разрешенных параметров для app.show().
1439     * Перечень параметров берется из:
1440     * 1) из самого массива
1441     * 2) app.attrsAndParams (эти параметры можно передавать как через API так и через data-атрибуты)
1442     * 3) app.userCallbackNames (эти параметры можно передавать только через API)
1443     * Заполняется в app.__init().
1444     */
1445    app.params = [
1446        'jquery'
1447    ];
1448
1449    /**
1450     * Colorbox
1451     */
1452    app.$colorboxOverlay = null;
1453    app.$colorboxWindow = null;
1454    app.colorboxFound = false;
1455
1456    /**
1457     * Возможные режимы показа модального окна.
1458     * @property {object}
1459     */
1460    app.modes = {
1461        'default':'default',
1462        'fullscreen':'fullscreen',
1463        'top':'top',
1464        'right':'right',
1465        'bottom':'bottom',
1466        'left':'left',
1467        'alert':'alert'
1468    };
1469
1470    /**
1471     * Объект-коллекция модальных окон
1472     * @type {object}
1473     */
1474    app.modals = {};
1475
1476    /**
1477     * Id самого верхнего окна (по z-index)
1478     * @type {boolean}
1479     */
1480    app.modalsTopId = false;
1481
1482    /**
1483     * В мобильном IE console отсутствует и вызов его методов вызовет ошибки
1484     * Попутно используем app.debugPanel.log()
1485     */
1486    app.log = function(){
1487        if ( window.console && window.console.log ) {
1488            console.log.apply(console, arguments);
1489        }
1490        app.debugPanel.log.apply(app.debugPanel, arguments);
1491    };
1492
1493    app.getIEVersion = function () {
1494        var sAgent = window.navigator.userAgent;
1495        var Idx = sAgent.indexOf("MSIE");
1496
1497        // IE, return version number.
1498        if (Idx > 0) {
1499            return parseInt(sAgent.substring(Idx + 5, sAgent.indexOf(".", Idx)));
1500
1501        // IE 11 then look for Updated user agent string.
1502        } else if (!!navigator.userAgent.match(/Trident\/7\./)) {
1503            return 11;
1504
1505        // not IE
1506        } else {
1507            return 0;
1508        }
1509    };
1510
1511    /**
1512     * Панель (окно) отладки для мобильных платформ (вместо console.log).
1513     *
1514     * Можно использовать после вызова:
1515     *      app.debugPanel.on()
1516     * Пример использования:
1517     *      app.debugPanel.log($x, $y, $z)
1518     * Стили можно править через CSS или:
1519     *      app.debugPanel.$wrap.css('стили')
1520     */
1521    app.DebugPanel = function(){
1522        var panel = this;
1523
1524        panel.active = false;
1525        panel.time = false;
1526        panel.$wrap = $();
1527        panel.msg = '-----------------------\niexModal: Панель отладки\n-----------------------';
1528        panel.html = '<div class="iexmodal-debug-panel">'+panel.msg+'</div>';
1529
1530        panel._add = function () {
1531            panel.$wrap = $(panel.html).appendTo(app.$body);
1532        };
1533        panel._remove = function () {
1534            panel.$wrap.remove();
1535            panel.$wrap = $();
1536        };
1537
1538        panel._ts = function(){
1539            var time = new Date();
1540
1541            function format2(val){
1542                return ("0"+val).slice(-2);
1543            }
1544            function format3(val){
1545                return (val+"00").slice(0,3);
1546            }
1547
1548            return (
1549                format2(time.getHours()) + ':' +
1550                format2(time.getMinutes()) + ':' +
1551                format2(time.getSeconds()) + ':' +
1552                format3(time.getMilliseconds())
1553            )
1554        };
1555
1556        panel.clear = function(){
1557            panel.$wrap.html(panel.msg)
1558        };
1559
1560        panel.on = function(params){
1561            params = params || {};
1562            panel.time = (typeof params.time === 'boolean') ? params.time : false;
1563
1564            if ( panel.$wrap.length ) {
1565                panel._remove();
1566            }
1567            panel._add();
1568            panel.active = true;
1569        };
1570        panel.off = function(){
1571            panel._remove();
1572            panel.active = false;
1573        };
1574
1575        panel.log = function(){
1576            if ( !panel.active ) return;
1577
1578            var time = panel.time ? panel._ts() + ' ' : '';
1579
1580            var args = [].slice.call(arguments);
1581            var text = '';
1582            $(args).each(function (i,val) {
1583                text += typeof val === 'object' ? JSON.stringify(val) : val;
1584                text += ' ';
1585            });
1586
1587            panel.$wrap.text(panel.$wrap.text() + '\n' + time + text);
1588            panel.$wrap[0].scrollTop = panel.$wrap[0].scrollHeight;
1589        };
1590    };
1591    app.debugPanel = new app.DebugPanel();
1592
1593    /**
1594     * Возвращает объект самого верхнего по z-индексу модала
1595     *
1596     * @return {undefined|object}
1597     */
1598    app.getTopModal = ()=>{
1599        if (app.modalsTopId) {
1600            return app.modals[app.modalsTopId];
1601        }
1602        return undefined;
1603    }
1604
1605    /**
1606     * Возвращает объект модала по wrapId
1607     *
1608     * @param wrapId {string}
1609     * @return {undefined|object}
1610     */
1611    app.getModalByWrapId = (wrapId)=>{
1612        if (typeof wrapId !== 'string') {
1613            return undefined;
1614        }
1615        return app.modals[wrapId];
1616    };
1617
1618    /**
1619     * Возвращает объект модала id из атрибута data-iexmodal-id
1620     *
1621     * @param id {string}
1622     * @return {undefined|object}
1623     */
1624    app.getModalById = (id)=>{
1625        return app.getModalByWrapId('id-'+id);
1626    }
1627
1628    /**
1629     * Возвращает модал либо по wrapId, либо по id, либо самый верхний по z-индексу
1630     *
1631     * @param id
1632     * @returns {Object|undefined}
1633     */
1634    app.getModal = (id)=>{
1635        return app.getModalById(id) || app.getModalByWrapId(id) || app.getTopModal();
1636    }
1637
1638    /**
1639     * Имеется ли окно с заданным id в списке открытых
1640     *
1641     * @param id
1642     * @return {*}
1643     */
1644    app.isOpened = function (id){
1645        return id && app.modals[id];
1646    };
1647
1648    /**
1649     * Возвращает UID из 5 цифр
1650     * @return {number}
1651     */
1652    app.getUid = function(){
1653        return Math.floor(10000 + Math.random()*89999);
1654    };
1655
1656    app.inArray = function (val, arr) {
1657        if ( typeof arr !== 'object') return false;
1658        return arr.indexOf(val) > -1;
1659    };
1660
1661    /**
1662     * Достает первое по порядку значение в объекте
1663     * @param obj
1664     * @returns {*}
1665     */
1666    app.firstInObj = function (obj) {
1667        if (typeof obj !== 'object') return false;
1668        return obj[Object.keys(obj)[0]];
1669    };
1670
1671    /**
1672     * Достает ключ последнего по порядку элемента в объекте
1673     * @param obj
1674     * @returns {*}
1675     */
1676    app.lastKeyInObj = function (obj) {
1677        if (typeof obj !== 'object') {
1678            return false;
1679        }
1680        var keys = Object.keys(obj);
1681        return keys.length ? keys[keys.length - 1] : false;
1682    };
1683
1684    /**
1685     * Возвращает последний элемент в массиве или false
1686     * @param arr {object}
1687     * @returns {object|false}
1688     */
1689    app.lastInArr = function (arr) {
1690        if (typeof arr !== 'object') return false;
1691        return arr.length ? arr[ arr.length-1 ] : false;
1692    };
1693
1694    /**
1695     * Получает допустимый режим показа окна из кнопки/ссылки
1696     * @returns {string}
1697     */
1698    app.getMode = function (mode) {
1699        if (!mode) return app.firstInObj(app.modes);
1700        return app.modes[mode] ? mode : app.firstInObj(app.modes);
1701    };
1702
1703    /**
1704     * Получает CSS-класс-модификатор для режима показа
1705     * @returns {string}
1706     */
1707    app.getModeClass = function (mode) {
1708        return mode==='default' ? '' : app.classWrap+'-'+mode;
1709    };
1710
1711    /**
1712     * Вычисление ширины скробара (у каждого браузера она своя)
1713     * Позаимствовано из bootstrap.modal.js
1714     */
1715    app.getScrollbarWidth = function () {
1716        var divStyles =
1717            'position: absolute; '+
1718            'top: -9999px; '+
1719            'width: 50px; '+
1720            'height: 50px; '+
1721            'overflow: scroll;';
1722        var scrollDiv = document.createElement('div');
1723        scrollDiv.setAttribute('style', divStyles);
1724        app.$body.append(scrollDiv);
1725        var scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth;
1726        app.$body[0].removeChild(scrollDiv);
1727        return scrollbarWidth
1728    };
1729
1730    /**
1731     * Интеграция с Colorbox.
1732     * Нужна когда из iexModal-окна открываются Сolorbox-окна.
1733     * Устанавливаем Сolorbox-окну z-index больший чем у iexModal-окна.
1734     */
1735    app.onColorboxOpen = function(){
1736        if (app.modalsTopId) {
1737            var zIndex = app.getWrapZindex();
1738            app.$colorboxOverlay.css('z-index', zIndex+1);
1739            app.$colorboxWindow.css('z-index', zIndex+2);
1740        }
1741    };
1742    app.onColorboxClosed = function(){
1743        if (app.modalsTopId) {
1744            app.$colorboxOverlay.css('z-index', '');
1745            app.$colorboxWindow.css('z-index', '');
1746        }
1747    };
1748    app.colorboxInit = function(){
1749        app.$colorboxOverlay = $('#cboxOverlay');
1750        app.$colorboxWindow = $('#colorbox');
1751        app.colorboxFound = app.$colorboxOverlay.length && app.$colorboxWindow.length;
1752        if (app.colorboxFound) {
1753            app.$document
1754                .on('cbox_open', app.onColorboxOpen)
1755                .on('cbox_closed', app.onColorboxClosed);
1756        }
1757    };
1758
1759    /**
1760     * Текущий размер окна браузера в виде объекта {width: 450px, height: 600px}.
1761     * @return {object}
1762     */
1763    app.getWindowSize = function () {
1764        if (window.visualViewport) {
1765            app.windowWidth = window.visualViewport.width;
1766            app.windowHeight = window.visualViewport.height;
1767        } else {
1768            app.windowWidth = app.$window.width();
1769            app.windowHeight = app.$window.height();
1770            // Алтернатива для вышерасположенный кода, если он срабатывает некорректно (замечено на некторых сайтах)
1771            // app.windowWidth = document.body.clientWidth;
1772            // app.windowHeight = document.body.clientHeight;
1773        }
1774        return {width: app.windowWidth, height: app.windowHeight}
1775    };
1776
1777    /**
1778     * Получить максимальный z-index на странице
1779     * @return {int}
1780     */
1781    app.getMaxZIndex = function (){
1782        var maxZ = -1;
1783        $('body *').not('.iexmodal-debug-panel').each(function(i,el){
1784            var pos = $(el).css('position');
1785            if(pos === 'absolute' || pos === 'fixed'){
1786                var z = parseInt($(el).css('z-index')) || 1;
1787                maxZ = Math.max(z, maxZ);
1788            }
1789        });
1790        return maxZ;
1791    };
1792
1793    app.getWrapZindex = function () {
1794        var zMax = app.getMaxZIndex();
1795        /*
1796        var zCur = parseInt( app.$wrap.css('z-index') );
1797        return (zMax===zCur ? zMax : zMax+1);
1798        */
1799        return zMax+1;
1800    };
1801
1802    /**
1803     * Корректировка размера и положения окна по горизонтали
1804     * Не вызывается для режимов fullscreen, top и bottom
1805     *
1806     * @param modal {object} Объект модального окна из app.modals
1807     * @param animate {bool} Выполнять анимацию при изменении CSS-свойств
1808     */
1809    app.correctPositionX = function (modal, animate = false) {
1810        let cssParams = {}, animateParams = {};
1811        let maxPopupWidth = modal.width || app.popupWidthDefault;
1812        let maxPopupWidthInWindow = app.windowWidth - app.popupIndentX * 2;
1813        let maxMarginLeftInWindow = -1 * parseInt(maxPopupWidthInWindow/2);
1814        let breakpointWidth = parseInt(maxPopupWidth) + app.popupIndentX * modal.identXCoeff;
1815        let overflowX = app.windowWidth <= breakpointWidth;
1816        
1817        let enableOverflowMode = ()=>{
1818            modal.$wrap.addClass(app.classOverflowX);
1819            modal.$popup.css('width', '');
1820            if (!modal.outerScroll) {
1821                modal.$popup.css('margin-left', '');
1822            }
1823        }
1824
1825        if (!overflowX && modal.overflowX) {
1826            modal.$wrap.removeClass(app.classOverflowX);
1827        }
1828
1829        if (overflowX && !modal.overflowX) {
1830            modal.calculatedX = false;
1831            if (animate) {
1832                animateParams = {
1833                    width: maxPopupWidthInWindow,
1834                    complete: function(anim) {
1835                        enableOverflowMode();
1836                    }
1837                };
1838                if (modal.identXCoeff === 2) { // не режим left/right
1839                    animateParams.marginLeft = maxMarginLeftInWindow
1840                }
1841                app.animation.popupChange(modal, animateParams)
1842            } else {
1843                enableOverflowMode();
1844            }            
1845        }
1846
1847        if (
1848            !overflowX && (modal.overflowX || !modal.calculatedX || animate)
1849        ) {
1850            modal.calculatedX = true;
1851
1852            
1853            cssParams.width = maxPopupWidth;
1854            if (modal.overflowX && animate) {
1855                animateParams.width = [maxPopupWidthInWindow, maxPopupWidth];
1856            } else {
1857                animateParams.width = maxPopupWidth;
1858            }
1859
1860            if (
1861                modal.mode === 'default' &&
1862                !modal.outerScroll
1863            ) {
1864                let mLeft = -1 * parseInt(maxPopupWidth)/2;
1865                cssParams.marginLeft = mLeft+'px'
1866                if (modal.overflowX && animate) {
1867                    animateParams.marginLeft = [maxMarginLeftInWindow, mLeft];
1868                } else {
1869                    animateParams.marginLeft = mLeft;
1870                }
1871            }
1872
1873            if (animate) {
1874                app.animation.popupChange(modal, animateParams);
1875            } else {
1876                modal.$popup.css(cssParams);
1877            }
1878        }
1879
1880        modal.overflowX = overflowX;
1881    };
1882
1883    /**
1884     * Возвращает высоту контента попапа в сумме с вертикальными паддингами modal.$inner
1885     *
1886     * @param modal {object} Объект модального окна из app.modals
1887     * @return {int} Пиксели
1888     */
1889    app.getContentHeight = function(modal) {
1890        return Math.ceil(
1891            modal.$innerWrap.outerHeight() +
1892            parseInt(modal.$inner.css('padding-top')) +
1893            parseInt(modal.$inner.css('padding-bottom'))
1894        );
1895    };
1896
1897    /**
1898     *
1899     * @param modal {object} Объект модального окна из app.modals
1900     * @param animate {bool} Выполнять анимацию при изменении CSS-свойств
1901     */
1902    app.setPopupSizeY = (modal, animate = false)=>{
1903        let cssParams = {}, animateParams = {};
1904        
1905        let enableOverflowMode = ()=>{
1906            modal.$wrap.addClass(app.classOverflowY);
1907            cssParams.marginTop = '';
1908            cssParams.height = '';
1909            modal.$popup.css(cssParams);
1910        }
1911
1912        if (modal.overflowYdetected && !modal.overflowY) {
1913            modal.calculatedY = false;
1914            modal.overflowY = true;
1915            if (animate) {
1916                animateParams = {
1917                    height: modal.popupMaxHeightInWindow,
1918                    complete: function(anim) {
1919                        enableOverflowMode();
1920                    }
1921                }
1922                if (modal.identYCoeff === 2) { // не режим top/bottom
1923                    animateParams.marginTop = modal.popupMaxMarginTopInWindow;
1924                }
1925                app.animation.popupChange(modal, animateParams)
1926            } else {
1927                enableOverflowMode();
1928            }            
1929        }
1930
1931        if (
1932            !modal.overflowYdetected && (modal.overflowY || !modal.calculatedY || animate)
1933        ) {
1934            modal.calculatedY = true;
1935
1936            if (modal.overflowY) {
1937                modal.$wrap.removeClass(app.classOverflowY);
1938            }
1939
1940            if (modal.mode === 'default') {
1941                let marginTop = -1 * parseInt(modal.popupMaxHeight/2);
1942                cssParams.marginTop = marginTop+'px';
1943                if (modal.overflowY && animate) {
1944                    animateParams.marginTop = [modal.popupMaxMarginTopInWindow, marginTop];
1945                } else {
1946                    animateParams.marginTop = marginTop;
1947                }
1948            }
1949
1950            cssParams.height = modal.popupMaxHeight+'px';
1951            if (modal.overflowY && animate) {
1952                animateParams.height = [modal.popupMaxHeightInWindow, modal.popupMaxHeight];
1953            } else {
1954                animateParams.height = modal.popupMaxHeight;
1955            }
1956
1957            if (animate) {
1958                app.animation.popupChange(modal, animateParams)
1959            } else {
1960                modal.$popup.css(cssParams);
1961            }
1962
1963            modal.overflowY = false;
1964        }
1965    }
1966
1967    /**
1968     * Корректировка размера и положения окна по вертикали.
1969     * Предусмотрена работа только в режимах default, alert, top, bottom.
1970     *
1971     * @param modal {object} Объект модального окна из app.modals
1972     * @param animate {bool} Выполнять анимацию при изменении CSS-свойств
1973     */
1974    app.correctPositionY = function (modal, animate = false) {
1975        if (modal.positionFirstMesurement) {
1976            modal.isTopBottom = app.inArray(modal.mode, ['top','bottom']);
1977            modal.popupStoredTop = false;
1978            modal.popupStoredBottom = false;
1979            modal.popupContentHeight = app.getContentHeight(modal);
1980            modal.popupMaxHeight = app.getPopupMaxHeight(modal);
1981            modal.breakpointHeight = modal.popupMaxHeight + app.popupIndentY * modal.identYCoeff;
1982            modal.popupMaxHeightInWindow = app.windowHeight - app.popupIndentY * modal.identYCoeff;
1983            modal.popupMaxMarginTopInWindow = -1 * parseInt(modal.popupMaxHeightInWindow/2);
1984            modal.positionFirstMesurement = false;
1985        }
1986
1987        modal.overflowYdetected = app.windowHeight <= modal.breakpointHeight;
1988        app.setPopupSizeY(modal, animate);
1989
1990        if (modal.mode === 'alert') {
1991
1992            if (!modal.overflowY && !modal.overflowYdetected) {
1993                let popupClientRect = modal.$popup[0].getBoundingClientRect();
1994                if ((popupClientRect.bottom + app.popupIndentY) > app.windowHeight) {
1995                    modal.overflowYdetected = true;
1996                    modal.popupStoredBottom = popupClientRect.bottom + app.popupIndentY;
1997                }
1998                if (!modal.overflowYdetected && popupClientRect.top < app.popupIndentY) {
1999                    modal.overflowYdetected = true;
2000                    modal.popupStoredTop = popupClientRect.top;
2001                }
2002                app.setPopupSizeY(modal, animate);
2003            }
2004
2005            if (modal.overflowY) {
2006                if (
2007                    modal.overflowYdetected &&
2008                    modal.popupStoredBottom !== false &&
2009                    modal.popupStoredBottom < app.windowHeight
2010                ) {
2011                    modal.overflowYdetected = false;
2012                    modal.popupStoredBottom = false;
2013                }
2014
2015                if (
2016                    modal.overflowYdetected &&
2017                    modal.popupStoredTop !== false &&
2018                    modal.popupStoredTop > app.popupIndentY
2019                ) {
2020                    modal.overflowYdetected = false;
2021                    modal.popupStoredTop = false;
2022                }
2023
2024                app.setPopupSizeY(modal, animate);
2025            }
2026
2027        }
2028    };
2029
2030    /**
2031     * Корректировка размерров и положения открытых окон.
2032     * Автоматически выполняется при каждом изменении размера окна браузера (onresize) и повороте мобильного устройства (onorientationchange).
2033     * Нужно вызывать после изменения количества контента в окне/окнах, чтобы расположение на экране оставалось оптимальным.
2034     *
2035     * @return {boolean}
2036     */
2037    app.correctPosition = function(){
2038        if ( !app.modalsTopId ) return false;
2039
2040        $.each(app.modals, function (wrapId, modal) {
2041            if (modal.mode === 'fullscreen') {
2042                return true;
2043            }
2044
2045            // Установка ширины дожна выполняться ДО установки высоты, чтобы inline/inline-block
2046            // элементы правильно распределились по строкам и дали правильную высоту контента
2047            if (!app.inArray(modal.mode, ['top', 'bottom'])) {
2048                app.correctPositionX(modal);
2049            }
2050            if (!app.inArray(modal.mode, ['left', 'right'])) {
2051                app.correctPositionY(modal);
2052            }
2053            if (modal.ps) {
2054                modal.ps.update();
2055            }
2056        });
2057
2058        return false;
2059    };
2060
2061    /**
2062     * Возвращает максимально возможную высоту попапа
2063     *
2064     * @param modal {object} Объект модального окна из app.modals
2065     * @return {object} app
2066     */
2067    app.getPopupMaxHeight = function(modal){
2068        let height = parseInt(modal.height);
2069        if (
2070            !height &&
2071            app.inArray(modal.mode, ['top','bottom'])
2072        ) {
2073            height = app.popupHeightDefaultForTopBottom;
2074        }
2075        if (!height) {
2076            height = modal.popupContentHeight; // в качестве app.popupHeightDefault используется высота контента модала
2077        }
2078        return height;
2079    };
2080
2081    app.setPopupHeightOnceAfterLoad = false;
2082
2083    /**
2084     * Изменение высоты модала
2085     *
2086     * @param height {string} Ширина модала
2087     * @param id {string} id существующего модала из app.modals
2088     */
2089    app.setHeight = (height, id)=>{
2090        let modal = app.getModal(id);
2091        if (!modal || app.inArray(modal.mode, ['fullscreen', 'left', 'right'])) {
2092            return;
2093        }
2094
2095        if (!height) {
2096            height = 'content';
2097        }
2098        if (height === 'max') {
2099            height = app.windowHeight+'px';
2100        }
2101
2102        modal.height = height === 'content' ? null : height;
2103        modal.positionFirstMesurement = true;
2104        app.correctPositionY(modal, true);
2105    }
2106
2107    /**
2108     * Изменение ширины модала
2109     *
2110     * @param width {string} Ширина модала
2111     * @param id {string} id существующего модала из app.modals
2112     */
2113    app.setWidth = (width, id)=>{
2114        let modal = app.getModal(id);
2115        if (!modal || app.inArray(modal.mode, ['fullscreen', 'top', 'bottom'])) {
2116            return;
2117        }
2118
2119        if (!width) {
2120            width = app.popupWidthDefault+'px';
2121        }
2122
2123        modal.width = (width === 'max') ? (app.windowWidth+'px') : width;
2124        app.correctPositionX(modal, true);
2125    }
2126
2127    /**
2128     * Рендерит html-код для модального окна, добавляет его Ð
2128½Ð°Ñ‡Ð°Ð»Ð¾ документа и возвращает jQuery-ссылку
2129     *
2130     * @param id {string} Уникальный id модального окна из app.modals
2131     * @return {jQuery} jQuery-ссылка на вставленный html
2132     */
2133    app.insertWrap = function(id) {
2134        var html =
2135            '<div class="' + app.classWrap + '" data-iexmodal-id="' + id + '">\n'+
2136            '    <div class="' + app.classClose + ' iexmodal-close-outer">\n'+
2137            '        <svg class="iexmodal-icon"><use xlink:href="#close"></use></svg>\n'+
2138            '    </div>\n'+
2139            '    <div class="' + app.classPopup + '">\n'+
2140            '        <div class="' + app.classInner + '"><div class="'+app.classInnerWrap + '"></div></div>\n'+
2141            '        <div class="' + app.classClose + ' iexmodal-close-inner">\n'+
2142            '            <svg class="iexmodal-icon"><use xlink:href="#close"></use></svg>\n'+
2143            '        </div>\n'+
2144            '    </div>\n'+
2145            '    <div class="iexmodal-spinner"></div>\n'+
2146            '</div>';
2147        return $(html).appendTo('body');
2148    };
2149
2150    /**
2151     * Вставляет SVG-спрайт в начало документа и возвращает jQuery-ссылку
2152     *
2153     * @return {jQuery}
2154     */
2155    app.insertSprite = function() {
2156        var html =
2157            '<svg class="' + app.classSprite + '" aria-hidden="true" style="position: absolute; width: 0; height: 0; overflow: hidden;" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">\n'+
2158            '    <defs>\n'+
2159            '        <symbol id="close" viewBox="0 0 18 18">\n'+
2160            '            <title>close</title>\n'+
2161            '            <line x1="2" y1="2" x2="16" y2="16"/>\n'+
2162            '            <line x1="2" y1="16" x2="16" y2="2"/>\n'+
2163            '        </symbol>\n'+
2164            '    </defs>\n'+
2165            '</svg>';
2166        return $(html).appendTo('body');
2167    };
2168
2169    /**
2170     * jQuery-ссылка на вставленный в документ SVG-спрайт.
2171     *
2172     * @type {*}
2173     */
2174    app.$sprite = false;
2175
2176    /**
2177     * Используется при app.loadType равным 'selector' или 'jquery'
2178     *
2179     * @return {jQuery}
2180     */
2181    app.insertPlaceholder = function($sibling) {
2182        var html = '<div class="iexmodal-content-placeholder"></div>';
2183        return $(html).insertAfter($sibling);
2184    };
2185
2186    /**
2187     * Получение data-атрибутов кнопки/ссылки
2188     * в виде объекта c параметрами для app.show()
2189     *
2190     * @param $btn - jQuery-ссылка на кнопку/ссылку
2191     * @return {*}
2192     */
2193    app.parseBtnAttrs = function ($btn) {
2194        if (!($btn instanceof jQuery && $btn.length)) return false;
2195        var obParsed = {};
2196        $.each(app.attrsAndParams, function (btnAttr, showParam) {
2197            obParsed[showParam] = $btn.attr(btnAttr) || ''; // $.data() может отдавать закэшированные (старые) значения при уже изменившемся DOM
2198        });
2199        return obParsed;
2200    };
2201
2202    /**
2203     * Подсчет количества переданных способов загрузки html-контента.
2204     * Используется в app.validateParams() для проверки, что передан ровно один способ.
2205     *
2206     * @param params Параметры для app.show()
2207     * @return {number}
2208     */
2209    app.loadTypesCnt = function (params) {
2210        var cnt = 0;
2211        $.each(app.loadTypes, function (key,val) {
2212            cnt += params[val] ? 1 : 0;
2213        });
2214        return cnt;
2215    };
2216
2217    /**
2218     * Получение способа загрузки html-контента из параметров app.show()
2219     *
2220     * @param params Параметры для app.show()
2221     * @return {boolean}
2222     */
2223    app.getLoadType = function (params) {
2224        var loadType = false;
2225        $.each(app.loadTypes, function (key,val) {
2226            if ( !!params[val] ) {
2227                loadType = val;
2228                return false
2229            }
2230        });
2231        return loadType;
2232    };
2233
2234    app.getContentWrap = function(id){
2235        return app.$body.find('.'+app.classContent+'[data-iexmodal-id="' + id + '"]').first();
2236    };
2237
2238    /**
2239     * Отчет об аякс-запросе, выполненного методом $.ajax()
2240     *
2241     * @param url {string} Урл загружаемого контента
2242     * @param jqXHR {jqXHR} jqXHR-объект, который вернул метод $.ajax()
2243     * @return {string} Html-код с отчетом
2244     */
2245    app.ajaxReport = function(url, jqXHR){
2246        if ( !url || !jqXHR ) return '';
2247
2248        var responseText = jqXHR.responseJSON ? JSON.stringify(jqXHR.responseJSON) : jqXHR.responseText;
2249        responseText = $('<div></div>').text(responseText).html();
2250
2251        return (
2252            '<div class="' + app.classDebugWrap + '">' +
2253            'URL: <a href="' + url + '" target="_blank">' + url + '</a><br>' +
2254            'Timeout: ' + app.ajaxTimeOut/1000 + ' sec<br>' +
2255            '<br>' +
2256            'jqXHR.readyState: ' + jqXHR.readyState + '<br>' +
2257            'jqXHR.status: ' + jqXHR.status + '<br>' +
2258            'jqXHR.statusText: ' + jqXHR.statusText +
2259            '<br><br>' +
2260            'jqXHR.responseText / jqXHR.responseJSON:' +
2261            '<div class="' + app.classDebugCode + '">' + responseText + '</div>' +
2262            '</div>'
2263        );
2264    };
2265
2266    /**
2267     * Валидация параметров для app.show().
2268     * @param rawParams {object} Объект с 'сырыми' параметрами для проверки-исправления
2269     * @return {object} Объект с проверенными-исправленными параметрами
2270     */
2271    app.validateParams = function(rawParams){
2272        if (!rawParams) {
2273            app.log(app.errLogMsg+' Не задан объект с параметрами. Смотрите документацию по iexModal.show().');
2274            return false;
2275        }
2276        var validParams = {};
2277
2278        $.each(app.params, function(key, param) {
2279            if ( app.inArray(param, app.userCallbackNames) ) {
2280                if (typeof rawParams[param] === 'function') {
2281                    validParams[param] = rawParams[param];
2282                }
2283            } else if ( app.inArray(param, ['jquery','selector']) || (typeof rawParams[param] === 'boolean' ) ) {
2284                validParams[param] = rawParams[param];
2285            } else {
2286                validParams[param] = $.trim(rawParams[param] || '');
2287            }
2288
2289            if (
2290                param==='url' &&
2291                validParams[param] &&
2292                (
2293                    validParams[param].indexOf('#')===0 ||
2294                    validParams[param].indexOf('javascript:')>-1
2295                )
2296            ) {
2297                validParams[param] = '';
2298            }
2299
2300            if ( param==='mode' ) {
2301                validParams[param] = app.getMode(validParams[param]);
2302            }
2303
2304            if (
2305                (param==='overlay' || param==='ajaxReport') &&
2306                (typeof validParams[param] !== 'boolean')
2307            ) {
2308                validParams[param] = validParams[param]==='true';
2309            }
2310
2311            if (
2312                (param==='contentWrap' || param==='contentScroll' || param==='calcZindex') &&
2313                (typeof validParams[param] !== 'boolean')
2314            ) {
2315                validParams[param] = validParams[param]!=='false';
2316            }
2317
2318            if (
2319                (param==='documentScroll' || param==='outerScroll') &&
2320                (typeof validParams[param] !== 'boolean')
2321            ) {
2322                validParams[param] = validParams[param]==='true';
2323            }
2324
2325            if ( param==='timeout' ) {
2326                validParams[param] = parseInt(validParams[param]) || 0;
2327            }
2328        });
2329
2330        if (validParams['mode'] && validParams['mode'] !== 'default') {
2331            validParams['classes'] = validParams['classes'] ? ' '+validParams['classes'] : '';
2332            validParams['classes'] = app.getModeClass(validParams['mode']) + validParams['classes'];
2333        }
2334
2335        if (validParams['outerScroll']) {
2336            validParams['classes'] += ' ' + app.classOuterScroll;
2337        }
2338
2339        // if (validParams['mode'] === 'fullscreen') {
2340        //     validParams['width'] = '';
2341        //     validParams['height'] = '';
2342        // }
2343
2344        var
2345            errMsg = '',
2346            loadType = app.getLoadType(validParams),
2347            loadTypesCnt = app.loadTypesCnt(validParams);
2348
2349        if (
2350            !loadTypesCnt
2351        ) {
2352            errMsg = 'Не задан способ загрузки html-контента: ' + app.loadTypes.join(', ');
2353
2354        } else if (
2355            app.loadTypesCnt(validParams) > 1
2356        ) {
2357            errMsg = 'Из списка параметров ' + app.loadTypes.join(', ') + ' одновременно можно передавать только ОДИН!';
2358
2359        } else if (
2360            loadType==='selector' &&
2361            !$(validParams['selector']).length
2362        ) {
2363            errMsg = 'Элемент с селектором "' + validParams['selector'] + '" не найден на странице!';
2364
2365        } else if (
2366            loadType==='jquery' &&
2367            !(validParams['jquery'] instanceof jQuery)
2368        ) {
2369            errMsg = 'Элемент, переданный в параметр jquery, не является экземпляром jQuery!';
2370
2371        } else if (
2372            loadType==='jquery' &&
2373            !validParams['jquery'].length
2374        ) {
2375            errMsg = 'Элемент, переданный в параметр jquery, не найден на странице!';
2376
2377        } else if (
2378            loadType==='id' &&
2379            !app.getContentWrap(validParams['id']).length
2380        ) {
2381            errMsg = 'Не найден враппер контента с data-iexmodal-id="' + validParams['id'] + '".';
2382
2383        } else if (
2384            validParams['outerScroll'] &&
2385            !app.inArray(validParams['mode'], ['default','fullscreen'])
2386        ) {
2387            errMsg = 'Опция с прокруткой всего модала и внешним скроллбаром (data-iexmodal-outer-scroll="true") работает только в режимах default и fullscreen!';
2388        }
2389
2390        if ( errMsg ) {
2391            app.log(app.errLogMsg +' ' + errMsg + ' Переданные параметры:', validParams);
2392            return false
2393        }
2394
2395        return validParams;
2396    };
2397
2398    /**
2399     * Добавляет модальное окно в HTML-кода и коллекцию app.modals
2400     *
2401     * @param params - параметры для app.show()
2402     * @return {object} - объект созданного модального окна
2403     */
2404    app.create = function (params) {
2405        var loadType = app.getLoadType(params);
2406        var wrapId = loadType + '-' + ( loadType==='id' ? params.id : app.getUid() );
2407        var $wrap = app.insertWrap(wrapId);
2408
2409        // перечень всех возможных полей объекта modal
2410        var modal = app.modals[wrapId] = {
2411            wrapId: wrapId,
2412            loadType: loadType,
2413            timeoutId: false,
2414            contentArray: [],
2415            $wrap: $wrap,
2416            $popup: $wrap.find('.'+app.classPopup),
2417            $inner: $wrap.find('.'+app.classInner),
2418            $innerWrap: $wrap.find('.'+app.classInnerWrap),
2419            $currWrapper: null,
2420            $currContent: null,
2421            $contentPlaceholder: null,
2422            mouseLeftButtonPushed: false,
2423            overflowY: false,
2424            overflowX: false,
2425            calculatedY: false,
2426            calculatedX: false,
2427            identXCoeff: 2,
2428            identYCoeff: 2,
2429            positionFirstMesurement: true,
2430            ps: null,
2431            psDragging: false,
2432            isVisible: false, // устанавливается в true после завершения анамации показа
2433            
2434            // приходят из параметров метода show() и атрибутов data-iexmodal-*
2435            url: null,
2436            html: null,
2437            selector: null,
2438            id: null,
2439            mode: null,
2440            classes: null,
2441            width: null,
2442            height: null,
2443            overlay: null,
2444            contentScroll: null,
2445            documentScroll: false,
2446            outerScroll: false,
2447            timeout: null,
2448            ajaxReport: null,
2449            calcZindex: null,
2450            
2451            // коллбэки
2452            onBeforeShow: ()=>{},
2453            onAfterContentLoad: ()=>{},
2454            onAfterShow: ()=>{},
2455            onBeforeClose: ()=>{},
2456            onAfterClose: ()=>{}
2457        };
2458        modal = $.extend(modal, params);
2459
2460        modal.identXCoeff = app.inArray(modal.mode, ['left','right']) ? 1 : 2;
2461        modal.identYCoeff = app.inArray(modal.mode, ['top','bottom']) ? 1 : 2;
2462
2463        // Заботимся чтобы во время перетаскивании скроллбара мышью случайно не кликался .iexmodal и окно не закрывалось
2464        function resetWrapSetts() {
2465            modal.psDragging = false;
2466            modal.$wrap.css('cursor','');
2467        }
2468
2469        if ( !modal.outerScroll && modal.contentScroll ) {
2470            modal.ps = new app.PerfectScrollbar( modal.$inner[0], {
2471                    wheelSpeed: 1, // сделать зависимой длинны (высоты контента) = parseInt(modal.$inner.outerHeight() / modal.$popup.outerHeight() * 2)
2472                    wheelPropagation: false,
2473                    minScrollbarLength: 60
2474                }
2475            );
2476            modal.$wrap.find('.ps__thumb-y')
2477                .on('mousedown', function (e) {
2478                    // e.which = 1 (левая), 2 (средня), 3 (правая)
2479                    modal.psDragging = true;
2480                    modal.$wrap.css('cursor','default');
2481                })
2482                .on('mouseup', function (e) {
2483                    resetWrapSetts();
2484                });
2485            modal.$wrap.find('.ps').on('mouseup', function (e) {
2486                if ( modal.psDragging ) {
2487                    resetWrapSetts();
2488                }
2489            });
2490        }
2491
2492        modal.$wrap
2493            .on('mousedown', function (e) { // если нажали именно над оверлеем и именно левую кнопку
2494                modal.mouseLeftButtonPushed = ( e.target === this && e.which === 1 );
2495            })
2496            .on('click', function (e) {
2497                if ( e.target === this ) {
2498                    if ( modal.ps && modal.psDragging ) {
2499                        resetWrapSetts();
2500                    } else {
2501                        if ( modal.mouseLeftButtonPushed ) {
2502                            app.close();
2503                        }
2504                    }
2505                }
2506            });
2507
2508        app.modalsTopId = wrapId;
2509
2510        return modal;
2511    };
2512
2513    /**
2514     * Перенос контента модального окна для типов загрузки 'selector' и 'jquery'
2515     * - moveToPopup() в модальное окно
2516     * - moveBack() обратно во враппер контента
2517     */
2518    app.contentArray = {
2519
2520        moveToPopup: function (modal) {
2521
2522            function arrayContentPush($el) {
2523                modal.contentArray.push({
2524                    '$currContent': $el,
2525                    '$contentPlaceholder': app.insertPlaceholder($el),
2526                });
2527                $el.appendTo( modal.$innerWrap );
2528            }
2529
2530            if ( modal.loadType==='jquery' ) {
2531                modal.jquery.each(function (i, el) {
2532                   arrayContentPush($(el))
2533                });
2534            }
2535
2536            // Cелекторы с запятыми разбиваем на отдельные jQuery-объекты, чтобы сохранить порядок выборки блоков
2537            // с контентом именно таким, как указано в селекторе, в противном случае порядок будет таким как в DOM-дереве.
2538            if ( modal.loadType==='selector' ) {
2539                var arSelectors = modal.selector.split(',');
2540
2541                $.each(arSelectors, function (index,selector) {
2542                    selector = selector.trim();
2543                    if (selector) {
2544                        $(selector).each(function (i, el) {
2545                            arrayContentPush($(el))
2546                        });
2547                    }
2548                });
2549            }
2550        },
2551
2552        moveBack: function (modal) {
2553
2554            $.each( modal.contentArray, function (key, item) {
2555                item.$currContent.insertAfter(item.$contentPlaceholder);
2556                item.$contentPlaceholder.remove();
2557            });
2558
2559        }
2560
2561    };
2562
2563    /**
2564     * Удаляет модальное окно из HTML-кода и коллекции app.modals
2565     *
2566     * @param {object} modal - удаляемое модальное окно (объект из коллекции app.modals)
2567     * @return {boolean}
2568     */
2569    app.remove = function (modal) {
2570        if (
2571            typeof modal !== 'object' ||
2572            typeof app.modals[modal.wrapId] !== 'object'
2573        ) {
2574            return false;
2575        }
2576
2577        if (modal.loadType==='selector' || modal.loadType==='jquery') {
2578            app.contentArray.moveBack(modal);
2579        }
2580        if (modal.loadType==='id') {
2581            modal.$currContent.appendTo( modal.$currWrapper );
2582        }
2583        if ( modal.ps ) {
2584            modal.ps.destroy();
2585            modal.ps = null; // to make sure garbages are collected
2586        }
2587
2588        modal.$wrap.remove();
2589        delete app.modals[modal.wrapId];
2590        app.modalsTopId = app.lastKeyInObj(app.modals);
2591
2592        return true;
2593    };
2594
2595    /**
2596     * Функционал для анимации
2597     *
2598     * @constructor
2599     */
2600    app.Animation = function(){
2601        var anim = this;
2602
2603        anim.timeIn = 400;
2604        anim.timeOut = 300;
2605        
2606        anim.popupAnimations = {
2607            default: {
2608                in: {translateY: [-50, 0], opacity: 1},
2609                out: {translateY: [0, 70], opacity: 0},
2610            },
2611            fullscreen: {
2612                in: {opacity: 1},
2613                out: {opacity: 0},
2614            },
2615            alert: {
2616                in: {translateX: ['100%', 0], opacity: 1},
2617                out: {translateX: [0, '100%'], opacity: 0},
2618            },
2619            top: {
2620                in: {translateY: ['-100%', 0], opacity: 1},
2621                out: {translateY: [0, '-100%'], opacity: 0},
2622            },
2623            right: {
2624                in: {translateX: ['100%', 0], opacity: 1},
2625                out: {translateX: [0, '100%'], opacity: 0},
2626            },
2627            bottom: {
2628                in: {translateY: ['100%', 0], opacity: 1},
2629                out: {translateY: [0, '100%'], opacity: 0},
2630            },
2631            left: {
2632                in: {translateX: ['-100%', 0], opacity: 1},
2633                out: {translateX: [0, '-100%'], opacity: 0},
2634            },
2635        }
2636
2637        anim.wrapIn = function(modal) {
2638            if (modal.calcZindex) {
2639                modal.$wrap.css('z-index', app.getWrapZindex());
2640            }
2641            
2642            modal.$wrap
2643                .css('display', 'block')
2644                .addClass(modal.classes + ' ' + app.classLoading);
2645
2646            let params = {
2647                targets: modal.$wrap[0],
2648                opacity: 1,
2649                easing: 'linear',
2650                duration: anim.timeIn
2651            };
2652            app.AnimeJs(params);
2653        };
2654
2655        anim.popupIn = function(modal) {
2656            modal.$wrap.removeClass(app.classLoading);
2657
2658            let params = anim.popupAnimations[modal.mode]['in'];
2659            params.easing = modal.mode === 'alert' ? 'easeInOutBack' : 'easeInOutSine'; // по-умолчанию выбран 'easeOutElastic(1, .5)' (резиновый, пружинящий)
2660            params.duration = modal.mode === 'alert' ? anim.timeIn + 200 : anim.timeIn;
2661
2662            $.extend(params, {
2663                targets: modal.$popup[0],
2664                complete: function(anim) {
2665                    modal.isVisible = true;
2666                    app.callbacks.onAfterShow(modal);
2667                }
2668            });
2669            app.AnimeJs(params);
2670        };
2671
2672        anim.popupChange = function(modal, props) {
2673            app.AnimeJs($.extend(props, {
2674                targets: modal.$popup[0],
2675                duration: anim.timeOut,
2676                easing: 'easeInOutSine'
2677            }));
2678        }
2679
2680        anim.allOut = function(modal) {
2681            app.AnimeJs({
2682                targets: modal.$wrap[0],
2683                opacity: 0,
2684                easing: 'linear',
2685                duration: anim.timeOut,
2686            });
2687
2688            let params = anim.popupAnimations[modal.mode]['out'];
2689            params.easing = modal.mode === 'alert'? 'easeInOutBack' : 'easeInOutSine'; // по-умолчанию выбран 'easeOutElastic(1, .5)' (резиновый, пружинящий)
2690            params.duration = modal.mode === 'alert' ? anim.timeOut + 200 : anim.timeIn;
2691
2692            app.AnimeJs($.extend(params, {
2693                targets: modal.$popup[0],
2694                complete: function(anim) {
2695                    app.callbacks.onAfterClose(modal);
2696                }
2697            }));
2698        };
2699    };
2700    app.animation = new app.Animation();
2701
2702    /**
2703     * Показ модального окна
2704     * @param {object} params
2705     * - selector {string} - jQuery-селектор на враппер с html-контентом
2706     * - jquery {jquery} - jQuery-ссылка на враппер с html-контентом
2707     * - html {string} - html-строка с контентом
2708     * - url {string} - урл загружаемого контента
2709     * - id {string}- Значение атрибута data-iexmodal-id враппера с контентом, который нужно показать
2710     * - mode {string} - Режим показа модального окна из app.modes (по-умолчанию 'default')
2711     * - classes {string}- Список CSS-классов (через пробел), которые нужно добавить к модальному окну
2712     * - width {string}- Ширина модального окна с единицами измерения (px, %, em и т.д.). По-умолчанию ширина равна 450px. Игнорируется при modal.mode !== 'default'.
2713     * - overlay {boolean}
2713 - true - новое окно нужно открыть поверх текущего, не закрывая его, false - сначала закрыть текущее окно (по-умолчанию)
2714     * - contentScroll {string} - Прокручивать контент, если он не умещается в окне: true | false (по-умолчанию true)
2715     * - documentScroll {string} - Прокручивать документ: true | false (по-умолчанию false)
2716     * - timeout {integer} - Время в секундах, после которого окно само должно закрыться (по-умолчанию 0 сек)
2717     * - ajaxReport {boolean} - Включить отчет об ajax-запросе
2718     * - onBeforeShow {function}
2719     * - onAfterContentLoad {function}
2720     * - onAfterShow {function}
2721     * - onBeforeClose {function}
2722     * - onAfterClose {function}
2723     * Из списка параметров app.loadTypes одновременно можно передать только ОДИН!
2724     *
2725     * @return {boolean}
2726     */
2727    app.show = function (params) {
2728        params = app.validateParams(params);
2729        if ( !params ) {
2730            return false;
2731        }
2732
2733        if ( !params.overlay && app.modalsTopId ) {
2734            app.callbacks._onAfterClose = function () {
2735                app.callbacks._onAfterClose = function () {};
2736                app.show(params);
2737            };
2738            app.close();
2739            return true;
2740        }
2741
2742        var modal = app.create(params);
2743
2744        app.callbacks.onBeforeShow(modal);
2745        app.animation.wrapIn(modal);
2746
2747        if (modal.loadType==='selector' || modal.loadType==='jquery') {
2748            app.contentArray.moveToPopup(modal);
2749            app.callbacks.onAfterContentLoad(modal);
2750        }
2751
2752        if (modal.loadType==='html') {
2753            modal.$innerWrap.html(modal.html);
2754            app.callbacks.onAfterContentLoad(modal);
2755        }
2756
2757        if (modal.loadType==='url') {
2758            var modalId = modal.wrapId;
2759            $.ajax({
2760                url: modal.url,
2761                timeout: 25000, // ms, по-умолчанию таймаут отсутствует, зависит от браузера и может быть очень большим
2762                dataType: 'html',
2763                success: function (data, textStatus, jqXHR) {
2764                    if ( !app.isOpened(modalId) ) return; // если окно закрыли раньше срабатывания данного колбэка
2765
2766                    var report = '';
2767                    if (modal.ajaxReport) {
2768                        report =
2769                            '<b>' + app.repAjaxMsg + '</b>' +
2770                            '<br><br>' +
2771                            app.ajaxReport(modal.url, jqXHR) +
2772                            '<br><br>';
2773                    }
2774
2775                    modal.$innerWrap.html(report + data);
2776                    app.callbacks.onAfterContentLoad(modal);
2777                },
2778                error: function(jqXHR) {
2779                    if ( !app.isOpened(modalId) ) return; // если окно закрыли раньше срабатывания данного колбэка
2780
2781                    var report =
2782                        '<b>' + app.errAjaxMsg + '</b>' +
2783                        '<br><br>' +
2784                        app.ajaxReport(modal.url, jqXHR);
2785
2786                    modal.$innerWrap.html(report);
2787                    app.callbacks.onAfterContentLoad(modal);
2788                }
2789            });
2790        }
2791
2792        if (modal.loadType==='id') {
2793            modal.$currWrapper = app.getContentWrap(modal.id);
2794
2795            var wrapClasses = $.trim( modal.$currWrapper.attr('data-iexmodal-classes') );
2796            if ( wrapClasses ) {
2797                modal.$wrap.addClass( wrapClasses );
2798            }
2799
2800            // Переносится в модальное окно только один элемент - дополнительная обертка контента, это особенность работы $.appendTo()
2801            modal.$currContent = modal.$currWrapper.children('.'+app.classContentWrap);
2802            modal.$currContent.appendTo( modal.$innerWrap );
2803            app.callbacks.onAfterContentLoad(modal);
2804        }
2805
2806        return true;
2807    };
2808
2809    /**
2810     * Аналог String.repeat(), поддерживаемый в IE11
2811     *
2812     * @param str Строка
2813     * @param cnt Количество повторений
2814     * @return {string}
2815     */
2816    app.strRepeat = function(str, cnt){
2817        if ( !str || !cnt ) return '';
2818        return Array(cnt + 1).join('<i></i>')
2819    };
2820
2821    /**
2822     * Генератор нескольких одновременно открытых окон
2823     * Удобен для тестирования адативности и отладки
2824     * @param count Количество генерируемых окон
2825     */
2826    app.devShowMany = function (count) {
2827        var width, textTotal, textChunk;
2828        for (var $i=1; $i<=count; $i++) {
2829            width = (count +1 -$i)*100+200 + 'px';
2830            textChunk = 'Адаптивность у данного окна включается при ширине окна браузера < ' + width + '. ';
2831            textTotal = '<p>' + ( app.strRepeat(textChunk, (count-$i+1)*3) ) + '</p>';
2832            iexModal.show({
2833                'html': '<h2>Окно '+ width + '</h2><a href="#" class="iexmodal-close">Закрыть текущее окно</a>' + textTotal + '<a href="#" class="iexmodal-close-all">Закрыть все окна</a>',
2834                'width': width,
2835                'overlay': 'true'
2836            });
2837        }
2838    };
2839
2840    /**
2841     * Закрыть модальное окно
2842     * Закрывается окно переданное первым параметром, либо (без параметра) самое верхнее.
2843     *
2844     * @param modal {object|string} Объект модала или строка c wrapId. Необязательный параметр.
2845     * @return {boolean}
2846     */
2847    app.close = function (modal) {
2848        if (typeof modal !== 'object') {
2849            modal = app.getModal(modal);
2850        }
2851        if (typeof modal !== 'object') {
2852            return false;
2853        }
2854
2855        clearTimeout(modal.timeoutId);
2856        app.callbacks.onBeforeClose(modal);
2857        app.animation.allOut(modal);
2858
2859        return true;
2860    };
2861
2862    /**
2863     * Закрыть все модалы
2864     * @return {boolean}
2865     */
2866    app.closeAll = function () {
2867        let cnt = Object.entries(app.modals).length;
2868        for(let i = 1; i <= cnt; i++){
2869            app.close();
2870        }
2871        return true;
2872    };
2873
2874    /**
2875     * Функционал для блокировки прокрутки документа при открытом модальном окне
2876     *
2877     * @constructor
2878     */
2879    app.DocumentScroll = function(){
2880        var docScroll = this;
2881
2882        this.disabled = false;
2883        this.scrollCurr = [0,0]; // [left,top]
2884        this.isIE = app.getIEVersion() > 0;
2885
2886        var userAgent = window.navigator.userAgent;
2887        var isMobile = /iP(ad|hone)/i.test(userAgent);
2888        var isWebkit = /WebKit/i.test(userAgent);
2889        var isChrome = /CriOS/i.test(userAgent);
2890        var isOpera = /OPiOS/i.test(userAgent);
2891        this.isMobileSafari = isMobile && isWebkit && !isChrome && !isOpera;
2892
2893        this.scrollGet = function () {
2894            return [
2895                app.$window.scrollLeft(),
2896                app.$window.scrollTop()
2897            ]
2898        };
2899
2900        this.scrollSave = function () {
2901            docScroll.scrollCurr = docScroll.scrollGet();
2902        };
2903
2904        // Вместо preventDefault() для scroll
2905        // Для scroll preventDefault() не работает потому, что событие происходит ПОСЛЕ прокрутки
2906        this.scrollRestore = function () {
2907            app.$html.scrollLeft( docScroll.scrollCurr[0] );
2908            app.$html.scrollTop( docScroll.scrollCurr[1] );
2909        };
2910
2911        /**
2912         * Массив строк, при наличии которых в контенте модального окна считаем,
2913         * что в окне есть поля формы, а значит не нужно блокировать необходимые для этих полей клавиши
2914         *
2915         * @type {string[]}
2916         */
2917        this.formTags = [
2918            'input', 'textarea'
2919        ];
2920
2921        /**
2922         * Клавиши (их коды), которые будут блокироваться при открытом модальном окне во избежание прокрутки страницы
2923         * ---
2924         * 32 spacebar
2925         * 33 pageup
2926         * 34 pagedown
2927         * 35 end
2928         * 36 home
2929         * 37 left
2930         * 38 up
2931         * 39 right
2932         * 40 down
2933         * ---
2934         *
2935         * @type {{default: number[], form: number[]}}
2936         */
2937        this.keyCodeSets = {
2938            'default': [32, 33, 34, 35, 36, 37, 38, 39, 40],
2939            'form': [33, 34] // для корректной работы полей форм в модальном окне
2940        };
2941
2942        this.keyCodes = [];
2943
2944        this.setKeyCodes = function () {
2945            let modal = app.getTopModal();
2946            if (typeof modal !== 'object') {
2947                return;
2948            }
2949
2950            let
2951                html = modal.$innerWrap.html(),
2952                regex = new RegExp( docScroll.formTags.join('|') );
2953
2954            docScroll.keyCodes = docScroll.keyCodeSets['default'];
2955            if ( regex.exec(html) ) {
2956                docScroll.keyCodes = docScroll.keyCodeSets['form'];
2957            }
2958        };
2959
2960        this.handleTouch = function(event) {
2961            event.preventDefault();
2962        };
2963
2964        this.handleWheel = function(event) {
2965            event.preventDefault();
2966        };
2967
2968        this.handleKeydown = function(event) {
2969            if ( docScroll.keyCodes.indexOf(event.keyCode) > -1 ) {
2970                event.preventDefault();
2971            }
2972        };
2973
2974        this.handleScrollbar = function(event) {
2975            if (!docScroll.isMobileSafari) { // в сафари прокрутку не компенсируем во избежание рывков при переключении между полями формы
2976                docScroll.scrollRestore(); // Для scroll preventDefault() не работает потому, что событие происходит ПОСЛЕ прокрутки
2977            }
2978        };
2979
2980        this.off = function () {
2981            if ( docScroll.disabled || docScroll.isIE ){ // в IE не работают нормально addEventListener и removeEventListener
2982                return;
2983            }
2984
2985            docScroll.scrollSave();
2986            docScroll.setKeyCodes();
2987
2988            app.$html.css('touch-action', 'none');
2989            app.$html[0].addEventListener('mousewheel DOMMouseScroll', docScroll.handleWheel, { passive: false });
2990            app.$html[0].addEventListener('keydown', docScroll.handleKeydown, { passive: false });
2991            app.$html[0].addEventListener('touchmove', docScroll.handleTouch, {passive: false});
2992            window.addEventListener('scroll', docScroll.handleScrollbar, { passive: false });
2993
2994            docScroll.disabled = true;
2995        };
2996
2997        this.on = function () {
2998            if ( !docScroll.disabled || docScroll.isIE ){
2999                return;
3000            }
3001
3002            app.$html.css('touch-action', 'auto');
3003            app.$html[0].removeEventListener('mousewheel DOMMouseScroll', docScroll.handleWheel);
3004            app.$html[0].removeEventListener('keydown', docScroll.handleKeydown);
3005            app.$html[0].removeEventListener('touchmove', docScroll.handleTouch);
3006            window.removeEventListener('scroll', docScroll.handleScrollbar);
3007
3008            docScroll.disabled = false;
3009        }
3010    };
3011    app.documentScroll = new app.DocumentScroll;
3012
3013    /**
3014     * Системные коллбэки, запускающие одноименные пользовательские.
3015     * Выполняются в приведенном порядке, сверху-вниз.
3016     */
3017    app.callbacks = {
3018
3019        onBeforeShow: function(modal){
3020            modal.onBeforeShow(modal);
3021
3022            if (modal.outerScroll) {
3023                app.$body
3024                    .addClass(app.classOpened)
3025                    .css('padding-right', app.scrollbarWidth+'px')
3026            }
3027        },
3028
3029        onAfterContentLoad: function (modal) {
3030            modal.onAfterContentLoad(modal);
3031
3032            if (app.modalsTopId) {
3033                if (
3034                    !modal.outerScroll &&
3035                    modal.mode !== 'alert'
3036                ) {
3037                    app.documentScroll.off();
3038                }
3039                app.$window.on('resize orientationchange', app.windowRelatedActions);
3040                if (window.visualViewport) {
3041                    window.visualViewport.addEventListener('resize', app.windowRelatedActions);
3042                }
3043            }
3044
3045            app.windowRelatedActions();
3046            app.animation.popupIn(modal);
3047        },
3048
3049        onAfterShow: function(modal){
3050            if ( modal.timeout ) {
3051                modal.timeoutId = setTimeout(function () {
3052                    app.close(modal);
3053                }, modal.timeout*1000)
3054            }
3055            modal.onAfterShow(modal);
3056        },
3057
3058        onBeforeClose: function(modal){
3059            modal.onBeforeClose(modal);
3060        },
3061
3062        onAfterClose: function(modal){
3063            if (app.modalsTopId) {
3064                if (
3065                    !modal.outerScroll &&
3066                    modal.mode !== 'alert'
3067                ) {
3068                    app.documentScroll.on();
3069                }
3070                app.$window.off('resize orientationchange', app.windowRelatedActions);
3071                if (window.visualViewport) {
3072                    window.visualViewport.removeEventListener('resize', app.windowRelatedActions);
3073                }
3074                if (modal.outerScroll) {
3075                    app.$body
3076                        .removeClass(app.classOpened)
3077                        .css('padding-right', '')
3078                }
3079            }
3080
3081            modal.onAfterClose(modal);
3082            app.remove(modal);
3083            app.callbacks._onAfterClose(modal);
3084        },
3085
3086        // Используется в app.show() для предварительного закрытия текущего окна
3087        // и показа нового только после завершения анимации у текущего
3088        _onAfterClose: function () {}
3089    };
3090
3091    /**
3092     * Обработчик нажатия Escape.
3093     * Вещаем его в $(document).ready() во избежание клонирования при повторном выполнении iexModal.init()
3094     */
3095    app.handleEscape = function (e) {
3096        if (app.modalsTopId && e.keyCode===27) {
3097            app.close();
3098        }
3099    };
3100
3101    /**
3102     * Действия, связанные с событиями resize и orientationchange
3103     */
3104    app.windowRelatedActions = function(){
3105        app.getWindowSize();
3106        app.correctPosition();
3107    };
3108
3109    /**
3110     * Публичный этап инициализация модуля, который можно выполнять повторно.
3111     * Автоматически выполняется при каждой загрузке страницы.
3112     *
3113     */
3114    app.init = function () {
3115
3116        app.$body.find('.'+app.classContent+':not([data-iexmodal-content-wrap="false"])')
3117        // предварительно удаляем дополнительные обертки контента
3118        // для возможности повторного выполнения app.init()
3119        //
3120        // TODO: Не трогать врапперы, уже обработанные во время предыдущего запуска app.init()
3121            .each(function () {
3122                var $firstChild = $(this).children('.'+app.classContentWrap).children().first();
3123                if ( $firstChild.parent().is('.'+app.classContentWrap) ) {
3124                    $firstChild.unwrap();
3125                }
3126            })
3127            // создаем дополнительные вложенные обертки контента, которые и будут переноситься в модальное окно методом $.appendTo()
3128            .wrapInner('<div class="'+app.classContentWrap+'"></div>');
3129
3130        app.colorboxInit();
3131        app.getWindowSize();
3132    };
3133
3134    /**
3135     * Приватный этап инициализация модуля, который нельзя/нежелательно выполнять повторно.
3136     * Автоматически выполняется при каждой загрузке страницы.
3137     * Некоторые обработчики вешаем здесь чтобы:
3138     * 1) работало делегирование
3139     * 2) избежать клонирования обработчиков при повторной публичной инициализации iexModal.init()
3140     *
3141     * @private
3142     */
3143    app.__init = function () {
3144        app.$sprite = app.insertSprite();
3145
3146        app.$window.on('keyup', app.handleEscape);
3147
3148        app.$body
3149            .on('click', '.'+app.classBtn, function (e) {
3150                app.show( app.parseBtnAttrs( $(this) ) );
3151                e.preventDefault();
3152            })
3153            .on('click touchstart', '.'+app.classClose, function (e) { // touchstart - для Safari, т.к. в нем вместо click чаще touchmove происходит (в 3-х случаях из 4-
3153х)
3154                let wrapId = $(e.originalEvent.target).parents('.'+app.classWrap+'[data-iexmodal-id]').attr('data-iexmodal-id')
3155                app.close(wrapId);
3156            })
3157            .on('click', '.'+app.classCloseAll, app.closeAll);
3158
3159        app.scrollbarWidth = app.getScrollbarWidth();
3160
3161        $.each(app.attrsAndParams, function (key,val){
3162            app.params.push(val);
3163        });
3164        $.each(app.userCallbackNames, function (key,val){
3165            app.params.push(val);
3166        });
3167    };
3168
3169    app.init();
3170    app.__init();
3171};
3172
3173$(document).ready(function () {
3174    if (!!window.IexModal && !!window.jQuery) {
3175        if (!!window.iexModal) {
3176            console.log(iexModal.errScriptLoadingMsg);
3177        } else {
3178            window.iexModal = new IexModal(jQuery);
3179        }
3180    }
3181});
3182
3183/**
3184 * END: iexModal
3185 */
3186
3187},{"./anime.js":1,"./perfect-srollbar.js":3}],3:[function(require,module,exports){
3188/*!
3189 * perfect-scrollbar v1.3.0
3190 * (c) 2017 Hyunje Jun
3191 * @license MIT
3192 */
3193(function (global, factory) {
3194    typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
3195        typeof define === 'function' && define.amd ? define(factory) :
3196            (global.PerfectScrollbar = factory());
3197}(this, (function () { 'use strict';
3198
3199    function get(element) {
3200        return getComputedStyle(element);
3201    }
3202
3203    function set(element, obj) {
3204        for (var key in obj) {
3205            var val = obj[key];
3206            if (typeof val === 'number') {
3207                val = val + "px";
3208            }
3209            element.style[key] = val;
3210        }
3211        return element;
3212    }
3213
3214    function div(className) {
3215        var div = document.createElement('div');
3216        div.className = className;
3217        return div;
3218    }
3219
3220    var elMatches =
3221        typeof Element !== 'undefined' &&
3222        (Element.prototype.matches ||
3223            Element.prototype.webkitMatchesSelector ||
3224            Element.prototype.msMatchesSelector);
3225
3226    function matches(element, query) {
3227        if (!elMatches) {
3228            throw new Error('No element matching method supported');
3229        }
3230
3231        return elMatches.call(element, query);
3232    }
3233
3234    function remove(element) {
3235        if (element.remove) {
3236            element.remove();
3237        } else {
3238            if (element.parentNode) {
3239                element.parentNode.removeChild(element);
3240            }
3241        }
3242    }
3243
3244    function queryChildren(element, selector) {
3245        return Array.prototype.filter.call(element.children, function (child) { return matches(child, selector); }
3246        );
3247    }
3248
3249    var cls = {
3250        main: 'ps',
3251        element: {
3252            thumb: function (x) { return ("ps__thumb-" + x); },
3253            rail: function (x) { return ("ps__rail-" + x); },
3254            consuming: 'ps__child--consume',
3255        },
3256        state: {
3257            focus: 'ps--focus',
3258            active: function (x) { return ("ps--active-" + x); },
3259            scrolling: function (x) { return ("ps--scrolling-" + x); },
3260        },
3261    };
3262
3263    /*
3264     * Helper methods
3265     */
3266    var scrollingClassTimeout = { x: null, y: null };
3267
3268    function addScrollingClass(i, x) {
3269        var classList = i.element.classList;
3270        var className = cls.state.scrolling(x);
3271
3272        if (classList.contains(className)) {
3273            clearTimeout(scrollingClassTimeout[x]);
3274        } else {
3275            classList.add(className);
3276        }
3277    }
3278
3279    function removeScrollingClass(i, x) {
3280        scrollingClassTimeout[x] = setTimeout(
3281            function () { return i.isAlive && i.element.classList.remove(cls.state.scrolling(x)); },
3282            i.settings.scrollingThreshold
3283        );
3284    }
3285
3286    function setScrollingClassInstantly(i, x) {
3287        addScrollingClass(i, x);
3288        removeScrollingClass(i, x);
3289    }
3290
3291    var EventElement = function EventElement(element) {
3292        this.element = element;
3293        this.handlers = {};
3294    };
3295
3296    var prototypeAccessors = { isEmpty: { configurable: true } };
3297
3298    EventElement.prototype.bind = function bind (eventName, handler) {
3299        if (typeof this.handlers[eventName] === 'undefined') {
3300            this.handlers[eventName] = [];
3301        }
3302        this.handlers[eventName].push(handler);
3303        this.element.addEventListener(eventName, handler, false);
3304    };
3305
3306    EventElement.prototype.unbind = function unbind (eventName, target) {
3307        var this$1 = this;
3308
3309        this.handlers[eventName] = this.handlers[eventName].filter(function (handler) {
3310            if (target && handler !== target) {
3311                return true;
3312            }
3313            this$1.element.removeEventListener(eventName, handler, false);
3314            return false;
vendor: 4,217 bytes, lines 3315-3458
3315        });
3316    };
3317
3318    EventElement.prototype.unbindAll = function unbindAll () {
3319        var this$1 = this;
3320
3321        for (var name in this$1.handlers) {
3322            this$1.unbind(name);
3323        }
3324    };
3325
3326    prototypeAccessors.isEmpty.get = function () {
3327        var this$1 = this;
3328
3329        return Object.keys(this.handlers).every(
3330            function (key) { return this$1.handlers[key].length === 0; }
3331        );
3332    };
3333
3334    Object.defineProperties( EventElement.prototype, prototypeAccessors );
3335
3336    var EventManager = function EventManager() {
3337        this.eventElements = [];
3338    };
3339
3340    EventManager.prototype.eventElement = function eventElement (element) {
3341        var ee = this.eventElements.filter(function (ee) { return ee.element === element; })[0];
3342        if (!ee) {
3343            ee = new EventElement(element);
3344            this.eventElements.push(ee);
3345        }
3346        return ee;
3347    };
3348
3349    EventManager.prototype.bind = function bind (element, eventName, handler) {
3350        this.eventElement(element).bind(eventName, handler);
3351    };
3352
3353    EventManager.prototype.unbind = function unbind (element, eventName, handler) {
3354        var ee = this.eventElement(element);
3355        ee.unbind(eventName, handler);
3356
3357        if (ee.isEmpty) {
3358            // remove
3359            this.eventElements.splice(this.eventElements.indexOf(ee), 1);
3360        }
3361    };
3362
3363    EventManager.prototype.unbindAll = function unbindAll () {
3364        this.eventElements.forEach(function (e) { return e.unbindAll(); });
3365        this.eventElements = [];
3366    };
3367
3368    EventManager.prototype.once = function once (element, eventName, handler) {
3369        var ee = this.eventElement(element);
3370        var onceHandler = function (evt) {
3371            ee.unbind(eventName, onceHandler);
3372            handler(evt);
3373        };
3374        ee.bind(eventName, onceHandler);
3375    };
3376
3377    function createEvent(name) {
3378        if (typeof window.CustomEvent === 'function') {
3379            return new CustomEvent(name);
3380        } else {
3381            var evt = document.createEvent('CustomEvent');
3382            evt.initCustomEvent(name, false, false, undefined);
3383            return evt;
3384        }
3385    }
3386
3387    var processScrollDiff = function(
3388        i,
3389        axis,
3390        diff,
3391        useScrollingClass,
3392        forceFireReachEvent
3393    ) {
3394        if ( useScrollingClass === void 0 ) useScrollingClass = true;
3395        if ( forceFireReachEvent === void 0 ) forceFireReachEvent = false;
3396
3397        var fields;
3398        if (axis === 'top') {
3399            fields = [
3400                'contentHeight',
3401                'containerHeight',
3402                'scrollTop',
3403                'y',
3404                'up',
3405                'down' ];
3406        } else if (axis === 'left') {
3407            fields = [
3408                'contentWidth',
3409                'containerWidth',
3410                'scrollLeft',
3411                'x',
3412                'left',
3413                'right' ];
3414        } else {
3415            throw new Error('A proper axis should be provided');
3416        }
3417
3418        processScrollDiff$1(i, diff, fields, useScrollingClass, forceFireReachEvent);
3419    };
3420
3421    function processScrollDiff$1(
3422        i,
3423        diff,
3424        ref,
3425        useScrollingClass,
3426        forceFireReachEvent
3427    ) {
3428        var contentHeight = ref[0];
3429        var containerHeight = ref[1];
3430        var scrollTop = ref[2];
3431        var y = ref[3];
3432        var up = ref[4];
3433        var down = ref[5];
3434        if ( useScrollingClass === void 0 ) useScrollingClass = true;
3435        if ( forceFireReachEvent === void 0 ) forceFireReachEvent = false;
3436
3437        var element = i.element;
3438
3439        // reset reach
3440        i.reach[y] = null;
3441
3442        // 1 for subpixel rounding
3443        if (element[scrollTop] < 1) {
3444            i.reach[y] = 'start';
3445        }
3446
3447        // 1 for subpixel rounding
3448        if (element[scrollTop] > i[contentHeight] - i[containerHeight] - 1) {
3449            i.reach[y] = 'end';
3450        }
3451
3452        if (diff) {
3453            element.dispatchEvent(createEvent(("ps-scroll-" + y)));
3454
3455            if (diff < 0) {
3456                element.dispatchEvent(createEvent(("ps-scroll-" + up)));
3457            } else if (diff > 0) {
3458                element.dispatchEvent(createEvent(("ps-scroll-" + down))
vendor: 29,959 bytes, lines 3458-4341
3458);
3459            }
3460
3461            if (useScrollingClass) {
3462                setScrollingClassInstantly(i, y);
3463            }
3464        }
3465
3466        if (i.reach[y] && (diff || forceFireReachEvent)) {
3467            element.dispatchEvent(createEvent(("ps-" + y + "-reach-" + (i.reach[y]))));
3468        }
3469    }
3470
3471    function toInt(x) {
3472        return parseInt(x, 10) || 0;
3473    }
3474
3475    function isEditable(el) {
3476        return (
3477            matches(el, 'input,[contenteditable]') ||
3478            matches(el, 'select,[contenteditable]') ||
3479            matches(el, 'textarea,[contenteditable]') ||
3480            matches(el, 'button,[contenteditable]')
3481        );
3482    }
3483
3484    function outerWidth(element) {
3485        var styles = get(element);
3486        return (
3487            toInt(styles.width) +
3488            toInt(styles.paddingLeft) +
3489            toInt(styles.paddingRight) +
3490            toInt(styles.borderLeftWidth) +
3491            toInt(styles.borderRightWidth)
3492        );
3493    }
3494
3495    var env = {
3496        isWebKit:
3497            typeof document !== 'undefined' &&
3498            'WebkitAppearance' in document.documentElement.style,
3499        supportsTouch:
3500            typeof window !== 'undefined' &&
3501            ('ontouchstart' in window ||
3502                (window.DocumentTouch && document instanceof window.DocumentTouch)),
3503        supportsIePointer:
3504            typeof navigator !== 'undefined' && navigator.msMaxTouchPoints,
3505        isChrome:
3506            typeof navigator !== 'undefined' &&
3507            /Chrome/i.test(navigator && navigator.userAgent),
3508    };
3509
3510    var updateGeometry = function(i) {
3511        var element = i.element;
3512
3513        i.containerWidth = element.clientWidth;
3514        i.containerHeight = element.clientHeight;
3515        i.contentWidth = element.scrollWidth;
3516        i.contentHeight = element.scrollHeight;
3517
3518        if (!element.contains(i.scrollbarXRail)) {
3519            // clean up and append
3520            queryChildren(element, cls.element.rail('x')).forEach(function (el) { return remove(el); }
3521            );
3522            element.appendChild(i.scrollbarXRail);
3523        }
3524        if (!element.contains(i.scrollbarYRail)) {
3525            // clean up and append
3526            queryChildren(element, cls.element.rail('y')).forEach(function (el) { return remove(el); }
3527            );
3528            element.appendChild(i.scrollbarYRail);
3529        }
3530
3531        if (
3532            !i.settings.suppressScrollX &&
3533            i.containerWidth + i.settings.scrollXMarginOffset < i.contentWidth
3534        ) {
3535            i.scrollbarXActive = true;
3536            i.railXWidth = i.containerWidth - i.railXMarginWidth;
3537            i.railXRatio = i.containerWidth / i.railXWidth;
3538            i.scrollbarXWidth = getThumbSize(
3539                i,
3540                toInt(i.railXWidth * i.containerWidth / i.contentWidth)
3541            );
3542            i.scrollbarXLeft = toInt(
3543                (i.negativeScrollAdjustment + element.scrollLeft) *
3544                (i.railXWidth - i.scrollbarXWidth) /
3545                (i.contentWidth - i.containerWidth)
3546            );
3547        } else {
3548            i.scrollbarXActive = false;
3549        }
3550
3551        if (
3552            !i.settings.suppressScrollY &&
3553            i.containerHeight + i.settings.scrollYMarginOffset < i.contentHeight
3554        ) {
3555            i.scrollbarYActive = true;
3556            i.railYHeight = i.containerHeight - i.railYMarginHeight;
3557            i.railYRatio = i.containerHeight / i.railYHeight;
3558            i.scrollbarYHeight = getThumbSize(
3559                i,
3560                toInt(i.railYHeight * i.containerHeight / i.contentHeight)
3561            );
3562            i.scrollbarYTop = toInt(
3563                element.scrollTop *
3564                (i.railYHeight - i.scrollbarYHeight) /
3565                (i.contentHeight - i.containerHeight)
3566            );
3567        } else {
3568            i.scrollbarYActive = false;
3569        }
3570
3571        if (i.scrollbarXLeft >= i.railXWidth - i.scrollbarXWidth) {
3572            i.scrollbarXLeft = i.railXWidth - i.scrollbarXWidth;
3573        }
3574        if (i.scrollbarYTop >= i.railYHeight - i.scrollbarYHeight) {
3575            i.scrollbarYTop = i.railYHeight - i.scrollbarYHeight;
3576        }
3577
3578        updateCss(element, i);
3579
3580        if (i.scrollbarXActive) {
3581            element.classList.add(cls.state.active('x'));
3582        } else {
3583            element.classList.remove(cls.state.active('x'));
3584            i.scrollbarXWidth = 0;
3585            i.scrollbarXLeft = 0;
3586            element.scrollLeft = 0;
3587        }
3588        if (i.scrollbarYActive) {
3589            element.classList.add(cls.state.active('y'));
3590        } else {
3591            element.classList.remove(cls.state.active('y'));
3592            i.scrollbarYHeight = 0;
3593            i.scrollbarYTop = 0;
3594            element.scrollTop = 0;
3595        }
3596    };
3597
3598    function getThumbSize(i, thumbSize) {
3599        if (i.settings.minScrollbarLength) {
3600            thumbSize = Math.max(thumbSize, i.settings.minScrollbarLength);
3601        }
3602        if (i.settings.maxScrollbarLength) {
3603            thumbSize = Math.min(thumbSize, i.settings.maxScrollbarLength);
3604        }
3605        return thumbSize;
3606    }
3607
3608    function updateCss(element, i) {
3609        var xRailOffset = { width: i.railXWidth };
3610        if (i.isRtl) {
3611            xRailOffset.left =
3612                i.negativeScrollAdjustment +
3613                element.scrollLeft +
3614                i.containerWidth -
3615                i.contentWidth;
3616        } else {
3617            xRailOffset.left = element.scrollLeft;
3618        }
3619        if (i.isScrollbarXUsingBottom) {
3620            xRailOffset.bottom = i.scrollbarXBottom - element.scrollTop;
3621        } else {
3622            xRailOffset.top = i.scrollbarXTop + element.scrollTop;
3623        }
3624        set(i.scrollbarXRail, xRailOffset);
3625
3626        var yRailOffset = { top: element.scrollTop, height: i.railYHeight };
3627        if (i.isScrollbarYUsingRight) {
3628            if (i.isRtl) {
3629                yRailOffset.right =
3630                    i.contentWidth -
3631                    (i.negativeScrollAdjustment + element.scrollLeft) -
3632                    i.scrollbarYRight -
3633                    i.scrollbarYOuterWidth;
3634            } else {
3635                yRailOffset.right = i.scrollbarYRight - element.scrollLeft;
3636            }
3637        } else {
3638            if (i.isRtl) {
3639                yRailOffset.left =
3640                    i.negativeScrollAdjustment +
3641                    element.scrollLeft +
3642                    i.containerWidth * 2 -
3643                    i.contentWidth -
3644                    i.scrollbarYLeft -
3645                    i.scrollbarYOuterWidth;
3646            } else {
3647                yRailOffset.left = i.scrollbarYLeft + element.scrollLeft;
3648            }
3649        }
3650        set(i.scrollbarYRail, yRailOffset);
3651
3652        set(i.scrollbarX, {
3653            left: i.scrollbarXLeft,
3654            width: i.scrollbarXWidth - i.railBorderXWidth,
3655        });
3656        set(i.scrollbarY, {
3657            top: i.scrollbarYTop,
3658            height: i.scrollbarYHeight - i.railBorderYWidth,
3659        });
3660    }
3661
3662    var clickRail = function(i) {
3663        i.event.bind(i.scrollbarY, 'mousedown', function (e) { return e.stopPropagation(); });
3664        i.event.bind(i.scrollbarYRail, 'mousedown', function (e) {
3665            var positionTop =
3666                e.pageY -
3667                window.pageYOffset -
3668                i.scrollbarYRail.getBoundingClientRect().top;
3669            var direction = positionTop > i.scrollbarYTop ? 1 : -1;
3670
3671            i.element.scrollTop += direction * i.containerHeight;
3672            updateGeometry(i);
3673
3674            e.stopPropagation();
3675        });
3676
3677        i.event.bind(i.scrollbarX, 'mousedown', function (e) { return e.stopPropagation(); });
3678        i.event.bind(i.scrollbarXRail, 'mousedown', function (e) {
3679            var positionLeft =
3680                e.pageX -
3681                window.pageXOffset -
3682                i.scrollbarXRail.getBoundingClientRect().left;
3683            var direction = positionLeft > i.scrollbarXLeft ? 1 : -1;
3684
3685            i.element.scrollLeft += direction * i.containerWidth;
3686            updateGeometry(i);
3687
3688            e.stopPropagation();
3689        });
3690    };
3691
3692    var dragThumb = function(i) {
3693        bindMouseScrollHandler(i, [
3694            'containerWidth',
3695            'contentWidth',
3696            'pageX',
3697            'railXWidth',
3698            'scrollbarX',
3699            'scrollbarXWidth',
3700            'scrollLeft',
3701            'x' ]);
3702        bindMouseScrollHandler(i, [
3703            'containerHeight',
3704            'contentHeight',
3705            'pageY',
3706            'railYHeight',
3707            'scrollbarY',
3708            'scrollbarYHeight',
3709            'scrollTop',
3710            'y' ]);
3711    };
3712
3713    function bindMouseScrollHandler(
3714        i,
3715        ref
3716    ) {
3717        var containerHeight = ref[0];
3718        var contentHeight = ref[1];
3719        var pageY = ref[2];
3720        var railYHeight = ref[3];
3721        var scrollbarY = ref[4];
3722        var scrollbarYHeight = ref[5];
3723        var scrollTop = ref[6];
3724        var y = ref[7];
3725
3726        var element = i.element;
3727
3728        var startingScrollTop = null;
3729        var startingMousePageY = null;
3730        var scrollBy = null;
3731
3732        function mouseMoveHandler(e) {
3733            element[scrollTop] =
3734                startingScrollTop + scrollBy * (e[pageY] - startingMousePageY);
3735            addScrollingClass(i, y);
3736            updateGeometry(i);
3737
3738            e.stopPropagation();
3739            e.preventDefault();
3740        }
3741
3742        function mouseUpHandler() {
3743            removeScrollingClass(i, y);
3744            i.event.unbind(i.ownerDocument, 'mousemove', mouseMoveHandler);
3745        }
3746
3747        i.event.bind(i[scrollbarY], 'mousedown', function (e) {
3748            startingScrollTop = element[scrollTop];
3749            startingMousePageY = e[pageY];
3750            scrollBy =
3751                (i[contentHeight] - i[containerHeight]) /
3752                (i[railYHeight] - i[scrollbarYHeight]);
3753
3754            i.event.bind(i.ownerDocument, 'mousemove', mouseMoveHandler);
3755            i.event.once(i.ownerDocument, 'mouseup', mouseUpHandler);
3756
3757            e.stopPropagation();
3758            e.preventDefault();
3759        });
3760    }
3761
3762    var keyboard = function(i) {
3763        var element = i.element;
3764
3765        var elementHovered = function () { return matches(element, ':hover'); };
3766        var scrollbarFocused = function () { return matches(i.scrollbarX, ':focus') || matches(i.scrollbarY, ':focus'); };
3767
3768        function shouldPreventDefault(deltaX, deltaY) {
3769            var scrollTop = element.scrollTop;
3770            if (deltaX === 0) {
3771                if (!i.scrollbarYActive) {
3772                    return false;
3773                }
3774                if (
3775                    (scrollTop === 0 && deltaY > 0) ||
3776                    (scrollTop >= i.contentHeight - i.containerHeight && deltaY < 0)
3777                ) {
3778                    return !i.settings.wheelPropagation;
3779                }
3780            }
3781
3782            var scrollLeft = element.scrollLeft;
3783            if (deltaY === 0) {
3784                if (!i.scrollbarXActive) {
3785                    return false;
3786                }
3787                if (
3788                    (scrollLeft === 0 && deltaX < 0) ||
3789                    (scrollLeft >= i.contentWidth - i.containerWidth && deltaX > 0)
3790                ) {
3791                    return !i.settings.wheelPropagation;
3792                }
3793            }
3794            return true;
3795        }
3796
3797        i.event.bind(i.ownerDocument, 'keydown', function (e) {
3798            if (
3799                (e.isDefaultPrevented && e.isDefaultPrevented()) ||
3800                e.defaultPrevented
3801            ) {
3802                return;
3803            }
3804
3805            if (!elementHovered() && !scrollbarFocused()) {
3806                return;
3807            }
3808
3809            var activeElement = document.activeElement
3810                ? document.activeElement
3811                : i.ownerDocument.activeElement;
3812            if (activeElement) {
3813                if (activeElement.tagName === 'IFRAME') {
3814                    activeElement = activeElement.contentDocument.activeElement;
3815                } else {
3816                    // go deeper if element is a webcomponent
3817                    while (activeElement.shadowRoot) {
3818                        activeElement = activeElement.shadowRoot.activeElement;
3819                    }
3820                }
3821                if (isEditable(activeElement)) {
3822                    return;
3823                }
3824            }
3825
3826            var deltaX = 0;
3827            var deltaY = 0;
3828
3829            switch (e.which) {
3830                case 37: // left
3831                    if (e.metaKey) {
3832                        deltaX = -i.contentWidth;
3833                    } else if (e.altKey) {
3834                        deltaX = -i.containerWidth;
3835                    } else {
3836                        deltaX = -30;
3837                    }
3838                    break;
3839                case 38: // up
3840                    if (e.metaKey) {
3841                        deltaY = i.contentHeight;
3842                    } else if (e.altKey) {
3843                        deltaY = i.containerHeight;
3844                    } else {
3845                        deltaY = 30;
3846                    }
3847                    break;
3848                case 39: // right
3849                    if (e.metaKey) {
3850                        deltaX = i.contentWidth;
3851                    } else if (e.altKey) {
3852                        deltaX = i.containerWidth;
3853                    } else {
3854                        deltaX = 30;
3855                    }
3856                    break;
3857                case 40: // down
3858                    if (e.metaKey) {
3859                        deltaY = -i.contentHeight;
3860                    } else if (e.altKey) {
3861                        deltaY = -i.containerHeight;
3862                    } else {
3863                        deltaY = -30;
3864                    }
3865                    break;
3866                case 32: // space bar
3867                    if (e.shiftKey) {
3868                        deltaY = i.containerHeight;
3869                    } else {
3870                        deltaY = -i.containerHeight;
3871                    }
3872                    break;
3873                case 33: // page up
3874                    deltaY = i.containerHeight;
3875                    break;
3876                case 34: // page down
3877                    deltaY = -i.containerHeight;
3878                    break;
3879                case 36: // home
3880                    deltaY = i.contentHeight;
3881                    break;
3882                case 35: // end
3883                    deltaY = -i.contentHeight;
3884                    break;
3885                default:
3886                    return;
3887            }
3888
3889            if (i.settings.suppressScrollX && deltaX !== 0) {
3890                return;
3891            }
3892            if (i.settings.suppressScrollY && deltaY !== 0) {
3893                return;
3894            }
3895
3896            element.scrollTop -= deltaY;
3897            element.scrollLeft += deltaX;
3898            updateGeometry(i);
3899
3900            if (shouldPreventDefault(deltaX, deltaY)) {
3901                e.preventDefault();
3902            }
3903        });
3904    };
3905
3906    var wheel = function(i) {
3907        var element = i.element;
3908
3909        function shouldPreventDefault(deltaX, deltaY) {
3910            var isTop = element.scrollTop === 0;
3911            var isBottom =
3912                element.scrollTop + element.offsetHeight === element.scrollHeight;
3913            var isLeft = element.scrollLeft === 0;
3914            var isRight =
3915                element.scrollLeft + element.offsetWidth === element.offsetWidth;
3916
3917            var hitsBound;
3918
3919            // pick axis with primary direction
3920            if (Math.abs(deltaY) > Math.abs(deltaX)) {
3921                hitsBound = isTop || isBottom;
3922            } else {
3923                hitsBound = isLeft || isRight;
3924            }
3925
3926            return hitsBound ? !i.settings.wheelPropagation : true;
3927        }
3928
3929        function getDeltaFromEvent(e) {
3930            var deltaX = e.deltaX;
3931            var deltaY = -1 * e.deltaY;
3932
3933            if (typeof deltaX === 'undefined' || typeof deltaY === 'undefined') {
3934                // OS X Safari
3935                deltaX = -1 * e.wheelDeltaX / 6;
3936                deltaY = e.wheelDeltaY / 6;
3937            }
3938
3939            if (e.deltaMode && e.deltaMode === 1) {
3940                // Firefox in deltaMode 1: Line scrolling
3941                deltaX *= 10;
3942                deltaY *= 10;
3943            }
3944
3945            if (deltaX !== deltaX && deltaY !== deltaY /* NaN checks */) {
3946                // IE in some mouse drivers
3947                deltaX = 0;
3948                deltaY = e.wheelDelta;
3949            }
3950
3951            if (e.shiftKey) {
3952                // reverse axis with shift key
3953                return [-deltaY, -deltaX];
3954            }
3955            return [deltaX, deltaY];
3956        }
3957
3958        function shouldBeConsumedByChild(target, deltaX, deltaY) {
3959            // FIXME: this is a workaround for <select> issue in FF and IE #571
3960            if (!env.isWebKit && element.querySelector('select:focus')) {
3961                return true;
3962            }
3963
3964            if (!element.contains(target)) {
3965                return false;
3966            }
3967
3968            var cursor = target;
3969
3970            while (cursor && cursor !== element) {
3971                if (cursor.classList.contains(cls.element.consuming)) {
3972                    return true;
3973                }
3974
3975                var style = get(cursor);
3976                var overflow = [style.overflow, style.overflowX, style.overflowY].join(
3977                    ''
3978                );
3979
3980                // if scrollable
3981                if (overflow.match(/(scroll|auto)/)) {
3982                    var maxScrollTop = cursor.scrollHeight - cursor.clientHeight;
3983                    if (maxScrollTop > 0) {
3984                        if (
3985                            !(cursor.scrollTop === 0 && deltaY > 0) &&
3986                            !(cursor.scrollTop === maxScrollTop && deltaY < 0)
3987                        ) {
3988                            return true;
3989                        }
3990                    }
3991                    var maxScrollLeft = cursor.scrollLeft - cursor.clientWidth;
3992                    if (maxScrollLeft > 0) {
3993                        if (
3994                            !(cursor.scrollLeft === 0 && deltaX < 0) &&
3995                            !(cursor.scrollLeft === maxScrollLeft && deltaX > 0)
3996                        ) {
3997                            return true;
3998                        }
3999                    }
4000                }
4001
4002                cursor = cursor.parentNode;
4003            }
4004
4005            return false;
4006        }
4007
4008        function mousewheelHandler(e) {
4009            var ref = getDeltaFromEvent(e);
4010            var deltaX = ref[0];
4011            var deltaY = ref[1];
4012
4013            if (shouldBeConsumedByChild(e.target, deltaX, deltaY)) {
4014                return;
4015            }
4016
4017            var shouldPrevent = false;
4018            if (!i.settings.useBothWheelAxes) {
4019                // deltaX will only be used for horizontal scrolling and deltaY will
4020                // only be used for vertical scrolling - this is the default
4021                element.scrollTop -= deltaY * i.settings.wheelSpeed;
4022                element.scrollLeft += deltaX * i.settings.wheelSpeed;
4023            } else if (i.scrollbarYActive && !i.scrollbarXActive) {
4024                // only vertical scrollbar is active and useBothWheelAxes option is
4025                // active, so let's scroll vertical bar using both mouse wheel axes
4026                if (deltaY) {
4027                    element.scrollTop -= deltaY * i.settings.wheelSpeed;
4028                } else {
4029                    element.scrollTop += deltaX * i.settings.wheelSpeed;
4030                }
4031                shouldPrevent = true;
4032            } else if (i.scrollbarXActive && !i.scrollbarYActive) {
4033                // useBothWheelAxes and only horizontal bar is active, so use both
4034                // wheel axes for horizontal bar
4035                if (deltaX) {
4036                    element.scrollLeft += deltaX * i.settings.wheelSpeed;
4037                } else {
4038                    element.scrollLeft -= deltaY * i.settings.wheelSpeed;
4039                }
4040                shouldPrevent = true;
4041            }
4042
4043            updateGeometry(i);
4044
4045            shouldPrevent = shouldPrevent || shouldPreventDefault(deltaX, deltaY);
4046            if (shouldPrevent && !e.ctrlKey) {
4047                e.stopPropagation();
4048                e.preventDefault();
4049            }
4050        }
4051
4052        if (typeof window.onwheel !== 'undefined') {
4053            i.event.bind(element, 'wheel', mousewheelHandler);
4054        } else if (typeof window.onmousewheel !== 'undefined') {
4055            i.event.bind(element, 'mousewheel', mousewheelHandler);
4056        }
4057    };
4058
4059    var touch = function(i) {
4060        if (!env.supportsTouch && !env.supportsIePointer) {
4061            return;
4062        }
4063
4064        var element = i.element;
4065
4066        function shouldPrevent(deltaX, deltaY) {
4067            var scrollTop = element.scrollTop;
4068            var scrollLeft = element.scrollLeft;
4069            var magnitudeX = Math.abs(deltaX);
4070            var magnitudeY = Math.abs(deltaY);
4071
4072            if (magnitudeY > magnitudeX) {
4073                // user is perhaps trying to swipe up/down the page
4074
4075                if (
4076                    (deltaY < 0 && scrollTop === i.contentHeight - i.containerHeight) ||
4077                    (deltaY > 0 && scrollTop === 0)
4078                ) {
4079                    // set prevent for mobile Chrome refresh
4080                    return window.scrollY === 0 && deltaY > 0 && env.isChrome;
4081                }
4082            } else if (magnitudeX > magnitudeY) {
4083                // user is perhaps trying to swipe left/right across the page
4084
4085                if (
4086                    (deltaX < 0 && scrollLeft === i.contentWidth - i.containerWidth) ||
4087                    (deltaX > 0 && scrollLeft === 0)
4088                ) {
4089                    return true;
4090                }
4091            }
4092
4093            return true;
4094        }
4095
4096        function applyTouchMove(differenceX, differenceY) {
4097            element.scrollTop -= differenceY;
4098            element.scrollLeft -= differenceX;
4099
4100            updateGeometry(i);
4101        }
4102
4103        var startOffset = {};
4104        var startTime = 0;
4105        var speed = {};
4106        var easingLoop = null;
4107
4108        function getTouch(e) {
4109            if (e.targetTouches) {
4110                return e.targetTouches[0];
4111            } else {
4112                // Maybe IE pointer
4113                return e;
4114            }
4115        }
4116
4117        function shouldHandle(e) {
4118            if (e.pointerType && e.pointerType === 'pen' && e.buttons === 0) {
4119                return false;
4120            }
4121            if (e.targetTouches && e.targetTouches.length === 1) {
4122                return true;
4123            }
4124            if (
4125                e.pointerType &&
4126                e.pointerType !== 'mouse' &&
4127                e.pointerType !== e.MSPOINTER_TYPE_MOUSE
4128            ) {
4129                return true;
4130            }
4131            return false;
4132        }
4133
4134        function touchStart(e) {
4135            if (!shouldHandle(e)) {
4136                return;
4137            }
4138
4139            var touch = getTouch(e);
4140
4141            startOffset.pageX = touch.pageX;
4142            startOffset.pageY = touch.pageY;
4143
4144            startTime = new Date().getTime();
4145
4146            if (easingLoop !== null) {
4147                clearInterval(easingLoop);
4148            }
4149        }
4150
4151        function shouldBeConsumedByChild(target, deltaX, deltaY) {
4152            if (!element.contains(target)) {
4153                return false;
4154            }
4155
4156            var cursor = target;
4157
4158            while (cursor && cursor !== element) {
4159                if (cursor.classList.contains(cls.element.consuming)) {
4160                    return true;
4161                }
4162
4163                var style = get(cursor);
4164                var overflow = [style.overflow, style.overflowX, style.overflowY].join(
4165                    ''
4166                );
4167
4168                // if scrollable
4169                if (overflow.match(/(scroll|auto)/)) {
4170                    var maxScrollTop = cursor.scrollHeight - cursor.clientHeight;
4171                    if (maxScrollTop > 0) {
4172                        if (
4173                            !(cursor.scrollTop === 0 && deltaY > 0) &&
4174                            !(cursor.scrollTop === maxScrollTop && deltaY < 0)
4175                        ) {
4176                            return true;
4177                        }
4178                    }
4179                    var maxScrollLeft = cursor.scrollLeft - cursor.clientWidth;
4180                    if (maxScrollLeft > 0) {
4181                        if (
4182                            !(cursor.scrollLeft === 0 && deltaX < 0) &&
4183                            !(cursor.scrollLeft === maxScrollLeft && deltaX > 0)
4184                        ) {
4185                            return true;
4186                        }
4187                    }
4188                }
4189
4190                cursor = cursor.parentNode;
4191            }
4192
4193            return false;
4194        }
4195
4196        function touchMove(e) {
4197            if (shouldHandle(e)) {
4198                var touch = getTouch(e);
4199
4200                var currentOffset = { pageX: touch.pageX, pageY: touch.pageY };
4201
4202                var differenceX = currentOffset.pageX - startOffset.pageX;
4203                var differenceY = currentOffset.pageY - startOffset.pageY;
4204
4205                if (shouldBeConsumedByChild(e.target, differenceX, differenceY)) {
4206                    return;
4207                }
4208
4209                applyTouchMove(differenceX, differenceY);
4210                startOffset = currentOffset;
4211
4212                var currentTime = new Date().getTime();
4213
4214                var timeGap = currentTime - startTime;
4215                if (timeGap > 0) {
4216                    speed.x = differenceX / timeGap;
4217                    speed.y = differenceY / timeGap;
4218                    startTime = currentTime;
4219                }
4220
4221                if (shouldPrevent(differenceX, differenceY)) {
4222                    e.preventDefault();
4223                }
4224            }
4225        }
4226        function touchEnd() {
4227            if (i.settings.swipeEasing) {
4228                clearInterval(easingLoop);
4229                easingLoop = setInterval(function() {
4230                    if (i.isInitialized) {
4231                        clearInterval(easingLoop);
4232                        return;
4233                    }
4234
4235                    if (!speed.x && !speed.y) {
4236                        clearInterval(easingLoop);
4237                        return;
4238                    }
4239
4240                    if (Math.abs(speed.x) < 0.01 && Math.abs(speed.y) < 0.01) {
4241                        clearInterval(easingLoop);
4242                        return;
4243                    }
4244
4245                    applyTouchMove(speed.x * 30, speed.y * 30);
4246
4247                    speed.x *= 0.8;
4248                    speed.y *= 0.8;
4249                }, 10);
4250            }
4251        }
4252
4253        if (env.supportsTouch) {
4254            i.event.bind(element, 'touchstart', touchStart);
4255            i.event.bind(element, 'touchmove', touchMove);
4256            i.event.bind(element, 'touchend', touchEnd);
4257        } else if (env.supportsIePointer) {
4258            if (window.PointerEvent) {
4259                i.event.bind(element, 'pointerdown', touchStart);
4260                i.event.bind(element, 'pointermove', touchMove);
4261                i.event.bind(element, 'pointerup', touchEnd);
4262            } else if (window.MSPointerEvent) {
4263                i.event.bind(element, 'MSPointerDown', touchStart);
4264                i.event.bind(element, 'MSPointerMove', touchMove);
4265                i.event.bind(element, 'MSPointerUp', touchEnd);
4266            }
4267        }
4268    };
4269
4270    var defaultSettings = function () { return ({
4271        handlers: ['click-rail', 'drag-thumb', 'keyboard', 'wheel', 'touch'],
4272        maxScrollbarLength: null,
4273        minScrollbarLength: null,
4274        scrollingThreshold: 1000,
4275        scrollXMarginOffset: 0,
4276        scrollYMarginOffset: 0,
4277        suppressScrollX: false,
4278        suppressScrollY: false,
4279        swipeEasing: true,
4280        useBothWheelAxes: false,
4281        wheelPropagation: false,
4282        wheelSpeed: 1,
4283    }); };
4284
4285    var handlers = {
4286        'click-rail': clickRail,
4287        'drag-thumb': dragThumb,
4288        keyboard: keyboard,
4289        wheel: wheel,
4290        touch: touch,
4291    };
4292
4293    var PerfectScrollbar = function PerfectScrollbar(element, userSettings) {
4294        var this$1 = this;
4295        if ( userSettings === void 0 ) userSettings = {};
4296
4297        if (typeof element === 'string') {
4298            element = document.querySelector(element);
4299        }
4300
4301        if (!element || !element.nodeName) {
4302            throw new Error('no element is specified to initialize PerfectScrollbar');
4303        }
4304
4305        this.element = element;
4306
4307        element.classList.add(cls.main);
4308
4309        this.settings = defaultSettings();
4310        for (var key in userSettings) {
4311            this$1.settings[key] = userSettings[key];
4312        }
4313
4314        this.containerWidth = null;
4315        this.containerHeight = null;
4316        this.contentWidth = null;
4317        this.contentHeight = null;
4318
4319        var focus = function () { return element.classList.add(cls.state.focus); };
4320        var blur = function () { return element.classList.remove(cls.state.focus); };
4321
4322        this.isRtl = get(element).direction === 'rtl';
4323        this.isNegativeScroll = (function () {
4324            var originalScrollLeft = element.scrollLeft;
4325            var result = null;
4326            element.scrollLeft = -1;
4327            result = element.scrollLeft < 0;
4328            element.scrollLeft = originalScrollLeft;
4329            return result;
4330        })();
4331        this.negativeScrollAdjustment = this.isNegativeScroll
4332            ? element.scrollWidth - element.clientWidth
4333            : 0;
4334        this.event = new EventManager();
4335        this.ownerDocument = element.ownerDocument || document;
4336
4337        this.scrollbarXRail = div(cls.element.rail('x'));
4338        element.appendChild(this.scrollbarXRail);
4339        this.scrollbarX = div(cls.element.thumb('x'));
4340        this.scrollbarXRail.appendChild(this.scrollbarX);
4341        this.scrollbarX.setAttribute('tabindex', 0);
vendor: 5,472 bytes, lines 4342-4487
4342        this.event.bind(this.scrollbarX, 'focus', focus);
4343        this.event.bind(this.scrollbarX, 'blur', blur);
4344        this.scrollbarXActive = null;
4345        this.scrollbarXWidth = null;
4346        this.scrollbarXLeft = null;
4347        var railXStyle = get(this.scrollbarXRail);
4348        this.scrollbarXBottom = parseInt(railXStyle.bottom, 10);
4349        if (isNaN(this.scrollbarXBottom)) {
4350            this.isScrollbarXUsingBottom = false;
4351            this.scrollbarXTop = toInt(railXStyle.top);
4352        } else {
4353            this.isScrollbarXUsingBottom = true;
4354        }
4355        this.railBorderXWidth =
4356            toInt(railXStyle.borderLeftWidth) + toInt(railXStyle.borderRightWidth);
4357        // Set rail to display:block to calculate margins
4358        set(this.scrollbarXRail, { display: 'block' });
4359        this.railXMarginWidth =
4360            toInt(railXStyle.marginLeft) + toInt(railXStyle.marginRight);
4361        set(this.scrollbarXRail, { display: '' });
4362        this.railXWidth = null;
4363        this.railXRatio = null;
4364
4365        this.scrollbarYRail = div(cls.element.rail('y'));
4366        element.appendChild(this.scrollbarYRail);
4367        this.scrollbarY = div(cls.element.thumb('y'));
4368        this.scrollbarYRail.appendChild(this.scrollbarY);
4369        this.scrollbarY.setAttribute('tabindex', 0);
4370        this.event.bind(this.scrollbarY, 'focus', focus);
4371        this.event.bind(this.scrollbarY, 'blur', blur);
4372        this.scrollbarYActive = null;
4373        this.scrollbarYHeight = null;
4374        this.scrollbarYTop = null;
4375        var railYStyle = get(this.scrollbarYRail);
4376        this.scrollbarYRight = parseInt(railYStyle.right, 10);
4377        if (isNaN(this.scrollbarYRight)) {
4378            this.isScrollbarYUsingRight = false;
4379            this.scrollbarYLeft = toInt(railYStyle.left);
4380        } else {
4381            this.isScrollbarYUsingRight = true;
4382        }
4383        this.scrollbarYOuterWidth = this.isRtl ? outerWidth(this.scrollbarY) : null;
4384        this.railBorderYWidth =
4385            toInt(railYStyle.borderTopWidth) + toInt(railYStyle.borderBottomWidth);
4386        set(this.scrollbarYRail, { display: 'block' });
4387        this.railYMarginHeight =
4388            toInt(railYStyle.marginTop) + toInt(railYStyle.marginBottom);
4389        set(this.scrollbarYRail, { display: '' });
4390        this.railYHeight = null;
4391        this.railYRatio = null;
4392
4393        this.reach = {
4394            x:
4395                element.scrollLeft <= 0
4396                    ? 'start'
4397                    : element.scrollLeft >= this.contentWidth - this.containerWidth
4398                    ? 'end'
4399                    : null,
4400            y:
4401                element.scrollTop <= 0
4402                    ? 'start'
4403                    : element.scrollTop >= this.contentHeight - this.containerHeight
4404                    ? 'end'
4405                    : null,
4406        };
4407
4408        this.isAlive = true;
4409
4410        this.settings.handlers.forEach(function (handlerName) { return handlers[handlerName](this$1); });
4411
4412        this.lastScrollTop = element.scrollTop; // for onScroll only
4413        this.lastScrollLeft = element.scrollLeft; // for onScroll only
4414        this.event.bind(this.element, 'scroll', function (e) { return this$1.onScroll(e); });
4415        updateGeometry(this);
4416    };
4417
4418    PerfectScrollbar.prototype.update = function update () {
4419        if (!this.isAlive) {
4420            return;
4421        }
4422
4423        // Recalcuate negative scrollLeft adjustment
4424        this.negativeScrollAdjustment = this.isNegativeScroll
4425            ? this.element.scrollWidth - this.element.clientWidth
4426            : 0;
4427
4428        // Recalculate rail margins
4429        set(this.scrollbarXRail, { display: 'block' });
4430        set(this.scrollbarYRail, { display: 'block' });
4431        this.railXMarginWidth =
4432            toInt(get(this.scrollbarXRail).marginLeft) +
4433            toInt(get(this.scrollbarXRail).marginRight);
4434        this.railYMarginHeight =
4435            toInt(get(this.scrollbarYRail).marginTop) +
4436            toInt(get(this.scrollbarYRail).marginBottom);
4437
4438        // Hide scrollbars not to affect scrollWidth and scrollHeight
4439        set(this.scrollbarXRail, { display: 'none' });
4440        set(this.scrollbarYRail, { display: 'none' });
4441
4442        updateGeometry(this);
4443
4444        processScrollDiff(this, 'top', 0, false, true);
4445        processScrollDiff(this, 'left', 0, false, true);
4446
4447        set(this.scrollbarXRail, { display: '' });
4448        set(this.scrollbarYRail, { display: '' });
4449    };
4450
4451    PerfectScrollbar.prototype.onScroll = function onScroll (e) {
4452        if (!this.isAlive) {
4453            return;
4454        }
4455
4456        updateGeometry(this);
4457        processScrollDiff(this, 'top', this.element.scrollTop - this.lastScrollTop);
4458        processScrollDiff(
4459            this,
4460            'left',
4461            this.element.scrollLeft - this.lastScrollLeft
4462        );
4463
4464        this.lastScrollTop = this.element.scrollTop;
4465        this.lastScrollLeft = this.element.scrollLeft;
4466    };
4467
4468    PerfectScrollbar.prototype.destroy = function destroy () {
4469        if (!this.isAlive) {
4470            return;
4471        }
4472
4473        this.event.unbindAll();
4474        remove(this.scrollbarX);
4475        remove(this.scrollbarY);
4476        remove(this.scrollbarXRail);
4477        remove(this.scrollbarYRail);
4478        this.removePsClasses();
4479
4480        // unset elements
4481        this.element = null;
4482        this.scrollbarX = null;
4483        this.scrollbarY = null;
4484        this.scrollbarXRail = null;
4485        this.scrollbarYRail = null;
4486
4487        this.isAlive = false;
4488    };
4489
4490    PerfectScrollbar.prototype.removePsClasses = function removePsClasses () {
4491        this.element.className = this.element.className
4492            .split(' ')
4493            .filter(function (name) { return !name.match(/^ps([-_].+|)$/); })
4494            .join(' ');
4495    };
4496
4497    return PerfectScrollbar;
4498
4499})));
4500/**
4501 * END: perfect-scrollbar.js
4502 */
4503},{}]},{},[2]);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.