PageSourceSearch

https://www.bancobpi.pt/CW_SP_Common/Blocks/OutSystemsUIWeb/Content/Carousel.pt.js?12117

js bancobpi.pt collected 2026-10-02 14:31:49 UTC 103,156 bytes, 3,250 lines download raw bytes

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

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.