Skip to content

Instantly share code, notes, and snippets.

@jpcody
Created August 19, 2011 15:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jpcody/1157078 to your computer and use it in GitHub Desktop.
Save jpcody/1157078 to your computer and use it in GitHub Desktop.
/**
* QUESTION MAINTENANCE OPERATIONS
*
* This object contains the code to handle question maintenance. That includes, but is
* not limited to, switching to view administrative vs applicant questions, updating the
* qualification status of a given question, and selecting a new question to add.
*
*/
SM.adminQuestions = {
init : function(){
this.addAndRemove.init();
SM.misc.makeSortable.init( $('tbody'), this.addAndRemove.updateAfterDrag );
},
// handles the addition and removal of questions from the list of asked questions and
// the bank of unasked questions
addAndRemove : {
config : {
currentVisibility : null
},
init : function(){
this.doDomBindings();
},
doDomBindings : function(){
var that = this,
$unaskedQuestions = $('.unasked-questions'),
$addQuestion = $('.add-question'),
$toggleView = $('.create-question, .cancel-new-question'),
$questionLists = $('.question-list'),
editQuestion = '.edit-question, .cancel-question-edit',
removeQuestion = '.remove-asked-question',
$editFormField = $('.edit-form-field'),
$previewType = $('.form-type-preview'),
typeSelect = '.type-select',
addChoice = '.add-new-choice',
$showSetQuestions = $('.show-set-questions'),
addSetQuestion = '.add-question-to-set',
requiredFields = 'fieldset.has-requirements input.required',
$submitQuestion = $('.submit-new-question'),
showHelp = '.show-help',
addQuestionRow = '.add-unasked-question';
// DISPLAY THE LIST OF UNASKED QUESTIONS
$addQuestion.click(function(e){
e.preventDefault();
that.config.currentVisibility = $(this).attr('data-visibility');
that.displayUnaskedQuestions($(this));
});
// SWITCH BETWEEN LIST OF UNASKED QUESTIONS AND NEW CREATION FORM
$toggleView.click(function(e){
e.preventDefault();
that.toggleCreateOrAdd( $(this) );
});
$questionLists.delegate(removeQuestion, 'click', function(e){
e.preventDefault();
var $row = $(this).closest('tr').prev('tr');
that.removeQuestionRow( $row, that.prepareExistingQuestion($row));
});
$questionLists.delegate(editQuestion, 'click', function(e){
e.preventDefault();
that.toggleQuestionEditor( $(this) );
});
$previewType.click(function(e){
e.preventDefault();
var $container = $(this).closest('div').find('.type-samples');
SM.baseFormFields.previewQuestionType( $container );
});
$unaskedQuestions.delegate(addChoice, 'click', function(e){
e.preventDefault();
SM.baseFormFields.addNewChoice( $(this) );
});
$unaskedQuestions.delegate(typeSelect, 'change', function(){
var $parent;
$parent = $(this).closest('.question-in-set').length ? $(this).closest('.question-in-set') : $(this).closest('fieldset');
SM.baseFormFields.displayProperFields( $(this), $parent );
});
$showSetQuestions.click(function(e){
e.preventDefault();
that.displayQuestionsForSet( $(this) );
});
$unaskedQuestions.delegate(addSetQuestion, 'click', function(e){
e.preventDefault();
that.addNewQuestionforSet( $(this) );
});
$unaskedQuestions.delegate(requiredFields, 'keyup', function(){
that.checkRequirements($(this).closest('fieldset'));
});
$submitQuestion.click(function(e){
e.preventDefault();
that.submitQuestion( $(this).closest('form') );
});
$unaskedQuestions.delegate(showHelp, 'click', function(e){
e.preventDefault();
var $nextContainer = $(this).closest('div.full-width-rows').next('div.hidden');
$nextContainer.slideDown(100, function(){
$(this).removeClass('hidden');
$(this).removeAttr('style');
});
SM.misc.wysiwyg.buildIt($nextContainer.find('textarea'));
});
$editFormField.click(function(e){
e.preventDefault();
var formFieldId = $(this).attr('data-form-field-id'),
formFieldType = $(this).attr('data-form-field-type') === "QuestionSet" ? "FormFieldSet" : "FormField";
that.displayFormFieldDetails( formFieldId, formFieldType );
});
$questionLists.delegate(addQuestionRow, 'click', function(e){
e.preventDefault();
var $this = $(this);
$this.closest('tr').remove();
that.addQuestionRow( that.prepareExistingQuestion($this.closest('tr')));
});
},
prepareNewQuestion : function( data ){
var obj = {
id : data.id,
label : data.label,
fieldType : data.klass,
isRequired : false,
isReviewable : data.reviewer_visible,
isQuestionSet : function(){
return data.klass === "QuestionSet";
},
isAdding : function(){
return true;
}
};
return obj;
},
prepareExistingQuestion : function( $row ){
var obj = {
id : $row.attr('data-field-id'),
label : $row.find('.label').text(),
fieldType : $row.find('.type').text(),
isRequired : $row.find('.required').text() === "Optional" ? "<span class='deemphasize'>Optional</span>" : "Required",
isReviewable : $row.find('.reviewable').text() === "Yes" ? "Yes" : "No",
isSetOfQuestions : function(){
return $row.find('.type').text().replace(/\s/g, '') === "QuestionSet";
}
};
return obj;
},
addQuestionRow : function( obj ){
obj.isAdding = true;
obj.isRemoving = false;
var rowTpl = SM.templates.questions.questionRow,
editTpl = SM.templates.questions.questionRowEdit,
newRow = Mustache.to_html(rowTpl, obj),
newEdit = Mustache.to_html(editTpl, obj);
// go ahead and build a new row from our HTML
var $newRow = $(newRow).prependTo( $('#specific_' + this.config.currentVisibility + '_questions_asked')
.find('tbody')).effect('highlight');
$(newEdit).insertAfter($newRow);
$('.lightboxed:visible').find('a.close').click();
this.checkForEmptyRows( $newRow.closest('tbody'));
},
removeQuestionRow : function( $row, obj ){
obj.isAdding = false;
obj.isRemoving = true;
var rowTpl = SM.templates.questions.questionRow,
newRow = Mustache.to_html(rowTpl, obj);
// pull out our editing buddy, the actual row, then prepend it over on the other side
$row.next('tr').remove();
$row.remove();
$(newRow).prependTo($("#common_" + this.config.currentVisibility + "_questions_not_asked").find('tbody'));
this.checkForEmptyRows( $row.closest('tbody'));
},
checkForEmptyRows : function( $fieldset ){
var shownRows = $fieldset.find('tr').not(':last').length,
$lastRow = $fieldset.find('tr.last');
$lastRow[ shownRows ? 'addClass' : 'removeClass' ]('hidden');
},
displayFormFieldDetails : function( formFieldId, formFieldType ){
var that = this;
$.ajax( '/admin/form_field_collections/' + formFieldId + '/edit?klass=' + formFieldType, {
success : function(a){
$newDiv = $('<div>', {
'class' : 'section lightboxed',
html : a
});
$newDiv.lightbox_me({
overlayCSS : {
background : '#000000',
opacity : 0.5
},
onLoad : function(){ that.checkRequirements( $newDiv.find('fieldset')); },
destroyOnClose : true
});
},
type : 'GET',
dataType : 'html'
});
},
updateAfterDrag : function(e, ui){
var $dragged = $(ui.item[0]),
editorSelector = '#' + $dragged.attr('id').replace(/show/, 'edit'),
$draggedEditor = $(editorSelector);
$draggedEditor.insertAfter($dragged);
$dragged.find('button').show();
$dragged.removeClass('highlight');
$dragged.effect("highlight");
},
checkRequirements : function( $fieldset ){
var $requiredFields = $fieldset.find('input.required'),
unmet = _.any($requiredFields, function(el){ return $(el).val() === ''; }),
$submit = $('#' + $fieldset.attr('data-submit-id'));
if(!unmet){
$submit.animate({ opacity : 1.0 }, 100);
$submit.removeClass('disabled');
}
},
createEmptyQuestion : function( $trigger ){
var newHtml = Mustache.to_html( SM.templates.questions.questionInSet, {} );
$newHtml = $(newHtml).insertAfter( $trigger.closest('.add-choice') );
$newHtml.find('input.label').focus();
},
toggleQuestionDetails: function toggle( $trigger, $container, isContracted ){
var $container = $trigger.closest('.add-choice').prev('.question-in-set'),
$rows = $container.find('.full-width-rows'),
isContracted = isContracted || false,
$edit = $('<button>', {
'class' : 'tertiary button edit',
'text' : 'Edit'
});
$container.find('.full-width-rows').not(':first').not('.hidden')[ isContracted ? 'slideDown' : 'slideUp' ]( 100 );
if( isContracted ){
$($rows[0]).find('button.edit').remove();
$($rows[0]).find('input').removeClass('almost-full');
} else {
$($rows[0]).find('input').addClass('almost-full');
$edit.insertAfter($($rows[0]).find('input'));
$edit.click(function(e){
e.preventDefault();
toggle( $trigger, $container, true );
});
}
},
updateAddTrigger : function( $trigger ){
$trigger.parent('div').addClass('complete');
$trigger.hide();
},
addNewQuestionforSet : function( $trigger ){
this.toggleQuestionDetails( $trigger );
this.createEmptyQuestion( $trigger );
this.updateAddTrigger( $trigger );
},
displayQuestionsForSet : function( $trigger ){
var $form = $trigger.closest('form');
$trigger.closest('div.form-complete').hide();
$form.find('fieldset').removeClass('hidden');
$form.find('.question-in-set').addClass('active');
$form.find('.question-in-set input').eq(0).focus();
},
displayUnaskedQuestions : function( $trigger ){
var that = this;
$('#' + this.config.currentVisibility + '-unasked-questions').lightbox_me({
overlayCSS : {
background : '#000000',
opacity : 0.5
}
});
},
restoreDefaultState : function(){
},
transferQuestionText : function( $trigger, $form ){
var re = new RegExp('cancel', 'gi'),
isCancel = re.test($trigger.text()),
$starterQuestion = $('#' + this.config.currentVisibility + '-question-label-preview'),
$formLabel = $form.find('input.question-text').eq(0);
if(!isCancel && !($starterQuestion.val() === '')){ $formLabel.val($starterQuestion.val()); }
$starterQuestion.val('');
},
toggleCreateOrAdd : function( $trigger ){
var $newItem = $('#' + $trigger.attr('data-next-step')),
$oldItem = $trigger.closest('.question-step'),
text = $trigger.closest();
this.transferQuestionText( $trigger, $newItem );
$newItem.insertAfter($oldItem);
$oldItem.hide().insertAfter($('#unasked-questions'));
$newItem.show();
this.checkRequirements($newItem.find('fieldset:visible'));
},
toggleQuestionEditor : function( $trigger ){
var $row = $trigger.closest('tr'),
wasCancel = $row.hasClass('edit');
if(wasCancel){
$row.prev().removeClass('highlight');
$row.prev().find('button').show();
$row.addClass('hidden');
} else {
$row.addClass('highlight');
$row.next().removeClass('hidden');
$trigger.hide();
}
},
buildQuestionData : function( $form, formFieldSetData ){
var formFieldData,
vis = this.config.currentVisibility,
$reviewerVisibility = $form.find('.reviewable'),
applicantVisibility = this.config.currentVisibility === "applicant" ? true : false,
$reference = $form.find('.reference'),
$label = $form.find('.label'),
$overUnder = $form.find('.over-under'),
$type = $form.find('.type'),
$help = $form.find('.help'),
$valuesChoices = $form.find('.choices input'),
deferToSet = ["reviewer_visible", "applicant_visible", "required"];
formFieldData = {
klass : "FormField",
reviewer_visible : $reviewerVisibility.is(':checked'),
applicant_visible : applicantVisibility,
reference : $reference.is(':checked'),
label : $label.val(),
over_under : $overUnder.is(':checked'),
type : $type.val(),
help_message : $help.val(),
values : _.map($valuesChoices, function(el){ return $(el).val(); }),
availability : "personal"
};
if( formFieldSetData ){
_.each(deferToSet, function(field){ delete formFieldData[field]; });
return _.defaults(formFieldData, formFieldSetData);
} else {
return formFieldData;
}
},
buildFormFieldSetData : function( $form ){
var that = this,
formFieldSetData,
vis = this.config.currentVisibility,
applicantVisibility = this.config.currentVisibility === "applicant" ? true : false,
$label = $form.find('.label'),
$questions = $('.question-in-set.active'),
$reviewerVisibility = $form.find('.reviewable'),
passToFormField = ["reviewer_visible", "applicant_visible", "required"];
formFieldSetData = {
klass : "FormFieldSet",
label : $label.val(),
reviewer_visible : $reviewerVisibility.is(':checked'),
applicant_visible : applicantVisibility,
form_fields : [],
availability : "personal"
};
_.each($questions, function(el){
var reducedformFieldSetData,
formFieldData;
reducedformFieldSetData = _.reduce(formFieldSetData, function(memo, val, ind){
if(_.include(passToFormField, ind)){
memo[ind] = {};
memo[ind] = val;
}
return memo;
}, {});
formFieldData = that.buildQuestionData( $(el), reducedformFieldSetData);
formFieldSetData.form_fields.push(formFieldData);
});
return formFieldSetData;
},
submitQuestion : function( $form ){
var that = this,
isGroup = $form.attr('data-type') === "question-group",
formData,
postUrl = "/admin/form_field_collections";
formData = this[ isGroup ? 'buildFormFieldSetData' : 'buildQuestionData' ]($form);
$.ajax( postUrl, {
data : {'form_field_collection' : JSON.stringify(formData)},
dataType : 'json',
type : 'POST',
success : function(data){
that.addQuestionRow( that.prepareNewQuestion(data) );
},
error : function(a, b, c){
console.log(a);
}
});
}
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment