├── Rakefile ├── lib ├── bxslider-rails │ └── version.rb └── bxslider-rails.rb ├── Gemfile ├── vendor └── assets │ ├── images │ ├── controls.png │ └── bx_loader.gif │ ├── javascripts │ ├── bxslider.js │ ├── jquery.fitvids.js │ ├── jquery.easing.1.3.js │ └── jquery.bxslider.js │ └── stylesheets │ └── bxslider.css.scss ├── .gitignore ├── bxslider-rails.gemspec ├── LICENSE └── README.md /Rakefile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env rake 2 | require "bundler/gem_tasks" 3 | -------------------------------------------------------------------------------- /lib/bxslider-rails/version.rb: -------------------------------------------------------------------------------- 1 | module Bxslider 2 | module Rails 3 | VERSION = "4.2.5.1" 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | # Specify your gem's dependencies in bxslider-rails.gemspec 4 | gemspec 5 | -------------------------------------------------------------------------------- /vendor/assets/images/controls.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manfe/bxslider-rails/HEAD/vendor/assets/images/controls.png -------------------------------------------------------------------------------- /vendor/assets/images/bx_loader.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manfe/bxslider-rails/HEAD/vendor/assets/images/bx_loader.gif -------------------------------------------------------------------------------- /vendor/assets/javascripts/bxslider.js: -------------------------------------------------------------------------------- 1 | //= require jquery.bxslider 2 | //= require jquery.easing.1.3 3 | //= require jquery.fitvids 4 | -------------------------------------------------------------------------------- /lib/bxslider-rails.rb: -------------------------------------------------------------------------------- 1 | require "bxslider-rails/version" 2 | 3 | module Bxslider 4 | module Rails 5 | class Engine < ::Rails::Engine 6 | end 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.gem 2 | *.rbc 3 | .bundle 4 | .config 5 | .yardoc 6 | Gemfile.lock 7 | InstalledFiles 8 | _yardoc 9 | coverage 10 | doc/ 11 | lib/bundler/man 12 | pkg 13 | rdoc 14 | spec/reports 15 | test/tmp 16 | test/version_tmp 17 | tmp 18 | .DS_store 19 | -------------------------------------------------------------------------------- /bxslider-rails.gemspec: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | require File.expand_path('../lib/bxslider-rails/version', __FILE__) 3 | 4 | Gem::Specification.new do |gem| 5 | gem.name = "bxslider-rails" 6 | gem.require_paths = ["lib"] 7 | gem.version = Bxslider::Rails::VERSION 8 | gem.authors = ["Mauricio N. Ferreira"] 9 | gem.email = ["contato@ferreiramauricio.com"] 10 | gem.description = <<-EOF 11 | bxSlider is a jQuery HTML Content Slider. 12 | This gem allows for its easy inclusion into the rails asset pipeline. 13 | EOF 14 | gem.summary = "The bxSlider Rails is a jQuery HTML Content Slider ready to play with Rails." 15 | gem.files = Dir["{lib,vendor}/**/*"] + ["LICENSE", "README.md"] 16 | 17 | end 18 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 Mauricio N. Ferreira 2 | 3 | MIT License 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # bxSlider Rails Gem - v4.2.5 2 | 3 | jQuery bxSlider v4.2.5 - http://bxslider.com 4 | 5 | bxSlider Author: Steven Wanderski, Copyright 2011 6 | bxslider-rails Author: Mauricio Natanael Ferreira. 7 | 8 | ### Extra info 9 | 10 | bxSlider 4.2.5 == bxslider-rails (4.2.5.1) 11 | 12 | ## Installation 13 | 14 | Add this line to your application's Gemfile: 15 | 16 | gem 'bxslider-rails' 17 | 18 | And then execute: 19 | 20 | $ bundle install 21 | 22 | Or install it yourself as: 23 | 24 | $ gem install bxslider-rails 25 | 26 | ## Usage 27 | 28 | The bxSlider is a jQuery HTML Content Slider, so please check if you are using the jquery on your rails app 29 | 30 | //= require jquery 31 | 32 | Your app/assets/javascripts/application.js must appear like: 33 | 34 | //= require jquery 35 | //= require jquery_ujs 36 | //= require bxslider 37 | //= require_tree . 38 | 39 | And your app/assets/stylesheets/application.css like this: 40 | 41 | *= require_self 42 | *= require bxslider 43 | *= require_tree . 44 | 45 | 46 | Basic Structure example from http://bxslider.com 47 | 48 | 54 | 55 | ### Production environmet setup (Rails 4.0+ only) 56 | 57 | You have to add images to precompile array manually in your `config/environments/production.rb` 58 | 59 | # Precompile additional assets. 60 | # application.js, application.css, and all non-JS/CSS in app/assets folder are already added. 61 | config.assets.precompile += %w( bx_loader.gif controls.png ) 62 | 63 | On rails 4.2 you need to change it on `config/initializers/assets.rb` 64 | 65 | # Precompile additional assets. 66 | # application.js, application.css, and all non-JS/CSS in app/assets folder are already added. 67 | Rails.application.config.assets.precompile += %w( bx_loader.gif controls.png ) 68 | 69 | ## REMEMBER TO INITIALIZE IT! 70 | 71 | If you are going to use coffee script: 72 | 73 | $(document).ready -> 74 | $(".bxslider").bxSlider() 75 | 76 | Or just javascript: 77 | 78 | $(document).ready(function(){ 79 | $('.bxslider').bxSlider(); 80 | }); 81 | 82 | For more documentation please checkout the bxslider 4 repository here: 83 | https://github.com/wandoledzep/bxslider-4 84 | 85 | ##### Gem Author 86 | 87 | http://twitter.com/manfe01 88 | http://ferreiramauricio.com 89 | -------------------------------------------------------------------------------- /vendor/assets/javascripts/jquery.fitvids.js: -------------------------------------------------------------------------------- 1 | /*global jQuery */ 2 | /*jshint multistr:true browser:true */ 3 | /*! 4 | * FitVids 1.0 5 | * 6 | * Copyright 2011, Chris Coyier - http://css-tricks.com + Dave Rupert - http://daverupert.com 7 | * Credit to Thierry Koblentz - http://www.alistapart.com/articles/creating-intrinsic-ratios-for-video/ 8 | * Released under the WTFPL license - http://sam.zoy.org/wtfpl/ 9 | * 10 | * Date: Thu Sept 01 18:00:00 2011 -0500 11 | */ 12 | 13 | (function( $ ){ 14 | 15 | "use strict"; 16 | 17 | $.fn.fitVids = function( options ) { 18 | var settings = { 19 | customSelector: null 20 | }; 21 | 22 | var div = document.createElement('div'), 23 | ref = document.getElementsByTagName('base')[0] || document.getElementsByTagName('script')[0]; 24 | 25 | div.className = 'fit-vids-style'; 26 | div.innerHTML = '­'; 43 | 44 | ref.parentNode.insertBefore(div,ref); 45 | 46 | if ( options ) { 47 | $.extend( settings, options ); 48 | } 49 | 50 | return this.each(function(){ 51 | var selectors = [ 52 | "iframe[src*='player.vimeo.com']", 53 | "iframe[src*='www.youtube.com']", 54 | "iframe[src*='www.kickstarter.com']", 55 | "object", 56 | "embed" 57 | ]; 58 | 59 | if (settings.customSelector) { 60 | selectors.push(settings.customSelector); 61 | } 62 | 63 | var $allVideos = $(this).find(selectors.join(',')); 64 | 65 | $allVideos.each(function(){ 66 | var $this = $(this); 67 | if (this.tagName.toLowerCase() === 'embed' && $this.parent('object').length || $this.parent('.fluid-width-video-wrapper').length) { return; } 68 | var height = ( this.tagName.toLowerCase() === 'object' || ($this.attr('height') && !isNaN(parseInt($this.attr('height'), 10))) ) ? parseInt($this.attr('height'), 10) : $this.height(), 69 | width = !isNaN(parseInt($this.attr('width'), 10)) ? parseInt($this.attr('width'), 10) : $this.width(), 70 | aspectRatio = height / width; 71 | if(!$this.attr('id')){ 72 | var videoID = 'fitvid' + Math.floor(Math.random()*999999); 73 | $this.attr('id', videoID); 74 | } 75 | $this.wrap('
').parent('.fluid-width-video-wrapper').css('padding-top', (aspectRatio * 100)+"%"); 76 | $this.removeAttr('height').removeAttr('width'); 77 | }); 78 | }); 79 | }; 80 | })( jQuery ); 81 | -------------------------------------------------------------------------------- /vendor/assets/stylesheets/bxslider.css.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * bxSlider v4.2.5 3 | * Copyright 2013-2015 Steven Wanderski 4 | * Written while drinking Belgian ales and listening to jazz 5 | 6 | * Licensed under MIT (http://opensource.org/licenses/MIT) 7 | */ 8 | 9 | /** VARIABLES 10 | ===================================*/ 11 | /** RESET AND LAYOUT 12 | ===================================*/ 13 | .bx-wrapper { 14 | position: relative; 15 | margin: 0 auto 60px; 16 | padding: 0; 17 | *zoom: 1; 18 | -ms-touch-action: pan-y; 19 | touch-action: pan-y; 20 | } 21 | .bx-wrapper img { 22 | max-width: 100%; 23 | display: block; 24 | } 25 | .bxslider { 26 | margin: 0; 27 | padding: 0; 28 | } 29 | ul.bxslider { 30 | list-style: none; 31 | } 32 | .bx-viewport { 33 | /*fix other elements on the page moving (on Chrome)*/ 34 | -webkit-transform: translatez(0); 35 | } 36 | /** THEME 37 | ===================================*/ 38 | .bx-wrapper { 39 | -moz-box-shadow: 0 0 5px #ccc; 40 | -webkit-box-shadow: 0 0 5px #ccc; 41 | box-shadow: 0 0 5px #ccc; 42 | border: 5px solid #fff; 43 | background: #fff; 44 | } 45 | .bx-wrapper .bx-pager, 46 | .bx-wrapper .bx-controls-auto { 47 | position: absolute; 48 | bottom: -30px; 49 | width: 100%; 50 | } 51 | /* LOADER */ 52 | .bx-wrapper .bx-loading { 53 | min-height: 50px; 54 | background: image-url('bx_loader.gif') center center no-repeat #ffffff; 55 | height: 100%; 56 | width: 100%; 57 | position: absolute; 58 | top: 0; 59 | left: 0; 60 | z-index: 2000; 61 | } 62 | /* PAGER */ 63 | .bx-wrapper .bx-pager { 64 | text-align: center; 65 | font-size: .85em; 66 | font-family: Arial; 67 | font-weight: bold; 68 | color: #666; 69 | padding-top: 20px; 70 | } 71 | .bx-wrapper .bx-pager.bx-default-pager a { 72 | background: #666; 73 | text-indent: -9999px; 74 | display: block; 75 | width: 10px; 76 | height: 10px; 77 | margin: 0 5px; 78 | outline: 0; 79 | -moz-border-radius: 5px; 80 | -webkit-border-radius: 5px; 81 | border-radius: 5px; 82 | } 83 | .bx-wrapper .bx-pager.bx-default-pager a:hover, 84 | .bx-wrapper .bx-pager.bx-default-pager a.active, 85 | .bx-wrapper .bx-pager.bx-default-pager a:focus { 86 | background: #000; 87 | } 88 | .bx-wrapper .bx-pager-item, 89 | .bx-wrapper .bx-controls-auto .bx-controls-auto-item { 90 | display: inline-block; 91 | *zoom: 1; 92 | *display: inline; 93 | } 94 | .bx-wrapper .bx-pager-item { 95 | font-size: 0; 96 | line-height: 0; 97 | } 98 | /* DIRECTION CONTROLS (NEXT / PREV) */ 99 | .bx-wrapper .bx-prev { 100 | left: 10px; 101 | background: image-url('controls.png') no-repeat 0 -32px; 102 | } 103 | .bx-wrapper .bx-prev:hover, 104 | .bx-wrapper .bx-prev:focus { 105 | background-position: 0 0; 106 | } 107 | .bx-wrapper .bx-next { 108 | right: 10px; 109 | background: image-url('controls.png') no-repeat -43px -32px; 110 | } 111 | .bx-wrapper .bx-next:hover, 112 | .bx-wrapper .bx-next:focus { 113 | background-position: -43px 0; 114 | } 115 | .bx-wrapper .bx-controls-direction a { 116 | position: absolute; 117 | top: 50%; 118 | margin-top: -16px; 119 | outline: 0; 120 | width: 32px; 121 | height: 32px; 122 | text-indent: -9999px; 123 | z-index: 9999; 124 | } 125 | .bx-wrapper .bx-controls-direction a.disabled { 126 | display: none; 127 | } 128 | /* AUTO CONTROLS (START / STOP) */ 129 | .bx-wrapper .bx-controls-auto { 130 | text-align: center; 131 | } 132 | .bx-wrapper .bx-controls-auto .bx-start { 133 | display: block; 134 | text-indent: -9999px; 135 | width: 10px; 136 | height: 11px; 137 | outline: 0; 138 | background: image-url('controls.png') -86px -11px no-repeat; 139 | margin: 0 3px; 140 | } 141 | .bx-wrapper .bx-controls-auto .bx-start:hover, 142 | .bx-wrapper .bx-controls-auto .bx-start.active, 143 | .bx-wrapper .bx-controls-auto .bx-start:focus { 144 | background-position: -86px 0; 145 | } 146 | .bx-wrapper .bx-controls-auto .bx-stop { 147 | display: block; 148 | text-indent: -9999px; 149 | width: 9px; 150 | height: 11px; 151 | outline: 0; 152 | background: image-url('controls.png') -86px -44px no-repeat; 153 | margin: 0 3px; 154 | } 155 | .bx-wrapper .bx-controls-auto .bx-stop:hover, 156 | .bx-wrapper .bx-controls-auto .bx-stop.active, 157 | .bx-wrapper .bx-controls-auto .bx-stop:focus { 158 | background-position: -86px -33px; 159 | } 160 | /* PAGER WITH AUTO-CONTROLS HYBRID LAYOUT */ 161 | .bx-wrapper .bx-controls.bx-has-controls-auto.bx-has-pager .bx-pager { 162 | text-align: left; 163 | width: 80%; 164 | } 165 | .bx-wrapper .bx-controls.bx-has-controls-auto.bx-has-pager .bx-controls-auto { 166 | right: 0; 167 | width: 35px; 168 | } 169 | /* IMAGE CAPTIONS */ 170 | .bx-wrapper .bx-caption { 171 | position: absolute; 172 | bottom: 0; 173 | left: 0; 174 | background: #666; 175 | background: rgba(80, 80, 80, 0.75); 176 | width: 100%; 177 | } 178 | .bx-wrapper .bx-caption span { 179 | color: #fff; 180 | font-family: Arial; 181 | display: block; 182 | font-size: .85em; 183 | padding: 10px; 184 | } 185 | -------------------------------------------------------------------------------- /vendor/assets/javascripts/jquery.easing.1.3.js: -------------------------------------------------------------------------------- 1 | /* 2 | * jQuery Easing v1.3 - http://gsgd.co.uk/sandbox/jquery/easing/ 3 | * 4 | * Uses the built in easing capabilities added In jQuery 1.1 5 | * to offer multiple easing options 6 | * 7 | * TERMS OF USE - jQuery Easing 8 | * 9 | * Open source under the BSD License. 10 | * 11 | * Copyright © 2008 George McGinley Smith 12 | * All rights reserved. 13 | * 14 | * Redistribution and use in source and binary forms, with or without modification, 15 | * are permitted provided that the following conditions are met: 16 | * 17 | * Redistributions of source code must retain the above copyright notice, this list of 18 | * conditions and the following disclaimer. 19 | * Redistributions in binary form must reproduce the above copyright notice, this list 20 | * of conditions and the following disclaimer in the documentation and/or other materials 21 | * provided with the distribution. 22 | * 23 | * Neither the name of the author nor the names of contributors may be used to endorse 24 | * or promote products derived from this software without specific prior written permission. 25 | * 26 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 27 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 28 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 29 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 30 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 31 | * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 32 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 33 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 34 | * OF THE POSSIBILITY OF SUCH DAMAGE. 35 | * 36 | */ 37 | 38 | // t: current time, b: begInnIng value, c: change In value, d: duration 39 | jQuery.easing['jswing'] = jQuery.easing['swing']; 40 | 41 | jQuery.extend( jQuery.easing, 42 | { 43 | def: 'easeOutQuad', 44 | swing: function (x, t, b, c, d) { 45 | //alert(jQuery.easing.default); 46 | return jQuery.easing[jQuery.easing.def](x, t, b, c, d); 47 | }, 48 | easeInQuad: function (x, t, b, c, d) { 49 | return c*(t/=d)*t + b; 50 | }, 51 | easeOutQuad: function (x, t, b, c, d) { 52 | return -c *(t/=d)*(t-2) + b; 53 | }, 54 | easeInOutQuad: function (x, t, b, c, d) { 55 | if ((t/=d/2) < 1) return c/2*t*t + b; 56 | return -c/2 * ((--t)*(t-2) - 1) + b; 57 | }, 58 | easeInCubic: function (x, t, b, c, d) { 59 | return c*(t/=d)*t*t + b; 60 | }, 61 | easeOutCubic: function (x, t, b, c, d) { 62 | return c*((t=t/d-1)*t*t + 1) + b; 63 | }, 64 | easeInOutCubic: function (x, t, b, c, d) { 65 | if ((t/=d/2) < 1) return c/2*t*t*t + b; 66 | return c/2*((t-=2)*t*t + 2) + b; 67 | }, 68 | easeInQuart: function (x, t, b, c, d) { 69 | return c*(t/=d)*t*t*t + b; 70 | }, 71 | easeOutQuart: function (x, t, b, c, d) { 72 | return -c * ((t=t/d-1)*t*t*t - 1) + b; 73 | }, 74 | easeInOutQuart: function (x, t, b, c, d) { 75 | if ((t/=d/2) < 1) return c/2*t*t*t*t + b; 76 | return -c/2 * ((t-=2)*t*t*t - 2) + b; 77 | }, 78 | easeInQuint: function (x, t, b, c, d) { 79 | return c*(t/=d)*t*t*t*t + b; 80 | }, 81 | easeOutQuint: function (x, t, b, c, d) { 82 | return c*((t=t/d-1)*t*t*t*t + 1) + b; 83 | }, 84 | easeInOutQuint: function (x, t, b, c, d) { 85 | if ((t/=d/2) < 1) return c/2*t*t*t*t*t + b; 86 | return c/2*((t-=2)*t*t*t*t + 2) + b; 87 | }, 88 | easeInSine: function (x, t, b, c, d) { 89 | return -c * Math.cos(t/d * (Math.PI/2)) + c + b; 90 | }, 91 | easeOutSine: function (x, t, b, c, d) { 92 | return c * Math.sin(t/d * (Math.PI/2)) + b; 93 | }, 94 | easeInOutSine: function (x, t, b, c, d) { 95 | return -c/2 * (Math.cos(Math.PI*t/d) - 1) + b; 96 | }, 97 | easeInExpo: function (x, t, b, c, d) { 98 | return (t==0) ? b : c * Math.pow(2, 10 * (t/d - 1)) + b; 99 | }, 100 | easeOutExpo: function (x, t, b, c, d) { 101 | return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b; 102 | }, 103 | easeInOutExpo: function (x, t, b, c, d) { 104 | if (t==0) return b; 105 | if (t==d) return b+c; 106 | if ((t/=d/2) < 1) return c/2 * Math.pow(2, 10 * (t - 1)) + b; 107 | return c/2 * (-Math.pow(2, -10 * --t) + 2) + b; 108 | }, 109 | easeInCirc: function (x, t, b, c, d) { 110 | return -c * (Math.sqrt(1 - (t/=d)*t) - 1) + b; 111 | }, 112 | easeOutCirc: function (x, t, b, c, d) { 113 | return c * Math.sqrt(1 - (t=t/d-1)*t) + b; 114 | }, 115 | easeInOutCirc: function (x, t, b, c, d) { 116 | if ((t/=d/2) < 1) return -c/2 * (Math.sqrt(1 - t*t) - 1) + b; 117 | return c/2 * (Math.sqrt(1 - (t-=2)*t) + 1) + b; 118 | }, 119 | easeInElastic: function (x, t, b, c, d) { 120 | var s=1.70158;var p=0;var a=c; 121 | if (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3; 122 | if (a < Math.abs(c)) { a=c; var s=p/4; } 123 | else var s = p/(2*Math.PI) * Math.asin (c/a); 124 | return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b; 125 | }, 126 | easeOutElastic: function (x, t, b, c, d) { 127 | var s=1.70158;var p=0;var a=c; 128 | if (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3; 129 | if (a < Math.abs(c)) { a=c; var s=p/4; } 130 | else var s = p/(2*Math.PI) * Math.asin (c/a); 131 | return a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b; 132 | }, 133 | easeInOutElastic: function (x, t, b, c, d) { 134 | var s=1.70158;var p=0;var a=c; 135 | if (t==0) return b; if ((t/=d/2)==2) return b+c; if (!p) p=d*(.3*1.5); 136 | if (a < Math.abs(c)) { a=c; var s=p/4; } 137 | else var s = p/(2*Math.PI) * Math.asin (c/a); 138 | if (t < 1) return -.5*(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b; 139 | return a*Math.pow(2,-10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )*.5 + c + b; 140 | }, 141 | easeInBack: function (x, t, b, c, d, s) { 142 | if (s == undefined) s = 1.70158; 143 | return c*(t/=d)*t*((s+1)*t - s) + b; 144 | }, 145 | easeOutBack: function (x, t, b, c, d, s) { 146 | if (s == undefined) s = 1.70158; 147 | return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b; 148 | }, 149 | easeInOutBack: function (x, t, b, c, d, s) { 150 | if (s == undefined) s = 1.70158; 151 | if ((t/=d/2) < 1) return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b; 152 | return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b; 153 | }, 154 | easeInBounce: function (x, t, b, c, d) { 155 | return c - jQuery.easing.easeOutBounce (x, d-t, 0, c, d) + b; 156 | }, 157 | easeOutBounce: function (x, t, b, c, d) { 158 | if ((t/=d) < (1/2.75)) { 159 | return c*(7.5625*t*t) + b; 160 | } else if (t < (2/2.75)) { 161 | return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b; 162 | } else if (t < (2.5/2.75)) { 163 | return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b; 164 | } else { 165 | return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b; 166 | } 167 | }, 168 | easeInOutBounce: function (x, t, b, c, d) { 169 | if (t < d/2) return jQuery.easing.easeInBounce (x, t*2, 0, c, d) * .5 + b; 170 | return jQuery.easing.easeOutBounce (x, t*2-d, 0, c, d) * .5 + c*.5 + b; 171 | } 172 | }); 173 | 174 | /* 175 | * 176 | * TERMS OF USE - EASING EQUATIONS 177 | * 178 | * Open source under the BSD License. 179 | * 180 | * Copyright © 2001 Robert Penner 181 | * All rights reserved. 182 | * 183 | * Redistribution and use in source and binary forms, with or without modification, 184 | * are permitted provided that the following conditions are met: 185 | * 186 | * Redistributions of source code must retain the above copyright notice, this list of 187 | * conditions and the following disclaimer. 188 | * Redistributions in binary form must reproduce the above copyright notice, this list 189 | * of conditions and the following disclaimer in the documentation and/or other materials 190 | * provided with the distribution. 191 | * 192 | * Neither the name of the author nor the names of contributors may be used to endorse 193 | * or promote products derived from this software without specific prior written permission. 194 | * 195 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 196 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 197 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 198 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 199 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 200 | * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 201 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 202 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 203 | * OF THE POSSIBILITY OF SUCH DAMAGE. 204 | * 205 | */ -------------------------------------------------------------------------------- /vendor/assets/javascripts/jquery.bxslider.js: -------------------------------------------------------------------------------- 1 | /** 2 | * bxSlider v4.2.5 3 | * Copyright 2013-2015 Steven Wanderski 4 | * Written while drinking Belgian ales and listening to jazz 5 | 6 | * Licensed under MIT (http://opensource.org/licenses/MIT) 7 | */ 8 | 9 | ;(function($) { 10 | 11 | var defaults = { 12 | 13 | // GENERAL 14 | mode: 'horizontal', 15 | slideSelector: '', 16 | infiniteLoop: true, 17 | hideControlOnEnd: false, 18 | speed: 500, 19 | easing: null, 20 | slideMargin: 0, 21 | startSlide: 0, 22 | randomStart: false, 23 | captions: false, 24 | ticker: false, 25 | tickerHover: false, 26 | adaptiveHeight: false, 27 | adaptiveHeightSpeed: 500, 28 | video: false, 29 | useCSS: true, 30 | preloadImages: 'visible', 31 | responsive: true, 32 | slideZIndex: 50, 33 | wrapperClass: 'bx-wrapper', 34 | 35 | // TOUCH 36 | touchEnabled: true, 37 | swipeThreshold: 50, 38 | oneToOneTouch: true, 39 | preventDefaultSwipeX: true, 40 | preventDefaultSwipeY: false, 41 | 42 | // ACCESSIBILITY 43 | ariaLive: true, 44 | ariaHidden: true, 45 | 46 | // KEYBOARD 47 | keyboardEnabled: false, 48 | 49 | // PAGER 50 | pager: true, 51 | pagerType: 'full', 52 | pagerShortSeparator: ' / ', 53 | pagerSelector: null, 54 | buildPager: null, 55 | pagerCustom: null, 56 | 57 | // CONTROLS 58 | controls: true, 59 | nextText: 'Next', 60 | prevText: 'Prev', 61 | nextSelector: null, 62 | prevSelector: null, 63 | autoControls: false, 64 | startText: 'Start', 65 | stopText: 'Stop', 66 | autoControlsCombine: false, 67 | autoControlsSelector: null, 68 | 69 | // AUTO 70 | auto: false, 71 | pause: 4000, 72 | autoStart: true, 73 | autoDirection: 'next', 74 | stopAutoOnClick: false, 75 | autoHover: false, 76 | autoDelay: 0, 77 | autoSlideForOnePage: false, 78 | 79 | // CAROUSEL 80 | minSlides: 1, 81 | maxSlides: 1, 82 | moveSlides: 0, 83 | slideWidth: 0, 84 | shrinkItems: false, 85 | 86 | // CALLBACKS 87 | onSliderLoad: function() { return true; }, 88 | onSlideBefore: function() { return true; }, 89 | onSlideAfter: function() { return true; }, 90 | onSlideNext: function() { return true; }, 91 | onSlidePrev: function() { return true; }, 92 | onSliderResize: function() { return true; } 93 | }; 94 | 95 | $.fn.bxSlider = function(options) { 96 | 97 | if (this.length === 0) { 98 | return this; 99 | } 100 | 101 | // support multiple elements 102 | if (this.length > 1) { 103 | this.each(function() { 104 | $(this).bxSlider(options); 105 | }); 106 | return this; 107 | } 108 | 109 | // create a namespace to be used throughout the plugin 110 | var slider = {}, 111 | // set a reference to our slider element 112 | el = this, 113 | // get the original window dimens (thanks a lot IE) 114 | windowWidth = $(window).width(), 115 | windowHeight = $(window).height(); 116 | 117 | // Return if slider is already initialized 118 | if ($(el).data('bxSlider')) { return; } 119 | 120 | /** 121 | * =================================================================================== 122 | * = PRIVATE FUNCTIONS 123 | * =================================================================================== 124 | */ 125 | 126 | /** 127 | * Initializes namespace settings to be used throughout plugin 128 | */ 129 | var init = function() { 130 | // Return if slider is already initialized 131 | if ($(el).data('bxSlider')) { return; } 132 | // merge user-supplied options with the defaults 133 | slider.settings = $.extend({}, defaults, options); 134 | // parse slideWidth setting 135 | slider.settings.slideWidth = parseInt(slider.settings.slideWidth); 136 | // store the original children 137 | slider.children = el.children(slider.settings.slideSelector); 138 | // check if actual number of slides is less than minSlides / maxSlides 139 | if (slider.children.length < slider.settings.minSlides) { slider.settings.minSlides = slider.children.length; } 140 | if (slider.children.length < slider.settings.maxSlides) { slider.settings.maxSlides = slider.children.length; } 141 | // if random start, set the startSlide setting to random number 142 | if (slider.settings.randomStart) { slider.settings.startSlide = Math.floor(Math.random() * slider.children.length); } 143 | // store active slide information 144 | slider.active = { index: slider.settings.startSlide }; 145 | // store if the slider is in carousel mode (displaying / moving multiple slides) 146 | slider.carousel = slider.settings.minSlides > 1 || slider.settings.maxSlides > 1 ? true : false; 147 | // if carousel, force preloadImages = 'all' 148 | if (slider.carousel) { slider.settings.preloadImages = 'all'; } 149 | // calculate the min / max width thresholds based on min / max number of slides 150 | // used to setup and update carousel slides dimensions 151 | slider.minThreshold = (slider.settings.minSlides * slider.settings.slideWidth) + ((slider.settings.minSlides - 1) * slider.settings.slideMargin); 152 | slider.maxThreshold = (slider.settings.maxSlides * slider.settings.slideWidth) + ((slider.settings.maxSlides - 1) * slider.settings.slideMargin); 153 | // store the current state of the slider (if currently animating, working is true) 154 | slider.working = false; 155 | // initialize the controls object 156 | slider.controls = {}; 157 | // initialize an auto interval 158 | slider.interval = null; 159 | // determine which property to use for transitions 160 | slider.animProp = slider.settings.mode === 'vertical' ? 'top' : 'left'; 161 | // determine if hardware acceleration can be used 162 | slider.usingCSS = slider.settings.useCSS && slider.settings.mode !== 'fade' && (function() { 163 | // create our test div element 164 | var div = document.createElement('div'), 165 | // css transition properties 166 | props = ['WebkitPerspective', 'MozPerspective', 'OPerspective', 'msPerspective']; 167 | // test for each property 168 | for (var i = 0; i < props.length; i++) { 169 | if (div.style[props[i]] !== undefined) { 170 | slider.cssPrefix = props[i].replace('Perspective', '').toLowerCase(); 171 | slider.animProp = '-' + slider.cssPrefix + '-transform'; 172 | return true; 173 | } 174 | } 175 | return false; 176 | }()); 177 | // if vertical mode always make maxSlides and minSlides equal 178 | if (slider.settings.mode === 'vertical') { slider.settings.maxSlides = slider.settings.minSlides; } 179 | // save original style data 180 | el.data('origStyle', el.attr('style')); 181 | el.children(slider.settings.slideSelector).each(function() { 182 | $(this).data('origStyle', $(this).attr('style')); 183 | }); 184 | 185 | // perform all DOM / CSS modifications 186 | setup(); 187 | }; 188 | 189 | /** 190 | * Performs all DOM and CSS modifications 191 | */ 192 | var setup = function() { 193 | var preloadSelector = slider.children.eq(slider.settings.startSlide); // set the default preload selector (visible) 194 | 195 | // wrap el in a wrapper 196 | el.wrap('
'); 197 | // store a namespace reference to .bx-viewport 198 | slider.viewport = el.parent(); 199 | 200 | // add aria-live if the setting is enabled and ticker mode is disabled 201 | if (slider.settings.ariaLive && !slider.settings.ticker) { 202 | slider.viewport.attr('aria-live', 'polite'); 203 | } 204 | // add a loading div to display while images are loading 205 | slider.loader = $('
'); 206 | slider.viewport.prepend(slider.loader); 207 | // set el to a massive width, to hold any needed slides 208 | // also strip any margin and padding from el 209 | el.css({ 210 | width: slider.settings.mode === 'horizontal' ? (slider.children.length * 1000 + 215) + '%' : 'auto', 211 | position: 'relative' 212 | }); 213 | // if using CSS, add the easing property 214 | if (slider.usingCSS && slider.settings.easing) { 215 | el.css('-' + slider.cssPrefix + '-transition-timing-function', slider.settings.easing); 216 | // if not using CSS and no easing value was supplied, use the default JS animation easing (swing) 217 | } else if (!slider.settings.easing) { 218 | slider.settings.easing = 'swing'; 219 | } 220 | // make modifications to the viewport (.bx-viewport) 221 | slider.viewport.css({ 222 | width: '100%', 223 | overflow: 'hidden', 224 | position: 'relative' 225 | }); 226 | slider.viewport.parent().css({ 227 | maxWidth: getViewportMaxWidth() 228 | }); 229 | // make modification to the wrapper (.bx-wrapper) 230 | if (!slider.settings.pager && !slider.settings.controls) { 231 | slider.viewport.parent().css({ 232 | margin: '0 auto 0px' 233 | }); 234 | } 235 | // apply css to all slider children 236 | slider.children.css({ 237 | 'float': slider.settings.mode === 'horizontal' ? 'left' : 'none', 238 | listStyle: 'none', 239 | position: 'relative' 240 | }); 241 | // apply the calculated width after the float is applied to prevent scrollbar interference 242 | slider.children.css('width', getSlideWidth()); 243 | // if slideMargin is supplied, add the css 244 | if (slider.settings.mode === 'horizontal' && slider.settings.slideMargin > 0) { slider.children.css('marginRight', slider.settings.slideMargin); } 245 | if (slider.settings.mode === 'vertical' && slider.settings.slideMargin > 0) { slider.children.css('marginBottom', slider.settings.slideMargin); } 246 | // if "fade" mode, add positioning and z-index CSS 247 | if (slider.settings.mode === 'fade') { 248 | slider.children.css({ 249 | position: 'absolute', 250 | zIndex: 0, 251 | display: 'none' 252 | }); 253 | // prepare the z-index on the showing element 254 | slider.children.eq(slider.settings.startSlide).css({zIndex: slider.settings.slideZIndex, display: 'block'}); 255 | } 256 | // create an element to contain all slider controls (pager, start / stop, etc) 257 | slider.controls.el = $('
'); 258 | // if captions are requested, add them 259 | if (slider.settings.captions) { appendCaptions(); } 260 | // check if startSlide is last slide 261 | slider.active.last = slider.settings.startSlide === getPagerQty() - 1; 262 | // if video is true, set up the fitVids plugin 263 | if (slider.settings.video) { el.fitVids(); } 264 | if (slider.settings.preloadImages === 'all' || slider.settings.ticker) { preloadSelector = slider.children; } 265 | // only check for control addition if not in "ticker" mode 266 | if (!slider.settings.ticker) { 267 | // if controls are requested, add them 268 | if (slider.settings.controls) { appendControls(); } 269 | // if auto is true, and auto controls are requested, add them 270 | if (slider.settings.auto && slider.settings.autoControls) { appendControlsAuto(); } 271 | // if pager is requested, add it 272 | if (slider.settings.pager) { appendPager(); } 273 | // if any control option is requested, add the controls wrapper 274 | if (slider.settings.controls || slider.settings.autoControls || slider.settings.pager) { slider.viewport.after(slider.controls.el); } 275 | // if ticker mode, do not allow a pager 276 | } else { 277 | slider.settings.pager = false; 278 | } 279 | loadElements(preloadSelector, start); 280 | }; 281 | 282 | var loadElements = function(selector, callback) { 283 | var total = selector.find('img:not([src=""]), iframe').length, 284 | count = 0; 285 | if (total === 0) { 286 | callback(); 287 | return; 288 | } 289 | selector.find('img:not([src=""]), iframe').each(function() { 290 | $(this).one('load error', function() { 291 | if (++count === total) { callback(); } 292 | }).each(function() { 293 | if (this.complete) { $(this).load(); } 294 | }); 295 | }); 296 | }; 297 | 298 | /** 299 | * Start the slider 300 | */ 301 | var start = function() { 302 | // if infinite loop, prepare additional slides 303 | if (slider.settings.infiniteLoop && slider.settings.mode !== 'fade' && !slider.settings.ticker) { 304 | var slice = slider.settings.mode === 'vertical' ? slider.settings.minSlides : slider.settings.maxSlides, 305 | sliceAppend = slider.children.slice(0, slice).clone(true).addClass('bx-clone'), 306 | slicePrepend = slider.children.slice(-slice).clone(true).addClass('bx-clone'); 307 | if (slider.settings.ariaHidden) { 308 | sliceAppend.attr('aria-hidden', true); 309 | slicePrepend.attr('aria-hidden', true); 310 | } 311 | el.append(sliceAppend).prepend(slicePrepend); 312 | } 313 | // remove the loading DOM element 314 | slider.loader.remove(); 315 | // set the left / top position of "el" 316 | setSlidePosition(); 317 | // if "vertical" mode, always use adaptiveHeight to prevent odd behavior 318 | if (slider.settings.mode === 'vertical') { slider.settings.adaptiveHeight = true; } 319 | // set the viewport height 320 | slider.viewport.height(getViewportHeight()); 321 | // make sure everything is positioned just right (same as a window resize) 322 | el.redrawSlider(); 323 | // onSliderLoad callback 324 | slider.settings.onSliderLoad.call(el, slider.active.index); 325 | // slider has been fully initialized 326 | slider.initialized = true; 327 | // bind the resize call to the window 328 | if (slider.settings.responsive) { $(window).bind('resize', resizeWindow); } 329 | // if auto is true and has more than 1 page, start the show 330 | if (slider.settings.auto && slider.settings.autoStart && (getPagerQty() > 1 || slider.settings.autoSlideForOnePage)) { initAuto(); } 331 | // if ticker is true, start the ticker 332 | if (slider.settings.ticker) { initTicker(); } 333 | // if pager is requested, make the appropriate pager link active 334 | if (slider.settings.pager) { updatePagerActive(slider.settings.startSlide); } 335 | // check for any updates to the controls (like hideControlOnEnd updates) 336 | if (slider.settings.controls) { updateDirectionControls(); } 337 | // if touchEnabled is true, setup the touch events 338 | if (slider.settings.touchEnabled && !slider.settings.ticker) { initTouch(); } 339 | // if keyboardEnabled is true, setup the keyboard events 340 | if (slider.settings.keyboardEnabled && !slider.settings.ticker) { 341 | $(document).keydown(keyPress); 342 | } 343 | }; 344 | 345 | /** 346 | * Returns the calculated height of the viewport, used to determine either adaptiveHeight or the maxHeight value 347 | */ 348 | var getViewportHeight = function() { 349 | var height = 0; 350 | // first determine which children (slides) should be used in our height calculation 351 | var children = $(); 352 | // if mode is not "vertical" and adaptiveHeight is false, include all children 353 | if (slider.settings.mode !== 'vertical' && !slider.settings.adaptiveHeight) { 354 | children = slider.children; 355 | } else { 356 | // if not carousel, return the single active child 357 | if (!slider.carousel) { 358 | children = slider.children.eq(slider.active.index); 359 | // if carousel, return a slice of children 360 | } else { 361 | // get the individual slide index 362 | var currentIndex = slider.settings.moveSlides === 1 ? slider.active.index : slider.active.index * getMoveBy(); 363 | // add the current slide to the children 364 | children = slider.children.eq(currentIndex); 365 | // cycle through the remaining "showing" slides 366 | for (i = 1; i <= slider.settings.maxSlides - 1; i++) { 367 | // if looped back to the start 368 | if (currentIndex + i >= slider.children.length) { 369 | children = children.add(slider.children.eq(i - 1)); 370 | } else { 371 | children = children.add(slider.children.eq(currentIndex + i)); 372 | } 373 | } 374 | } 375 | } 376 | // if "vertical" mode, calculate the sum of the heights of the children 377 | if (slider.settings.mode === 'vertical') { 378 | children.each(function(index) { 379 | height += $(this).outerHeight(); 380 | }); 381 | // add user-supplied margins 382 | if (slider.settings.slideMargin > 0) { 383 | height += slider.settings.slideMargin * (slider.settings.minSlides - 1); 384 | } 385 | // if not "vertical" mode, calculate the max height of the children 386 | } else { 387 | height = Math.max.apply(Math, children.map(function() { 388 | return $(this).outerHeight(false); 389 | }).get()); 390 | } 391 | 392 | if (slider.viewport.css('box-sizing') === 'border-box') { 393 | height += parseFloat(slider.viewport.css('padding-top')) + parseFloat(slider.viewport.css('padding-bottom')) + 394 | parseFloat(slider.viewport.css('border-top-width')) + parseFloat(slider.viewport.css('border-bottom-width')); 395 | } else if (slider.viewport.css('box-sizing') === 'padding-box') { 396 | height += parseFloat(slider.viewport.css('padding-top')) + parseFloat(slider.viewport.css('padding-bottom')); 397 | } 398 | 399 | return height; 400 | }; 401 | 402 | /** 403 | * Returns the calculated width to be used for the outer wrapper / viewport 404 | */ 405 | var getViewportMaxWidth = function() { 406 | var width = '100%'; 407 | if (slider.settings.slideWidth > 0) { 408 | if (slider.settings.mode === 'horizontal') { 409 | width = (slider.settings.maxSlides * slider.settings.slideWidth) + ((slider.settings.maxSlides - 1) * slider.settings.slideMargin); 410 | } else { 411 | width = slider.settings.slideWidth; 412 | } 413 | } 414 | return width; 415 | }; 416 | 417 | /** 418 | * Returns the calculated width to be applied to each slide 419 | */ 420 | var getSlideWidth = function() { 421 | var newElWidth = slider.settings.slideWidth, // start with any user-supplied slide width 422 | wrapWidth = slider.viewport.width(); // get the current viewport width 423 | // if slide width was not supplied, or is larger than the viewport use the viewport width 424 | if (slider.settings.slideWidth === 0 || 425 | (slider.settings.slideWidth > wrapWidth && !slider.carousel) || 426 | slider.settings.mode === 'vertical') { 427 | newElWidth = wrapWidth; 428 | // if carousel, use the thresholds to determine the width 429 | } else if (slider.settings.maxSlides > 1 && slider.settings.mode === 'horizontal') { 430 | if (wrapWidth > slider.maxThreshold) { 431 | return newElWidth; 432 | } else if (wrapWidth < slider.minThreshold) { 433 | newElWidth = (wrapWidth - (slider.settings.slideMargin * (slider.settings.minSlides - 1))) / slider.settings.minSlides; 434 | } else if (slider.settings.shrinkItems) { 435 | newElWidth = Math.floor((wrapWidth + slider.settings.slideMargin) / (Math.ceil((wrapWidth + slider.settings.slideMargin) / (newElWidth + slider.settings.slideMargin))) - slider.settings.slideMargin); 436 | } 437 | } 438 | return newElWidth; 439 | }; 440 | 441 | /** 442 | * Returns the number of slides currently visible in the viewport (includes partially visible slides) 443 | */ 444 | var getNumberSlidesShowing = function() { 445 | var slidesShowing = 1, 446 | childWidth = null; 447 | if (slider.settings.mode === 'horizontal' && slider.settings.slideWidth > 0) { 448 | // if viewport is smaller than minThreshold, return minSlides 449 | if (slider.viewport.width() < slider.minThreshold) { 450 | slidesShowing = slider.settings.minSlides; 451 | // if viewport is larger than maxThreshold, return maxSlides 452 | } else if (slider.viewport.width() > slider.maxThreshold) { 453 | slidesShowing = slider.settings.maxSlides; 454 | // if viewport is between min / max thresholds, divide viewport width by first child width 455 | } else { 456 | childWidth = slider.children.first().width() + slider.settings.slideMargin; 457 | slidesShowing = Math.floor((slider.viewport.width() + 458 | slider.settings.slideMargin) / childWidth); 459 | } 460 | // if "vertical" mode, slides showing will always be minSlides 461 | } else if (slider.settings.mode === 'vertical') { 462 | slidesShowing = slider.settings.minSlides; 463 | } 464 | return slidesShowing; 465 | }; 466 | 467 | /** 468 | * Returns the number of pages (one full viewport of slides is one "page") 469 | */ 470 | var getPagerQty = function() { 471 | var pagerQty = 0, 472 | breakPoint = 0, 473 | counter = 0; 474 | // if moveSlides is specified by the user 475 | if (slider.settings.moveSlides > 0) { 476 | if (slider.settings.infiniteLoop) { 477 | pagerQty = Math.ceil(slider.children.length / getMoveBy()); 478 | } else { 479 | // when breakpoint goes above children length, counter is the number of pages 480 | while (breakPoint < slider.children.length) { 481 | ++pagerQty; 482 | breakPoint = counter + getNumberSlidesShowing(); 483 | counter += slider.settings.moveSlides <= getNumberSlidesShowing() ? slider.settings.moveSlides : getNumberSlidesShowing(); 484 | } 485 | } 486 | // if moveSlides is 0 (auto) divide children length by sides showing, then round up 487 | } else { 488 | pagerQty = Math.ceil(slider.children.length / getNumberSlidesShowing()); 489 | } 490 | return pagerQty; 491 | }; 492 | 493 | /** 494 | * Returns the number of individual slides by which to shift the slider 495 | */ 496 | var getMoveBy = function() { 497 | // if moveSlides was set by the user and moveSlides is less than number of slides showing 498 | if (slider.settings.moveSlides > 0 && slider.settings.moveSlides <= getNumberSlidesShowing()) { 499 | return slider.settings.moveSlides; 500 | } 501 | // if moveSlides is 0 (auto) 502 | return getNumberSlidesShowing(); 503 | }; 504 | 505 | /** 506 | * Sets the slider's (el) left or top position 507 | */ 508 | var setSlidePosition = function() { 509 | var position, lastChild, lastShowingIndex; 510 | // if last slide, not infinite loop, and number of children is larger than specified maxSlides 511 | if (slider.children.length > slider.settings.maxSlides && slider.active.last && !slider.settings.infiniteLoop) { 512 | if (slider.settings.mode === 'horizontal') { 513 | // get the last child's position 514 | lastChild = slider.children.last(); 515 | position = lastChild.position(); 516 | // set the left position 517 | setPositionProperty(-(position.left - (slider.viewport.width() - lastChild.outerWidth())), 'reset', 0); 518 | } else if (slider.settings.mode === 'vertical') { 519 | // get the last showing index's position 520 | lastShowingIndex = slider.children.length - slider.settings.minSlides; 521 | position = slider.children.eq(lastShowingIndex).position(); 522 | // set the top position 523 | setPositionProperty(-position.top, 'reset', 0); 524 | } 525 | // if not last slide 526 | } else { 527 | // get the position of the first showing slide 528 | position = slider.children.eq(slider.active.index * getMoveBy()).position(); 529 | // check for last slide 530 | if (slider.active.index === getPagerQty() - 1) { slider.active.last = true; } 531 | // set the respective position 532 | if (position !== undefined) { 533 | if (slider.settings.mode === 'horizontal') { setPositionProperty(-position.left, 'reset', 0); } 534 | else if (slider.settings.mode === 'vertical') { setPositionProperty(-position.top, 'reset', 0); } 535 | } 536 | } 537 | }; 538 | 539 | /** 540 | * Sets the el's animating property position (which in turn will sometimes animate el). 541 | * If using CSS, sets the transform property. If not using CSS, sets the top / left property. 542 | * 543 | * @param value (int) 544 | * - the animating property's value 545 | * 546 | * @param type (string) 'slide', 'reset', 'ticker' 547 | * - the type of instance for which the function is being 548 | * 549 | * @param duration (int) 550 | * - the amount of time (in ms) the transition should occupy 551 | * 552 | * @param params (array) optional 553 | * - an optional parameter containing any variables that need to be passed in 554 | */ 555 | var setPositionProperty = function(value, type, duration, params) { 556 | var animateObj, propValue; 557 | // use CSS transform 558 | if (slider.usingCSS) { 559 | // determine the translate3d value 560 | propValue = slider.settings.mode === 'vertical' ? 'translate3d(0, ' + value + 'px, 0)' : 'translate3d(' + value + 'px, 0, 0)'; 561 | // add the CSS transition-duration 562 | el.css('-' + slider.cssPrefix + '-transition-duration', duration / 1000 + 's'); 563 | if (type === 'slide') { 564 | // set the property value 565 | el.css(slider.animProp, propValue); 566 | if (duration !== 0) { 567 | // bind a callback method - executes when CSS transition completes 568 | el.bind('transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd', function(e) { 569 | //make sure it's the correct one 570 | if (!$(e.target).is(el)) { return; } 571 | // unbind the callback 572 | el.unbind('transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd'); 573 | updateAfterSlideTransition(); 574 | }); 575 | } else { //duration = 0 576 | updateAfterSlideTransition(); 577 | } 578 | } else if (type === 'reset') { 579 | el.css(slider.animProp, propValue); 580 | } else if (type === 'ticker') { 581 | // make the transition use 'linear' 582 | el.css('-' + slider.cssPrefix + '-transition-timing-function', 'linear'); 583 | el.css(slider.animProp, propValue); 584 | if (duration !== 0) { 585 | el.bind('transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd', function(e) { 586 | //make sure it's the correct one 587 | if (!$(e.target).is(el)) { return; } 588 | // unbind the callback 589 | el.unbind('transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd'); 590 | // reset the position 591 | setPositionProperty(params.resetValue, 'reset', 0); 592 | // start the loop again 593 | tickerLoop(); 594 | }); 595 | } else { //duration = 0 596 | setPositionProperty(params.resetValue, 'reset', 0); 597 | tickerLoop(); 598 | } 599 | } 600 | // use JS animate 601 | } else { 602 | animateObj = {}; 603 | animateObj[slider.animProp] = value; 604 | if (type === 'slide') { 605 | el.animate(animateObj, duration, slider.settings.easing, function() { 606 | updateAfterSlideTransition(); 607 | }); 608 | } else if (type === 'reset') { 609 | el.css(slider.animProp, value); 610 | } else if (type === 'ticker') { 611 | el.animate(animateObj, duration, 'linear', function() { 612 | setPositionProperty(params.resetValue, 'reset', 0); 613 | // run the recursive loop after animation 614 | tickerLoop(); 615 | }); 616 | } 617 | } 618 | }; 619 | 620 | /** 621 | * Populates the pager with proper amount of pages 622 | */ 623 | var populatePager = function() { 624 | var pagerHtml = '', 625 | linkContent = '', 626 | pagerQty = getPagerQty(); 627 | // loop through each pager item 628 | for (var i = 0; i < pagerQty; i++) { 629 | linkContent = ''; 630 | // if a buildPager function is supplied, use it to get pager link value, else use index + 1 631 | if (slider.settings.buildPager && $.isFunction(slider.settings.buildPager) || slider.settings.pagerCustom) { 632 | linkContent = slider.settings.buildPager(i); 633 | slider.pagerEl.addClass('bx-custom-pager'); 634 | } else { 635 | linkContent = i + 1; 636 | slider.pagerEl.addClass('bx-default-pager'); 637 | } 638 | // var linkContent = slider.settings.buildPager && $.isFunction(slider.settings.buildPager) ? slider.settings.buildPager(i) : i + 1; 639 | // add the markup to the string 640 | pagerHtml += ''; 641 | } 642 | // populate the pager element with pager links 643 | slider.pagerEl.html(pagerHtml); 644 | }; 645 | 646 | /** 647 | * Appends the pager to the controls element 648 | */ 649 | var appendPager = function() { 650 | if (!slider.settings.pagerCustom) { 651 | // create the pager DOM element 652 | slider.pagerEl = $('
'); 653 | // if a pager selector was supplied, populate it with the pager 654 | if (slider.settings.pagerSelector) { 655 | $(slider.settings.pagerSelector).html(slider.pagerEl); 656 | // if no pager selector was supplied, add it after the wrapper 657 | } else { 658 | slider.controls.el.addClass('bx-has-pager').append(slider.pagerEl); 659 | } 660 | // populate the pager 661 | populatePager(); 662 | } else { 663 | slider.pagerEl = $(slider.settings.pagerCustom); 664 | } 665 | // assign the pager click binding 666 | slider.pagerEl.on('click touchend', 'a', clickPagerBind); 667 | }; 668 | 669 | /** 670 | * Appends prev / next controls to the controls element 671 | */ 672 | var appendControls = function() { 673 | slider.controls.next = $('' + slider.settings.nextText + ''); 674 | slider.controls.prev = $('' + slider.settings.prevText + ''); 675 | // bind click actions to the controls 676 | slider.controls.next.bind('click touchend', clickNextBind); 677 | slider.controls.prev.bind('click touchend', clickPrevBind); 678 | // if nextSelector was supplied, populate it 679 | if (slider.settings.nextSelector) { 680 | $(slider.settings.nextSelector).append(slider.controls.next); 681 | } 682 | // if prevSelector was supplied, populate it 683 | if (slider.settings.prevSelector) { 684 | $(slider.settings.prevSelector).append(slider.controls.prev); 685 | } 686 | // if no custom selectors were supplied 687 | if (!slider.settings.nextSelector && !slider.settings.prevSelector) { 688 | // add the controls to the DOM 689 | slider.controls.directionEl = $('
'); 690 | // add the control elements to the directionEl 691 | slider.controls.directionEl.append(slider.controls.prev).append(slider.controls.next); 692 | // slider.viewport.append(slider.controls.directionEl); 693 | slider.controls.el.addClass('bx-has-controls-direction').append(slider.controls.directionEl); 694 | } 695 | }; 696 | 697 | /** 698 | * Appends start / stop auto controls to the controls element 699 | */ 700 | var appendControlsAuto = function() { 701 | slider.controls.start = $(''); 702 | slider.controls.stop = $(''); 703 | // add the controls to the DOM 704 | slider.controls.autoEl = $('
'); 705 | // bind click actions to the controls 706 | slider.controls.autoEl.on('click', '.bx-start', clickStartBind); 707 | slider.controls.autoEl.on('click', '.bx-stop', clickStopBind); 708 | // if autoControlsCombine, insert only the "start" control 709 | if (slider.settings.autoControlsCombine) { 710 | slider.controls.autoEl.append(slider.controls.start); 711 | // if autoControlsCombine is false, insert both controls 712 | } else { 713 | slider.controls.autoEl.append(slider.controls.start).append(slider.controls.stop); 714 | } 715 | // if auto controls selector was supplied, populate it with the controls 716 | if (slider.settings.autoControlsSelector) { 717 | $(slider.settings.autoControlsSelector).html(slider.controls.autoEl); 718 | // if auto controls selector was not supplied, add it after the wrapper 719 | } else { 720 | slider.controls.el.addClass('bx-has-controls-auto').append(slider.controls.autoEl); 721 | } 722 | // update the auto controls 723 | updateAutoControls(slider.settings.autoStart ? 'stop' : 'start'); 724 | }; 725 | 726 | /** 727 | * Appends image captions to the DOM 728 | */ 729 | var appendCaptions = function() { 730 | // cycle through each child 731 | slider.children.each(function(index) { 732 | // get the image title attribute 733 | var title = $(this).find('img:first').attr('title'); 734 | // append the caption 735 | if (title !== undefined && ('' + title).length) { 736 | $(this).append('
' + title + '
'); 737 | } 738 | }); 739 | }; 740 | 741 | /** 742 | * Click next binding 743 | * 744 | * @param e (event) 745 | * - DOM event object 746 | */ 747 | var clickNextBind = function(e) { 748 | e.preventDefault(); 749 | if (slider.controls.el.hasClass('disabled')) { return; } 750 | // if auto show is running, stop it 751 | if (slider.settings.auto && slider.settings.stopAutoOnClick) { el.stopAuto(); } 752 | el.goToNextSlide(); 753 | }; 754 | 755 | /** 756 | * Click prev binding 757 | * 758 | * @param e (event) 759 | * - DOM event object 760 | */ 761 | var clickPrevBind = function(e) { 762 | e.preventDefault(); 763 | if (slider.controls.el.hasClass('disabled')) { return; } 764 | // if auto show is running, stop it 765 | if (slider.settings.auto && slider.settings.stopAutoOnClick) { el.stopAuto(); } 766 | el.goToPrevSlide(); 767 | }; 768 | 769 | /** 770 | * Click start binding 771 | * 772 | * @param e (event) 773 | * - DOM event object 774 | */ 775 | var clickStartBind = function(e) { 776 | el.startAuto(); 777 | e.preventDefault(); 778 | }; 779 | 780 | /** 781 | * Click stop binding 782 | * 783 | * @param e (event) 784 | * - DOM event object 785 | */ 786 | var clickStopBind = function(e) { 787 | el.stopAuto(); 788 | e.preventDefault(); 789 | }; 790 | 791 | /** 792 | * Click pager binding 793 | * 794 | * @param e (event) 795 | * - DOM event object 796 | */ 797 | var clickPagerBind = function(e) { 798 | var pagerLink, pagerIndex; 799 | e.preventDefault(); 800 | if (slider.controls.el.hasClass('disabled')) { 801 | return; 802 | } 803 | // if auto show is running, stop it 804 | if (slider.settings.auto && slider.settings.stopAutoOnClick) { el.stopAuto(); } 805 | pagerLink = $(e.currentTarget); 806 | if (pagerLink.attr('data-slide-index') !== undefined) { 807 | pagerIndex = parseInt(pagerLink.attr('data-slide-index')); 808 | // if clicked pager link is not active, continue with the goToSlide call 809 | if (pagerIndex !== slider.active.index) { el.goToSlide(pagerIndex); } 810 | } 811 | }; 812 | 813 | /** 814 | * Updates the pager links with an active class 815 | * 816 | * @param slideIndex (int) 817 | * - index of slide to make active 818 | */ 819 | var updatePagerActive = function(slideIndex) { 820 | // if "short" pager type 821 | var len = slider.children.length; // nb of children 822 | if (slider.settings.pagerType === 'short') { 823 | if (slider.settings.maxSlides > 1) { 824 | len = Math.ceil(slider.children.length / slider.settings.maxSlides); 825 | } 826 | slider.pagerEl.html((slideIndex + 1) + slider.settings.pagerShortSeparator + len); 827 | return; 828 | } 829 | // remove all pager active classes 830 | slider.pagerEl.find('a').removeClass('active'); 831 | // apply the active class for all pagers 832 | slider.pagerEl.each(function(i, el) { $(el).find('a').eq(slideIndex).addClass('active'); }); 833 | }; 834 | 835 | /** 836 | * Performs needed actions after a slide transition 837 | */ 838 | var updateAfterSlideTransition = function() { 839 | // if infinite loop is true 840 | if (slider.settings.infiniteLoop) { 841 | var position = ''; 842 | // first slide 843 | if (slider.active.index === 0) { 844 | // set the new position 845 | position = slider.children.eq(0).position(); 846 | // carousel, last slide 847 | } else if (slider.active.index === getPagerQty() - 1 && slider.carousel) { 848 | position = slider.children.eq((getPagerQty() - 1) * getMoveBy()).position(); 849 | // last slide 850 | } else if (slider.active.index === slider.children.length - 1) { 851 | position = slider.children.eq(slider.children.length - 1).position(); 852 | } 853 | if (position) { 854 | if (slider.settings.mode === 'horizontal') { setPositionProperty(-position.left, 'reset', 0); } 855 | else if (slider.settings.mode === 'vertical') { setPositionProperty(-position.top, 'reset', 0); } 856 | } 857 | } 858 | // declare that the transition is complete 859 | slider.working = false; 860 | // onSlideAfter callback 861 | slider.settings.onSlideAfter.call(el, slider.children.eq(slider.active.index), slider.oldIndex, slider.active.index); 862 | }; 863 | 864 | /** 865 | * Updates the auto controls state (either active, or combined switch) 866 | * 867 | * @param state (string) "start", "stop" 868 | * - the new state of the auto show 869 | */ 870 | var updateAutoControls = function(state) { 871 | // if autoControlsCombine is true, replace the current control with the new state 872 | if (slider.settings.autoControlsCombine) { 873 | slider.controls.autoEl.html(slider.controls[state]); 874 | // if autoControlsCombine is false, apply the "active" class to the appropriate control 875 | } else { 876 | slider.controls.autoEl.find('a').removeClass('active'); 877 | slider.controls.autoEl.find('a:not(.bx-' + state + ')').addClass('active'); 878 | } 879 | }; 880 | 881 | /** 882 | * Updates the direction controls (checks if either should be hidden) 883 | */ 884 | var updateDirectionControls = function() { 885 | if (getPagerQty() === 1) { 886 | slider.controls.prev.addClass('disabled'); 887 | slider.controls.next.addClass('disabled'); 888 | } else if (!slider.settings.infiniteLoop && slider.settings.hideControlOnEnd) { 889 | // if first slide 890 | if (slider.active.index === 0) { 891 | slider.controls.prev.addClass('disabled'); 892 | slider.controls.next.removeClass('disabled'); 893 | // if last slide 894 | } else if (slider.active.index === getPagerQty() - 1) { 895 | slider.controls.next.addClass('disabled'); 896 | slider.controls.prev.removeClass('disabled'); 897 | // if any slide in the middle 898 | } else { 899 | slider.controls.prev.removeClass('disabled'); 900 | slider.controls.next.removeClass('disabled'); 901 | } 902 | } 903 | }; 904 | 905 | /** 906 | * Initializes the auto process 907 | */ 908 | var initAuto = function() { 909 | // if autoDelay was supplied, launch the auto show using a setTimeout() call 910 | if (slider.settings.autoDelay > 0) { 911 | var timeout = setTimeout(el.startAuto, slider.settings.autoDelay); 912 | // if autoDelay was not supplied, start the auto show normally 913 | } else { 914 | el.startAuto(); 915 | 916 | //add focus and blur events to ensure its running if timeout gets paused 917 | $(window).focus(function() { 918 | el.startAuto(); 919 | }).blur(function() { 920 | el.stopAuto(); 921 | }); 922 | } 923 | // if autoHover is requested 924 | if (slider.settings.autoHover) { 925 | // on el hover 926 | el.hover(function() { 927 | // if the auto show is currently playing (has an active interval) 928 | if (slider.interval) { 929 | // stop the auto show and pass true argument which will prevent control update 930 | el.stopAuto(true); 931 | // create a new autoPaused value which will be used by the relative "mouseout" event 932 | slider.autoPaused = true; 933 | } 934 | }, function() { 935 | // if the autoPaused value was created be the prior "mouseover" event 936 | if (slider.autoPaused) { 937 | // start the auto show and pass true argument which will prevent control update 938 | el.startAuto(true); 939 | // reset the autoPaused value 940 | slider.autoPaused = null; 941 | } 942 | }); 943 | } 944 | }; 945 | 946 | /** 947 | * Initializes the ticker process 948 | */ 949 | var initTicker = function() { 950 | var startPosition = 0, 951 | position, transform, value, idx, ratio, property, newSpeed, totalDimens; 952 | // if autoDirection is "next", append a clone of the entire slider 953 | if (slider.settings.autoDirection === 'next') { 954 | el.append(slider.children.clone().addClass('bx-clone')); 955 | // if autoDirection is "prev", prepend a clone of the entire slider, and set the left position 956 | } else { 957 | el.prepend(slider.children.clone().addClass('bx-clone')); 958 | position = slider.children.first().position(); 959 | startPosition = slider.settings.mode === 'horizontal' ? -position.left : -position.top; 960 | } 961 | setPositionProperty(startPosition, 'reset', 0); 962 | // do not allow controls in ticker mode 963 | slider.settings.pager = false; 964 | slider.settings.controls = false; 965 | slider.settings.autoControls = false; 966 | // if autoHover is requested 967 | if (slider.settings.tickerHover) { 968 | if (slider.usingCSS) { 969 | idx = slider.settings.mode === 'horizontal' ? 4 : 5; 970 | slider.viewport.hover(function() { 971 | transform = el.css('-' + slider.cssPrefix + '-transform'); 972 | value = parseFloat(transform.split(',')[idx]); 973 | setPositionProperty(value, 'reset', 0); 974 | }, function() { 975 | totalDimens = 0; 976 | slider.children.each(function(index) { 977 | totalDimens += slider.settings.mode === 'horizontal' ? $(this).outerWidth(true) : $(this).outerHeight(true); 978 | }); 979 | // calculate the speed ratio (used to determine the new speed to finish the paused animation) 980 | ratio = slider.settings.speed / totalDimens; 981 | // determine which property to use 982 | property = slider.settings.mode === 'horizontal' ? 'left' : 'top'; 983 | // calculate the new speed 984 | newSpeed = ratio * (totalDimens - (Math.abs(parseInt(value)))); 985 | tickerLoop(newSpeed); 986 | }); 987 | } else { 988 | // on el hover 989 | slider.viewport.hover(function() { 990 | el.stop(); 991 | }, function() { 992 | // calculate the total width of children (used to calculate the speed ratio) 993 | totalDimens = 0; 994 | slider.children.each(function(index) { 995 | totalDimens += slider.settings.mode === 'horizontal' ? $(this).outerWidth(true) : $(this).outerHeight(true); 996 | }); 997 | // calculate the speed ratio (used to determine the new speed to finish the paused animation) 998 | ratio = slider.settings.speed / totalDimens; 999 | // determine which property to use 1000 | property = slider.settings.mode === 'horizontal' ? 'left' : 'top'; 1001 | // calculate the new speed 1002 | newSpeed = ratio * (totalDimens - (Math.abs(parseInt(el.css(property))))); 1003 | tickerLoop(newSpeed); 1004 | }); 1005 | } 1006 | } 1007 | // start the ticker loop 1008 | tickerLoop(); 1009 | }; 1010 | 1011 | /** 1012 | * Runs a continuous loop, news ticker-style 1013 | */ 1014 | var tickerLoop = function(resumeSpeed) { 1015 | var speed = resumeSpeed ? resumeSpeed : slider.settings.speed, 1016 | position = {left: 0, top: 0}, 1017 | reset = {left: 0, top: 0}, 1018 | animateProperty, resetValue, params; 1019 | 1020 | // if "next" animate left position to last child, then reset left to 0 1021 | if (slider.settings.autoDirection === 'next') { 1022 | position = el.find('.bx-clone').first().position(); 1023 | // if "prev" animate left position to 0, then reset left to first non-clone child 1024 | } else { 1025 | reset = slider.children.first().position(); 1026 | } 1027 | animateProperty = slider.settings.mode === 'horizontal' ? -position.left : -position.top; 1028 | resetValue = slider.settings.mode === 'horizontal' ? -reset.left : -reset.top; 1029 | params = {resetValue: resetValue}; 1030 | setPositionProperty(animateProperty, 'ticker', speed, params); 1031 | }; 1032 | 1033 | /** 1034 | * Check if el is on screen 1035 | */ 1036 | var isOnScreen = function(el) { 1037 | var win = $(window), 1038 | viewport = { 1039 | top: win.scrollTop(), 1040 | left: win.scrollLeft() 1041 | }, 1042 | bounds = el.offset(); 1043 | 1044 | viewport.right = viewport.left + win.width(); 1045 | viewport.bottom = viewport.top + win.height(); 1046 | bounds.right = bounds.left + el.outerWidth(); 1047 | bounds.bottom = bounds.top + el.outerHeight(); 1048 | 1049 | return (!(viewport.right < bounds.left || viewport.left > bounds.right || viewport.bottom < bounds.top || viewport.top > bounds.bottom)); 1050 | }; 1051 | 1052 | /** 1053 | * Initializes keyboard events 1054 | */ 1055 | var keyPress = function(e) { 1056 | var activeElementTag = document.activeElement.tagName.toLowerCase(), 1057 | tagFilters = 'input|textarea', 1058 | p = new RegExp(activeElementTag,['i']), 1059 | result = p.exec(tagFilters); 1060 | 1061 | if (result == null && isOnScreen(el)) { 1062 | if (e.keyCode === 39) { 1063 | clickNextBind(e); 1064 | return false; 1065 | } else if (e.keyCode === 37) { 1066 | clickPrevBind(e); 1067 | return false; 1068 | } 1069 | } 1070 | }; 1071 | 1072 | /** 1073 | * Initializes touch events 1074 | */ 1075 | var initTouch = function() { 1076 | // initialize object to contain all touch values 1077 | slider.touch = { 1078 | start: {x: 0, y: 0}, 1079 | end: {x: 0, y: 0} 1080 | }; 1081 | slider.viewport.bind('touchstart MSPointerDown pointerdown', onTouchStart); 1082 | 1083 | //for browsers that have implemented pointer events and fire a click after 1084 | //every pointerup regardless of whether pointerup is on same screen location as pointerdown or not 1085 | slider.viewport.on('click', '.bxslider a', function(e) { 1086 | if (slider.viewport.hasClass('click-disabled')) { 1087 | e.preventDefault(); 1088 | slider.viewport.removeClass('click-disabled'); 1089 | } 1090 | }); 1091 | }; 1092 | 1093 | /** 1094 | * Event handler for "touchstart" 1095 | * 1096 | * @param e (event) 1097 | * - DOM event object 1098 | */ 1099 | var onTouchStart = function(e) { 1100 | //disable slider controls while user is interacting with slides to avoid slider freeze that happens on touch devices when a slide swipe happens immediately after interacting with slider controls 1101 | slider.controls.el.addClass('disabled'); 1102 | 1103 | if (slider.working) { 1104 | e.preventDefault(); 1105 | slider.controls.el.removeClass('disabled'); 1106 | } else { 1107 | // record the original position when touch starts 1108 | slider.touch.originalPos = el.position(); 1109 | var orig = e.originalEvent, 1110 | touchPoints = (typeof orig.changedTouches !== 'undefined') ? orig.changedTouches : [orig]; 1111 | // record the starting touch x, y coordinates 1112 | slider.touch.start.x = touchPoints[0].pageX; 1113 | slider.touch.start.y = touchPoints[0].pageY; 1114 | 1115 | if (slider.viewport.get(0).setPointerCapture) { 1116 | slider.pointerId = orig.pointerId; 1117 | slider.viewport.get(0).setPointerCapture(slider.pointerId); 1118 | } 1119 | // bind a "touchmove" event to the viewport 1120 | slider.viewport.bind('touchmove MSPointerMove pointermove', onTouchMove); 1121 | // bind a "touchend" event to the viewport 1122 | slider.viewport.bind('touchend MSPointerUp pointerup', onTouchEnd); 1123 | slider.viewport.bind('MSPointerCancel pointercancel', onPointerCancel); 1124 | } 1125 | }; 1126 | 1127 | /** 1128 | * Cancel Pointer for Windows Phone 1129 | * 1130 | * @param e (event) 1131 | * - DOM event object 1132 | */ 1133 | var onPointerCancel = function(e) { 1134 | /* onPointerCancel handler is needed to deal with situations when a touchend 1135 | doesn't fire after a touchstart (this happens on windows phones only) */ 1136 | setPositionProperty(slider.touch.originalPos.left, 'reset', 0); 1137 | 1138 | //remove handlers 1139 | slider.controls.el.removeClass('disabled'); 1140 | slider.viewport.unbind('MSPointerCancel pointercancel', onPointerCancel); 1141 | slider.viewport.unbind('touchmove MSPointerMove pointermove', onTouchMove); 1142 | slider.viewport.unbind('touchend MSPointerUp pointerup', onTouchEnd); 1143 | if (slider.viewport.get(0).releasePointerCapture) { 1144 | slider.viewport.get(0).releasePointerCapture(slider.pointerId); 1145 | } 1146 | }; 1147 | 1148 | /** 1149 | * Event handler for "touchmove" 1150 | * 1151 | * @param e (event) 1152 | * - DOM event object 1153 | */ 1154 | var onTouchMove = function(e) { 1155 | var orig = e.originalEvent, 1156 | touchPoints = (typeof orig.changedTouches !== 'undefined') ? orig.changedTouches : [orig], 1157 | // if scrolling on y axis, do not prevent default 1158 | xMovement = Math.abs(touchPoints[0].pageX - slider.touch.start.x), 1159 | yMovement = Math.abs(touchPoints[0].pageY - slider.touch.start.y), 1160 | value = 0, 1161 | change = 0; 1162 | 1163 | // x axis swipe 1164 | if ((xMovement * 3) > yMovement && slider.settings.preventDefaultSwipeX) { 1165 | e.preventDefault(); 1166 | // y axis swipe 1167 | } else if ((yMovement * 3) > xMovement && slider.settings.preventDefaultSwipeY) { 1168 | e.preventDefault(); 1169 | } 1170 | if (slider.settings.mode !== 'fade' && slider.settings.oneToOneTouch) { 1171 | // if horizontal, drag along x axis 1172 | if (slider.settings.mode === 'horizontal') { 1173 | change = touchPoints[0].pageX - slider.touch.start.x; 1174 | value = slider.touch.originalPos.left + change; 1175 | // if vertical, drag along y axis 1176 | } else { 1177 | change = touchPoints[0].pageY - slider.touch.start.y; 1178 | value = slider.touch.originalPos.top + change; 1179 | } 1180 | setPositionProperty(value, 'reset', 0); 1181 | } 1182 | }; 1183 | 1184 | /** 1185 | * Event handler for "touchend" 1186 | * 1187 | * @param e (event) 1188 | * - DOM event object 1189 | */ 1190 | var onTouchEnd = function(e) { 1191 | slider.viewport.unbind('touchmove MSPointerMove pointermove', onTouchMove); 1192 | //enable slider controls as soon as user stops interacing with slides 1193 | slider.controls.el.removeClass('disabled'); 1194 | var orig = e.originalEvent, 1195 | touchPoints = (typeof orig.changedTouches !== 'undefined') ? orig.changedTouches : [orig], 1196 | value = 0, 1197 | distance = 0; 1198 | // record end x, y positions 1199 | slider.touch.end.x = touchPoints[0].pageX; 1200 | slider.touch.end.y = touchPoints[0].pageY; 1201 | // if fade mode, check if absolute x distance clears the threshold 1202 | if (slider.settings.mode === 'fade') { 1203 | distance = Math.abs(slider.touch.start.x - slider.touch.end.x); 1204 | if (distance >= slider.settings.swipeThreshold) { 1205 | if (slider.touch.start.x > slider.touch.end.x) { 1206 | el.goToNextSlide(); 1207 | } else { 1208 | el.goToPrevSlide(); 1209 | } 1210 | el.stopAuto(); 1211 | } 1212 | // not fade mode 1213 | } else { 1214 | // calculate distance and el's animate property 1215 | if (slider.settings.mode === 'horizontal') { 1216 | distance = slider.touch.end.x - slider.touch.start.x; 1217 | value = slider.touch.originalPos.left; 1218 | } else { 1219 | distance = slider.touch.end.y - slider.touch.start.y; 1220 | value = slider.touch.originalPos.top; 1221 | } 1222 | // if not infinite loop and first / last slide, do not attempt a slide transition 1223 | if (!slider.settings.infiniteLoop && ((slider.active.index === 0 && distance > 0) || (slider.active.last && distance < 0))) { 1224 | setPositionProperty(value, 'reset', 200); 1225 | } else { 1226 | // check if distance clears threshold 1227 | if (Math.abs(distance) >= slider.settings.swipeThreshold) { 1228 | if (distance < 0) { 1229 | el.goToNextSlide(); 1230 | } else { 1231 | el.goToPrevSlide(); 1232 | } 1233 | el.stopAuto(); 1234 | } else { 1235 | // el.animate(property, 200); 1236 | setPositionProperty(value, 'reset', 200); 1237 | } 1238 | } 1239 | } 1240 | slider.viewport.unbind('touchend MSPointerUp pointerup', onTouchEnd); 1241 | if (slider.viewport.get(0).releasePointerCapture) { 1242 | slider.viewport.get(0).releasePointerCapture(slider.pointerId); 1243 | } 1244 | }; 1245 | 1246 | /** 1247 | * Window resize event callback 1248 | */ 1249 | var resizeWindow = function(e) { 1250 | // don't do anything if slider isn't initialized. 1251 | if (!slider.initialized) { return; } 1252 | // Delay if slider working. 1253 | if (slider.working) { 1254 | window.setTimeout(resizeWindow, 10); 1255 | } else { 1256 | // get the new window dimens (again, thank you IE) 1257 | var windowWidthNew = $(window).width(), 1258 | windowHeightNew = $(window).height(); 1259 | // make sure that it is a true window resize 1260 | // *we must check this because our dinosaur friend IE fires a window resize event when certain DOM elements 1261 | // are resized. Can you just die already?* 1262 | if (windowWidth !== windowWidthNew || windowHeight !== windowHeightNew) { 1263 | // set the new window dimens 1264 | windowWidth = windowWidthNew; 1265 | windowHeight = windowHeightNew; 1266 | // update all dynamic elements 1267 | el.redrawSlider(); 1268 | // Call user resize handler 1269 | slider.settings.onSliderResize.call(el, slider.active.index); 1270 | } 1271 | } 1272 | }; 1273 | 1274 | /** 1275 | * Adds an aria-hidden=true attribute to each element 1276 | * 1277 | * @param startVisibleIndex (int) 1278 | * - the first visible element's index 1279 | */ 1280 | var applyAriaHiddenAttributes = function(startVisibleIndex) { 1281 | var numberOfSlidesShowing = getNumberSlidesShowing(); 1282 | // only apply attributes if the setting is enabled and not in ticker mode 1283 | if (slider.settings.ariaHidden && !slider.settings.ticker) { 1284 | // add aria-hidden=true to all elements 1285 | slider.children.attr('aria-hidden', 'true'); 1286 | // get the visible elements and change to aria-hidden=false 1287 | slider.children.slice(startVisibleIndex, startVisibleIndex + numberOfSlidesShowing).attr('aria-hidden', 'false'); 1288 | } 1289 | }; 1290 | 1291 | /** 1292 | * Returns index according to present page range 1293 | * 1294 | * @param slideOndex (int) 1295 | * - the desired slide index 1296 | */ 1297 | var setSlideIndex = function(slideIndex) { 1298 | if (slideIndex < 0) { 1299 | if (slider.settings.infiniteLoop) { 1300 | return getPagerQty() - 1; 1301 | }else { 1302 | //we don't go to undefined slides 1303 | return slider.active.index; 1304 | } 1305 | // if slideIndex is greater than children length, set active index to 0 (this happens during infinite loop) 1306 | } else if (slideIndex >= getPagerQty()) { 1307 | if (slider.settings.infiniteLoop) { 1308 | return 0; 1309 | } else { 1310 | //we don't move to undefined pages 1311 | return slider.active.index; 1312 | } 1313 | // set active index to requested slide 1314 | } else { 1315 | return slideIndex; 1316 | } 1317 | }; 1318 | 1319 | /** 1320 | * =================================================================================== 1321 | * = PUBLIC FUNCTIONS 1322 | * =================================================================================== 1323 | */ 1324 | 1325 | /** 1326 | * Performs slide transition to the specified slide 1327 | * 1328 | * @param slideIndex (int) 1329 | * - the destination slide's index (zero-based) 1330 | * 1331 | * @param direction (string) 1332 | * - INTERNAL USE ONLY - the direction of travel ("prev" / "next") 1333 | */ 1334 | el.goToSlide = function(slideIndex, direction) { 1335 | // onSlideBefore, onSlideNext, onSlidePrev callbacks 1336 | // Allow transition canceling based on returned value 1337 | var performTransition = true, 1338 | moveBy = 0, 1339 | position = {left: 0, top: 0}, 1340 | lastChild = null, 1341 | lastShowingIndex, eq, value, requestEl; 1342 | // store the old index 1343 | slider.oldIndex = slider.active.index; 1344 | //set new index 1345 | slider.active.index = setSlideIndex(slideIndex); 1346 | 1347 | // if plugin is currently in motion, ignore request 1348 | if (slider.working || slider.active.index === slider.oldIndex) { return; } 1349 | // declare that plugin is in motion 1350 | slider.working = true; 1351 | 1352 | performTransition = slider.settings.onSlideBefore.call(el, slider.children.eq(slider.active.index), slider.oldIndex, slider.active.index); 1353 | 1354 | // If transitions canceled, reset and return 1355 | if (typeof (performTransition) !== 'undefined' && !performTransition) { 1356 | slider.active.index = slider.oldIndex; // restore old index 1357 | slider.working = false; // is not in motion 1358 | return; 1359 | } 1360 | 1361 | if (direction === 'next') { 1362 | // Prevent canceling in future functions or lack there-of from negating previous commands to cancel 1363 | if (!slider.settings.onSlideNext.call(el, slider.children.eq(slider.active.index), slider.oldIndex, slider.active.index)) { 1364 | performTransition = false; 1365 | } 1366 | } else if (direction === 'prev') { 1367 | // Prevent canceling in future functions or lack there-of from negating previous commands to cancel 1368 | if (!slider.settings.onSlidePrev.call(el, slider.children.eq(slider.active.index), slider.oldIndex, slider.active.index)) { 1369 | performTransition = false; 1370 | } 1371 | } 1372 | 1373 | // check if last slide 1374 | slider.active.last = slider.active.index >= getPagerQty() - 1; 1375 | // update the pager with active class 1376 | if (slider.settings.pager || slider.settings.pagerCustom) { updatePagerActive(slider.active.index); } 1377 | // // check for direction control update 1378 | if (slider.settings.controls) { updateDirectionControls(); } 1379 | // if slider is set to mode: "fade" 1380 | if (slider.settings.mode === 'fade') { 1381 | // if adaptiveHeight is true and next height is different from current height, animate to the new height 1382 | if (slider.settings.adaptiveHeight && slider.viewport.height() !== getViewportHeight()) { 1383 | slider.viewport.animate({height: getViewportHeight()}, slider.settings.adaptiveHeightSpeed); 1384 | } 1385 | // fade out the visible child and reset its z-index value 1386 | slider.children.filter(':visible').fadeOut(slider.settings.speed).css({zIndex: 0}); 1387 | // fade in the newly requested slide 1388 | slider.children.eq(slider.active.index).css('zIndex', slider.settings.slideZIndex + 1).fadeIn(slider.settings.speed, function() { 1389 | $(this).css('zIndex', slider.settings.slideZIndex); 1390 | updateAfterSlideTransition(); 1391 | }); 1392 | // slider mode is not "fade" 1393 | } else { 1394 | // if adaptiveHeight is true and next height is different from current height, animate to the new height 1395 | if (slider.settings.adaptiveHeight && slider.viewport.height() !== getViewportHeight()) { 1396 | slider.viewport.animate({height: getViewportHeight()}, slider.settings.adaptiveHeightSpeed); 1397 | } 1398 | // if carousel and not infinite loop 1399 | if (!slider.settings.infiniteLoop && slider.carousel && slider.active.last) { 1400 | if (slider.settings.mode === 'horizontal') { 1401 | // get the last child position 1402 | lastChild = slider.children.eq(slider.children.length - 1); 1403 | position = lastChild.position(); 1404 | // calculate the position of the last slide 1405 | moveBy = slider.viewport.width() - lastChild.outerWidth(); 1406 | } else { 1407 | // get last showing index position 1408 | lastShowingIndex = slider.children.length - slider.settings.minSlides; 1409 | position = slider.children.eq(lastShowingIndex).position(); 1410 | } 1411 | // horizontal carousel, going previous while on first slide (infiniteLoop mode) 1412 | } else if (slider.carousel && slider.active.last && direction === 'prev') { 1413 | // get the last child position 1414 | eq = slider.settings.moveSlides === 1 ? slider.settings.maxSlides - getMoveBy() : ((getPagerQty() - 1) * getMoveBy()) - (slider.children.length - slider.settings.maxSlides); 1415 | lastChild = el.children('.bx-clone').eq(eq); 1416 | position = lastChild.position(); 1417 | // if infinite loop and "Next" is clicked on the last slide 1418 | } else if (direction === 'next' && slider.active.index === 0) { 1419 | // get the last clone position 1420 | position = el.find('> .bx-clone').eq(slider.settings.maxSlides).position(); 1421 | slider.active.last = false; 1422 | // normal non-zero requests 1423 | } else if (slideIndex >= 0) { 1424 | //parseInt is applied to allow floats for slides/page 1425 | requestEl = slideIndex * parseInt(getMoveBy()); 1426 | position = slider.children.eq(requestEl).position(); 1427 | } 1428 | 1429 | /* If the position doesn't exist 1430 | * (e.g. if you destroy the slider on a next click), 1431 | * it doesn't throw an error. 1432 | */ 1433 | if (typeof (position) !== 'undefined') { 1434 | value = slider.settings.mode === 'horizontal' ? -(position.left - moveBy) : -position.top; 1435 | // plugin values to be animated 1436 | setPositionProperty(value, 'slide', slider.settings.speed); 1437 | } else { 1438 | slider.working = false; 1439 | } 1440 | } 1441 | if (slider.settings.ariaHidden) { applyAriaHiddenAttributes(slider.active.index * getMoveBy()); } 1442 | }; 1443 | 1444 | /** 1445 | * Transitions to the next slide in the show 1446 | */ 1447 | el.goToNextSlide = function() { 1448 | // if infiniteLoop is false and last page is showing, disregard call 1449 | if (!slider.settings.infiniteLoop && slider.active.last) { return; } 1450 | var pagerIndex = parseInt(slider.active.index) + 1; 1451 | el.goToSlide(pagerIndex, 'next'); 1452 | }; 1453 | 1454 | /** 1455 | * Transitions to the prev slide in the show 1456 | */ 1457 | el.goToPrevSlide = function() { 1458 | // if infiniteLoop is false and last page is showing, disregard call 1459 | if (!slider.settings.infiniteLoop && slider.active.index === 0) { return; } 1460 | var pagerIndex = parseInt(slider.active.index) - 1; 1461 | el.goToSlide(pagerIndex, 'prev'); 1462 | }; 1463 | 1464 | /** 1465 | * Starts the auto show 1466 | * 1467 | * @param preventControlUpdate (boolean) 1468 | * - if true, auto controls state will not be updated 1469 | */ 1470 | el.startAuto = function(preventControlUpdate) { 1471 | // if an interval already exists, disregard call 1472 | if (slider.interval) { return; } 1473 | // create an interval 1474 | slider.interval = setInterval(function() { 1475 | if (slider.settings.autoDirection === 'next') { 1476 | el.goToNextSlide(); 1477 | } else { 1478 | el.goToPrevSlide(); 1479 | } 1480 | }, slider.settings.pause); 1481 | // if auto controls are displayed and preventControlUpdate is not true 1482 | if (slider.settings.autoControls && preventControlUpdate !== true) { updateAutoControls('stop'); } 1483 | }; 1484 | 1485 | /** 1486 | * Stops the auto show 1487 | * 1488 | * @param preventControlUpdate (boolean) 1489 | * - if true, auto controls state will not be updated 1490 | */ 1491 | el.stopAuto = function(preventControlUpdate) { 1492 | // if no interval exists, disregard call 1493 | if (!slider.interval) { return; } 1494 | // clear the interval 1495 | clearInterval(slider.interval); 1496 | slider.interval = null; 1497 | // if auto controls are displayed and preventControlUpdate is not true 1498 | if (slider.settings.autoControls && preventControlUpdate !== true) { updateAutoControls('start'); } 1499 | }; 1500 | 1501 | /** 1502 | * Returns current slide index (zero-based) 1503 | */ 1504 | el.getCurrentSlide = function() { 1505 | return slider.active.index; 1506 | }; 1507 | 1508 | /** 1509 | * Returns current slide element 1510 | */ 1511 | el.getCurrentSlideElement = function() { 1512 | return slider.children.eq(slider.active.index); 1513 | }; 1514 | 1515 | /** 1516 | * Returns a slide element 1517 | * @param index (int) 1518 | * - The index (zero-based) of the element you want returned. 1519 | */ 1520 | el.getSlideElement = function(index) { 1521 | return slider.children.eq(index); 1522 | }; 1523 | 1524 | /** 1525 | * Returns number of slides in show 1526 | */ 1527 | el.getSlideCount = function() { 1528 | return slider.children.length; 1529 | }; 1530 | 1531 | /** 1532 | * Return slider.working variable 1533 | */ 1534 | el.isWorking = function() { 1535 | return slider.working; 1536 | }; 1537 | 1538 | /** 1539 | * Update all dynamic slider elements 1540 | */ 1541 | el.redrawSlider = function() { 1542 | // resize all children in ratio to new screen size 1543 | slider.children.add(el.find('.bx-clone')).outerWidth(getSlideWidth()); 1544 | // adjust the height 1545 | slider.viewport.css('height', getViewportHeight()); 1546 | // update the slide position 1547 | if (!slider.settings.ticker) { setSlidePosition(); } 1548 | // if active.last was true before the screen resize, we want 1549 | // to keep it last no matter what screen size we end on 1550 | if (slider.active.last) { slider.active.index = getPagerQty() - 1; } 1551 | // if the active index (page) no longer exists due to the resize, simply set the index as last 1552 | if (slider.active.index >= getPagerQty()) { slider.active.last = true; } 1553 | // if a pager is being displayed and a custom pager is not being used, update it 1554 | if (slider.settings.pager && !slider.settings.pagerCustom) { 1555 | populatePager(); 1556 | updatePagerActive(slider.active.index); 1557 | } 1558 | if (slider.settings.ariaHidden) { applyAriaHiddenAttributes(slider.active.index * getMoveBy()); } 1559 | }; 1560 | 1561 | /** 1562 | * Destroy the current instance of the slider (revert everything back to original state) 1563 | */ 1564 | el.destroySlider = function() { 1565 | // don't do anything if slider has already been destroyed 1566 | if (!slider.initialized) { return; } 1567 | slider.initialized = false; 1568 | $('.bx-clone', this).remove(); 1569 | slider.children.each(function() { 1570 | if ($(this).data('origStyle') !== undefined) { 1571 | $(this).attr('style', $(this).data('origStyle')); 1572 | } else { 1573 | $(this).removeAttr('style'); 1574 | } 1575 | }); 1576 | if ($(this).data('origStyle') !== undefined) { 1577 | this.attr('style', $(this).data('origStyle')); 1578 | } else { 1579 | $(this).removeAttr('style'); 1580 | } 1581 | $(this).unwrap().unwrap(); 1582 | if (slider.controls.el) { slider.controls.el.remove(); } 1583 | if (slider.controls.next) { slider.controls.next.remove(); } 1584 | if (slider.controls.prev) { slider.controls.prev.remove(); } 1585 | if (slider.pagerEl && slider.settings.controls && !slider.settings.pagerCustom) { slider.pagerEl.remove(); } 1586 | $('.bx-caption', this).remove(); 1587 | if (slider.controls.autoEl) { slider.controls.autoEl.remove(); } 1588 | clearInterval(slider.interval); 1589 | if (slider.settings.responsive) { $(window).unbind('resize', resizeWindow); } 1590 | if (slider.settings.keyboardEnabled) { $(document).unbind('keydown', keyPress); } 1591 | //remove self reference in data 1592 | $(this).removeData('bxSlider'); 1593 | }; 1594 | 1595 | /** 1596 | * Reload the slider (revert all DOM changes, and re-initialize) 1597 | */ 1598 | el.reloadSlider = function(settings) { 1599 | if (settings !== undefined) { options = settings; } 1600 | el.destroySlider(); 1601 | init(); 1602 | //store reference to self in order to access public functions later 1603 | $(el).data('bxSlider', this); 1604 | }; 1605 | 1606 | init(); 1607 | 1608 | $(el).data('bxSlider', this); 1609 | 1610 | // returns the current jQuery object 1611 | return this; 1612 | }; 1613 | 1614 | })(jQuery); 1615 | --------------------------------------------------------------------------------