
var Slider = Class.create( {
tlog: TMDebug.gen_tlog( 'slider' ),
initialize: function( options ) {
false;
false;
this.options = Object.extend( {
axis: 'horizontal',
snap_to: false,
handle_space: 0,
can_cross: false,
overlap: false,
track: {}
}, options );
this.slider = $(this.options.slider);
this.handles = [];
if ( this.options.track.style ) {
this.track = new Element( 'div', { 'class': this.options.track.style } );
this.track.style.overflow = "hidden";
if ( this.options.track.color ) {
this.inner_track = new Element( 'div', { 'class': this.options.track.color } );
this.inner_track.style.position = 'absolute';
this.inner_track.style.left = '0px';
this.inner_track.style.top = '0px';
this.track.appendChild( this.inner_track );
}
this.slider.appendChild( this.track );
}
if ( !this.options.track.offset ) {
this.options.track.offset = [ 0, 0, 0, 0 ];
}
this.num_handles = this.options.num_handles;
if ( this.options.range ) {
this.num_points = this.options.range[1] - this.options.range[0];
}
this.dragging = false;
this.base_z = this.options.zIndex || 100;
this.max_z = this.base_z + 1;
this.make_handles();
this.setup_track_info();
this.render();
},
setup_track_info: function() {
this.slider_offset = Element.cumulativeOffset( this.slider );
this.slider_offset[0] += this.options.track.offset[0];
this.slider_offset[1] += this.options.track.offset[1];
this.slider_size = Element.getDimensions( this.slider );
this.slider_size.width += this.options.track.offset[2];
this.slider_size.height += this.options.track.offset[3];
this.real_width = this.slider_size.width - this.handle_width;
if ( this.track ) {
this.track_width = this.calc_indexed_position( this.num_points ) - this.calc_indexed_position( 0 );
this.track.style.width = this.track_width + "px";
if ( this.inner_track ) {
this.inner_track.style.width = this.track_width + "px";
this.inner_track.style.height = Element.getHeight( this.track ) + "px";
}
}
},
make_handles: function() {
false;
for( var i = 0 ; i < this.num_handles ; i ++ ) {
false;
var handle_element = new Element('div');
handle_element.className = this.options.handle;
this.slider.appendChild( handle_element );
this.handle_width = Element.getWidth( handle_element );
this.handle_offset = this.handle_width / 2;
this.handles.push ( {
element: handle_element
} );
}
},
get_handle_index: function( element ) {
for ( var i = 0 ; i < this.handles.length ; i ++ )
if ( element == this.handles[i].element )
return i;
return -1;
},
end_drag: function(event) {
false;
Event.stopObserving(document.body, "mousemove", this.eventMouseMove);
Event.stopObserving(document.body, "mouseup", this.eventMouseUp);
this.dragging = false;
this.draw_track();
this.fire_handle_released( this.active_handle_index );
Event.stop(event);
},
start_handle_drag: function(event) {
if( Event.isLeftClick(event) ) {
this.active_handle_index = this.get_handle_index( event.element() );
if( this.active_handle_index >= 0 && Event.isLeftClick(event) ) {
false;
var pointer = { x : Event.pointerX(event), y : Event.pointerY(event) };
Event.observe(document.body, "mousemove", this.eventMouseMove);
Event.observe(document.body, "mouseup", this.eventMouseUp);
this.active_handle_index = this.get_handle_index( event.element() );
this.active_handle = this.handles[this.active_handle_index];
this.active_offset = pointer.x - (this.active_handle.position + this.slider_offset[0]);
this.raise_handle( this.active_handle_index );
this.fire_handle_clicked( this.active_handle_index );
this.dragging = true;
Event.stop(event);
}
}
},
will_cross_handle: function( handle_index, index ) {
false;
for( var i = 0 ; i < this.handles.length ; i ++ ) {
if ( handle_index != i ) {
if ( handle_index > i ) {
if ( index <= this.handles[i].index ) {
return i;
}
}
else {
if ( index >= this.handles[i].index ) {
return i;
}
}
}
}
return -1;
},
update: function(event) {
false;
var new_pos = this.get_position_from_event( event );
this.update_handle_position( this.active_handle_index, new_pos );
this.draw_track();
Event.stop( event );
},
update_handle_position: function( handle_index, position ) {
var handle = this.handles[handle_index];
if ( !this.options.snap_to ) {
var old_pos = handle.position;
handle.position = position;
if ( old_pos != position && !this.options.range ) {
this.fire_slider_changed( this.active_handle_index );
}
}
if ( this.options.range ) {
var index = this.get_index_from_position( position );
index = this._get_constrained_index( handle_index, index );
if ( index != handle.index ) {
handle.index = index;
if ( this.options.snap_to ) {
this.set_indexed_position( handle, index );
}
this.fire_slider_changed( handle_index );
}
}
this.raise_handle( handle_index );
this.draw_handle( handle );
},
_get_constrained_index: function( handle_index, index ) {
var handle = this.handles[handle_index];
if ( index != handle.index ) {
if ( !this.options.can_cross ) {
var blocking_handle_index = this.will_cross_handle( handle_index, index );
if ( blocking_handle_index >= 0 ) {
if ( blocking_handle_index < handle_index ) {
index = this.handles[blocking_handle_index].index + 1;
}
else {
index = this.handles[blocking_handle_index].index - 1;
}
}
}
}
if ( index < this.options.range[0] )
index = this.options.range[0];
else if ( index > this.options.range[1] )
index = this.options.range[1];
return index;
},
set_handle_index: function( handle_index, index ) {
var handle = this.handles[handle_index];
index = this._get_constrained_index( handle_index, index );
if ( index != handle.index ) {
this.set_indexed_position( handle, index );
this.draw_handle( handle );
this.raise_handle( handle_index );
this.draw_track();
this.fire_slider_changed( handle_index );
}
},
get_position_from_event: function( event ) {
var pointer = { x : Event.pointerX(event), y : Event.pointerY(event) };
var new_pos = pointer.x - this.slider_offset[0] - this.active_offset;
if ( new_pos < 0 ) {
new_pos = 0;
this.active_offset = this.handle_offset;
}
else if ( new_pos > this.real_width ) {
new_pos = this.real_width;
this.active_offset = this.handle_offset;
}
return new_pos;
},
on_track_click: function( event ) {
if( Event.isLeftClick(event) ) {
false;
this.active_offset = this.handle_offset;
var new_pos = this.get_position_from_event( event );
var closest_handle;
var closest_distance = -1;
for ( var i = 0 ; i < this.handles.length ; i ++ ) {
var distance = Math.abs( this.handles[i].position - new_pos );
if ( closest_distance >= 0 ) {
if ( distance <= closest_distance ) {
closest_distance = distance;
closest_handle = i;
}
}
else {
closest_distance = distance;
closest_handle = i;
}
}
this.update_handle_position( closest_handle, new_pos );
this.draw_track();
Event.stop(event);
}
},
draw_handle: function( handle ) {
handle.element.style.left = handle.position + 'px';
},
draw_track: function() {
if ( this.track ) {
this.track.style.left = this.handles[0].position + this.handle_offset + 'px';
if ( this.inner_track ) {
this.inner_track.style.left = this.handles[1].position - this.handles[0].position - this.track_width + "px";
}
}
},
calc_indexed_position: function( index ) {
return Math.round( this.real_width * ((index - this.options.range[0]) / this.num_points) );
},
set_indexed_position: function( handle, index ) {
handle.index = index;
handle.position = this.calc_indexed_position( index );
},
get_index_from_position: function( position ) {
return Math.round( this.num_points * (position / this.real_width) ) + this.options.range[0];
},
raise_handle: function( handle_index ) {
false;
if ( this.dragging )
return;
for( var i = 0 ; i < this.handles.length ; i++ )
this.handles[i].element.style.zIndex = i == handle_index ? this.max_z : this.base_z;
},
reset_handles: function() {
false;
for( var i = 0 ; i < this.handles.length ; i ++ ) {
var handle = this.handles[i];
var position;
if ( this.num_handles == 1 ) {
position = Math.round( this.real_width / 2 );
}
else {
position = Math.round( this.real_width * (i / (this.handles.length-1) ) );
}
handle.position = position;
if ( this.options.range ) {
var index = this.get_index_from_position( handle.position );
this.set_indexed_position( handle, index );
}
this.draw_handle( this.handles[i] );
this.raise_handle( i );
this.fire_slider_changed( i );
}
this.draw_track();
this.fire_slider_reset();
},
fire_slider_reset: function() {
false;
this.track.fire('slider:reset');
},
fire_slider_changed: function( handle_index ) {
false;
this.track.fire('slider:change', { index: handle_index, handle: this.handles[handle_index] } );
},
fire_handle_clicked: function( handle_index ) {
false;
this.active_handle.element.fire('slider:handle_clicked', { index: handle_index, handle: this.handles[handle_index] } );
},
fire_handle_released: function( handle_index ) {
false;
this.active_handle.element.fire('slider:handle_released', { index: handle_index, handle: this.handles[handle_index] } );
},
register_on_price_change_handler: function( handler ) {
var slider_node = this.slider;
Event.observe( slider_node, 'slider:change', handler );
},
render: function() {
false;
var eventHandleMouseDown = this.start_handle_drag.bindAsEventListener(this);
this.eventMouseUp   = this.end_drag.bindAsEventListener(this);
this.eventMouseMove = this.update.bindAsEventListener(this);
for( var i = 0 ; i < this.handles.length ; i ++ ) {
var handle = this.handles[i];
handle.element.observe("mousedown", eventHandleMouseDown);
handle.element.observe("mouseover", this.raise_handle.bind(this, i) );
};
this.slider.observe("mousedown", this.on_track_click.bindAsEventListener(this));
this.reset_handles();
}
} );

