Skip to content

Commit

Permalink
adding back slider. closes NUBIC#230
Browse files Browse the repository at this point in the history
  • Loading branch information
Mark Yoon committed May 21, 2012
1 parent 77544e2 commit 70f9910
Show file tree
Hide file tree
Showing 5 changed files with 363 additions and 2 deletions.
2 changes: 1 addition & 1 deletion app/views/partials/_question.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
= ff.input :question_id, :as => :quiet
= ff.input :response_group, :as => :quiet, :value => rg if g && g.display_type == "repeater"
= ff.input :id, :as => :quiet unless r.new_record?
= ff.input :answer_id, :as => :select, :collection => q.answers.map{|a| [a.text, a.id]}, :label => q.text, :input_html => { :disabled => disabled }
= ff.input :answer_id, :as => :select, :collection => q.answers.map{|a| [a.text, a.id]}, :include_blank => (renderer != :slider), :label => q.text, :input_html => { :disabled => disabled }
- else # :default, :inline, :inline_default
- if q.pick == "one"
- r = response_for(@response_set, q, nil, rg)
Expand Down
240 changes: 240 additions & 0 deletions lib/assets/javascripts/surveyor/jquery.selectToUISlider.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,240 @@
/*
* --------------------------------------------------------------------
* jQuery-Plugin - selectToUISlider - creates a UI slider component from a select element(s)
* by Scott Jehl, [email protected]
* http://www.filamentgroup.com
* reference article: http://www.filamentgroup.com/lab/update_jquery_ui_16_slider_from_a_select_element/
* demo page: http://www.filamentgroup.com/examples/slider_v2/index.html
*
* Copyright (c) 2008 Filament Group, Inc
* Dual licensed under the MIT (filamentgroup.com/examples/mit-license.txt) and GPL (filamentgroup.com/examples/gpl-license.txt) licenses.
*
* Usage Notes: please refer to our article above for documentation
*
* --------------------------------------------------------------------
*/


