Advertisement
Guest User

Untitled

a guest
Feb 9th, 2016
59
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 21.18 KB | None | 0 0
  1. // ------------------------------ //
  2. // Slider //
  3. // ------------------------------ //
  4.  
  5. var $ = require('jquery');
  6. var inherits = require('inherits');
  7. var EventEmitter = require('events').EventEmitter;
  8. var focusable = require('focusable');
  9.  
  10. function Slider(obj, config) {
  11. this.slider = obj;
  12. this.classes = window.PROJECT_NAME.Settings.Classes;
  13.  
  14. this.config = $.extend({
  15. displayedSlides: 4,
  16. slidesMargin: 20,
  17. createNavigation: true,
  18. navigationType: 'both',
  19. sliderWrapperClass: 'slider-wrapper',
  20. sliderContainerClass: 'slider-container',
  21. slideClass: 'slide',
  22. sliderActiveContentClass: 'slider-activecontent',
  23. sliderTriggerClass: 'slide-trigger',
  24. sliderTriggerContentClass: 'slide-trigger-content',
  25. sliderNavigationClass: 'slider-navigation',
  26. navigationPrevClass: 'slider-navigation-prev',
  27. navigationNextClass: 'slider-navigation-next',
  28. navigationArrowClass: 'slider-navigation-arrows',
  29. navigationDotClass: 'slider-navigation-dots',
  30. navigationPrevText: 'Précédent',
  31. navigationNextText: 'Suivant',
  32. navigationDotText: 'Afficher la diapositive ',
  33. navigationDotActiveText: 'Diapositive présentement affichée',
  34. ariaTextClass: 'aria-text',
  35. ariaTextActiveClass: 'aria-text-active',
  36. ariaHiddenBoxClass: 'aria-hidden-box',
  37. displayDotsNumber: true,
  38. autoCenterActiveSlide: true,
  39. autoplay: false,
  40. autoplayDelay: 3000,
  41. autoplayButtonClass: 'slider-autoplay',
  42. autoplayButtonText: 'Mettre le carrousel en marche',
  43. autoplayButtonPauseText: 'Mettre le carrousel en pause',
  44. changeSlideLoop: true,
  45. animationSpeed: 300,
  46. beforeClone: $.noop,
  47. afterClone: $.noop,
  48. beforeChangeSlide: $.noop,
  49. afterChangeSlide: $.noop,
  50. beforeUpdateLayout: $.noop,
  51. afterUpdateLayout: $.noop,
  52. breakpoints: []
  53. }, config);
  54.  
  55. // Get the sliders wrapper
  56. this.sliderWrapper = this.slider.find('.' + this.config.sliderWrapperClass);
  57.  
  58. // Get the sliders container
  59. this.sliderContainer = this.slider.find('.' + this.config.sliderContainerClass);
  60.  
  61. // Get the slides
  62. this.slides = this.slider.find('.' + this.config.slideClass);
  63.  
  64. // Initialize activeSlideIndex
  65. this.activeSlideIndex = 0;
  66.  
  67. // Get displayed slides number
  68. this.displayedSlides = this.config.displayedSlides;
  69.  
  70. // Initialize current breakpoint
  71. this.currentBreakpoint = undefined;
  72.  
  73. // Initialize mouse hover state
  74. this.mouseHover = false;
  75.  
  76. // Initialize animated state
  77. this.animated = false;
  78.  
  79. // Bind events
  80. this.bindEvents();
  81.  
  82. // Navigation initialization
  83. if (this.config.createNavigation) {
  84. this.createNavigation(this.config.navigationType);
  85. }
  86.  
  87. // Autoplay initialization
  88. if (this.config.autoplay) {
  89. this.autoplay();
  90. }
  91.  
  92. this.detectswipe(this.slider, function(direction) {
  93. console.log('You swiped ' + direction);
  94. });
  95.  
  96. this.init();
  97. }
  98.  
  99. inherits(Slider, EventEmitter);
  100.  
  101. $.extend(Slider.prototype, {
  102.  
  103. // Component initialization
  104. init: function() {
  105. // Layout initialization
  106. this.initLayout(this.config.displayedSlides);
  107. this.onResize();
  108.  
  109. this.createAriabox();
  110.  
  111. // Create active content wrapper
  112. if (this.isActiveContent()) {
  113. var content = this.slides.first().find('.' + this.config.sliderTriggerContentClass).clone();
  114. this.slider.prepend('<div class="' + this.config.sliderActiveContentClass + '"></div>');
  115. this.updateActiveSlideContent(content);
  116. // Auto center active slide
  117. if (this.config.autoCenterActiveSlide === true) {
  118. this.slider.find('.' + this.config.sliderActiveContentClass).css('text-align', 'center');
  119. }
  120. }
  121. },
  122.  
  123. // Layout initialization
  124. initLayout: function() {
  125. var slideWidth = 100 / this.slides.length,
  126. slideWidthCalc = this.config.slidesMargin / this.slides.length * (this.slides.length - 1),
  127. slidesCSS = 'float: left;' +
  128. 'position: relative;' +
  129. 'width: ' + slideWidth + '%;' +
  130. 'width: calc(' + slideWidth + '% - ' + slideWidthCalc + 'px);';
  131.  
  132. // Callback
  133. this.config.beforeUpdateLayout();
  134.  
  135. // Add necessary css for the slider
  136. this.sliderWrapper.css({
  137. 'position': 'relative',
  138. 'overflow': 'hidden'
  139. });
  140.  
  141. this.sliderContainer.css({
  142. 'position': 'relative',
  143. 'left': '0',
  144. 'width': this.slides.length / this.displayedSlides * 100 + '%'
  145. });
  146.  
  147. this.slides.attr('style', slidesCSS).find('> a').css('display', 'block');
  148.  
  149. // Add margin to all slides except the first one
  150. this.slides.slice(1).css({
  151. 'margin-left': this.config.slidesMargin + 'px'
  152. });
  153.  
  154. // Disable focus on hidden slides
  155. this.slides.slice(this.displayedSlides).find(':focusable').attr('tabindex', '-1');
  156.  
  157. // Callback
  158. this.config.afterUpdateLayout();
  159. },
  160.  
  161. // Bind events with actions
  162. bindEvents: function() {
  163. // Function called each time the window is resized
  164. $(window).on('resize', $.proxy(function() {
  165. this.onResize();
  166. }, this));
  167.  
  168. this.slider.hover($.proxy(function() {
  169. this.mouseHover = true;
  170. }, this), $.proxy(function() {
  171. this.mouseHover = false;
  172. }, this));
  173.  
  174. // Function called each time the sliderTrigger element is clicked
  175. if (this.isActiveContent()) {
  176. this.slider.find('.' + this.config.sliderTriggerClass).on('click', $.proxy(function(e) {
  177. var content = $(e.currentTarget).parents('.' + this.config.slideClass).find('.' + this.config.sliderTriggerContentClass).clone();
  178. this.updateActiveSlideContent(content);
  179. e.prevent();
  180. }, this));
  181. }
  182.  
  183. // Detect keyboard navigation
  184. $(document).on('keyboardnavigation', $.proxy(function() {
  185. // Stop autoplay
  186. this.stopAutoplay();
  187. }, this));
  188. },
  189.  
  190. // Create navigation
  191. createNavigation: function(type) {
  192. // Clear existing navigation
  193. this.slider.find('.' + this.config.sliderNavigationClass).remove();
  194.  
  195. // Create navigation wrapper
  196. this.sliderWrapper.after('<div class="' + this.config.sliderNavigationClass + ' clearfix"></div>');
  197.  
  198. // Get navigation wrapper obejct
  199. this.sliderNavigation = this.slider.find('.' + this.config.sliderNavigationClass);
  200.  
  201. // Add navigation type class
  202. this.sliderNavigation.addClass('is-' + this.config.sliderNavigationClass + '-' + type);
  203.  
  204. // Arrows navigation type
  205. if (type === 'arrows') {
  206. this.createArrowsNavigation();
  207. }
  208. // Dots navigation type
  209. else if (type === 'dots') {
  210. this.createDotsNavigation();
  211. }
  212. // Both navigation type
  213. else {
  214. this.createArrowsNavigation();
  215. this.createDotsNavigation();
  216. }
  217. },
  218.  
  219. // Create arrows navigation
  220. createArrowsNavigation: function() {
  221. var previousButton = '<button class="' + this.config.navigationPrevClass + '"><span class="visuallyhidden ' + this.config.ariaTextClass + '">' + this.config.navigationPrevText + '</span></button>',
  222. nextButton = '<button class="' + this.config.navigationNextClass + '"><span class="visuallyhidden ' + this.config.ariaTextClass + '">' + this.config.navigationNextText + '</span></button>';
  223.  
  224. // Create navigation wrapper
  225. this.sliderNavigation.append('<div class="' + this.config.navigationArrowClass + '-wrapper"></div>');
  226.  
  227. // Append each arrows
  228. this.sliderNavigation.find('.' + this.config.navigationArrowClass + '-wrapper').append(previousButton, nextButton);
  229.  
  230. // Get previous and next buttons
  231. this.navigationPrevious = this.sliderNavigation.find('.' + this.config.navigationPrevClass);
  232. this.navigationNext = this.sliderNavigation.find('.' + this.config.navigationNextClass);
  233.  
  234. if (this.config.navigationType === 'both') {
  235. this.navigationPrevious.attr('aria-hidden', 'true');
  236. this.navigationNext.attr('aria-hidden', 'true');
  237. }
  238.  
  239. this.bindEventsArrowsNavigation();
  240. },
  241.  
  242. // Bind events for the arrows navigation
  243. bindEventsArrowsNavigation: function() {
  244. // Bind previous arrow event
  245. this.navigationPrevious.on('click', $.proxy(function(e) {
  246. this.navigationTypeTriggered = 'arrows';
  247. this.changeSlide(this.activeSlideIndex - 1);
  248. this.navigationNext.removeClass(this.classes.active);
  249. $(e.currentTarget).addClass(this.classes.active);
  250.  
  251. // Update hidden aria box
  252. this.updateAriabox('La diapositive précédente est affichée.');
  253.  
  254. // Stop autoplay
  255. this.stopAutoplay();
  256. }, this));
  257.  
  258. // Bind next arrow event
  259. this.navigationNext.on('click', $.proxy(function(e) {
  260. this.navigationTypeTriggered = 'arrows';
  261. this.changeSlide(this.activeSlideIndex + 1);
  262. this.navigationPrevious.removeClass(this.classes.active);
  263. $(e.currentTarget).addClass(this.classes.active);
  264.  
  265. // Update hidden aria box
  266. this.updateAriabox('La diapositive suivante est affichée.');
  267.  
  268. // Stop autoplay
  269. this.stopAutoplay();
  270. }, this));
  271. },
  272.  
  273. // Create dots navigation
  274. createDotsNavigation: function() {
  275. var dot = '<button class="' + this.config.navigationDotClass + '"><span class="visuallyhidden ' + this.config.ariaTextClass + '"></span></button>';
  276.  
  277. // Create navigation wrapper
  278. this.sliderNavigation.append('<div class="' + this.config.navigationDotClass + '-wrapper"></div>');
  279.  
  280. // Append each dots
  281. for (var i = 0; i < this.slides.length / this.displayedSlides; i++) {
  282. this.sliderNavigation.find('.' + this.config.navigationDotClass + '-wrapper').append(dot);
  283. }
  284.  
  285. // Get dots elements
  286. this.navigationDots = this.sliderNavigation.find('.' + this.config.navigationDotClass);
  287.  
  288. // Add aria text for each dot
  289. this.navigationDots.each($.proxy(function(index, el) {
  290. // Show dots number
  291. if (this.config.displayDotsNumber === true) {
  292. $(el).find('.' + this.config.ariaTextClass).text(this.config.navigationDotText).after(index + 1);
  293. }
  294. // Don't show dots number
  295. else {
  296. $(el).find('.' + this.config.ariaTextClass).text(this.config.navigationDotText + (parseInt(index) + 1));
  297. }
  298. }, this));
  299.  
  300. // Initialize first dot button
  301. this.navigationDots.eq(0).addClass(this.classes.active).append('<span class="visuallyhidden ' + this.config.ariaTextActiveClass + '"> ' + this.config.navigationDotActiveText + '</span>');
  302.  
  303. this.bindEventsDotsNavigation();
  304. },
  305.  
  306. // Bind events for the dots navigation
  307. bindEventsDotsNavigation: function() {
  308. // Get dots elements
  309. this.navigationDots = this.sliderNavigation.find('.' + this.config.navigationDotClass);
  310.  
  311. // Bind click events
  312. this.navigationDots.on('click', $.proxy(function(e) {
  313. this.navigationTypeTriggered = 'dots';
  314. var index = $(e.currentTarget).index() - $(e.currentTarget).parent().find('.slider-navigation-prev, .slider-navigation-next').length;
  315. this.changeSlide(index * this.displayedSlides);
  316. this.navigationDots.removeClass(this.classes.active);
  317. $(e.currentTarget).addClass(this.classes.active);
  318.  
  319. // Stop autoplay
  320. this.stopAutoplay();
  321. }, this));
  322. },
  323.  
  324. // Initialize autoplay
  325. autoplay: function() {
  326. this.createAutoplayButton();
  327.  
  328. this.isAutoplay = true;
  329. this.toggleAutoplayText();
  330.  
  331. this.autoplayInterval = setInterval($.proxy(function() {
  332. if (!this.mouseHover) {
  333. this.changeSlide(this.activeSlideIndex + 1);
  334. }
  335. }, this), this.config.autoplayDelay);
  336.  
  337. },
  338.  
  339. // Create autoplay button
  340. createAutoplayButton: function() {
  341. var button = '<button class="' + this.config.autoplayButtonClass + ' ' + this.classes.active + '"><span class="">' + this.config.autoplayButtonText + '</span></button>';
  342.  
  343. // Create button
  344. if (this.sliderNavigation.find('.' + this.config.autoplayButtonClass).length < 1) {
  345. this.sliderNavigation.append(button);
  346. this.bindEventsAutoplayButton();
  347. }
  348. },
  349.  
  350. bindEventsAutoplayButton: function() {
  351. // Get autoplay button
  352. this.autoplayButton = this.sliderNavigation.find('.' + this.config.autoplayButtonClass);
  353.  
  354. // Bind click events
  355. this.autoplayButton.on('click', $.proxy(function() {
  356. if (this.isAutoplay) {
  357. this.stopAutoplay();
  358. this.autoplayButton.removeClass(this.classes.active);
  359. } else {
  360. this.mouseHover = false;
  361. this.autoplay();
  362. this.autoplayButton.addClass(this.classes.active);
  363. }
  364. }, this));
  365. },
  366.  
  367. // Stop autoplay
  368. stopAutoplay: function() {
  369. this.isAutoplay = false;
  370. clearInterval(this.autoplayInterval);
  371.  
  372. // Remove active class on autoplay button
  373. if (this.sliderNavigation.find('.' + this.config.autoplayButtonClass).length > 0) {
  374. this.sliderNavigation.find('.' + this.config.autoplayButtonClass).removeClass(this.classes.active);
  375. this.toggleAutoplayText();
  376. }
  377. },
  378.  
  379. // Toggle aria text of autoplay button
  380. toggleAutoplayText: function() {
  381. if (this.sliderNavigation.find('.' + this.config.autoplayButtonClass).length > 0) {
  382. if (this.isAutoplay) {
  383. this.autoplayButton.find('span').text(this.config.autoplayButtonPauseText);
  384. } else {
  385. this.autoplayButton.find('span').text(this.config.autoplayButtonText);
  386. }
  387. }
  388. },
  389.  
  390. // Create aria hidden box
  391. createAriabox: function() {
  392. if (this.config.navigationType === 'arrows') {
  393. this.slider.append('<div class="visuallyhidden ' + this.config.ariaHiddenBoxClass + '" aria-live="polite" aria-atomic="true" aria-hidden="true"></div>');
  394. this.ariaHiddenBox = this.slider.find('.' + this.config.ariaHiddenBoxClass);
  395. }
  396. },
  397.  
  398. // Update aria hidden box
  399. updateAriabox: function(content) {
  400. if (this.config.navigationType === 'arrows') {
  401. this.ariaHiddenBox.html(content);
  402. }
  403. },
  404.  
  405. // Change active slide
  406. changeSlide: function(index) {
  407. // Prevent slide outside the wrapper
  408. if (index < 0) {
  409. if (this.config.changeSlideLoop) {
  410. index = this.slides.length - this.displayedSlides;
  411. } else {
  412. index = 0;
  413. }
  414. } else if (index > this.slides.length - this.displayedSlides) {
  415. if (this.navigationTypeTriggered === 'dots') {
  416. index = this.slides.length - this.displayedSlides;
  417. } else {
  418. if (this.config.changeSlideLoop) {
  419. index = 0;
  420. } else {
  421. index = this.slides.length - this.displayedSlides;
  422. }
  423. }
  424. }
  425.  
  426. // Only animated if there is no active animation
  427. if (!this.animated) {
  428. this.changeSlideAnimation(index);
  429. }
  430. },
  431.  
  432. // Change active slide animation
  433. changeSlideAnimation: function(index) {
  434. // Update animation state
  435. this.animated = true;
  436.  
  437. // Callback
  438. this.config.beforeChangeSlide();
  439.  
  440. // Change slide animation
  441. this.sliderContainer.animate({
  442. left: 100 / this.displayedSlides * index * -1 + '%'
  443. }, this.config.animationSpeed, $.proxy(function() {
  444. // Update animation state
  445. this.animated = false;
  446. // Callback
  447. this.config.afterChangeSlide();
  448. // Update active slide index
  449. this.activeSlideIndex = index;
  450. // Update tabindex
  451. this.slides.find(':focusable').attr('tabindex', '-1');
  452. this.slides.slice(index, index + this.displayedSlides).find(':focusable').removeAttr('tabindex');
  453. if (this.config.navigationType === 'dots' || this.config.navigationType === 'both') {
  454. // Update dots buttons
  455. this.navigationDots.removeClass(this.classes.active).eq(index).addClass(this.classes.active);
  456. // Update hidden active text
  457. this.navigationDots.find('.' + this.config.ariaTextActiveClass).remove();
  458. this.navigationDots.eq(index).append('<span class="visuallyhidden ' + this.config.ariaTextActiveClass + '">' + this.config.navigationDotActiveText + '</span>');
  459. }
  460. }, this));
  461. },
  462.  
  463. // Update active slide content
  464. updateActiveSlideContent: function(content) {
  465. this.config.beforeClone();
  466. this.slider.find('.' + this.config.sliderActiveContentClass).html(content);
  467. this.config.afterClone();
  468. },
  469.  
  470. // Function triggered each time the window is resized
  471. onResize: function() {
  472. var breakpoints = this.config.breakpoints,
  473. currentBreakpoint;
  474.  
  475. // Loop through each breakpoints
  476. for (var i = 0; i < breakpoints.length; i++) {
  477. if (Modernizr.mq('only all and (max-width: ' + breakpoints[i].maxwidth + 'px)')) {
  478. currentBreakpoint = i;
  479. break;
  480. } else {
  481. currentBreakpoint = undefined;
  482. }
  483. }
  484.  
  485. // Update breakpoint
  486. this.updateBreakpoint(currentBreakpoint);
  487. },
  488.  
  489. detectswipe: function(element, callback) {
  490. swipe_det = new Object();
  491. swipe_det.sX = 0;
  492. swipe_det.sY = 0;
  493. swipe_det.eX = 0;
  494. swipe_det.eY = 0;
  495. var min_x = 30
  496. var max_x = 30
  497. var min_y = 50
  498. var max_y = 60
  499. var direc = "";
  500. element = element[0];
  501. element.addEventListener('touchstart', function(e) {
  502. var t = e.touches[0];
  503. swipe_det.sX = t.screenX;
  504. swipe_det.sY = t.screenY;
  505. }, false);
  506. element.addEventListener('touchmove', function(e) {
  507. e.preventDefault();
  508. var t = e.touches[0];
  509. swipe_det.eX = t.screenX;
  510. swipe_det.eY = t.screenY;
  511. }, false);
  512. element.addEventListener('touchend', function(e) {
  513. if ((((swipe_det.eX - min_x > swipe_det.sX) || (swipe_det.eX + min_x < swipe_det.sX)) && ((swipe_det.eY < swipe_det.sY + max_y) && (swipe_det.sY > swipe_det.eY - max_y) && (swipe_det.eX > 0)))) {
  514. if (swipe_det.eX > swipe_det.sX) direction = 'right';
  515. else direction = 'left';
  516. } else if ((((swipe_det.eY - min_y > swipe_det.sY) || (swipe_det.eY + min_y < swipe_det.sY)) && ((swipe_det.eX < swipe_det.sX + max_x) && (swipe_det.sX > swipe_det.eX - max_x) && (swipe_det.eY > 0)))) {
  517. if (swipe_det.eY > swipe_det.sY) direction = 'down';
  518. else direction = 'up';
  519. }
  520. if (direction != '') {
  521. if (typeof callback == 'function') callback(direction);
  522. }
  523. direction = '';
  524. swipe_det.sX = 0;
  525. swipe_det.sY = 0;
  526. swipe_det.eX = 0;
  527. swipe_det.eY = 0;
  528. }, false);
  529. },
  530.  
  531. // Update layout when a breakpoint is triggered
  532. updateBreakpoint: function(breakpoint) {
  533. var breakpoints = this.config.breakpoints;
  534.  
  535. // Check if breakpoint is not already active
  536. if (this.currentBreakpoint !== breakpoint) {
  537. // Check if existing breakpoint
  538. if (breakpoint !== undefined) {
  539. this.displayedSlides = breakpoints[breakpoint].displayedSlides;
  540. this.createNavigation(breakpoints[breakpoint].navigationType);
  541. this.initLayout();
  542. }
  543. // Fallback to config
  544. else {
  545. this.displayedSlides = this.config.displayedSlides;
  546. this.createNavigation(this.config.navigationType);
  547. this.initLayout();
  548. }
  549.  
  550. // Update current breakpoint
  551. this.currentBreakpoint = breakpoint;
  552. }
  553. },
  554.  
  555. // Check if slider has active content attribute set to true
  556. isActiveContent: function() {
  557. return typeof this.slider.data('activecontent') !== 'undefined';
  558. }
  559. });
  560.  
  561. module.exports = function(obj, config) {
  562. return obj.map(function(index, element) {
  563. return new Slider($(element), config);
  564. });
  565. };
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement