Вход Регистрация
Файл: contao-3.5.8/assets/swipe/2.0/js/swipe.js
Строк: 898
<?php
/**
 * Swipe 2.0
 *
 * Brad Birdsall
 * Copyright 2013, MIT License
 *
 * Dot menu enhancements
 * Copyright (c) 2013-2014 Leo Feyer
 */

function Swipe(container, options) {

  
"use strict";

  
// utilities
  
var noop = function() {}; // simple no operation function
  
var offloadFn = function(fn) { setTimeout(fn || noop, 0) }; // offload a functions execution

  // check browser capabilities
  
var browser = {
    
addEventListener: !!window.addEventListener,
    
touch: ('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch,
    
transitions: (function(temp) {
      var 
props = ['transitionProperty', 'WebkitTransition', 'MozTransition', 'OTransition', 'msTransition'];
      for ( var 
i in props ) if (temp.style[ props[i] ] !== undefined) return true;
      return 
false;
    })(
document.createElement('swipe'))
  };

  
// quit if no root element
  
if (!container) return;
  var 
element = container.children[0];
  var 
slides, slidePos, width, length;
  
options = options || {};
  var 
index = parseInt(options.startSlide, 10) || 0;
  var 
position = index;
  var 
clonedSlides = false;
  var 
speed = options.speed || 300;
  
options.continuous = options.continuous !== undefined ? options.continuous : true;
  var 
nodes = {}, listeners = {};

  function 
setup() {

    
// cache slides
    
slides = element.children;

    
// filter comments (IE8)
    
for (var i=0; i<slides.length; i++) {
      if (
slides[i].nodeType == 8) {
        
element.removeChild(slides[i]);
        --
i;
      }
    }

    
length = slides.length;

    
// set continuous to false if only one slide
    
if (slides.length < 2) options.continuous = false;

    
// special case if two slides
    
if (browser.transitions && options.continuous && slides.length < 3) {
      
element.appendChild(slides[0].cloneNode(true));
      
element.appendChild(element.children[1].cloneNode(true));
      
slides = element.children;
      
clonedSlides = true;
    }

    
// create an array to store current positions of each slide
    
slidePos = new Array(slides.length);

    
// determine width of each slide
    
width = container.getBoundingClientRect().width || container.offsetWidth;

    
element.style.width = (slides.length * width) + 'px';

    
// stack elements
    
var pos = slides.length;
    while (
pos--) {

      var 
slide = slides[pos];

      
slide.style.width = width + 'px';
      
slide.setAttribute('data-index', pos.toString());

      if (
browser.transitions) {
        
slide.style.left = (pos * -width) + 'px';
        
move(pos, index > pos ? -width : (index < pos ? width : 0), 0);
      }

    }

    
// reposition elements before and after index
    
if (options.continuous && browser.transitions) {
      
move(circle(index-1), -width, 0);
      
move(circle(index+1), width, 0);
    }

    if (!
browser.transitions) element.style.left = (index * -width) + 'px';

    
container.style.visibility = 'visible';

  }

  function 
addEvent(el, type, fn) {

    if (
browser.addEventListener) el.addEventListener(type, fn, false);
    else if (
window.attachEvent) el.attachEvent('on' + type, fn);

  }

  function 
stopEvent(e) {

    
e.returnValue = false; // IE < 9
    
e.preventDefault && e.preventDefault();

  }

  function 
removeEvent(el, type, fn) {

    if (
browser.addEventListener) el.removeEventListener(type, fn, false);
    else if (
window.detachEvent) el.detachEvent('on' + type, fn);

  }

  function 
menu() {

    var 
childs = options.menu.childNodes;

    for (var 
h=0; h<childs.length; h++) {

      
// previous button
      
if (childs[h].className && childs[h].className.indexOf('slider-prev') != -1) {

        
listeners.prev = function(e) {
          
stopEvent(e);
          
stop();
          
prev();
        };

        
nodes.prev = childs[h];
        
addEvent(nodes.prev, 'click', listeners.prev);

      }

      
// next button
      
else if (childs[h].className && childs[h].className.indexOf('slider-next') != -1) {

        
listeners.next = function(e) {
          
stopEvent(e);
          
stop();
          
next();
        };

        
nodes.next = childs[h];
        
addEvent(nodes.next, 'click', listeners.next);

      }

      
// dot navigation
      
else if (childs[h].className && childs[h].className.indexOf('slider-menu') != -1) {

        for (var 
i=0; i<length; i++) {

          var 
b = document.createElement('b');
          
b.innerHTML = '•';
          
b.setAttribute('data-index', i.toString());

          if (
i == position) b.className = 'active';

          
addEvent(b, 'click', (function(b) {
            return (function(
e) {
              
stopEvent(e);
              
stop();
              
slide(parseInt((this.getAttribute ? this.getAttribute('data-index') : b.attributes['data-index'].nodeValue)));
            });
          })(
b));

          
childs[h].appendChild(b);

        }

        
nodes.dots = childs[h];

      }

    }

  }

  function 
updateMenu() {

    for (var 
i=0; i<length; i++) {

      var 
child = nodes.dots.children[i];
      
child.className = (parseInt(child.getAttribute ? child.getAttribute('data-index') : child.attributes['data-index'].nodeValue) == position) ? 'active' : '';

    }

  }

  function 
killMenu() {

    var 
childs = nodes.dots.childNodes;

    while (
childs.length > 0) {
        
nodes.dots.removeChild(childs[0]);
    }

    
removeEvent(nodes.prev, 'click', listeners.prev);
    
removeEvent(nodes.next, 'click', listeners.next);

  }

  function 
prev() {

    if (
options.continuous) slide(index-1);
    else if (
index) slide(index-1);

  }

  function 
next() {

    if (
options.continuous) slide(index+1);
    else if (
index < slides.length - 1) slide(index+1);

  }

  function 
circle(index) {

    
// a simple positive modulo using slides.length
    
return (slides.length + (index % slides.length)) % slides.length;

  }

  function 
slide(to, slideSpeed) {

    
// do nothing if already on requested slide
    
if (index == to) return;

    if (
browser.transitions) {

      var 
direction = Math.abs(index-to) / (index-to); // 1: backward, -1: forward

      // get the actual position of the slide
      
if (options.continuous) {
        var 
natural_direction = direction;
        
direction = -slidePos[circle(to)] / width;

        
// if going forward but to < index, use to = slides.length + to
        // if going backward but to > index, use to = -slides.length + to
        
if (direction !== natural_direction) to =  -direction * slides.length + to;

      }

      var 
diff = Math.abs(index-to) - 1;

      
// move all the slides between index and to in the right direction
      
while (diff--) move( circle((to > index ? to : index) - diff - 1), width * direction, 0);

      
to = circle(to);

      
move(index, width * direction, slideSpeed || speed);
      
move(to, 0, slideSpeed || speed);

      if (
options.continuous) move(circle(to - direction), -(width * direction), 0); // we need to get the next in place

    
} else {

      
to = circle(to);
      
animate(index * -width, to * -width, slideSpeed || speed);
      
//no fallback for a circular continuous if the browser does not accept transitions
    
}

    
index = to;
    
position = clonedSlides ? (index % 2) : index;

    
// update the menu
    
if (options.menu) updateMenu();

    
offloadFn(options.callback && options.callback(position, slides[index]));

  }

  function 
move(index, dist, speed) {

    
translate(index, dist, speed);
    
slidePos[index] = dist;

  }

  function 
translate(index, dist, speed) {

    var 
slide = slides[index];
    var 
style = slide && slide.style;

    if (!
style) return;

    
style.webkitTransitionDuration =
    
style.MozTransitionDuration =
    
style.msTransitionDuration =
    
style.OTransitionDuration =
    
style.transitionDuration = speed + 'ms';

    
style.webkitTransform = 'translate(' + dist + 'px,0)' + 'translateZ(0)';
    
style.msTransform =
    
style.MozTransform =
    
style.OTransform = 'translateX(' + dist + 'px)';

  }

  function 
animate(from, to, speed) {

    
// if not an animation, just reposition
    
if (!speed) {

      
element.style.left = to + 'px';
      return;

    }

    var 
start = +new Date;

    var 
timer = setInterval(function() {

      var 
timeElap = +new Date - start;

      if (
timeElap > speed) {

        
element.style.left = to + 'px';

        if (
delay) begin();

        
options.transitionEnd && options.transitionEnd.call(event, position, slides[index]);

        
clearInterval(timer);
        return;

      }

      
element.style.left = (( (to - from) * (Math.floor((timeElap / speed) * 100) / 100) ) + from) + 'px';

    }, 
4);

  }

  
// setup auto slideshow
  
var delay = options.auto || 0;
  var 
interval;

  function 
begin() {

    
interval = setTimeout(next, delay);

  }

  function 
stop() {

    
delay = 0;
    
clearTimeout(interval);

  }

  
// setup initial vars
  
var start = {};
  var 
delta = {};
  var 
isScrolling;

  
// setup event capturing
  
var events = {

    
handleEvent: function(event) {

      switch (
event.type) {
        case 
'touchstart': this.start(event); break;
        case 
'touchmove': this.move(event); break;
        case 
'touchend': offloadFn(this.end(event)); break;
        case 
'webkitTransitionEnd':
        case 
'msTransitionEnd':
        case 
'oTransitionEnd':
        case 
'otransitionend':
        case 
'transitionend': offloadFn(this.transitionEnd(event)); break;
        case 
'resize': offloadFn(setup); break;
      }

      if (
options.stopPropagation) event.stopPropagation();

    },
    
start: function(event) {

      var 
touches = event.touches[0];

      
// measure start values
      
start = {

        
// get initial touch coords
        
x: touches.pageX,
        
y: touches.pageY,

        
// store time to determine touch duration
        
time: +new Date

      
};

      
// used for testing first move event
      
isScrolling = undefined;

      
// reset delta and end measurements
      
delta = {};

      
// attach touchmove and touchend listeners
      
element.addEventListener('touchmove', this, false);
      
element.addEventListener('touchend', this, false);

    },
    
move: function(event) {

      
// ensure swiping with one touch and not pinching
      
if (event.touches.length > 1 || event.scale && event.scale !== 1) return;

      if (
options.disableScroll) event.preventDefault();

      var 
touches = event.touches[0];

      
// measure change in x and y
      
delta = {
        
x: touches.pageX - start.x,
        
y: touches.pageY - start.y
      
};

      
// determine if scrolling test has run - one time test
      
if (typeof isScrolling == 'undefined') {
        
isScrolling = !!( isScrolling || Math.abs(delta.x) < Math.abs(delta.y) );
      }

      
// if user is not trying to scroll vertically
      
if (!isScrolling) {

        
// prevent native scrolling
        
event.preventDefault();

        
// stop slideshow
        
stop();

        
// increase resistance if first or last slide
        
if (options.continuous) { // we don't add resistance at the end

          
translate(circle(index-1), delta.x + slidePos[circle(index-1)], 0);
          
translate(index, delta.x + slidePos[index], 0);
          
translate(circle(index+1), delta.x + slidePos[circle(index+1)], 0);

        } else {

          
delta.x =
            
delta.x /
              ( (!
index && delta.x > 0               // if first slide and sliding left
                
|| index == slides.length - 1        // or if last slide and sliding right
                
&& delta.x < 0                       // and if sliding at all
              
) ?
              ( 
Math.abs(delta.x) / width + 1 )      // determine resistance level
              
: 1 );                                 // no resistance if false

          // translate 1:1
          
translate(index-1, delta.x + slidePos[index-1], 0);
          
translate(index, delta.x + slidePos[index], 0);
          
translate(index+1, delta.x + slidePos[index+1], 0);
        }

      }

    },
    
end: function() {

      
// measure duration
      
var duration = +new Date - start.time;

      
// determine if slide attempt triggers next/prev slide
      
var isValidSlide =
            
Number(duration) < 250               // if slide duration is less than 250ms
            
&& Math.abs(delta.x) > 20            // and if slide amt is greater than 20px
            
|| Math.abs(delta.x) > width/2;      // or if slide amt is greater than half the width

      // determine if slide attempt is past start and end
      
var isPastBounds =
            !
index && delta.x > 0                            // if first slide and slide amt is greater than 0
            
|| index == slides.length - 1 && delta.x < 0;    // or if last slide and slide amt is less than 0

      
if (options.continuous) isPastBounds = false;

      
// determine direction of swipe (true:right, false:left)
      
var direction = delta.x < 0;

      
// if not scrolling vertically
      
if (!isScrolling) {

        if (
isValidSlide && !isPastBounds) {

          if (
direction) {

            if (
options.continuous) { // we need to get the next in this direction in place

              
move(circle(index-1), -width, 0);
              
move(circle(index+2), width, 0);

            } else {
              
move(index-1, -width, 0);
            }

            
move(index, slidePos[index]-width, speed);
            
move(circle(index+1), slidePos[circle(index+1)]-width, speed);
            
index = circle(index+1);

          } else {
            if (
options.continuous) { // we need to get the next in this direction in place

              
move(circle(index+1), width, 0);
              
move(circle(index-2), -width, 0);

            } else {
              
move(index+1, width, 0);
            }

            
move(index, slidePos[index]+width, speed);
            
move(circle(index-1), slidePos[circle(index-1)]+width, speed);
            
index = circle(index-1);

          }

          
position = clonedSlides ? (index % 2) : index;

          
// update the menu
          
if (options.menu) updateMenu();

          
options.callback && options.callback(position, slides[index]);

        } else {

          if (
options.continuous) {

            
move(circle(index-1), -width, speed);
            
move(index, 0, speed);
            
move(circle(index+1), width, speed);

          } else {

            
move(index-1, -width, speed);
            
move(index, 0, speed);
            
move(index+1, width, speed);
          }

        }

      }

      
// kill touchmove and touchend event listeners until touchstart called again
      
element.removeEventListener('touchmove', events, false);
      
element.removeEventListener('touchend', events, false);

    },
    
transitionEnd: function(event) {

      if (
parseInt(event.target.getAttribute('data-index'), 10) == index) {

        if (
delay) begin();

        
options.transitionEnd && options.transitionEnd.call(event, position, slides[index]);

      }

    }

  };

  
// trigger setup
  
setup();

  
// set up the menu
  
if (options.menu) menu();

  
// start auto slideshow if applicable
  
if (delay) begin();

  
// add event listeners
  
if (browser.addEventListener) {

    
// set touchstart event on element
    
if (browser.touch) element.addEventListener('touchstart', events, false);

    if (
browser.transitions) {
      
element.addEventListener('webkitTransitionEnd', events, false);
      
element.addEventListener('msTransitionEnd', events, false);
      
element.addEventListener('oTransitionEnd', events, false);
      
element.addEventListener('otransitionend', events, false);
      
element.addEventListener('transitionend', events, false);
    }

    
// set resize event on window
    
window.addEventListener('resize', events, false);

  } else {

    
window.onresize = function () { setup() }; // to play nice with old IE

  
}

  
// expose the Swipe API
  
return {
    
setup: function() {

      
setup();

    },
    
slide: function(to, speed) {

      
// cancel slideshow
      
stop();

      
slide(to, speed);

    },
    
prev: function() {

      
// cancel slideshow
      
stop();

      
prev();

    },
    
next: function() {

      
// cancel slideshow
      
stop();

      
next();

    },
    
stop: function() {

      
// cancel slideshow
      
stop();

    },
    
getPos: function() {

      
// return current index position
      
return position;

    },
    
getNumSlides: function() {

      
// return total number of slides
      
return length;

    },
    
kill: function() {

      
// cancel slideshow
      
stop();

      
// reset element
      
element.style.width = '';
      
element.style.left = '';

      
// reset slides
      
var pos = slides.length;
      while(
pos--) {

        var 
slide = slides[pos];
        
slide.style.width = '';
        
slide.style.left = '';

        if (
browser.transitions) translate(pos, 0, 0);

      }

      
// removed event listeners
      
if (browser.addEventListener) {

        
// remove current event listeners
        
element.removeEventListener('touchstart', events, false);
        
element.removeEventListener('webkitTransitionEnd', events, false);
        
element.removeEventListener('msTransitionEnd', events, false);
        
element.removeEventListener('oTransitionEnd', events, false);
        
element.removeEventListener('otransitionend', events, false);
        
element.removeEventListener('transitionend', events, false);
        
window.removeEventListener('resize', events, false);

      } else {

        
window.onresize = null;

      }

      
// kill the menu
      
killMenu();

    }
  }

}
?>
Онлайн: 2
Реклама