diff --git a/app/views/partials/_question.html.haml b/app/views/partials/_question.html.haml
index 06e0fc04..b9b0ac8d 100644
--- a/app/views/partials/_question.html.haml
+++ b/app/views/partials/_question.html.haml
@@ -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)
diff --git a/lib/assets/javascripts/surveyor/jquery.selectToUISlider.js b/lib/assets/javascripts/surveyor/jquery.selectToUISlider.js
new file mode 100755
index 00000000..18704d78
--- /dev/null
+++ b/lib/assets/javascripts/surveyor/jquery.selectToUISlider.js
@@ -0,0 +1,240 @@
+/*
+ * --------------------------------------------------------------------
+ * jQuery-Plugin - selectToUISlider - creates a UI slider component from a select element(s)
+ * by Scott Jehl, scott@filamentgroup.com
+ * 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('
');
+
+ //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(''+labelText+''+
+ ''+
+ ''+
+ '')
+ .data('handleNum',i)
+ .appendTo(sliderComponent);
+ });
+
+ //CREATE SCALE AND TICS
+
+ //write dl if there are optgroups
+ if(groups) {
+ var inc = 0;
+ var scale = sliderComponent.append('
').find('.ui-slider-scale:eq(0)');
+ jQuery(groups).each(function(h){
+ scale.append(''+this.label+'');//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(''+ labelText +'');
+ inc++;
+ });
+ });
+ }
+ //write ol
+ else {
+ var scale = sliderComponent.append('
').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(''+ labelText +'');
+ });
+ }
+
+ 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 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;
+}
+
+
diff --git a/lib/assets/javascripts/surveyor/jquery.surveyor.js b/lib/assets/javascripts/surveyor/jquery.surveyor.js
index 71c19e72..fab074c9 100644
--- a/lib/assets/javascripts/surveyor/jquery.surveyor.js
+++ b/lib/assets/javascripts/surveyor/jquery.surveyor.js
@@ -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();
diff --git a/lib/assets/stylesheets/surveyor.sass b/lib/assets/stylesheets/surveyor.sass
index 59b3be67..dc33212e 100644
--- a/lib/assets/stylesheets/surveyor.sass
+++ b/lib/assets/stylesheets/surveyor.sass
@@ -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"]
diff --git a/lib/assets/stylesheets/surveyor/ui.slider.extras.css b/lib/assets/stylesheets/surveyor/ui.slider.extras.css
new file mode 100755
index 00000000..862388b6
--- /dev/null
+++ b/lib/assets/stylesheets/surveyor/ui.slider.extras.css
@@ -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;
+}
+