diff --git a/languages/es_GO/themes/wilma/i18n/all_es_GO.properties b/languages/es_GO/themes/wilma/i18n/all_es_GO.properties
index 88e99c11..3f645749 100644
--- a/languages/es_GO/themes/wilma/i18n/all_es_GO.properties
+++ b/languages/es_GO/themes/wilma/i18n/all_es_GO.properties
@@ -878,4 +878,6 @@ missing_credential = falta credencial
grant_administered_by = conceder administrado por
missing_grant = falta de subvención
editor_of_entry = editor de para
-researcher_role = El papel del investigador en el proyecto
+role_type = Tipo de papel
+add_capitalized = Añadir
+researcher_role = El papel del investigador
\ No newline at end of file
diff --git a/productMods/templates/freemarker/edit/forms/grantHasContributor.ftl b/productMods/templates/freemarker/edit/forms/grantHasContributor.ftl
new file mode 100644
index 00000000..43a42ce3
--- /dev/null
+++ b/productMods/templates/freemarker/edit/forms/grantHasContributor.ftl
@@ -0,0 +1,185 @@
+<#-- $This file is distributed under the terms of the license in /doc/license.txt$ -->
+
+<#-- this is in request.subject.name -->
+
+<#-- leaving this edit/add mode code in for reference in case we decide we need it -->
+
+<#import "lib-vivo-form.ftl" as lvf>
+
+<#assign subjectName=""/>
+<#assign roleActivityUri="mysteryRoleActivityURI"/>
+<#assign personLabel="mysteryPersonLabel"/>
+
+<#--Retrieve certain edit configuration information-->
+<#assign editMode = editConfiguration.pageData.editMode />
+<#assign htmlForElements = editConfiguration.pageData.htmlForElements />
+
+<#--The blank sentinel indicates what value should be put in a URI when no autocomplete result has been selected.
+If the blank value is non-null or non-empty, n3 editing for an existing object will remove the original relationship
+if nothing is selected for that object-->
+<#assign blankSentinel = "" />
+<#if editConfigurationConstants?has_content && editConfigurationConstants?keys?seq_contains("BLANK_SENTINEL")>
+ <#assign blankSentinel = editConfigurationConstants["BLANK_SENTINEL"] />
+#if>
+
+<#--This flag is for clearing the label field on submission for an existing object being selected from autocomplete.
+Set this flag on the input acUriReceiver where you would like this behavior to occur. -->
+<#assign flagClearLabelForExisting = "flagClearLabelForExisting" />
+
+<#--Retrieve variables needed-->
+<#assign firstNameValue = lvf.getFormFieldValue(editSubmission, editConfiguration, "firstName")/>
+<#assign lastNameValue = lvf.getFormFieldValue(editSubmission, editConfiguration, "lastName") />
+<#assign personLabelValue = lvf.getFormFieldValue(editSubmission, editConfiguration, "personLabel") />
+<#assign personLabelDisplayValue = lvf.getFormFieldValue(editSubmission, editConfiguration, "personLabelDisplay") />
+<#assign existingPersonValue = lvf.getFormFieldValue(editSubmission, editConfiguration, "existingPerson") />
+<#assign roleTypeValue = lvf.getFormFieldValue(editSubmission, editConfiguration, "roleType")/>
+
+<#-- If edit submission exists, then retrieve validation errors if they exist-->
+<#if editSubmission?has_content && editSubmission.submissionExists = true && editSubmission.validationErrors?has_content>
+ <#assign submissionErrors = editSubmission.validationErrors/>
+#if>
+
+<#if editMode == "edit" || editMode == "repair">
+ <#assign titleVerb="${i18n().edit_capitalized}">
+ <#assign submitButtonText="${i18n().save_changes}">
+ <#assign disabledVal="disabled">
+<#else>
+ <#assign titleVerb="${i18n().add_capitalized}">
+ <#assign submitButtonText="${i18n().create_entry}">
+ <#assign disabledVal=""/>
+#if>
+
+<#assign requiredHint = " *" />
+<#assign yearHint = "(${i18n().year_hint_format})" />
+
+
+
+ <#--below shows examples of both printing out all error messages and checking the error message for a specific field-->
+ <#list submissionErrors?keys as errorFieldName>
+ <#if errorFieldName == "startField">
+ <#if submissionErrors[errorFieldName]?contains("before")>
+ ${i18n().start_year_must_precede_end}
+ <#else>
+ ${submissionErrors[errorFieldName]}
+ #if>
+
+ <#elseif errorFieldName == "endField">
+ <#if submissionErrors[errorFieldName]?contains("after")>
+ ${i18n().end_year_must_be_later}
+ <#else>
+ ${submissionErrors[errorFieldName]}
+ #if>
+ <#else>
+ ${submissionErrors[errorFieldName]}
+ #if>
+ #list>
+ <#--Checking if Person Type field is empty-->
+ <#if lvf.submissionErrorExists(editSubmission, "personType")>
+ ${i18n().select_person_type}
+ #if>
+ <#--Checking if Person Name field is empty-->
+ <#if lvf.submissionErrorExists(editSubmission, "personLabel")>
+ ${i18n().select_an_person_name}
+ #if>
+ <#--Checking if Role Type field is empty-->
+ <#if lvf.submissionErrorExists(editSubmission, "roleType")>
+ ${i18n().select_educational_training_value}
+ #if>
+
+
+
+
+#if>
+
+<@lvf.unsupportedBrowser urls.base />
+
+
+
+
+
+
+
+
+
+
+${stylesheets.add('')}
+${stylesheets.add('')}
+${stylesheets.add('')}
+
+
+${scripts.add('',
+ '',
+ '',
+ '',
+ '',
+ '',
+ '')}
+
+
diff --git a/productMods/templates/freemarker/edit/forms/js/grantHasContributorUtils.js b/productMods/templates/freemarker/edit/forms/js/grantHasContributorUtils.js
new file mode 100644
index 00000000..23d1630b
--- /dev/null
+++ b/productMods/templates/freemarker/edit/forms/js/grantHasContributorUtils.js
@@ -0,0 +1,80 @@
+/* $This file is distributed under the terms of the license in /doc/license.txt$ */
+
+var grantHasContributorUtils = {
+
+ onLoad: function(blankSentinel) {
+ this.sentinel = '';
+ if ( blankSentinel ) { this.sentinel = blankSentinel; }
+
+ this.initObjectReferences();
+ this.bindEventListeners();
+
+ $.extend(this, vitro.customFormUtils);
+ $.extend(this, i18nStrings);
+
+ if ( this.findValidationErrors() ) {
+ this.resetLastNameLabel();
+ }
+ },
+
+ initObjectReferences: function() {
+
+ this.form = $('#grantHasContributor');
+ this.person = $('#person');
+ this.fauxLabel = $('#maskLabelBuilding');
+ this.firstName = $('#firstName');
+ this.lastName = $('#lastName');
+ this.personUri = $('#personUri');
+
+ // may not need this
+ this.firstName.attr('disabled', '');
+
+ },
+
+ bindEventListeners: function() {
+ this.idCache = {};
+
+ this.form.submit(function() {
+ grantHasContributorUtils.resolveFirstLastNames();
+ });
+ },
+
+ resolveFirstLastNames: function() {
+ var firstName,
+ lastName,
+ name;
+
+ // If selecting an existing person, don't submit name fields
+ if (this.personUri.val() == '' || this.personUri.val() == this.sentinel ) {
+ firstName = this.firstName.val();
+ lastName = this.person.val();
+
+ name = lastName;
+
+ if (firstName) {
+ name += ', ' + firstName;
+ }
+
+ // we don't want the user to see the label getting built, so hide the acSelector
+ // field and display a bogus field that just has the last name in it.
+ this.fauxLabel.val(lastName);
+ this.person.hide();
+ this.fauxLabel.show();
+ this.person.val(name);
+ this.lastName.val(lastName);
+ }
+ else {
+ this.firstName.attr('disabled', 'disabled');
+ this.lastName.attr('disabled', 'disabled');
+ }
+ },
+
+ resetLastNameLabel: function() {
+ var indx = this.person.val().indexOf(", ");
+ if ( indx != -1 ) {
+ var temp = this.person.val().substr(0,indx);
+ this.person.val(temp);
+ }
+ },
+
+}
diff --git a/productMods/templates/freemarker/edit/forms/projectHasParticipant.ftl b/productMods/templates/freemarker/edit/forms/projectHasParticipant.ftl
index 1e1aeba5..d73d6636 100644
--- a/productMods/templates/freemarker/edit/forms/projectHasParticipant.ftl
+++ b/productMods/templates/freemarker/edit/forms/projectHasParticipant.ftl
@@ -44,7 +44,7 @@ Set this flag on the input acUriReceiver where you would like this behavior to o
<#assign submitButtonText="${i18n().save_changes}">
<#assign disabledVal="disabled">
<#else>
- <#assign titleVerb="${i18n().create_capitalized}">
+ <#assign titleVerb="${i18n().add_capitalized}">
<#assign submitButtonText="${i18n().create_entry}">
<#assign disabledVal=""/>
#if>
diff --git a/rdf/display/everytime/PropertyConfig.n3 b/rdf/display/everytime/PropertyConfig.n3
index 5ec9d41a..f8bc0c66 100644
--- a/rdf/display/everytime/PropertyConfig.n3
+++ b/rdf/display/everytime/PropertyConfig.n3
@@ -1762,6 +1762,7 @@ local:grantRelatesConfig a :ObjectPropertyDisplayConfig ;
vitro:displayRankAnnot 55;
vitro:hiddenFromDisplayBelowRoleLevelAnnot role:public ;
vitro:prohibitedFromUpdateBelowRoleLevelAnnot role:nobody ;
+ vitro:customEntryFormAnnot "edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.generators.GrantHasContributorGenerator"^^ ;
:propertyGroup .
local:contractRelatesContext a :ConfigContext ;
@@ -1776,6 +1777,7 @@ local:contractRelatesConfig a :ObjectPropertyDisplayConfig ;
vitro:displayRankAnnot 55;
vitro:hiddenFromDisplayBelowRoleLevelAnnot role:public ;
vitro:prohibitedFromUpdateBelowRoleLevelAnnot role:nobody ;
+ vitro:customEntryFormAnnot "edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.generators.GrantHasContributorGenerator"^^ ;
:propertyGroup .
### faux properties for dateTimeValue ###
diff --git a/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/GrantHasContributorGenerator.java b/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/GrantHasContributorGenerator.java
new file mode 100644
index 00000000..5dbf4fde
--- /dev/null
+++ b/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/GrantHasContributorGenerator.java
@@ -0,0 +1,190 @@
+/* $This file is distributed under the terms of the license in /doc/license.txt$ */
+package edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.generators;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+
+import javax.servlet.http.HttpSession;
+
+import com.hp.hpl.jena.vocabulary.XSD;
+
+import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
+import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary;
+import edu.cornell.mannlib.vitro.webapp.edit.n3editing.FirstAndLastNameValidator;
+import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.DateTimeIntervalValidationVTwo;
+import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.DateTimeWithPrecisionVTwo;
+import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.EditConfigurationVTwo;
+import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.fields.ChildVClassesOptions;
+import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.fields.ChildVClassesWithParent;
+import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.fields.FieldVTwo;
+import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.fields.IndividualsViaVClassOptions;
+import edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.validators.AntiXssValidation;
+import edu.cornell.mannlib.vitro.webapp.utils.FrontEndEditingUtils.EditMode;
+import edu.cornell.mannlib.vitro.webapp.utils.generators.EditModeUtils;
+
+public class GrantHasContributorGenerator extends VivoBaseGenerator implements EditConfigurationGenerator{
+
+ // NOTE: This generator is for contract as well as grants.
+ //TODO: can we get rid of the session and get it form the vreq?
+ public EditConfigurationVTwo getEditConfiguration(VitroRequest vreq, HttpSession session) throws Exception {
+
+ EditConfigurationVTwo conf = new EditConfigurationVTwo();
+
+ initBasics(conf, vreq);
+ initPropertyParameters(vreq, session, conf);
+ initObjectPropForm(conf, vreq);
+
+ conf.setTemplate("grantHasContributor.ftl");
+
+ conf.setVarNameForSubject("subject");
+ conf.setVarNameForPredicate("predicate");
+ conf.setVarNameForObject("theRole");
+
+ conf.setN3Required( Arrays.asList( n3ForNewProjectRole, roleTypeAssertion ) );
+ conf.setN3Optional(Arrays.asList( n3ForNewPerson, n3ForExistingPerson, firstNameAssertion, lastNameAssertion ) );
+
+ conf.addNewResource("theRole", DEFAULT_NS_FOR_NEW_RESOURCE);
+ conf.addNewResource("newPerson",DEFAULT_NS_FOR_NEW_RESOURCE);
+ conf.addNewResource("vcardPerson", DEFAULT_NS_FOR_NEW_RESOURCE);
+ conf.addNewResource("vcardName", DEFAULT_NS_FOR_NEW_RESOURCE);
+
+ //uris in scope: none
+ //literals in scope: none
+
+ conf.setUrisOnform( Arrays.asList( "existingPerson", "roleType"));
+ conf.setLiteralsOnForm( Arrays.asList("personLabel", "personLabelDisplay", "firstName", "lastName"));
+
+ conf.addSparqlForExistingLiteral("personLabel", personLabelQuery);
+
+ conf.addSparqlForExistingUris("existingPerson", existingPersonQuery);
+ conf.addSparqlForExistingUris("roleType", roleTypeQuery);
+
+ conf.addField( new FieldVTwo().
+ setName("existingPerson")
+ //options will be added in browser by auto complete JS
+ );
+
+ conf.addField( new FieldVTwo().
+ setName("personLabel").
+ setRangeDatatypeUri(XSD.xstring.toString() ).
+ setValidators( list("datatype:" + XSD.xstring.toString())));
+
+ conf.addField( new FieldVTwo().
+ setName("personLabelDisplay").
+ setRangeDatatypeUri(XSD.xstring.toString() ));
+
+ conf.addField( new FieldVTwo().
+ setName("firstName").
+ setRangeDatatypeUri(XSD.xstring.toString() ).
+ setValidators( list("datatype:" + XSD.xstring.toString()) )
+ );
+
+ conf.addField( new FieldVTwo().
+ setName("lastName").
+ setRangeDatatypeUri(XSD.xstring.toString() ).
+ setValidators( list("datatype:" + XSD.xstring.toString()) )
+ );
+
+ conf.addField( new FieldVTwo().
+ setName("roleType").
+ setValidators( list("nonempty") ).
+ setOptions(
+ new ChildVClassesWithParent("http://vivoweb.org/ontology/core#ResearcherRole")));
+
+
+ //Add validator
+ conf.addValidator(new AntiXssValidation());
+ conf.addValidator(new FirstAndLastNameValidator("existingPerson"));
+
+ //Adding additional data, specifically edit mode
+ addFormSpecificData(conf, vreq);
+ prepare(vreq, conf);
+ return conf;
+ }
+
+ /* N3 assertions for working with educational training */
+
+ final static String n3ForNewProjectRole =
+ "@prefix core: <"+ vivoCore +"> .\n" +
+ "@prefix rdfs: <"+ rdfs +"> . \n"+
+ "?subject core:relates ?theRole .\n" +
+ "?theRole core:relatedBy ?subject . \n" ;
+
+ final static String roleTypeAssertion =
+ "?theRole a ?roleType .";
+
+ final static String n3ForNewPerson =
+ "@prefix core: <"+ vivoCore +"> .\n" +
+ "?theRole ?newPerson . \n" +
+ "?newPerson ?theRole . \n" +
+ "?subject core:relates ?newPerson . \n" +
+ "?newPerson core:relatedBy ?subject . \n" +
+ "?newPerson a . \n" +
+ "?newPerson <"+ label +"> ?personLabel . ";
+
+ final static String n3ForExistingPerson =
+ "@prefix core: <"+ vivoCore +"> .\n" +
+ "?theRole ?existingPerson . \n" +
+ "?existingPerson ?theRole . \n" +
+ "?subject core:relates ?newPerson . \n" +
+ "?newPerson core:relatedBy ?subject . \n" +
+ " ";
+
+ final static String firstNameAssertion =
+ "@prefix vcard: . \n" +
+ "?newPerson ?vcardPerson . \n" +
+ "?vcardPerson ?newPerson . \n" +
+ "?vcardPerson a . \n" +
+ "?vcardPerson vcard:hasName ?vcardName . \n" +
+ "?vcardName a . \n" +
+ "?vcardName vcard:givenName ?firstName .";
+
+ final static String lastNameAssertion =
+ "@prefix vcard: . \n" +
+ "?newPerson ?vcardPerson . \n" +
+ "?vcardPerson ?newPerson . \n" +
+ "?vcardPerson a . \n" +
+ "?vcardPerson vcard:hasName ?vcardName . \n" +
+ "?vcardName a . \n" +
+ "?vcardName vcard:familyName ?lastName .";
+
+ /* Queries for editing an existing educational training entry */
+
+ final static String roleTypeQuery =
+ "PREFIX vitro: <" + VitroVocabulary.vitroURI + "> \n" +
+ "SELECT ?roleType WHERE { \n" +
+ " ?theRole vitro:mostSpecificType ?roleType . }";
+
+ final static String existingPersonQuery =
+ "PREFIX rdfs: <"+ rdfs +"> \n"+
+ "SELECT ?existingPerson WHERE {\n"+
+ "?theRole ?existingPerson . \n" +
+ "?existingPerson ?theRole . \n" +
+ "?existingPerson a . \n " +
+ " }";
+
+ final static String personLabelQuery =
+ "PREFIX rdfs: <"+ rdfs +"> \n"+
+ "SELECT ?existingPersonLabel WHERE {\n"+
+ "?theRole ?existingPerson . \n" +
+ "?existingPerson ?theRole .\n"+
+ "?existingPerson <"+ label +"> ?existingPersonLabel .\n"+
+ "?existingPerson a . \n " +
+ " }";
+
+
+ //Adding form specific data such as edit mode
+ public void addFormSpecificData(EditConfigurationVTwo editConfiguration, VitroRequest vreq) {
+ HashMap formSpecificData = new HashMap();
+ formSpecificData.put("editMode", getEditMode(vreq).name().toLowerCase());
+ editConfiguration.setFormSpecificData(formSpecificData);
+ }
+
+ public EditMode getEditMode(VitroRequest vreq) {
+ List predicates = new ArrayList();
+ predicates.add("http://purl.obolibrary.org/obo/RO_0000053");
+ return EditModeUtils.getEditMode(vreq, predicates);
+ }
+}
diff --git a/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/ProjectHasParticipantGenerator.java b/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/ProjectHasParticipantGenerator.java
index 88642c89..57e4b507 100644
--- a/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/ProjectHasParticipantGenerator.java
+++ b/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/ProjectHasParticipantGenerator.java
@@ -154,16 +154,16 @@ public class ProjectHasParticipantGenerator extends VivoBaseGenerator implement
final static String existingPersonQuery =
"PREFIX rdfs: <"+ rdfs +"> \n"+
"SELECT ?existingPerson WHERE {\n"+
- "?projectRole ?existingPerson . \n" +
- "?existingPerson ?projectRole . \n" +
+ "?projectRole ?existingPerson . \n" +
+ "?existingPerson ?projectRole . \n" +
"?existingPerson a . \n " +
" }";
final static String personLabelQuery =
"PREFIX rdfs: <"+ rdfs +"> \n"+
"SELECT ?existingPersonLabel WHERE {\n"+
- "?projectRole ?existingPerson . \n" +
- "?existingPerson ?projectRole .\n"+
+ "?projectRole ?existingPerson . \n" +
+ "?existingPerson ?projectRole .\n"+
"?existingPerson <"+ label +"> ?existingPersonLabel .\n"+
"?existingPerson a . \n " +
" }";
diff --git a/themes/wilma/i18n/all.properties b/themes/wilma/i18n/all.properties
index 9154b55a..648aae2e 100644
--- a/themes/wilma/i18n/all.properties
+++ b/themes/wilma/i18n/all.properties
@@ -884,4 +884,6 @@ missing_credential = missing credential
grant_administered_by = grant being administered by
missing_grant = missing grant
editor_of_entry = editor of entry for
-researcher_role = Researcher's role in the project
\ No newline at end of file
+role_type = Role type
+add_capitalized = Add
+researcher_role = Researcher Role
\ No newline at end of file