1/*! Copyright (c) 2011 Piotr Rochala (http://rocha.la) 2 * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) 3 * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses. 4 * 5 * Version: 1.3.6 6 * 7 */ 8(function($) { 9 10 $.fn.extend({ 11 slimScroll: function(options) { 12 13 var defaults = { 14 15 // width in pixels of the visible scroll area 16 width : 'auto', 17 18 // height in pixels of the visible scroll area 19 height : '250px', 20 21 // width in pixels of the scrollbar and rail 22 size : '7px', 23 24 // scrollbar color, accepts any hex/color value 25 color: '#000', 26 27 // scrollbar position - left/right 28 position : 'right', 29 30 // distance in pixels between the side edge and the scrollbar 31 distance : '1px', 32 33 // default scroll position on load - top / bottom / $('selector') 34 start : 'top', 35 36 // sets scrollbar opacity 37 opacity : .4, 38 39 // enables always-on mode for the scrollbar 40 alwaysVisible : false, 41 42 // check if we should hide the scrollbar when user is hovering over 43 disableFadeOut : false, 44 45 // sets visibility of the rail 46 railVisible : false, 47 48 // sets rail color 49 railColor : '#333', 50 51 // sets rail opacity 52 railOpacity : .2, 53 54 // whether we should use jQuery UI Draggable to enable bar dragging 55 railDraggable : true, 56 57 // defautlt CSS class of the slimscroll rail 58 railClass : 'slimScrollRail', 59 60 // defautlt CSS class of the slimscroll bar 61 barClass : 'slimScrollBar', 62 63 // defautlt CSS class of the slimscroll wrapper 64 wrapperClass : 'slimScrollDiv', 65 66 // check if mousewheel should scroll the window if we reach top/bottom 67 allowPageScroll : false, 68 69 // scroll amount applied to each mouse wheel step 70 wheelStep : 20, 71 72 // scroll amount applied when user is using gestures 73 touchScrollStep : 200, 74 75 // sets border radius 76 borderRadius: '7px', 77 78 // sets border radius of the rail 79 railBorderRadius : '7px' 80 }; 81 82 var o = $.extend(defaults, options); 83 84 // do it for every element that matches selector 85 this.each(function(){ 86 87 var isOverPanel, isOverBar, isDragg, queueHide, touchDif, 88 barHeight, percentScroll, lastScroll, 89 divS = '<div></div>', 90 minBarHeight = 30, 91 releaseScroll = false; 92 93 // used in event handlers and for better minification 94 var me = $(this); 95 96 // ensure we are not binding it again 97 if (me.parent().hasClass(o.wrapperClass)) 98 { 99 // start from last bar position 100 var offset = me.scrollTop(); 101 102 // find bar and rail 103 bar = me.closest('.' + o.barClass); 104 rail = me.closest('.' + o.railClass); 105 106 getBarHeight(); 107 108 // check if we should scroll existing instance 109 if ($.isPlainObject(options)) 110 { 111 // Pass height: auto to an existing slimscroll object to force a resize after contents have changed 112 if ( 'height' in options && options.height == 'auto' ) { 113 me.parent().css('height', 'auto'); 114 me.css('height', 'auto'); 115 var height = me.parent().parent().height(); 116 me.parent().css('height', height); 117 me.css('height', height); 118 } 119 120 if ('scrollTo' in options) 121 { 122 // jump to a static point 123 offset = parseInt(o.scrollTo); 124 } 125 else if ('scrollBy' in options) 126 { 127 // jump by value pixels 128 offset += parseInt(o.scrollBy); 129 } 130 else if ('destroy' in options) 131 { 132 // remove slimscroll elements 133 bar.remove(); 134 rail.remove(); 135 me.unwrap(); 136 return; 137 } 138 139 // scroll content by the given offset 140 scrollContent(offset, false, true); 141 } 142 143 return; 144 } 145 else if ($.isPlainObject(options)) 146 { 147 if ('destroy' in options) 148 { 149 return; 150 } 151 } 152 153 // optionally set height to the parent's height 154 o.height = (o.height == 'auto') ? me.parent().height() : o.height; 155 156 // wrap content 157 var wrapper = $(divS) 158 .addClass(o.wrapperClass) 159 .css({ 160 position: 'relative', 161 overflow: 'hidden', 162 width: o.width, 163 height: o.height 164 }); 165 166 // update style for the div 167 me.css({ 168 overflow: 'hidden', 169 width: o.width, 170 height: o.height 171 }); 172 173 // create scrollbar rail 174 var rail = $(divS) 175 .addClass(o.railClass) 176 .css({ 177 width: o.size, 178 height: '100%', 179 position: 'absolute', 180 top: 0, 181 display: (o.alwaysVisible && o.railVisible) ? 'block' : 'none', 182 'border-radius': o.railBorderRadius, 183 background: o.railColor, 184 opacity: o.railOpacity, 185 zIndex: 90 186 }); 187 188 // create scrollbar 189 var bar = $(divS) 190 .addClass(o.barClass) 191 .css({ 192 background: o.color, 193 width: o.size, 194 position: 'absolute', 195 top: 0, 196 opacity: o.opacity, 197 display: o.alwaysVisible ? 'block' : 'none', 198 'border-radius' : o.borderRadius, 199 BorderRadius: o.borderRadius, 200 MozBorderRadius: o.borderRadius, 201 WebkitBorderRadius: o.borderRadius, 202 zIndex: 99 203 }); 204 205 // set position
206 var posCss = (o.position == 'right') ? { right: o.distance } : { left: o.distance }; 207 rail.css(posCss); 208 bar.css(posCss); 209 210 // wrap it 211 me.wrap(wrapper); 212 213 // append to parent div 214 me.parent().append(bar); 215 me.parent().append(rail); 216 217 // make it draggable and no longer dependent on the jqueryUI 218 if (o.railDraggable){ 219 bar.bind("mousedown", function(e) { 220 var $doc = $(document); 221 isDragg = true; 222 t = parseFloat(bar.css('top')); 223 pageY = e.pageY; 224 225 $doc.bind("mousemove.slimscroll", function(e){ 226 currTop = t + e.pageY - pageY; 227 bar.css('top', currTop); 228 scrollContent(0, bar.position().top, false);// scroll content 229 }); 230 231 $doc.bind("mouseup.slimscroll", function(e) { 232 isDragg = false;hideBar(); 233 $doc.unbind('.slimscroll'); 234 }); 235 return false; 236 }).bind("selectstart.slimscroll", function(e){ 237 e.stopPropagation(); 238 e.preventDefault(); 239 return false; 240 }); 241 } 242 243 // on rail over 244 rail.hover(function(){ 245 showBar(); 246 }, function(){ 247 hideBar(); 248 }); 249 250 // on bar over 251 bar.hover(function(){ 252 isOverBar = true; 253 }, function(){ 254 isOverBar = false; 255 }); 256 257 // show on parent mouseover 258 me.hover(function(){ 259 isOverPanel = true; 260 showBar(); 261 hideBar(); 262 }, function(){ 263 isOverPanel = false; 264 hideBar(); 265 }); 266 267 // support for mobile 268 me.bind('touchstart', function(e,b){ 269 if (e.originalEvent.touches.length) 270 { 271 // record where touch started 272 touchDif = e.originalEvent.touches[0].pageY; 273 } 274 }); 275 276 me.bind('touchmove', function(e){ 277 // prevent scrolling the page if necessary 278 if(!releaseScroll) 279 { 280 e.originalEvent.preventDefault(); 281 } 282 if (e.originalEvent.touches.length) 283 { 284 // see how far user swiped 285 var diff = (touchDif - e.originalEvent.touches[0].pageY) / o.touchScrollStep; 286 // scroll content 287 scrollContent(diff, true); 288 touchDif = e.originalEvent.touches[0].pageY; 289 } 290 }); 291 292 // set up initial height 293 getBarHeight(); 294 295 // check start position 296 if (o.start === 'bottom') 297 { 298 // scroll content to bottom 299 bar.css({ top: me.outerHeight() - bar.outerHeight() }); 300 scrollContent(0, true); 301 } 302 else if (o.start !== 'top') 303 { 304 // assume jQuery selector 305 scrollContent($(o.start).position().top, null, true); 306 307 // make sure bar stays hidden 308 if (!o.alwaysVisible) { bar.hide(); } 309 } 310 311 // attach scroll events 312 attachWheel(this); 313 314 function _onWheel(e) 315 { 316 // use mouse wheel only when mouse is over 317 if (!isOverPanel) { return; } 318 319 var e = e || window.event; 320 321 var delta = 0; 322 if (e.wheelDelta) { delta = -e.wheelDelta/120; } 323 if (e.detail) { delta = e.detail / 3; } 324 325 var target = e.target || e.srcTarget || e.srcElement; 326 if ($(target).closest('.' + o.wrapperClass).is(me.parent())) { 327 // scroll content 328 scrollContent(delta, true); 329 } 330 331 // stop window scroll 332 if (e.preventDefault && !releaseScroll) { e.preventDefault(); } 333 if (!releaseScroll) { e.returnValue = false; } 334 } 335 336 function scrollContent(y, isWheel, isJump) 337 { 338 releaseScroll = false; 339 var delta = y; 340 var maxTop = me.outerHeight() - bar.outerHeight(); 341 342 if (isWheel) 343 { 344 // move bar with mouse wheel 345 delta = parseInt(bar.css('top')) + y * parseInt(o.wheelStep) / 100 * bar.outerHeight(); 346 347 // move bar, make sure it doesn't go out 348 delta = Math.min(Math.max(delta, 0), maxTop); 349 350 // if scrolling down, make sure a fractional change to the 351 // scroll position isn't rounded away when the scrollbar's CSS is set 352 // this flooring of delta would happened automatically when 353 // bar.css is set below, but we floor here for clarity 354 delta = (y > 0) ? Math.ceil(delta) : Math.floor(delta); 355 356 // scroll the scrollbar 357 bar.css({ top: delta + 'px' }); 358 } 359 360 // calculate actual scroll amount 361 percentScroll = parseInt(bar.css('top')) / (me.outerHeight() - bar.outerHeight()); 362 delta = percentScroll * (me[0].scrollHeight - me.outerHeight()); 363 364 if (isJump) 365 { 366 delta = y; 367 var offsetTop = delta / me[0].scrollHeight * me.outerHeight(); 368 offsetTop = Math.min(Math.max(offsetTop, 0), maxTop); 369 bar.css({ top: offsetTop + 'px' }); 370 } 371 372 // scroll content 373 me.scrollTop(delta); 374 375 // fire scrolling event 376 me.trigger('slimscrolling', ~~delta); 377 378 // ensure bar is visible 379 showBar(); 380 381 // trigger hide when scroll is stopped 382 hideBar(); 383 } 384 385 function attachWheel(target) 386 { 387 if (window.addEventListener) 388 { 389 target.addEventListener('DOMMouseScroll', _onWheel, false ); 390 target.addEventListener('mousewheel', _onWheel, false ); 391 } 392 else 393 { 394 document.attachEvent("onmousewheel", _onWheel) 395 } 396 } 397 398 function getBarHeight() 399 { 400 // calculate scrollbar height and make sure it is not too small 401 barHeight = Math.max((me.outerHeight() / me[0].scrollHeight) * me.outerHeight(), minBarHeight); 402 bar.css({ height: barHeight + 'px' }); 403 404 // hide scrollbar if content is not long enough 405 var display = barHeight == me.outerHeight() ? 'none' : 'block'; 406 bar.css({ display: display }); 407 } 408 409 function showBar() 410 { 411 // recalculate bar height 412 getBarHeight(); 413 clearTimeout(queueHide); 414 415 // when bar reached top or bottom 416 if (percentScroll == ~~percentScroll) 417 { 418 //release wheel 419 releaseScroll = o.allowPageScroll; 420 421 // publish approporiate event 422 if (lastScroll != percentScroll) 423 { 424 var msg = (~~percentScroll == 0) ? 'top' : 'bottom'; 425 me.trigger('slimscroll', msg); 426 } 427 } 428 else 429 { 430 releaseScroll = false;
431 } 432 lastScroll = percentScroll; 433 434 // show only when required 435 if(barHeight >= me.outerHeight()) { 436 //allow window scroll 437 releaseScroll = true; 438 return; 439 } 440 bar.stop(true,true).fadeIn('fast'); 441 if (o.railVisible) { rail.stop(true,true).fadeIn('fast'); } 442 } 443 444 function hideBar() 445 { 446 // only hide when options allow it 447 if (!o.alwaysVisible) 448 { 449 queueHide = setTimeout(function(){ 450 if (!(o.disableFadeOut && isOverPanel) && !isOverBar && !isDragg) 451 { 452 bar.fadeOut('slow'); 453 rail.fadeOut('slow'); 454 } 455 }, 1000); 456 } 457 } 458 459 }); 460 461 // maintain chainability 462 return this; 463 } 464 }); 465 466 $.fn.extend({ 467 slimscroll: $.fn.slimScroll 468 }); 469 470})(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.