Well, actually I do have a solution for a similar requirement where I allow dragging items into "buckets". I use a multiple-short-text question for this with sub-questions being the draggable items. The data recorded for each item is the "bucket" number that it was dropped in. "Buckets" are pre-defined in a list in the "Help" section of the question.
So, this is what it would look like to start:
And this is after manipulation (the data would, of course, be hidden from the respondent):
1) Add a function like this to the end of
template.js:
Code:
function cardSort(qID) {
// Define some stuff...
var thisQuestion = $('#question'+qID);
var thisQuestionHelp = $('img[alt="Help"]', thisQuestion).parent();
thisQuestion.addClass('card-sort-question');
// Hide the "Help" section
thisQuestionHelp.hide();
//Insert the "card sort" elements
$('ul.questions-list', thisQuestion).parent().prepend('<div class="droppable items-start"></div><div class="items-end-wrapper" />');
$('ul:eq(0) li', thisQuestionHelp).each(function(i) {
$('.items-end-wrapper', thisQuestion).append('<div class="items-end-inner">\
<div class="items-end-text">'+$(this).html()+'</div>\
<div class="droppable items-end items-end-'+(i+1)+'" data-items-end="'+(i+1)+'"></div>\
</div>')});
// Insert the "cards"
$('li.answer-item', thisQuestion).each(function(i) {
var thisSGQA = $(this).attr('id').replace(/javatbd/, '');
var thisCode = $(this).attr('id').split('X'+qID)[1];
var thisHTML = $('label', this).html();
$('div.items-start').append('<div class="card draggable" data-sgqa="'+thisSGQA+'" data-code="'+thisCode+'">\
'+thisHTML+'\
</div>');
});
// Make the "cards" draggable
$('.draggable').draggable({
revert: "invalid",
zIndex: 2700,
helper: 'original',
start: function( event, ui ) {
$(ui.helper).addClass('ui-draggable-helper');
},
stop: function( event, ui ) {
}
});
// Set the targets for the draggables
$('.droppable.items-start').droppable({
hoverClass: 'target-hover',
accept: '.draggable.moved'
});
$('.droppable.items-end').droppable({
hoverClass: 'target-hover',
accept: '.draggable'
});
// After dropped
$('.droppable').bind('drop', function(event, ui) {
// Physically move the draggable to the target
// (the plugin just visually moves it)
// (need to use a clone here to fake out iPad)
var newDraggable = $(ui.draggable).clone();
$(newDraggable).appendTo(this);
$(ui.draggable).remove();
if($(this).hasClass('items-end')) {
$(newDraggable).addClass('moved');
}
else {
$(newDraggable).removeClass('moved');
}
$(newDraggable).removeClass('ui-draggable-helper ui-draggable-dragging').css({
'z-index':'',
'top':'auto',
'left':'auto'
});
// Now, make this new clone draggable
$(newDraggable).draggable({
revert: "invalid",
zIndex: 2700,
helper: 'original',
start: function( event, ui ) {
$(ui.helper).addClass('ui-draggable-helper');
},
stop: function( event, ui ) {
}
});
});
// Initial "card" positions
$('li.question-item input.text', thisQuestion).each(function(i) {
if($(this).val() > 0) {
$('.items-end[data-items-end="'+$(this).val()+'"]').append($('.card[data-sgqa="'+$(this).attr('name')+'"]'));
$('.card[data-sgqa="'+$(this).attr('name')+'"]').appendTo($('.items-end[data-items-end="'+$(this).val()+'"]')).addClass('moved');
}
});
// Interrupt the Next/Submit function and load the inputs
$('form#limesurvey').submit(function(){
$('.question-item input.text', thisQuestion).val(0);
$('.droppable.items-end .card', thisQuestion).each(function(i) {
var thisItemsEnd = $(this).closest('.droppable.items-end').attr('data-items-end');
var thisID = $(this).attr('data-sgqa');
$('#answer'+thisID+'').val(thisItemsEnd);
});
});
}
2) Then call it it the source of the question like this:
Code:
<script type="text/javascript" charset="utf-8">
$(document).ready(function() {
cardSort({QID});
});
</script>
3) Add some style rules to the end of
template.css like this:
Code:
/* Card Sort */
.card-sort-question ul.subquestions-list {
/*display: none;
clear: both;*/
}
.card-sort-question .items-start {
float: left;
width: 340px;
height: 317px;
margin-top: 8px;
border: 1px solid #666;
-moz-border-radius: 6px;
-webkit-border-radius: 6px;
-khtml-border-radius: 6px;
border-radius: 6px;
}
.card-sort-question .items-start.target-hover {
background:#C9C9C9;
}
.card-sort-question .items-end-wrapper {
float: left;
margin-left: 20px;
width: 340px;
}
.card-sort-question .items-end {
width: 338px;
min-height: 73px;
margin-bottom: 10px;
padding-bottom: 5px;
border: 1px solid #666;
-moz-border-radius: 6px;
-webkit-border-radius: 6px;
-khtml-border-radius: 6px;
border-radius: 6px;
background: #EBEBEB;
}
.card-sort-question .items-end.target-hover {
background: #C9C9C9;
}
.card-sort-question .items-end.ui-state-disabled {
opacity: 1;
filter:alpha(opacity=100);
}
.card-sort-question .items-end-text {
width: 338px;
padding-bottom: 5px;
background: #FFFFFF;
font-size: 110%;
font-weight: bold;
}
.card-sort-question .card {
display: inline-block;
width: 140px;
height: auto;
margin: 5px 8px;
padding: 3px;
border: 2px solid #2F4354;
-moz-border-radius: 8px;
-webkit-border-radius: 8px;
-khtml-border-radius: 8px;
border-radius: 8px;
background-color: #43b3d1;
color: #2f4354;
font-weight: bold;
text-align: center;
line-height: normal;
}
.card-sort-question .items-end .card {
margin: 5px 7px;
}
.card-sort-question div.answer {
clear: both;
padding-top: 1px;
margin-top: 0;
}
Sample template:
Sample survey: