Chapter is quite ok

ajax loaded content
graphics ok
interactivity ok
remains the video interactions
This commit is contained in:
Bachir Soussi Chiadmi
2015-03-10 20:23:17 +01:00
parent d5edfa75c8
commit dab5226cd7
30 changed files with 3508 additions and 399 deletions
@@ -0,0 +1,42 @@
{
"name": "Peppermint",
"version": "1.3.7",
"homepage": "http://wd.dizaina.net/en/scripts/peppermint/",
"authors": [
"Oleg Korsunsky <wd@dizaina.net>"
],
"description": "Responsive touch-enabled slider. Tiny, supports mouse and all sorts of touch, library agnostic.",
"main": [
"dist/peppermint.min.js",
"dist/peppermint.suggested.css"
],
"keywords": [
"touch",
"touch-events",
"pointer-events",
"mouse-events",
"slider",
"carousel",
"gallery",
"vanilla-js",
"framework-agnostic",
"library-agnostic"
],
"license": "MIT",
"ignore": [
"**/.*",
"node_modules",
"bower_components",
"test"
],
"_release": "1.3.7",
"_resolution": {
"type": "version",
"tag": "1.3.7",
"commit": "cec00832caa3a1940801a0b20f84c8b9c8518b1f"
},
"_source": "git://github.com/wilddeer/Peppermint.git",
"_target": "~1.3.7",
"_originalSource": "Peppermint",
"_direct": true
}
@@ -0,0 +1,111 @@
/*global module */
module.exports = function(grunt) {
'use strict';
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
banner: '/*!\n * Peppermint touch slider\n * v. <%= pkg.version %> | <%= pkg.homepage %>\n * Copyright <%= pkg.author.name %> | <%= pkg.author.url %>\n *\n * Depends on Event Burrito (included) | https://github.com/wilddeer/Event-Burrito\n * MIT License\n */\n',
bannerPure: '/*!\n * Peppermint touch slider\n * v. <%= pkg.version %> | <%= pkg.homepage %>\n * Copyright <%= pkg.author.name %> | <%= pkg.author.url %>\n *\n * Depends on Event Burrito | https://github.com/wilddeer/Event-Burrito\n * MIT License\n */\n',
uglify: {
options: {
mangle: {
except: ['Peppermint', '$', 'jQuery', 'EventBurrito']
}
},
peppermint: {
files: {
'temp/peppermint.min.js': ['src/peppermint.js']
}
},
burrito: {
files: {
'temp/eventburrito.min.js': ['src/burrito/eventburrito.js']
}
}
},
concat: {
options: {
banner: '<%= banner %>',
separator: '\n'
},
full: {
src: ['src/peppermint.js','src/burrito/eventburrito.js'],
dest: 'dist/peppermint.js',
},
min: {
src: ['temp/peppermint.min.js','temp/eventburrito.min.js'],
dest: 'dist/peppermint.min.js',
},
pureFull: {
options: {
banner: '<%= bannerPure %>'
},
src: ['src/peppermint.js'],
dest: 'dist/pure/peppermint.pure.js'
},
pureMin: {
options: {
banner: '<%= bannerPure %>'
},
src: ['temp/peppermint.min.js'],
dest: 'dist/pure/peppermint.pure.min.js'
},
cssRequired: {
options: {
banner: '/* Peppermint minimal required styles */\n\n'
},
src: ['src/peppermint.required.css'],
dest: 'dist/peppermint.required.css'
},
cssSuggested: {
options: {
banner: '/* Peppermint required styles + default appearance styles */\n\n',
separator: '\n\n/* default appearance styles */\n'
},
src: ['src/peppermint.required.css', 'src/peppermint.appearance.css'],
dest: 'dist/peppermint.suggested.css'
}
},
bump: {
options: {
files: ['package.json', 'bower.json'],
updateConfigs: ['pkg'],
commit: true,
commitMessage: 'tagging v. %VERSION%',
commitFiles: ['.'],
createTag: true,
tagName: '%VERSION%',
tagMessage: 'tagging v. %VERSION%',
push: false
}
},
shell: {
push: {
command: 'git push'
},
pushTags: {
command: 'git push --tags'
}
},
watch: {
files: ['src/**/*.js', 'src/**/*.css', 'package.json'],
tasks: ['build']
},
});
// build
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-bump');
grunt.loadNpmTasks('grunt-shell');
grunt.registerTask('build', ['uglify', 'concat']);
grunt.registerTask('release', ['bump-only:patch', 'uglify', 'concat', 'bump-commit', 'shell:push', 'shell:pushTags']);
grunt.registerTask('w', ['build', 'watch']);
grunt.registerTask('default', 'build');
};
@@ -0,0 +1,224 @@
#Peppermint touch slider
[Check out the demo](http://wd.dizaina.net/en/scripts/peppermint/)
Yet another touch slider. Only better.
- Works with mouse, [Touch Events](http://www.w3.org/TR/touch-events/), [Pointer Events](http://www.w3.org/TR/pointerevents/), old [IE10 Pointer Events](http://msdn.microsoft.com/en-us/library/ie/hh673557\(v=vs.85\).aspx)
- Responsive, works on iPhones, Androids, Windows Phones, Blackberries, Windows 8 devices
- IE7+ compatible
- Library agnostic. If jQuery is available, registers itself as a plugin.
- Uses CSS3 transforms &amp; animations, falls back to timer animations when necessary
- Only 7.7 Kb minified
- Perfomance-optimized `touch` functions
- API and callback functions for extensibility
- [Doesn't break](http://wd.dizaina.net/en/internet-maintenance/js-sliders-and-the-tab-key/) when <kbd>tab</kbd>&rsquo;bing
##Kit
- **[peppermint.min.js](https://raw.github.com/wilddeer/Peppermint/master/dist/peppermint.min.js)** – minified production script
- **[peppermint.required.css](https://raw.github.com/wilddeer/Peppermint/master/dist/peppermint.required.css)** – styles required for proper functioning
- **[peppermint.suggested.css](https://raw.github.com/wilddeer/Peppermint/master/dist/peppermint.suggested.css)** – default styles to start with (required styles included)
Also available in [Bower](http://bower.io):
```
bower install Peppermint --save
```
##Usage
HTML markup:
```html
<div class="peppermint peppermint-inactive" id="peppermint">
<figure> ... </figure>
<figure> ... </figure>
<figure> ... </figure>
</div>
```
Javascript:
```javascript
var slider = Peppermint(document.getElementById('peppermint'));
```
Or javascript + jQuery:
```javascript
$('.peppermint').Peppermint();
```
`peppermint-inactive` class is not required. It is replaced with `peppermint-active` during setup.
You are free to use any other tag instead of `figure`. When using `figure`, don't forget to include [html5shiv](https://github.com/aFarkas/html5shiv), otherwise it won't work in old IEs.
Place anything you want within the slides.
##Settings
Peppermint can take settings object as an optional second parameter (first when using jQuery). Default settings:
```javascript
{
//transition time when changing slides, ms
speed: 300,
//transition time when changing slides after touch, ms
touchSpeed: 300,
//slideshow enabled
slideshow: false,
//slideshow interval, ms
slideshowInterval: 4000,
//stop slideshow after user interacts with the slider
stopSlideshowAfterInteraction: false,
//slide number to start with
startSlide: 0,
//use mouse to drag the slider
mouseDrag: true,
//don't initialize Peppermint if there's only one slide
disableIfOneSlide: true,
//Prefix to be used with Peppermint classes,
//such as `inactive`, `active`, `mouse`, `drag`, etc.
//Don't forget to change the stylesheet appropriately!
cssPrefix: 'peppermint-',
//show dots
dots: false,
//prepend dots to dotsContainer (default is append)
dotsPrepend: false,
//Element to contain dots, defaults to Peppermint's root element.
//Can be anywhere on the page.
dotsContainer: undefined,
//element containing slides, defaults to Peppermint's root element
slidesContainer: undefined,
//Callback function, runs at slide change.
//Receives slide number as a parameter.
onSlideChange: undefined,
//Callback function, runs at setup end.
//Receives total number of slides as a parameter.
onSetup: undefined
}
```
####Examples
JS:
```javascript
var slider = Peppermint(document.getElementById('peppermint'), {
dots: true,
slideshow: true,
speed: 500,
slideshowInterval: 5000,
stopSlideshowAfterInteraction: true,
onSetup: function(n) {
console.log('Peppermint setup done. Slides found: ' + n);
}
});
```
JS + jQuery:
```javascript
$('.peppermint').Peppermint({
dots: true,
slideshow: true,
speed: 500,
slideshowInterval: 5000,
stopSlideshowAfterInteraction: true,
onSetup: function(n) {
console.log('Peppermint setup done. Slides found: ' + n);
}
});
```
##API
Peppermint exposes a set of functions upon installation. These functions can be used to controll the slider externally:
`slideTo(n)` – change active slide to `n`;
`next()` – next slide;
`prev()` – previous slide;
`start()` – start slideshow;
`stop()` – stop slideshow;
`pause()` – pause slideshow until the next slide change;
`getCurrentPos()` – get current slide number;
`getSlidesNumber()` – get total number of slides;
`recalcWidth()` – recalculate slider's and slides' widths. Usefull when the container width is changed. Width recalculation runs automatically on window resize and device orientation change.
####Examples
JS:
```javascript
//init Peppermint and save the API object
var slider = Peppermint(document.getElementById('peppermint')),
//save links to HTML nodes
rightArr = document.getElementById('right-arr'),
leftArr = document.getElementById('left-arr'),
getSlidesNumberButton = document.getElementById('getslidesnumber');
//click `#right-arr` to go to the next slide
rightArr.addEventListener('click', slider.next, false);
//click `#left-arr` to go to the previous slide
leftArr.addEventListener('click', slider.prev, false);
//click `#getslidesnumber` to alert total number of slides
getSlidesNumberButton.addEventListener('click', function() {
alert('There are ' + slider.getSlidesNumber() + ' slides');
}, false);
```
JS + jQuery:
```javascript
//save jQuery link to slider's block
var slider = $('#peppermint');
//init Peppermint
slider.Peppermint();
//click `#right-arr` to go to the next slide
$('#right-arr').click(slider.data('Peppermint').next);
//click `#left-arr` to go to the previous slide
$('#left-arr').click(slider.data('Peppermint').prev);
//click `#getslidesnumber` to alert total number of slides
$('#getslidesnumber').click(function() {
alert('There are ' + slider.data('Peppermint').getSlidesNumber() + ' slides');
});
```
##Using Peppermint?
Drop me a link &rarr; [:envelope: wd@dizaina.net](mailto:wd@dizaina.net).
##License
[MIT license](http://opensource.org/licenses/MIT).
@@ -0,0 +1,32 @@
{
"name": "Peppermint",
"version": "1.3.7",
"homepage": "http://wd.dizaina.net/en/scripts/peppermint/",
"authors": [
"Oleg Korsunsky <wd@dizaina.net>"
],
"description": "Responsive touch-enabled slider. Tiny, supports mouse and all sorts of touch, library agnostic.",
"main": [
"dist/peppermint.min.js",
"dist/peppermint.suggested.css"
],
"keywords": [
"touch",
"touch-events",
"pointer-events",
"mouse-events",
"slider",
"carousel",
"gallery",
"vanilla-js",
"framework-agnostic",
"library-agnostic"
],
"license": "MIT",
"ignore": [
"**/.*",
"node_modules",
"bower_components",
"test"
]
}
@@ -0,0 +1,716 @@
/*!
* Peppermint touch slider
* v. 1.3.7 | https://github.com/wilddeer/Peppermint
* Copyright Oleg Korsunsky | http://wd.dizaina.net/
*
* Depends on Event Burrito (included) | https://github.com/wilddeer/Event-Burrito
* MIT License
*/
function Peppermint(_this, options) {
var slider = {
slides: [],
dots: [],
left: 0
},
slidesNumber,
flickThreshold = 200, //Flick threshold (ms)
activeSlide = 0,
slideWidth,
dotBlock,
slideBlock,
slideshowTimeoutId,
slideshowActive,
animationTimer;
//default options
var o = {
speed: 300, //transition between slides in ms
touchSpeed: 300, //transition between slides in ms after touch
slideshow: false, //launch slideshow at start
slideshowInterval: 4000,
stopSlideshowAfterInteraction: false, //stop slideshow after user interaction
startSlide: 0, //first slide to show
mouseDrag: true, //enable mouse drag
disableIfOneSlide: true,
cssPrefix: 'peppermint-',
dots: false, //show dots
dotsPrepend: false, //dots before slides
dotsContainer: undefined,
slidesContainer: undefined,
onSlideChange: undefined, //slide change callback
onSetup: undefined //setup callback
};
//merge user options into defaults
options && mergeObjects(o, options);
var classes = {
inactive: o.cssPrefix + 'inactive',
active: o.cssPrefix + 'active',
mouse: o.cssPrefix + 'mouse',
drag: o.cssPrefix + 'drag',
slides: o.cssPrefix + 'slides',
dots: o.cssPrefix + 'dots',
activeDot: o.cssPrefix + 'active-dot',
mouseClicked: o.cssPrefix + 'mouse-clicked'
};
//feature detects
var support = {
transforms: testProp('transform'),
transitions: testProp('transition')
};
function mergeObjects(targetObj, sourceObject) {
for (var key in sourceObject) {
if (sourceObject.hasOwnProperty(key)) {
targetObj[key] = sourceObject[key];
}
}
}
function testProp(prop) {
var prefixes = ['Webkit', 'Moz', 'O', 'ms'],
block = document.createElement('div');
if (block.style[prop] !== undefined) return true;
prop = prop.charAt(0).toUpperCase() + prop.slice(1);
for (var i in prefixes) {
if (block.style[prefixes[i]+prop] !== undefined) return true;
}
return false;
}
function addClass(el, cl) {
if (!new RegExp('(\\s|^)'+cl+'(\\s|$)').test(el.className)) {
el.className += ' ' + cl;
}
}
function removeClass(el, cl) {
el.className = el.className.replace(new RegExp('(\\s+|^)'+cl+'(\\s+|$)', 'g'), ' ').replace(/^\s+|\s+$/g, '');
}
//n - slide number (starting from 0)
//speed - transition in ms, can be omitted
function changeActiveSlide(n, speed) {
if (n<0) {
n = 0;
}
else if (n>slidesNumber-1) {
n = slidesNumber-1;
}
//change active dot
for (var i = slider.dots.length - 1; i >= 0; i--) {
removeClass(slider.dots[i], classes.activeDot);
}
addClass(slider.dots[n], classes.activeDot);
activeSlide = n;
changePos(-n*slider.width, (speed===undefined?o.speed:speed));
//reset slideshow timeout whenever active slide is changed for whatever reason
stepSlideshow();
//API callback
o.onSlideChange && o.onSlideChange(n);
return n;
}
//changes position of the slider (in px) with given speed (in ms)
function changePos(pos, speed) {
var time = speed?speed+'ms':'';
slideBlock.style.webkitTransitionDuration =
slideBlock.style.MozTransitionDuration =
slideBlock.style.msTransitionDuration =
slideBlock.style.OTransitionDuration =
slideBlock.style.transitionDuration = time;
setPos(pos);
}
//fallback to `setInterval` animations for UAs with no CSS transitions
function changePosFallback(pos, speed) {
animationTimer && clearInterval(animationTimer);
if (!speed) {
setPos(pos);
return;
}
var startTime = +new Date,
startPos = slider.left;
animationTimer = setInterval(function() {
//rough bezier emulation
var diff, y,
elapsed = +new Date - startTime,
f = elapsed / speed,
bezier = [0, 0.7, 1, 1];
function getPoint(p1, p2) {
return (p2-p1)*f + p1;
}
if (f >= 1) {
setPos(pos);
clearInterval(animationTimer);
return;
}
diff = pos - startPos;
y = getPoint(
getPoint(getPoint(bezier[0], bezier[1]), getPoint(bezier[1], bezier[2])),
getPoint(getPoint(bezier[1], bezier[2]), getPoint(bezier[2], bezier[3]))
);
setPos(Math.floor(y*diff + startPos));
}, 15);
}
//sets position of the slider (in px)
function setPos(pos) {
slideBlock.style.webkitTransform = 'translate('+pos+'px,0) translateZ(0)';
slideBlock.style.msTransform =
slideBlock.style.MozTransform =
slideBlock.style.OTransform =
slideBlock.style.transform = 'translateX('+pos+'px)';
slider.left = pos;
}
//`setPos` fallback for UAs with no CSS transforms support
function setPosFallback(pos) {
slideBlock.style.left = pos+'px';
slider.left = pos;
}
function nextSlide() {
var n = activeSlide + 1;
if (n > slidesNumber - 1) {
n = 0;
}
return changeActiveSlide(n);
}
function prevSlide() {
var n = activeSlide - 1;
if (n < 0) {
n = slidesNumber - 1;
}
return changeActiveSlide(n);
}
function startSlideshow() {
slideshowActive = true;
stepSlideshow();
}
//sets or resets timeout before switching to the next slide
function stepSlideshow() {
if (slideshowActive) {
slideshowTimeoutId && clearTimeout(slideshowTimeoutId);
slideshowTimeoutId = setTimeout(function() {
nextSlide();
},
o.slideshowInterval);
}
}
//pauses slideshow until `stepSlideshow` is invoked
function pauseSlideshow() {
slideshowTimeoutId && clearTimeout(slideshowTimeoutId);
}
function stopSlideshow() {
slideshowActive = false;
slideshowTimeoutId && clearTimeout(slideshowTimeoutId);
}
//this should be invoked when the width of the slider is changed
function onWidthChange() {
slider.width = _this.offsetWidth;
//have to do this in `px` because of webkit's rounding errors :-(
slideBlock.style.width = slider.width*slidesNumber+'px';
for (var i = 0; i < slidesNumber; i++) {
slider.slides[i].style.width = slider.width+'px';
}
changePos(-activeSlide*slider.width);
}
function addEvent(el, event, func, bool) {
if (!event) return;
el.addEventListener? el.addEventListener(event, func, !!bool): el.attachEvent('on'+event, func);
}
//init touch events
function touchInit() {
EventBurrito(slideBlock, {
mouse: o.mouseDrag,
start: function(event, start) {
//firefox doesn't want to apply cursor from `:active` CSS rule, have to add a class :-/
addClass(_this, classes.drag);
},
move: function(event, start, diff, speed) {
pauseSlideshow(); //pause the slideshow when touch is in progress
//if it's first slide and moving left or last slide and moving right -- resist!
diff.x =
diff.x /
(
(!activeSlide && diff.x > 0
|| activeSlide == slidesNumber - 1 && diff.x < 0)
?
(Math.abs(diff.x)/slider.width*2 + 1)
:
1
);
//change position of the slider appropriately
changePos(diff.x - slider.width*activeSlide);
},
end: function(event, start, diff, speed) {
if (diff.x) {
var ratio = Math.abs(diff.x)/slider.width,
//How many slides to skip. Remainder > 0.25 counts for one slide.
skip = Math.floor(ratio) + (ratio - Math.floor(ratio) > 0.25?1:0),
//Super-duper formula to detect a flick.
//First, it's got to be fast enough.
//Second, if `skip==0`, 20px move is enough to switch to the next slide.
//If `skip>0`, it's enough to slide to the middle of the slide minus `slider.width/9` to skip even further.
flick = diff.time < flickThreshold+flickThreshold*skip/1.8 && Math.abs(diff.x) - skip*slider.width > (skip?-slider.width/9:20);
skip += (flick?1:0);
if (diff.x < 0) {
changeActiveSlide(activeSlide+skip, o.touchSpeed);
}
else {
changeActiveSlide(activeSlide-skip, o.touchSpeed);
}
o.stopSlideshowAfterInteraction && stopSlideshow();
}
//remove the drag class
removeClass(_this, classes.drag);
}
});
}
function setup() {
var slideSource = o.slidesContainer || _this,
dotsTarget = o.dotsContainer || _this;
if (o.disableIfOneSlide && slideSource.children.length <= 1) return;
//If current UA doesn't support css transforms or transitions -- use fallback functions.
//(Using separate functions instead of checks for better performance)
if (!support.transforms || !!window.opera) setPos = setPosFallback;
if (!support.transitions || !!window.opera) changePos = changePosFallback;
slideBlock = o.slidesContainer || document.createElement('div');
addClass(slideBlock, classes.slides);
//get slides & generate dots
for (var i = 0, l = slideSource.children.length; i < l; i++) {
var slide = slideSource.children[i],
dot = document.createElement('li');
slider.slides.push(slide);
//`tabindex` makes dots tabbable
dot.setAttribute('tabindex', '0');
dot.setAttribute('role', 'button');
dot.innerHTML = '<span></span>';
(function(x, dotClosure) {
//bind events to dots
addEvent(dotClosure, 'click', function(event) {
changeActiveSlide(x);
o.stopSlideshowAfterInteraction && stopSlideshow();
});
//Bind the same function to Enter key except for the `blur` part -- I dont't want
//the focus to be lost when the user is using his keyboard to navigate.
addEvent(dotClosure, 'keyup', function(event) {
if (event.keyCode == 13) {
changeActiveSlide(x);
o.stopSlideshowAfterInteraction && stopSlideshow();
}
});
//Don't want to disable outlines completely for accessibility reasons.
//Instead, add class with `outline: 0` on mouseup and remove it on blur.
addEvent(dotClosure, 'mouseup', function(event) {
addClass(dotClosure, classes.mouseClicked);
});
//capturing fixes IE bug
addEvent(dotClosure, 'blur', function(){
removeClass(dotClosure, classes.mouseClicked);
}, true);
//This solves tabbing problems:
//When an element inside a slide catches focus we switch to that slide
//and reset `scrollLeft` of the slider block.
//`SetTimeout` solves Chrome's bug.
//Event capturing is used to catch events on the slide level.
//Since older IEs don't have capturing, `onfocusin` is used as a fallback.
addEvent(slide, 'focus', slide.onfocusin = function(e) {
_this.scrollLeft = 0;
setTimeout(function() {
_this.scrollLeft = 0;
}, 0);
changeActiveSlide(x);
}, true);
})(i, dot)
slider.dots.push(dot);
}
slidesNumber = slider.slides.length;
slideWidth = 100/slidesNumber;
addClass(_this, classes.active);
removeClass(_this, classes.inactive);
o.mouseDrag && addClass(_this, classes.mouse);
slider.width = _this.offsetWidth;
//had to do this in `px` because of webkit's rounding errors :-(
slideBlock.style.width = slider.width*slidesNumber+'px';
for (var i = 0; i < slidesNumber; i++) {
slider.slides[i].style.width = slider.width+'px';
slideBlock.appendChild(slider.slides[i]);
}
if (!o.slidesContainer) _this.appendChild(slideBlock);
//append dots
if (o.dots && slidesNumber > 1) {
dotBlock = document.createElement('ul');
addClass(dotBlock, classes.dots);
for (var i = 0, l = slider.dots.length; i < l; i++) {
dotBlock.appendChild(slider.dots[i]);
}
if (o.dotsPrepend) {
dotsTarget.insertBefore(dotBlock,dotsTarget.firstChild);
}
else {
dotsTarget.appendChild(dotBlock);
}
}
//watch for slider width changes
addEvent(window, 'resize', onWidthChange);
addEvent(window, 'orientationchange', onWidthChange);
//init first slide, timeout to expose the API first
setTimeout(function() {
changeActiveSlide(o.startSlide, 0);
}, 0);
//init slideshow
if (o.slideshow) startSlideshow();
touchInit();
//API callback, timeout to expose the API first
setTimeout(function() {
o.onSetup && o.onSetup(slidesNumber);
}, 0);
}
//Init
setup();
//expose the API
return {
slideTo: function(slide) {
return changeActiveSlide(parseInt(slide, 10));
},
next: nextSlide,
prev: prevSlide,
//start slideshow
start: startSlideshow,
//stop slideshow
stop: stopSlideshow,
//pause slideshow until the next slide change
pause: pauseSlideshow,
//get current slide number
getCurrentPos: function() {
return activeSlide;
},
//get total number of slides
getSlidesNumber: function() {
return slidesNumber;
},
//invoke this when the slider's width is changed
recalcWidth: onWidthChange
};
};
//if jQuery is present -- create a plugin
if (window.jQuery) {
(function($) {
$.fn.Peppermint = function(options) {
this.each(function() {
$(this).data('Peppermint', Peppermint(this, options));
});
return this;
};
})(window.jQuery);
}
/*!
* Event Burrito is a touch / mouse / pointer event unifier
* https://github.com/wilddeer/Event-Burrito
* Copyright Oleg Korsunsky | http://wd.dizaina.net/
*
* MIT License
*/
function EventBurrito(_this, options) {
var noop = function() {},
o = {
preventDefault: true,
clickTolerance: 0,
preventScroll: false,
mouse: true,
start: noop,
move: noop,
end: noop,
click: noop
};
//merge user options into defaults
options && mergeObjects(o, options);
var support = {
pointerEvents: !!window.navigator.pointerEnabled,
msPointerEvents: !!window.navigator.msPointerEnabled
},
start = {},
diff = {},
speed = {},
stack = [],
listeners = [],
isScrolling,
eventType,
clicksAllowed = true, //flag allowing default click actions (e.g. links)
eventModel = (support.pointerEvents? 1 : (support.msPointerEvents? 2 : 0)),
events = [
['touchstart', 'touchmove', 'touchend', 'touchcancel'], //touch events
['pointerdown', 'pointermove', 'pointerup', 'pointercancel'], //pointer events
['MSPointerDown', 'MSPointerMove', 'MSPointerUp', 'MSPointerCancel'], //IE10 pointer events
['mousedown', 'mousemove', 'mouseup', false] //mouse events
],
//some checks for different event types
checks = [
//touch events
function(e) {
//skip the event if it's multitouch or pinch move
return (e.touches && e.touches.length > 1) || (e.scale && e.scale !== 1);
},
//pointer events
function(e) {
//Skip it, if:
//1. event is not primary (other pointers during multitouch),
//2. left mouse button is not pressed,
//3. mouse drag is disabled and event is not touch
return !e.isPrimary || (e.buttons && e.buttons !== 1) || (!o.mouse && e.pointerType !== 'touch' && e.pointerType !== 'pen');
},
//IE10 pointer events
function(e) {
//same checks as in pointer events
return !e.isPrimary || (e.buttons && e.buttons !== 1) || (!o.mouse && e.pointerType !== e.MSPOINTER_TYPE_TOUCH && e.pointerType !== e.MSPOINTER_TYPE_PEN);
},
//mouse events
function(e) {
//skip the event if left mouse button is not pressed
//in IE7-8 `buttons` is not defined, in IE9 LMB is 0
return (e.buttons && e.buttons !== 1);
}
];
function mergeObjects(targetObj, sourceObject) {
for (var key in sourceObject) {
if (sourceObject.hasOwnProperty(key)) {
targetObj[key] = sourceObject[key];
}
}
}
function addEvent(el, event, func, bool) {
if (!event) return;
el.addEventListener? el.addEventListener(event, func, !!bool): el.attachEvent('on'+event, func);
//return event remover to easily remove anonymous functions later
return {
remove: function() {
removeEvent(el, event, func, bool);
}
};
}
function removeEvent(el, event, func, bool) {
if (!event) return;
el.removeEventListener? el.removeEventListener(event, func, !!bool): el.detachEvent('on'+event, func);
}
function preventDefault(event) {
event.preventDefault? event.preventDefault() : event.returnValue = false;
}
function getDiff(event) {
diff = {
x: (eventType? event.clientX : event.touches[0].clientX) - start.x,
y: (eventType? event.clientY : event.touches[0].clientY) - start.y,
time: Number(new Date) - start.time
};
if (diff.time - stack[stack.length - 1].time) {
for (var i = 0; i < stack.length - 1 && diff.time - stack[i].time > 80; i++);
speed = {
x: (diff.x - stack[i].x) / (diff.time - stack[i].time),
y: (diff.y - stack[i].y) / (diff.time - stack[i].time)
};
if (stack.length >= 5) stack.shift();
stack.push({x: diff.x, y: diff.y, time: diff.time});
}
}
function tStart(event, eType) {
clicksAllowed = true;
eventType = eType; //leak event type
if (checks[eventType](event)) return;
//attach event listeners to the document, so that the slider
//will continue to recieve events wherever the pointer is
addEvent(document, events[eventType][1], tMove);
addEvent(document, events[eventType][2], tEnd);
addEvent(document, events[eventType][3], tEnd);
//fixes WebKit's cursor while dragging
if (o.preventDefault && eventType) preventDefault(event);
//remember starting time and position
start = {
x: eventType? event.clientX : event.touches[0].clientX,
y: eventType? event.clientY : event.touches[0].clientY,
time: Number(new Date)
};
//reset
isScrolling = undefined;
diff = {x:0, y:0, time: 0};
speed = {x:0, y:0};
stack = [{x:0, y:0, time: 0}];
o.start(event, start);
}
function tMove(event) {
//if user is trying to scroll vertically -- do nothing
if ((!o.preventScroll && isScrolling) || checks[eventType](event)) return;
getDiff(event);
if (Math.abs(diff.x) > o.clickTolerance || Math.abs(diff.y) > o.clickTolerance) clicksAllowed = false; //if there was a move -- deny all the clicks before the next touchstart
//check whether the user is trying to scroll vertically
if (isScrolling === undefined && eventType !== 3) {
//assign and check `isScrolling` at the same time
if (isScrolling = (Math.abs(diff.x) < Math.abs(diff.y)) && !o.preventScroll) return;
}
if (o.preventDefault) preventDefault(event); //Prevent scrolling
o.move(event, start, diff, speed);
}
function tEnd(event) {
eventType && getDiff(event);
//IE likes to focus links after touchend.
//Since we don't want to disable link outlines completely for accessibility reasons,
//we just defocus it after touch and disable the outline for `:active` links in css.
//This way the outline will remain visible when using keyboard.
!clicksAllowed && event.target && event.target.blur && event.target.blur();
//detach event listeners from the document
removeEvent(document, events[eventType][1], tMove);
removeEvent(document, events[eventType][2], tEnd);
removeEvent(document, events[eventType][3], tEnd);
o.end(event, start, diff, speed);
}
function init() {
//bind touchstart
listeners.push(addEvent(_this, events[eventModel][0], function(e) {tStart(e, eventModel);}));
//prevent stuff from dragging when using mouse
listeners.push(addEvent(_this, 'dragstart', preventDefault));
//bind mousedown if necessary
if (o.mouse && !eventModel) {
listeners.push(addEvent(_this, events[3][0], function(e) {tStart(e, 3);}));
}
//No clicking during touch
listeners.push(addEvent(_this, 'click', function(event) {
clicksAllowed? o.click(event): preventDefault(event);
}));
}
init();
//expose the API
return {
getClicksAllowed: function() {
return clicksAllowed;
},
kill: function() {
for (var i = listeners.length - 1; i >= 0; i--) {
listeners[i].remove();
}
}
}
}
@@ -0,0 +1,10 @@
/*!
* Peppermint touch slider
* v. 1.3.7 | https://github.com/wilddeer/Peppermint
* Copyright Oleg Korsunsky | http://wd.dizaina.net/
*
* Depends on Event Burrito (included) | https://github.com/wilddeer/Event-Burrito
* MIT License
*/
function Peppermint(a,b){function c(a,b){for(var c in b)b.hasOwnProperty(c)&&(a[c]=b[c])}function d(a){var b=["Webkit","Moz","O","ms"],c=document.createElement("div");if(void 0!==c.style[a])return!0;a=a.charAt(0).toUpperCase()+a.slice(1);for(var d in b)if(void 0!==c.style[b[d]+a])return!0;return!1}function e(a,b){new RegExp("(\\s|^)"+b+"(\\s|$)").test(a.className)||(a.className+=" "+b)}function f(a,b){a.className=a.className.replace(new RegExp("(\\s+|^)"+b+"(\\s+|$)","g")," ").replace(/^\s+|\s+$/g,"")}function g(a,b){0>a?a=0:a>v-1&&(a=v-1);for(var c=C.dots.length-1;c>=0;c--)f(C.dots[c],G.activeDot);return e(C.dots[a],G.activeDot),E=a,h(-a*C.width,void 0===b?F.speed:b),o(),F.onSlideChange&&F.onSlideChange(a),a}function h(a,b){var c=b?b+"ms":"";y.style.webkitTransitionDuration=y.style.MozTransitionDuration=y.style.msTransitionDuration=y.style.OTransitionDuration=y.style.transitionDuration=c,j(a)}function i(a,b){if(B&&clearInterval(B),!b)return void j(a);var c=+new Date,d=C.left;B=setInterval(function(){function e(a,b){return(b-a)*i+a}var f,g,h=+new Date-c,i=h/b,k=[0,.7,1,1];return i>=1?(j(a),void clearInterval(B)):(f=a-d,g=e(e(e(k[0],k[1]),e(k[1],k[2])),e(e(k[1],k[2]),e(k[2],k[3]))),void j(Math.floor(g*f+d)))},15)}function j(a){y.style.webkitTransform="translate("+a+"px,0) translateZ(0)",y.style.msTransform=y.style.MozTransform=y.style.OTransform=y.style.transform="translateX("+a+"px)",C.left=a}function k(a){y.style.left=a+"px",C.left=a}function l(){var a=E+1;return a>v-1&&(a=0),g(a)}function m(){var a=E-1;return 0>a&&(a=v-1),g(a)}function n(){A=!0,o()}function o(){A&&(z&&clearTimeout(z),z=setTimeout(function(){l()},F.slideshowInterval))}function p(){z&&clearTimeout(z)}function q(){A=!1,z&&clearTimeout(z)}function r(){C.width=a.offsetWidth,y.style.width=C.width*v+"px";for(var b=0;v>b;b++)C.slides[b].style.width=C.width+"px";h(-E*C.width)}function s(a,b,c,d){b&&(a.addEventListener?a.addEventListener(b,c,!!d):a.attachEvent("on"+b,c))}function t(){EventBurrito(y,{mouse:F.mouseDrag,start:function(){e(a,G.drag)},move:function(a,b,c){p(),c.x=c.x/(!E&&c.x>0||E==v-1&&c.x<0?Math.abs(c.x)/C.width*2+1:1),h(c.x-C.width*E)},end:function(b,c,d){if(d.x){var e=Math.abs(d.x)/C.width,h=Math.floor(e)+(e-Math.floor(e)>.25?1:0),i=d.time<D+D*h/1.8&&Math.abs(d.x)-h*C.width>(h?-C.width/9:20);h+=i?1:0,d.x<0?g(E+h,F.touchSpeed):g(E-h,F.touchSpeed),F.stopSlideshowAfterInteraction&&q()}f(a,G.drag)}})}function u(){var b=F.slidesContainer||a,c=F.dotsContainer||a;if(!(F.disableIfOneSlide&&b.children.length<=1)){(!H.transforms||window.opera)&&(j=k),(!H.transitions||window.opera)&&(h=i),y=F.slidesContainer||document.createElement("div"),e(y,G.slides);for(var d=0,l=b.children.length;l>d;d++){var m=b.children[d],o=document.createElement("li");C.slides.push(m),o.setAttribute("tabindex","0"),o.setAttribute("role","button"),o.innerHTML="<span></span>",function(b,c){s(c,"click",function(){g(b),F.stopSlideshowAfterInteraction&&q()}),s(c,"keyup",function(a){13==a.keyCode&&(g(b),F.stopSlideshowAfterInteraction&&q())}),s(c,"mouseup",function(){e(c,G.mouseClicked)}),s(c,"blur",function(){f(c,G.mouseClicked)},!0),s(m,"focus",m.onfocusin=function(){a.scrollLeft=0,setTimeout(function(){a.scrollLeft=0},0),g(b)},!0)}(d,o),C.dots.push(o)}v=C.slides.length,w=100/v,e(a,G.active),f(a,G.inactive),F.mouseDrag&&e(a,G.mouse),C.width=a.offsetWidth,y.style.width=C.width*v+"px";for(var d=0;v>d;d++)C.slides[d].style.width=C.width+"px",y.appendChild(C.slides[d]);if(F.slidesContainer||a.appendChild(y),F.dots&&v>1){x=document.createElement("ul"),e(x,G.dots);for(var d=0,l=C.dots.length;l>d;d++)x.appendChild(C.dots[d]);F.dotsPrepend?c.insertBefore(x,c.firstChild):c.appendChild(x)}s(window,"resize",r),s(window,"orientationchange",r),setTimeout(function(){g(F.startSlide,0)},0),F.slideshow&&n(),t(),setTimeout(function(){F.onSetup&&F.onSetup(v)},0)}}var v,w,x,y,z,A,B,C={slides:[],dots:[],left:0},D=200,E=0,F={speed:300,touchSpeed:300,slideshow:!1,slideshowInterval:4e3,stopSlideshowAfterInteraction:!1,startSlide:0,mouseDrag:!0,disableIfOneSlide:!0,cssPrefix:"peppermint-",dots:!1,dotsPrepend:!1,dotsContainer:void 0,slidesContainer:void 0,onSlideChange:void 0,onSetup:void 0};b&&c(F,b);var G={inactive:F.cssPrefix+"inactive",active:F.cssPrefix+"active",mouse:F.cssPrefix+"mouse",drag:F.cssPrefix+"drag",slides:F.cssPrefix+"slides",dots:F.cssPrefix+"dots",activeDot:F.cssPrefix+"active-dot",mouseClicked:F.cssPrefix+"mouse-clicked"},H={transforms:d("transform"),transitions:d("transition")};return u(),{slideTo:function(a){return g(parseInt(a,10))},next:l,prev:m,start:n,stop:q,pause:p,getCurrentPos:function(){return E},getSlidesNumber:function(){return v},recalcWidth:r}}window.jQuery&&!function($){$.fn.Peppermint=function(a){return this.each(function(){$(this).data("Peppermint",Peppermint(this,a))}),this}}(window.jQuery);
function EventBurrito(a,b){function c(a,b){for(var c in b)b.hasOwnProperty(c)&&(a[c]=b[c])}function d(a,b,c,d){return b?(a.addEventListener?a.addEventListener(b,c,!!d):a.attachEvent("on"+b,c),{remove:function(){e(a,b,c,d)}}):void 0}function e(a,b,c,d){b&&(a.removeEventListener?a.removeEventListener(b,c,!!d):a.detachEvent("on"+b,c))}function f(a){a.preventDefault?a.preventDefault():a.returnValue=!1}function g(a){if(r={x:(o?a.clientX:a.touches[0].clientX)-q.x,y:(o?a.clientY:a.touches[0].clientY)-q.y,time:Number(new Date)-q.time},r.time-t[t.length-1].time){for(var b=0;b<t.length-1&&r.time-t[b].time>80;b++);s={x:(r.x-t[b].x)/(r.time-t[b].time),y:(r.y-t[b].y)/(r.time-t[b].time)},t.length>=5&&t.shift(),t.push({x:r.x,y:r.y,time:r.time})}}function h(a,b){v=!0,o=b,y[o](a)||(d(document,x[o][1],i),d(document,x[o][2],j),d(document,x[o][3],j),m.preventDefault&&o&&f(a),q={x:o?a.clientX:a.touches[0].clientX,y:o?a.clientY:a.touches[0].clientY,time:Number(new Date)},n=void 0,r={x:0,y:0,time:0},s={x:0,y:0},t=[{x:0,y:0,time:0}],m.start(a,q))}function i(a){!m.preventScroll&&n||y[o](a)||(g(a),(Math.abs(r.x)>m.clickTolerance||Math.abs(r.y)>m.clickTolerance)&&(v=!1),void 0===n&&3!==o&&(n=Math.abs(r.x)<Math.abs(r.y)&&!m.preventScroll)||(m.preventDefault&&f(a),m.move(a,q,r,s)))}function j(a){o&&g(a),!v&&a.target&&a.target.blur&&a.target.blur(),e(document,x[o][1],i),e(document,x[o][2],j),e(document,x[o][3],j),m.end(a,q,r,s)}function k(){u.push(d(a,x[w][0],function(a){h(a,w)})),u.push(d(a,"dragstart",f)),m.mouse&&!w&&u.push(d(a,x[3][0],function(a){h(a,3)})),u.push(d(a,"click",function(a){v?m.click(a):f(a)}))}var l=function(){},m={preventDefault:!0,clickTolerance:0,preventScroll:!1,mouse:!0,start:l,move:l,end:l,click:l};b&&c(m,b);var n,o,p={pointerEvents:!!window.navigator.pointerEnabled,msPointerEvents:!!window.navigator.msPointerEnabled},q={},r={},s={},t=[],u=[],v=!0,w=p.pointerEvents?1:p.msPointerEvents?2:0,x=[["touchstart","touchmove","touchend","touchcancel"],["pointerdown","pointermove","pointerup","pointercancel"],["MSPointerDown","MSPointerMove","MSPointerUp","MSPointerCancel"],["mousedown","mousemove","mouseup",!1]],y=[function(a){return a.touches&&a.touches.length>1||a.scale&&1!==a.scale},function(a){return!a.isPrimary||a.buttons&&1!==a.buttons||!m.mouse&&"touch"!==a.pointerType&&"pen"!==a.pointerType},function(a){return!a.isPrimary||a.buttons&&1!==a.buttons||!m.mouse&&a.pointerType!==a.MSPOINTER_TYPE_TOUCH&&a.pointerType!==a.MSPOINTER_TYPE_PEN},function(a){return a.buttons&&1!==a.buttons}];return k(),{getClicksAllowed:function(){return v},kill:function(){for(var a=u.length-1;a>=0;a--)u[a].remove()}}}
@@ -0,0 +1,62 @@
/* Peppermint minimal required styles */
.peppermint.peppermint-active {
position: relative;
overflow: hidden;
padding-left: 0;
padding-right: 0;
}
.peppermint.peppermint-active .peppermint-slides {
position: relative;
overflow: hidden; /* clearfix */
-ms-touch-action: pan-y;
touch-action: pan-y;
}
.peppermint.peppermint-active .peppermint-slides > * {
float: left;
margin: 0;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
-webkit-tap-highlight-color: transparent;
tap-highlight-color: transparent;
}
.peppermint.peppermint-active .peppermint-slides a:active,
.peppermint.peppermint-active .peppermint-slides a:active img {
outline: none;
}
.peppermint.peppermint-active,
.peppermint.peppermint-active .peppermint-dots,
.peppermint.peppermint-active .peppermint-slides,
.peppermint.peppermint-active .peppermint-slides > * {
-webkit-transform: translate3d(0,0,0);
-ms-transform: translate3d(0,0,0);
-moz-transform: translate3d(0,0,0);
transform: translate3d(0,0,0);
-webkit-backface-visibility: hidden;
-moz-backface-visibility: hidden;
-ms-backface-visibility: hidden;
backface-visibility: hidden;
}
.peppermint.peppermint-mouse .peppermint-slides {
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
cursor: move;
cursor: -webkit-grab;
cursor: -moz-grab;
cursor: grab;
}
.peppermint.peppermint-mouse.peppermint-drag .peppermint-slides * {
cursor: move;
cursor: -webkit-grabbing;
cursor: -moz-grabbing;
cursor: grabbing;
}
@@ -0,0 +1,154 @@
/* Peppermint required styles + default appearance styles */
.peppermint.peppermint-active {
position: relative;
overflow: hidden;
padding-left: 0;
padding-right: 0;
}
.peppermint.peppermint-active .peppermint-slides {
position: relative;
overflow: hidden; /* clearfix */
-ms-touch-action: pan-y;
touch-action: pan-y;
}
.peppermint.peppermint-active .peppermint-slides > * {
float: left;
margin: 0;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
-webkit-tap-highlight-color: transparent;
tap-highlight-color: transparent;
}
.peppermint.peppermint-active .peppermint-slides a:active,
.peppermint.peppermint-active .peppermint-slides a:active img {
outline: none;
}
.peppermint.peppermint-active,
.peppermint.peppermint-active .peppermint-dots,
.peppermint.peppermint-active .peppermint-slides,
.peppermint.peppermint-active .peppermint-slides > * {
-webkit-transform: translate3d(0,0,0);
-ms-transform: translate3d(0,0,0);
-moz-transform: translate3d(0,0,0);
transform: translate3d(0,0,0);
-webkit-backface-visibility: hidden;
-moz-backface-visibility: hidden;
-ms-backface-visibility: hidden;
backface-visibility: hidden;
}
.peppermint.peppermint-mouse .peppermint-slides {
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
cursor: move;
cursor: -webkit-grab;
cursor: -moz-grab;
cursor: grab;
}
.peppermint.peppermint-mouse.peppermint-drag .peppermint-slides * {
cursor: move;
cursor: -webkit-grabbing;
cursor: -moz-grabbing;
cursor: grabbing;
}
/* default appearance styles */
.peppermint {
text-align: center;
}
.peppermint figure {
margin: 0 0 1.5em 0;
}
.peppermint figure img {
vertical-align: top;
max-width: 100%;
-webkit-box-shadow: 0 1px 5px rgba(0, 0, 0, 0.2);
box-shadow: 0 1px 5px rgba(0, 0, 0, 0.2);
}
.peppermint figure figcaption {
font-style: italic;
color: #787575;
font-size: 0.8em;
margin-top: 0.5em;
}
.peppermint.peppermint-active {
margin-bottom: 1.5em;
}
.peppermint-slides {
padding-top: 0.5em;
padding-bottom: 0.5em;
}
/* dots */
ul.peppermint-dots {
margin: 0.6em 0;
padding: 0;
text-align: center;
list-style-type: none;
}
.peppermint.peppermint-active ul.peppermint-dots {
margin: 0 0 0.6em 0;
}
.peppermint.peppermint-active .peppermint-slides + ul.peppermint-dots {
margin: 0.6em 0 0 0;
}
ul.peppermint-dots > li {
display: inline-block;
position: relative;
padding: 0.5em 0.6em;
width: 12px;
height: 12px;
cursor: pointer;
text-align: center;
vertical-align: middle;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
-webkit-tap-highlight-color: transparent;
/* ie7 fallback */
*display: inline;
*zoom: 1;
}
ul.peppermint-dots > li.peppermint-mouse-clicked,
ul.peppermint-dots > li:active {
outline: 0;
}
ul.peppermint-dots > li > span {
display: inline-block;
position: absolute;
top: 50%;
left: 50%;
margin: -4px 0 0 -4px;
width: 8px;
height: 8px;
border-radius: 50%;
background: #9b9890;
}
ul.peppermint-dots > li.peppermint-active-dot > span {
margin: -6px 0 0 -6px;
width: 10px;
height: 10px;
border: 1px solid #9b9890;
background: transparent;
}
@@ -0,0 +1,493 @@
/*!
* Peppermint touch slider
* v. 1.3.7 | https://github.com/wilddeer/Peppermint
* Copyright Oleg Korsunsky | http://wd.dizaina.net/
*
* Depends on Event Burrito | https://github.com/wilddeer/Event-Burrito
* MIT License
*/
function Peppermint(_this, options) {
var slider = {
slides: [],
dots: [],
left: 0
},
slidesNumber,
flickThreshold = 200, //Flick threshold (ms)
activeSlide = 0,
slideWidth,
dotBlock,
slideBlock,
slideshowTimeoutId,
slideshowActive,
animationTimer;
//default options
var o = {
speed: 300, //transition between slides in ms
touchSpeed: 300, //transition between slides in ms after touch
slideshow: false, //launch slideshow at start
slideshowInterval: 4000,
stopSlideshowAfterInteraction: false, //stop slideshow after user interaction
startSlide: 0, //first slide to show
mouseDrag: true, //enable mouse drag
disableIfOneSlide: true,
cssPrefix: 'peppermint-',
dots: false, //show dots
dotsPrepend: false, //dots before slides
dotsContainer: undefined,
slidesContainer: undefined,
onSlideChange: undefined, //slide change callback
onSetup: undefined //setup callback
};
//merge user options into defaults
options && mergeObjects(o, options);
var classes = {
inactive: o.cssPrefix + 'inactive',
active: o.cssPrefix + 'active',
mouse: o.cssPrefix + 'mouse',
drag: o.cssPrefix + 'drag',
slides: o.cssPrefix + 'slides',
dots: o.cssPrefix + 'dots',
activeDot: o.cssPrefix + 'active-dot',
mouseClicked: o.cssPrefix + 'mouse-clicked'
};
//feature detects
var support = {
transforms: testProp('transform'),
transitions: testProp('transition')
};
function mergeObjects(targetObj, sourceObject) {
for (var key in sourceObject) {
if (sourceObject.hasOwnProperty(key)) {
targetObj[key] = sourceObject[key];
}
}
}
function testProp(prop) {
var prefixes = ['Webkit', 'Moz', 'O', 'ms'],
block = document.createElement('div');
if (block.style[prop] !== undefined) return true;
prop = prop.charAt(0).toUpperCase() + prop.slice(1);
for (var i in prefixes) {
if (block.style[prefixes[i]+prop] !== undefined) return true;
}
return false;
}
function addClass(el, cl) {
if (!new RegExp('(\\s|^)'+cl+'(\\s|$)').test(el.className)) {
el.className += ' ' + cl;
}
}
function removeClass(el, cl) {
el.className = el.className.replace(new RegExp('(\\s+|^)'+cl+'(\\s+|$)', 'g'), ' ').replace(/^\s+|\s+$/g, '');
}
//n - slide number (starting from 0)
//speed - transition in ms, can be omitted
function changeActiveSlide(n, speed) {
if (n<0) {
n = 0;
}
else if (n>slidesNumber-1) {
n = slidesNumber-1;
}
//change active dot
for (var i = slider.dots.length - 1; i >= 0; i--) {
removeClass(slider.dots[i], classes.activeDot);
}
addClass(slider.dots[n], classes.activeDot);
activeSlide = n;
changePos(-n*slider.width, (speed===undefined?o.speed:speed));
//reset slideshow timeout whenever active slide is changed for whatever reason
stepSlideshow();
//API callback
o.onSlideChange && o.onSlideChange(n);
return n;
}
//changes position of the slider (in px) with given speed (in ms)
function changePos(pos, speed) {
var time = speed?speed+'ms':'';
slideBlock.style.webkitTransitionDuration =
slideBlock.style.MozTransitionDuration =
slideBlock.style.msTransitionDuration =
slideBlock.style.OTransitionDuration =
slideBlock.style.transitionDuration = time;
setPos(pos);
}
//fallback to `setInterval` animations for UAs with no CSS transitions
function changePosFallback(pos, speed) {
animationTimer && clearInterval(animationTimer);
if (!speed) {
setPos(pos);
return;
}
var startTime = +new Date,
startPos = slider.left;
animationTimer = setInterval(function() {
//rough bezier emulation
var diff, y,
elapsed = +new Date - startTime,
f = elapsed / speed,
bezier = [0, 0.7, 1, 1];
function getPoint(p1, p2) {
return (p2-p1)*f + p1;
}
if (f >= 1) {
setPos(pos);
clearInterval(animationTimer);
return;
}
diff = pos - startPos;
y = getPoint(
getPoint(getPoint(bezier[0], bezier[1]), getPoint(bezier[1], bezier[2])),
getPoint(getPoint(bezier[1], bezier[2]), getPoint(bezier[2], bezier[3]))
);
setPos(Math.floor(y*diff + startPos));
}, 15);
}
//sets position of the slider (in px)
function setPos(pos) {
slideBlock.style.webkitTransform = 'translate('+pos+'px,0) translateZ(0)';
slideBlock.style.msTransform =
slideBlock.style.MozTransform =
slideBlock.style.OTransform =
slideBlock.style.transform = 'translateX('+pos+'px)';
slider.left = pos;
}
//`setPos` fallback for UAs with no CSS transforms support
function setPosFallback(pos) {
slideBlock.style.left = pos+'px';
slider.left = pos;
}
function nextSlide() {
var n = activeSlide + 1;
if (n > slidesNumber - 1) {
n = 0;
}
return changeActiveSlide(n);
}
function prevSlide() {
var n = activeSlide - 1;
if (n < 0) {
n = slidesNumber - 1;
}
return changeActiveSlide(n);
}
function startSlideshow() {
slideshowActive = true;
stepSlideshow();
}
//sets or resets timeout before switching to the next slide
function stepSlideshow() {
if (slideshowActive) {
slideshowTimeoutId && clearTimeout(slideshowTimeoutId);
slideshowTimeoutId = setTimeout(function() {
nextSlide();
},
o.slideshowInterval);
}
}
//pauses slideshow until `stepSlideshow` is invoked
function pauseSlideshow() {
slideshowTimeoutId && clearTimeout(slideshowTimeoutId);
}
function stopSlideshow() {
slideshowActive = false;
slideshowTimeoutId && clearTimeout(slideshowTimeoutId);
}
//this should be invoked when the width of the slider is changed
function onWidthChange() {
slider.width = _this.offsetWidth;
//have to do this in `px` because of webkit's rounding errors :-(
slideBlock.style.width = slider.width*slidesNumber+'px';
for (var i = 0; i < slidesNumber; i++) {
slider.slides[i].style.width = slider.width+'px';
}
changePos(-activeSlide*slider.width);
}
function addEvent(el, event, func, bool) {
if (!event) return;
el.addEventListener? el.addEventListener(event, func, !!bool): el.attachEvent('on'+event, func);
}
//init touch events
function touchInit() {
EventBurrito(slideBlock, {
mouse: o.mouseDrag,
start: function(event, start) {
//firefox doesn't want to apply cursor from `:active` CSS rule, have to add a class :-/
addClass(_this, classes.drag);
},
move: function(event, start, diff, speed) {
pauseSlideshow(); //pause the slideshow when touch is in progress
//if it's first slide and moving left or last slide and moving right -- resist!
diff.x =
diff.x /
(
(!activeSlide && diff.x > 0
|| activeSlide == slidesNumber - 1 && diff.x < 0)
?
(Math.abs(diff.x)/slider.width*2 + 1)
:
1
);
//change position of the slider appropriately
changePos(diff.x - slider.width*activeSlide);
},
end: function(event, start, diff, speed) {
if (diff.x) {
var ratio = Math.abs(diff.x)/slider.width,
//How many slides to skip. Remainder > 0.25 counts for one slide.
skip = Math.floor(ratio) + (ratio - Math.floor(ratio) > 0.25?1:0),
//Super-duper formula to detect a flick.
//First, it's got to be fast enough.
//Second, if `skip==0`, 20px move is enough to switch to the next slide.
//If `skip>0`, it's enough to slide to the middle of the slide minus `slider.width/9` to skip even further.
flick = diff.time < flickThreshold+flickThreshold*skip/1.8 && Math.abs(diff.x) - skip*slider.width > (skip?-slider.width/9:20);
skip += (flick?1:0);
if (diff.x < 0) {
changeActiveSlide(activeSlide+skip, o.touchSpeed);
}
else {
changeActiveSlide(activeSlide-skip, o.touchSpeed);
}
o.stopSlideshowAfterInteraction && stopSlideshow();
}
//remove the drag class
removeClass(_this, classes.drag);
}
});
}
function setup() {
var slideSource = o.slidesContainer || _this,
dotsTarget = o.dotsContainer || _this;
if (o.disableIfOneSlide && slideSource.children.length <= 1) return;
//If current UA doesn't support css transforms or transitions -- use fallback functions.
//(Using separate functions instead of checks for better performance)
if (!support.transforms || !!window.opera) setPos = setPosFallback;
if (!support.transitions || !!window.opera) changePos = changePosFallback;
slideBlock = o.slidesContainer || document.createElement('div');
addClass(slideBlock, classes.slides);
//get slides & generate dots
for (var i = 0, l = slideSource.children.length; i < l; i++) {
var slide = slideSource.children[i],
dot = document.createElement('li');
slider.slides.push(slide);
//`tabindex` makes dots tabbable
dot.setAttribute('tabindex', '0');
dot.setAttribute('role', 'button');
dot.innerHTML = '<span></span>';
(function(x, dotClosure) {
//bind events to dots
addEvent(dotClosure, 'click', function(event) {
changeActiveSlide(x);
o.stopSlideshowAfterInteraction && stopSlideshow();
});
//Bind the same function to Enter key except for the `blur` part -- I dont't want
//the focus to be lost when the user is using his keyboard to navigate.
addEvent(dotClosure, 'keyup', function(event) {
if (event.keyCode == 13) {
changeActiveSlide(x);
o.stopSlideshowAfterInteraction && stopSlideshow();
}
});
//Don't want to disable outlines completely for accessibility reasons.
//Instead, add class with `outline: 0` on mouseup and remove it on blur.
addEvent(dotClosure, 'mouseup', function(event) {
addClass(dotClosure, classes.mouseClicked);
});
//capturing fixes IE bug
addEvent(dotClosure, 'blur', function(){
removeClass(dotClosure, classes.mouseClicked);
}, true);
//This solves tabbing problems:
//When an element inside a slide catches focus we switch to that slide
//and reset `scrollLeft` of the slider block.
//`SetTimeout` solves Chrome's bug.
//Event capturing is used to catch events on the slide level.
//Since older IEs don't have capturing, `onfocusin` is used as a fallback.
addEvent(slide, 'focus', slide.onfocusin = function(e) {
_this.scrollLeft = 0;
setTimeout(function() {
_this.scrollLeft = 0;
}, 0);
changeActiveSlide(x);
}, true);
})(i, dot)
slider.dots.push(dot);
}
slidesNumber = slider.slides.length;
slideWidth = 100/slidesNumber;
addClass(_this, classes.active);
removeClass(_this, classes.inactive);
o.mouseDrag && addClass(_this, classes.mouse);
slider.width = _this.offsetWidth;
//had to do this in `px` because of webkit's rounding errors :-(
slideBlock.style.width = slider.width*slidesNumber+'px';
for (var i = 0; i < slidesNumber; i++) {
slider.slides[i].style.width = slider.width+'px';
slideBlock.appendChild(slider.slides[i]);
}
if (!o.slidesContainer) _this.appendChild(slideBlock);
//append dots
if (o.dots && slidesNumber > 1) {
dotBlock = document.createElement('ul');
addClass(dotBlock, classes.dots);
for (var i = 0, l = slider.dots.length; i < l; i++) {
dotBlock.appendChild(slider.dots[i]);
}
if (o.dotsPrepend) {
dotsTarget.insertBefore(dotBlock,dotsTarget.firstChild);
}
else {
dotsTarget.appendChild(dotBlock);
}
}
//watch for slider width changes
addEvent(window, 'resize', onWidthChange);
addEvent(window, 'orientationchange', onWidthChange);
//init first slide, timeout to expose the API first
setTimeout(function() {
changeActiveSlide(o.startSlide, 0);
}, 0);
//init slideshow
if (o.slideshow) startSlideshow();
touchInit();
//API callback, timeout to expose the API first
setTimeout(function() {
o.onSetup && o.onSetup(slidesNumber);
}, 0);
}
//Init
setup();
//expose the API
return {
slideTo: function(slide) {
return changeActiveSlide(parseInt(slide, 10));
},
next: nextSlide,
prev: prevSlide,
//start slideshow
start: startSlideshow,
//stop slideshow
stop: stopSlideshow,
//pause slideshow until the next slide change
pause: pauseSlideshow,
//get current slide number
getCurrentPos: function() {
return activeSlide;
},
//get total number of slides
getSlidesNumber: function() {
return slidesNumber;
},
//invoke this when the slider's width is changed
recalcWidth: onWidthChange
};
};
//if jQuery is present -- create a plugin
if (window.jQuery) {
(function($) {
$.fn.Peppermint = function(options) {
this.each(function() {
$(this).data('Peppermint', Peppermint(this, options));
});
return this;
};
})(window.jQuery);
}
@@ -0,0 +1,9 @@
/*!
* Peppermint touch slider
* v. 1.3.7 | https://github.com/wilddeer/Peppermint
* Copyright Oleg Korsunsky | http://wd.dizaina.net/
*
* Depends on Event Burrito | https://github.com/wilddeer/Event-Burrito
* MIT License
*/
function Peppermint(a,b){function c(a,b){for(var c in b)b.hasOwnProperty(c)&&(a[c]=b[c])}function d(a){var b=["Webkit","Moz","O","ms"],c=document.createElement("div");if(void 0!==c.style[a])return!0;a=a.charAt(0).toUpperCase()+a.slice(1);for(var d in b)if(void 0!==c.style[b[d]+a])return!0;return!1}function e(a,b){new RegExp("(\\s|^)"+b+"(\\s|$)").test(a.className)||(a.className+=" "+b)}function f(a,b){a.className=a.className.replace(new RegExp("(\\s+|^)"+b+"(\\s+|$)","g")," ").replace(/^\s+|\s+$/g,"")}function g(a,b){0>a?a=0:a>v-1&&(a=v-1);for(var c=C.dots.length-1;c>=0;c--)f(C.dots[c],G.activeDot);return e(C.dots[a],G.activeDot),E=a,h(-a*C.width,void 0===b?F.speed:b),o(),F.onSlideChange&&F.onSlideChange(a),a}function h(a,b){var c=b?b+"ms":"";y.style.webkitTransitionDuration=y.style.MozTransitionDuration=y.style.msTransitionDuration=y.style.OTransitionDuration=y.style.transitionDuration=c,j(a)}function i(a,b){if(B&&clearInterval(B),!b)return void j(a);var c=+new Date,d=C.left;B=setInterval(function(){function e(a,b){return(b-a)*i+a}var f,g,h=+new Date-c,i=h/b,k=[0,.7,1,1];return i>=1?(j(a),void clearInterval(B)):(f=a-d,g=e(e(e(k[0],k[1]),e(k[1],k[2])),e(e(k[1],k[2]),e(k[2],k[3]))),void j(Math.floor(g*f+d)))},15)}function j(a){y.style.webkitTransform="translate("+a+"px,0) translateZ(0)",y.style.msTransform=y.style.MozTransform=y.style.OTransform=y.style.transform="translateX("+a+"px)",C.left=a}function k(a){y.style.left=a+"px",C.left=a}function l(){var a=E+1;return a>v-1&&(a=0),g(a)}function m(){var a=E-1;return 0>a&&(a=v-1),g(a)}function n(){A=!0,o()}function o(){A&&(z&&clearTimeout(z),z=setTimeout(function(){l()},F.slideshowInterval))}function p(){z&&clearTimeout(z)}function q(){A=!1,z&&clearTimeout(z)}function r(){C.width=a.offsetWidth,y.style.width=C.width*v+"px";for(var b=0;v>b;b++)C.slides[b].style.width=C.width+"px";h(-E*C.width)}function s(a,b,c,d){b&&(a.addEventListener?a.addEventListener(b,c,!!d):a.attachEvent("on"+b,c))}function t(){EventBurrito(y,{mouse:F.mouseDrag,start:function(){e(a,G.drag)},move:function(a,b,c){p(),c.x=c.x/(!E&&c.x>0||E==v-1&&c.x<0?Math.abs(c.x)/C.width*2+1:1),h(c.x-C.width*E)},end:function(b,c,d){if(d.x){var e=Math.abs(d.x)/C.width,h=Math.floor(e)+(e-Math.floor(e)>.25?1:0),i=d.time<D+D*h/1.8&&Math.abs(d.x)-h*C.width>(h?-C.width/9:20);h+=i?1:0,d.x<0?g(E+h,F.touchSpeed):g(E-h,F.touchSpeed),F.stopSlideshowAfterInteraction&&q()}f(a,G.drag)}})}function u(){var b=F.slidesContainer||a,c=F.dotsContainer||a;if(!(F.disableIfOneSlide&&b.children.length<=1)){(!H.transforms||window.opera)&&(j=k),(!H.transitions||window.opera)&&(h=i),y=F.slidesContainer||document.createElement("div"),e(y,G.slides);for(var d=0,l=b.children.length;l>d;d++){var m=b.children[d],o=document.createElement("li");C.slides.push(m),o.setAttribute("tabindex","0"),o.setAttribute("role","button"),o.innerHTML="<span></span>",function(b,c){s(c,"click",function(){g(b),F.stopSlideshowAfterInteraction&&q()}),s(c,"keyup",function(a){13==a.keyCode&&(g(b),F.stopSlideshowAfterInteraction&&q())}),s(c,"mouseup",function(){e(c,G.mouseClicked)}),s(c,"blur",function(){f(c,G.mouseClicked)},!0),s(m,"focus",m.onfocusin=function(){a.scrollLeft=0,setTimeout(function(){a.scrollLeft=0},0),g(b)},!0)}(d,o),C.dots.push(o)}v=C.slides.length,w=100/v,e(a,G.active),f(a,G.inactive),F.mouseDrag&&e(a,G.mouse),C.width=a.offsetWidth,y.style.width=C.width*v+"px";for(var d=0;v>d;d++)C.slides[d].style.width=C.width+"px",y.appendChild(C.slides[d]);if(F.slidesContainer||a.appendChild(y),F.dots&&v>1){x=document.createElement("ul"),e(x,G.dots);for(var d=0,l=C.dots.length;l>d;d++)x.appendChild(C.dots[d]);F.dotsPrepend?c.insertBefore(x,c.firstChild):c.appendChild(x)}s(window,"resize",r),s(window,"orientationchange",r),setTimeout(function(){g(F.startSlide,0)},0),F.slideshow&&n(),t(),setTimeout(function(){F.onSetup&&F.onSetup(v)},0)}}var v,w,x,y,z,A,B,C={slides:[],dots:[],left:0},D=200,E=0,F={speed:300,touchSpeed:300,slideshow:!1,slideshowInterval:4e3,stopSlideshowAfterInteraction:!1,startSlide:0,mouseDrag:!0,disableIfOneSlide:!0,cssPrefix:"peppermint-",dots:!1,dotsPrepend:!1,dotsContainer:void 0,slidesContainer:void 0,onSlideChange:void 0,onSetup:void 0};b&&c(F,b);var G={inactive:F.cssPrefix+"inactive",active:F.cssPrefix+"active",mouse:F.cssPrefix+"mouse",drag:F.cssPrefix+"drag",slides:F.cssPrefix+"slides",dots:F.cssPrefix+"dots",activeDot:F.cssPrefix+"active-dot",mouseClicked:F.cssPrefix+"mouse-clicked"},H={transforms:d("transform"),transitions:d("transition")};return u(),{slideTo:function(a){return g(parseInt(a,10))},next:l,prev:m,start:n,stop:q,pause:p,getCurrentPos:function(){return E},getSlidesNumber:function(){return v},recalcWidth:r}}window.jQuery&&!function($){$.fn.Peppermint=function(a){return this.each(function(){$(this).data("Peppermint",Peppermint(this,a))}),this}}(window.jQuery);
@@ -0,0 +1,22 @@
{
"name": "Peppermint",
"version": "1.3.7",
"license": "MIT",
"homepage": "https://github.com/wilddeer/Peppermint",
"repository": {
"type": "git",
"url": "https://github.com/wilddeer/Peppermint.git"
},
"author": {
"name": "Oleg Korsunsky",
"url": "http://wd.dizaina.net/"
},
"devDependencies": {
"grunt": "~0.4.1",
"grunt-contrib-uglify": "~0.2.5",
"grunt-contrib-concat": "~0.3.0",
"grunt-contrib-watch": "~0.5.3",
"grunt-bump": "0.0.14",
"grunt-shell": "~0.7.0"
}
}
@@ -0,0 +1,90 @@
.peppermint {
text-align: center;
}
.peppermint figure {
margin: 0 0 1.5em 0;
}
.peppermint figure img {
vertical-align: top;
max-width: 100%;
-webkit-box-shadow: 0 1px 5px rgba(0, 0, 0, 0.2);
box-shadow: 0 1px 5px rgba(0, 0, 0, 0.2);
}
.peppermint figure figcaption {
font-style: italic;
color: #787575;
font-size: 0.8em;
margin-top: 0.5em;
}
.peppermint.peppermint-active {
margin-bottom: 1.5em;
}
.peppermint-slides {
padding-top: 0.5em;
padding-bottom: 0.5em;
}
/* dots */
ul.peppermint-dots {
margin: 0.6em 0;
padding: 0;
text-align: center;
list-style-type: none;
}
.peppermint.peppermint-active ul.peppermint-dots {
margin: 0 0 0.6em 0;
}
.peppermint.peppermint-active .peppermint-slides + ul.peppermint-dots {
margin: 0.6em 0 0 0;
}
ul.peppermint-dots > li {
display: inline-block;
position: relative;
padding: 0.5em 0.6em;
width: 12px;
height: 12px;
cursor: pointer;
text-align: center;
vertical-align: middle;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
-webkit-tap-highlight-color: transparent;
/* ie7 fallback */
*display: inline;
*zoom: 1;
}
ul.peppermint-dots > li.peppermint-mouse-clicked,
ul.peppermint-dots > li:active {
outline: 0;
}
ul.peppermint-dots > li > span {
display: inline-block;
position: absolute;
top: 50%;
left: 50%;
margin: -4px 0 0 -4px;
width: 8px;
height: 8px;
border-radius: 50%;
background: #9b9890;
}
ul.peppermint-dots > li.peppermint-active-dot > span {
margin: -6px 0 0 -6px;
width: 10px;
height: 10px;
border: 1px solid #9b9890;
background: transparent;
}
@@ -0,0 +1,485 @@
function Peppermint(_this, options) {
var slider = {
slides: [],
dots: [],
left: 0
},
slidesNumber,
flickThreshold = 200, //Flick threshold (ms)
activeSlide = 0,
slideWidth,
dotBlock,
slideBlock,
slideshowTimeoutId,
slideshowActive,
animationTimer;
//default options
var o = {
speed: 300, //transition between slides in ms
touchSpeed: 300, //transition between slides in ms after touch
slideshow: false, //launch slideshow at start
slideshowInterval: 4000,
stopSlideshowAfterInteraction: false, //stop slideshow after user interaction
startSlide: 0, //first slide to show
mouseDrag: true, //enable mouse drag
disableIfOneSlide: true,
cssPrefix: 'peppermint-',
dots: false, //show dots
dotsPrepend: false, //dots before slides
dotsContainer: undefined,
slidesContainer: undefined,
onSlideChange: undefined, //slide change callback
onSetup: undefined //setup callback
};
//merge user options into defaults
options && mergeObjects(o, options);
var classes = {
inactive: o.cssPrefix + 'inactive',
active: o.cssPrefix + 'active',
mouse: o.cssPrefix + 'mouse',
drag: o.cssPrefix + 'drag',
slides: o.cssPrefix + 'slides',
dots: o.cssPrefix + 'dots',
activeDot: o.cssPrefix + 'active-dot',
mouseClicked: o.cssPrefix + 'mouse-clicked'
};
//feature detects
var support = {
transforms: testProp('transform'),
transitions: testProp('transition')
};
function mergeObjects(targetObj, sourceObject) {
for (var key in sourceObject) {
if (sourceObject.hasOwnProperty(key)) {
targetObj[key] = sourceObject[key];
}
}
}
function testProp(prop) {
var prefixes = ['Webkit', 'Moz', 'O', 'ms'],
block = document.createElement('div');
if (block.style[prop] !== undefined) return true;
prop = prop.charAt(0).toUpperCase() + prop.slice(1);
for (var i in prefixes) {
if (block.style[prefixes[i]+prop] !== undefined) return true;
}
return false;
}
function addClass(el, cl) {
if (!new RegExp('(\\s|^)'+cl+'(\\s|$)').test(el.className)) {
el.className += ' ' + cl;
}
}
function removeClass(el, cl) {
el.className = el.className.replace(new RegExp('(\\s+|^)'+cl+'(\\s+|$)', 'g'), ' ').replace(/^\s+|\s+$/g, '');
}
//n - slide number (starting from 0)
//speed - transition in ms, can be omitted
function changeActiveSlide(n, speed) {
if (n<0) {
n = 0;
}
else if (n>slidesNumber-1) {
n = slidesNumber-1;
}
//change active dot
for (var i = slider.dots.length - 1; i >= 0; i--) {
removeClass(slider.dots[i], classes.activeDot);
}
addClass(slider.dots[n], classes.activeDot);
activeSlide = n;
changePos(-n*slider.width, (speed===undefined?o.speed:speed));
//reset slideshow timeout whenever active slide is changed for whatever reason
stepSlideshow();
//API callback
o.onSlideChange && o.onSlideChange(n);
return n;
}
//changes position of the slider (in px) with given speed (in ms)
function changePos(pos, speed) {
var time = speed?speed+'ms':'';
slideBlock.style.webkitTransitionDuration =
slideBlock.style.MozTransitionDuration =
slideBlock.style.msTransitionDuration =
slideBlock.style.OTransitionDuration =
slideBlock.style.transitionDuration = time;
setPos(pos);
}
//fallback to `setInterval` animations for UAs with no CSS transitions
function changePosFallback(pos, speed) {
animationTimer && clearInterval(animationTimer);
if (!speed) {
setPos(pos);
return;
}
var startTime = +new Date,
startPos = slider.left;
animationTimer = setInterval(function() {
//rough bezier emulation
var diff, y,
elapsed = +new Date - startTime,
f = elapsed / speed,
bezier = [0, 0.7, 1, 1];
function getPoint(p1, p2) {
return (p2-p1)*f + p1;
}
if (f >= 1) {
setPos(pos);
clearInterval(animationTimer);
return;
}
diff = pos - startPos;
y = getPoint(
getPoint(getPoint(bezier[0], bezier[1]), getPoint(bezier[1], bezier[2])),
getPoint(getPoint(bezier[1], bezier[2]), getPoint(bezier[2], bezier[3]))
);
setPos(Math.floor(y*diff + startPos));
}, 15);
}
//sets position of the slider (in px)
function setPos(pos) {
slideBlock.style.webkitTransform = 'translate('+pos+'px,0) translateZ(0)';
slideBlock.style.msTransform =
slideBlock.style.MozTransform =
slideBlock.style.OTransform =
slideBlock.style.transform = 'translateX('+pos+'px)';
slider.left = pos;
}
//`setPos` fallback for UAs with no CSS transforms support
function setPosFallback(pos) {
slideBlock.style.left = pos+'px';
slider.left = pos;
}
function nextSlide() {
var n = activeSlide + 1;
if (n > slidesNumber - 1) {
n = 0;
}
return changeActiveSlide(n);
}
function prevSlide() {
var n = activeSlide - 1;
if (n < 0) {
n = slidesNumber - 1;
}
return changeActiveSlide(n);
}
function startSlideshow() {
slideshowActive = true;
stepSlideshow();
}
//sets or resets timeout before switching to the next slide
function stepSlideshow() {
if (slideshowActive) {
slideshowTimeoutId && clearTimeout(slideshowTimeoutId);
slideshowTimeoutId = setTimeout(function() {
nextSlide();
},
o.slideshowInterval);
}
}
//pauses slideshow until `stepSlideshow` is invoked
function pauseSlideshow() {
slideshowTimeoutId && clearTimeout(slideshowTimeoutId);
}
function stopSlideshow() {
slideshowActive = false;
slideshowTimeoutId && clearTimeout(slideshowTimeoutId);
}
//this should be invoked when the width of the slider is changed
function onWidthChange() {
slider.width = _this.offsetWidth;
//have to do this in `px` because of webkit's rounding errors :-(
slideBlock.style.width = slider.width*slidesNumber+'px';
for (var i = 0; i < slidesNumber; i++) {
slider.slides[i].style.width = slider.width+'px';
}
changePos(-activeSlide*slider.width);
}
function addEvent(el, event, func, bool) {
if (!event) return;
el.addEventListener? el.addEventListener(event, func, !!bool): el.attachEvent('on'+event, func);
}
//init touch events
function touchInit() {
EventBurrito(slideBlock, {
mouse: o.mouseDrag,
start: function(event, start) {
//firefox doesn't want to apply cursor from `:active` CSS rule, have to add a class :-/
addClass(_this, classes.drag);
},
move: function(event, start, diff, speed) {
pauseSlideshow(); //pause the slideshow when touch is in progress
//if it's first slide and moving left or last slide and moving right -- resist!
diff.x =
diff.x /
(
(!activeSlide && diff.x > 0
|| activeSlide == slidesNumber - 1 && diff.x < 0)
?
(Math.abs(diff.x)/slider.width*2 + 1)
:
1
);
//change position of the slider appropriately
changePos(diff.x - slider.width*activeSlide);
},
end: function(event, start, diff, speed) {
if (diff.x) {
var ratio = Math.abs(diff.x)/slider.width,
//How many slides to skip. Remainder > 0.25 counts for one slide.
skip = Math.floor(ratio) + (ratio - Math.floor(ratio) > 0.25?1:0),
//Super-duper formula to detect a flick.
//First, it's got to be fast enough.
//Second, if `skip==0`, 20px move is enough to switch to the next slide.
//If `skip>0`, it's enough to slide to the middle of the slide minus `slider.width/9` to skip even further.
flick = diff.time < flickThreshold+flickThreshold*skip/1.8 && Math.abs(diff.x) - skip*slider.width > (skip?-slider.width/9:20);
skip += (flick?1:0);
if (diff.x < 0) {
changeActiveSlide(activeSlide+skip, o.touchSpeed);
}
else {
changeActiveSlide(activeSlide-skip, o.touchSpeed);
}
o.stopSlideshowAfterInteraction && stopSlideshow();
}
//remove the drag class
removeClass(_this, classes.drag);
}
});
}
function setup() {
var slideSource = o.slidesContainer || _this,
dotsTarget = o.dotsContainer || _this;
if (o.disableIfOneSlide && slideSource.children.length <= 1) return;
//If current UA doesn't support css transforms or transitions -- use fallback functions.
//(Using separate functions instead of checks for better performance)
if (!support.transforms || !!window.opera) setPos = setPosFallback;
if (!support.transitions || !!window.opera) changePos = changePosFallback;
slideBlock = o.slidesContainer || document.createElement('div');
addClass(slideBlock, classes.slides);
//get slides & generate dots
for (var i = 0, l = slideSource.children.length; i < l; i++) {
var slide = slideSource.children[i],
dot = document.createElement('li');
slider.slides.push(slide);
//`tabindex` makes dots tabbable
dot.setAttribute('tabindex', '0');
dot.setAttribute('role', 'button');
dot.innerHTML = '<span></span>';
(function(x, dotClosure) {
//bind events to dots
addEvent(dotClosure, 'click', function(event) {
changeActiveSlide(x);
o.stopSlideshowAfterInteraction && stopSlideshow();
});
//Bind the same function to Enter key except for the `blur` part -- I dont't want
//the focus to be lost when the user is using his keyboard to navigate.
addEvent(dotClosure, 'keyup', function(event) {
if (event.keyCode == 13) {
changeActiveSlide(x);
o.stopSlideshowAfterInteraction && stopSlideshow();
}
});
//Don't want to disable outlines completely for accessibility reasons.
//Instead, add class with `outline: 0` on mouseup and remove it on blur.
addEvent(dotClosure, 'mouseup', function(event) {
addClass(dotClosure, classes.mouseClicked);
});
//capturing fixes IE bug
addEvent(dotClosure, 'blur', function(){
removeClass(dotClosure, classes.mouseClicked);
}, true);
//This solves tabbing problems:
//When an element inside a slide catches focus we switch to that slide
//and reset `scrollLeft` of the slider block.
//`SetTimeout` solves Chrome's bug.
//Event capturing is used to catch events on the slide level.
//Since older IEs don't have capturing, `onfocusin` is used as a fallback.
addEvent(slide, 'focus', slide.onfocusin = function(e) {
_this.scrollLeft = 0;
setTimeout(function() {
_this.scrollLeft = 0;
}, 0);
changeActiveSlide(x);
}, true);
})(i, dot)
slider.dots.push(dot);
}
slidesNumber = slider.slides.length;
slideWidth = 100/slidesNumber;
addClass(_this, classes.active);
removeClass(_this, classes.inactive);
o.mouseDrag && addClass(_this, classes.mouse);
slider.width = _this.offsetWidth;
//had to do this in `px` because of webkit's rounding errors :-(
slideBlock.style.width = slider.width*slidesNumber+'px';
for (var i = 0; i < slidesNumber; i++) {
slider.slides[i].style.width = slider.width+'px';
slideBlock.appendChild(slider.slides[i]);
}
if (!o.slidesContainer) _this.appendChild(slideBlock);
//append dots
if (o.dots && slidesNumber > 1) {
dotBlock = document.createElement('ul');
addClass(dotBlock, classes.dots);
for (var i = 0, l = slider.dots.length; i < l; i++) {
dotBlock.appendChild(slider.dots[i]);
}
if (o.dotsPrepend) {
dotsTarget.insertBefore(dotBlock,dotsTarget.firstChild);
}
else {
dotsTarget.appendChild(dotBlock);
}
}
//watch for slider width changes
addEvent(window, 'resize', onWidthChange);
addEvent(window, 'orientationchange', onWidthChange);
//init first slide, timeout to expose the API first
setTimeout(function() {
changeActiveSlide(o.startSlide, 0);
}, 0);
//init slideshow
if (o.slideshow) startSlideshow();
touchInit();
//API callback, timeout to expose the API first
setTimeout(function() {
o.onSetup && o.onSetup(slidesNumber);
}, 0);
}
//Init
setup();
//expose the API
return {
slideTo: function(slide) {
return changeActiveSlide(parseInt(slide, 10));
},
next: nextSlide,
prev: prevSlide,
//start slideshow
start: startSlideshow,
//stop slideshow
stop: stopSlideshow,
//pause slideshow until the next slide change
pause: pauseSlideshow,
//get current slide number
getCurrentPos: function() {
return activeSlide;
},
//get total number of slides
getSlidesNumber: function() {
return slidesNumber;
},
//invoke this when the slider's width is changed
recalcWidth: onWidthChange
};
};
//if jQuery is present -- create a plugin
if (window.jQuery) {
(function($) {
$.fn.Peppermint = function(options) {
this.each(function() {
$(this).data('Peppermint', Peppermint(this, options));
});
return this;
};
})(window.jQuery);
}
@@ -0,0 +1,60 @@
.peppermint.peppermint-active {
position: relative;
overflow: hidden;
padding-left: 0;
padding-right: 0;
}
.peppermint.peppermint-active .peppermint-slides {
position: relative;
overflow: hidden; /* clearfix */
-ms-touch-action: pan-y;
touch-action: pan-y;
}
.peppermint.peppermint-active .peppermint-slides > * {
float: left;
margin: 0;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
-webkit-tap-highlight-color: transparent;
tap-highlight-color: transparent;
}
.peppermint.peppermint-active .peppermint-slides a:active,
.peppermint.peppermint-active .peppermint-slides a:active img {
outline: none;
}
.peppermint.peppermint-active,
.peppermint.peppermint-active .peppermint-dots,
.peppermint.peppermint-active .peppermint-slides,
.peppermint.peppermint-active .peppermint-slides > * {
-webkit-transform: translate3d(0,0,0);
-ms-transform: translate3d(0,0,0);
-moz-transform: translate3d(0,0,0);
transform: translate3d(0,0,0);
-webkit-backface-visibility: hidden;
-moz-backface-visibility: hidden;
-ms-backface-visibility: hidden;
backface-visibility: hidden;
}
.peppermint.peppermint-mouse .peppermint-slides {
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
cursor: move;
cursor: -webkit-grab;
cursor: -moz-grab;
cursor: grab;
}
.peppermint.peppermint-mouse.peppermint-drag .peppermint-slides * {
cursor: move;
cursor: -webkit-grabbing;
cursor: -moz-grabbing;
cursor: grabbing;
}