diff --git a/productMods/edit/forms/js/customForm.js b/productMods/edit/forms/js/customForm.js index 95d0233f..41cc2f0d 100644 --- a/productMods/edit/forms/js/customForm.js +++ b/productMods/edit/forms/js/customForm.js @@ -1,133 +1,246 @@ /* $This file is distributed under the terms of the license in /doc/license.txt$ */ +/* ADD new property form +/* Step 1: Initial step, with choice to select existing or add new secondary individual. + * Displays: + * - On page load, unless there are validation error messages in the form + * - if there are validation error messages in the form, we are returning from a failed + * submission, and will go directly to view 2 to display the error messages. + * - After cancelling out of step 2 + * + * Step 2: Main data entry step + * Displays: + * - On page load after an attempted submission that fails validation + * - After clicking button or add new link in view 1 + * Has three view variations: + * - Select an existing secondary individual view + * - Add new secondary individual view + * - Combined view, if we are returning from a failed validation and can't determine + * which variant of view 2 we had submitted the form from. Contains the select + * existing element plus the add new link. + * + * EDIT existing property form + * Looks like add form step 2 except shows add new link + * Has same three view variants as step 2 add form + * + */ + var customForm = { onLoad: function() { - // Create references to form elements. - // NB must be done after the elements have been loaded. + this.initObjects(); + this.adjustForJs(); + this.initForm(); + }, + + // On page load, create references within the customForm scope to DOM elements. + // NB These must be assigned after the elements have been loaded onto the page. + initObjects: function() { - this.form = $('#content form'), - this.button = $('#submit'), - this.requiredLegend = $('#requiredLegend'), + this.form = $('#content form'); + this.button = $('#submit'); + this.requiredLegend = $('#requiredLegend'); // These may need to be changed to classes rather than ids, if there are // multiple sets of divs to show/hide during the workflow. - this.addNewLink = $('#addNewLink'), - this.existing = $('#existing'), - this.addNew = $('#new'), - this.entry = $('#entry'), - this.existingOrNew = $('#existingOrNew'), + this.addNewLink = $('#addNewLink'); + this.existing = $('#existing'); + this.addNew = $('#new'); + this.entry = $('#entry'); + this.existingOrNew = $('#existingOrNew'); - this.cancel = this.form.find('.cancel'), - this.requiredHints = this.form.find('.requiredHint'), + this.cancel = this.form.find('.cancel'); + this.requiredHints = this.form.find('.requiredHint'); // Read values used to control display - this.editType = $("input[name='editType']").val(), - this.entryType = $("input[name='entryType']").val().capitalize(), + this.editType = $("input[name='editType']").val(); + this.entryType = $("input[name='entryType']").val().capitalize(); this.newType = $("input[name='newType']").val().capitalize(); - - this.adjustForJs(); - - if (this.editType == 'add') { //adding a new entry - this.initAddForm(); - - } else { // editing existing entry - this.initEditForm(); - } }, // On page load, make changes to the non-Javascript version for the Javascript version. - // These are features that will not change in the Javascript version. + // These are features that will NOT CHANGE throughout the workflow of the Javascript version.. adjustForJs: function() { - this.existingOrNew.hide(); - - var selectExistingLabel = $('#existing label'); - selectExistingLabel.html(selectExistingLabel.html().replace('Select Existing ', '')); - - }, - - // Reset add form to initial state (step 1) - // Should only be needed after returning to step 1 from step 2, - // but sometimes seems to be needed on page load as well, so call it from initAddForm() - resetAddForm: function() { - // Clear all form data and error messages - $('input:text').val(''); - $('.error').text(''); + var selectExistingLabel = $('#existing label'); + selectExistingLabel.html(selectExistingLabel.html().replace(/Select (Existing )?/, '')); - // Remove previously bound event handlers - this.cancel.unbind('click'); - this.button.unbind('click'); - this.addNewLink.unbind('click'); + this.existingOrNew.hide(); + }, + + initForm: function() { - this.toggleRequiredHints('remove', this.addNew, this.existing); + //Adding a new entry + if (this.editType == 'add') { + this.initAddForm(); + // Editing an existing entry + } else { + this.initEditForm(); + } + }, + + /***** ADD form *****/ + + // Set up add form on page load, or when returning to initial state from step 2 + initAddForm: function() { + + // If there are validation errors on the page, we're returning from + // an attempted submission that failed validation, and we need to go + // directly to step 2. + if (this.findValidationErrors()) { + this.doAddFormStep2(); + } else { + this.doAddFormStep1(); + } + + }, + + // Reset add form to initial state (step 1) after cancelling out of step 2 + resetAddFormToStep1: function() { + + this.resetForm(); + this.doAddFormStep1(); }, - // Set up add form on page load, or when returning to initial state - initAddForm: function() { + // Set up the add form for step 1 + doAddFormStep1: function() { - this.resetAddForm(); - - // Step 1 of the form - this.addNewLink.show(); this.existing.show(); + this.addNewLink.show(); this.addNew.hide(); this.entry.hide(); this.requiredLegend.hide(); this.button.val('Continue'); - // Assign event listeners - - // button => step 2a + // Assign event listeners + //this.button.unbind('click'); // RY *** Don't need this if we've done a reset this.button.bind('click', function() { - customForm.entry.show(); - customForm.showFields(customForm.existing); - customForm.addNewLink.hide(); - customForm.requiredLegend.show(); - - $(this).val('Create ' + customForm.entryType); - $(this).unbind('click'); - - customForm.doCancel(); - + customForm.doAddFormStep2SelectExisting(); return false; }); - // add new link => step 2b + //this.addNewLink.unbind('click'); // RY *** Don't need this if we've done a reset this.addNewLink.bind('click', function() { - $(this).hide(); - customForm.existing.hide(); - customForm.showFields(customForm.addNew); - customForm.entry.show(); - customForm.requiredLegend.show(); - - customForm.button.val('Create ' + customForm.entryType + ' & ' + customForm.newType); - customForm.button.unbind('click'); - - customForm.doCancel(); + customForm.doAddFormStep2AddNew(); }); }, + // Set up form when returning directly to step 2, such as after validation errors + // on the form submission. + doAddFormStep2: function() { + + // If possible, determine which view of the form we were on + var existingInputs = this.existing.find(':input'), + existingInputsLen = existingInputs.length, + addNewInputs = this.addNew.find(':input'), + addNewInputsLen = addNewInputs.length, + input, + i, + fn = null; + + // If a value was entered in the addNew section, go back to the addNew view + for (i = 0; i < addNewInputsLen; i++) { + input = $(addNewInputs[i]); + if (input.val() != '') { + fn = this.doAddFormStep2AddNew; + break; + } + } + + // If a value was selected in the existing section, go back to the existing view + if (fn === null) { + for (i = 0; i < existingInputsLen; i++) { + input = $(existingInputs[i]); + if (input.val() != '') { + fn = this.doAddFormStep2SelectExisting; + break; + } + } + } + + // Otherwise, default to the combined view + // (same as view used to edit existing entry) + if (fn === null) { + fn = this.doAddFormStep2Combined; + } + + fn.call(); + }, + + // Step 2: selecting an existing individual + doAddFormStep2SelectExisting: function() { + + // NB Use 'customForm' instead of 'this', because 'this' + // doesn't reference customForm when called from an event handler. + customForm.entry.show(); + customForm.showFields(customForm.existing); + customForm.addNew.hide(); + customForm.addNewLink.hide(); + customForm.requiredLegend.show(); + + customForm.doButtonForStep2('Create ' + customForm.entryType); + customForm.doCancelForStep2(); + }, + + // Step 2: adding a new individual + doAddFormStep2AddNew: function() { + + // NB Use customForm instead of 'this', because 'this' + // doesn't reference customForm when called from an event handler. + customForm.addNewLink.hide(); + customForm.existing.hide(); + customForm.showFields(customForm.addNew); + customForm.entry.show(); + customForm.requiredLegend.show(); + + customForm.doButtonForStep2('Create ' + customForm.entryType + ' & ' + customForm.newType); + customForm.doCancelForStep2(); + }, + + // Step 2: combined view, when we are returning from validation errors and we + // can't determine which view of the form we had been on. + doAddFormStep2Combined: function() { + + this.showCombinedView(); + this.doAddNewLink(); + this.doButtonForStep2('Create ' + this.newType); + this.doCancelForStep2(); + }, + + + /***** Edit form *****/ + + // RY Here we need logic for returning from validation errors, as in add form ******** initEditForm: function() { - this.showFields(this.existing); - this.addNewLink.show(); - this.addNew.hide(); - this.entry.show(); - this.requiredLegend.show(); + this.showCombinedView(); + this.doAddNewLink(); this.button.val('Save Changes'); - - this.addNewLink.bind('click', function() { - $(this).hide(); - customForm.existing.hide(); - customForm.showFields(customForm.addNew); - - customForm.button.val('Create ' + customForm.newType + ' & Save Changes'); - }); + // Cancel just takes us back to the individual page - no event listener needed }, + /***** Utilities *****/ + + unbindEventListeners: function() { + this.cancel.unbind('click'); + this.button.unbind('click'); + this.addNewLink.unbind('click'); + }, + + clearFormData: function() { + this.form.find('input:text').val(''); + this.form.find('select').val(''); + this.form.find('textarea').val(''); + + // For now we can remove the error elements. Later we may include them in + // the markup, for customized positioning, in which case we will empty them + // but not remove them here. See findValidationErrors(). + //this.form.find('.validationError').text(''); + this.form.find('.validationError').remove(); + }, + // Add required hints to required fields in a list of elements. // Use when the non-Javascript version should not show the required hint, // because the field is not required in that version (e.g., it's one of two @@ -138,9 +251,10 @@ var customForm = { var labelText, newLabelText, - requiredHintText = ' *'; + requiredHintText = ' *', + numArgs = arguments.length; - for (var i = 1; i < arguments.length; i++) { + for (var i = 1; i < numArgs; i++) { arguments[i].find('label.required').each(function() { labelText = $(this).html(); newLabelText = action == 'add' ? labelText + requiredHintText : @@ -155,13 +269,89 @@ var customForm = { this.toggleRequiredHints('add', el); }, + hideFields: function(el) { + // Clear any input, so if we reshow the element the input won't still be there. + el.find('input:text').val(''); + alert('here'); + el.hide(); + }, + + + doButtonForStep2: function(text) { + customForm.button.unbind('click'); + customForm.button.val(text); + }, + // Add event listener to the cancel link in step 2 - doCancel: function() { - this.cancel.unbind('click'); - this.cancel.bind('click', function() { - customForm.initAddForm(); + doCancelForStep2: function() { + + customForm.cancel.unbind('click'); + customForm.cancel.bind('click', function() { + customForm.resetAddFormToStep1(); return false; }); + }, + + doAddNewLink: function() { + + this.addNewLink.unbind('click'); + this.addNewLink.bind('click', function() { + $(this).hide(); + customForm.hideFields(customForm.existing); + customForm.showFields(customForm.addNew); + + customForm.button.val('Create ' + customForm.newType + ' & Save Changes'); + }); + }, + + // Return true iff there are validation errors on the form + findValidationErrors: function() { + + return this.form.find('.validationError').length > 0; + +// RY For now, we just need to look for the presence of the error elements. +// Later, however, we may generate empty error messages in the markup, for +// customized positioning, in which case we need to look for whether they have +// content. See clearFormData(). +// var foundErrors = false, +// errors = this.form.find('.validationError'), +// numErrors = errors.length, +// i, +// error; +// +// for (i = 0; foundErrors == false && i < numErrors; i++) { +// error = errors[i]; +// if (error.html() != '') { +// foundErrors = true; +// } +// } +// +// return foundErrors; + }, + + resetForm: function() { + + // Clear all form data and error messages + this.clearFormData(); + + // Remove previously bound event handlers + this.unbindEventListeners(); + + // Remove required field hints + this.toggleRequiredHints('remove', this.addNew, this.existing); + }, + + // This version of the form shows both the existing select and add new link. + // Used when loading edit form, and when returning from failed submission + // of add form when we can't determine which view was being used to make + // the submission. + showCombinedView: function() { + + this.showFields(this.existing); + this.addNewLink.show(); + this.addNew.hide(); + this.entry.show(); + this.requiredLegend.show(); } }; diff --git a/productMods/templates/entity/positionShortView.jsp b/productMods/templates/entity/positionShortView.jsp index 9496754f..019d8574 100644 --- a/productMods/templates/entity/positionShortView.jsp +++ b/productMods/templates/entity/positionShortView.jsp @@ -4,8 +4,6 @@ <%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %> <%@ taglib uri="http://vitro.mannlib.cornell.edu/vitro/tags/StringProcessorTag" prefix="p" %> - - <%-- individual is the OBJECT of the property referenced -- the Position, not the Person or Organization --%>