Created
August 19, 2011 15:29
-
-
Save jpcody/1157078 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /** | |
| * 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