1/** 2 * simplyScroll 2 - a scroll-tastic jQuery plugin 3 * 4 * http://logicbox.net/jquery/simplyscroll/ 5 * 6 * Copyright (c) 2009-2018 Will Kelly - http://logicbox.net 7 * 8 * @license MIT 9 * 10 */ 11 12(function (factory) { 13 if(typeof module === "object" && typeof module.exports === "object") { 14 module.exports = factory(require("jquery"), window, document); 15 } else { 16 factory(jQuery, window, document); 17 } 18}(function($, window, document, undefined) { 19 20 $.fn.simplyScroll = function(options) { 21 return this.each(function() { 22 // check to see if already attached to element 23 if (typeof $(this).data('simplyScroll') === "undefined") { 24 // access methods and properties like 25 // element.data('simplyScroll').method(arg1, arg2, ...) 26 var simplyScroll = new $.simplyScroll(this, options); 27 $(this).data('simplyScroll', simplyScroll); 28 } 29 }); 30 }; 31 32 var defaults = { 33 customClass: 'simply-scroll', 34 frameRate: 24, //No of movements per second 35 speed: 1, //Intended no. of pixels per frame (/w scroller size & requestAnimationFrame this may not be honoured) 36 orientation: 'horizontal', //'horizontal or 'vertical' - not to be confused with device orientation 37 auto: true, 38 autoMode: 'loop', //if auto == true, use 'loop' or 'bounce', 39 manualMode: 'end', //if auto == false, use 'loop' or 'end' 40 direction: 'forwards', //'forwards' or 'backwards'. 41 pauseOnHover: true, //if autoMode == loop || bounce only 42 pauseOnTouch: true, //" touch device only 43 pauseButton: false, //" generates an extra element to allow manual pausing 44 startOnLoad: false, //use this to delay starting of plugin until all page assets have loaded 45 initialOffset: 0 46 }; 47 48 $.simplyScroll = function(el,options) { 49 50 var self = this; 51 52 this.o = $.extend({}, defaults, options || {}); 53 this.isAuto = this.o.auto !== false && this.o.autoMode.match(/^loop|bounce$/) !== null; 54 this.isHorizontal = 55 this.o.orientation.match(/^horizontal|vertical$/) !== null && this.o.orientation === defaults.orientation; 56 this.isRTL = this.isHorizontal && $("html").attr('dir') === 'rtl'; 57 this.isForwards = !this.isAuto && !this.isRTL || 58 (this.isAuto && this.o.direction.match(/^forwards|backwards$/) !== null && this.o.direction === defaults.direction); 59 this.isLoop = this.isAuto && this.o.autoMode === 'loop' || !this.isAuto && this.o.manualMode === 'loop'; 60 61 this.supportsTouch = ('createTouch' in document); 62 63 this.events = this.supportsTouch ? 64 {start:'touchstart MozTouchDown',move:'touchmove MozTouchMove',end:'touchend touchcancel MozTouchRelease'} : 65 {start:'mouseenter',end:'mouseleave'}; 66 67 this.$list = $(el); //called on ul/ol/div etc 68 var $items = this.$list.children(); 69 70 //generate extra markup 71 this.$list.addClass('simply-scroll-list') 72 .wrap('<div class="simply-scroll-clip"></div>') 73 .parent().wrap('<div class="' + this.o.customClass + ' simply-scroll-container"></div>'); 74 75 if (!this.isAuto) { //button placeholders 76 this.$list.parent().parent() 77 .prepend('<div class="simply-scroll-forward"></div>') 78 .prepend('<div class="simply-scroll-back"></div>'); 79 } else { 80 if (this.o.pauseButton) { 81 this.$list.parent().parent() 82 .prepend('<div class="simply-scroll-btn simply-scroll-btn-pause"></div>'); 83 this.o.pauseOnHover = false; 84 } 85 } 86 87 //wrap an extra div around the whole lot if elements scrolled aren't equal 88 if ($items.length > 1) { 89 var extra_wrap = false, 90 total = 0; 91 92 if (this.isHorizontal) { 93 $items.each(function() { total+=$(this).outerWidth(true); }); 94 extra_wrap = $items.eq(0).outerWidth(true) * $items.length !== total; 95 } else { 96 $items.each(function() { total+=$(this).outerHeight(true); }); 97 extra_wrap = $items.eq(0).outerHeight(true) * $items.length !== total; 98 } 99 100 if (extra_wrap) { 101 this.$list = this.$list.wrap('<div></div>').parent().addClass('simply-scroll-list'); 102 if (this.isHorizontal) { 103 this.$list.children().css({"float":'left',width: total + 1 + 'px'}); 104 } else { 105 this.$list.children().css({height: total + 'px'}); 106 } 107 } 108 } 109 110 if (!this.o.startOnLoad) { 111 this.init(); 112 } else { 113 //wait for load before completing setup 114 $(window).load(function() { self.init(); }); 115 } 116 117 }; 118
119 $.simplyScroll.fn = $.simplyScroll.prototype = {}; 120 121 $.simplyScroll.fn.extend = $.extend; 122 123 $.simplyScroll.fn.extend({ 124 init: function() { 125 var self = this; 126 127 this.$items = this.$list.children(); 128 this.$clip = this.$list.parent(); //this is the element that scrolls 129 this.$container = this.$clip.parent(); 130 this.$btnBack = $('.simply-scroll-back',this.$container); 131 this.$btnForward = $('.simply-scroll-forward',this.$container); 132 133 if (!this.isHorizontal) { 134 this.itemMax = this.$items.eq(0).outerHeight(true); 135 this.clipMax = this.$clip.height(); 136 this.dimension = 'height'; 137 this.moveBackClass = 'simply-scroll-btn-up'; 138 this.moveForwardClass = 'simply-scroll-btn-down'; 139 this.scrollPos = 'Top'; 140 } else { 141 this.itemMax = this.$items.eq(0).outerWidth(true); 142 this.clipMax = this.$clip.width(); 143 this.dimension = 'width'; 144 this.moveBackClass = 'simply-scroll-btn-left'; 145 this.moveForwardClass = 'simply-scroll-btn-right'; 146 this.scrollPos = 'Left'; 147 } 148 149 this.posMin = 0; 150 151 this.posMax = this.$items.length * this.itemMax; 152 153 var addItems = Math.ceil(this.clipMax / this.itemMax); 154 155 //auto scroll loop & manual scroll bounce or end(to-end) 156 if (this.isAuto && this.o.autoMode === 'loop') { 157 158 this.$list.css(this.dimension,this.posMax+(this.itemMax*addItems) +'px'); 159 160 this.posMax += (this.clipMax - this.o.speed); 161 162 if (this.isForwards) { 163 this.$items.slice(0,addItems).clone(true).appendTo(this.$list); 164 this.resetPosition = 0; 165 166 } else { 167 this.$items.slice(-addItems).clone(true).prependTo(this.$list); 168 this.resetPosition = this.$items.length * this.itemMax; 169 //due to inconsistent RTL implementation force back to LTR then fake 170 if (this.isRTL) { 171 this.$clip[0].dir = 'ltr'; 172 //based on feedback seems a good idea to force float right 173 this.$items.css('float','right'); 174 } 175 } 176 177 //manual and loop 178 } else if (!this.isAuto && this.o.manualMode === 'loop') { 179 180 this.posMax += this.itemMax * addItems; 181 182 this.$list.css(this.dimension,this.posMax+(this.itemMax*addItems) +'px'); 183 184 this.posMax += (this.clipMax - this.o.speed); 185 186 this.$items.slice(0,addItems).clone(true).appendTo(this.$list); 187 this.$items.slice(-addItems).clone(true).prependTo(this.$list); 188 189 this.resetPositionForwards = this.resetPosition = addItems * this.itemMax; 190 this.resetPositionBackwards = this.$items.length * this.itemMax; 191 192 //extra events to force scroll direction change 193 this.$btnBack.bind(this.events.start, function() { 194 self.isForwards = false; 195 self.resetPosition = self.resetPositionBackwards; 196 }); 197 198 this.$btnForward.bind(this.events.start, function() { 199 self.isForwards = true; 200 self.resetPosition = self.resetPositionForwards; 201 }); 202 203 } else { //(!this.isAuto && this.o.manualMode=='end') 204 205 this.$list.css(this.dimension,this.posMax +'px'); 206 207 if (this.isForwards) { 208 this.resetPosition = 0; 209 210 } else { 211 this.resetPosition = this.$items.length * this.itemMax; 212 //due to inconsistent RTL implementation force back to LTR then fake 213 if (this.isRTL) { 214 this.$clip[0].dir = 'ltr'; 215 //based on feedback seems a good idea to force float right 216 this.$items.css('float','right'); 217 } 218 } 219 } 220 221 this.resetPos(this.o.initialOffset); //ensure scroll position is reset 222 223 this.timestamp = null; 224 this.interval = null; 225 226 if (!(!this.isAuto && this.o.manualMode === 'end')) { //loop mode 227 //ensure that speed is divisible by item width. Helps to always make images even not odd widths! 228 while (this.itemMax % this.o.speed !== 0) { 229 this.o.speed--; 230 if (this.o.speed===0) { 231 this.o.speed=1; break; 232 } 233 } 234 } 235 236 this.trigger = null; 237 238 this.funcMoveBack = function(e) { 239 if (e !== undefined) { 240 e.preventDefault(); 241 } 242 self.trigger = !self.isAuto && self.o.manualMode === 'end' ? this : null; 243 if (self.isAuto) { 244 self.isForwards ? self.moveBack() : self.moveForward(); 245 } else { 246 self.moveBack(); 247 } 248 }; 249 250 this.funcMoveForward = function(e) { 251 if (e !== undefined) { 252 e.preventDefault(); 253 } 254 self.trigger = !self.isAuto && self.o.manualMode === 'end' ? this : null; 255 if (self.isAuto) { 256 self.isForwards ? self.moveForward() : self.moveBack(); 257 } else { 258 self.moveForward(); 259 } 260 }; 261 262 this.funcMovePause = function() { self.movePause(); }; 263 this.funcMoveStop = function() { self.moveStop(); }; 264 this.funcMoveResume = function() { self.moveResume(); }; 265 266 if (this.isAuto) { 267 268 this.paused = false;
269 270 function togglePause() { 271 if (self.paused===false) { 272 self.paused=true; 273 self.funcMovePause(); 274 } else { 275 self.paused=false; 276 self.funcMoveResume(); 277 } 278 return self.paused; 279 } 280 281 //disable pauseTouch when links are present 282 if (this.supportsTouch && this.$items.find('a').length) { 283 this.supportsTouch=false; 284 } 285 286 if (this.isAuto && this.o.pauseOnHover && !this.supportsTouch) { 287 this.$clip 288 .bind(this.events.start, this.funcMovePause) 289 .bind(this.events.end, this.funcMoveResume); 290 } else if (this.isAuto && this.o.pauseOnTouch && !this.o.pauseButton && this.supportsTouch) { 291 292 var touchStartPos, scrollStartPos; 293 294 this.$clip.bind(this.events.start, function(e) { 295 togglePause(); 296 var touch = e.originalEvent.touches[0]; 297 touchStartPos = self.isHorizontal ? touch.pageX : touch.pageY; 298 scrollStartPos = self.$clip[0]['scroll' + self.scrollPos]; 299 e.stopPropagation(); 300 e.preventDefault(); 301 302 }).bind(this.events.move,function(e) { 303 304 e.stopPropagation(); 305 e.preventDefault(); 306 307 var touch = e.originalEvent.touches[0], 308 endTouchPos = self.isHorizontal ? touch.pageX : touch.pageY, 309 pos = (touchStartPos - endTouchPos) + scrollStartPos; 310 311 if (pos < 0) pos = 0; 312 else if (pos > self.posMax) pos = self.posMax; 313 314 self.$clip[0]['scroll' + self.scrollPos] = pos; 315 316 //force pause 317 self.funcMovePause(); 318 self.paused = true; 319 }); 320 } else { 321 if (this.o.pauseButton) { 322 323 this.$btnPause = $(".simply-scroll-btn-pause",this.$container) 324 .bind('click', function(e) { 325 e.preventDefault(); 326 togglePause() ? $(this).addClass('active') : $(this).removeClass('active'); 327 }); 328 } 329 } 330 this.funcMoveForward(); 331 } else { 332 333 this.$btnBack 334 .addClass('simply-scroll-btn' + ' ' + this.moveBackClass) 335 .bind(this.events.start, this.funcMoveBack) 336 .bind(this.events.end, this.funcMoveStop); 337 this.$btnForward 338 .addClass('simply-scroll-btn' + ' ' + this.moveForwardClass) 339 .bind(this.events.start,this.funcMoveForward) 340 .bind(this.events.end, this.funcMoveStop); 341 342 if (this.o.manualMode === 'end') { 343 !this.isRTL ? this.$btnBack.addClass('disabled') : this.$btnForward.addClass('disabled'); 344 } 345 } 346 }, 347 348 moveForward: function() { 349 var self = this; 350 this.movement = 'forward'; 351 if (this.trigger !== null) { 352 this.$btnBack.removeClass('disabled'); 353 } 354 var frame = function(timestamp) { 355 if (self.$clip[0]['scroll' + self.scrollPos] < (self.posMax-self.clipMax)) { 356 var delta = (timestamp - (self.timestamp || timestamp)) * self.o.speed/self.o.frameRate; 357 self.$clip[0]['scroll' + self.scrollPos] += Math.ceil(delta); //scroll pos. needs to be an int 358 } else if (self.isLoop) { 359 self.resetPos(); 360 } else { 361 self.moveStop(self.movement); 362 } 363 self.timestamp = timestamp; 364 self.interval = requestAnimationFrame(frame); 365 }; 366 requestAnimationFrame(frame); 367 }, 368 369 moveBack: function() { 370 var self = this; 371 this.movement = 'back'; 372 if (this.trigger !== null) { 373 this.$btnForward.removeClass('disabled'); 374 } 375 var frame = function(timestamp) { 376 if (self.$clip[0]['scroll' + self.scrollPos] > self.posMin) { 377 var delta = (timestamp - (self.timestamp || timestamp)) * self.o.speed/self.o.frameRate; 378 self.$clip[0]['scroll' + self.scrollPos] -= Math.ceil(delta); 379 } else if (self.isLoop) { 380 self.resetPos(); 381 } else { 382 self.moveStop(self.movement); 383 } 384 self.timestamp = timestamp; 385 self.interval = requestAnimationFrame(frame); 386 }; 387 requestAnimationFrame(frame); 388 }, 389 390 movePause: function() { 391 cancelAnimationFrame(this.interval); 392 this.timestamp = null; 393 }, 394 395 moveStop: function(moveDir) { 396 this.movePause(); 397 this.timestamp = null; 398 if (this.trigger!==null) { 399 if (typeof moveDir !== 'undefined') { 400 $(this.trigger).addClass('disabled'); 401 } 402 this.trigger = null; 403 } 404 if (this.isAuto) { 405 if (this.o.autoMode === 'bounce') { 406 moveDir === 'forward' ? this.moveBack() : this.moveForward(); 407 } 408 } 409 }, 410 411 moveResume: function() { 412 this.movement === 'forward' ? this.moveForward() : this.moveBack(); 413 }, 414 415 resetPos: function(resetPos) { 416 this.$clip[0]['scroll' + this.scrollPos] = resetPos ? resetPos : this.resetPosition; 417 } 418 }); 419 420}));
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.