Adding JS files for use in Surveys.
authorDaniel Diniz <ajaksu@gmail.com>
Sat, 27 Jun 2009 09:35:50 +0200
changeset 2423 d6b4be046c26
parent 2422 44c500fc0eca
child 2424 51cf7a0c00a4
Adding JS files for use in Surveys. Patch by: Daniel Diniz, James Levy Reviewed by: Mario Ferraro
app/soc/content/js/survey-default-text-090627.js
app/soc/content/js/survey-edit-090627.js
app/soc/content/js/survey-take-090627.js
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/app/soc/content/js/survey-default-text-090627.js	Sat Jun 27 09:35:50 2009 +0200
@@ -0,0 +1,91 @@
+ /* Copyright 2009 the Melange authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+*
+* @author <a href="mailto:ajaksu@gmail.com">Daniel Diniz</a>
+* @author <a href="mailto:jamesalexanderlevy@gmail.com">James Levy</a>
+*/
+
+(function ($) {
+
+  var map = [];
+
+  $.preserveDefaultText = {
+
+    ShowAll: function () {
+      for (var i = 0; i < map.length; i = i + 1) {
+        if (map[i].obj.val() === "") {
+          map[i].obj.val(map[i].text);
+          map[i].obj.css("color", map[i].WatermarkColor);
+        }
+        else {
+          map[i].obj.css("color", map[i].DefaultColor);
+        }
+      }
+    },
+
+    HideAll: function () {
+      for (var i = 0; i < map.length; i = i + 1) {
+        if (map[i].obj.val() === map[i].text) {
+          map[i].obj.val("");
+        }
+      }
+    }
+  };
+
+  $.fn.preserveDefaultText = function (text, color) {
+
+    if (!color) {
+      color = "#aaa";
+    }
+
+    return this.each(
+      function () {
+        var input = $(this);
+        var defaultColor = input.css("color");
+
+        map[map.length] = {
+          text: text,
+          obj: input,
+          DefaultColor: defaultColor,
+          WatermarkColor: color
+        };
+
+        function clearMessage() {
+          if (input.val() === text) {
+            input.val("");
+          }
+          input.css("color", defaultColor);
+        }
+
+        function insertMessage() {
+          if (input.val().length === 0 || input.val() === text) {
+            input.val(text);
+            input.css("color", color);
+          }
+          else {
+            input.css("color", defaultColor);
+          }
+        }
+
+        input.focus(clearMessage);
+        input.blur(insertMessage);
+        input.change(insertMessage);
+
+        insertMessage();
+      });
+  };
+}(jQuery));
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/app/soc/content/js/survey-edit-090627.js	Sat Jun 27 09:35:50 2009 +0200
@@ -0,0 +1,715 @@
+ /* Copyright 2009 the Melange authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+*
+* @author <a href="mailto:ajaksu@gmail.com">Daniel Diniz</a>
+* @author <a href="mailto:jamesalexanderlevy@gmail.com">James Levy</a>
+*/
+
+(function ($) {
+
+  var DEFAULT_LONG_ANSWER_TEXT = 'Write a Custom Prompt For This Question...';
+  var DEFAULT_SHORT_ANSWER_TEXT = 'Write a Custom Prompt...';
+
+  $(function () {
+    /*
+    * == Set Selectors ==
+    *
+    */
+    var widget = $('div#survey_widget');
+
+    widget.parents('td.formfieldvalue:first').css({
+      'float': 'left',
+      'width': 200
+    });
+
+    /*
+    * == Setup for existing surveys ==
+    *
+    */
+
+    if ($('input#id_title').val() === '' && $('.formfielderror').length < 1) {
+      widget.find('tr').remove();
+    }
+
+    widget.find('table:first').show();
+
+    /*
+    *  Restore survey content html from editPost
+    *  if POST fails
+    */
+
+    var SURVEY_PREFIX = 'survey__';
+    var del_el = ["<a class='delete'><img '",
+                  "src='/soc/content/images/minus.gif'/></a>"].join("");
+    var del_li = ["<a class='delete_item' id='del_",
+                  "' ><img src='/soc/content/images/minus.gif'/></a> "];
+
+    var survey_html = $('form').find("#id_survey_html").attr('value');
+
+    function renderHTML() {
+      // render existing survey forms
+      widget.find('td > label').prepend(del_el).end();
+
+      $('ol').find('li').each(
+        function () {
+          $(this).prepend(del_li.join($(this).attr('id'))).end();
+        }
+      );
+      widget.find('.short_answer').each(
+        function () {
+          $(this).attr('name', SURVEY_PREFIX + $(this).getPosition() +
+                             'short_answer__' + $(this).attr('name'));
+        }
+      );
+
+      widget.find('.long_answer').each(
+        function () {
+          $(this).attr('name', SURVEY_PREFIX + $(this).getPosition() +
+                             'long_answer__' + $(this).attr('name'))
+          .attr('overflow', 'auto');
+          // TODO: replace scrollbar with jquery autogrow
+        }
+      );
+    }
+
+    if (survey_html && survey_html.length > 1) {
+      widget.html(survey_html); // we don't need to re-render HTML
+
+      widget.find('.long_answer,input').each(
+        function () {
+          $(this).val($(this).attr('val'));
+        }
+      );
+    }
+    else {
+      renderHTML();
+    }
+
+    var survey = widget.find('tbody:first');
+    var options = widget.find('#survey_options');
+
+    /*
+    * == Handle Enter key on dialogs ==
+    */
+    $('form input, form button, form select').keypress(
+      function (e) {
+        if ((e.which && e.which === 13) || (e.keyCode && e.keyCode === 13)) {
+          $(this).parents('.ui-dialog:first').find(":button:first").click();
+          return false;
+        }
+      }
+    );
+
+    /*
+    * == Display survey answers inline ==
+    */
+    $('a.fetch_answers').click(
+      function () {
+        var user = this.id.replace('results_for_', '');
+        var path = window.location.pathname;
+        path = path.replace('/edit/', '/show/').replace('/results/', '/show/');
+
+        // TODO(ajaksu) add Date().getTime() to query arg if needed
+        var query = '?read_only=true&user_results=' + user;
+        var scrollable = ['<div style="overflow-y: auto; ',
+                          'margin-bottom: 100px;"></div>'].join("");
+        $(scrollable).load(path + query + ' #survey_widget').dialog({
+          title: user,
+          height: 500,
+          width: 700
+        });
+      }
+    );
+
+    /*
+    * == Initiation ==
+    *
+    * Runs on PageLoad and Each Time Field is Added to Survey
+    *
+    */
+
+    survey.bind('init',
+      function () {
+        // TODO(jamslevy) unnecessarily redundant
+        // TODO(jamslevy) This should be refactored as a jQuery function that
+        // acts on only a single field and it should be merged with renderHTML
+        // since they have comparable functionality.
+
+        widget.find('input').each(
+          function () {
+            if (($(this).val().length < 1 ||
+            $(this).val() === DEFAULT_SHORT_ANSWER_TEXT) &&
+            ($(this).attr('type') !== 'hidden')) {
+              $(this).preserveDefaultText(DEFAULT_SHORT_ANSWER_TEXT);
+            }
+          }
+        );
+
+        widget.find('.long_answer').each(
+          function () {
+            if ($(this).val().length < 1 ||
+            $(this).val() === DEFAULT_LONG_ANSWER_TEXT) {
+              $(this).preserveDefaultText(DEFAULT_LONG_ANSWER_TEXT);
+            }
+            $(this).growfield();
+          }
+        );
+
+        widget.find('a.delete img').click(
+          function () {
+            // delete a field
+            var this_field = $(this).parents('tr:first');
+            var deleted_id = $(this_field).find('label').attr('for');
+            var delete_this = confirm(["Deleting this field will remove all ",
+                                       "answers submitted for this field. ",
+                                       "Continue?"].join(""));
+            if (delete_this) {
+              var edit_form = $('#EditForm');
+              var deleted_field = $('#__deleted__');
+              if (deleted_field.val()) {
+                deleted_field.val(deleted_field.val() + ',' +
+                                  deleted_id.replace('id_', '')).end();
+              }
+              else {
+                var deleted_input = $("<input type='hidden' value='" +
+                                      deleted_id.replace('id_', '') + "' />");
+                deleted_input.attr({'id': '__deleted__'}).attr({
+                  'name': '__deleted__'
+                });
+                edit_form.append(deleted_input);
+              }
+              this_field.remove();
+            }
+          }
+        );
+
+        // Add list/choice-field item to survey
+        $('[name=create-option-button]').each(
+          function () {
+            $(this).click(
+              function () {
+                var new_option_val = $('#new_item_field_ul_id');
+                var new_option_dialog = $("#new_item_dialog");
+
+                new_option_val.val($(this).parents('fieldset').children('ol')
+                .attr('id'));
+
+                new_option_dialog.dialog('open').find('input:first').focus();
+              }
+            )
+            .hover(
+              function () {
+                $(this).addClass("ui-state-hover");
+              },
+              function () {
+                $(this).removeClass("ui-state-hover");
+              }
+            )
+            .mousedown(
+              function () {
+                $(this).addClass("ui-state-active");
+              }
+            )
+            .mouseup(
+              function () {
+                $(this).removeClass("ui-state-active");
+              }
+            );
+          }
+        );
+
+        options.find('.AddQuestion').click(
+          function (e) {
+            // Choose a field type
+            $("#new_question_button_id").val($(this).attr('id'));
+            var question_options_div = $('#question_options_div');
+            if ($(this).attr('id') === 'choice')  {
+              question_options_div.show();
+            }
+            else {
+              question_options_div.hide();
+            }
+
+            $("#new_question_dialog").dialog('open').find('input:first')
+            .focus();
+          }
+        );
+      }).trigger('init')
+      .bind('option_init',
+        function () {
+
+          // Delete list/choice-field item from survey
+          widget.find('a.delete_item').click(
+            function () {
+              var to_delete = this.id.replace('del_', '');
+              $('#delete_item_field').val(to_delete);
+              $('#delete_item_dialog').dialog('open');
+            }
+          ).end();
+
+        }
+      ).trigger('option_init');
+
+
+    /* GSOC ROLE-SPECIFIC FIELD PLUGIN
+    * Choice between student/mentor renders required GSOC specific fields
+    */
+
+    var taking_access_field = $('select#id_taking_access');
+
+    var addRoleFields = function (role_type) {
+      // these should ideally be generated with django forms
+      // TODO: apply info tooltips
+      var CHOOSE_A_PROJECT_FIELD = [
+        '<tr class="role-specific"><th><label>Choose Project:</label></th>',
+        '<td> <select disabled=TRUE id="id_survey__NA__selection__project"',
+        ' name="survey__1__selection__see"><option>Survey Taker\'s Projects',
+        'For This Program</option></select> </td></tr>'
+      ].join("");
+
+      var CHOOSE_A_GRADE_FIELD = [
+        '<tr class="role-specific"><th><label>Assign Grade:</label></th><td>',
+        '<select disabled=TRUE id="id_survey__NA__selection__grade"',
+        'name="survey__1__selection__see"><option>Pass/Fail</option></select>',
+        '</td></tr>'
+      ].join("");
+
+      // flush existing role-specific fields
+      var role_specific_fields = survey.find('tr.role-specific');
+      role_specific_fields.remove();
+
+      switch (role_type) {
+      case "mentor evaluation":
+        survey.prepend(CHOOSE_A_PROJECT_FIELD);
+        survey.append(CHOOSE_A_GRADE_FIELD);
+        break;
+
+      case "student evaluation":
+        survey.prepend(CHOOSE_A_PROJECT_FIELD);
+        break;
+      }
+    };
+
+    taking_access_field.change(
+      function () {
+        var role_type = $(this).val();
+        addRoleFields(role_type);
+      }
+    );
+
+    addRoleFields(taking_access_field.val());
+
+    /*
+    * == Survey Submission Handler ==
+    */
+    // Bind submit
+    $('form').bind('submit',
+      function () {
+
+        /*
+        * get rid of role-specific fields
+        */
+        survey.find('tr.role-specific').remove();
+
+        /*
+        * Save survey content html from editPost
+        * if POST fails
+        */
+
+        // save field vals
+        widget.find('.long_answer,input').each(
+          function () {
+            $(this).attr('val', $(this).val());
+          }
+        );
+
+        $(this).find("#id_survey_html").attr('value', widget.html());
+
+        // don't save default value
+        widget.find('input').each(
+          function () {
+            if ($(this).val() === DEFAULT_SHORT_ANSWER_TEXT) {
+              $(this).val('');
+            }
+          }
+        );
+
+        // don't save default value
+        widget.find('.long_answer').each(
+          function () {
+            if ($(this).val() === DEFAULT_LONG_ANSWER_TEXT) {
+              $(this).val('');
+            }
+          }
+        );
+
+        // get rid of the options
+        $('input#id_s_html')
+        .val(
+          widget
+          .find(
+            'div#survey_options'
+          )
+          .remove()
+          .end()
+          .html()
+        );
+        // only needed for HTML
+
+        // Get option order per field
+        survey.find('.sortable').each(
+          function () {
+            $('#order_for_' + this.id)
+            .val(
+              $(this).sortable(
+                'serialize'
+              )
+            );
+          }
+        );
+      }
+    );
+  });
+}(jQuery));
+
+
+(function ($) {
+  /*
+  * == Utils ==
+  *
+  */
+  jQuery.fn.extend({
+
+    // get position of survey field
+    getPosition: function () {
+      var this_row = $(this).parents('tr:first');
+      var this_table = this_row.parents('table:first');
+      var position = this_table.find('tr').index(this_row) + '__';
+      return position;
+    }
+  });
+}(jQuery));
+
+
+(function ($) {
+  /*
+  * == Sortable options ==
+  */
+  $(function () {
+    $(".sortable").each(
+      function (i, domEle) {
+        $(domEle).sortable().disableSelection().end();
+      }
+    );
+  });
+}(jQuery));
+
+
+(function ($) {
+  /*
+  * == Editable options ==
+  */
+  $(function () {
+    function onSubmitEditable(content) {
+      var id_ = $(this).parent().attr('id').replace('-li-', '_');
+      id_ = id_ + '__field';
+      $('#' + id_).val(content.current);
+    }
+    $('.editable_option').editable({
+      editBy: 'dblclick',
+      submit: 'change',
+      cancel: 'cancel',
+      onSubmit: onSubmitEditable
+    });
+  });
+}(jQuery));
+
+
+(function ($) {
+  $(function () {
+  var del_li = ["<a class='delete_item' id='del_",
+                "' ><img src='/soc/content/images/minus.gif'/></a> "];
+
+    // Confirmation dialog for deleting list/choice-field item from survey
+    $("#delete_item_dialog").dialog({
+      autoOpen: false,
+      bgiframe: true,
+      resizable: false,
+      height: 300,
+      modal: true,
+      overlay: {
+        backgroundColor: '#000',
+        opacity: 0.5
+      },
+      buttons: {
+        'Delete this item': function () {
+          $('#' + $('#delete_item_field').val()).remove();
+          $('#delete_item_field').val('');
+          $(this).dialog('close');
+        },
+        Cancel: function () {
+          $('#delete_item_field').val('');
+          $(this).dialog('close');
+        }
+      }
+    });
+
+
+    //  Dialog for adding list/choice-field item to survey
+    $("#new_item_dialog").dialog({
+      bgiframe: true,
+      autoOpen: false,
+      height: 300,
+      modal: true,
+      buttons: {
+        'Add option': function () {
+          var ol_id =  $('#new_item_field_ul_id').val();
+          var ol = $('#' + ol_id);
+          var name = $('#new_item_name').val();
+          var i = ol.find('li').length;
+          var id_ = 'id_' + ol_id + '_' + i;
+          var option_html = $([
+            '<li id="id-li-', ol_id, '_', i,
+            '" class="ui-state-defaolt sortable_li">',
+            '<span class="ui-icon ui-icon-arrowthick-2-n-s"></span>',
+            '<span id="', id_, '" class="editable_option" name="', id_,
+            '__field">', name, '</span>', '<input type="hidden" id="', id_,
+            '__field" name="', id_, '__field" value="', name, '" >', '</li>'
+          ].join(""));
+
+          ol.append(
+            option_html
+            .prepend(
+              del_li.join(
+                option_html.attr('id')
+              )
+            )
+          );
+          ol.sortable().disableSelection();
+          $('#new_item_name').val('');
+          $('#new_item_field_ol_id').val('');
+          $(this).dialog('close');
+        },
+        Cancel: function () {
+          $('#new_item_name').val('');
+          $('#new_item_field_ul_id').val('');
+          $(this).dialog('close');
+        }
+      }
+    });
+  });
+}(jQuery));
+
+
+(function ($) {
+  $(function () {
+    //  Dialog for adding new question to survey
+    var SURVEY_PREFIX = 'survey__';
+    var del_el = ["<a class='delete'><img '",
+              "src='/soc/content/images/minus.gif'/></a>"].join("");
+    var del_li = ["<a class='delete_item' id='del_",
+                  "' ><img src='/soc/content/images/minus.gif'/></a> "];
+
+
+    var widget = $('div#survey_widget');
+    var survey = widget.find('tbody:first');
+
+    $("#new_question_dialog").dialog({
+      bgiframe: true,
+      autoOpen: false,
+      height: 400,
+      modal: true,
+      buttons: {
+        'Add question': function () {
+          var button_id = $("#new_question_button_id").val();
+          var survey_table = $('div#survey_widget').find('tbody:first');
+          $("#new_question_button_id").val('');
+
+          var field_template =  $(["<tr><th><label>", del_el,
+                                   "</label></th><td>  </td></tr>"].join(""));
+
+          var field_name = $("#new_question_name").val();
+          var question_content = $("#new_question_content").val();
+          var question_options = $("#new_question_options").val();
+
+          if (field_name !== '') {
+            $("#new_question_name").val('');
+            $("#new_question_content").val('');
+            $("#new_question_options").val('');
+
+            var new_field = false;
+            var type = button_id + "__";
+            var field_count = survey_table.find('tr').length;
+            var new_field_count = field_count + 1 + '__';
+
+            var MIN_ROWS = 10;
+            var MAX_ROWS = MIN_ROWS * 2;
+            var DEFAULT_OPTION_TEXT = 'Add A New Option...';
+            var default_option = ["<option>", DEFAULT_OPTION_TEXT,
+                                  "</option>"].join("");
+
+            // create the HTML for the field
+            switch (button_id) {
+            case "short_answer":
+              new_field = "<input type='text'/ class='short_answer'>";
+              break;
+            case "long_answer":
+              new_field = ["<textarea cols='40' rows='", MIN_ROWS,
+                           "' class='long_answer'/>"].join("");
+              break;
+            case "selection":
+              new_field = ["<select><option></option>", default_option,
+                           "</select>"].join("");
+              break;
+            case "pick_multi":
+              new_field = ["<fieldset class='fieldset'><input type='button'",
+                           "value='", DEFAULT_OPTION_TEXT, "' /></fieldset>"]
+                          .join("");
+              break;
+            case "choice":
+              new_field = ["<fieldset class='fieldset'><input type='button'",
+                           "value='", DEFAULT_OPTION_TEXT, "' /></fieldset>"]
+                          .join("");
+              break;
+            }
+
+            if (new_field) {
+              var question_for = [
+                '\n  <input type="hidden" name="NEW_', field_name,
+                '" id="NEW_', field_name, '" value="', question_content,
+                '"/>'
+              ].join("");
+
+              field_count = survey_table.find('tr').length;
+              new_field_count = field_count + 1 + '__';
+              var formatted_name = (SURVEY_PREFIX + new_field_count + type +
+                                    field_name);
+              if (button_id === 'choice')  {
+                var name = (field_name);
+                new_field = $([
+                  '<fieldset>\n <label for="render_for_', name,
+                  '">Render as</label>', '\n  <select id="render_for_', name,
+                  '" name="render_for_', name, '">', '\n    <option',
+                  'selected="selected" value="select">select</option>',
+                  '\n    <option value="checkboxes">checkboxes</option>',
+                  '\n    <option value="radio_buttons">radio_buttons</option>',
+                  '\n  </select>', '\n  <input type="hidden" id="order_for_',
+                  name, '\n  " name="order_for_', name, '" value=""/>',
+                  '\n  <input type="hidden" id="index_for_', name,
+                  '\n  " name="index_for_', name, '" value="',
+                  (field_count + 1), '"/>\n  <ol id="', name,
+                  '" class="sortable"></ol>',
+                  question_for, '\n  <button name="create-option-button"',
+                  'id="create-option-button__', name,
+                  '" class="ui-button ui-state-default ui-corner-all" value="',
+                  name, '" onClick="return false;">Create new option',
+                  '</button>\n</fieldset>'
+                ].join(""));
+
+                $(new_field).attr({
+                  'id': 'id_' + formatted_name,
+                  'name': formatted_name
+                });
+                field_template
+                .find(
+                  'label'
+                )
+                .attr(
+                  'for',
+                  'NEW_' + name
+                )
+                .append(question_content).end()
+                .find(
+                  'td'
+                )
+                .append(new_field);
+                survey_table.append(field_template).end();
+
+                if (question_options) {
+
+                  var options_array = question_options.split('\n');
+                  var ol = $('#' + name);
+                  var length = options_array.length;
+                  var oname = '';
+                  var id_ = '';
+                  var option_html = '';
+
+                  for (var i = 0; i < length; i = i + 1) {
+                    id_ = 'id_' + name + '_' + i;
+                    oname = options_array[i];
+                    option_html = $([
+                      '<li id="id-li-', name, '_', i,
+                      '" class="ui-state-defaolt sortable_li">',
+                      '<span class="ui-icon ui-icon-arrowthick-2-n-s"></span>',
+                      '<span id="' + id_ + '" class="editable_option" name="',
+                      id_, '__field">', oname, '</span>', '<input ',
+                      'type="hidden" id="', id_, '__field" name="', id_,
+                      '__field" value="', oname, '" >', '</li>'
+                    ].join(""));
+                    ol.append(option_html.prepend(
+                      del_li.join(option_html.attr('id'))));
+                    ol.sortable().disableSelection();
+                  }
+
+                  survey.trigger('option_init');
+                }
+              }
+
+              else {
+                new_field = $(new_field);
+                // maybe the name should be serialized in a more common format
+                $(new_field).attr({
+                  'id': 'id_' + formatted_name,
+                  'name': formatted_name
+                });
+                field_template.find(
+                  'label'
+                )
+                .attr(
+                  'for',
+                  'id_' + formatted_name
+                )
+                .append(question_content + ":").end()
+                .find(
+                  'td'
+                )
+                .append(new_field).append($(question_for));
+
+                survey_table.append(field_template);
+              }
+
+              survey.trigger('init');
+
+            }
+          }
+          $("#new_question_name").val('');
+          $("#new_question_content").val('');
+          $("#new_question_options").val('');
+          $(this).dialog('close');
+        },
+
+        Cancel: function () {
+          $('#new_question_name').val('');
+          $("#new_question_button_id").val('');
+          $("#new_question_content").val('');
+          $("#new_question_options").val('');
+          $(this).dialog('close');
+        }
+      }
+    });
+  });
+}(jQuery));
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/app/soc/content/js/survey-take-090627.js	Sat Jun 27 09:35:50 2009 +0200
@@ -0,0 +1,152 @@
+/* Copyright 2009 the Melange authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+*
+* @author <a href="mailto:ajaksu@gmail.com">Daniel Diniz</a>
+* @author <a href="mailto:jamesalexanderlevy@gmail.com">James Levy</a>
+*/
+
+(function ($) {
+  $(function () {
+
+    /*
+    * == Setup Survey on Page Load ==
+    *
+    */
+
+    var widget = $('div#survey_widget');
+    widget.parents('td.formfieldvalue:first').css({
+      'float': 'left',
+      'width': 200
+    });
+
+    // TODO(ajaksu) survey below is unused, remove if no known use is predicted
+    var survey = widget.find('tbody:first');
+
+    if (widget.hasClass('create')) {
+
+      /*
+      * == Set Custom Field Rules ==
+      *
+      */
+      widget.find('input').each(
+        function () {
+          $(this).preserveDefaultText($(this).val());
+        }
+      );
+
+      widget.find('textarea').each(
+        function () {
+          $(this).preserveDefaultText($(this).val()).attr('overflow', 'auto')
+          .growfield();
+        }
+      );
+    }
+
+    else { // survey has saved results
+      widget.find('textarea').each(
+        function () {
+          $(this).attr('overflow', 'auto').growfield();
+        }
+      ).end()
+      .find('.pick_multi').each(
+        function () {
+          $(this).find('input').each(
+            function () {
+              // if $(this).attr('checked', 'true');});
+            }
+          );
+        }
+      );
+    }
+
+    /*
+    * == Configure Project ==
+    *
+    */
+
+    // remember if form has been touched
+    $('input,textarea,select').change(
+      function () {
+        if ($(this).attr('id') === 'id_project') {
+          return;
+        }
+        $('form:first').data('touched', true);
+      }
+    );
+
+  // remember initially chosen project choice
+    $('select#id_project').blur(
+      function () {
+        $(this).data('selected', $(this).find('option:first'));
+      }
+    ).change(
+      function () {
+        if ($('form:first').data('touched') === true) {
+          // if form has been touched, send confirmation dialog
+          var save_check = confirm(["Switching projects will lose unsaved ",
+                                    "edits made to this survey."].join(""));
+          if (!save_check) {
+            $(this).data('selected').attr('selected', 'selected');
+            return false;
+          }
+        }
+
+        if ($(this).val() !== 'None') {
+          // redirect with new project GET param
+          window.location = [window.location.href.split('?')[0],  "?project=",
+                             $(this).val()].join("");
+        }
+      }
+    );
+
+    // insert project link after project select field
+    $('div#project_link').insertAfter($('select#id_project')).show();
+
+    /*
+    * == Survey Submission Handler ==
+    *
+    */
+
+    // validate form
+    $('input[type=submit]').bind(
+      'click',
+      function (e) {
+        e.preventDefault();
+
+        // validate project and grade choice fields
+        if ($('select#id_project') &&
+        $('select#id_project').val() === 'None') {
+          return alert('Please Choose a Project');
+        }
+
+        if ($('select#id_grade') && $('select#id_grade').val() === 'None') {
+          return alert('Please Choose a Grade');
+        }
+        $('form').trigger('submit');
+
+      }
+    );
+
+    $('form').bind('submit',
+      function () {
+        $('input#id_s_html').val(
+          widget.find('div#survey_options').remove().end().html()
+        );
+      }
+    );
+  });
+}(jQuery));