├── .nvmrc
├── CNAME
├── .gitignore
├── icons
├── cnn.png
├── htc.png
├── nhl.png
├── airbnb.png
├── snapguide.png
└── thinkgeek.png
├── left-arrow.png
├── right-arrow.png
├── swipe_bullet.png
├── component.json
├── Gruntfile.js
├── package.json
├── LICENSE.md
├── style.css
├── index.html
├── README.md
└── swipe.js
/.nvmrc:
--------------------------------------------------------------------------------
1 | 6
--------------------------------------------------------------------------------
/CNAME:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | build
3 |
--------------------------------------------------------------------------------
/icons/cnn.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tes/Swipe/master/icons/cnn.png
--------------------------------------------------------------------------------
/icons/htc.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tes/Swipe/master/icons/htc.png
--------------------------------------------------------------------------------
/icons/nhl.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tes/Swipe/master/icons/nhl.png
--------------------------------------------------------------------------------
/left-arrow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tes/Swipe/master/left-arrow.png
--------------------------------------------------------------------------------
/right-arrow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tes/Swipe/master/right-arrow.png
--------------------------------------------------------------------------------
/icons/airbnb.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tes/Swipe/master/icons/airbnb.png
--------------------------------------------------------------------------------
/swipe_bullet.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tes/Swipe/master/swipe_bullet.png
--------------------------------------------------------------------------------
/icons/snapguide.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tes/Swipe/master/icons/snapguide.png
--------------------------------------------------------------------------------
/icons/thinkgeek.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tes/Swipe/master/icons/thinkgeek.png
--------------------------------------------------------------------------------
/component.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "swipe-js",
3 | "version": "2.0.0",
4 | "main": ["./swipe.js"],
5 | "author": "Brad Birdsall",
6 | "license": "MIT",
7 | "ignore": [
8 | "**/*.html",
9 | "**/*.css",
10 | "Gruntfile.js"
11 | ]
12 | }
13 |
--------------------------------------------------------------------------------
/Gruntfile.js:
--------------------------------------------------------------------------------
1 | /*global module */
2 | module.exports = function( grunt ) {
3 |
4 | 'use strict';
5 |
6 | grunt.initConfig({
7 |
8 | uglify: {
9 | options: {
10 | mangle: {
11 | except: ['Swipe']
12 | }
13 | },
14 | dist: {
15 | files: {
16 | 'build/swipe.min.js': 'swipe.js'
17 | }
18 | }
19 | }
20 |
21 | });
22 |
23 | // build
24 | grunt.loadNpmTasks('grunt-contrib-uglify');
25 | grunt.registerTask('build', 'uglify');
26 | grunt.registerTask('default', 'build');
27 | };
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "tes-swipe-js",
3 | "version": "0.0.2",
4 | "main": "./swipe.js",
5 | "dependencies": {
6 | "jquery": "^3.4.0"
7 | },
8 | "devDependencies": {
9 | "grunt": "~0.4.5",
10 | "grunt-contrib-uglify": "~0.8.0"
11 | },
12 | "repository": {
13 | "type": "git",
14 | "url": "https://github.com/tes/Swipe"
15 | },
16 | "keywords": [
17 | "ecosystem:jquery",
18 | "jquery-plugin",
19 | "swipe",
20 | "slider",
21 | "touch"
22 | ],
23 | "engines": {
24 | "node": ">=0.8.0"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Brad Birdsall and Xiuyu Li
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
--------------------------------------------------------------------------------
/style.css:
--------------------------------------------------------------------------------
1 | html, body, div, span, object, iframe, h1, h2, h3, h4, h5, h6, p, del, dfn, em, img, ins, kbd, q, samp, small, strong, b, i, dl, dt, dd, ol, ul, li, fieldset, form, label, table, tbody, tfoot, thead, tr, th, td, article, aside, footer, header, nav, section {
2 | margin:0;
3 | padding:0;
4 | border:0;
5 | outline:0;
6 | font-size:100%;
7 | vertical-align:baseline;
8 | background:transparent;
9 | }
10 | body {
11 | -webkit-text-size-adjust:none;
12 | font-family:sans-serif;
13 | min-height:416px;
14 | }
15 | h1 {
16 | font-size:33px;
17 | margin:50px 0 15px;
18 | text-align:center;
19 | color:#212121;
20 | }
21 | h2 {
22 | font-size:14px;
23 | font-weight:bold;
24 | color:#3c3c3c;
25 | margin:20px 10px 10px;
26 | }
27 | small {
28 | margin:0 10px 30px;
29 | display:block;
30 | font-size:12px;
31 | }
32 | a {
33 | margin:0 0 0 10px;
34 | font-size:12px;
35 | color:#3c3c3c;
36 | }
37 |
38 |
39 | html, body {
40 | background: #f3f3f3;
41 | }
42 |
43 | #console {
44 | font-size: 12px;
45 | font-family:"Inconsolata", "Monaco", "Consolas", "Andale Mono", "Bitstream Vera Sans Mono", "Courier New", Courier, monospace;
46 | color: #999;
47 | line-height: 18px;
48 | margin-top: 20px;
49 | max-height: 150px;
50 | overflow: auto;
51 | }
52 |
53 | #mySwipe div b {
54 | display:block;
55 | font-weight:bold;
56 | color:#14ADE5;
57 | font-size:20px;
58 | text-align:center;
59 | margin:10px;
60 | padding:100px 10px;
61 | box-shadow: 0 1px #EBEBEB;
62 | background: #fff;
63 | border-radius: 3px;
64 | border: 1px solid;
65 | border-color: #E5E5E5 #D3D3D3 #B9C1C6;
66 | }
67 |
68 |
69 |
70 | /*************************** SWIPE NAVIGATION ********************/
71 |
72 | #swipe_direction_nav {
73 | display: table;
74 | margin: 0 auto;
75 | position: relative;
76 | text-align: center;
77 | }
78 |
79 | #swipe_direction_nav a {
80 | display: inline-block;
81 | width: 9px;
82 | height: 18px;
83 | text-indent: -9999px;
84 | margin: 0 30px;
85 | }
86 |
87 | #swipe_direction_nav .swipe-slider-next {
88 | background-position: 100% 0;
89 | }
90 |
91 | #swipe_bullet_wrapper {
92 | text-align: center;
93 | z-index: 10;
94 | float:left;
95 | }
96 |
97 | #swipe_bullet_wrapper a {
98 | display: inline-block;
99 | width: 14px;
100 | height: 14px;
101 | background: url('swipe_bullet.png') no-repeat 0 0;
102 | text-indent: -9999px;
103 | margin: 0 2px;
104 | background-position: 0 55%;
105 | }
106 | #swipe_bullet_wrapper a.active {
107 | background-position: 0 0;
108 | }
109 |
110 | .swipe-slider-prev {
111 | background-image: url("left-arrow.png");
112 | float:left;
113 | }
114 |
115 | .swipe-slider-next {
116 | background-image: url("right-arrow.png");
117 | float:left;
118 | }
119 |
120 | /*************************** SWIPE NAVIGATION ********************/
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Swipe 2
5 |
6 |
7 |
8 |
30 |
31 |
32 |
33 |
34 | Swipe 2
35 |
36 |
37 |
38 |
0
39 |
1
40 |
2
41 |
3
42 |
4
43 |
5
44 |
6
45 |
7
46 |
8
47 |
9
48 |
10
49 |
11
50 |
12
51 |
13
52 |
14
53 |
15
54 |
16
55 |
17
56 |
18
57 |
19
58 |
20
59 |
60 |
61 |
62 |
63 |
64 |
69 |
70 |
71 |
72 |
73 |
74 | prev
75 | next
76 |
77 |
78 |
79 |
80 |
81 |
82 | var element = document.getElementById('mySwipe');
83 | window.mySwipe = Swipe(element, {
84 | startSlide: 0,
85 | auto: 3000,
86 | autoRestart: true,
87 | continuous: true,
88 | disableScroll: true,
89 | stopPropagation: true,
90 | callback: function(index, element) {},
91 | transitionEnd: function(index, element) {}
92 | });
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 | window.mySwipe = $('#mySwipe').Swipe().data('Swipe');
101 |
102 |
103 |
104 |
105 |
106 |
107 |
131 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Swipe
2 |
3 | Swipe is the most accurate touch slider and extremely lightweight (only 5kb for minified version)
4 |
5 | ## Note
6 |
7 | Swipe is originally created by **[Brad Birdsall](https://github.com/thebird)** who seems not maintainning it, and this version is maintain by **[Xiuyu Li](https://github.com/nickleefly)** with new features and bugfix.
8 |
9 | ## Install
10 |
11 | You can directly install this package via Bower: `npm install swipe-js`
12 |
13 |
14 | ## Demo
15 |
16 | See [online example](http://nickleefly.github.io/swipe/)
17 |
18 | ## Usage
19 | Swipe only needs to follow a simple pattern. Here is an example:
20 |
21 | ``` html
22 |
29 | ```
30 |
31 | Above is the initial required structure– a series of elements wrapped in two containers. Place any content you want within the items. The containing div will need to be passed to the Swipe function like so:
32 |
33 | ``` js
34 | window.mySwipe = Swipe(document.getElementById('slider'));
35 | ```
36 |
37 | I always place this at the bottom of the page, externally, to verify the page is ready.
38 |
39 | Also Swipe needs just a few styles added to your stylesheet:
40 |
41 | ``` css
42 | .swipe {
43 | overflow: hidden;
44 | visibility: hidden;
45 | position: relative;
46 | }
47 | .swipe-wrap {
48 | overflow: hidden;
49 | position: relative;
50 | }
51 | .swipe-wrap > div {
52 | float:left;
53 | width:100%;
54 | position: relative;
55 | }
56 | ```
57 |
58 | ## Swipe now supports bullets and arrow navigation
59 |
60 | If you want to add arrows and bullets to your swipe wonder you would do something similar to this, but you can structure it as you like, this is just an example, but you can see in action if you open the index.html file:
61 |
62 | ``` html
63 |
68 | ```
69 |
70 | Also when you click on a bullet Swipe will slide to that specific section. Neat!
71 |
72 | Go ahead and give the demo a try and see how amazing Swipe is.
73 |
74 | Built-in bullet support and arrow navigation contributed by [Alex Budin](https://github.com/alex-b).
75 |
76 |
77 |
78 | ## Config Options
79 |
80 | Swipe can take an optional second parameter– an object of key/value settings:
81 |
82 | - **startSlide** Integer *(default:0)* - index position Swipe should start at
83 |
84 | - **speed** Integer *(default:300)* - speed of prev and next transitions in milliseconds.
85 |
86 | - **auto** Integer - begin with auto slideshow (time in milliseconds between slides)
87 |
88 | - **continuous** Boolean *(default:true)* - create an infinite feel with no endpoints
89 |
90 | - **disableScroll** Boolean *(default:false)* - stop any touches on this container from scrolling the page
91 |
92 | - **stopPropagation** Boolean *(default:false)* - stop event propagation
93 |
94 | - **callback** Function - runs at slide change.
95 |
96 | - **transitionEnd** Function - runs at the end slide transition.
97 |
98 | - **btnNextId** Function - the ID of the element that you want to trigger the next slide.
99 |
100 | - **btnPrevId** Function - the ID of the element that you want to trigger the previous slide.
101 |
102 | - **bulletWrapperId** Function - the wrapper that will contain the bullets related to your slides (you can style it at your free will in your CSS).
103 |
104 | - **bulletClass** Function - the CSS class that you have created for your bullet, if not specified a default 'swipe-bullet' will be used.
105 |
106 | - **bulletActiveClass** Function - the CSS class that represents the active state of your bullet, if not specified a default 'active' class will be used.
107 |
108 | ### Example
109 |
110 | ``` js
111 |
112 | window.mySwipe = new Swipe(document.getElementById('slider'), {
113 | startSlide: 2,
114 | speed: 400,
115 | auto: 3000,
116 | continuous: true,
117 | disableScroll: false,
118 | stopPropagation: false,
119 | callback: function(index, elem) {},
120 | transitionEnd: function(index, elem) {},
121 | btnNextId : 'swipe_next',
122 | btnPrevId : 'swipe_prev',
123 | bulletWrapperId : 'swipe_bullet_wrapper',
124 | bulletClass : 'swipe-bullet',
125 | bulletActiveClass : 'active',
126 | });
127 |
128 | ```
129 |
130 | ## Swipe API
131 |
132 | Swipe exposes a few functions that can be useful for script control of your slider.
133 |
134 | `prev()` slide to prev
135 |
136 | `next()` slide to next
137 |
138 | `getPos()` returns current slide index position
139 |
140 | `getNumSlides()` returns the total amount of slides
141 |
142 | `slide(index, duration)` slide to set index position (duration: speed of transition in milliseconds)
143 |
144 | `restart()` restart the auto slide
145 |
146 | `stop()` stop the auto slide
147 |
148 | `kill()` remove swipe totally
149 |
150 | ## Browser Support
151 | Swipe is now compatible with all browsers, including IE7+. Swipe works best on devices that support CSS transforms and touch, but can be used without these as well. A few helper methods determine touch and CSS transition support and choose the proper animation methods accordingly.
152 |
153 | ## Who's using Swipe
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 | Shoot me a [note](mailto:nickleefly@gmail.com) if you want your logo here
162 |
163 | ## License
164 | Copyright (c) 2015 Brad Birdsall Licensed under the [The MIT License (MIT)](http://opensource.org/licenses/MIT).
165 |
--------------------------------------------------------------------------------
/swipe.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Swipe 2.0
3 | *
4 | * Brad Birdsall and Xiuyu Li
5 | * Copyright 2015, MIT License
6 | *
7 | */
8 |
9 | function Swipe(container, options) {
10 |
11 | "use strict";
12 |
13 | // utilities
14 | var noop = function() {}; // simple no operation function
15 | var offloadFn = function(fn) { setTimeout(fn || noop, 0) }; // offload a functions execution
16 |
17 | // check browser capabilities
18 | var browser = {
19 | addEventListener: !!window.addEventListener,
20 | touch: ('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch,
21 | transitions: (function(temp) {
22 | var props = ['transitionProperty', 'WebkitTransition', 'MozTransition', 'OTransition', 'msTransition'];
23 | for ( var i in props ) if (temp.style[ props[i] ] !== undefined) return true;
24 | return false;
25 | })(document.createElement('swipe'))
26 | };
27 |
28 | // quit if no root element
29 | if (!container) return;
30 | var element = container.children[0];
31 | var slides, slidePos, width, length;
32 | options = options || {};
33 | options.bulletWrapperClass = options.bulletWrapperClass ? '.' + options.bulletWrapperClass : '';
34 | var bulletWrapper = options.bulletWrapperClass || null;
35 | var bulletClass = options.bulletClass || 'swipe-bullet';
36 | var activeBulletClass = options.bulletActiveClass || 'active';
37 | var index = parseInt(options.startSlide, 10) || 0;
38 | var position = index;
39 | var clonedSlides = false;
40 | var speed = options.speed || 300;
41 | options.continuous = options.continuous !== undefined ? options.continuous : true;
42 |
43 | // AutoRestart option: auto restart slideshow after user's touch event
44 | options.autoRestart = options.autoRestart !== undefined ? options.autoRestart : true;
45 |
46 | //add a css class to a dom element
47 | function addClassToElem(elem,value){
48 | var rspaces = /\s+/;
49 | var classNames = (value || "").split( rspaces );
50 | var className = " " + elem.className + " ",
51 | setClass = elem.className;
52 | for ( var c = 0, cl = classNames.length; c < cl; c++ ) {
53 |
54 | if ( className.indexOf( " " + classNames[c] + " " ) < 0 ) {
55 | setClass += " " + classNames[c];
56 | }
57 |
58 | }
59 | elem.className = setClass.replace(/^\s+|\s+$/g,''); //trim
60 | }
61 |
62 | //remove a css class from a dom element
63 | function removeClassFromElem(elem,value){
64 | var rspaces = /\s+/;
65 | var rclass = /[\n\t]/g
66 | var classNames = (value || "").split( rspaces );
67 | var className = (" " + elem.className + " ").replace(rclass, " ");
68 |
69 | for ( var c = 0, cl = classNames.length; c < cl; c++ ) {
70 | className = className.replace(" " + classNames[c] + " ", " ");
71 | }
72 |
73 | elem.className = className.replace(/^\s+|\s+$/g,''); //trim
74 | }
75 |
76 |
77 | function addEventHandler(elem,eventType,handler) {
78 | if (elem.addEventListener)
79 | elem.addEventListener (eventType,handler,false);
80 | else if (elem.attachEvent)
81 | elem.attachEvent ('on'+eventType,handler);
82 | }
83 |
84 | // get the target of a click event, we need this so we have support for multiple browsers
85 | function getTarget(e) {
86 | var clickTarget;
87 | if (e.target) clickTarget = e.target;
88 | else if (e.srcElement) clickTarget = e.srcElement;
89 | if (clickTarget.nodeType == 3) // defeat Safari bug
90 | clickTarget = clickTarget.parentNode;
91 |
92 | return clickTarget;
93 | }
94 |
95 | function setup() {
96 |
97 | // cache slides
98 | slides = element.children;
99 | length = slides.length;
100 |
101 | // set continuous to false if only one slide
102 | if (slides.length < 2) options.continuous = false;
103 |
104 | //special case if two slides
105 | if (browser.transitions && options.continuous && slides.length < 3) {
106 | element.appendChild(slides[0].cloneNode(true));
107 | element.appendChild(element.children[1].cloneNode(true));
108 | slides = element.children;
109 | clonedSlides = true;
110 | }
111 |
112 | // create an array to store current positions of each slide
113 | slidePos = new Array(slides.length);
114 |
115 | // determine width of each slide
116 | width = container.getBoundingClientRect().width || container.offsetWidth;
117 |
118 | element.style.width = (slides.length * width) + 'px';
119 |
120 | // stack elements
121 | var pos = slides.length;
122 |
123 | if (bulletWrapper != null) {
124 |
125 | var bulletWrapperObj = container.querySelector(bulletWrapper);
126 | var bulletInc = 0;
127 | bulletWrapperObj.innerHTML = '';
128 |
129 | }
130 |
131 | while(pos--) {
132 |
133 | var slide = slides[pos];
134 |
135 | slide.style.width = width + 'px';
136 | slide.setAttribute('data-index', pos);
137 |
138 | if (clonedSlides === false || pos <= 1) {
139 | if (bulletWrapperObj) {
140 | bulletWrapperObj.innerHTML += '' + bulletInc + ' ';
141 | bulletInc++;
142 | }
143 | }
144 |
145 | if (browser.transitions) {
146 | slide.style.left = (pos * -width) + 'px';
147 | move(pos, index > pos ? -width : (index < pos ? width : 0), 0);
148 | }
149 |
150 | }
151 |
152 | // reposition elements before and after index
153 | if (options.continuous && browser.transitions) {
154 | move(circle(index-1), -width, 0);
155 | move(circle(index+1), width, 0);
156 | }
157 |
158 | if (!browser.transitions) element.style.left = (index * -width) + 'px';
159 |
160 | container.style.visibility = 'visible';
161 | container.className = container.className + ' initialised';
162 |
163 | // Need to highlight the bullet assigned to the current slide
164 | // the setup function is called on window resize so we cant highlight the first bullet but the current index
165 | hightlightCurrentBullet(index);
166 | }
167 |
168 | function hightlightCurrentBullet(to){
169 | if (bulletWrapper){
170 |
171 | var bulletWrapperObj = container.querySelector(bulletWrapper);
172 | var childObj = bulletWrapperObj.childNodes;
173 |
174 | for (var i=0;i index, use to = -slides.length + to
218 | if (direction !== natural_direction) to = -direction * slides.length + to;
219 |
220 | }
221 |
222 | var diff = Math.abs(index-to) - 1;
223 |
224 | // move all the slides between index and to in the right direction
225 | while (diff--) move( circle((to > index ? to : index) - diff - 1), width * direction, 0);
226 |
227 | to = circle(to);
228 |
229 | move(index, width * direction, slideSpeed || speed);
230 | move(to, 0, slideSpeed || speed);
231 |
232 | if (options.continuous) move(circle(to - direction), -(width * direction), 0); // we need to get the next in place
233 |
234 | } else {
235 |
236 | to = circle(to);
237 | animate(index * -width, to * -width, slideSpeed || speed);
238 | //no fallback for a circular continuous if the browser does not accept transitions
239 | }
240 |
241 | index = to;
242 |
243 | position = clonedSlides ? (index % 2) : index;
244 |
245 | // Highlighting the current slide bullet
246 | hightlightCurrentBullet(position);
247 |
248 | offloadFn(options.callback && options.callback(position, slides[index]));
249 | }
250 |
251 | function move(index, dist, speed) {
252 |
253 | translate(index, dist, speed);
254 | slidePos[index] = dist;
255 |
256 | }
257 |
258 | function translate(index, dist, speed) {
259 |
260 | var slide = slides[index];
261 | var style = slide && slide.style;
262 |
263 | if (!style) return;
264 |
265 | style.webkitTransitionDuration =
266 | style.MozTransitionDuration =
267 | style.msTransitionDuration =
268 | style.OTransitionDuration =
269 | style.transitionDuration = speed + 'ms';
270 |
271 | style.webkitTransform = 'translate(' + dist + 'px,0)' + 'translateZ(0)';
272 | style.msTransform =
273 | style.MozTransform =
274 | style.OTransform = 'translateX(' + dist + 'px)';
275 |
276 | }
277 |
278 | function animate(from, to, speed) {
279 |
280 | // if not an animation, just reposition
281 | if (!speed) {
282 |
283 | element.style.left = to + 'px';
284 | return;
285 |
286 | }
287 |
288 | var start = +new Date;
289 |
290 | var timer = setInterval(function() {
291 |
292 | var timeElap = +new Date - start;
293 |
294 | if (timeElap > speed) {
295 |
296 | element.style.left = to + 'px';
297 |
298 | if (delay) begin();
299 |
300 | options.transitionEnd && options.transitionEnd.call(event, position, slides[index]);
301 |
302 | clearInterval(timer);
303 | return;
304 |
305 | }
306 |
307 | element.style.left = (( (to - from) * (Math.floor((timeElap / speed) * 100) / 100) ) + from) + 'px';
308 |
309 | }, 4);
310 |
311 | }
312 |
313 | // setup auto slideshow
314 | var delay = options.auto || 0;
315 | var interval;
316 |
317 | function begin() {
318 |
319 | interval = setTimeout(next, delay);
320 |
321 | }
322 |
323 | function stop() {
324 |
325 | delay = 0;
326 | clearTimeout(interval);
327 |
328 | }
329 |
330 | function restart() {
331 | stop();
332 | delay = options.auto || 0;
333 | begin();
334 | }
335 |
336 | // setup initial vars
337 | var start = {};
338 | var delta = {};
339 | var isScrolling;
340 |
341 | // setup event capturing
342 | var events = {
343 |
344 | handleEvent: function(event) {
345 |
346 | switch (event.type) {
347 | case 'touchstart': this.start(event); break;
348 | case 'touchmove': this.move(event); break;
349 | case 'touchend': offloadFn(this.end(event)); break;
350 | case 'webkitTransitionEnd':
351 | case 'msTransitionEnd':
352 | case 'oTransitionEnd':
353 | case 'otransitionend':
354 | case 'transitionend': offloadFn(this.transitionEnd(event)); break;
355 | case 'resize': offloadFn(setup); break;
356 | }
357 |
358 | if (options.stopPropagation) event.stopPropagation();
359 |
360 | },
361 | start: function(event) {
362 |
363 | var touches = event.touches[0];
364 |
365 | // measure start values
366 | start = {
367 |
368 | // get initial touch coords
369 | x: touches.pageX,
370 | y: touches.pageY,
371 |
372 | // store time to determine touch duration
373 | time: +new Date
374 |
375 | };
376 |
377 | // used for testing first move event
378 | isScrolling = undefined;
379 |
380 | // reset delta and end measurements
381 | delta = {};
382 |
383 | // attach touchmove and touchend listeners
384 | element.addEventListener('touchmove', this, false);
385 | element.addEventListener('touchend', this, false);
386 |
387 | },
388 | move: function(event) {
389 |
390 | // ensure swiping with one touch and not pinching
391 | if ( event.touches.length > 1 || event.scale && event.scale !== 1) return
392 |
393 | if (options.disableScroll) event.preventDefault();
394 |
395 | var touches = event.touches[0];
396 |
397 | // measure change in x and y
398 | delta = {
399 | x: touches.pageX - start.x,
400 | y: touches.pageY - start.y
401 | };
402 |
403 | // determine if scrolling test has run - one time test
404 | if ( typeof isScrolling === 'undefined') {
405 | isScrolling = !!( isScrolling || Math.abs(delta.x) < Math.abs(delta.y) );
406 | }
407 |
408 | // if user is not trying to scroll vertically
409 | if (!isScrolling) {
410 |
411 | // prevent native scrolling
412 | event.preventDefault();
413 |
414 | // stop slideshow
415 | stop();
416 |
417 | // increase resistance if first or last slide
418 | if (options.continuous) { // we don't add resistance at the end
419 |
420 | translate(circle(index-1), delta.x + slidePos[circle(index-1)], 0);
421 | translate(index, delta.x + slidePos[index], 0);
422 | translate(circle(index+1), delta.x + slidePos[circle(index+1)], 0);
423 |
424 | } else {
425 |
426 | delta.x =
427 | delta.x /
428 | ( (!index && delta.x > 0 // if first slide and sliding left
429 | || index == slides.length - 1 // or if last slide and sliding right
430 | && delta.x < 0 // and if sliding at all
431 | ) ?
432 | ( Math.abs(delta.x) / width + 1 ) // determine resistance level
433 | : 1 ); // no resistance if false
434 |
435 | // translate 1:1
436 | translate(index-1, delta.x + slidePos[index-1], 0);
437 | translate(index, delta.x + slidePos[index], 0);
438 | translate(index+1, delta.x + slidePos[index+1], 0);
439 | }
440 |
441 | }
442 |
443 | },
444 | end: function(event) {
445 |
446 | // measure duration
447 | var duration = +new Date - start.time;
448 |
449 | // determine if slide attempt triggers next/prev slide
450 | var isValidSlide =
451 | Number(duration) < 250 // if slide duration is less than 250ms
452 | && Math.abs(delta.x) > 20 // and if slide amt is greater than 20px
453 | || Math.abs(delta.x) > width/2; // or if slide amt is greater than half the width
454 |
455 | // determine if slide attempt is past start and end
456 | var isPastBounds =
457 | !index && delta.x > 0 // if first slide and slide amt is greater than 0
458 | || index == slides.length - 1 && delta.x < 0; // or if last slide and slide amt is less than 0
459 |
460 | if (options.continuous) isPastBounds = false;
461 |
462 | // determine direction of swipe (true:right, false:left)
463 | var direction = delta.x < 0;
464 |
465 | // if not scrolling vertically
466 | if (!isScrolling) {
467 |
468 | if (isValidSlide && !isPastBounds) {
469 |
470 | if (direction) {
471 |
472 | if (options.continuous) { // we need to get the next in this direction in place
473 |
474 | move(circle(index-1), -width, 0);
475 | move(circle(index+2), width, 0);
476 |
477 | } else {
478 | move(index-1, -width, 0);
479 | }
480 |
481 | move(index, slidePos[index]-width, speed);
482 | move(circle(index+1), slidePos[circle(index+1)]-width, speed);
483 | index = circle(index+1);
484 |
485 | } else {
486 | if (options.continuous) { // we need to get the next in this direction in place
487 |
488 | move(circle(index+1), width, 0);
489 | move(circle(index-2), -width, 0);
490 |
491 | } else {
492 | move(index+1, width, 0);
493 | }
494 |
495 | move(index, slidePos[index]+width, speed);
496 | move(circle(index-1), slidePos[circle(index-1)]+width, speed);
497 | index = circle(index-1);
498 |
499 | }
500 |
501 | position = clonedSlides ? (index % 2) : index;
502 | options.callback && options.callback(position, slides[index]);
503 |
504 | } else {
505 |
506 | if (options.continuous) {
507 |
508 | move(circle(index-1), -width, speed);
509 | move(index, 0, speed);
510 | move(circle(index+1), width, speed);
511 |
512 | } else {
513 |
514 | move(index-1, -width, speed);
515 | move(index, 0, speed);
516 | move(index+1, width, speed);
517 | }
518 |
519 | }
520 |
521 | }
522 |
523 | // kill touchmove and touchend event listeners until touchstart called again
524 | element.removeEventListener('touchmove', events, false)
525 | element.removeEventListener('touchend', events, false)
526 |
527 | // we need to highlight the bullet when we swipe the slide, not just on next or prev
528 | hightlightCurrentBullet(index);
529 | },
530 | transitionEnd: function(event) {
531 |
532 | if (parseInt(event.target.getAttribute('data-index'), 10) == index) {
533 |
534 | if (delay || options.autoRestart) restart();
535 |
536 | options.transitionEnd && options.transitionEnd.call(event, position, slides[index]);
537 |
538 | }
539 |
540 | }
541 |
542 | };
543 |
544 | // trigger setup
545 | setup();
546 |
547 | // start auto slideshow if applicable
548 | if (delay) begin();
549 |
550 |
551 | // add event listeners
552 | if (browser.addEventListener) {
553 |
554 |
555 | // We need to add the listeners on the prev and next buttons if the specific DOM ids were sent when the Swipe object was instantiated
556 | // We keep them separated because a user might want to add only one button (either next or prev)
557 | if (options.btnNextClass) {
558 |
559 | var nextButton = container.querySelector(options.btnNextClass);
560 |
561 | addEventHandler(nextButton,"click",function(e){
562 | e.preventDefault();
563 | offloadFn(stop.call());
564 | offloadFn(next.call());
565 | });
566 |
567 | }
568 |
569 | if (options.btnPrevClass) {
570 |
571 | var prevButton = container.querySelector(options.btnPrevClass);
572 |
573 | addEventHandler(prevButton,"click",function(e){
574 | e.preventDefault();
575 | offloadFn(stop.call());
576 | offloadFn(prev.call());
577 | });
578 |
579 | }
580 |
581 | if (options.bulletWrapperClass) {
582 |
583 | var bulletWrap = container.querySelector(options.bulletWrapperClass);
584 |
585 | addEventHandler(bulletWrap,"click",function(e){
586 | if (getTarget(e).innerHTML) {
587 | var slideNumber = parseInt(getTarget(e).innerHTML);
588 | if (!isNaN(slideNumber)) {
589 | e.preventDefault();
590 | offloadFn(stop.call());
591 | offloadFn(slide(slideNumber));
592 | }
593 | }
594 | });
595 |
596 | }
597 |
598 |
599 | // set touchstart event on element
600 | if (browser.touch) element.addEventListener('touchstart', events, false);
601 |
602 | if (browser.transitions) {
603 | element.addEventListener('webkitTransitionEnd', events, false);
604 | element.addEventListener('msTransitionEnd', events, false);
605 | element.addEventListener('oTransitionEnd', events, false);
606 | element.addEventListener('otransitionend', events, false);
607 | element.addEventListener('transitionend', events, false);
608 | }
609 |
610 | // set resize event on window
611 | window.addEventListener('resize', events, false);
612 |
613 | } else {
614 |
615 | window.onresize = function () { setup() }; // to play nice with old IE
616 |
617 | }
618 |
619 | // expose the Swipe API
620 | return {
621 | setup: function() {
622 |
623 | setup();
624 |
625 | },
626 | slide: function(to, speed) {
627 |
628 | // cancel slideshow
629 | stop();
630 |
631 | slide(to, speed);
632 |
633 | },
634 | prev: function() {
635 |
636 | // cancel slideshow
637 | stop();
638 |
639 | prev();
640 |
641 | },
642 | next: function() {
643 |
644 | // cancel slideshow
645 | stop();
646 |
647 | next();
648 |
649 | },
650 | restart: function() {
651 |
652 | // Restart slideshow
653 | restart();
654 |
655 | },
656 | stop: function() {
657 |
658 | // cancel slideshow
659 | stop();
660 |
661 | },
662 | getPos: function() {
663 |
664 | // return current index position
665 | return position;
666 |
667 | },
668 | getNumSlides: function() {
669 |
670 | // return total number of slides
671 | return length;
672 | },
673 | kill: function() {
674 |
675 | // cancel slideshow
676 | stop();
677 |
678 | // reset element
679 | element.style.width = '';
680 | element.style.left = '';
681 |
682 | // reset slides
683 | var pos = slides.length;
684 | while (pos--) {
685 |
686 | var slide = slides[pos];
687 | slide.style.width = '';
688 | slide.style.left = '';
689 |
690 | if (browser.transitions) translate(pos, 0, 0);
691 |
692 | }
693 |
694 | // removed event listeners
695 | if (browser.addEventListener) {
696 |
697 | // remove current event listeners
698 | element.removeEventListener('touchstart', events, false);
699 | element.removeEventListener('webkitTransitionEnd', events, false);
700 | element.removeEventListener('msTransitionEnd', events, false);
701 | element.removeEventListener('oTransitionEnd', events, false);
702 | element.removeEventListener('otransitionend', events, false);
703 | element.removeEventListener('transitionend', events, false);
704 | window.removeEventListener('resize', events, false);
705 |
706 | }
707 | else {
708 |
709 | window.onresize = null;
710 |
711 | }
712 |
713 | }
714 | }
715 |
716 | }
717 |
718 |
719 | if ( window.jQuery || window.Zepto ) {
720 | (function($) {
721 | $.fn.Swipe = function(params) {
722 | return this.each(function() {
723 | $(this).data('Swipe', new Swipe($(this)[0], params));
724 | });
725 | }
726 | })( window.jQuery || window.Zepto )
727 | }
728 |
729 | if(typeof module === "object" && typeof module.exports === "object") {
730 | module.exports = Swipe;
731 | } else {
732 | window.Swipe = Swipe;
733 | }
734 |
--------------------------------------------------------------------------------