/
slider-rating.js
175 lines (170 loc) · 8.56 KB
/
slider-rating.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
/*
* @license This file is part of LimeSurvey
* See COPYRIGHT.php for copyright notices and details.
*
* Update answers part for rating slider
*
* @author Markus Flür (lacrioque)
* @TODO: Make sizes responsive
* @param {number} qId The qid of the question where apply.
*/
function getRatingSlider(qID){
//Find the basic php-generated part of the question
var answersList=$('#question'+qID+' .answers-list.radio-list:not(.slidered-list)'),
basicSettings = {
},
package = {
sliderHtmlElement : $("<div id='emoji_slider_container_"+qID+"' class='slider-wrapper'></div>"), //wrapper for the slider parts
sliderInnerHtmlElement : $("<div class='slider-labels'></div>"), //the labels of the wrapper
sliderGrabContainer : $("<div id='emoji_slider_grab_container_"+qID+"' class='slider-grab-container'></div>"), //the container for the handle and the colorline
sliderLine : $("<div id='slider_line_item_"+qID+"' class='slider-line'></div>"), //The colored baseline
sliderHandle : $("<div id='slider_handle_item_"+qID+"' class='slider-handle'></div>"), //the handle
sliderLabelEmoji : $("<div class='slider-label'><i class='emoji emoji-enormous'></i></div>"),
sliderLabelNoAnswer : $("<div class='slider-label slider-label-6' data-position='6'><i class='fa fa-ban' style='font-size:28px;'></i></div>")
},
mapEmojiToValue = function(position){
var imageMap = {1: "emoji-sad",2: "emoji-mildlyunamused",3: "emoji-whatever",4: "emoji-smile",5: "emoji-grin-eyes",6: "emoji-grin",7: "emoji-bigsmile"};
return imageMap[position];
},
calculateMapObjects = function(){
var maps = {};
//the map to the relative position based on the container for screens >640px
var mapToStickToSelection = { 1 : 31 , 2 : 123, 3 : 214, 4 : 304, 5 : 397, 6 : 476};
//the map to the relative position based on the container for screens <640px
var mapToStickToSelectionSmallScreen = { 1 : 16 , 2 : 72, 3 : 127, 4 : 182, 5 : 236, 6 : 286};
if( $(window).width() < 640){
maps.selection = mapToStickToSelectionSmallScreen;
} else {
maps.selection = mapToStickToSelection;
}
//the map to the field with attributes min and max for screens >640px
var mapToStickToSelection = { 1 : {min: 0, max:78} , 2 : {min: 78, max:171}, 3 : {min: 171, max:264}, 4 : {min: 264, max:357}, 5 : {min: 357, max:450}, 6 : {min: 450, max:543}};
//the map to the field with attributes min and max for screens <640px
var mapToStickToSelectionSmallScreen = { 1 : {min: 0, max:44} , 2 : {min: 44, max:100} , 3 : {min: 100, max:156} , 4 : {min: 156, max:212} , 5 : {min: 212, max:268}, 6 : {min: 268, max:324} };
if( $(window).width() < 640){
maps.borders = mapToStickToSelectionSmallScreen;
} else {
maps.borders = mapToStickToSelection;
}
return maps
},
//Method setting the value on the EM-calculateable part
setValueAndColorize = function(index){
answersList.find('input[type=radio][value='+index+']').prop('checked',true).trigger('click');
$("#emoji_slider_container_"+qID).find(".slider-label").find('i').removeClass('emoji-color'); //remove all other color-classes
if(index==6){ //if it is the "no Answer" set, add text-danger instead of emoji-color
$("#emoji_slider_container_"+qID).find(".slider-label-"+index).find('i').addClass('text-danger');
} else {
$("#emoji_slider_container_"+qID).find(".slider-label-6").find('i').removeClass('text-danger');
$("#emoji_slider_container_"+qID).find(".slider-label-"+index).find('i').addClass('emoji-color');
}
},
//Method to unset all events on dragend
onEndDrag = function(e){
var element = this;
onSetHandlePosition(e,element);
$("#emoji_slider_container_"+qID).find('.slider-grab-container').off("mousemove.dragOn");
$("#emoji_slider_container_"+qID).find('.slider-grab-container').off("mouseup.dragOn");
},
//method to set the handle and therefore register a change event
onSetHandlePosition = function(e,element){
var rawPosition = e.pageX,
element = element || this;
var position = calculateSliderPositionFromOffset(rawPosition);
var index = getIndexFromPosition(position);
setSliderPosition(position,element);
setValueAndColorize(index);
},
checkHasNoAnswerOption = function(){
return (answersList.find('.noanswer-item').length > 0);
},
checkOpenValue = function(){
var openValue = answersList.find("input:radio:checked").val() || (checkHasNoAnswerOption() ? 6 : 1); //Select either noAnswer, or the preselected
return openValue || false;
},
relativeOffset = function(rawOffset){
var baseZero = package.sliderHtmlElement.offset();
var relativeZero = baseZero.left;
var offset = rawOffset-relativeZero;
return offset;
},
getIndexFromPosition = function(position){
var maps = calculateMapObjects();
for(var i in maps.borders){
if(maps.selection[i] == position) {
return i;
}
}
},
calculateSliderPositionFromOffset = function(rawOffsetX){
var offsetX = relativeOffset(rawOffsetX);
var maps = calculateMapObjects();
for(var i in maps.borders){
if(offsetX >= maps.borders[i]['min'] && offsetX < maps.borders[i]['max']) {
return maps.selection[i];
}
}
},
getSliderPositionFromIndex = function(index){
var maps = calculateMapObjects();
return maps.selection[index];
},
setSliderPosition = function(position,element){
$(element).closest('.slider-wrapper').find('.slider-handle').css('left', position+"px");
},
//Register the events
bindEventsToContainer = function(){
//Register the click event on the slider container
//this event will trigger when the slider area is clicked,
//to move the slider to where the click was generated
$("#emoji_slider_grab_container_"+qID).on('click', onSetHandlePosition );
//Registers to the event, when the handle is dragged.
//Emulate a dragging behaviour, that is ignoring the Y-axis and skipst through the predefined stoppoints
$("#emoji_slider_grab_container_"+qID).find('.slider-handle').on("mousedown.drag", function(e){
//set events on dragging, on leaving the container and on dropping the handle
$("#emoji_slider_grab_container_"+qID).on("mousemove.dragOn", onSetHandlePosition );
$("#emoji_slider_grab_container_"+qID).on("mouseup.dragOn", onEndDrag);
});
//Bind events for clicking on the labels
$("#emoji_slider_container_"+qID).find('.slider-label').on('click',onSetHandlePosition);
},
pinUpHtml = function(){
//Fill the inner Element with the labels
//create 5 Emojis and append them as labels to the label-row
for (i=1; i<=5; i++) {
package.sliderLabelEmoji.clone().addClass("slider-label-"+i).data('position', i).find('i').addClass(mapEmojiToValue(i)).end().appendTo(package.sliderInnerHtmlElement);
}
//Add the "no answer" label, if the question need one, also add the mandatory class to the sliderline
if(!checkHasNoAnswerOption()){
package.sliderLine.addClass('mandatory');
package.sliderLine.addClass('mandatory');
} else {
package.sliderInnerHtmlElement.append(package.sliderLabelNoAnswer);
}
//append the colored line on the bottom
package.sliderGrabContainer.append(package.sliderLine);
//append the handle
package.sliderGrabContainer.append(package.sliderHandle);
//Append things to the main elemen
//append the labels
package.sliderHtmlElement.append(package.sliderInnerHtmlElement);
//append the grabContainer (handle + colored baseline)
package.sliderHtmlElement.append(package.sliderGrabContainer);
//put everything on the screen
answersList.after(package.sliderHtmlElement);
},
doRatingSlider = function () {
if(!answersList){return;} //if the generated part is not available => jump out of this method
//hide the basic radioes
pinUpHtml();
bindEventsToContainer();
answersList.addClass("slidered-list hide read");
//if a value is set, set it in the emojis
var openValue = checkOpenValue();
if(openValue){
setValueAndColorize(openValue);
setSliderPosition(getSliderPositionFromIndex(openValue), package.sliderGrabContainer);
}
}
return doRatingSlider;
}