From 805ddb1d1ebdb37dda16b2718ce33b7e45ff2ff6 Mon Sep 17 00:00:00 2001 From: tworrall Date: Thu, 7 Jun 2012 15:20:49 +0000 Subject: [PATCH] NIHVIVO 2599 and 2702 updates to addAuthorToPub to allow selection of organizations --- .../forms/addAuthorsToInformationResource.ftl | 40 +++- .../js/addAuthorsToInformationResource.js | 218 +++++++++++++++--- .../PublicationHasAuthorValidator.java | 18 +- ...AuthorsToInformationResourceGenerator.java | 38 ++- 4 files changed, 268 insertions(+), 46 deletions(-) diff --git a/productMods/templates/freemarker/edit/forms/addAuthorsToInformationResource.ftl b/productMods/templates/freemarker/edit/forms/addAuthorsToInformationResource.ftl index f80a6e62..8c0c608a 100644 --- a/productMods/templates/freemarker/edit/forms/addAuthorsToInformationResource.ftl +++ b/productMods/templates/freemarker/edit/forms/addAuthorsToInformationResource.ftl @@ -18,6 +18,7 @@ <#assign lastNameValue = lvf.getFormFieldValue(editSubmission, editConfiguration, "lastName") /> <#assign firstNameValue = lvf.getFormFieldValue(editSubmission, editConfiguration, "firstName") /> <#assign middleNameValue = lvf.getFormFieldValue(editSubmission, editConfiguration, "middleName") /> +<#assign orgNameValue = lvf.getFormFieldValue(editSubmission, editConfiguration, "orgName") /> @@ -104,6 +105,15 @@

Add an Author

+ +
+ + + + +
+ +
<#--These wrapper paragraph elements are important because javascript hides parent of these fields, since last name should be visible even when first name/middle name are not, the parents should be separate for each field-->

@@ -116,22 +126,39 @@

-

- -

- (Verify this match) + (Verify this match)

+
+
+

+ + +

+ +
+

+ + + (Verify this match) + +

+
+
+ + + +

