LivePipe has been deprecated and is no longer maintained.
The author now works primarily on Thorax

Control.ScrollBar

Pure JavaScript/CSS scroll bars for Prototype.

Introduction

Why emulate a native UI component? Primarily, the inconsistent cross browser behavior of native scrollbars. Firefox for instance considers scrollbars to be entirely outside the layout of a document. If a Draggable element goes over a native scrollbar in this case, the mouse has left the page, disrupting the drag operation. Rewriting the scrollbar in the DOM solves this problem. Fringe benefits include granular control over the behavior and style as well as richer API.

This scrollbar implementation includes mouse wheel support, a proportionally drawn handle, and can accommodate dynamic content and layout changes with the recalculateLayout() method.

Use the Mouse Wheel or Handle to Scroll

Nulla facilisi. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Fusce consectetuer. Phasellus molestie, sem vel laoreet pretium, arcu arcu rutrum eros, ac mattis felis ante at orci. Vivamus vel mauris. Ut porttitor, nunc eu tincidunt gravida, orci odio luctus mi, id venenatis dui nunc sit amet turpis. Mauris urna nisl, feugiat a, ultrices id, ultrices et, est. Nam eu felis non tortor luctus congue. Mauris consequat malesuada augue. Donec eu nibh in libero tempor aliquet. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Pellentesque sapien erat, imperdiet tincidunt, vestibulum eget, fringilla vel, odio. Ut risus. Ut pretium neque ac velit. Vivamus diam. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. In hac habitasse platea dictumst. Nunc luctus fringilla mi. Nunc ultrices nisi ac urna.

Convallis Felis ac Massa Accumsan

Phasellus faucibus adipiscing quam. Maecenas gravida, diam sit amet mollis accumsan, risus diam ornare leo, non sollicitudin lorem mi vitae ante. In at mi. In vestibulum nunc eleifend justo. Nullam semper. Nulla venenatis ornare ipsum. Phasellus pharetra. Suspendisse molestie. Fusce porta vulputate quam. Etiam vitae tortor. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Maecenas vulputate magna nec diam. Aliquam sagittis lectus a pede. Sed fermentum, risus non sollicitudin posuere, erat arcu iaculis nibh, eu faucibus sapien velit dapibus ipsum. Proin fringilla sapien sed dui.

Eleifend Justo Nullam Semper

Cras eros tellus, posuere at, condimentum eget, fringilla nec, lectus. Mauris ut enim. Quisque imperdiet rutrum elit. Curabitur in nunc. Sed pretium. Aliquam convallis. Proin venenatis. Proin sed magna. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nunc tincidunt. Nam vitae leo at urna dictum venenatis.

Cras iaculis. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Ut nisl. Duis quis enim at justo euismod accumsan. Duis mollis. Curabitur sed ante. Morbi bibendum iaculis ligula. Suspendisse aliquet est. Sed velit orci, sagittis non, posuere vitae, aliquet in, massa. Vestibulum egestas.

Insert Paragraph and recalculateLayout()

HTML

Control.ScrollBar requires a very particular HTML structure. There must be a positioned outer container, with the track and scrollable container as direct children. The track must contain a single div (with any id or class name). You do not reference the outer container or handle when calling initialize(), only the scrollable content, and the track. The scrollable content must have it's overflow property set to hidden.


		<div id="scrollbar_container">
			<div id="scrollbar_track"><div id="scrollbar_handle"></div></div>
			<div id="scrollbar_content">...</div>
		</div>
	

JavaScript


	var scrollbar = new Control.ScrollBar('scrollbar_content','scrollbar_track');
	
	$('scroll_down_50').observe('click',function(event){
		scrollbar.scrollBy(-50);
		event.stop();
	});
	
	$('scroll_up_50').observe('click',function(event){
		scrollbar.scrollBy(50);
		event.stop();
	});
	
	$('scroll_top').observe('click',function(event){
		scrollbar.scrollTo('top');
		event.stop();
	});
	
	$('scroll_bottom').observe('click',function(event){
		//to animate a scroll operation you can pass true
		//or a callback that will be called when scrolling is complete
		scrollbar.scrollTo('bottom',function(){
			if(typeof(console) != "undefined")
				console.log('Finished scrolling to bottom.');
		});
		event.stop();
	});
	
	$('scroll_second').observe('click',function(event){
		//you can pass a number or element to scroll to
		//if you pass an element, it will be centered, unless it is
		//near the bottom of the container
		scrollbar.scrollTo($('second_subhead'));
		event.stop();
	});
	
	$('scroll_third').observe('click',function(event){
		//passing true will animate the scroll
		scrollbar.scrollTo($('third_subhead'),true);
		event.stop();
	});
	
	$('scroll_insert').observe('click',function(event){
		$('scrollbar_content').insert('<p>Inserted: ' + $('repeat').innerHTML + '</p>');
		//you only need to call this if ajax or dom operations modify the layout
		//this is automatically called when the window resizes
		scrollbar.recalculateLayout();
		event.stop();
	});

CSS


#scrollbar_container {
	position:relative;
	width:500px;
}

#scrollbar_track {
	position:absolute;
	top:0;
	right:0;
	height:100%;
	width:10px;
	background-color:transparent;
	cursor:move;
}

#scrollbar_handle {
	width:10px;
	background-color:#5c92e7;
	cursor:move;
	-moz-border-radius: 5px;
	-webkit-border-radius: 5px;
	opacity:0.9;
    -moz-opacity:0.9;
}

#scrollbar_content {
	overflow:hidden;
	width:485px;
	height:250px;
}

Instance

ReturnNameDescription
Control.ScrollBarinitialize(Element container, Element track [,Hash options])Automatically calls recalculateLayout(). The handle will be obtained via track.firstDescendant()
nulldestroy()
nulldisable()
nullenable()
nullrecalculateLayout()Call this if the page layout changes from dynamic content. Recalculates track length, handle length and wether or not the scrollbar should be hidden or visible.
nullreset()
nullscrollBy(number y)y can be a positive or negative integer.
nullscrollTo(mixed y [,mixed animate])y can be an Element, a number (offsetTop), or the string 'top' or 'bottom'. animate (smooth scrolling) can be a boolean, or can be a callback to execute when the scroll is complete. If a callback is passed the it is always called, even if scrolling is not necessary.
Elementcontainer
Elementhandle
Elementtrack

Options

TypeNameDefaultDescription
stringactive_class_name'scrolling'
Elementapply_active_class_name_tothis.container
numberhandle_minimum_height25If proportional is true, this is the minimum height in pixels.
numbernotification_timeout_length125Milliseconds between change() events when scrolling.
boolproportionaltrueDraw the handle proportional to (container height / length of track).
numberscroll_to_smoothing0.01
numberscroll_to_steps15
Hashslider_options{}Will be passed to Control.Slider

Events

NameDescription
change(number delta)Forwarded from slider.onSlide and slider.onChange, but will fire at a maximum interval of options.notification_timeout_length for performance.
disabled()
enabled()