jQuery.fn.selectToUISlider = function(settings){
var selects = jQuery(this);

//accessible slider options
var options = jQuery.extend({
labels: 3, //number of visible labels
tooltip: true, //show tooltips, boolean
tooltipSrc: 'text',//accepts 'value' as well
labelSrc: 'value',//accepts 'value' as well ,
sliderOptions: null
}, settings);


//handle ID attrs - selects each need IDs for handles to find them
var handleIds = (function(){
var tempArr = [];
selects.each(function(){
tempArr.push('handle_'+jQuery(this).attr('id'));
});
return tempArr;
})();

//array of all option elements in select element (ignores optgroups)
var selectOptions = (function(){
var opts = [];
selects.eq(0).find('option').each(function(){
opts.push({
value: jQuery(this).attr('value'),
text: jQuery(this).text()
});
});
return opts;
})();

//array of opt groups if present
var groups = (function(){
if(selects.eq(0).find('optgroup').size()>0){
var groupedData = [];
selects.eq(0).find('optgroup').each(function(i){
groupedData[i] = {};
groupedData[i].label = jQuery(this).attr('label');
groupedData[i].options = [];
jQuery(this).find('option').each(function(){
groupedData[i].options.push({text: jQuery(this).text(), value: jQuery(this).attr('value')});
});
});
return groupedData;
}
else return null;
})();

//check if obj is array
function isArray(obj) {
return obj.constructor == Array;
}
//return tooltip text from option index
function ttText(optIndex){
return (options.tooltipSrc == 'text') ? selectOptions[optIndex].text : selectOptions[optIndex].value;
}

//plugin-generated slider options (can be overridden)
var sliderOptions = {
step: 1,
min: 0,
orientation: 'horizontal',
max: selectOptions.length-1,
range: selects.length > 1,//multiple select elements = true
slide: function(e, ui) {//slide function
var thisHandle = jQuery(ui.handle);
//handle feedback
var textval = ttText(ui.value);
thisHandle
.attr('aria-valuetext', textval)
.attr('aria-valuenow', ui.value)
.find('.ui-slider-tooltip .ttContent')
.text( textval );

//control original select menu
var currSelect = jQuery('#' + thisHandle.attr('id').split('handle_')[1]);
currSelect.find('option').eq(ui.value).attr('selected', 'selected');
},
values: (function(){
var values = [];
selects.each(function(){
values.push( jQuery(this).get(0).selectedIndex );
});
return values;
})()
};

//slider options from settings
options.sliderOptions = (settings) ? jQuery.extend(sliderOptions, settings.sliderOptions) : sliderOptions;

//select element change event
selects.bind('change keyup click', function(){
var thisIndex = jQuery(this).get(0).selectedIndex;
var thisHandle = jQuery('#handle_'+ jQuery(this).attr('id'));
var handleIndex = thisHandle.data('handleNum');
thisHandle.parents('.ui-slider:eq(0)').slider("values", handleIndex, thisIndex);
});


//create slider component div
var sliderComponent = jQuery('<div></div>');

//CREATE HANDLES
selects.each(function(i){
var hidett = '';

//associate label for ARIA
var thisLabel = jQuery('label[for=' + jQuery(this).attr('id') +']');
//labelled by aria doesn't seem to work on slider handle. Using title attr as backup
var labelText = (thisLabel.size()>0) ? 'Slider control for '+ thisLabel.text()+'' : '';
var thisLabelId = thisLabel.attr('id') || thisLabel.attr('id', 'label_'+handleIds[i]).attr('id');


if( options.tooltip == false ){hidett = ' style="display: none;"';}
jQuery('<a '+
'href="#" tabindex="0" '+
'id="'+handleIds[i]+'" '+
'class="ui-slider-handle" '+
'role="slider" '+
'aria-labelledby="'+thisLabelId+'" '+
'aria-valuemin="'+options.sliderOptions.min+'" '+
'aria-valuemax="'+options.sliderOptions.max+'" '+
'aria-valuenow="'+options.sliderOptions.values[i]+'" '+
'aria-valuetext="'+ttText(options.sliderOptions.values[i])+'" '+
'><span class="screenReaderContext">'+labelText+'</span>'+
'<span class="ui-slider-tooltip ui-widget-content ui-corner-all"'+ hidett +'><span class="ttContent"></span>'+
'<span class="ui-tooltip-pointer-down ui-widget-content"><span class="ui-tooltip-pointer-down-inner"></span></span>'+
'</span></a>')
.data('handleNum',i)
.appendTo(sliderComponent);
});

//CREATE SCALE AND TICS

//write dl if there are optgroups
if(groups) {
var inc = 0;
var scale = sliderComponent.append('<dl class="ui-slider-scale ui-helper-reset" role="presentation"></dl>').find('.ui-slider-scale:eq(0)');
jQuery(groups).each(function(h){
scale.append('<dt style="width: '+ (100/groups.length).toFixed(2) +'%' +'; left:'+ (h/(groups.length-1) * 100).toFixed(2) +'%' +'"><span>'+this.label+'</span></dt>');//class name becomes camelCased label
var groupOpts = this.options;
jQuery(this.options).each(function(i){
var style = (inc == selectOptions.length-1 || inc == 0) ? 'style="display: none;"' : '' ;
var labelText = (options.labelSrc == 'text') ? groupOpts[i].text : groupOpts[i].value;
scale.append('<dd style="left:'+ leftVal(inc) +'"><span class="ui-slider-label">'+ labelText +'</span><span class="ui-slider-tic ui-widget-content"'+ style +'></span></dd>');
inc++;
});
});
}
//write ol
else {
var scale = sliderComponent.append('<ol class="ui-slider-scale ui-helper-reset" role="presentation"></ol>').find('.ui-slider-scale:eq(0)');
jQuery(selectOptions).each(function(i){
var style = (i == selectOptions.length-1 || i == 0) ? 'style="display: none;"' : '' ;
var labelText = (options.labelSrc == 'text') ? this.text : this.value;
scale.append('<li style="left:'+ leftVal(i) +'"><span class="ui-slider-label">'+ labelText +'</span><span class="ui-slider-tic ui-widget-content"'+ style +'></span></li>');
});
}

function leftVal(i){
return (i/(selectOptions.length-1) * 100).toFixed(2) +'%';

}




//show and hide labels depending on labels pref
//show the last one if there are more than 1 specified
if(options.labels > 1) sliderComponent.find('.ui-slider-scale li:last span.ui-slider-label, .ui-slider-scale dd:last span.ui-slider-label').addClass('ui-slider-label-show');

//set increment
var increm = Math.max(1, Math.round(selectOptions.length / options.labels));
//show em based on inc
for(var j=0; j<selectOptions.length; j+=increm){
if((selectOptions.length - j) > increm){//don't show if it's too close to the end label
sliderComponent.find('.ui-slider-scale li:eq('+ j +') span.ui-slider-label, .ui-slider-scale dd:eq('+ j +') span.ui-slider-label').addClass('ui-slider-label-show');
}
}

//style the dt's
sliderComponent.find('.ui-slider-scale dt').each(function(i){
jQuery(this).css({
'left': ((100 /( groups.length))*i).toFixed(2) + '%'
});
});


//inject and return
sliderComponent
.insertAfter(jQuery(this).eq(this.length-1))
.slider(options.sliderOptions)
.attr('role','application')
.find('.ui-slider-label')
.each(function(){
jQuery(this).css('marginLeft', -jQuery(this).width()/2);
});

//update tooltip arrow inner color
sliderComponent.find('.ui-tooltip-pointer-down-inner').each(function(){
var bWidth = jQuery('.ui-tooltip-pointer-down-inner').css('borderTopWidth');
var bColor = jQuery(this).parents('.ui-slider-tooltip').css('backgroundColor')
jQuery(this).css('border-top', bWidth+' solid '+bColor);
});

var values = sliderComponent.slider('values');

if(isArray(values)){
jQuery(values).each(function(i){
sliderComponent.find('.ui-slider-tooltip .ttContent').eq(i).text( ttText(this) );
});
}
else {
sliderComponent.find('.ui-slider-tooltip .ttContent').eq(0).text( ttText(values) );
}

return this;
}


