Here is a small jQuery plugin that inserts a jQuery UI range slider into a multi-numeric question and automatically populates that question's inputs with the range min and max values.
The plugin handles:
- previous answers
- slider max/min
- range min start
- range max start
- range span min
- slider step
- slider width
- record the start values
- show slider max and min
1) Add the following to the end of template.js:
Code:
// A jQuery plugin to display a range slider in LimeSurvey
(function( $ ){
$.fn.lsRangeSlider = function(options) {
// The defaults, extended and modified with any passed in the function call
var opts = $.extend( {
range :true,
sliderMin :0,
sliderMax :100,
rangeStartMin :'',
rangeStartMax :'',
minRangeSpan :0,
step :1,
width :250,
recordStart :false,
showMin :false,
showMax :false
}, options);
return this.each(function() {
if($(this).hasClass('numeric-multi') && $('input.text', this).length == 2) {
// Define some vars
var $this = $(this);
var qID = $(this).attr('id').split('question')[1];
var rangeMinInput = $('input.text:eq(0)', $this);
var rangeMaxInput = $('input.text:eq(1)', $this);
// Some classes for the question and sub-questions
$this.addClass('range-slider-question');
// Check for pre-existing answer
if($(rangeMinInput).val() != '' && $(rangeMinInput).val() != '') {
opts.rangeStartMin = $(rangeMinInput).val();
opts.rangeStartMax = $(rangeMaxInput).val();
}
// Insert the slider elements
$('.subquestions-list', $this).before(
'<div class="range-slider-wrapper"> \
<div class="range-slider-min"></div> \
<div id="range-slider-'+qID+'" class="range-slider" style="width:'+opts.width+'px;"> \
<div class="range-slider-callout" id="slider-callout-min-'+qID+'"></div> \
<div class="range-slider-callout" id="slider-callout-max-'+qID+'"></div> \
</div> \
<div class="range-slider-max"></div> \
<div style="clear:both;"></div> \
</div>'
);
// Show min/max if option is set
if(opts.showMax) {
$('.range-slider-max', $this).text(opts.sliderMax);
}
if(opts.showMin) {
$('.range-slider-min', $this).text(opts.sliderMin);
}
// Initiate the slider
var rangeMin;
var rangeMax;
if(opts.rangeStartMin == '' || opts.rangeStartMin < opts.sliderMin || opts.rangeStartMin > opts.rangeStartMax) {
rangeMin = opts.sliderMin+((opts.sliderMax-opts.sliderMin)*0.3333);
}
else {
rangeMin = opts.rangeStartMin;
}
if(opts.rangeStartMax == '' || opts.rangeStartMax > opts.sliderMax || opts.rangeStartMax < opts.rangeStartMin) {
rangeMax = opts.sliderMin+((opts.sliderMax-opts.sliderMin)*0.6667);
}
else {
rangeMax = opts.rangeStartMax;
}
$('#range-slider-'+qID).slider({
range: true,
min: opts.sliderMin,
max: opts.sliderMax,
values: [ rangeMin, rangeMax ],
step: opts.step,
slide: function(event, ui) {
if((ui.values[1] - ui.values[0]) < opts.minRangeSpan) {
return false; // Nothing happens if less than minRangeSpan
}
$(rangeMinInput).val(ui.values[0]);
$(rangeMaxInput).val(ui.values[1]);
$('#slider-callout-min-'+qID).text(ui.values[0]);
$('#slider-callout-max-'+qID).text(ui.values[1]);
setTimeout(function() {
$('#slider-callout-min-'+qID).css({ 'left':$('.ui-slider-handle:eq(0)', $this).position().left - $('#slider-callout-min-'+qID).outerWidth() - ($('.ui-slider-handle:eq(1)', $this).outerWidth()/2)+'px' }).show();
$('#slider-callout-max-'+qID).css({ 'left':($('.ui-slider-handle:eq(1)', $this).position().left)+($('.ui-slider-handle:eq(1)', $this).outerWidth()/2)+'px' }).show();
}, 10);
},
create: function(event, ui) {
// Initial values and positions
if($(rangeMinInput).val() != '' && $(rangeMaxInput).val() != '') { // Pre-existing answer
$('#slider-callout-min-'+qID).text(opts.rangeStartMin);
$('#slider-callout-max-'+qID).text(opts.rangeStartMax);
}
else if(opts.recordStart && opts.rangeStartMin && opts.rangeStartMin && $(rangeMinInput).val() == '' && $(rangeMaxInput).val() == '') { // Record the start value (if option is set)
$(rangeMinInput).val(opts.rangeStartMin);
$(rangeMaxInput).val(opts.rangeStartMax);
$('#slider-callout-min-'+qID).text(opts.rangeStartMin);
$('#slider-callout-max-'+qID).text(opts.rangeStartMax);
}
else {
$('.range-slider-callout', $this).hide();
}
$('#slider-callout-min-'+qID).css({ 'left':$('.ui-slider-handle:eq(0)', $this).position().left - $('#slider-callout-min-'+qID).outerWidth() - ($('.ui-slider-handle:eq(1)', $this).outerWidth()/2)+'px' });
$('#slider-callout-max-'+qID).css({ 'left':($('.ui-slider-handle:eq(1)', $this).position().left)+($('.ui-slider-handle:eq(1)', $this).outerWidth()/2)+'px' });
}
});
}
});
};
})( jQuery );
2) Add these styles to the end of template.css (they are for the default template but easily modified for others):
Code:
.range-slider-question p.tip,
.range-slider-question .subquestions-list {
display: none;
}
.range-slider-wrapper {
clear: both;
margin: 10px 0;
padding-top: 20px;
}
.range-slider,
.range-slider-max,
.range-slider-min {
float: left;
position: relative;
}
.range-slider-max,
.range-slider-min {
font-size: 0.8em;
color:#666666;
line-height: 1.20;
}
.range-slider-min {
margin-right: 5px;
}
.range-slider-max {
margin-left: 5px;
}
.range-slider-question .ui-slider-handle {
top: -4px;
border-radius: 4px;
}
.range-slider-callout {
position: absolute;
top: -30px;
margin: 0;
min-width: 1.3em;
padding: 0.1em;
font-size: 0.9em;
color:#000000;
line-height: 1;
text-align: center;
background: #F8F8FF;
border: 1px solid #D2E0F2;
border-radius: 4px;
}
3) Then, add something like this to the source of your question (I think the comments explain the options adequately)
Code:
<script type="text/javascript" charset="utf-8">
$(document).ready(function(){
$('#question{QID}').lsRangeSlider({
sliderMin :0, // Minimum slider value (default 0)
sliderMax :100, // Maximum slider value (default 100)
rangeStartMin :20, // Minimum range handle start value
rangeStartMax :80, // Maximum range handle start value
minRangeSpan :5, // Minimum allowed range span
step :1, // Slider increments (default 1)
width :400, // Width of slider in pixels (default 250)
recordStart :true, // Record the start value? (default no)
showMin :true, // Show slider minimum value? (default no)
showMax :true // Show slider maximum value? (default no)
});
});
</script>