PageSourceSearch

https://www.acsh.org/themes/custom/b5acsh/js/tiny-slider.js?v=2.9.3

js acsh.org collected 2026-10-01 09:16:18 UTC 102,146 bytes, 3,241 lines download raw bytes

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

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.