5 changes: 4 additions & 1 deletion lib/assets/javascripts/surveyor/jquery.surveyor.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,10 @@ jQuery(document).ready(function(){
}
});
});


// http://www.filamentgroup.com/lab/update_jquery_ui_slider_from_a_select_element_now_with_aria_support/
$('fieldset.q_slider select').each(function(i,e){ $(e).selectToUISlider({"labelSrc": "text"}).hide() });

// If javascript works, we don't need to show dependents from previous sections at the top of the page.
jQuery("#dependents").remove();

Expand Down
8 changes: 8 additions & 0 deletions lib/assets/stylesheets/surveyor.sass
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,14 @@ body
fieldset.q_dropdown, fieldset.q_inline_dropdown, fieldset.q_default_dropdown, fieldset.q_slider, fieldset.q_repeater_dropdown
label
:display none
fieldset.q_slider
:margin-bottom 3em
li.select
:width 50%
:font-size .8em
.ui-slider span.ui-slider-label-show
:position relative
:display inline

// buttons
input[type="submit"]
Expand Down
110 changes: 110 additions & 0 deletions lib/assets/stylesheets/surveyor/ui.slider.extras.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
/*NEW SLIDER STYLES FOR SCALE, ETC*/
/* slider widget */
.ui-slider {
text-decoration: none !important;
}
.ui-slider .ui-slider-handle {
overflow: visible !important;
}
.ui-slider .ui-slider-tooltip {
display: none;
}
.ui-slider .screenReaderContext {
position: absolute;
width: 0;
height: 0;
overflow: hidden;
left: -999999999px;
}
.ui-slider .ui-state-active .ui-slider-tooltip, .ui-slider .ui-state-focus .ui-slider-tooltip, .ui-slider .ui-state-hover .ui-slider-tooltip {
display: block;
position: absolute;
bottom: 2.5em;
text-align: center;
padding: .3em .2em .4em;
font-size: .9em;
width: 8em;
margin-left: -3.7em;
}
.ui-slider .ui-slider-tooltip .ui-tooltip-pointer-down, .ui-slider .ui-slider-tooltip .ui-tooltip-pointer-down-inner {
position: absolute;
display: block;
width:0;
height:0;
border-bottom-width: 0;
background: none;
}
.ui-slider .ui-slider-tooltip .ui-tooltip-pointer-down {
border-left: 7px dashed transparent;
border-right: 7px dashed transparent;
border-top-width: 8px;
bottom: -8px;
right: auto;
left: 50%;
margin-left: -7px;
}
.ui-slider .ui-slider-tooltip .ui-tooltip-pointer-down-inner {
border-left: 6px dashed transparent;
border-right: 6px dashed transparent;
border-top: 7px solid #fff;
bottom: auto;
top: -9px;
left: -6px;
}
.ui-slider a {
text-decoration: none;
}
.ui-slider ol, .ui-slider li, .ui-slider dl, .ui-slider dd, .ui-slider dt {
list-style: none;
margin: 0;
padding: 0;
}
.ui-slider ol, .ui-slider dl {
position: relative;
top: 1.3em;
width: 100%;
}
.ui-slider dt {
top: 1.5em;
position: absolute;
padding-top: .2em;
text-align: center;
border-bottom: 1px dotted #ddd;
height: .7em;
color: #999;
}
.ui-slider dt span {
background: #fff;
padding: 0 .5em;
}
.ui-slider li, .ui-slider dd {
position: absolute;
overflow: visible;
color: #666;
}
.ui-slider span.ui-slider-label {
position: absolute;
}
.ui-slider li span.ui-slider-label, .ui-slider dd span.ui-slider-label {
display: none;
}
.ui-slider li span.ui-slider-label-show, .ui-slider dd span.ui-slider-label-show {
display: block;
}
.ui-slider span.ui-slider-tic {
position: absolute;
left: 0;
height: .8em;
top: -1.3em;
}
.ui-slider li span.ui-widget-content, .ui-slider dd span.ui-widget-content {
border-right: 0;
border-left-width: 1px;
border-left-style: solid;
border-top: 0;
border-bottom: 0;
}
.ui-slider .first .ui-slider-tic, .ui-slider .last .ui-slider-tic {
display: none;
}

0 comments on commit 70f9910

Please sign in to comment.