@@ -149,7 +176,10 @@ diff --git a/productMods/templates/freemarker/edit/forms/js/addAuthorsToInformationResource.js b/productMods/templates/freemarker/edit/forms/js/addAuthorsToInformationResource.js index 07137ebb..9ddf9dc8 100644 --- a/productMods/templates/freemarker/edit/forms/js/addAuthorsToInformationResource.js +++ b/productMods/templates/freemarker/edit/forms/js/addAuthorsToInformationResource.js @@ -60,8 +60,20 @@ var addAuthorForm = { this.selectedAuthor = $('#selectedAuthor'); this.selectedAuthorName = $('#selectedAuthorName'); this.acHelpTextClass = 'acSelectorWithHelpText'; - this.verifyMatch = this.form.find('.verifyMatch'); - + this.verifyMatch = this.form.find('.verifyMatch'); + this.personRadio = $('input.person-radio'); + this.orgRadio = $('input.org-radio'); + this.personSection = $('section#personFields'); + this.orgSection = $('section#organizationFields'); + this.orgName = $('input#orgName'); + this.orgNameWrapper = this.orgName.parent(); + this.orgUriField = $('input#orgUri'); + this.selectedOrg = $('div#selectedOrg'); + this.selectedOrgName = $('span#selectedOrgName'); + this.orgLink = $('a#orgLink'); + this.personLink = $('a#personLink'); + + this.orgSection.hide(); }, // Initial page setup. Called only at page load. @@ -138,7 +150,7 @@ var addAuthorForm = { // however. $('#lastName').val(''); // Set the initial autocomplete help text in the acSelector field. - this.addAcHelpText(); + this.addAcHelpText(this.acSelector); return false; @@ -151,11 +163,13 @@ var addAuthorForm = { // Hide the button that shows the form this.showFormButtonWrapper.hide(); - this.hideSelectedAuthor(); + this.hideSelectedPerson(); + this.hideSelectedOrg(); this.cancel.unbind('click'); this.cancel.bind('click', function() { addAuthorForm.showAuthorListOnlyView(); + addAuthorForm.setAuthorType("person"); return false; }); @@ -169,12 +183,18 @@ var addAuthorForm = { //this.lastNameField.focus(); }, - hideSelectedAuthor: function() { + hideSelectedPerson: function() { this.selectedAuthor.hide(); this.selectedAuthorName.html(''); this.personUriField.val(''); }, + hideSelectedOrg: function() { + this.selectedOrg.hide(); + this.selectedOrgName.html(''); + this.orgUriField.val(''); + }, + showFieldsForNewPerson: function() { this.firstNameWrapper.show(); this.middleNameWrapper.show(); @@ -193,9 +213,22 @@ var addAuthorForm = { // Make cache a property of this so we can access it after removing // an author. this.acCache = {}; - this.setAcFilter(); + this.setAcFilter(); + var $acField; + var urlString; + var authType; - this.lastNameField.autocomplete({ + if ( this.personRadio.attr("checked") ) { + $acField = this.lastNameField; + urlString = addAuthorForm.acUrl + addAuthorForm.personUrl + addAuthorForm.tokenize; + authType = "person"; + } + else { + $acField = this.orgName; + urlString = addAuthorForm.acUrl + addAuthorForm.orgUrl + addAuthorForm.tokenize; + authType = "org"; + } + $acField.autocomplete({ minLength: 2, source: function(request, response) { if (request.term in addAuthorForm.acCache) { @@ -209,7 +242,7 @@ var addAuthorForm = { // here instead of a get. Add the exclude uris to the data // rather than to the url. $.ajax({ - url: addAuthorForm.acUrl, + url: urlString, dataType: 'json', data: { term: request.term @@ -232,7 +265,7 @@ var addAuthorForm = { // select event has been triggered. To trigger a select, the user must hit enter // or click on the selection with the mouse. This appears to confuse some users. select: function(event, ui) { - addAuthorForm.showSelectedAuthor(ui); + addAuthorForm.showSelectedAuthor(ui,authType); } }); @@ -288,27 +321,41 @@ var addAuthorForm = { }, // Action taken after selecting an author from the autocomplete list - showSelectedAuthor: function(ui) { + showSelectedAuthor: function(ui,authType) { - this.personUriField.val(ui.item.uri); - this.selectedAuthor.show(); + if ( authType == "person" ) { + this.personUriField.val(ui.item.uri); + this.selectedAuthor.show(); + + // Transfer the name from the autocomplete to the selected author + // name display, and hide the last name field. + this.selectedAuthorName.html(ui.item.label); + // NB For some reason this doesn't delete the value from the last name + // field when the form is redisplayed. Thus it's done explicitly in initFormView. + this.hideFields(this.lastNameWrapper); + // These get displayed if the selection was made through an enter keystroke, + // since the keydown event on the last name field is also triggered (and + // executes first). So re-hide them here. + this.hideFieldsForNewPerson(); + this.personLink.attr('href', this.verifyMatch.data('baseHref') + ui.item.uri); + } + else { + // do the same as above but for the organization fields + this.orgUriField.val(ui.item.uri); + this.selectedOrg.show(); + + this.selectedOrgName.html(ui.item.label); + + this.hideFields(this.orgNameWrapper); + + this.orgLink.attr('href', this.verifyMatch.data('baseHref') + ui.item.uri); + } - // Transfer the name from the autocomplete to the selected author - // name display, and hide the last name field. - this.selectedAuthorName.html(ui.item.label); - // NB For some reason this doesn't delete the value from the last name - // field when the form is redisplayed. Thus it's done explicitly in initFormView. - this.hideFields(this.lastNameWrapper); - // These get displayed if the selection was made through an enter keystroke, - // since the keydown event on the last name field is also triggered (and - // executes first). So re-hide them here. - this.hideFieldsForNewPerson(); - this.verifyMatch.attr('href', this.verifyMatch.data('baseHref') + ui.item.uri); - // Cancel restores initial form view this.cancel.unbind('click'); this.cancel.bind('click', function() { addAuthorForm.initFormView(); + addAuthorForm.setAuthorType(authType); return false; }); }, @@ -432,11 +479,20 @@ var addAuthorForm = { return false; }); + this.orgRadio.click(function() { + addAuthorForm.setAuthorType("org"); + }); + + this.personRadio.click(function() { + addAuthorForm.setAuthorType("person"); + }); + this.form.submit(function() { // NB Important JavaScript scope issue: if we call it this way, this = addAuthorForm // in prepareSubmit. If we do this.form.submit(this.prepareSubmit); then // this != addAuthorForm in prepareSubmit. - addAuthorForm.deleteAcHelpText(); + $selectedObj = addAuthorForm.form.find('input.acSelector'); + addAuthorForm.deleteAcHelpText($selectedObj); addAuthorForm.prepareSubmit(); }); @@ -451,17 +507,30 @@ var addAuthorForm = { addAuthorForm.onLastNameChange(); }); - this.verifyMatch.click(function() { + this.personLink.click(function() { + window.open($(this).attr('href'), 'verifyMatchWindow', 'width=640,height=640,scrollbars=yes,resizable=yes,status=yes,toolbar=no,menubar=no,location=no'); + return false; + }); + + this.orgLink.click(function() { window.open($(this).attr('href'), 'verifyMatchWindow', 'width=640,height=640,scrollbars=yes,resizable=yes,status=yes,toolbar=no,menubar=no,location=no'); return false; }); this.acSelector.focus(function() { - addAuthorForm.deleteAcHelpText(); + addAuthorForm.deleteAcHelpText(this); }); this.acSelector.blur(function() { - addAuthorForm.addAcHelpText(); + addAuthorForm.addAcHelpText(this); + }); + + this.orgName.focus(function() { + addAuthorForm.deleteAcHelpText(this); + }); + + this.orgName.blur(function() { + addAuthorForm.addAcHelpText(this); }); // When hitting enter in last name field, show first and middle name fields. @@ -495,7 +564,7 @@ var addAuthorForm = { name; // If selecting an existing person, don't submit name fields - if (this.personUriField.val() != '') { + if (this.personUriField.val() != '' || this.orgUriField.val() != '' || this.orgName.val() != '' ) { this.firstNameField.attr('disabled', 'disabled'); this.middleNameField.attr('disabled', 'disabled'); this.lastNameField.attr('disabled', 'disabled'); @@ -639,21 +708,94 @@ var addAuthorForm = { }, // Set the initial help text in the lastName field and change the class name. - addAcHelpText: function() { + addAcHelpText: function(selectedObj) { var typeText; - - if (!this.acSelector.val()) { - this.acSelector.val("Select an existing Author or add a new one.") + if ( $(selectedObj).attr('id') == "lastName" ) { + typeText = "Author"; + } + else { + typeText = "Organization"; + } + + if (!$(selectedObj).val()) { + $(selectedObj).val("Select an existing " + typeText + " or add a new one.") .addClass(this.acHelpTextClass); } }, - deleteAcHelpText: function() { - if (this.acSelector.hasClass(this.acHelpTextClass)) { - this.acSelector.val('') - .removeClass(this.acHelpTextClass); - } + deleteAcHelpText: function(selectedObj) { + if ($(selectedObj).hasClass(this.acHelpTextClass)) { + $(selectedObj).val('') + .removeClass(this.acHelpTextClass); } + }, + + // Depending on whether the author is a person or an organization, + // we need to set the correct class names for fields like the acSelector, acSelection, etc. + // as well as clear and disable fields, call other functions ... + setAuthorType: function(authType) { + if ( authType == "org" ) { + this.personSection.hide(); + this.orgSection.show(); + // person fields + this.personRadio.attr('checked', false); // needed for reset when cancel button is clicked + this.acSelector.removeClass("acSelector"); + this.acSelector.removeClass(this.acHelpTextClass); + this.selectedAuthor.removeClass("acSelection"); + this.selectedAuthorName.removeClass("acSelectionInfo"); + this.personLink.removeClass("verifyMatch"); + this.acSelector.attr('disabled', 'disabled'); + this.firstNameField.attr('disabled', 'disabled'); + this.middleNameField.attr('disabled', 'disabled'); + this.lastNameField.attr('disabled', 'disabled'); + this.acSelector.val(''); + this.firstNameField.val(''); + this.middleNameField.val(''); + this.lastNameField.val(''); + // org fields + this.orgRadio.attr('checked', true); // needed for reset when cancel button is clicked + this.orgName.addClass("acSelector"); + this.selectedOrg.addClass("acSelection"); + this.selectedOrgName.addClass("acSelectionInfo"); + this.orgLink.addClass("verifyMatch"); + this.orgName.attr('disabled', ''); + this.orgUriField.attr('disabled', ''); + + addAuthorForm.addAcHelpText(this.orgName); + addAuthorForm.initAutocomplete(); + addAuthorForm.hideSelectedPerson(); + } + else if ( authType == "person" ) { + this.orgSection.hide(); + this.personSection.show(); + // org fields + this.orgRadio.attr('checked', false); // needed for reset when cancel button is clicked + this.orgName.removeClass("acSelector"); + this.orgName.removeClass(this.acHelpTextClass); + this.selectedOrg.removeClass("acSelection"); + this.selectedOrgName.removeClass("acSelectionInfo"); + this.orgLink.removeClass("verifyMatch"); + this.orgName.attr('disabled', 'disabled'); + this.orgUriField.attr('disabled', 'disabled'); + this.orgName.val(''); + this.orgUriField.val(''); + // person fields + this.acSelector.addClass("acSelector"); + this.personRadio.attr('checked', true); // needed for reset when cancel button is clicked + this.selectedAuthor.addClass("acSelection"); + this.selectedAuthorName.addClass("acSelectionInfo"); + this.personLink.addClass("verifyMatch"); + this.acSelector.attr('disabled', ''); + this.firstNameField.attr('disabled', ''); + this.middleNameField.attr('disabled', ''); + this.lastNameField.attr('disabled', ''); + + addAuthorForm.addAcHelpText(this.acSelector); + addAuthorForm.initAutocomplete(); + addAuthorForm.hideSelectedOrg(); + + } + } }; $(document).ready(function() { diff --git a/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/PublicationHasAuthorValidator.java b/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/PublicationHasAuthorValidator.java index 238e3cf3..b6402621 100644 --- a/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/PublicationHasAuthorValidator.java +++ b/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/PublicationHasAuthorValidator.java @@ -2,10 +2,14 @@ package edu.cornell.mannlib.vitro.webapp.edit.n3editing; +import java.lang.String; + import java.util.HashMap; import java.util.List; import java.util.Map; +import org.apache.commons.lang.StringUtils; + import com.hp.hpl.jena.rdf.model.Literal; import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.N3ValidatorVTwo; @@ -27,12 +31,22 @@ public class PublicationHasAuthorValidator implements N3ValidatorVTwo { Map errors = new HashMap(); List personUri = urisFromForm.get("personUri"); + List orgUri = urisFromForm.get("orgUri"); + List orgNameList = literalsFromForm.get("orgName"); + if (allListElementsEmpty(personUri)) { personUri = null; } - // If there's a personUri, then we're done. The firstName and lastName fields are + if (allListElementsEmpty(orgUri)) { + orgUri = null; + } + Literal orgName = null; + if(orgNameList != null && orgNameList.size() > 0) { + orgName = orgNameList.get(0); + } + // If there's a personUri, orgUri or orgName, then we're done. The firstName and lastName fields are // disabled and so don't get submitted. - if (personUri != null) { + if (personUri != null || orgUri != null || orgName != null ) { return null; } diff --git a/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/AddAuthorsToInformationResourceGenerator.java b/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/AddAuthorsToInformationResourceGenerator.java index d28c0c6d..7ccd8d5b 100644 --- a/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/AddAuthorsToInformationResourceGenerator.java +++ b/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/AddAuthorsToInformationResourceGenerator.java @@ -57,6 +57,7 @@ public class AddAuthorsToInformationResourceGenerator extends VivoBaseGenerator editConfiguration.addNewResource("authorshipUri", DEFAULT_NS_TOKEN); editConfiguration.addNewResource("newPerson", DEFAULT_NS_TOKEN); + editConfiguration.addNewResource("newOrg", DEFAULT_NS_TOKEN); //In scope setUrisAndLiteralsInScope(editConfiguration, vreq); @@ -118,7 +119,9 @@ public class AddAuthorsToInformationResourceGenerator extends VivoBaseGenerator getN3NewPersonLastName(), getN3NewPerson(), getN3AuthorshipRank(), - getN3ForExistingPerson()); + getN3ForExistingPerson(), + getN3NewOrg(), + getN3ForExistingOrg()); } @@ -152,6 +155,19 @@ public class AddAuthorsToInformationResourceGenerator extends VivoBaseGenerator "?personUri core:authorInAuthorship ?authorshipUri ."; } + private String getN3NewOrg() { + return getN3PrefixString() + + "?newOrg a foaf:Organization ;\n" + + "<" + RDFS.label.getURI() + "> ?orgName .\n" + + "?authorshipUri core:linkedAuthor ?newOrg .\n" + + "?newOrg core:authorInAuthorship ?authorshipUri . "; + } + + private String getN3ForExistingOrg() { + return getN3PrefixString() + + "?authorshipUri core:linkedAuthor ?orgUri .\n" + + "?orgUri core:authorInAuthorship ?authorshipUri ."; + } /** Get new resources */ //A new authorship uri will always be created when an author is added //A new person may be added if a person not in the system will be added as author @@ -161,6 +177,7 @@ public class AddAuthorsToInformationResourceGenerator extends VivoBaseGenerator HashMap newResources = new HashMap(); newResources.put("authorshipUri", DEFAULT_NS_TOKEN); newResources.put("newPerson", DEFAULT_NS_TOKEN); + newResources.put("newOrg", DEFAULT_NS_TOKEN); return newResources; } @@ -180,6 +197,7 @@ public class AddAuthorsToInformationResourceGenerator extends VivoBaseGenerator List urisOnForm = new ArrayList(); //If an existing person is being used as an author, need to get the person uri urisOnForm.add("personUri"); + urisOnForm.add("orgUri"); editConfiguration.setUrisOnform(urisOnForm); //for person who is not in system, need to add first name, last name and middle name @@ -188,6 +206,7 @@ public class AddAuthorsToInformationResourceGenerator extends VivoBaseGenerator "middleName", "lastName", "rank", + "orgName", "label"); editConfiguration.setLiteralsOnForm(literalsOnForm); } @@ -216,6 +235,8 @@ public class AddAuthorsToInformationResourceGenerator extends VivoBaseGenerator setLastNameField(editConfiguration); setRankField(editConfiguration); setPersonUriField(editConfiguration); + setOrgUriField(editConfiguration); + setOrgNameField(editConfiguration); } private void setLabelField(EditConfigurationVTwo editConfiguration) { @@ -278,6 +299,21 @@ public class AddAuthorsToInformationResourceGenerator extends VivoBaseGenerator } + private void setOrgUriField(EditConfigurationVTwo editConfiguration) { + editConfiguration.addField(new FieldVTwo(). + setName("orgUri") + //.setObjectClassUri(personClass) + ); + + } + private void setOrgNameField(EditConfigurationVTwo editConfiguration) { + editConfiguration.addField(new FieldVTwo(). + setName("orgName"). + setValidators(list("datatype:" + XSD.xstring.toString())). + setRangeDatatypeUri(XSD.xstring.toString()) + ); + + } //Form specific data public void addFormSpecificData(EditConfigurationVTwo editConfiguration, VitroRequest vreq) { HashMap formSpecificData = new HashMap();