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