PageSourceSearch

https://www.morrisseycentral.com/static/_common/slideshows/format-…19583d053e3e008a99afb7ba7a22369b590eb464.js

js morrisseycentral.com collected 2026-10-02 07:32:25 UTC 105,596 bytes, 3,196 lines download raw bytes

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

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.