peppermint.js 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716
  1. /*!
  2. * Peppermint touch slider
  3. * v. 1.3.7 | https://github.com/wilddeer/Peppermint
  4. * Copyright Oleg Korsunsky | http://wd.dizaina.net/
  5. *
  6. * Depends on Event Burrito (included) | https://github.com/wilddeer/Event-Burrito
  7. * MIT License
  8. */
  9. function Peppermint(_this, options) {
  10. var slider = {
  11. slides: [],
  12. dots: [],
  13. left: 0
  14. },
  15. slidesNumber,
  16. flickThreshold = 200, //Flick threshold (ms)
  17. activeSlide = 0,
  18. slideWidth,
  19. dotBlock,
  20. slideBlock,
  21. slideshowTimeoutId,
  22. slideshowActive,
  23. animationTimer;
  24. //default options
  25. var o = {
  26. speed: 300, //transition between slides in ms
  27. touchSpeed: 300, //transition between slides in ms after touch
  28. slideshow: false, //launch slideshow at start
  29. slideshowInterval: 4000,
  30. stopSlideshowAfterInteraction: false, //stop slideshow after user interaction
  31. startSlide: 0, //first slide to show
  32. mouseDrag: true, //enable mouse drag
  33. disableIfOneSlide: true,
  34. cssPrefix: 'peppermint-',
  35. dots: false, //show dots
  36. dotsPrepend: false, //dots before slides
  37. dotsContainer: undefined,
  38. slidesContainer: undefined,
  39. onSlideChange: undefined, //slide change callback
  40. onSetup: undefined //setup callback
  41. };
  42. //merge user options into defaults
  43. options && mergeObjects(o, options);
  44. var classes = {
  45. inactive: o.cssPrefix + 'inactive',
  46. active: o.cssPrefix + 'active',
  47. mouse: o.cssPrefix + 'mouse',
  48. drag: o.cssPrefix + 'drag',
  49. slides: o.cssPrefix + 'slides',
  50. dots: o.cssPrefix + 'dots',
  51. activeDot: o.cssPrefix + 'active-dot',
  52. mouseClicked: o.cssPrefix + 'mouse-clicked'
  53. };
  54. //feature detects
  55. var support = {
  56. transforms: testProp('transform'),
  57. transitions: testProp('transition')
  58. };
  59. function mergeObjects(targetObj, sourceObject) {
  60. for (var key in sourceObject) {
  61. if (sourceObject.hasOwnProperty(key)) {
  62. targetObj[key] = sourceObject[key];
  63. }
  64. }
  65. }
  66. function testProp(prop) {
  67. var prefixes = ['Webkit', 'Moz', 'O', 'ms'],
  68. block = document.createElement('div');
  69. if (block.style[prop] !== undefined) return true;
  70. prop = prop.charAt(0).toUpperCase() + prop.slice(1);
  71. for (var i in prefixes) {
  72. if (block.style[prefixes[i]+prop] !== undefined) return true;
  73. }
  74. return false;
  75. }
  76. function addClass(el, cl) {
  77. if (!new RegExp('(\\s|^)'+cl+'(\\s|$)').test(el.className)) {
  78. el.className += ' ' + cl;
  79. }
  80. }
  81. function removeClass(el, cl) {
  82. el.className = el.className.replace(new RegExp('(\\s+|^)'+cl+'(\\s+|$)', 'g'), ' ').replace(/^\s+|\s+$/g, '');
  83. }
  84. //n - slide number (starting from 0)
  85. //speed - transition in ms, can be omitted
  86. function changeActiveSlide(n, speed) {
  87. if (n<0) {
  88. n = 0;
  89. }
  90. else if (n>slidesNumber-1) {
  91. n = slidesNumber-1;
  92. }
  93. //change active dot
  94. for (var i = slider.dots.length - 1; i >= 0; i--) {
  95. removeClass(slider.dots[i], classes.activeDot);
  96. }
  97. addClass(slider.dots[n], classes.activeDot);
  98. activeSlide = n;
  99. changePos(-n*slider.width, (speed===undefined?o.speed:speed));
  100. //reset slideshow timeout whenever active slide is changed for whatever reason
  101. stepSlideshow();
  102. //API callback
  103. o.onSlideChange && o.onSlideChange(n);
  104. return n;
  105. }
  106. //changes position of the slider (in px) with given speed (in ms)
  107. function changePos(pos, speed) {
  108. var time = speed?speed+'ms':'';
  109. slideBlock.style.webkitTransitionDuration =
  110. slideBlock.style.MozTransitionDuration =
  111. slideBlock.style.msTransitionDuration =
  112. slideBlock.style.OTransitionDuration =
  113. slideBlock.style.transitionDuration = time;
  114. setPos(pos);
  115. }
  116. //fallback to `setInterval` animations for UAs with no CSS transitions
  117. function changePosFallback(pos, speed) {
  118. animationTimer && clearInterval(animationTimer);
  119. if (!speed) {
  120. setPos(pos);
  121. return;
  122. }
  123. var startTime = +new Date,
  124. startPos = slider.left;
  125. animationTimer = setInterval(function() {
  126. //rough bezier emulation
  127. var diff, y,
  128. elapsed = +new Date - startTime,
  129. f = elapsed / speed,
  130. bezier = [0, 0.7, 1, 1];
  131. function getPoint(p1, p2) {
  132. return (p2-p1)*f + p1;
  133. }
  134. if (f >= 1) {
  135. setPos(pos);
  136. clearInterval(animationTimer);
  137. return;
  138. }
  139. diff = pos - startPos;
  140. y = getPoint(
  141. getPoint(getPoint(bezier[0], bezier[1]), getPoint(bezier[1], bezier[2])),
  142. getPoint(getPoint(bezier[1], bezier[2]), getPoint(bezier[2], bezier[3]))
  143. );
  144. setPos(Math.floor(y*diff + startPos));
  145. }, 15);
  146. }
  147. //sets position of the slider (in px)
  148. function setPos(pos) {
  149. slideBlock.style.webkitTransform = 'translate('+pos+'px,0) translateZ(0)';
  150. slideBlock.style.msTransform =
  151. slideBlock.style.MozTransform =
  152. slideBlock.style.OTransform =
  153. slideBlock.style.transform = 'translateX('+pos+'px)';
  154. slider.left = pos;
  155. }
  156. //`setPos` fallback for UAs with no CSS transforms support
  157. function setPosFallback(pos) {
  158. slideBlock.style.left = pos+'px';
  159. slider.left = pos;
  160. }
  161. function nextSlide() {
  162. var n = activeSlide + 1;
  163. if (n > slidesNumber - 1) {
  164. n = 0;
  165. }
  166. return changeActiveSlide(n);
  167. }
  168. function prevSlide() {
  169. var n = activeSlide - 1;
  170. if (n < 0) {
  171. n = slidesNumber - 1;
  172. }
  173. return changeActiveSlide(n);
  174. }
  175. function startSlideshow() {
  176. slideshowActive = true;
  177. stepSlideshow();
  178. }
  179. //sets or resets timeout before switching to the next slide
  180. function stepSlideshow() {
  181. if (slideshowActive) {
  182. slideshowTimeoutId && clearTimeout(slideshowTimeoutId);
  183. slideshowTimeoutId = setTimeout(function() {
  184. nextSlide();
  185. },
  186. o.slideshowInterval);
  187. }
  188. }
  189. //pauses slideshow until `stepSlideshow` is invoked
  190. function pauseSlideshow() {
  191. slideshowTimeoutId && clearTimeout(slideshowTimeoutId);
  192. }
  193. function stopSlideshow() {
  194. slideshowActive = false;
  195. slideshowTimeoutId && clearTimeout(slideshowTimeoutId);
  196. }
  197. //this should be invoked when the width of the slider is changed
  198. function onWidthChange() {
  199. slider.width = _this.offsetWidth;
  200. //have to do this in `px` because of webkit's rounding errors :-(
  201. slideBlock.style.width = slider.width*slidesNumber+'px';
  202. for (var i = 0; i < slidesNumber; i++) {
  203. slider.slides[i].style.width = slider.width+'px';
  204. }
  205. changePos(-activeSlide*slider.width);
  206. }
  207. function addEvent(el, event, func, bool) {
  208. if (!event) return;
  209. el.addEventListener? el.addEventListener(event, func, !!bool): el.attachEvent('on'+event, func);
  210. }
  211. //init touch events
  212. function touchInit() {
  213. EventBurrito(slideBlock, {
  214. mouse: o.mouseDrag,
  215. start: function(event, start) {
  216. //firefox doesn't want to apply cursor from `:active` CSS rule, have to add a class :-/
  217. addClass(_this, classes.drag);
  218. },
  219. move: function(event, start, diff, speed) {
  220. pauseSlideshow(); //pause the slideshow when touch is in progress
  221. //if it's first slide and moving left or last slide and moving right -- resist!
  222. diff.x =
  223. diff.x /
  224. (
  225. (!activeSlide && diff.x > 0
  226. || activeSlide == slidesNumber - 1 && diff.x < 0)
  227. ?
  228. (Math.abs(diff.x)/slider.width*2 + 1)
  229. :
  230. 1
  231. );
  232. //change position of the slider appropriately
  233. changePos(diff.x - slider.width*activeSlide);
  234. },
  235. end: function(event, start, diff, speed) {
  236. if (diff.x) {
  237. var ratio = Math.abs(diff.x)/slider.width,
  238. //How many slides to skip. Remainder > 0.25 counts for one slide.
  239. skip = Math.floor(ratio) + (ratio - Math.floor(ratio) > 0.25?1:0),
  240. //Super-duper formula to detect a flick.
  241. //First, it's got to be fast enough.
  242. //Second, if `skip==0`, 20px move is enough to switch to the next slide.
  243. //If `skip>0`, it's enough to slide to the middle of the slide minus `slider.width/9` to skip even further.
  244. flick = diff.time < flickThreshold+flickThreshold*skip/1.8 && Math.abs(diff.x) - skip*slider.width > (skip?-slider.width/9:20);
  245. skip += (flick?1:0);
  246. if (diff.x < 0) {
  247. changeActiveSlide(activeSlide+skip, o.touchSpeed);
  248. }
  249. else {
  250. changeActiveSlide(activeSlide-skip, o.touchSpeed);
  251. }
  252. o.stopSlideshowAfterInteraction && stopSlideshow();
  253. }
  254. //remove the drag class
  255. removeClass(_this, classes.drag);
  256. }
  257. });
  258. }
  259. function setup() {
  260. var slideSource = o.slidesContainer || _this,
  261. dotsTarget = o.dotsContainer || _this;
  262. if (o.disableIfOneSlide && slideSource.children.length <= 1) return;
  263. //If current UA doesn't support css transforms or transitions -- use fallback functions.
  264. //(Using separate functions instead of checks for better performance)
  265. if (!support.transforms || !!window.opera) setPos = setPosFallback;
  266. if (!support.transitions || !!window.opera) changePos = changePosFallback;
  267. slideBlock = o.slidesContainer || document.createElement('div');
  268. addClass(slideBlock, classes.slides);
  269. //get slides & generate dots
  270. for (var i = 0, l = slideSource.children.length; i < l; i++) {
  271. var slide = slideSource.children[i],
  272. dot = document.createElement('li');
  273. slider.slides.push(slide);
  274. //`tabindex` makes dots tabbable
  275. dot.setAttribute('tabindex', '0');
  276. dot.setAttribute('role', 'button');
  277. dot.innerHTML = '<span></span>';
  278. (function(x, dotClosure) {
  279. //bind events to dots
  280. addEvent(dotClosure, 'click', function(event) {
  281. changeActiveSlide(x);
  282. o.stopSlideshowAfterInteraction && stopSlideshow();
  283. });
  284. //Bind the same function to Enter key except for the `blur` part -- I dont't want
  285. //the focus to be lost when the user is using his keyboard to navigate.
  286. addEvent(dotClosure, 'keyup', function(event) {
  287. if (event.keyCode == 13) {
  288. changeActiveSlide(x);
  289. o.stopSlideshowAfterInteraction && stopSlideshow();
  290. }
  291. });
  292. //Don't want to disable outlines completely for accessibility reasons.
  293. //Instead, add class with `outline: 0` on mouseup and remove it on blur.
  294. addEvent(dotClosure, 'mouseup', function(event) {
  295. addClass(dotClosure, classes.mouseClicked);
  296. });
  297. //capturing fixes IE bug
  298. addEvent(dotClosure, 'blur', function(){
  299. removeClass(dotClosure, classes.mouseClicked);
  300. }, true);
  301. //This solves tabbing problems:
  302. //When an element inside a slide catches focus we switch to that slide
  303. //and reset `scrollLeft` of the slider block.
  304. //`SetTimeout` solves Chrome's bug.
  305. //Event capturing is used to catch events on the slide level.
  306. //Since older IEs don't have capturing, `onfocusin` is used as a fallback.
  307. addEvent(slide, 'focus', slide.onfocusin = function(e) {
  308. _this.scrollLeft = 0;
  309. setTimeout(function() {
  310. _this.scrollLeft = 0;
  311. }, 0);
  312. changeActiveSlide(x);
  313. }, true);
  314. })(i, dot)
  315. slider.dots.push(dot);
  316. }
  317. slidesNumber = slider.slides.length;
  318. slideWidth = 100/slidesNumber;
  319. addClass(_this, classes.active);
  320. removeClass(_this, classes.inactive);
  321. o.mouseDrag && addClass(_this, classes.mouse);
  322. slider.width = _this.offsetWidth;
  323. //had to do this in `px` because of webkit's rounding errors :-(
  324. slideBlock.style.width = slider.width*slidesNumber+'px';
  325. for (var i = 0; i < slidesNumber; i++) {
  326. slider.slides[i].style.width = slider.width+'px';
  327. slideBlock.appendChild(slider.slides[i]);
  328. }
  329. if (!o.slidesContainer) _this.appendChild(slideBlock);
  330. //append dots
  331. if (o.dots && slidesNumber > 1) {
  332. dotBlock = document.createElement('ul');
  333. addClass(dotBlock, classes.dots);
  334. for (var i = 0, l = slider.dots.length; i < l; i++) {
  335. dotBlock.appendChild(slider.dots[i]);
  336. }
  337. if (o.dotsPrepend) {
  338. dotsTarget.insertBefore(dotBlock,dotsTarget.firstChild);
  339. }
  340. else {
  341. dotsTarget.appendChild(dotBlock);
  342. }
  343. }
  344. //watch for slider width changes
  345. addEvent(window, 'resize', onWidthChange);
  346. addEvent(window, 'orientationchange', onWidthChange);
  347. //init first slide, timeout to expose the API first
  348. setTimeout(function() {
  349. changeActiveSlide(o.startSlide, 0);
  350. }, 0);
  351. //init slideshow
  352. if (o.slideshow) startSlideshow();
  353. touchInit();
  354. //API callback, timeout to expose the API first
  355. setTimeout(function() {
  356. o.onSetup && o.onSetup(slidesNumber);
  357. }, 0);
  358. }
  359. //Init
  360. setup();
  361. //expose the API
  362. return {
  363. slideTo: function(slide) {
  364. return changeActiveSlide(parseInt(slide, 10));
  365. },
  366. next: nextSlide,
  367. prev: prevSlide,
  368. //start slideshow
  369. start: startSlideshow,
  370. //stop slideshow
  371. stop: stopSlideshow,
  372. //pause slideshow until the next slide change
  373. pause: pauseSlideshow,
  374. //get current slide number
  375. getCurrentPos: function() {
  376. return activeSlide;
  377. },
  378. //get total number of slides
  379. getSlidesNumber: function() {
  380. return slidesNumber;
  381. },
  382. //invoke this when the slider's width is changed
  383. recalcWidth: onWidthChange
  384. };
  385. };
  386. //if jQuery is present -- create a plugin
  387. if (window.jQuery) {
  388. (function($) {
  389. $.fn.Peppermint = function(options) {
  390. this.each(function() {
  391. $(this).data('Peppermint', Peppermint(this, options));
  392. });
  393. return this;
  394. };
  395. })(window.jQuery);
  396. }
  397. /*!
  398. * Event Burrito is a touch / mouse / pointer event unifier
  399. * https://github.com/wilddeer/Event-Burrito
  400. * Copyright Oleg Korsunsky | http://wd.dizaina.net/
  401. *
  402. * MIT License
  403. */
  404. function EventBurrito(_this, options) {
  405. var noop = function() {},
  406. o = {
  407. preventDefault: true,
  408. clickTolerance: 0,
  409. preventScroll: false,
  410. mouse: true,
  411. start: noop,
  412. move: noop,
  413. end: noop,
  414. click: noop
  415. };
  416. //merge user options into defaults
  417. options && mergeObjects(o, options);
  418. var support = {
  419. pointerEvents: !!window.navigator.pointerEnabled,
  420. msPointerEvents: !!window.navigator.msPointerEnabled
  421. },
  422. start = {},
  423. diff = {},
  424. speed = {},
  425. stack = [],
  426. listeners = [],
  427. isScrolling,
  428. eventType,
  429. clicksAllowed = true, //flag allowing default click actions (e.g. links)
  430. eventModel = (support.pointerEvents? 1 : (support.msPointerEvents? 2 : 0)),
  431. events = [
  432. ['touchstart', 'touchmove', 'touchend', 'touchcancel'], //touch events
  433. ['pointerdown', 'pointermove', 'pointerup', 'pointercancel'], //pointer events
  434. ['MSPointerDown', 'MSPointerMove', 'MSPointerUp', 'MSPointerCancel'], //IE10 pointer events
  435. ['mousedown', 'mousemove', 'mouseup', false] //mouse events
  436. ],
  437. //some checks for different event types
  438. checks = [
  439. //touch events
  440. function(e) {
  441. //skip the event if it's multitouch or pinch move
  442. return (e.touches && e.touches.length > 1) || (e.scale && e.scale !== 1);
  443. },
  444. //pointer events
  445. function(e) {
  446. //Skip it, if:
  447. //1. event is not primary (other pointers during multitouch),
  448. //2. left mouse button is not pressed,
  449. //3. mouse drag is disabled and event is not touch
  450. return !e.isPrimary || (e.buttons && e.buttons !== 1) || (!o.mouse && e.pointerType !== 'touch' && e.pointerType !== 'pen');
  451. },
  452. //IE10 pointer events
  453. function(e) {
  454. //same checks as in pointer events
  455. return !e.isPrimary || (e.buttons && e.buttons !== 1) || (!o.mouse && e.pointerType !== e.MSPOINTER_TYPE_TOUCH && e.pointerType !== e.MSPOINTER_TYPE_PEN);
  456. },
  457. //mouse events
  458. function(e) {
  459. //skip the event if left mouse button is not pressed
  460. //in IE7-8 `buttons` is not defined, in IE9 LMB is 0
  461. return (e.buttons && e.buttons !== 1);
  462. }
  463. ];
  464. function mergeObjects(targetObj, sourceObject) {
  465. for (var key in sourceObject) {
  466. if (sourceObject.hasOwnProperty(key)) {
  467. targetObj[key] = sourceObject[key];
  468. }
  469. }
  470. }
  471. function addEvent(el, event, func, bool) {
  472. if (!event) return;
  473. el.addEventListener? el.addEventListener(event, func, !!bool): el.attachEvent('on'+event, func);
  474. //return event remover to easily remove anonymous functions later
  475. return {
  476. remove: function() {
  477. removeEvent(el, event, func, bool);
  478. }
  479. };
  480. }
  481. function removeEvent(el, event, func, bool) {
  482. if (!event) return;
  483. el.removeEventListener? el.removeEventListener(event, func, !!bool): el.detachEvent('on'+event, func);
  484. }
  485. function preventDefault(event) {
  486. event.preventDefault? event.preventDefault() : event.returnValue = false;
  487. }
  488. function getDiff(event) {
  489. diff = {
  490. x: (eventType? event.clientX : event.touches[0].clientX) - start.x,
  491. y: (eventType? event.clientY : event.touches[0].clientY) - start.y,
  492. time: Number(new Date) - start.time
  493. };
  494. if (diff.time - stack[stack.length - 1].time) {
  495. for (var i = 0; i < stack.length - 1 && diff.time - stack[i].time > 80; i++);
  496. speed = {
  497. x: (diff.x - stack[i].x) / (diff.time - stack[i].time),
  498. y: (diff.y - stack[i].y) / (diff.time - stack[i].time)
  499. };
  500. if (stack.length >= 5) stack.shift();
  501. stack.push({x: diff.x, y: diff.y, time: diff.time});
  502. }
  503. }
  504. function tStart(event, eType) {
  505. clicksAllowed = true;
  506. eventType = eType; //leak event type
  507. if (checks[eventType](event)) return;
  508. //attach event listeners to the document, so that the slider
  509. //will continue to recieve events wherever the pointer is
  510. addEvent(document, events[eventType][1], tMove);
  511. addEvent(document, events[eventType][2], tEnd);
  512. addEvent(document, events[eventType][3], tEnd);
  513. //fixes WebKit's cursor while dragging
  514. if (o.preventDefault && eventType) preventDefault(event);
  515. //remember starting time and position
  516. start = {
  517. x: eventType? event.clientX : event.touches[0].clientX,
  518. y: eventType? event.clientY : event.touches[0].clientY,
  519. time: Number(new Date)
  520. };
  521. //reset
  522. isScrolling = undefined;
  523. diff = {x:0, y:0, time: 0};
  524. speed = {x:0, y:0};
  525. stack = [{x:0, y:0, time: 0}];
  526. o.start(event, start);
  527. }
  528. function tMove(event) {
  529. //if user is trying to scroll vertically -- do nothing
  530. if ((!o.preventScroll && isScrolling) || checks[eventType](event)) return;
  531. getDiff(event);
  532. 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
  533. //check whether the user is trying to scroll vertically
  534. if (isScrolling === undefined && eventType !== 3) {
  535. //assign and check `isScrolling` at the same time
  536. if (isScrolling = (Math.abs(diff.x) < Math.abs(diff.y)) && !o.preventScroll) return;
  537. }
  538. if (o.preventDefault) preventDefault(event); //Prevent scrolling
  539. o.move(event, start, diff, speed);
  540. }
  541. function tEnd(event) {
  542. eventType && getDiff(event);
  543. //IE likes to focus links after touchend.
  544. //Since we don't want to disable link outlines completely for accessibility reasons,
  545. //we just defocus it after touch and disable the outline for `:active` links in css.
  546. //This way the outline will remain visible when using keyboard.
  547. !clicksAllowed && event.target && event.target.blur && event.target.blur();
  548. //detach event listeners from the document
  549. removeEvent(document, events[eventType][1], tMove);
  550. removeEvent(document, events[eventType][2], tEnd);
  551. removeEvent(document, events[eventType][3], tEnd);
  552. o.end(event, start, diff, speed);
  553. }
  554. function init() {
  555. //bind touchstart
  556. listeners.push(addEvent(_this, events[eventModel][0], function(e) {tStart(e, eventModel);}));
  557. //prevent stuff from dragging when using mouse
  558. listeners.push(addEvent(_this, 'dragstart', preventDefault));
  559. //bind mousedown if necessary
  560. if (o.mouse && !eventModel) {
  561. listeners.push(addEvent(_this, events[3][0], function(e) {tStart(e, 3);}));
  562. }
  563. //No clicking during touch
  564. listeners.push(addEvent(_this, 'click', function(event) {
  565. clicksAllowed? o.click(event): preventDefault(event);
  566. }));
  567. }
  568. init();
  569. //expose the API
  570. return {
  571. getClicksAllowed: function() {
  572. return clicksAllowed;
  573. },
  574. kill: function() {
  575. for (var i = listeners.length - 1; i >= 0; i--) {
  576. listeners[i].remove();
  577. }
  578. }
  579. }
  580. }