PageSourceSearch

https://altavistava.gov/_assets_/plugins/tiny-slider-master/dist/tiny-slider.js

js altavistava.gov collected 2026-09-26 07:30:26 UTC 100,151 bytes, 3,194 lines download raw bytes

vendor: 100,151 bytes, lines 1-3194
1var tns = (function (){
2var win = window;
3
4var raf = win.requestAnimationFrame
5  || win.webkitRequestAnimationFrame
6  || win.mozRequestAnimationFrame
7  || win.msRequestAnimationFrame
8  || function(cb) { return setTimeout(cb, 16); };
9
10var win$1 = window;
11
12var caf = win$1.cancelAnimationFrame
13  || win$1.mozCancelAnimationFrame
14  || function(id){ clearTimeout(id); };
15
16function extend() {
17  var obj, name, copy,
18      target = arguments[0] || {},
19      i = 1,
20      length = arguments.length;
21
22  for (; i < length; i++) {
23    if ((obj = arguments[i]) !== null) {
24      for (name in obj) {
25        copy = obj[name];
26
27        if (target === copy) {
28          continue;
29        } else if (copy !== undefined) {
30          target[name] = copy;
31        }
32      }
33    }
34  }
35  return target;
36}
37
38function checkStorageValue (value) {
39  return ['true', 'false'].indexOf(value) >= 0 ? JSON.parse(value) : value;
40}
41
42function setLocalStorage(storage, key, value, access) {
43  if (access) {
44    try { storage.setItem(key, value); } catch (e) {}
45  }
46  return value;
47}
48
49function getSlideId() {
50  var id = window.tnsId;
51  window.tnsId = !id ? 1 : id + 1;
52  
53  return 'tns' + window.tnsId;
54}
55
56function getBody () {
57  var doc = document,
58      body = doc.body;
59
60  if (!body) {
61    body = doc.createElement('body');
62    body.fake = true;
63  }
64
65  return body;
66}
67
68var docElement = document.documentElement;
69
70function setFakeBody (body) {
71  var docOverflow = '';
72  if (body.fake) {
73    docOverflow = docElement.style.overflow;
74    //avoid crashing IE8, if background image is used
75    body.style.background = '';
76    //Safari 5.13/5.1.4 OSX stops loading if ::-webkit-scrollbar is used and scrollbars are visible
77    body.style.overflow = docElement.style.overflow = 'hidden';
78    docElement.appendChild(body);
79  }
80
81  return docOverflow;
82}
83
84function resetFakeBody (body, docOverflow) {
85  if (body.fake) {
86    body.remove();
87    docElement.style.overflow = docOverflow;
88    // Trigger layout so kinetic scrolling isn't disabled in iOS6+
89    // eslint-disable-next-line
90    docElement.offsetHeight;
91  }
92}
93
94// get css-calc 
95
96function calc() {
97  var doc = document, 
98      body = getBody(),
99      docOverflow = setFakeBody(body),
100      div = doc.createElement('div'), 
101      result = false;
102
103  body.appendChild(div);
104  try {
105    var str = '(10px * 10)',
106        vals = ['calc' + str, '-moz-calc' + str, '-webkit-calc' + str],
107        val;
108    for (var i = 0; i < 3; i++) {
109      val = vals[i];
110      div.style.width = val;
111      if (div.offsetWidth === 100) { 
112        result = val.replace(str, ''); 
113        break;
114      }
115    }
116  } catch (e) {}
117  
118  body.fake ? resetFakeBody(body, docOverflow) : div.remove();
119
120  return result;
121}
122
123// get subpixel support value
124
125function percentageLayout() {
126  // check subpixel layout supporting
127  var doc = document,
128      body = getBody(),
129      docOverflow = setFakeBody(body),
130      wrapper = doc.createElement('div'),
131      outer = doc.createElement('div'),
132      str = '',
133      count = 70,
134      perPage = 3,
135      supported = false;
136
137  wrapper.className = "tns-t-subp2";
138  outer.className = "tns-t-ct";
139
140  for (var i = 0; i < count; i++) {
141    str += '<div></div>';
142  }
143
144  outer.innerHTML = str;
145  wrapper.appendChild(outer);
146  body.appendChild(wrapper);
147
148  supported = Math.abs(wrapper.getBoundingClientRect().left - outer.children[count - perPage].getBoundingClientRect().left) < 2;
149
150  body.fake ? resetFakeBody(body, docOverflow) : wrapper.remove();
151
152  return supported;
153}
154
155function mediaquerySupport () {
156  var doc = document,
157      body = getBody(),
158      docOverflow = setFakeBody(body),
159      div = doc.createElement('div'),
160      style = doc.createElement('style'),
161      rule = '@media all and (min-width:1px){.tns-mq-test{position:absolute}}',
162      position;
163
164  style.type = 'text/css';
165  div.className = 'tns-mq-test';
166
167  body.appendChild(style);
168  body.appendChild(div);
169
170  if (style.styleSheet) {
171    style.styleSheet.cssText = rule;
172  } else {
173    style.appendChild(doc.createTextNode(rule));
174  }
175
176  position = window.getComputedStyle ? window.getComputedStyle(div).position : div.currentStyle['position'];
177
178  body.fake ? resetFakeBody(body, docOverflow) : div.remove();
179
180  return position === "absolute";
181}
182
183// create and append style sheet
184function createStyleSheet (media) {
185  // Create the <style> tag
186  var style = document.createElement("style");
187  // style.setAttribute("type", "text/css");
188
189  // Add a media (and/or media query) here if you'd like!
190  // style.setAttribute("media", "screen")
191  // style.setAttribute("media", "only screen and (max-width : 1024px)")
192  if (media) { style.setAttribute("media", media); }
193
194  // WebKit hack :(
195  // style.appendChild(document.createTextNode(""));
196
197  // Add the <style> element to the page
198  document.querySelector('head').appendChild(style);
199
200  return style.sheet ? style.sheet : style.styleSheet;
201}
202
203// cross browsers addRule method
204function addCSSRule(sheet, selector, rules, index) {
205  // return raf(function() {
206    'insertRule' in sheet ?
207      sheet.insertRule(selector + '{' + rules + '}', index) :
208      sheet.addRule(selector, rules, index);
209  // });
210}
211
212// cross browsers addRule method
213function removeCSSRule(sheet, index) {
214  // return raf(function() {
215    'deleteRule' in sheet ?
216      sheet.deleteRule(index) :
217      sheet.removeRule(index);
218  // });
219}
220
221function getCssRulesLength(sheet) {
222  var rule = ('insertRule' in sheet) ? sheet.cssRules : sheet.rules;
223  return rule.length;
224}
225
226function toDegree (y, x) {
227  return Math.atan2(y, x) * (180 / Math.PI);
228}
229
230function getTouchDirection(angle, range) {
231  var direction = false,
232      gap = Math.abs(90 - Math.abs(angle));
233      
234  if (gap >= 90 - range) {
235    direction = 'horizontal';
236  } else if (gap <= range) {
237    direction = 'vertical';
238  }
239
240  return direction;
241}
242
243// https://toddmotto.com/ditch-the-array-foreach-call-nodelist-hack/
244function forEach (arr, callback, scope) {
245  for (var i = 0, l = arr.length; i < l; i++) {
246    callback.call(scope, arr[i], i);
247  }
248}
249
250var classListSupport = 'classList' in document.createElement('_');
251
252var hasClass = classListSupport ?
253    function (el, str) { return el.classList.contains(str); } :
254    function (el, str) { return el.className.indexOf(str) >= 0; };
255
256var addClass = classListSupport ?
257    function (el, str) {
258      if (!hasClass(el,  str)) { el.classList.add(str); }
259    } :
260    function (el, str) {
261      if (!hasClass(el,  str)) { el.className += ' ' + str; }
262    };
263
264var removeClass = classListSupport ?
265    function (el, str) {
266      if (hasClass(el,  str)) { el.classList.remove(str); }
267    } :
268    function (el, str) {
269      if (hasClass(el, str)) { el.className = el.className.replace(str, ''); }
270    };
271
272function hasAttr(el, attr) {
273  return el.hasAttribute(attr);
274}
275
276function getAttr(el, attr) {
277  return el.getAttribute(attr);
278}
279
280function isNodeList(el) {
281  // Only NodeList has the "item()" function
282  return typeof el.item !== "undefined"; 
283}
284
285function setAttrs(els, attrs) {
286  els = (isNodeList(els) || els instanceof Array) ? els : [els];
287  if (Object.prototype.toString.call(attrs) !== '[object Object]') { return; }
288
289  for (var i = els.length; i--;) {
290    for(var key in attrs) {
291      els[i].setAttribute(key, attrs[key]);
292    }
293  }
294}
295
296function removeAttrs(els, attrs) {
297  els = (isNodeList(els) || els instanceof Array) ? els : [els];
298  attrs = (attrs instanceof Array) ? attrs : [attrs];
299
300  var attrLength = attrs.length;
301  for (var i = els.length; i--;) {
302    for (var j = attrLength; j--;) {
303      els[i].removeAttribute(attrs[j]);
304    }
305  }
306}
307
308function arrayFromNodeList (nl) {
309  var arr = [];
310  for (var i = 0, l = nl.length; i < l; i++) {
311    arr.push(nl[i]);
312  }
313  return arr;
314}
315
316function hideElement(el, forceHide) {
317  if (el.style.display !== 'none') { el.style.display = 'none'; }
318}
319
320function showElement(el, forceHide) {
321  if (el.style.display === 'none') { el.style.display = ''; }
322}
323
324function isVisible(el) {
325  return window.getComputedStyle(el).display !== 'none';
326}
327
328function whichProperty(props){
329  if (typeof props === 'string') {
330    var arr = [props],
331        Props = props.charAt(0).toUpperCase() + props.substr(1),
332        prefixes = ['Webkit', 'Moz', 'ms', 'O'];
333        
334    prefixes.forEach(function(prefix) {
335      if (prefix !== 'ms' || props === 'transform') {
336        arr.push(prefix + Props);
337      }
338    });
339
340    props = arr;
341  }
342
343  var el = document.createElement('fakeelement'),
344      len = props.length;
345  for(var i = 0; i < props.length; i++){
346    var prop = props[i];
347    if( el.style[prop] !== undefined ){ return prop; }
348  }
349
350  return false; // explicit for ie9-
351}
352
353function has3DTransforms(tf){
354  if (!tf) { return false; }
355  if (!window.getComputedStyle) { return false; }
356  
357  var doc = document,
358      body = getBody(),
359      docOverflow = setFakeBody(body),
360      el = doc.createElement('p'),
361      has3d,
362      cssTF = tf.length > 9 ? '-' + tf.slice(0, -9).toLowerCase() + '-' : '';
363
364  cssTF += 'transform';
365
366  // Add it to the body to get the computed style
367  body.insertBefore(el, null);
368
369  el.style[tf] = 'translate3d(1px,1px,1px)';
370  has3d = window.getComputedStyle(el).getPropertyValue(cssTF);
371
372  body.fake ? resetFakeBody(body, docOverflow) : el.remove();
373
374  return (has3d !== undefined && has3d.length > 0 && has3d !== "none");
375}
376
377// get transitionend, animationend based on transitionDuration
378// @propin: string
379// @propOut: string, first-letter uppercase
380// Usage: getEndProperty('WebkitTransitionDuration', 'Transition') => webkitTransitionEnd
381function getEndProperty(propIn, propOut) {
382  var endProp = false;
383  if (/^Webkit/.test(propIn)) {
384    endProp = 'webkit' + propOut + 'End';
385  } else if (/^O/.test(propIn)) {
386    endProp = 'o' + propOut + 'End';
387  } else if (propIn) {
388    endProp = propOut.toLowerCase() + 'end';
389  }
390  return endProp;
391}
392
393// Test via a getter in the options object to see if the passive property is accessed
394var supportsPassive = false;
395try {
396  var opts = Object.defineProperty({}, 'passive', {
397    get: function() {
398      supportsPassive = true;
399    }
400  });
401  window.addEventListener("test", null, opts);
402} catch (e) {}
403var passiveOption = supportsPassive ? { passive: true } : false;
404
405function addEvents(el, obj, preventScrolling) {
406  for (var prop in obj) {
407    var option = ['touchstart', 'touchmove'].indexOf(prop) >= 0 && !preventScrolling ? passiveOption : false;
408    el.addEventListener(prop, obj[prop], option);
409  }
410}
411
412function removeEvents(el, obj) {
413  for (var prop in obj) {
414    var option = ['touchstart', 'touchmove'].indexOf(prop) >= 0 ? passiveOption : false;
415    el.removeEventListener(prop, obj[prop], option);
416  }
417}
418
419function Events() {
420  return {
421    topics: {},
422    on: function (eventName, fn) {
423      this.topics[eventName] = this.topics[eventName] || [];
424      this.topics[eventName].push(fn);
425    },
426    off: function(eventName, fn) {
427      if (this.topics[eventName]) {
428        for (var i = 0; i < this.topics[eventName].length; i++) {
429          if (this.topics[eventName][i] === fn) {
430            this.topics[eventName].splice(i, 1);
431            break;
432          }
433        }
434      }
435    },
436    emit: function (eventName, data) {
437      data.type = eventName;
438      if (this.topics[eventName]) {
439        this.topics[eventName].forEach(function(fn) {
440          fn(data, eventName);
441        });
442      }
443    }
444  };
445}
446
447function jsTransform(element, attr, prefix, postfix, to, duration, callback) {
448  var tick = Math.min(duration, 10),
449      unit = (to.indexOf('%') >= 0) ? '%' : 'px',
450      to = to.replace(unit, ''),
451      from = Number(element.style[attr].replace(prefix, '').replace(postfix, '').replace(unit, '')),
452      positionTick = (to - from) / duration * tick,
453      running;
454
455  setTimeout(moveElement, tick);
456  function moveElement() {
457    duration -= tick;
458    from += positionTick;
459    element.style[attr] = prefix + from + unit + postfix;
460    if (duration > 0) { 
461      setTimeout(moveElement, tick); 
462    } else {
463      callback();
464    }
465  }
466}
467
468// Object.keys
469if (!Object.keys) {
470  Object.keys = function(object) {
471    var keys = [];
472    for (var name in object) {
473      if (Object.prototype.hasOwnProperty.call(object, name)) {
474        keys.push(name);
475      }
476    }
477    return keys;
478  };
479}
480
481// ChildNode.remove
482if(!("remove" in Element.prototype)){
483  Element.prototype.remove = function(){
484    if(this.parentNode) {
485      this.parentNode.removeChild(this);
486    }
487  };
488}
489
490var tns = function(options) {
491  options = extend({
492    container: '.slider',
493    mode: 'carousel',
494    axis: 'horizontal',
495    items: 1,
496    gutter: 0,
497    edgePadding: 0,
498    fixedWidth: false,
499    autoWidth: false,
500    viewportMax: false,
501    slideBy: 1,
502    center: false,
503    controls: true,
504    controlsPosition: 'top',
505    controlsText: ['prev', 'next'],
506    controlsContainer: false,
507    prevButton: false,
508    nextButton: false,
509    nav: true,
510    navPosition: 'top',
511    navContainer: false,
512    navAsThumbnails: false,
513    arrowKeys: false,
514    speed: 300,
515    autoplay: false,
516    autoplayPosition: 'top',
517    autoplayTimeout: 5000,
518    autoplayDirection: 'forward',
519    autoplayText: ['start', 'stop'],
520    autoplayHoverPause: false,
521    autoplayButton: false,
522    autoplayButtonOutput: true,
523    autoplayResetOnVisibility: true,
524    animateIn: 'tns-fadeIn',
525    animateOut: 'tns-fadeOut',
526    animateNormal: 'tns-normal',
527    animateDelay: false,
528    loop: true,
529    rewind: false,
530    autoHeight: false,
531    responsive: false,
532    lazyload: false,
533    lazyloadSelector: '.tns-lazy-img',
534    touch: true,
535    mouseDrag: false,
536    swipeAngle: 15,
537    nested: false,
538    preventActionWhenRunning: false,
539    preventScrollOnTouch: false,
540    freezable: true,
541    onInit: false,
542    useLocalStorage: true
543  }, options || {});
544
545  var doc = document,
546      win = window,
547      KEYS = {
548        ENTER: 13,
549        SPACE: 32,
550        LEFT: 37,
551        RIGHT: 39
552      },
553      tnsStorage = {},
554      localStorageAccess = options.useLocalStorage;
555
556  if (localStorageAccess) {
557    // check browser version and local storage access
558    var browserInfo = navigator.userAgent;
559    var uid = new Date;
560
561    try {
562      tnsStorage = win.localStorage;
563      if (tnsStorage) {
564        tnsStorage.setItem(uid, uid);
565        localStorageAccess = tnsStorage.getItem(uid) == uid;
566        tnsStorage.removeItem(uid);
567      } else {
568        localStorageAccess = false;
569      }
570      if (!localStorageAccess) { tnsStorage = {}; }
571    } catch(e) {
572      localStorageAccess = false;
573    }
574
575    if (localStorageAccess) {
576      // remove storage when browser version changes
577      if (tnsStorage['tnsApp'] && tnsStorage['tnsApp'] !== browserInfo) {
578        ['tC', 'tPL', 'tMQ', 'tTf', 't3D', 'tTDu', 'tTDe', 'tADu', 'tADe', 'tTE', 'tAE'].forEach(function(item) { tnsStorage.removeItem(item); });
579      }
580      // update browserInfo
581      localStorage['tnsApp'] = browserInfo;
582    }
583  }
584
585  var CALC = tnsStorage['tC'] ? checkStorageValue(tnsStorage['tC']) : setLocalStorage(tnsStorage, 'tC', calc(), localStorageAccess),
586      PERCENTAGELAYOUT = tnsStorage['tPL'] ? checkStorageValue(tnsStorage['tPL']) : setLocalStorage(tnsStorage, 'tPL', percentageLayout(), localStorageAccess),
587      CSSMQ = tnsStorage['tMQ'] ? checkStorageValue(tnsStorage['tMQ']) : setLocalStorage(tnsStorage, 'tMQ', mediaquerySupport(), localStorageAccess),
588      TRANSFORM = tnsStorage['tTf'] ? checkStorageValue(tnsStorage['tTf']) : setLocalStorage(tnsStorage, 'tTf', whichProperty('transform'), localStorageAccess),
589      HAS3DTRANSFORMS = tnsStorage['t3D'] ? checkStorageValue(tnsStorage['t3D']) : setLocalStorage(tnsStorage, 't3D', has3DTransforms(TRANSFORM), localStorageAccess),
590      TRANSITIONDURATION = tnsStorage['tTDu'] ? checkStorageValue(tnsStorage['tTDu']) : setLocalStorage(tnsStorage, 'tTDu', whichProperty('transitionDuration'), localStorageAccess),
591      TRANSITIONDELAY = tnsStorage['tTDe'] ? checkStorageValue(tnsStorage['tTDe']) : setLocalStorage(tnsStorage, 'tTDe', whichProperty('transitionDelay'), localStorageAccess),
592      ANIMATIONDURATION = tnsStorage['tADu'] ? checkStorageValue(tnsStorage['tADu']) : setLocalStorage(tnsStorage, 'tADu', whichProperty('animationDuration'), localStorageAccess),
593      ANIMATIONDELAY = tnsStorage['tADe'] ? checkStorageValue(tnsStorage['tADe']) : setLocalStorage(tnsStorage, 'tADe', whichProperty('animationDelay'), localStorageAccess),
594      TRANSITIONEND = tnsStorage['tTE'] ? checkStorageValue(tnsStorage['tTE']) : setLocalStorage(tnsStorage, 'tTE', getEndProperty(TRANSITIONDURATION, 'Transition'), localStorageAccess),
595      ANIMATIONEND = tnsStorage['tAE'] ? checkStorageValue(tnsStorage['tAE']) : setLocalStorage(tnsStorage, 'tAE', getEndProperty(ANIMATIONDURATION, 'Animation'), localStorageAccess);
596
597  // get element nodes from selectors
598  var supportConsoleWarn = win.console && typeof win.console.warn === "function",
599      tnsList = ['container', 'controlsContainer', 'prevButton', 'nextButton', 'navContainer', 'autoplayButton'],
600      optionsElements = {};
601
602  tnsList.forEach(function(item) {
603    if (typeof options[item] === 'string') {
604      var str = options[item],
605          el = doc.querySelector(str);
606      optionsElements[item] = str;
607
608      if (el && el.nodeName) {
609        options[item] = el;
610      } else {
611        if (supportConsoleWarn) { console.warn('Can\'t find', options[item]); }
612        return;
613      }
614    }
615  });
616
617  // make sure at least 1 slide
618  if (options.container.children.length < 1) {
619    if (supportConsoleWarn) { console.warn('No slides found in', options.container); }
620    return;
621   }
622
623  // update options
624  var responsive = options.responsive,
625      nested = options.nested,
626      carousel = options.mode === 'carousel' ? true : false;
627
628  if (responsive) {
629    // apply responsive[0] to options and remove it
630    if (0 in responsive) {
631      options = extend(options, responsive[0]);
632      delete responsive[0];
633    }
634
635    var responsiveTem = {};
636    for (var key in responsive) {
637      var val = responsive[key];
638      // update responsive
639      // from: 300: 2
640      // to:
641      //   300: {
642      //     items: 2
643      //   }
644      val = typeof val === 'number' ? {items: val} : val;
645      responsiveTem[key] = val;
646    }
647    responsive = responsiveTem;
648    responsiveTem = null;
649  }
650
651  // update options
652  function updateOptions (obj) {
653    for (var key in obj) {
654      if (!carousel) {
655        if (key === 'slideBy') { obj[key] = 'page'; }
656        if (key === 'edgePadding') { obj[key] = false; }
657        if (key === 'autoHeight') { obj[key] = false; }
658      }
659
660      // update responsive options
661      if (key === 'responsive') { updateOptions(obj[key]); }
662    }
663  }
664  if (!carousel) { updateOptions(options); }
665
666
667  // === define and set variables ===
668  if (!carousel) {
669    options.axis = 'horizontal';
670    options.slideBy = 'page';
671    options.edgePadding = false;
672
673    var animateIn = options.animateIn,
674        animateOut = options.animateOut,
675        animateDelay = options.animateDelay,
676        animateNormal = options.animateNormal;
677  }
678
679  var horizontal = options.axis === 'horizontal' ? true : false,
680      outerWrapper = doc.createElement('div'),
681      innerWrapper = doc.createElement('div'),
682      middleWrapper,
683      container = options.container,
684      containerParent = container.parentNode,
685      containerHTML = container.outerHTML,
686      slideItems = container.children,
687      slideCount = slideItems.length,
688      breakpointZone,
689      windowWidth = getWindowWidth(),
690      isOn = false;
691  if (responsive) { setBreakpointZone(); }
692  if (carousel) { container.className += ' tns-vpfix'; }
693
694  // fixedWidth: viewport > rightBoundary > indexMax
695  var autoWidth = options.autoWidth,
696      fixedWidth = getOption('fixedWidth'),
697      edgePadding = getOption('edgePadding'),
698      gutter = getOption('gutter'),
699      viewport = getViewportWidth(),
700      center = getOption('center'),
701      items = !autoWidth ? Math.floor(getOption('items')) : 1,
702      slideBy = getOption('slideBy'),
703      viewportMax = options.viewportMax || options.fixedWidthViewportWidth,
704      arrowKeys = getOption('arrowKeys'),
705      speed = getOption('speed'),
706      rewind = options.rewind,
707      loop = rewind ? false : options.loop,
708      autoHeight = getOption('autoHeight'),
709      controls = getOption('controls'),
710      controlsText = getOption('controlsText'),
711      nav = getOption('nav'),
712      touch = getOption('touch'),
713      mouseDrag = getOption('mouseDrag'),
714      autoplay = getOption('autoplay'),
715      autoplayTimeout = getOption('autoplayTimeout'),
716      autoplayText = getOption('autoplayText'),
717      autoplayHoverPause = getOption('autoplayHoverPause'),
718      autoplayResetOnVisibility = getOption('autoplayResetOnVisibility'),
719      sheet = createStyleSheet(),
720      lazyload = options.lazyload,
721      lazyloadSelector = options.lazyloadSelector,
722      slidePositions, // collection of slide positions
723      slideItemsOut = [],
724      cloneCount = loop ? getCloneCountForLoop() : 0,
725      slideCountNew = !carousel ? slideCount + cloneCount : slideCount + cloneCount * 2,
726      hasRightDeadZone = (fixedWidth || autoWidth) && !loop ? true : false,
727      rightBoundary = fixedWidth ? getRightBoundary() : null,
728      updateIndexBeforeTransform = (!carousel || !loop) ? true : false,
729      // transform
730      transformAttr = horizontal ? 'left' : 'top',
731      transformPrefix = '',
732      transformPostfix = '',
733      // index
734      getIndexMax = (function () {
735        if (fixedWidth) {
736          return function() { return center && !loop ? slideCount - 1 : Math.ceil(- rightBoundary / (fixedWidth + gutter)); };
737        } else if (autoWidth) {
738          return function() {
739            for (var i = slideCountNew; i--;) {
740              if (slidePositions[i] >= - rightBoundary) { return i; }
741            }
742          };
743        } else {
744          return function() {
745            if (center && carousel && !loop) {
746              return slideCount - 1;
747            } else {
748              return loop || carousel ? Math.max(0, slideCountNew - Math.ceil(items)) : slideCountNew - 1;
749            }
750          };
751        }
752      })(),
753      index = getStartIndex(getOption('startIndex')),
754      indexCached = index,
755      displayIndex = getCurrentSlide(),
756      indexMin = 0,
757      indexMax = !autoWidth ? getIndexMax() : null,
758      // resize
759      resizeTimer,
760      preventActionWhenRunning = options.preventActionWhenRunning,
761      swipeAngle = options.swipeAngle,
762      moveDirectionExpected = swipeAngle ? '?' : true,
763      running = false,
764      onInit = options.onInit,
765      events = new Events(),
766      // id, class
767      newContainerClasses = ' tns-slider tns-' + options.mode,
768      slideId = container.id || getSlideId(),
769      disable = getOption('disable'),
770      disabled = false,
771      freezable = options.freezable,
772      freeze = freezable && !autoWidth ? getFreeze() : false,
773      frozen = false,
774      controlsEvents = {
775        'click': onControlsClick,
776        'keydown': onControlsKeydown
777      },
778      navEvents = {
779        'click': onNavClick,
780        'keydown': onNavKeydown
781      },
782      hoverEvents = {
783        'mouseover': mouseoverPause,
784        'mouseout': mouseoutRestart
785      },
786      visibilityEvent = {'visibilitychange': onVisibilityChange},
787      docmentKeydownEvent = {'keydown': onDocumentKeydown},
788      touchEvents = {
789        'touchstart': onPanStart,
790        'touchmove': onPanMove,
791        'touchend': onPanEnd,
792        'touchcancel': onPanEnd
793      }, dragEvents = {
794        'mousedown': onPanStart,
795        'mousemove': onPanMove,
796        'mouseup': onPanEnd,
797        'mouseleave': onPanEnd
798      },
799      hasControls = hasOption('controls'),
800      hasNav = hasOption('nav'),
801      navAsThumbnails = autoWidth ? true : options.navAsThumbnails,
802      hasAutoplay = hasOption('autoplay'),
803      hasTouch = hasOption('touch'),
804      hasMouseDrag = hasOption('mouseDrag'),
805      slideActiveClass = 'tns-slide-active',
806      imgCompleteClass = 'tns-complete',
807      imgEvents = {
808        'load': onImgLoaded,
809        'error': onImgFailed
810      },
811      imgsComplete,
812      liveregionCurrent,
813      preventScroll = options.preventScrollOnTouch === 'force' ? true : false;
814
815  // controls
816  if (hasControls) {
817    var controlsContainer = options.controlsContainer,
818        controlsContainerHTML = options.controlsContainer ? options.controlsContainer.outerHTML : '',
819        prevButton = options.prevButton,
820        nextButton = options.nextButton,
821        prevButtonHTML = options.prevButton ? options.prevButton.outerHTML : '',
822        nextButtonHTML = options.nextButton ? options.nextButton.outerHTML : '',
823        prevIsButton,
824        nextIsButton;
825  }
826
827  // nav
828  if (hasNav) {
829    var navContainer = options.navContainer,
830        navContainerHTML = options.navContainer ? options.navContainer.outerHTML : '',
831        navItems,
832        pages = autoWidth ? slideCount : getPages(),
833        pagesCached = 0,
834        navClicked = -1,
835        navCurrentIndex = getCurrentNavIndex(),
836        navCurrentIndexCached = navCurrentIndex,
837        navActiveClass = 'tns-nav-active',
838        navStr = 'Carousel Page ',
839        navStrCurrent = ' (Current Slide)';
840  }
841
842  // autoplay
843  if (hasAutoplay) {
844    var autoplayDirection = options.autoplayDirection === 'forward' ? 1 : -1,
845        autoplayButton = options.autoplayButton,
846        autoplayButtonHTML = options.autoplayButton ? options.autoplayButton.outerHTML : '',
847        autoplayHtmlStrings = ['<span class=\'tns-visually-hidden\'>', ' animation</span>'],
848        autoplayTimer,
849        animating,
850        autoplayHoverPaused,
851        autoplayUserPaused,
852        autoplayVisibilityPaused;
853  }
854
855  if (hasTouch || hasMouseDrag) {
856    var initPosition = {},
857        lastPosition = {},
858        translateInit,
859        disX,
860        disY,
861        panStart = false,
862        rafIndex,
863        getDist = horizontal ?
864          function(a, b) { return a.x - b.x; } :
865          function(a, b) { return a.y - b.y; };
866  }
867
868  // disable slider when slidecount <= items
869  if (!autoWidth) { resetVariblesWhenDisable(disable || freeze); }
870
871  if (TRANSFORM) {
872    transformAttr = TRANSFORM;
873    transformPrefix = 'translate';
874
875    if (HAS3DTRANSFORMS) {
876      transformPrefix += horizontal ? '3d(' : '3d(0px, ';
877      transformPostfix = horizontal ? ', 0px, 0px)' : ', 0px)';
878    } else {
879      transformPrefix += horizontal ? 'X(' : 'Y(';
880      transformPostfix = ')';
881    }
882
883  }
884
885  if (carousel) { container.className = container.className.replace('tns-vpfix', ''); }
886  initStructure();
887  initSheet();
888  initSliderTransform();
889
890  // === COMMON FUNCTIONS === //
891  function resetVariblesWhenDisable (condition) {
892    if (condition) {
893      controls = nav = touch = mouseDrag = arrowKeys = autoplay = autoplayHoverPause = autoplayResetOnVisibility = false;
894    }
895  }
896
897  function getCurrentSlide () {
898    var tem = carousel ? index - cloneCount : index;
899    while (tem < 0) { tem += slideCount; }
900    return tem%slideCount + 1;
901  }
902
903  function getStartIndex (ind) {
904    ind = ind ? Math.max(0, Math.min(loop ? slideCount - 1 : slideCount - items, ind)) : 0;
905    return carousel ? ind + cloneCount : ind;
906  }
907
908  function getAbsIndex (i) {
909    if (i == null) { i = index; }
910
911    if (carousel) { i -= cloneCount; }
912    while (i < 0) { i += slideCount; }
913
914    return Math.floor(i%slideCount);
915  }
916
917  function getCurrentNavIndex () {
918    var absIndex = getAbsIndex(),
919        result;
920
921    result = navAsThumbnails ? absIndex :
922      fixedWidth || autoWidth ? Math.ceil((absIndex + 1) * pages / slideCount - 1) :
923          Math.floor(absIndex / items);
924
925    // set active nav to the last one when reaches the right edge
926    if (!loop && carousel && index === indexMax) { result = pages - 1; }
927
928    return result;
929  }
930
931  function getItemsMax () {
932    // fixedWidth or autoWidth while viewportMax is not available
933    if (autoWidth || (fixedWidth && !viewportMax)) {
934      return slideCount - 1;
935    // most cases
936    } else {
937      var str = fixedWidth ? 'fixedWidth' : 'items',
938          arr = [];
939
940      if (fixedWidth || options[str] < slideCount) { arr.push(options[str]); }
941
942      if (responsive) {
943        for (var bp in responsive) {
944          var tem = responsive[bp][str];
945          if (tem && (fixedWidth || tem < slideCount)) { arr.push(tem); }
946        }
947      }
948
949      if (!arr.length) { arr.push(0); }
950
951      return Math.ceil(fixedWidth ? viewportMax / Math.min.apply(null, arr) : Math.max.apply(null, arr));
952    }
953  }
954
955  function getCloneCountForLoop () {
956    var itemsMax = getItemsMax(),
957        result = carousel ? Math.ceil((itemsMax * 5 - slideCount)/2) : (itemsMax * 4 - slideCount);
958    result = Math.max(itemsMax, result);
959
960    return hasOption('edgePadding') ? result + 1 : result;
961  }
962
963  function getWindowWidth () {
964    return win.innerWidth || doc.documentElement.clientWidth || doc.body.clientWidth;
965  }
966
967  function getInsertPosition (pos) {
968    return pos === 'top' ? 'afterbegin' : 'beforeend';
969  }
970
971  function getClientWidth (el) {
972    if (el == null) { return; }
973    var div = doc.createElement('div'), rect, width;
974    el.appendChild(div);
975    rect = div.getBoundingClientRect();
976    width = rect.right - rect.left;
977    div.remove();
978    return width || getClientWidth(el.parentNode);
979  }
980
981  function getViewportWidth () {
982    var gap = edgePadding ? edgePadding * 2 - gutter : 0;
983    return getClientWidth(containerParent) - gap;
984  }
985
986  function hasOption (item) {
987    if (options[item]) {
988      return true;
989    } else {
990      if (responsive) {
991        for (var bp in responsive) {
992          if (responsive[bp][item]) { return true; }
993        }
994      }
995      return false;
996    }
997  }
998
999  // get option:
1000  // fixed width: viewport, fixedWidth, gutter => items
1001  // others: window width => all variables
1002  // all: items => slideBy
1003  function getOption (item, ww) {
1004    if (ww == null) { ww = windowWidth; }
1005
1006    if (item === 'items' && fixedWidth) {
1007      return Math.floor((viewport + gutter) / (fixedWidth + gutter)) || 1;
1008
1009    } else {
1010      var result = options[item];
1011
1012      if (responsive) {
1013        for (var bp in responsive) {
1014          // bp: convert string to number
1015          if (ww >= parseInt(bp)) {
1016            if (item in responsive[bp]) { result = responsive[bp][item]; }
1017          }
1018        }
1019      }
1020
1021      if (item === 'slideBy' && result === 'page') { result = getOption('items'); }
1022      if (!carousel && (item === 'slideBy' || item === 'items')) { result = Math.floor(result); }
1023
1024      return result;
1025    }
1026  }
1027
1028  function getSlideMarginLeft (i) {
1029    return CALC ?
1030      CALC + '(' + i * 100 + '% / ' + slideCountNew + ')' :
1031      i * 100 / slideCountNew + '%';
1032  }
1033
1034  function getInnerWrapperStyles (edgePaddingTem, gutterTem, fixedWidthTem, speedTem, autoHeightBP) {
1035    var str = '';
1036
1037    if (edgePaddingTem !== undefined) {
1038      var gap = edgePaddingTem;
1039      if (gutterTem) { gap -= gutterTem; }
1040      str = horizontal ?
1041        'margin: 0 ' + gap + 'px 0 ' + edgePaddingTem + 'px;' :
1042        'margin: ' + edgePaddingTem + 'px 0 ' + gap + 'px 0;';
1043    } else if (gutterTem && !fixedWidthTem) {
1044      var gutterTemUnit = '-' + gutterTem + 'px',
1045          dir = horizontal ? gutterTemUnit + ' 0 0' : '0 ' + gutterTemUnit + ' 0';
1046      str = 'margin: 0 ' + dir + ';';
1047    }
1048
1049    if (!carousel && autoHeightBP && TRANSITIONDURATION && speedTem) { str += getTransitionDurationStyle(speedTem); }
1050    return str;
1051  }
1052
1053  function getContainerWidth (fixedWidthTem, gutterTem, itemsTem) {
1054    if (fixedWidthTem) {
1055      return (fixedWidthTem + gutterTem) * slideCountNew + 'px';
1056    } else {
1057      return CALC ?
1058        CALC + '(' + slideCountNew * 100 + '% / ' + itemsTem + ')' :
1059        slideCountNew * 100 / itemsTem + '%';
1060    }
1061  }
1062
1063  function getSlideWidthStyle (fixedWidthTem, gutterTem, itemsTem) {
1064    var width;
1065
1066    if (fixedWidthTem) {
1067      width = (fixedWidthTem + gutterTem) + 'px';
1068    } else {
1069      if (!carousel) { itemsTem = Math.floor(itemsTem); }
1070      var dividend = carousel ? slideCountNew : itemsTem;
1071      width = CALC ?
1072        CALC + '(100% / ' + dividend + ')' :
1073        100 / dividend + '%';
1074    }
1075
1076    width = 'width:' + width;
1077
1078    // inner slider: overwrite outer slider styles
1079    return nested !== 'inner' ? width + ';' : width + ' !important;';
1080  }
1081
1082  function getSlideGutterStyle (gutterTem) {
1083    var str = '';
1084
1085    // gutter maybe interger || 0
1086    // so can't use 'if (gutter)'
1087    if (gutterTem !== false) {
1088      var prop = horizontal ? 'padding-' : 'margin-',
1089          dir = horizontal ? 'right' : 'bottom';
1090      str = prop +  dir + ': ' + gutterTem + 'px;';
1091    }
1092
1093    return str;
1094  }
1095
1096  function getCSSPrefix (name, num) {
1097    var prefix = name.substring(0, name.length - num).toLowerCase();
1098    if (prefix) { prefix = '-' + prefix + '-'; }
1099
1100    return prefix;
1101  }
1102
1103  function getTransitionDurationStyle (speed) {
1104    return getCSSPrefix(TRANSITIONDURATION, 18) + 'transition-duration:' + speed / 1000 + 's;';
1105  }
1106
1107  function getAnimationDurationStyle (speed) {
1108    return getCSSPrefix(ANIMATIONDURATION, 17) + 'animation-duration:' + speed / 1000 + 's;';
1109  }
1110
1111  function initStructure () {
1112    var classOuter = 'tns-outer',
1113        classInner = 'tns-inner',
1114        hasGutter = hasOption('gutter');
1115
1116    outerWrapper.className = classOuter;
1117    innerWrapper.className = classInner;
1118    outerWrapper.id = slideId + '-ow';
1119    innerWrapper.id = slideId + '-iw';
1120
1121    // set container properties
1122    if (container.id === '') { container.id = slideId; }
1123    newContainerClasses += PERCENTAGELAYOUT || autoWidth ? ' tns-subpixel' : ' tns-no-subpixel';
1124    newContainerClasses += CALC ? ' tns-calc' : ' tns-no-calc';
1125    if (autoWidth) { newContainerClasses += ' tns-autowidth'; }
1126    newContainerClasses += ' tns-' + options.axis;
1127    container.className += newContainerClasses;
1128
1129    // add constrain layer for carousel
1130    if (carousel) {
1131      middleWrapper = doc.createElement('div');
1132      middleWrapper.id = slideId + '-mw';
1133      middleWrapper.className = 'tns-ovh';
1134
1135      outerWrapper.appendChild(middleWrapper);
1136      middleWrapper.appendChild(innerWrapper);
1137    } else {
1138      outerWrapper.appendChild(innerWrapper);
1139    }
1140
1141    if (autoHeight) {
1142      var wp = middleWrapper ? middleWrapper : innerWrapper;
1143      wp.className += ' tns-ah';
1144    }
1145
1146    containerParent.insertBefore(outerWrapper, container);
1147    innerWrapper.appendChild(container);
1148
1149    // add id, class, aria attributes
1150    // before clone slides
1151    forEach(slideItems, function(item, i) {
1152      addClass(item, 'tns-item');
1153      if (!item.id) { item.id = slideId + '-item' + i; }
1154      if (!carousel && animateNormal) { addClass(item, animateNormal); }
1155      setAttrs(item, {
1156        'aria-hidden': 'true',
1157        'tabindex': '-1'
1158      });
1159    });
1160
1161    // ## clone slides
1162    // carousel: n + slides + n
1163    // gallery:      slides + n
1164    if (cloneCount) {
1165      var fragmentBefore = doc.createDocumentFragment(),
1166          fragmentAfter = doc.createDocumentFragment();
1167
1168      for (var j = cloneCount; j--;) {
1169        var num = j%slideCount,
1170            cloneFirst = slideItems[num].cloneNode(true);
1171        removeAttrs(cloneFirst, 'id');
1172        fragmentAfter.insertBefore(cloneFirst, fragmentAfter.firstChild);
1173
1174        if (carousel) {
1175          var cloneLast = slideItems[slideCount - 1 - num].cloneNode(true);
1176          removeAttrs(cloneLast, 'id');
1177          fragmentBefore.appendChild(cloneLast);
1178        }
1179      }
1180
1181      container.insertBefore(fragmentBefore, container.firstChild);
1182      container.appendChild(fragmentAfter);
1183      slideItems = container.children;
1184    }
1185
1186  }
1187
1188  function initSliderTransform () {
1189    // ## images loaded/failed
1190    if (hasOption('autoHeight') || autoWidth || !horizontal) {
1191      var imgs = container.querySelectorAll('img');
1192
1193      // add img load event listener
1194      forEach(imgs, function(img) {
1195        var src = img.src;
1196
1197        if (!lazyload) {
1198          // not data img
1199          if (src && src.indexOf('data:image') < 0) {
1200            img.src = '';
1201            addEvents(img, imgEvents);
1202            addClass(img, 'loading');
1203
1204            img.src = src;
1205          // data img
1206          } else {
1207            imgLoaded(img);
1208          }
1209        }
1210      });
1211
1212      // set imgsComplete
1213      raf(function(){ imgsLoadedCheck(arrayFromNodeList(imgs), function() { imgsComplete = true; }); });
1214
1215      // reset imgs for auto height: check visible imgs only
1216      if (hasOption('autoHeight')) { imgs = getImageArray(index, Math.min(index + items - 1, slideCountNew - 1)); }
1217
1218      lazyload ? initSliderTransformStyleCheck() : raf(function(){ imgsLoadedCheck(arrayFromNodeList(imgs), initSliderTransformStyleCheck); });
1219
1220    } else {
1221      // set container transform property
1222      if (carousel) { doContainerTransformSilent(); }
1223
1224      // update slider tools and events
1225      initTools();
1226      initEvents();
1227    }
1228  }
1229
1230  function initSliderTransformStyleCheck () {
1231    if (autoWidth) {
1232      // check styles application
1233      var num = loop ? index : slideCount - 1;
1234
1235      (function stylesApplicationCheck() {
1236        var left = slideItems[num].getBoundingClientRect().left;
1237        var right = slideItems[num - 1].getBoundingClientRect().right;
1238
1239        (Math.abs(left - right) <= 1) ?
1240          initSliderTransformCore() :
1241          setTimeout(function(){ stylesApplicationCheck(); }, 16);
1242      })();
1243
1244    } else {
1245      initSliderTransformCore();
1246    }
1247  }
1248
1249
1250  function initSliderTransformCore () {
1251    // run Fn()s which are rely on image loading
1252    if (!horizontal || autoWidth) {
1253      setSlidePositions();
1254
1255      if (autoWidth) {
1256        rightBoundary = getRightBoundary();
1257        if (freezable) { freeze = getFreeze(); }
1258        indexMax = getIndexMax(); // <= slidePositions, rightBoundary <=
1259        resetVariblesWhenDisable(disable || freeze);
1260      } else {
1261        updateContentWrapperHeight();
1262      }
1263    }
1264
1265    // set container transform property
1266    if (carousel) { doContainerTransformSilent(); }
1267
1268    // update slider tools and events
1269    initTools();
1270    initEvents();
1271  }
1272
1273  function initSheet () {
1274    // gallery:
1275    // set animation classes and left value for gallery slider
1276    if (!carousel) {
1277      for (var i = index, l = index + Math.min(slideCount, items); i < l; i++) {
1278        var item = slideItems[i];
1279        item.style.left = (i - index) * 100 / items + '%';
1280        addClass(item, animateIn);
1281        removeClass(item, animateNormal);
1282      }
1283    }
1284
1285    // #### LAYOUT
1286
1287    // ## INLINE-BLOCK VS FLOAT
1288
1289    // ## PercentageLayout:
1290    // slides: inline-block
1291    // remove blank space between slides by set font-size: 0
1292
1293    // ## Non PercentageLayout:
1294    // slides: float
1295    //         margin-right: -100%
1296    //         margin-left: ~
1297
1298    // Resource: https://docs.google.com/spreadsheets/d/147up245wwTXeQYve3BRSAD4oVcvQmuGsFteJOeA5xNQ/edit?usp=sharing
1299    if (horizontal) {
1300      if (PERCENTAGELAYOUT || autoWidth) {
1301        addCSSRule(sheet, '#' + slideId + ' > .tns-item', 'font-size:' + win.getComputedStyle(slideItems[0]).fontSize + ';', getCssRulesLength(sheet));
1302        addCSSRule(sheet, '#' + slideId, 'font-size:0;', getCssRulesLength(sheet));
1303      } else if (carousel) {
1304        forEach(slideItems, function (slide, i) {
1305          slide.style.marginLeft = getSlideMarginLeft(i);
1306        });
1307      }
1308    }
1309
1310
1311    // ## BASIC STYLES
1312    if (CSSMQ) {
1313      // middle wrapper style
1314      if (TRANSITIONDURATION) {
1315        var str = middleWrapper && options.autoHeight ? getTransitionDurationStyle(options.speed) : '';
1316        addCSSRule(sheet, '#' + slideId + '-mw', str, getCssRulesLength(sheet));
1317      }
1318
1319      // inner wrapper styles
1320      str = getInnerWrapperStyles(options.edgePadding, options.gutter, options.fixedWidth, options.speed, options.autoHeight);
1321      addCSSRule(sheet, '#' + slideId + '-iw', str, getCssRulesLength(sheet));
1322
1323      // container styles
1324      if (carousel) {
1325        str = horizontal && !autoWidth ? 'width:' + getContainerWidth(options.fixedWidth, options.gutter, options.items) + ';' : '';
1326        if (TRANSITIONDURATION) { str += getTransitionDurationStyle(speed); }
1327        addCSSRule(sheet, '#' + slideId, str, getCssRulesLength(sheet));
1328      }
1329
1330      // slide styles
1331      str = horizontal && !autoWidth ? getSlideWidthStyle(options.fixedWidth, options.gutter, options.items) : '';
1332      if (options.gutter) { str += getSlideGutterStyle(options.gutter); }
1333      // set gallery items transition-duration
1334      if (!carousel) {
1335        if (TRANSITIONDURATION) { str += getTransitionDurationStyle(speed); }
1336        if (ANIMATIONDURATION) { str += getAnimationDurationStyle(speed); }
1337      }
1338      if (str) { addCSSRule(sheet, '#' + slideId + ' > .tns-item', str, getCssRulesLength(sheet)); }
1339
1340    // non CSS mediaqueries: IE8
1341    // ## update inner wrapper, container, slides if needed
1342    // set inline styles for inner wrapper & container
1343    // insert stylesheet (one line) for slides only (since slides are many)
1344    } else {
1345      // middle wrapper styles
1346      update_carousel_transition_duration();
1347
1348      // inner wrapper styles
1349      innerWrapper.style.cssText = getInnerWrapperStyles(edgePadding, gutter, fixedWidth, autoHeight);
1350
1351      // container styles
1352      if (carousel && horizontal && !autoWidth) {
1353        container.style.width = getContainerWidth(fixedWidth, gutter, items);
1354      }
1355
1356      // slide styles
1357      var str = horizontal && !autoWidth ? getSlideWidthStyle(fixedWidth, gutter, items) : '';
1358      if (gutter) { str += getSlideGutterStyle(gutter); }
1359
1360      // append to the last line
1361      if (str) { addCSSRule(sheet, '#' + slideId + ' > .tns-item', str, getCssRulesLength(sheet)); }
1362    }
1363
1364    // ## MEDIAQUERIES
1365    if (responsive && CSSMQ) {
1366      for (var bp in responsive) {
1367        // bp: convert string to number
1368        bp = parseInt(bp);
1369
1370        var opts = responsive[bp],
1371            str = '',
1372            middleWrapperStr = '',
1373            innerWrapperStr = '',
1374            containerStr = '',
1375            slideStr = '',
1376            itemsBP = !autoWidth ? getOption('items', bp) : null,
1377            fixedWidthBP = getOption('fixedWidth', bp),
1378            speedBP = getOption('speed', bp),
1379            edgePaddingBP = getOption('edgePadding', bp),
1380            autoHeightBP = getOption('autoHeight', bp),
1381            gutterBP = getOption('gutter', bp);
1382
1383        // middle wrapper string
1384        if (TRANSITIONDURATION && middleWrapper && getOption('autoHeight', bp) && 'speed' in opts) {
1385          middleWrapperStr = '#' + slideId + '-mw{' + getTransitionDurationStyle(speedBP) + '}';
1386        }
1387
1388        // inner wrapper string
1389        if ('edgePadding' in opts || 'gutter' in opts) {
1390          innerWrapperStr = '#' + slideId + '-iw{' + getInnerWrapperStyles(edgePaddingBP, gutterBP, fixedWidthBP, speedBP, autoHeightBP) + '}';
1391        }
1392
1393        // container string
1394        if (carousel && horizontal && !autoWidth && ('fixedWidth' in opts || 'items' in opts || (fixedWidth && 'gutter' in opts))) {
1395          containerStr = 'width:' + getContainerWidth(fixedWidthBP, gutterBP, itemsBP) + ';';
1396        }
1397        if (TRANSITIONDURATION && 'speed' in opts) {
1398          containerStr += getTransitionDurationStyle(speedBP);
1399        }
1400        if (containerStr) {
1401          containerStr = '#' + slideId + '{' + containerStr + '}';
1402        }
1403
1404        // slide string
1405        if ('fixedWidth' in opts || (fixedWidth && 'gutter' in opts) || !carousel && 'items' in opts) {
1406          slideStr += getSlideWidthStyle(fixedWidthBP, gutterBP, itemsBP);
1407        }
1408        if ('gutter' in opts) {
1409          slideStr += getSlideGutterStyle(gutterBP);
1410        }
1411        // set gallery items transition-duration
1412        if (!carousel && 'speed' in opts) {
1413          if (TRANSITIONDURATION) { slideStr += getTransitionDurationStyle(speedBP); }
1414          if (ANIMATIONDURATION) { slideStr += getAnimationDurationStyle(speedBP); }
1415        }
1416        if (slideStr) { slideStr = '#' + slideId + ' > .tns-item{' + slideStr + '}'; }
1417
1418        // add up
1419        str = middleWrapperStr + innerWrapperStr + containerStr + slideStr;
1420
1421        if (str) {
1422          sheet.insertRule('@media (min-width: ' + bp / 16 + 'em) {' + str + '}', sheet.cssRules.length);
1423        }
1424      }
1425    }
1426  }
1427
1428  function initTools () {
1429    // == slides ==
1430    updateSlideStatus();
1431
1432    // == live region ==
1433    outerWrapper.insertAdjacentHTML('afterbegin', '<div class="tns-liveregion tns-visually-hidden" aria-live="polite" aria-atomic="true">slide <span class="current">' + getLiveRegionStr() + '</span>  of ' + slideCount + '</div>');
1434    liveregionCurrent = outerWrapper.querySelector('.tns-liveregion .current');
1435
1436    // == autoplayInit ==
1437    if (hasAutoplay) {
1438      var txt = autoplay ? 'stop' : 'start';
1439      if (autoplayButton) {
1440        setAttrs(autoplayButton, {'data-action': txt});
1441      } else if (options.autoplayButtonOutput) {
1442        outerWrapper.insertAdjacentHTML(getInsertPosition(options.autoplayPosition), '<button type="button" data-action="' + txt + '">' + autoplayHtmlStrings[0] + txt + autoplayHtmlStrings[1] + autoplayText[0] + '</button>');
1443        autoplayButton = outerWrapper.querySelector('[data-action]');
1444      }
1445
1446      // add event
1447      if (autoplayButton) {
1448        addEvents(autoplayButton, {'click': toggleAutoplay});
1449      }
1450
1451      if (autoplay) {
1452        startAutoplay();
1453        if (autoplayHoverPause) { addEvents(container, hoverEvents); }
1454        if (autoplayResetOnVisibility) { addEvents(container, visibilityEvent); }
1455      }
1456    }
1457
1458    // == navInit ==
1459    if (hasNav) {
1460      var initIndex = !carousel ? 0 : cloneCount;
1461      // customized nav
1462      // will not hide the navs in case they're thumbnails
1463      if (navContainer) {
1464        setAttrs(navContainer, {'aria-label': 'Carousel Pagination'});
1465        navItems = navContainer.children;
1466        forEach(navItems, function(item, i) {
1467          setAttrs(item, {
1468            'data-nav': i,
1469            'tabindex': '-1',
1470            'aria-label': navStr + (i + 1),
1471            'aria-controls': slideId,
1472          });
1473        });
1474
1475      // generated nav
1476      } else {
1477        var navHtml = '',
1478            hiddenStr = navAsThumbnails ? '' : 'style="display:none"';
1479        for (var i = 0; i < slideCount; i++) {
1480          // hide nav items by default
1481          navHtml += '<button type="button" data-nav="' + i +'" tabindex="-1" aria-controls="' + slideId + '" ' + hiddenStr + ' aria-label="' + navStr + (i + 1) +'"></button>';
1482        }
1483        navHtml = '<div class="tns-nav" aria-label="Carousel Pagination">' + navHtml + '</div>';
1484        outerWrapper.insertAdjacentHTML(getInsertPosition(options.navPosition), navHtml);
1485
1486        navContainer = outerWrapper.querySelector('.tns-nav');
1487        navItems = navContainer.children;
1488      }
1489
1490      updateNavVisibility();
1491
1492      // add transition
1493      if (TRANSITIONDURATION) {
1494        var prefix = TRANSITIONDURATION.substring(0, TRANSITIONDURATION.length - 18).toLowerCase(),
1495            str = 'transition: all ' + speed / 1000 + 's';
1496
1497        if (prefix) {
1498          str = '-' + prefix + '-' + str;
1499        }
1500
1501        addCSSRule(sheet, '[aria-controls^=' + slideId + '-item]', str, getCssRulesLength(sheet));
1502      }
1503
1504      setAttrs(navItems[navCurrentIndex], {'aria-label': navStr + (navCurrentIndex + 1) + navStrCurrent});
1505      removeAttrs(navItems[navCurrentIndex], 'tabindex');
1506      addClass(navItems[navCurrentIndex], navActiveClass);
1507
1508      // add events
1509      addEvents(navContainer, navEvents);
1510    }
1511
1512
1513
1514    // == controlsInit ==
1515    if (hasControls) {
1516      if (!controlsContainer && (!prevButton || !nextButton)) {
1517        outerWrapper.insertAdjacentHTML(getInsertPosition(options.controlsPosition), '<div class="tns-controls" aria-label="Carousel Navigation" tabindex="0"><button type="button" data-controls="prev" tabindex="-1" aria-controls="' + slideId +'">' + controlsText[0] + '</button><button type="button" data-controls="next" tabindex="-1" aria-controls="' + slideId +'">' + controlsText[1] + '</button></div>');
1518
1519        controlsContainer = outerWrapper.querySelector('.tns-controls');
1520      }
1521
1522      if (!prevButton || !nextButton) {
1523        prevButton = controlsContainer.children[0];
1524        nextButton = controlsContainer.children[1];
1525      }
1526
1527      if (options.controlsContainer) {
1528        setAttrs(controlsContainer, {
1529          'aria-label': 'Carousel Navigation',
1530          'tabindex': '0'
1531        });
1532      }
1533
1534      if (options.controlsContainer || (options.prevButton && options.nextButton)) {
1535        setAttrs([prevButton, nextButton], {
1536          'aria-controls': slideId,
1537          'tabindex': '-1',
1538        });
1539      }
1540
1541      if (options.controlsContainer || (options.prevButton && options.nextButton)) {
1542        setAttrs(prevButton, {'data-controls' : 'prev'});
1543        setAttrs(nextButton, {'data-controls' : 'next'});
1544      }
1545
1546      prevIsButton = isButton(prevButton);
1547      nextIsButton = isButton(nextButton);
1548
1549      updateControlsStatus();
1550
1551      // add events
1552      if (controlsContainer) {
1553        addEvents(controlsContainer, controlsEvents);
1554      } else {
1555        addEvents(prevButton, controlsEvents);
1556        addEvents(nextButton, controlsEvents);
1557      }
1558    }
1559
1560    // hide tools if needed
1561    disableUI();
1562  }
1563
1564  function initEvents () {
1565    // add events
1566    if (carousel && TRANSITIONEND) {
1567      var eve = {};
1568      eve[TRANSITIONEND] = onTransitionEnd;
1569      addEvents(container, eve);
1570    }
1571
1572    if (touch) { addEvents(container, touchEvents, options.preventScrollOnTouch); }
1573    if (mouseDrag) { addEvents(container, dragEvents); }
1574    if (arrowKeys) { addEvents(doc, docmentKeydownEvent); }
1575
1576    if (nested === 'inner') {
1577      events.on('outerResized', function () {
1578        resizeTasks();
1579        events.emit('innerLoaded', info());
1580      });
1581    } else if (responsive || fixedWidth || autoWidth || autoHeight || !horizontal) {
1582      addEvents(win, {'resize': onResize});
1583    }
1584
1585    if (autoHeight) {
1586      if (nested === 'outer') {
1587        events.on('innerLoaded', doAutoHeight);
1588      } else if (!disable) { doAutoHeight(); }
1589    }
1590
1591    doLazyLoad();
1592    if (disable) { disableSlider(); } else if (freeze) { freezeSlider(); }
1593
1594    events.on('indexChanged', additionalUpdates);
1595    if (nested === 'inner') { events.emit('innerLoaded', info()); }
1596    if (typeof onInit === 'function') { onInit(info()); }
1597    isOn = true;
1598  }
1599
1600  function destroy () {
1601    // sheet
1602    sheet.disabled = true;
1603    if (sheet.ownerNode) { sheet.ownerNode.remove(); }
1604
1605    // remove win event listeners
1606    removeEvents(win, {'resize': onResize});
1607
1608    // arrowKeys, controls, nav
1609    if (arrowKeys) { removeEvents(doc, docmentKeydownEvent); }
1610    if (controlsContainer) { removeEvents(controlsContainer, controlsEvents); }
1611    if (navContainer) { removeEvents(navContainer, navEvents); }
1612
1613    // autoplay
1614    removeEvents(container, hoverEvents);
1615    removeEvents(container, visibilityEvent);
1616    if (autoplayButton) { removeEvents(autoplayButton, {'click': toggleAutoplay}); }
1617    if (autoplay) { clearInterval(autoplayTimer); }
1618
1619    // container
1620    if (carousel && TRANSITIONEND) {
1621      var eve = {};
1622      eve[TRANSITIONEND] = onTransitionEnd;
1623      removeEvents(container, eve);
1624    }
1625    if (touch) { removeEvents(container, touchEvents); }
1626    if (mouseDrag) { removeEvents(container, dragEvents); }
1627
1628    // cache Object values in options && reset HTML
1629    var htmlList = [containerHTML, controlsContainerHTML, prevButtonHTML, nextButtonHTML, navContainerHTML, autoplayButtonHTML];
1630
1631    tnsList.forEach(function(item, i) {
1632      var el = item === 'container' ? outerWrapper : options[item];
1633
1634      if (typeof el === 'object' && el) {
1635        var prevEl = el.previousElementSibling ? el.previousElementSibling : false,
1636            parentEl = el.parentNode;
1637        el.outerHTML = htmlList[i];
1638        options[item] = prevEl ? prevEl.nextElementSibling : parentEl.firstElementChild;
1639      }
1640    });
1641
1642
1643    // reset variables
1644    tnsList = animateIn = animateOut = animateDelay = animateNormal = horizontal = outerWrapper = innerWrapper = container = containerParent = containerHTML = slideItems = slideCount = breakpointZone = windowWidth = autoWidth = fixedWidth = edgePadding = gutter = viewport = items = slideBy = viewportMax = arrowKeys = speed = rewind = loop = autoHeight = sheet = lazyload = slidePositions = slideItemsOut = cloneCount = slideCountNew = hasRightDeadZone = rightBoundary = updateIndexBeforeTransform = transformAttr = transformPrefix = transformPostfix = getIndexMax = index = indexCached = indexMin = indexMax = resizeTimer = swipeAngle = moveDirectionExpected = running = onInit = events = newContainerClasses = slideId = disable = disabled = freezable = freeze = frozen = controlsEvents = navEvents = hoverEvents = visibilityEvent = docmentKeydownEvent = touchEvents = dragEvents = hasControls = hasNav = navAsThumbnails = hasAutoplay = hasTouch = hasMouseDrag = slideActiveClass = imgCompleteClass = imgEvents = imgsComplete = controls = controlsText = controlsContainer = controlsContainerHTML = prevButton = nextButton = prevIsButton = nextIsButton = nav = navContainer = navContainerHTML = navItems = pages = pagesCached = navClicked = navCurrentIndex = navCurrentIndexCached = navActiveClass = navStr = navStrCurrent = autoplay = autoplayTimeout = autoplayDirection = autoplayText = autoplayHoverPause = autoplayButton = autoplayButtonHTML = autoplayResetOnVisibility = autoplayHtmlStrings = autoplayTimer = animating = autoplayHoverPaused = autoplayUserPaused = autoplayVisibilityPaused = initPosition = lastPosition = translateInit = disX = disY = panStart = rafIndex = getDist = touch = mouseDrag = null;
1645    // check variables
1646    // [animateIn, animateOut, animateDelay, animateNormal, horizontal, outerWrapper, innerWrapper, container, containerParent, containerHTML, slideItems, slideCount, breakpointZone, windowWidth, autoWidth, fixedWidth, edgePadding, gutter, viewport, items, slideBy, viewportMax, arrowKeys, speed, rewind, loop, autoHeight, sheet, lazyload, slidePositions, slideItemsOut, cloneCount, slideCountNew, hasRightDeadZone, rightBoundary, updateIndexBeforeTransform, transformAttr, transformPrefix, transformPostfix, getIndexMax, index, indexCached, indexMin, indexMax, resizeTimer, swipeAngle, moveDirectionExpected, running, onInit, events, newContainerClasses, slideId, disable, disabled, freezable, freeze, frozen, controlsEvents, navEvents, hoverEvents, visibilityEvent, docmentKeydownEvent, touchEvents, dragEvents, hasControls, hasNav, navAsThumbnails, hasAutoplay, hasTouch, hasMouseDrag, slideActiveClass, imgCompleteClass, imgEvents, imgsComplete, controls, controlsText, controlsContainer, controlsContainerHTML, prevButton, nextButton, prevIsButton, nextIsButton, nav, navContainer, navContainerHTML, navItems, pages, pagesCached, navClicked, navCurrentIndex, navCurrentIndexCached, navActiveClass, navStr, navStrCurrent, autoplay, autoplayTimeout, autoplayDirection, autoplayText, autoplayHoverPause, autoplayButton, autoplayButtonHTML, autoplayResetOnVisibility, autoplayHtmlStrings, autoplayTimer, animating, autoplayHoverPaused, autoplayUserPaused, autoplayVisibilityPaused, initPosition, lastPosition, translateInit, disX, disY, panStart, rafIndex, getDist, touch, mouseDrag ].forEach(function(item) { if (item !== null) { console.log(item); } });
1647
1648    for (var a in this) {
1649      if (a !== 'rebuild') { this[a] = null; }
1650    }
1651    isOn = false;
1652  }
1653
1654// === ON RESIZE ===
1655  // responsive || fixedWidth || autoWidth || !horizontal
1656  function onResize (e) {
1657    raf(function(){ resizeTasks(getEvent(e)); });
1658  }
1659
1660  function resizeTasks (e) {
1661    if (!isOn) { return; }
1662    if (nested === 'outer') { events.emit('outerResized', info(e)); }
1663    windowWidth = getWindowWidth();
1664    var bpChanged,
1665        breakpointZoneTem = breakpointZone,
1666        needContainerTransform = false;
1667
1668    if (responsive) {
1669      setBreakpointZone();
1670      bpChanged = breakpointZoneTem !== breakpointZone;
1671      // if (hasRightDeadZone) { needContainerTransform = true; } // *?
1672      if (bpChanged) { events.emit('newBreakpointStart', info(e)); }
1673    }
1674
1675    var indChanged,
1676        itemsChanged,
1677        itemsTem = items,
1678        disableTem = disable,
1679        freezeTem = freeze,
1680        arrowKeysTem = arrowKeys,
1681        controlsTem = controls,
1682        navTem = nav,
1683        touchTem = touch,
1684        mouseDragTem = mouseDrag,
1685        autoplayTem = autoplay,
1686        autoplayHoverPauseTem = autoplayHoverPause,
1687        autoplayResetOnVisibilityTem = autoplayResetOnVisibility,
1688        indexTem = index;
1689
1690    if (bpChanged) {
1691      var fixedWidthTem = fixedWidth,
1692          autoHeightTem = autoHeight,
1693          controlsTextTem = controlsText,
1694          centerTem = center,
1695          autoplayTextTem = autoplayText;
1696
1697      if (!CSSMQ) {
1698        var gutterTem = gutter,
1699            edgePaddingTem = edgePadding;
1700      }
1701    }
1702
1703    // get option:
1704    // fixed width: viewport, fixedWidth, gutter => items
1705    // others: window width => all variables
1706    // all: items => slideBy
1707    arrowKeys = getOption('arrowKeys');
1708    controls = getOption('controls');
1709    nav = getOption('nav');
1710    touch = getOption('touch');
1711    center = getOption('center');
1712    mouseDrag = getOption('mouseDrag');
1713    autoplay = getOption('autoplay');
1714    autoplayHoverPause = getOption('autoplayHoverPause');
1715    autoplayResetOnVisibility = getOption('autoplayResetOnVisibility');
1716
1717    if (bpChanged) {
1718      disable = getOption('disable');
1719      fixedWidth = getOption('fixedWidth');
1720      speed = getOption('speed');
1721      autoHeight = getOption('autoHeight');
1722      controlsText = getOption('controlsText');
1723      autoplayText = getOption('autoplayText');
1724      autoplayTimeout = getOption('autoplayTimeout');
1725
1726      if (!CSSMQ) {
1727        edgePadding = getOption('edgePadding');
1728        gutter = getOption('gutter');
1729      }
1730    }
1731    // update options
1732    resetVariblesWhenDisable(disable);
1733
1734    viewport = getViewportWidth(); // <= edgePadding, gutter
1735    if ((!horizontal || autoWidth) && !disable) {
1736      setSlidePositions();
1737      if (!horizontal) {
1738        updateContentWrapperHeight(); // <= setSlidePositions
1739        needContainerTransform = true;
1740      }
1741    }
1742    if (fixedWidth || autoWidth) {
1743      rightBoundary = getRightBoundary(); // autoWidth: <= viewport, slidePositions, gutter
1744                                          // fixedWidth: <= viewport, fixedWidth, gutter
1745      indexMax = getIndexMax(); // autoWidth: <= rightBoundary, slidePositions
1746                                // fixedWidth: <= rightBoundary, fixedWidth, gutter
1747    }
1748
1749    if (bpChanged || fixedWidth) {
1750      items = getOption('items');
1751      slideBy = getOption('slideBy');
1752      itemsChanged = items !== itemsTem;
1753
1754      if (itemsChanged) {
1755        if (!fixedWidth && !autoWidth) { indexMax = getIndexMax(); } // <= items
1756        // check index before transform in case
1757        // slider reach the right edge then items become bigger
1758        updateIndex();
1759      }
1760    }
1761
1762    if (bpChanged) {
1763      if (disable !== disableTem) {
1764        if (disable) {
1765          disableSlider();
1766        } else {
1767          enableSlider(); // <= slidePositions, rightBoundary, indexMax
1768        }
1769      }
1770    }
1771
1772    if (freezable && (bpChanged || fixedWidth || autoWidth)) {
1773      freeze = getFreeze(); // <= autoWidth: slidePositions, gutter, viewport, rightBoundary
1774                            // <= fixedWidth: fixedWidth, gutter, rightBoundary
1775                            // <= others: items
1776
1777      if (freeze !== freezeTem) {
1778        if (freeze) {
1779          doContainerTransform(getContainerTransformValue(getStartIndex(0)));
1780          freezeSlider();
1781        } else {
1782          unfreezeSlider();
1783          needContainerTransform = true;
1784        }
1785      }
1786    }
1787
1788    resetVariblesWhenDisable(disable || freeze); // controls, nav, touch, mouseDrag, arrowKeys, autoplay, autoplayHoverPause, autoplayResetOnVisibility
1789    if (!autoplay) { autoplayHoverPause = autoplayResetOnVisibility = false; }
1790
1791    if (arrowKeys !== arrowKeysTem) {
1792      arrowKeys ?
1793        addEvents(doc, docmentKeydownEvent) :
1794        removeEvents(doc, docmentKeydownEvent);
1795    }
1796    if (controls !== controlsTem) {
1797      if (controls) {
1798        if (controlsContainer) {
1799          showElement(controlsContainer);
1800        } else {
1801          if (prevButton) { showElement(prevButton); }
1802          if (nextButton) { showElement(nextButton); }
1803        }
1804      } else {
1805        if (controlsContainer) {
1806          hideElement(controlsContainer);
1807        } else {
1808          if (prevButton) { hideElement(prevButton); }
1809          if (nextButton) { hideElement(nextButton); }
1810        }
1811      }
1812    }
1813    if (nav !== navTem) {
1814      nav ?
1815        showElement(navContainer) :
1816        hideElement(navContainer);
1817    }
1818    if (touch !== touchTem) {
1819      touch ?
1820        addEvents(container, touchEvents, options.preventScrollOnTouch) :
1821        removeEvents(container, touchEvents);
1822    }
1823    if (mouseDrag !== mouseDragTem) {
1824      mouseDrag ?
1825        addEvents(container, dragEvents) :
1826        removeEvents(container, dragEvents);
1827    }
1828    if (autoplay !== autoplayTem) {
1829      if (autoplay) {
1830        if (autoplayButton) { showElement(autoplayButton); }
1831        if (!animating && !autoplayUserPaused) { startAutoplay(); }
1832      } else {
1833        if (autoplayButton) { hideElement(autoplayButton); }
1834        if (animating) { stopAutoplay(); }
1835      }
1836    }
1837    if (autoplayHoverPause !== autoplayHoverPauseTem) {
1838      autoplayHoverPause ?
1839        addEvents(container, hoverEvents) :
1840        removeEvents(container, hoverEvents);
1841    }
1842    if (autoplayResetOnVisibility !== autoplayResetOnVisibilityTem) {
1843      autoplayResetOnVisibility ?
1844        addEvents(doc, visibilityEvent) :
1845        removeEvents(doc, visibilityEvent);
1846    }
1847
1848    if (bpChanged) {
1849      if (fixedWidth !== fixedWidthTem || center !== centerTem) { needContainerTransform = true; }
1850
1851      if (autoHeight !== autoHeightTem) {
1852        if (!autoHeight) { innerWrapper.style.height = ''; }
1853      }
1854
1855      if (controls && controlsText !== controlsTextTem) {
1856        prevButton.innerHTML = controlsText[0];
1857        nextButton.innerHTML = controlsText[1];
1858      }
1859
1860      if (autoplayButton && autoplayText !== autoplayTextTem) {
1861        var i = autoplay ? 1 : 0,
1862            html = autoplayButton.innerHTML,
1863            len = html.length - autoplayTextTem[i].length;
1864        if (html.substring(len) === autoplayTextTem[i]) {
1865          autoplayButton.innerHTML = html.substring(0, len) + autoplayText[i];
1866        }
1867      }
1868    } else {
1869      if (center && (fixedWidth || autoWidth)) { needContainerTransform = true; }
1870    }
1871
1872    if (itemsChanged || fixedWidth && !autoWidth) {
1873      pages = getPages();
1874      updateNavVisibility();
1875    }
1876
1877    indChanged = index !== indexTem;
1878    if (indChanged) {
1879      events.emit('indexChanged', info());
1880      needContainerTransform = true;
1881    } else if (itemsChanged) {
1882      if (!indChanged) { additionalUpdates(); }
1883    } else if (fixedWidth || autoWidth) {
1884      doLazyLoad();
1885      updateSlideStatus();
1886      updateLiveRegion();
1887    }
1888
1889    if (itemsChanged && !carousel) { updateGallerySlidePositions(); }
1890
1891    if (!disable && !freeze) {
1892      // non-mediaqueries: IE8
1893      if (bpChanged && !CSSMQ) {
1894        // middle wrapper styles
1895
1896        // inner wrapper styles
1897        if (edgePadding !== edgePaddingTem || gutter !== gutterTem) {
1898          innerWrapper.style.cssText = getInnerWrapperStyles(edgePadding, gutter, fixedWidth, speed, autoHeight);
1899        }
1900
1901        if (horizontal) {
1902          // container styles
1903          if (carousel) {
1904            container.style.width = getContainerWidth(fixedWidth, gutter, items);
1905          }
1906
1907          // slide styles
1908          var str = getSlideWidthStyle(fixedWidth, gutter, items) +
1909                    getSlideGutterStyle(gutter);
1910
1911          // remove the last line and
1912          // add new styles
1913          removeCSSRule(sheet, getCssRulesLength(sheet) - 1);
1914          addCSSRule(sheet, '#' + slideId + ' > .tns-item', str, getCssRulesLength(sheet));
1915        }
1916      }
1917
1918      // auto height
1919      if (autoHeight) { doAutoHeight(); }
1920
1921      if (needContainerTransform) {
1922        doContainerTransformSilent();
1923        indexCached = index;
1924      }
1925    }
1926
1927    if (bpChanged) { events.emit('newBreakpointEnd', info(e)); }
1928  }
1929
1930
1931
1932
1933
1934  // === INITIALIZATION FUNCTIONS === //
1935  function getFreeze () {
1936    if (!fixedWidth && !autoWidth) {
1937      var a = center ? items - (items - 1) / 2 : items;
1938      return  slideCount <= a;
1939    }
1940
1941    var width = fixedWidth ? (fixedWidth + gutter) * slideCount : slidePositions[slideCount],
1942        vp = edgePadding ? viewport + edgePadding * 2 : viewport + gutter;
1943
1944    if (center) {
1945      vp -= fixedWidth ? (viewport - fixedWidth) / 2 : (viewport - (slidePositions[index + 1] - slidePositions[index] - gutter)) / 2;
1946    }
1947
1948    return width <= vp;
1949  }
1950
1951  function setBreakpointZone () {
1952    breakpointZone = 0;
1953    for (var bp in responsive) {
1954      bp = parseInt(bp); // convert string to number
1955      if (windowWidth >= bp) { breakpointZone = bp; }
1956    }
1957  }
1958
1959  // (slideBy, indexMin, indexMax) => index
1960  var updateIndex = (function () {
1961    return loop ?
1962      carousel ?
1963        // loop + carousel
1964        function () {
1965          var leftEdge = indexMin,
1966              rightEdge = indexMax;
1967
1968          leftEdge += slideBy;
1969          rightEdge -= slideBy;
1970
1971          // adjust edges when has edge paddings
1972          // or fixed-width slider with extra space on the right side
1973          if (edgePadding) {
1974            leftEdge += 1;
1975            rightEdge -= 1;
1976          } else if (fixedWidth) {
1977            if ((viewport + gutter)%(fixedWidth + gutter)) { rightEdge -= 1; }
1978          }
1979
1980          if (cloneCount) {
1981            if (index > rightEdge) {
1982              index -= slideCount;
1983            } else if (index < leftEdge) {
1984              index += slideCount;
1985            }
1986          }
1987        } :
1988        // loop + gallery
1989        function() {
1990          if (index > indexMax) {
1991            while (index >= indexMin + slideCount) { index -= slideCount; }
1992          } else if (index < indexMin) {
1993            while (index <= indexMax - slideCount) { index += slideCount; }
1994          }
1995        } :
1996      // non-loop
1997      function() {
1998        index = Math.max(indexMin, Math.min(indexMax, index));
1999      };
2000  })();
2001
2002  function disableUI () {
2003    if (!autoplay && autoplayButton) { hideElement(autoplayButton); }
2004    if (!nav && navContainer) { hideElement(navContainer); }
2005    if (!controls) {
2006      if (controlsContainer) {
2007        hideElement(controlsContainer);
2008      } else {
2009        if (prevButton) { hideElement(prevButton); }
2010        if (nextButton) { hideElement(nextButton); }
2011      }
2012    }
2013  }
2014
2015  function enableUI () {
2016    if (autoplay && autoplayButton) { showElement(autoplayButton); }
2017    if (nav && navContainer) { showElement(navContainer); }
2018    if (controls) {
2019      if (controlsContainer) {
2020        showElement(controlsContainer);
2021      } else {
2022        if (prevButton) { showElement(prevButton); }
2023        if (nextButton) { showElement(nextButton); }
2024      }
2025    }
2026  }
2027
2028  function freezeSlider () {
2029    if (frozen) { return; }
2030
2031    // remove edge padding from inner wrapper
2032    if (edgePadding) { innerWrapper.style.margin = '0px'; }
2033
2034    // add class tns-transparent to cloned slides
2035    if (cloneCount) {
2036      var str = 'tns-transparent';
2037      for (var i = cloneCount; i--;) {
2038        if (carousel) { addClass(slideItems[i], str); }
2039        addClass(slideItems[slideCountNew - i - 1], str);
2040      }
2041    }
2042
2043    // update tools
2044    disableUI();
2045
2046    frozen = true;
2047  }
2048
2049  function unfreezeSlider () {
2050    if (!frozen) { return; }
2051
2052    // restore edge padding for inner wrapper
2053    // for mordern browsers
2054    if (edgePadding && CSSMQ) { innerWrapper.style.margin = ''; }
2055
2056    // remove class tns-transparent to cloned slides
2057    if (cloneCount) {
2058      var str = 'tns-transparent';
2059      for (var i = cloneCount; i--;) {
2060        if (carousel) { removeClass(slideItems[i], str); }
2061        removeClass(slideItems[slideCountNew - i - 1], str);
2062      }
2063    }
2064
2065    // update tools
2066    enableUI();
2067
2068    frozen = false;
2069  }
2070
2071  function disableSlider () {
2072    if (disabled) { return; }
2073
2074    sheet.disabled = true;
2075    container.className = container.className.replace(newContainerClasses.substring(1), '');
2076    removeAttrs(container, ['style']);
2077    if (loop) {
2078      for (var j = cloneCount; j--;) {
2079        if (carousel) { hideElement(slideItems[j]); }
2080        hideElement(slideItems[slideCountNew - j - 1]);
2081      }
2082    }
2083
2084    // vertical slider
2085    if (!horizontal || !carousel) { removeAttrs(innerWrapper, ['style']); }
2086
2087    // gallery
2088    if (!carousel) {
2089      for (var i = index, l = index + slideCount; i < l; i++) {
2090        var item = slideItems[i];
2091        removeAttrs(item, ['style']);
2092        removeClass(item, animateIn);
2093        removeClass(item, animateNormal);
2094      }
2095    }
2096
2097    // update tools
2098    disableUI();
2099
2100    disabled = true;
2101  }
2102
2103  function enableSlider () {
2104    if (!disabled) { return; }
2105
2106    sheet.disabled = false;
2107    container.className += newContainerClasses;
2108    doContainerTransformSilent();
2109
2110    if (loop) {
2111      for (var j = cloneCount; j--;) {
2112        if (carousel) { showElement(slideItems[j]); }
2113        showElement(slideItems[slideCountNew - j - 1]);
2114      }
2115    }
2116
2117    // gallery
2118    if (!carousel) {
2119      for (var i = index, l = index + slideCount; i < l; i++) {
2120        var item = slideItems[i],
2121            classN = i < index + items ? animateIn : animateNormal;
2122        item.style.left = (i - index) * 100 / items + '%';
2123        addClass(item, classN);
2124      }
2125    }
2126
2127    // update tools
2128    enableUI();
2129
2130    disabled = false;
2131  }
2132
2133  function updateLiveRegion () {
2134    var str = getLiveRegionStr();
2135    if (liveregionCurrent.innerHTML !== str) { liveregionCurrent.innerHTML = str; }
2136  }
2137
2138  function getLiveRegionStr () {
2139    var arr = getVisibleSlideRange(),
2140        start = arr[0] + 1,
2141        end = arr[1] + 1;
2142    return start === end ? start + '' : start + ' to ' + end;
2143  }
2144
2145  function getVisibleSlideRange (val) {
2146    if (val == null) { val = getContainerTransformValue(); }
2147    var start = index, end, rangestart, rangeend;
2148
2149    // get range start, range end for autoWidth and fixedWidth
2150    if (center || edgePadding) {
2151      if (autoWidth || fixedWidth) {
2152        rangestart = - (parseFloat(val) + edgePadding);
2153        rangeend = rangestart + viewport + edgePadding * 2;
2154      }
2155    } else {
2156      if (autoWidth) {
2157        rangestart = slidePositions[index];
2158        rangeend = rangestart + viewport;
2159      }
2160    }
2161
2162    // get start, end
2163    // - check auto width
2164    if (autoWidth) {
2165      slidePositions.forEach(function(point, i) {
2166        if (i < slideCountNew) {
2167          if ((center || edgePadding) && point <= rangestart + 0.5) { start = i; }
2168          if (rangeend - point >= 0.5) { end = i; }
2169        }
2170      });
2171
2172    // - check percentage width, fixed width
2173    } else {
2174
2175      if (fixedWidth) {
2176        var cell = fixedWidth + gutter;
2177        if (center || edgePadding) {
2178          start = Math.floor(rangestart/cell);
2179          end = Math.ceil(rangeend/cell - 1);
2180        } else {
2181          end = start + Math.ceil(viewport/cell) - 1;
2182        }
2183
2184      } else {
2185        if (center || edgePadding) {
2186          var a = items - 1;
2187          if (center) {
2188            start -= a / 2;
2189            end = index + a / 2;
2190          } else {
2191            end = index + a;
2192          }
2193
2194          if (edgePadding) {
2195            var b = edgePadding * items / viewport;
2196            start -= b;
2197            end += b;
2198          }
2199
2200          start = Math.floor(start);
2201          end = Math.ceil(end);
2202        } else {
2203          end = start + items - 1;
2204        }
2205      }
2206
2207      start = Math.max(start, 0);
2208      end = Math.min(end, slideCountNew - 1);
2209    }
2210
2211    return [start, end];
2212  }
2213
2214  function doLazyLoad () {
2215    if (lazyload && !disable) {
2216      var arg = getVisibleSlideRange();
2217      arg.push(lazyloadSelector);
2218
2219      getImageArray.apply(null, arg).forEach(function (img) {
2220        if (!hasClass(img, imgCompleteClass)) {
2221          // stop propagation transitionend event to container
2222          var eve = {};
2223          eve[TRANSITIONEND] = function (e) { e.stopPropagation(); };
2224          addEvents(img, eve);
2225
2226          addEvents(img, imgEvents);
2227
2228          // update src
2229          img.src = getAttr(img, 'data-src');
2230
2231          // update srcset
2232          var srcset = getAttr(img, 'data-srcset');
2233          if (srcset) { img.srcset = srcset; }
2234
2235          addClass(img, 'loading');
2236        }
2237      });
2238    }
2239  }
2240
2241  function onImgLoaded (e) {
2242    imgLoaded(getTarget(e));
2243  }
2244
2245  function onImgFailed (e) {
2246    imgFailed(getTarget(e));
2247  }
2248
2249  function imgLoaded (img) {
2250    addClass(img, 'loaded');
2251    imgCompleted(img);
2252  }
2253
2254  function imgFailed (img) {
2255    addClass(img, 'failed');
2256    imgCompleted(img);
2257  }
2258
2259  function imgCompleted (img) {
2260    addClass(img, imgCompleteClass);
2261    removeClass(img, 'loading');
2262    removeEvents(img, imgEvents);
2263  }
2264
2265  function getImageArray (start, end, imgSelector) {
2266    var imgs = [];
2267    if (!imgSelector) { imgSelector = 'img'; }
2268
2269    while (start <= end) {
2270      forEach(slideItems[start].querySelectorAll(imgSelector), function (img) { imgs.push(img); });
2271      start++;
2272    }
2273
2274    return imgs;
2275  }
2276
2277  // check if all visible images are loaded
2278  // and update container height if it's done
2279  function doAutoHeight () {
2280    var imgs = getImageArray.apply(null, getVisibleSlideRange());
2281    raf(function(){ imgsLoadedCheck(imgs, updateInnerWrapperHeight); });
2282  }
2283
2284  function imgsLoadedCheck (imgs, cb) {
2285    // execute callback function if all images are complete
2286    if (imgsComplete) { return cb(); }
2287
2288    // check image classes
2289    imgs.forEach(function (img, index) {
2290      if (!lazyload && img.complete) { imgCompleted(img); } // Check image.complete
2291      if (hasClass(img, imgCompleteClass)) { imgs.splice(index, 1); }
2292    });
2293
2294    // execute callback function if selected images are all complete
2295    if (!imgs.length) { return cb(); }
2296
2297    // otherwise execute this functiona again
2298    raf(function(){ imgsLoadedCheck(imgs, cb); });
2299  }
2300
2301  function additionalUpdates () {
2302    doLazyLoad();
2303    updateSlideStatus();
2304    updateLiveRegion();
2305    updateControlsStatus();
2306    updateNavStatus();
2307  }
2308
2309
2310  function update_carousel_transition_duration () {
2311    if (carousel && autoHeight) {
2312      middleWrapper.style[TRANSITIONDURATION] = speed / 1000 + 's';
2313    }
2314  }
2315
2316  function getMaxSlideHeight (slideStart, slideRange) {
2317    var heights = [];
2318    for (var i = slideStart, l = Math.min(slideStart + slideRange, slideCountNew); i < l; i++) {
2319      heights.push(slideItems[i].offsetHeight);
2320    }
2321
2322    return Math.max.apply(null, heights);
2323  }
2324
2325  // update inner wrapper height
2326  // 1. get the max-height of the visible slides
2327  // 2. set transitionDuration to speed
2328  // 3. update inner wrapper height to max-height
2329  // 4. set transitionDuration to 0s after transition done
2330  function updateInnerWrapperHeight () {
2331    var maxHeight = autoHeight ? getMaxSlideHeight(index, items) : getMaxSlideHeight(cloneCount, slideCount),
2332        wp = middleWrapper ? middleWrapper : innerWrapper;
2333
2334    if (wp.style.height !== maxHeight) { wp.style.height = maxHeight + 'px'; }
2335  }
2336
2337  // get the distance from the top edge of the first slide to each slide
2338  // (init) => slidePositions
2339  function setSlidePositions () {
2340    slidePositions = [0];
2341    var attr = horizontal ? 'left' : 'top',
2342        attr2 = horizontal ? 'right' : 'bottom',
2343        base = slideItems[0].getBoundingClientRect()[attr];
2344
2345    forEach(slideItems, function(item, i) {
2346      // skip the first slide
2347      if (i) { slidePositions.push(item.getBoundingClientRect()[attr] - base); }
2348      // add the end edge
2349      if (i === slideCountNew - 1) { slidePositions.push(item.getBoundingClientRect()[attr2] - base); }
2350    });
2351  }
2352
2353  // update slide
2354  function updateSlideStatus () {
2355    var range = getVisibleSlideRange(),
2356        start = range[0],
2357        end = range[1];
2358
2359    forEach(slideItems, function(item, i) {
2360      // show slides
2361      if (i >= start && i <= end) {
2362        if (hasAttr(item, 'aria-hidden')) {
2363          removeAttrs(item, ['aria-hidden', 'tabindex']);
2364          addClass(item, slideActiveClass);
2365        }
2366      // hide slides
2367      } else {
2368        if (!hasAttr(item, 'aria-hidden')) {
2369          setAttrs(item, {
2370            'aria-hidden': 'true',
2371            'tabindex': '-1'
2372          });
2373          removeClass(item, slideActiveClass);
2374        }
2375      }
2376    });
2377  }
2378
2379  // gallery: update slide position
2380  function updateGallerySlidePositions () {
2381    var l = index + Math.min(slideCount, items);
2382    for (var i = slideCountNew; i--;) {
2383      var item = slideItems[i];
2384
2385      if (i >= index && i < l) {
2386        // add transitions to visible slides when adjusting their positions
2387        addClass(item, 'tns-moving');
2388
2389        item.style.left = (i - index) * 100 / items + '%';
2390        addClass(item, animateIn);
2391        removeClass(item, animateNormal);
2392      } else if (item.style.left) {
2393        item.style.left = '';
2394        addClass(item, animateNormal);
2395        removeClass(item, animateIn);
2396      }
2397
2398      // remove outlet animation
2399      removeClass(item, animateOut);
2400    }
2401
2402    // removing '.tns-moving'
2403    setTimeout(function() {
2404      forEach(slideItems, function(el) {
2405        removeClass(el, 'tns-moving');
2406      });
2407    }, 300);
2408  }
2409
2410  // set tabindex on Nav
2411  function updateNavStatus () {
2412    // get current nav
2413    if (nav) {
2414      navCurrentIndex = navClicked >= 0 ? navClicked : getCurrentNavIndex();
2415      navClicked = -1;
2416
2417      if (navCurrentIndex !== navCurrentIndexCached) {
2418        var navPrev = navItems[navCurrentIndexCached],
2419            navCurrent = navItems[navCurrentIndex];
2420
2421        setAttrs(navPrev, {
2422          'tabindex': '-1',
2423          'aria-label': navStr + (navCurrentIndexCached + 1)
2424        });
2425        removeClass(navPrev, navActiveClass);
2426
2427        setAttrs(navCurrent, {'aria-label': navStr + (navCurrentIndex + 1) + navStrCurrent});
2428        removeAttrs(navCurrent, 'tabindex');
2429        addClass(navCurrent, navActiveClass);
2430
2431        navCurrentIndexCached = navCurrentIndex;
2432      }
2433    }
2434  }
2435
2436  function getLowerCaseNodeName (el) {
2437    return el.nodeName.toLowerCase();
2438  }
2439
2440  function isButton (el) {
2441    return getLowerCaseNodeName(el) === 'button';
2442  }
2443
2444  function isAriaDisabled (el) {
2445    return el.getAttribute('aria-disabled') === 'true';
2446  }
2447
2448  function disEnableElement (isButton, el, val) {
2449    if (isButton) {
2450      el.disabled = val;
2451    } else {
2452      el.setAttribute('aria-disabled', val.toString());
2453    }
2454  }
2455
2456  // set 'disabled' to true on controls when reach the edges
2457  function updateControlsStatus () {
2458    if (!controls || rewind || loop) { return; }
2459
2460    var prevDisabled = (prevIsButton) ? prevButton.disabled : isAriaDisabled(prevButton),
2461        nextDisabled = (nextIsButton) ? nextButton.disabled : isAriaDisabled(nextButton),
2462        disablePrev = (index <= indexMin) ? true : false,
2463        disableNext = (!rewind && index >= indexMax) ? true : false;
2464
2465    if (disablePrev && !prevDisabled) {
2466      disEnableElement(prevIsButton, prevButton, true);
2467    }
2468    if (!disablePrev && prevDisabled) {
2469      disEnableElement(prevIsButton, prevButton, false);
2470    }
2471    if (disableNext && !nextDisabled) {
2472      disEnableElement(nextIsButton, nextButton, true);
2473    }
2474    if (!disableNext && nextDisabled) {
2475      disEnableElement(nextIsButton, nextButton, false);
2476    }
2477  }
2478
2479  // set duration
2480  function resetDuration (el, str) {
2481    if (TRANSITIONDURATION) { el.style[TRANSITIONDURATION] = str; }
2482  }
2483
2484  function getSliderWidth () {
2485    return fixedWidth ? (fixedWidth + gutter) * slideCountNew : slidePositions[slideCountNew];
2486  }
2487
2488  function getCenterGap (num) {
2489    if (num == null) { num = index; }
2490
2491    var gap = edgePadding ? gutter : 0;
2492    return autoWidth ? ((viewport - gap) - (slidePositions[num + 1] - slidePositions[num] - gutter))/2 :
2493      fixedWidth ? (viewport - fixedWidth) / 2 :
2494        (items - 1) / 2;
2495  }
2496
2497  function getRightBoundary () {
2498    var gap = edgePadding ? gutter : 0,
2499        result = (viewport + gap) - getSliderWidth();
2500
2501    if (center && !loop) {
2502      result = fixedWidth ? - (fixedWidth + gutter) * (slideCountNew - 1) - getCenterGap() :
2503        getCenterGap(slideCountNew - 1) - slidePositions[slideCountNew - 1];
2504    }
2505    if (result > 0) { result = 0; }
2506
2507    return result;
2508  }
2509
2510  function getContainerTransformValue (num) {
2511    if (num == null) { num = index; }
2512
2513    var val;
2514    if (horizontal && !autoWidth) {
2515      if (fixedWidth) {
2516        val = - (fixedWidth + gutter) * num;
2517        if (center) { val += getCenterGap(); }
2518      } else {
2519        var denominator = TRANSFORM ? slideCountNew : items;
2520        if (center) { num -= getCenterGap(); }
2521        val = - num * 100 / denominator;
2522      }
2523    } else {
2524      val = - slidePositions[num];
2525      if (center && autoWidth) {
2526        val += getCenterGap();
2527      }
2528    }
2529
2530    if (hasRightDeadZone) { val = Math.max(val, rightBoundary); }
2531
2532    val += (horizontal && !autoWidth && !fixedWidth) ? '%' : 'px';
2533
2534    return val;
2535  }
2536
2537  function doContainerTransformSilent (val) {
2538    resetDuration(container, '0s');
2539    doContainerTransform(val);
2540  }
2541
2542  function doContainerTransform (val) {
2543    if (val == null) { val = getContainerTransformValue(); }
2544    container.style[transformAttr] = transformPrefix + val + transformPostfix;
2545  }
2546
2547  function animateSlide (number, classOut, classIn, isOut) {
2548    var l = number + items;
2549    if (!loop) { l = Math.min(l, slideCountNew); }
2550
2551    for (var i = number; i < l; i++) {
2552        var item = slideItems[i];
2553
2554      // set item positions
2555      if (!isOut) { item.style.left = (i - index) * 100 / items + '%'; }
2556
2557      if (animateDelay && TRANSITIONDELAY) {
2558        item.style[TRANSITIONDELAY] = item.style[ANIMATIONDELAY] = animateDelay * (i - number) / 1000 + 's';
2559      }
2560      removeClass(item, classOut);
2561      addClass(item, classIn);
2562
2563      if (isOut) { slideItemsOut.push(item); }
2564    }
2565  }
2566
2567  // make transfer after click/drag:
2568  // 1. change 'transform' property for mordern browsers
2569  // 2. change 'left' property for legacy browsers
2570  var transformCore = (function () {
2571    return carousel ?
2572      function () {
2573        resetDuration(container, '');
2574        if (TRANSITIONDURATION || !speed) {
2575          // for morden browsers with non-zero duration or
2576          // zero duration for all browsers
2577          doContainerTransform();
2578          // run fallback function manually
2579          // when duration is 0 / container is hidden
2580          if (!speed || !isVisible(container)) { onTransitionEnd(); }
2581
2582        } else {
2583          // for old browser with non-zero duration
2584          jsTransform(container, transformAttr, transformPrefix, transformPostfix, getContainerTransformValue(), speed, onTransitionEnd);
2585        }
2586
2587        if (!horizontal) { updateContentWrapperHeight(); }
2588      } :
2589      function () {
2590        slideItemsOut = [];
2591
2592        var eve = {};
2593        eve[TRANSITIONEND] = eve[ANIMATIONEND] = onTransitionEnd;
2594        removeEvents(slideItems[indexCached], eve);
2595        addEvents(slideItems[index], eve);
2596
2597        animateSlide(indexCached, animateIn, animateOut, true);
2598        animateSlide(index, animateNormal, animateIn);
2599
2600        // run fallback function manually
2601        // when transition or animation not supported / duration is 0
2602        if (!TRANSITIONEND || !ANIMATIONEND || !speed || !isVisible(container)) { onTransitionEnd(); }
2603      };
2604  })();
2605
2606  function render (e, sliderMoved) {
2607    if (updateIndexBeforeTransform) { updateIndex(); }
2608
2609    // render when slider was moved (touch or drag) even though index may not change
2610    if (index !== indexCached || sliderMoved) {
2611      // events
2612      events.emit('indexChanged', info());
2613      events.emit('transitionStart', info());
2614      if (autoHeight) { doAutoHeight(); }
2615
2616      // pause autoplay when click or keydown from user
2617      if (animating && e && ['click', 'keydown'].indexOf(e.type) >= 0) { stopAutoplay(); }
2618
2619      running = true;
2620      transformCore();
2621    }
2622  }
2623
2624  /*
2625   * Transfer prefixed properties to the same format
2626   * CSS: -Webkit-Transform => webkittransform
2627   * JS: WebkitTransform => webkittransform
2628   * @param {string} str - property
2629   *
2630   */
2631  function strTrans (str) {
2632    return str.toLowerCase().replace(/-/g, '');
2633  }
2634
2635  // AFTER TRANSFORM
2636  // Things need to be done after a transfer:
2637  // 1. check index
2638  // 2. add classes to visible slide
2639  // 3. disable controls buttons when reach the first/last slide in non-loop slider
2640  // 4. update nav status
2641  // 5. lazyload images
2642  // 6. update container height
2643  function onTransitionEnd (event) {
2644    // check running on gallery mode
2645    // make sure trantionend/animationend events run only once
2646    if (carousel || running) {
2647      events.emit('transitionEnd', info(event));
2648
2649      if (!carousel && slideItemsOut.length > 0) {
2650        for (var i = 0; i < slideItemsOut.length; i++) {
2651          var item = slideItemsOut[i];
2652          // set item positions
2653          item.style.left = '';
2654
2655          if (ANIMATIONDELAY && TRANSITIONDELAY) {
2656            item.style[ANIMATIONDELAY] = '';
2657            item.style[TRANSITIONDELAY] = '';
2658          }
2659          removeClass(item, animateOut);
2660          addClass(item, animateNormal);
2661        }
2662      }
2663
2664      /* update slides, nav, controls after checking ...
2665       * => legacy browsers who don't support 'event'
2666       *    have to check event first, otherwise event.target will cause an error
2667       * => or 'gallery' mode:
2668       *   + event target is slide item
2669       * => or 'carousel' mode:
2670       *   + event target is container,
2671       *   + event.property is the same with transform attribute
2672       */
2673      if (!event ||
2674          !carousel && event.target.parentNode === container ||
2675          event.target === container && strTrans(event.propertyName) === strTrans(transformAttr)) {
2676
2677        if (!updateIndexBeforeTransform) {
2678          var indexTem = index;
2679          updateIndex();
2680          if (index !== indexTem) {
2681            events.emit('indexChanged', info());
2682
2683            doContainerTransformSilent();
2684          }
2685        }
2686
2687        if (nested === 'inner') { events.emit('innerLoaded', info()); }
2688        running = false;
2689        indexCached = index;
2690      }
2691    }
2692
2693  }
2694
2695  // # ACTIONS
2696  function goTo (targetIndex, e) {
2697    if (freeze) { return; }
2698
2699    // prev slideBy
2700    if (targetIndex === 'prev') {
2701      onControlsClick(e, -1);
2702
2703    // next slideBy
2704    } else if (targetIndex === 'next') {
2705      onControlsClick(e, 1);
2706
2707    // go to exact slide
2708    } else {
2709      if (running) {
2710        if (preventActionWhenRunning) { return; } else { onTransitionEnd(); }
2711      }
2712
2713      var absIndex = getAbsIndex(),
2714          indexGap = 0;
2715
2716      if (targetIndex === 'first') {
2717        indexGap = - absIndex;
2718      } else if (targetIndex === 'last') {
2719        indexGap = carousel ? slideCount - items - absIndex : slideCount - 1 - absIndex;
2720      } else {
2721        if (typeof targetIndex !== 'number') { targetIndex = parseInt(targetIndex); }
2722
2723        if (!isNaN(targetIndex)) {
2724          // from directly called goTo function
2725          if (!e) { targetIndex = Math.max(0, Math.min(slideCount - 1, targetIndex)); }
2726
2727          indexGap = targetIndex - absIndex;
2728        }
2729      }
2730
2731      // gallery: make sure new page won't overlap with current page
2732      if (!carousel && indexGap && Math.abs(indexGap) < items) {
2733        var factor = indexGap > 0 ? 1 : -1;
2734        indexGap += (index + indexGap - slideCount) >= indexMin ? slideCount * factor : slideCount * 2 * factor * -1;
2735      }
2736
2737      index += indexGap;
2738
2739      // make sure index is in range
2740      if (carousel && loop) {
2741        if (index < indexMin) { index += slideCount; }
2742        if (index > indexMax) { index -= slideCount; }
2743      }
2744
2745      // if index is changed, start rendering
2746      if (getAbsIndex(index) !== getAbsIndex(indexCached)) {
2747        render(e);
2748      }
2749
2750    }
2751  }
2752
2753  // on controls click
2754  function onControlsClick (e, dir) {
2755    if (running) {
2756      if (preventActionWhenRunning) { return; } else { onTransitionEnd(); }
2757    }
2758    var passEventObject;
2759
2760    if (!dir) {
2761      e = getEvent(e);
2762      var target = getTarget(e);
2763
2764      while (target !== controlsContainer && [prevButton, nextButton].indexOf(target) < 0) { target = target.parentNode; }
2765
2766      var targetIn = [prevButton, nextButton].indexOf(target);
2767      if (targetIn >= 0) {
2768        passEventObject = true;
2769        dir = targetIn === 0 ? -1 : 1;
2770      }
2771    }
2772
2773    if (rewind) {
2774      if (index === indexMin && dir === -1) {
2775        goTo('last', e);
2776        return;
2777      } else if (index === indexMax && dir === 1) {
2778        goTo('first', e);
2779        return;
2780      }
2781    }
2782
2783    if (dir) {
2784      index += slideBy * dir;
2785      if (autoWidth) { index = Math.floor(index); }
2786      // pass e when click control buttons or keydown
2787      render((passEventObject || (e && e.type === 'keydown')) ? e : null);
2788    }
2789  }
2790
2791  // on nav click
2792  function onNavClick (e) {
2793    if (running) {
2794      if (preventActionWhenRunning) { return; } else { onTransitionEnd(); }
2795    }
2796
2797    e = getEvent(e);
2798    var target = getTarget(e), navIndex;
2799
2800    // find the clicked nav item
2801    while (target !== navContainer && !hasAttr(target, 'data-nav')) { target = target.parentNode; }
2802    if (hasAttr(target, 'data-nav')) {
2803      var navIndex = navClicked = Number(getAttr(target, 'data-nav')),
2804          targetIndexBase = fixedWidth || autoWidth ? navIndex * slideCount / pages : navIndex * items,
2805          targetIndex = navAsThumbnails ? navIndex : Math.min(Math.ceil(targetIndexBase), slideCount - 1);
2806      goTo(targetIndex, e);
2807
2808      if (navCurrentIndex === navIndex) {
2809        if (animating) { stopAutoplay(); }
2810        navClicked = -1; // reset navClicked
2811      }
2812    }
2813  }
2814
2815  // autoplay functions
2816  function setAutoplayTimer () {
2817    autoplayTimer = setInterval(function () {
2818      onControlsClick(null, autoplayDirection);
2819    }, autoplayTimeout);
2820
2821    animating = true;
2822  }
2823
2824  function stopAutoplayTimer () {
2825    clearInterval(autoplayTimer);
2826    animating = false;
2827  }
2828
2829  function updateAutoplayButton (action, txt) {
2830    setAttrs(autoplayButton, {'data-action': action});
2831    autoplayButton.innerHTML = autoplayHtmlStrings[0] + action + autoplayHtmlStrings[1] + txt;
2832  }
2833
2834  function startAutoplay () {
2835    setAutoplayTimer();
2836    if (autoplayButton) { updateAutoplayButton('stop', autoplayText[1]); }
2837  }
2838
2839  function stopAutoplay () {
2840    stopAutoplayTimer();
2841    if (autoplayButton) { updateAutoplayButton('start', autoplayText[0]); }
2842  }
2843
2844  // programaitcally play/pause the slider
2845  function play () {
2846    if (autoplay && !animating) {
2847      startAutoplay();
2848      autoplayUserPaused = false;
2849    }
2850  }
2851  function pause () {
2852    if (animating) {
2853      stopAutoplay();
2854      autoplayUserPaused = true;
2855    }
2856  }
2857
2858  function toggleAutoplay () {
2859    if (animating) {
2860      stopAutoplay();
2861      autoplayUserPaused = true;
2862    } else {
2863      startAutoplay();
2864      autoplayUserPaused = false;
2865    }
2866  }
2867
2868  function onVisibilityChange () {
2869    if (doc.hidden) {
2870      if (animating) {
2871        stopAutoplayTimer();
2872        autoplayVisibilityPaused = true;
2873      }
2874    } else if (autoplayVisibilityPaused) {
2875      setAutoplayTimer();
2876      autoplayVisibilityPaused = false;
2877    }
2878  }
2879
2880  function mouseoverPause () {
2881    if (animating) {
2882      stopAutoplayTimer();
2883      autoplayHoverPaused = true;
2884    }
2885  }
2886
2887  function mouseoutRestart () {
2888    if (autoplayHoverPaused) {
2889      setAutoplayTimer();
2890      autoplayHoverPaused = false;
2891    }
2892  }
2893
2894  // keydown events on document
2895  function onDocumentKeydown (e) {
2896    e = getEvent(e);
2897    var keyIndex = [KEYS.LEFT, KEYS.RIGHT].indexOf(e.keyCode);
2898
2899    if (keyIndex >= 0) {
2900      onControlsClick(e, keyIndex === 0 ? -1 : 1);
2901    }
2902  }
2903
2904  // on key control
2905  function onControlsKeydown (e) {
2906    e = getEvent(e);
2907    var keyIndex = [KEYS.LEFT, KEYS.RIGHT].indexOf(e.keyCode);
2908
2909    if (keyIndex >= 0) {
2910      if (keyIndex === 0) {
2911        if (!prevButton.disabled) { onControlsClick(e, -1); }
2912      } else if (!nextButton.disabled) {
2913        onControlsClick(e, 1);
2914      }
2915    }
2916  }
2917
2918  // set focus
2919  function setFocus (el) {
2920    el.focus();
2921  }
2922
2923  // on key nav
2924  function onNavKeydown (e) {
2925    e = getEvent(e);
2926    var curElement = doc.activeElement;
2927    if (!hasAttr(curElement, 'data-nav')) { return; }
2928
2929    // var code = e.keyCode,
2930    var keyIndex = [KEYS.LEFT, KEYS.RIGHT, KEYS.ENTER, KEYS.SPACE].indexOf(e.keyCode),
2931        navIndex = Number(getAttr(curElement, 'data-nav'));
2932
2933    if (keyIndex >= 0) {
2934      if (keyIndex === 0) {
2935        if (navIndex > 0) { setFocus(navItems[navIndex - 1]); }
2936      } else if (keyIndex === 1) {
2937        if (navIndex < pages - 1) { setFocus(navItems[navIndex + 1]); }
2938      } else {
2939        navClicked = navIndex;
2940        goTo(navIndex, e);
2941      }
2942    }
2943  }
2944
2945  function getEvent (e) {
2946    e = e || win.event;
2947    return isTouchEvent(e) ? e.changedTouches[0] : e;
2948  }
2949  function getTarget (e) {
2950    return e.target || win.event.srcElement;
2951  }
2952
2953  function isTouchEvent (e) {
2954    return e.type.indexOf('touch') >= 0;
2955  }
2956
2957  function preventDefaultBehavior (e) {
2958    e.preventDefault ? e.preventDefault() : e.returnValue = false;
2959  }
2960
2961  function getMoveDirectionExpected () {
2962    return getTouchDirection(toDegree(lastPosition.y - initPosition.y, lastPosition.x - initPosition.x), swipeAngle) === options.axis;
2963  }
2964
2965  function onPanStart (e) {
2966    if (running) {
2967      if (preventActionWhenRunning) { return; } else { onTransitionEnd(); }
2968    }
2969
2970    if (autoplay && animating) { stopAutoplayTimer(); }
2971
2972    panStart = true;
2973    if (rafIndex) {
2974      caf(rafIndex);
2975      rafIndex = null;
2976    }
2977
2978    var $ = getEvent(e);
2979    events.emit(isTouchEvent(e) ? 'touchStart' : 'dragStart', info(e));
2980
2981    if (!isTouchEvent(e) && ['img', 'a'].indexOf(getLowerCaseNodeName(getTarget(e))) >= 0) {
2982      preventDefaultBehavior(e);
2983    }
2984
2985    lastPosition.x = initPosition.x = $.clientX;
2986    lastPosition.y = initPosition.y = $.clientY;
2987    if (carousel) {
2988      translateInit = parseFloat(container.style[transformAttr].replace(transformPrefix, ''));
2989      resetDuration(container, '0s');
2990    }
2991  }
2992
2993  function onPanMove (e) {
2994    if (panStart) {
2995      var $ = getEvent(e);
2996      lastPosition.x = $.clientX;
2997      lastPosition.y = $.clientY;
2998
2999      if (carousel) {
3000        if (!rafIndex) { rafIndex = raf(function(){ panUpdate(e); }); }
3001      } else {
3002        if (moveDirectionExpected === '?') { moveDirectionExpected = getMoveDirectionExpected(); }
3003        if (moveDirectionExpected) { preventScroll = true; }
3004      }
3005
3006      if ((typeof e.cancelable !== 'boolean' || e.cancelable) && preventScroll) {
3007        e.preventDefault();
3008      }
3009    }
3010  }
3011
3012  function panUpdate (e) {
3013    if (!moveDirectionExpected) {
3014      panStart = false;
3015      return;
3016    }
3017    caf(rafIndex);
3018    if (panStart) { rafIndex = raf(function(){ panUpdate(e); }); }
3019
3020    if (moveDirectionExpected === '?') { moveDirectionExpected = getMoveDirectionExpected(); }
3021    if (moveDirectionExpected) {
3022      if (!preventScroll && isTouchEvent(e)) { preventScroll = true; }
3023
3024      try {
3025        if (e.type) { events.emit(isTouchEvent(e) ? 'touchMove' : 'dragMove', info(e)); }
3026      } catch(err) {}
3027
3028      var x = translateInit,
3029          dist = getDist(lastPosition, initPosition);
3030      if (!horizontal || fixedWidth || autoWidth) {
3031        x += dist;
3032        x += 'px';
3033      } else {
3034        var percentageX = TRANSFORM ? dist * items * 100 / ((viewport + gutter) * slideCountNew): dist * 100 / (viewport + gutter);
3035        x += percentageX;
3036        x += '%';
3037      }
3038
3039      container.style[transformAttr] = transformPrefix + x + transformPostfix;
3040    }
3041  }
3042
3043  function onPanEnd (e) {
3044    if (panStart) {
3045      if (rafIndex) {
3046        caf(rafIndex);
3047        rafIndex = null;
3048      }
3049      if (carousel) { resetDuration(container, ''); }
3050      panStart = false;
3051
3052      var $ = getEvent(e);
3053      lastPosition.x = $.clientX;
3054      lastPosition.y = $.clientY;
3055      var dist = getDist(lastPosition, initPosition);
3056
3057      if (Math.abs(dist)) {
3058        // drag vs click
3059        if (!isTouchEvent(e)) {
3060          // prevent "click"
3061          var target = getTarget(e);
3062          addEvents(target, {'click': function preventClick (e) {
3063            preventDefaultBehavior(e);
3064            removeEvents(target, {'click': preventClick});
3065          }});
3066        }
3067
3068        if (carousel) {
3069          rafIndex = raf(function() {
3070            if (horizontal && !autoWidth) {
3071              var indexMoved = - dist * items / (viewport + gutter);
3072              indexMoved = dist > 0 ? Math.floor(indexMoved) : Math.ceil(indexMoved);
3073              index += indexMoved;
3074            } else {
3075              var moved = - (translateInit + dist);
3076              if (moved <= 0) {
3077                index = indexMin;
3078              } else if (moved >= slidePositions[slideCountNew - 1]) {
3079                index = indexMax;
3080              } else {
3081                var i = 0;
3082                while (i < slideCountNew && moved >= slidePositions[i]) {
3083                  index = i;
3084                  if (moved > slidePositions[i] && dist < 0) { index += 1; }
3085                  i++;
3086                }
3087              }
3088            }
3089
3090            render(e, dist);
3091            events.emit(isTouchEvent(e) ? 'touchEnd' : 'dragEnd', info(e));
3092          });
3093        } else {
3094          if (moveDirectionExpected) {
3095            onControlsClick(e, dist > 0 ? -1 : 1);
3096          }
3097        }
3098      }
3099    }
3100
3101    // reset
3102    if (options.preventScrollOnTouch === 'auto') { preventScroll = false; }
3103    if (swipeAngle) { moveDirectionExpected = '?'; }
3104    if (autoplay && !animating) { setAutoplayTimer(); }
3105  }
3106
3107  // === RESIZE FUNCTIONS === //
3108  // (slidePositions, index, items) => vertical_conentWrapper.height
3109  function updateContentWrapperHeight () {
3110    var wp = middleWrapper ? middleWrapper : innerWrapper;
3111    wp.style.height = slidePositions[index + items] - slidePositions[index] + 'px';
3112  }
3113
3114  function getPages () {
3115    var rough = fixedWidth ? (fixedWidth + gutter) * slideCount / viewport : slideCount / items;
3116    return Math.min(Math.ceil(rough), slideCount);
3117  }
3118
3119  /*
3120   * 1. update visible nav items list
3121   * 2. add "hidden" attributes to previous visible nav items
3122   * 3. remove "hidden" attrubutes to new visible nav items
3123   */
3124  function updateNavVisibility () {
3125    if (!nav || navAsThumbnails) { return; }
3126
3127    if (pages !== pagesCached) {
3128      var min = pagesCached,
3129          max = pages,
3130          fn = showElement;
3131
3132      if (pagesCached > pages) {
3133        min = pages;
3134        max = pagesCached;
3135        fn = hideElement;
3136      }
3137
3138      while (min < max) {
3139        fn(navItems[min]);
3140        min++;
3141      }
3142
3143      // cache pages
3144      pagesCached = pages;
3145    }
3146  }
3147
3148  function info (e) {
3149    return {
3150      container: container,
3151      slideItems: slideItems,
3152      navContainer: navContainer,
3153      navItems: navItems,
3154      controlsContainer: controlsContainer,
3155      hasControls: hasControls,
3156      prevButton: prevButton,
3157      nextButton: nextButton,
3158      items: items,
3159      slideBy: slideBy,
3160      cloneCount: cloneCount,
3161      slideCount: slideCount,
3162      slideCountNew: slideCountNew,
3163      index: index,
3164      indexCached: indexCached,
3165      displayIndex: getCurrentSlide(),
3166      navCurrentIndex: navCurrentIndex,
3167      navCurrentIndexCached: navCurrentIndexCached,
3168      pages: pages,
3169      pagesCached: pagesCached,
3170      sheet: sheet,
3171      isOn: isOn,
3172      event: e || {},
3173    };
3174  }
3175
3176  return {
3177    version: '2.9.2',
3178    getInfo: info,
3179    events: events,
3180    goTo: goTo,
3181    play: play,
3182    pause: pause,
3183    isOn: isOn,
3184    updateSliderHeight: updateInnerWrapperHeight,
3185    refresh: initSliderTransform,
3186    destroy: destroy,
3187    rebuild: function() {
3188      return tns(extend(options, optionsElements));
3189    }
3190  };
3191};
3192
3193return tns;
3194})();

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.