1/* 2* MultiSlider | MIT License 3* 4* Copyright (c) 2017 Trevor Blackman 5* http://www.multislider.info 6* 7* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8*/ 9 10(function($){ 11 12 // ==== BEGINS PLUGGIN ==== 13 $.fn.multislider = function(data, callback){ 14 15 // ==== CACHE DOM ==== 16 var $multislider = $(this); 17 var $msContent = $multislider.find('.MS-content'); 18 var $msRight = $multislider.find('button.MS-right'); 19 var $msLeft = $multislider.find('button.MS-left'); 20 var $imgFirst = $msContent.find('.item:first'); 21 22 // === DETERMINE ACTION ==== 23 // string = method | object or nothing is to initialize 24 if(typeof data === 'string'){ 25 getStringArgs(data); 26 return $multislider; 27 } else if (typeof data === 'object' || typeof data ==='undefined'){ 28 init(); 29 }; 30 31 // ==== PLUGGIN VARIABLES ==== 32 var $imgLast, 33 currentMargin, 34 percentageRemaining, 35 totalWidth, 36 numberVisibleSlides, 37 numberTotalSlides, 38 animateDistance, 39 animateSlideRight, 40 animateSlideLeft, 41 defaults, 42 settings, 43 animateDuration, 44 autoSlideInterval; 45 46 // = INITIALIZE = 47 function init(){ 48 minifyContent(); // minify html 49 createSettings(); // merge defaults and user provided options 50 saveData(); // add data object to DOM el with reference to animation functions, allows for methods to reference at any time 51 selectAnimations(); // choose default animation 52 }; 53 54 55 // ==== EVENT HANDLERS ==== 56 $msRight.on('click', animateSlideLeft); 57 $msLeft.on('click', animateSlideRight); 58 $multislider.on('click','.MS-right, .MS-left', resetInterval); 59 $(window).on('resize', findItemWidth); 60 61 62 // ==== FUNCTIONS (for days...) ==== 63 // ================================= 64 65 function pauseAbove(){ 66 if (window.innerWidth > settings.pauseAbove){ $multislider.addClass('ms-PAUSE'); } 67 $(window).on('resize',function(){ 68 if (window.innerWidth > settings.pauseAbove){ 69 $multislider.addClass('ms-PAUSE'); 70 } else { 71 $multislider.removeClass('ms-PAUSE'); 72 } 73 }); 74 } 75 76 function pauseBelow(){ 77 if (window.innerWidth < settings.pauseBelow){ $multislider.addClass('ms-PAUSE'); } 78 $(window).on('resize',function(){ 79 if (window.innerWidth < settings.pauseBelow){ 80 $multislider.addClass('ms-PAUSE'); 81 } else { 82 $multislider.removeClass('ms-PAUSE'); 83 } 84 }); 85 } 86 87 // used if method is called after initialization 88 function getStringArgs(str){ 89 if (typeof $multislider.data(str) !== 'undefined'){ 90 $multislider.data(str)(); 91 } else { 92 console.error("Multislider currently only accepts the following methods: next, prev, pause, play") 93 } 94 } 95 96 // saves data object to DOM element 97 function saveData(){ 98 $multislider.data({ 99 "pause":function(){ $multislider.addClass('ms-PAUSE'); }, 100 "unPause":function(){ $multislider.removeClass('ms-PAUSE'); }, 101 "continuous":function(){ $multislider.removeClass('ms-PAUSE'); continuousLeft(); }, 102 "next":function(){ overRidePause(singleLeft); }, 103 "nextAll":function(){ overRidePause(allLeft); }, 104 "prev":function(){ overRidePause(singleRight); }, 105 "prevAll":function(){ overRidePause(allRight); }, 106 "settings":settings 107 }); 108 } 109 110 // used when calling 'next', 'prev' methods 111 function overRidePause(animation){ 112 if ($multislider.hasClass('ms-PAUSE')){ 113 $multislider.removeClass('ms-PAUSE'); 114 animation(); 115 $multislider.addClass('ms-PAUSE'); 116 } else { 117 animation(); 118 } 119 resetInterval(); 120 } 121 122 // CRITICAL for items to be perfectly side-by-side without floating them 123 function minifyContent(){ 124 $msContent.contents().filter(function(){ 125 return (this.nodeType == 3 && !/\S/.test(this.nodeValue)); 126 }).remove(); 127 } 128 129 // updated options with defaults, measure slide widths for animation calculations, carry out setting implementations 130 function createSettings() { 131 defaults = settings || { 132 continuous: false, // endless scrolling with no pauses 133 slideAll: false, // slide all visible slides, or just one at a time 134 // autoSlide: true, // DEPRECATED 135 interval: 2000, // time bewteen slide animation, 0 or 'false' prevents auto-sliding 136 duration: 500, // duration of slide animation 137 hoverPause: true, // pause slideshow on hover 138 pauseAbove: null, // pause above specified screen width 139 pauseBelow: null // pause below specified screen width 140 } 141 settings = $.extend({},defaults,data); 142 143 findItemWidth(); 144 animateDuration = settings.duration; 145 146 if (settings.hoverPause){pauseHover();}; 147 // autoSlide is being depricated | Feb 2 2017 148 if (settings.continuous !== true && settings.interval !== 0 && settings.interval !== false && settings.autoSlide !== false){autoSlide();} 149 if (settings.pauseAbove !== null && typeof settings.pauseAbove === 'number'){ pauseAbove(); } 150 if (settings.pauseBelow !== null && typeof settings.pauseBelow === 'number'){ pauseBelow(); } 151 } 152 153 // determine between single and multi-slide animations 154 function selectAnimations () { 155 if (settings.continuous){ 156 settings.autoSlide = false;
157 continuousLeft(); 158 } else if (settings.slideAll){ 159 animateSlideRight = $multislider.data('prevAll'); 160 animateSlideLeft = $multislider.data('nextAll'); 161 } else { 162 animateSlideRight = $multislider.data('prev'); 163 animateSlideLeft = $multislider.data('next'); 164 } 165 } 166 167 // measure slide width, for animation calculations 168 function findItemWidth(){ 169 reTargetSlides(); 170 animateDistance = $imgFirst.width(); 171 var left = parseInt($msContent.find('.item:first').css('padding-left')); 172 var right = parseInt($msContent.find('.item:first').css('padding-right')); 173 if (left !== 0){animateDistance += left;} 174 if (right !== 0){animateDistance += right;} 175 } 176 177 // recursive auto-slide loop 178 function autoSlide() { 179 autoSlideInterval = setInterval(function(){ 180 if (!$multislider.hasClass('ms-PAUSE')){ 181 animateSlideLeft(); 182 } 183 }, settings.interval); 184 }; 185 186 function resetInterval() { 187 if (settings.interval !== 0 && settings.interval !== false && settings.continuous !== true){ 188 clearInterval(autoSlideInterval); 189 autoSlide(); 190 } 191 } 192 193 // target first and last visible slides before each new animation 194 function reTargetSlides(){ 195 $imgFirst = $msContent.find('.item:first'); 196 $imgLast = $msContent.find('.item:last'); 197 } 198 199 // prevent animation firing if multislider is currently animating 200 // all animations pass through this function, which emits events, and adds/removes animating class 201 function isItAnimating(callback){ 202 if(!$multislider.hasClass('ms-animating') && 203 !$multislider.hasClass('ms-HOVER') && 204 !$multislider.hasClass('ms-PAUSE')){ 205 $multislider.trigger('ms.before.animate'); // event! 206 $multislider.addClass('ms-animating'); 207 callback(); //callback is animation 208 } 209 } 210 211 // update multislider at the end of each animation 212 function doneAnimating() { 213 if($multislider.hasClass('ms-animating')){ 214 $multislider.removeClass('ms-animating'); 215 $multislider.trigger('ms.after.animate'); // event! 216 } 217 } 218 219 // logic for pausing and restarting the multislider on hover 220 function pauseHover() { 221 // continuous scroll pause slightly different 222 if(settings.continuous){ 223 $msContent.on('mouseover',function(){ 224 doneAnimating(); 225 $msContent.children('.item:first').stop(); 226 }); 227 $msContent.on('mouseout',function(){ 228 continuousLeft(); 229 }); 230 } else { 231 // regular animation pausing 232 $msContent.on('mouseover',function(){ 233 $multislider.addClass('ms-HOVER'); 234 }); 235 $msContent.on('mouseout',function(){ 236 $multislider.removeClass('ms-HOVER'); 237 }); 238 } 239 } 240 241 // calculate remaining animation, if stopped mid-animation and resuming 242 function midAnimateResume(){ 243 animateDuration = settings.duration; 244 var currentMargin = parseFloat($msContent.find('.item:first').css("margin-left")); 245 var percentageRemaining = 1-(currentMargin/-(animateDistance-1)); 246 animateDuration = percentageRemaining*animateDuration; 247 } 248 249 // determine how many slides need to be moved over, if slideAll is true 250 function calcNumSlidesToMove(){ 251 totalWidth = $msContent.width(); // total width of .MS-content containing all visible slides 252 numberVisibleSlides = Math.round(totalWidth/animateDistance); // number of (visible) slides needed to be moved in each animation 253 } 254 255 256 // ==== ANIMATION FUNCTIONS ==== 257 // ============================= 258 function continuousLeft () { 259 isItAnimating(function(){ 260 reTargetSlides(); 261 midAnimateResume(); 262 $imgFirst.animate( 263 {marginLeft: -(animateDistance+1)}, 264 { 265 duration: animateDuration, 266 easing: "linear", 267 complete: function(){ 268 $imgFirst.insertAfter($imgLast).removeAttr("style"); 269 doneAnimating(); 270 continuousLeft (); 271 } 272 } 273 ); 274 }); 275 } 276 277 function allLeft(){ 278 isItAnimating(function(){ 279 reTargetSlides(); 280 calcNumSlidesToMove(); 281 282 var $clonedItemSet = $msContent.children('.item').clone(); 283 var filteredClones = $clonedItemSet.splice(0, numberVisibleSlides); 284 285 $msContent.append(filteredClones); 286 287 $imgFirst.animate( 288 {marginLeft: -totalWidth}, { 289 duration: animateDuration, 290 easing: "swing", 291 complete: function(){ 292 $($msContent.children('.item').splice(0,numberVisibleSlides)).remove(); 293 doneAnimating(); 294 } 295 } 296 ); 297 }); 298 } 299 300 function allRight() { 301 isItAnimating(function(){ 302 reTargetSlides(); 303 calcNumSlidesToMove(); 304 305 var numberTotalSlides = $msContent.children('.item').length; 306 var $clonedItemSet = $msContent.children('.item').clone(); 307 var filteredClones = $clonedItemSet.splice(numberTotalSlides-numberVisibleSlides,numberTotalSlides); 308 309 $($(filteredClones)[0]).css('margin-left',-totalWidth); // give clone array negative margin before preppending
310 $msContent.prepend(filteredClones); 311 312 reTargetSlides(); 313 314 $imgFirst.animate( 315 { 316 marginLeft: 0 317 }, { 318 duration: animateDuration, 319 easing: "swing", 320 complete: function(){ 321 numberTotalSlides = $msContent.find('.item').length; 322 $($msContent.find('.item').splice(numberTotalSlides-numberVisibleSlides,numberTotalSlides)).remove(); 323 $imgFirst.removeAttr('style'); 324 doneAnimating(); 325 } 326 } 327 ); 328 }); 329 } 330 331 function singleLeft(){ 332 isItAnimating(function(){ 333 reTargetSlides(); 334 $imgFirst.animate( 335 { 336 marginLeft: -animateDistance 337 }, { 338 duration: animateDuration, 339 easing: "swing", 340 complete: function(){ 341 $imgFirst.detach().removeAttr('style').appendTo($msContent); 342 doneAnimating(); 343 } 344 } 345 ); 346 }); 347 } 348 349 function singleRight(){ 350 isItAnimating(function(){ 351 reTargetSlides(); 352 $imgLast.css('margin-left',-animateDistance).prependTo($msContent); 353 $imgLast.animate( 354 { 355 marginLeft: 0 356 }, { 357 duration: animateDuration, 358 easing: "swing", 359 complete: function(){ 360 $imgLast.removeAttr("style"); 361 doneAnimating(); 362 } 363 } 364 ); 365 }); 366 } 367 return $multislider; 368 } 369})(jQuery);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.