Default object property from changed to switch to auto complete when there are too many individuals found in the range.
Auto complete code, css, templates and js moved from vivo to vitro.
This commit is contained in:
parent
414df19928
commit
2ba92cf8e7
7 changed files with 1206 additions and 92 deletions
|
@ -0,0 +1,28 @@
|
|||
/* $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 javax.servlet.http.HttpSession;
|
||||
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
|
||||
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.EditConfigurationVTwo;
|
||||
|
||||
|
||||
/**
|
||||
* Auto complete object property form generator folded into DefualtObjectPropertyFormGenerator.java
|
||||
*
|
||||
*/
|
||||
public class AutocompleteObjectPropertyFormGenerator extends DefaultObjectPropertyFormGenerator {
|
||||
|
||||
@Override
|
||||
public EditConfigurationVTwo getEditConfiguration(VitroRequest vreq,
|
||||
HttpSession session) throws Exception {
|
||||
//force auto complete
|
||||
doAutoComplete = true;
|
||||
|
||||
return super.getEditConfiguration(vreq, session);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
package edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.generators;
|
||||
|
||||
import static edu.cornell.mannlib.vitro.webapp.dao.DisplayVocabulary.DISPLAY_ONT_MODEL;
|
||||
import static edu.cornell.mannlib.vitro.webapp.dao.DisplayVocabulary.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
@ -12,60 +12,86 @@ import java.util.Map;
|
|||
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.apache.solr.client.solrj.SolrQuery;
|
||||
import org.apache.solr.client.solrj.SolrServer;
|
||||
import org.apache.solr.client.solrj.SolrServerException;
|
||||
import org.apache.solr.client.solrj.response.QueryResponse;
|
||||
import org.apache.solr.common.SolrDocumentList;
|
||||
|
||||
import com.hp.hpl.jena.ontology.OntModel;
|
||||
import com.hp.hpl.jena.rdf.model.Literal;
|
||||
import com.hp.hpl.jena.rdf.model.Model;
|
||||
|
||||
import edu.cornell.mannlib.vitro.webapp.beans.DataProperty;
|
||||
import edu.cornell.mannlib.vitro.webapp.beans.Individual;
|
||||
import edu.cornell.mannlib.vitro.webapp.beans.ObjectProperty;
|
||||
import edu.cornell.mannlib.vitro.webapp.beans.VClass;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.DisplayVocabulary;
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary;
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory;
|
||||
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.EditConfigurationUtils;
|
||||
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.EditConfigurationVTwo;
|
||||
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.fields.FieldOptions;
|
||||
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.fields.FieldVTwo;
|
||||
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.fields.IndividualsViaObjectPropetyOptions;
|
||||
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.validators.AntiXssValidation;
|
||||
import edu.cornell.mannlib.vitro.webapp.search.VitroSearchTermNames;
|
||||
import edu.cornell.mannlib.vitro.webapp.search.beans.ProhibitedFromSearch;
|
||||
import edu.cornell.mannlib.vitro.webapp.search.solr.SolrSetup;
|
||||
import edu.cornell.mannlib.vitro.webapp.utils.FrontEndEditingUtils;
|
||||
import edu.cornell.mannlib.vitro.webapp.utils.FrontEndEditingUtils.EditMode;
|
||||
|
||||
/**
|
||||
* Generates the edit configuration for a default property form.
|
||||
*
|
||||
* This handles the default object property auto complete.
|
||||
*
|
||||
* If a default property form is request and the number of indivdiuals
|
||||
* found in the range is too large, the the auto complete setup and
|
||||
* template will be used instead.
|
||||
*/
|
||||
public class DefaultObjectPropertyFormGenerator implements EditConfigurationGenerator {
|
||||
|
||||
//TODO: bdc34 why does the DefaultObjectPropertyForm have all this data property stuff?
|
||||
private Log log = LogFactory.getLog(DefaultObjectPropertyFormGenerator.class);
|
||||
private boolean isObjectPropForm = false;
|
||||
private Log log = LogFactory.getLog(DefaultObjectPropertyFormGenerator.class);
|
||||
private String subjectUri = null;
|
||||
private String predicateUri = null;
|
||||
private String objectUri = null;
|
||||
private String datapropKeyStr= null;
|
||||
private int dataHash = 0;
|
||||
|
||||
private String dataLiteral = null;
|
||||
private String objectUri = null;
|
||||
|
||||
private String objectPropertyTemplate = "defaultPropertyForm.ftl";
|
||||
private String dataPropertyTemplate = "defaultDataPropertyForm.ftl";
|
||||
private String acObjectPropertyTemplate = "autoCompleteObjectPropForm.ftl";
|
||||
|
||||
protected boolean doAutoComplete = false;
|
||||
protected boolean tooManyRangeIndividuals = false;
|
||||
|
||||
protected long maxNonACRangeIndividualCount = 1000;
|
||||
|
||||
private static HashMap<String,String> defaultsForXSDtypes ;
|
||||
static {
|
||||
defaultsForXSDtypes = new HashMap<String,String>();
|
||||
//defaultsForXSDtypes.put("http://www.w3.org/2001/XMLSchema#dateTime","2001-01-01T12:00:00");
|
||||
defaultsForXSDtypes.put("http://www.w3.org/2001/XMLSchema#dateTime","#Unparseable datetime defaults to now");
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public EditConfigurationVTwo getEditConfiguration(VitroRequest vreq,
|
||||
HttpSession session) throws Exception {
|
||||
if(!EditConfigurationUtils.isObjectProperty(EditConfigurationUtils.getPredicateUri(vreq), vreq)) {
|
||||
throw new Exception("DefaultObjectPropertyFormGenerator does not handle data properties.");
|
||||
}
|
||||
|
||||
if( tooManyRangeOptions( vreq, session ) ){
|
||||
tooManyRangeIndividuals = true;
|
||||
doAutoComplete = true;
|
||||
}
|
||||
|
||||
//Check if create new and return specific edit configuration from that generator.
|
||||
if(DefaultAddMissingIndividualFormGenerator.isCreateNewIndividual(vreq, session)) {
|
||||
DefaultAddMissingIndividualFormGenerator generator = new DefaultAddMissingIndividualFormGenerator();
|
||||
return generator.getEditConfiguration(vreq, session);
|
||||
}
|
||||
|
||||
|
||||
//TODO: Add a generator for delete: based on command being delete - propDelete.jsp
|
||||
//Generate a edit configuration for the default object property form and return it.
|
||||
//if(DefaultDeleteGenerator.isDelete( vreq,session)){
|
||||
|
@ -74,7 +100,33 @@ public class DefaultObjectPropertyFormGenerator implements EditConfigurationGene
|
|||
return getDefaultObjectEditConfiguration(vreq, session);
|
||||
}
|
||||
|
||||
private EditConfigurationVTwo getDefaultObjectEditConfiguration(VitroRequest vreq, HttpSession session) throws Exception {
|
||||
private boolean tooManyRangeOptions(VitroRequest vreq, HttpSession session ) throws SolrServerException {
|
||||
List<String> types = getRangeTypes(vreq);
|
||||
SolrServer solrServer = SolrSetup.getSolrServer(session.getServletContext());
|
||||
|
||||
long count = 0;
|
||||
for( String type:types){
|
||||
//solr query for type count.
|
||||
SolrQuery query = new SolrQuery();
|
||||
if( VitroVocabulary.OWL_THING.equals( type )){
|
||||
query.setQuery( "*:*" );
|
||||
}else{
|
||||
query.setQuery( VitroSearchTermNames.RDFTYPE + ":" + type);
|
||||
}
|
||||
query.setRows(0);
|
||||
|
||||
QueryResponse rsp = solrServer.query(query);
|
||||
SolrDocumentList docs = rsp.getResults();
|
||||
long found = docs.getNumFound();
|
||||
count = count + found;
|
||||
if( count > maxNonACRangeIndividualCount )
|
||||
break;
|
||||
}
|
||||
|
||||
return count > maxNonACRangeIndividualCount ;
|
||||
}
|
||||
|
||||
private EditConfigurationVTwo getDefaultObjectEditConfiguration(VitroRequest vreq, HttpSession session) throws Exception {
|
||||
EditConfigurationVTwo editConfiguration = new EditConfigurationVTwo();
|
||||
|
||||
//process subject, predicate, object parameters
|
||||
|
@ -112,19 +164,21 @@ public class DefaultObjectPropertyFormGenerator implements EditConfigurationGene
|
|||
//After the main processing is done, check if select from existing process
|
||||
processProhibitedFromSearch(vreq, session, editConfiguration);
|
||||
|
||||
//Form title and submit label now moved to edit configuration template
|
||||
//TODO: check if edit configuration template correct place to set those or whether
|
||||
//additional methods here should be used and reference instead, e.g. edit configuration template could call
|
||||
//default obj property form.populateTemplate or some such method
|
||||
//Select from existing also set within template itself
|
||||
//Form title and submit label moved to template
|
||||
setTemplate(editConfiguration, vreq);
|
||||
|
||||
editConfiguration.addValidator(new AntiXssValidation());
|
||||
|
||||
//Set edit key
|
||||
setEditKey(editConfiguration, vreq);
|
||||
|
||||
//Adding additional data, specifically edit mode
|
||||
addFormSpecificData(editConfiguration, vreq);
|
||||
if( doAutoComplete ){
|
||||
addFormSpecificDataForAC(editConfiguration, vreq, session);
|
||||
}else{
|
||||
addFormSpecificData(editConfiguration, vreq);
|
||||
}
|
||||
|
||||
return editConfiguration;
|
||||
}
|
||||
|
||||
|
@ -135,12 +189,10 @@ public class DefaultObjectPropertyFormGenerator implements EditConfigurationGene
|
|||
|
||||
private void setTemplate(EditConfigurationVTwo editConfiguration,
|
||||
VitroRequest vreq) {
|
||||
String template = objectPropertyTemplate;
|
||||
|
||||
if(EditConfigurationUtils.isDataProperty(editConfiguration.getPredicateUri(), vreq)){
|
||||
template = dataPropertyTemplate;
|
||||
}
|
||||
editConfiguration.setTemplate(template);
|
||||
if( doAutoComplete )
|
||||
editConfiguration.setTemplate(acObjectPropertyTemplate);
|
||||
else
|
||||
editConfiguration.setTemplate(objectPropertyTemplate);
|
||||
|
||||
}
|
||||
|
||||
|
@ -167,14 +219,11 @@ public class DefaultObjectPropertyFormGenerator implements EditConfigurationGene
|
|||
//"object" : [ "objectVar" , "${objectUriJson}" , "URI"],
|
||||
if(EditConfigurationUtils.isObjectProperty(predicateUri, vreq)) {
|
||||
log.debug("This is an object property: " + predicateUri);
|
||||
//not concerned about remainder, can move into default obj prop form if required
|
||||
this.isObjectPropForm = true;
|
||||
this.initObjectParameters(vreq);
|
||||
this.processObjectPropForm(vreq, editConfiguration);
|
||||
} else {
|
||||
log.debug("This is a data property: " + predicateUri);
|
||||
this.isObjectPropForm = false;
|
||||
this.processDataPropForm(vreq, editConfiguration);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -191,38 +240,21 @@ public class DefaultObjectPropertyFormGenerator implements EditConfigurationGene
|
|||
//pretends this is a data property editing statement and throws an error
|
||||
//TODO: Check if null in case no object uri exists but this is still an object property
|
||||
}
|
||||
|
||||
private void processDataPropForm(VitroRequest vreq, EditConfigurationVTwo editConfiguration) {
|
||||
//bdc34
|
||||
throw new Error("DefaultObjectPropertyForm should not be doing data property editing");
|
||||
}
|
||||
|
||||
|
||||
//Get N3 required
|
||||
//Handles both object and data property
|
||||
private List<String> generateN3Required(VitroRequest vreq) {
|
||||
List<String> n3ForEdit = new ArrayList<String>();
|
||||
String editString = "?subject ?predicate ";
|
||||
if(this.isObjectPropForm) {
|
||||
editString += "?objectVar";
|
||||
} else {
|
||||
DataProperty prop = EditConfigurationUtils.getDataProperty(vreq);
|
||||
String localName = prop.getLocalName();
|
||||
String dataLiteral = localName + "Edited";
|
||||
editString += "?"+dataLiteral;
|
||||
}
|
||||
String editString = "?subject ?predicate ";
|
||||
editString += "?objectVar";
|
||||
editString += " .";
|
||||
n3ForEdit.add(editString);
|
||||
return n3ForEdit;
|
||||
}
|
||||
|
||||
private List<String> generateN3Optional() {
|
||||
List<String> n3Inverse = new ArrayList<String>();
|
||||
//Note that for proper substitution, spaces expected between variables, i.e. string
|
||||
//of n3 format
|
||||
//Set only if object property form
|
||||
if(this.isObjectPropForm) {
|
||||
n3Inverse.add("?objectVar ?inverseProp ?subject .");
|
||||
}
|
||||
List<String> n3Inverse = new ArrayList<String>();
|
||||
n3Inverse.add("?objectVar ?inverseProp ?subject .");
|
||||
return n3Inverse;
|
||||
|
||||
}
|
||||
|
@ -258,22 +290,14 @@ public class DefaultObjectPropertyFormGenerator implements EditConfigurationGene
|
|||
private void setUrisAndLiteralsOnForm(EditConfigurationVTwo editConfiguration, VitroRequest vreq) {
|
||||
List<String> urisOnForm = new ArrayList<String>();
|
||||
List<String> literalsOnForm = new ArrayList<String>();
|
||||
if(EditConfigurationUtils.isDataProperty(EditConfigurationUtils.getPredicateUri(vreq), vreq)) {
|
||||
//if data property set to data literal
|
||||
literalsOnForm.add(dataLiteral);
|
||||
} else {
|
||||
//uris on form should be empty if data property
|
||||
urisOnForm.add("objectVar");
|
||||
}
|
||||
|
||||
//uris on form should be empty if data property
|
||||
urisOnForm.add("objectVar");
|
||||
|
||||
editConfiguration.setUrisOnform(urisOnForm);
|
||||
editConfiguration.setLiteralsOnForm(literalsOnForm);
|
||||
}
|
||||
|
||||
private String getDataLiteral(VitroRequest vreq) {
|
||||
DataProperty prop = EditConfigurationUtils.getDataProperty(vreq);
|
||||
return prop.getLocalName() + "Edited";
|
||||
}
|
||||
|
||||
|
||||
//This is for various items
|
||||
private void setSparqlQueries(EditConfigurationVTwo editConfiguration) {
|
||||
//Sparql queries defining retrieval of literals etc.
|
||||
|
@ -298,40 +322,29 @@ public class DefaultObjectPropertyFormGenerator implements EditConfigurationGene
|
|||
HashMap<String, String> map = new HashMap<String, String>();
|
||||
return map;
|
||||
}
|
||||
|
||||
|
||||
private void setFields(EditConfigurationVTwo editConfiguration, VitroRequest vreq, String predicateUri) throws Exception {
|
||||
Map<String, FieldVTwo> fields = new HashMap<String, FieldVTwo>();
|
||||
if(EditConfigurationUtils.isObjectProperty(EditConfigurationUtils.getPredicateUri(vreq), vreq)) {
|
||||
fields = getObjectPropertyField(editConfiguration, vreq);
|
||||
} else {
|
||||
throw new Exception("DefaultObjectPropertyFormGenerator does not handle data properties.");
|
||||
}
|
||||
|
||||
editConfiguration.setFields(fields);
|
||||
}
|
||||
|
||||
private Map<String, FieldVTwo> getObjectPropertyField(
|
||||
EditConfigurationVTwo editConfiguration, VitroRequest vreq) throws Exception {
|
||||
Map<String, FieldVTwo> fields = new HashMap<String, FieldVTwo>();
|
||||
private void setFields(EditConfigurationVTwo editConfiguration, VitroRequest vreq, String predicateUri) throws Exception {
|
||||
FieldVTwo field = new FieldVTwo();
|
||||
field.setName("objectVar");
|
||||
//queryForExisting is not being used anywhere in Field
|
||||
|
||||
List<String> validators = new ArrayList<String>();
|
||||
validators.add("nonempty");
|
||||
field.setValidators(validators);
|
||||
|
||||
field.setOptions( new IndividualsViaObjectPropetyOptions(
|
||||
if( ! doAutoComplete ){
|
||||
field.setOptions( new IndividualsViaObjectPropetyOptions(
|
||||
subjectUri,
|
||||
predicateUri,
|
||||
objectUri));
|
||||
|
||||
objectUri));
|
||||
}else{
|
||||
field.setOptions(null);
|
||||
}
|
||||
|
||||
Map<String, FieldVTwo> fields = new HashMap<String, FieldVTwo>();
|
||||
fields.put(field.getName(), field);
|
||||
return fields;
|
||||
|
||||
|
||||
}
|
||||
|
||||
editConfiguration.setFields(fields);
|
||||
}
|
||||
|
||||
private void prepareForUpdate(VitroRequest vreq, HttpSession session, EditConfigurationVTwo editConfiguration) {
|
||||
//Here, retrieve model from
|
||||
|
@ -390,7 +403,90 @@ public class DefaultObjectPropertyFormGenerator implements EditConfigurationGene
|
|||
formSpecificData.put("objectSelect", objectSelect);
|
||||
editConfiguration.setFormSpecificData(formSpecificData);
|
||||
}
|
||||
|
||||
public void addFormSpecificDataForAC(EditConfigurationVTwo editConfiguration, VitroRequest vreq, HttpSession session) throws SolrServerException {
|
||||
HashMap<String, Object> formSpecificData = new HashMap<String, Object>();
|
||||
//Get the edit mode
|
||||
formSpecificData.put("editMode", getEditMode(vreq).toString().toLowerCase());
|
||||
|
||||
//We also need the type of the object itself
|
||||
List<String> types = getRangeTypes(vreq);
|
||||
//if types array contains only owl:Thing, the search will not return any results
|
||||
//In this case, set an empty array
|
||||
if(types.size() == 1 && types.get(0).equals(VitroVocabulary.OWL_THING) ){
|
||||
types = new ArrayList<String>();
|
||||
}
|
||||
|
||||
formSpecificData.put("objectTypes", StringUtils.join(types, ","));
|
||||
|
||||
//Get label for individual if it exists
|
||||
if(EditConfigurationUtils.getObjectIndividual(vreq) != null) {
|
||||
String objectLabel = EditConfigurationUtils.getObjectIndividual(vreq).getName();
|
||||
formSpecificData.put("objectLabel", objectLabel);
|
||||
}
|
||||
|
||||
//TODO: find out if there are any individuals in the classes of objectTypes
|
||||
formSpecificData.put("rangeIndividualsExist", rangeIndividualsExist(session,types) );
|
||||
|
||||
formSpecificData.put("sparqlForAcFilter", getSparqlForAcFilter(vreq));
|
||||
editConfiguration.setTemplate(acObjectPropertyTemplate);
|
||||
editConfiguration.setFormSpecificData(formSpecificData);
|
||||
}
|
||||
|
||||
private Object rangeIndividualsExist(HttpSession session, List<String> types) throws SolrServerException {
|
||||
SolrServer solrServer = SolrSetup.getSolrServer(session.getServletContext());
|
||||
|
||||
boolean rangeIndividualsFound = false;
|
||||
for( String type:types){
|
||||
//solr for type count.
|
||||
SolrQuery query = new SolrQuery();
|
||||
query.setQuery( VitroSearchTermNames.RDFTYPE + ":" + type);
|
||||
query.setRows(0);
|
||||
|
||||
QueryResponse rsp = solrServer.query(query);
|
||||
SolrDocumentList docs = rsp.getResults();
|
||||
if( docs.getNumFound() > 0 ){
|
||||
rangeIndividualsFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return rangeIndividualsFound;
|
||||
}
|
||||
|
||||
protected List<String> getRangeTypes(VitroRequest vreq) {
|
||||
Individual subject = EditConfigurationUtils.getSubjectIndividual(vreq);
|
||||
String predicateUri = EditConfigurationUtils.getPredicateUri(vreq);
|
||||
WebappDaoFactory wDaoFact = vreq.getWebappDaoFactory();
|
||||
List<String> types = new ArrayList<String>();
|
||||
List <VClass> vclasses = new ArrayList<VClass>();
|
||||
vclasses = wDaoFact.getVClassDao().getVClassesForProperty(subject.getVClassURI(),predicateUri);
|
||||
for(VClass v: vclasses) {
|
||||
types.add(v.getURI());
|
||||
}
|
||||
return types;
|
||||
}
|
||||
|
||||
/** get the auto complete edit mode */
|
||||
public EditMode getEditMode(VitroRequest vreq) {
|
||||
//In this case, the original jsp didn't rely on FrontEndEditingUtils
|
||||
//but instead relied on whether or not the object Uri existed
|
||||
String objectUri = EditConfigurationUtils.getObjectUri(vreq);
|
||||
EditMode editMode = FrontEndEditingUtils.EditMode.ADD;
|
||||
if(objectUri != null && !objectUri.isEmpty()) {
|
||||
editMode = FrontEndEditingUtils.EditMode.EDIT;
|
||||
|
||||
}
|
||||
return editMode;
|
||||
}
|
||||
|
||||
|
||||
public String getSparqlForAcFilter(VitroRequest vreq) {
|
||||
String subject = EditConfigurationUtils.getSubjectUri(vreq);
|
||||
String predicate = EditConfigurationUtils.getPredicateUri(vreq);
|
||||
//Get all objects for existing predicate, filters out results from addition and edit
|
||||
String query = "SELECT ?objectVar WHERE { " +
|
||||
"<" + subject + "> <" + predicate + "> ?objectVar .} ";
|
||||
return query;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -95,8 +95,9 @@ public class EditConfigurationTemplateModel extends BaseTemplateModel {
|
|||
WebappDaoFactory wdf = vreq.getWebappDaoFactory();
|
||||
for(String fieldName: editConfig.getFields().keySet()){
|
||||
FieldVTwo field = editConfig.getField(fieldName);
|
||||
if( field.getFieldOptions() == null ){
|
||||
continue;
|
||||
if( field.getFieldOptions() == null ){
|
||||
//putting empty map in here because FM can't deal
|
||||
pageData.put(fieldName, Collections.EMPTY_MAP);
|
||||
}
|
||||
Map<String, String> optionsMap = SelectListGeneratorVTwo.getOptions(editConfig, fieldName, wdf);
|
||||
optionsMap = SelectListGeneratorVTwo.getSortedMap(optionsMap);
|
||||
|
|
|
@ -0,0 +1,148 @@
|
|||
<#-- $This file is distributed under the terms of the license in /doc/license.txt$ -->
|
||||
|
||||
<h1>autoCompleteObjectPropForm.ftl</h1>
|
||||
|
||||
<#--Assign variables from editConfig-->
|
||||
<#assign rangeOptions = editConfiguration.pageData.objectVar />
|
||||
<#--
|
||||
<#assign rangeOptionsExist = false />
|
||||
<#if (rangeOptions?keys?size > 0)>
|
||||
<#assign rangeOptionsExist = true/>
|
||||
</#if>
|
||||
-->
|
||||
|
||||
|
||||
<#assign rangeOptionsExist = true />
|
||||
|
||||
<#assign objectTypes = editConfiguration.pageData.objectTypes />
|
||||
<#assign objectTypesSize = objectTypes?length />
|
||||
<#assign objectTypesExist = false />
|
||||
<#assign multipleTypes = false />
|
||||
<#if (objectTypesSize > 1)>
|
||||
<#assign objectTypesExist = true />
|
||||
</#if>
|
||||
<#if objectTypes?contains(",")>
|
||||
<#assign multipleTypes = true/>
|
||||
</#if>
|
||||
<#assign sparqlForAcFilter = editConfiguration.pageData.sparqlForAcFilter />
|
||||
<#assign editMode = editConfiguration.pageData.editMode />
|
||||
<#assign propertyNameForDisplay = "" />
|
||||
<#if editConfiguration.objectPropertyNameForDisplay?has_content>
|
||||
<#assign propertyNameForDisplay = editConfiguration.objectPropertyNameForDisplay />
|
||||
</#if>
|
||||
<#if editMode = "edit" >
|
||||
<#assign titleVerb = "Edit" />
|
||||
<#assign objectLabel = editConfiguration.pageData.objectLabel />
|
||||
<#assign selectedObjectUri = editConfiguration.objectUri />
|
||||
<#assign submitButtonText = "Save Change" />
|
||||
<#else>
|
||||
<#assign titleVerb = "Add" >
|
||||
<#assign objectLabel = "" />
|
||||
<#assign selectedObjectUri = ""/>
|
||||
<#assign submitButtonText = "Create Entry" />
|
||||
</#if>
|
||||
|
||||
<#if editConfiguration.formTitle?contains("collaborator") >
|
||||
<#assign formTitle = "Select an existing Collaborator for ${editConfiguration.subjectName}" />
|
||||
<#else>
|
||||
<#assign formTitle = editConfiguration.formTitle />
|
||||
</#if>
|
||||
<#--In order to fill out the subject-->
|
||||
<#assign acFilterForIndividuals = "['" + editConfiguration.subjectUri + "']" />
|
||||
|
||||
range options ${rangeOptions?keys?size!"FUCK"}
|
||||
<#if rangeOptionsExist >FUXINGEXIST!<#else>NOEXIST!</#if>
|
||||
|
||||
|
||||
<h2>${formTitle}</h2>
|
||||
|
||||
<#if editConfiguration.propertySelectFromExisting = true>
|
||||
<#if rangeOptionsExist = true >
|
||||
<form class="customForm" action = "${submitUrl}">
|
||||
<input type="hidden" name="editKey" id="editKey" value="${editKey}" role="input" />
|
||||
<#if editConfiguration.propertyPublicDescription?has_content>
|
||||
<p>${editConfiguration.propertyPublicDescription}</p>
|
||||
</#if>
|
||||
|
||||
<#---This section should become autocomplete instead-->
|
||||
<p>
|
||||
<label for="object"> ${propertyNameForDisplay?capitalize} Name<span class='requiredHint'> *</span></label>
|
||||
<input class="acSelector" size="50" type="text" id="object" name="objectLabel" acGroupName="object" value="${objectLabel}" />
|
||||
</p>
|
||||
|
||||
<div class="acSelection" acGroupName="object" >
|
||||
<p class="inline">
|
||||
<label>Selected:</label>
|
||||
<span class="acSelectionInfo"></span>
|
||||
<a href="" class="verifyMatch" title="verify match">(Verify this match</a> or
|
||||
<a href="#" class="changeSelection" id="changeSelection">change selection)</a>
|
||||
</p>
|
||||
<input class="acUriReceiver" type="hidden" id="objectVar" name="objectVar" value="${selectedObjectUri}" />
|
||||
</div>
|
||||
|
||||
<#--The above section should be autocomplete-->
|
||||
|
||||
<p>
|
||||
<input type="submit" id="submit" value="${submitButtonText}" role="button" disabled="disabled"/>
|
||||
|
||||
<span class="or"> or </span>
|
||||
<a title="Cancel" class="cancel" href="${cancelUrl}">Cancel</a>
|
||||
</p>
|
||||
</form>
|
||||
<#else>
|
||||
<p> There are no entries in the system from which to select. </p>
|
||||
</#if>
|
||||
</#if>
|
||||
<p> </p>
|
||||
<#if editConfiguration.propertyOfferCreateNewOption = true>
|
||||
<#include "defaultOfferCreateNewOptionForm.ftl">
|
||||
|
||||
</#if>
|
||||
|
||||
<#if editConfiguration.propertySelectFromExisting = false && editConfiguration.propertyOfferCreateNewOption = false>
|
||||
<p>This property is currently configured to prohibit editing. </p>
|
||||
</#if>
|
||||
|
||||
|
||||
<#if editConfiguration.includeDeletionForm = true>
|
||||
<#include "defaultDeletePropertyForm.ftl">
|
||||
</#if>
|
||||
|
||||
|
||||
<#assign sparqlQueryUrl = "${urls.base}/ajax/sparqlQuery" >
|
||||
<#--Passing in object types only if there are any types returned, otherwise
|
||||
the parameter should not be passed at all to the solr search.
|
||||
Also multiple types parameter set to true only if more than one type returned-->
|
||||
<script type="text/javascript">
|
||||
var customFormData = {
|
||||
acUrl: '${urls.base}/autocomplete?tokenize=true',
|
||||
<#if objectTypesExist = true>
|
||||
acTypes: {object: '${objectTypes}'},
|
||||
</#if>
|
||||
<#if multipleTypes = true>
|
||||
acMultipleTypes: 'true',
|
||||
</#if>
|
||||
editMode: '${editMode}',
|
||||
typeName:'${propertyNameForDisplay}',
|
||||
acSelectOnly: 'true',
|
||||
sparqlForAcFilter: '${sparqlForAcFilter}',
|
||||
sparqlQueryUrl: '${sparqlQueryUrl}',
|
||||
acFilterForIndividuals: ${acFilterForIndividuals},
|
||||
defaultTypeName: '${propertyNameForDisplay}', // used in repair mode to generate button text
|
||||
baseHref: '${urls.base}/individual?uri='
|
||||
};
|
||||
</script>
|
||||
<#--
|
||||
edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.generators.AutocompleteObjectPropertyFormGenerator
|
||||
edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.generators.AddAttendeeRoleToPersonGenerator
|
||||
-->
|
||||
|
||||
${stylesheets.add('<link rel="stylesheet" href="${urls.base}/js/jquery-ui/css/smoothness/jquery-ui-1.8.9.custom.css" />')}
|
||||
${stylesheets.add('<link rel="stylesheet" href="${urls.base}/templates/freemarker/edit/forms/css/customForm.css" />')}
|
||||
${stylesheets.add('<link rel="stylesheet" href="${urls.base}/templates/freemarker/edit/forms/css/customFormWithAutocomplete.css" />')}
|
||||
|
||||
|
||||
${scripts.add('<script type="text/javascript" src="${urls.base}/js/jquery-ui/js/jquery-ui-1.8.9.custom.min.js"></script>',
|
||||
'<script type="text/javascript" src="${urls.base}/js/customFormUtils.js"></script>',
|
||||
'<script type="text/javascript" src="${urls.base}/js/browserUtils.js"></script>',
|
||||
'<script type="text/javascript" src="${urls.base}/templates/freemarker/edit/forms/js/customFormWithAutocomplete.js"></script>')}
|
149
webapp/web/templates/freemarker/edit/forms/css/customForm.css
Normal file
149
webapp/web/templates/freemarker/edit/forms/css/customForm.css
Normal file
|
@ -0,0 +1,149 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
form.customForm div {
|
||||
clear: left;
|
||||
}
|
||||
form.customForm h6 {
|
||||
font-size: 110%;
|
||||
}
|
||||
form.customForm div.addNewLink {
|
||||
float: left;
|
||||
clear: none;
|
||||
margin-left: 5em;
|
||||
margin-top: .9em;
|
||||
width: 200px;
|
||||
padding: .8em;
|
||||
border: 1px solid #9c9c9c;
|
||||
display: none; /* Hide if Javascript disabled. Javascript will show. */
|
||||
}
|
||||
form.customForm .existing span.requiredHint,
|
||||
form.customForm .new span.requiredHint {
|
||||
display: none; /* Hide if Javascript disabled. Javascript will show. */
|
||||
}
|
||||
form.customForm .existing {
|
||||
float: left;
|
||||
clear: none;
|
||||
}
|
||||
.existingOrNew {
|
||||
font-style: italic;
|
||||
margin-left: 1em;
|
||||
}
|
||||
.new {
|
||||
padding: .6em 0 .6em 1.5em;
|
||||
border: 1px solid #9c9c9c;
|
||||
width: 300px;
|
||||
}
|
||||
form.customForm p.inline input,
|
||||
form.customForm p.inline label {
|
||||
float: left;
|
||||
clear: left;
|
||||
}
|
||||
form.customForm p.inline.year input {
|
||||
margin-top: -1.75em;
|
||||
}
|
||||
input,
|
||||
select,
|
||||
form.customForm p {
|
||||
margin-top: 0;
|
||||
padding-top: 0;
|
||||
margin-bottom: 0;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
option {
|
||||
padding: 0 2px;
|
||||
}
|
||||
form.customForm .hint {
|
||||
color: #9c9c9c;
|
||||
font-weight: normal;
|
||||
}
|
||||
form.customForm .requiredHint {
|
||||
color: #c00;
|
||||
font-weight: normal;
|
||||
font-size: small;
|
||||
}
|
||||
form.customForm #requiredLegend {
|
||||
font-style: italic;
|
||||
margin-top: .5em;
|
||||
}
|
||||
form.customForm p.validationError {
|
||||
clear: both;
|
||||
margin-bottom: 1.8em;
|
||||
margin-top: 0;
|
||||
padding-top: 0;
|
||||
padding-left: .4em;
|
||||
font-size: .8em;
|
||||
}
|
||||
form.customForm a.close {
|
||||
float: right;
|
||||
margin-right: 1em;
|
||||
font-size: 90%;
|
||||
}
|
||||
form.customForm a.close:link,
|
||||
form.customForm a.close:visited {
|
||||
border-color: #ff7700;
|
||||
color: #ff7700;
|
||||
}
|
||||
form.customForm textarea {
|
||||
width: 30%;
|
||||
}
|
||||
div.acSelection {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
#ie67DisableWrapper {
|
||||
display: none;
|
||||
}
|
||||
form.customForm input.concept-search {
|
||||
float: right;
|
||||
margin-right: 1em;
|
||||
margin-bottom: 1em;
|
||||
background-color: #317e95;
|
||||
}
|
||||
form.customForm h4.services {
|
||||
margin-bottom: -5px;
|
||||
margin-top: -12px;
|
||||
}
|
||||
form.customForm p.inline-search {
|
||||
float: left;
|
||||
clear: left;
|
||||
}
|
||||
form.customForm p.inline-search #searchTerm{
|
||||
margin-top: 6px;
|
||||
}
|
||||
/* <------ DATE TIME*/
|
||||
form.customForm label.dateTime {
|
||||
display: inline;
|
||||
}
|
||||
form.customForm fieldset {
|
||||
display: inline;
|
||||
}
|
||||
fieldset.dateTime label {
|
||||
display: inline;
|
||||
}
|
||||
fieldset.dateTime select {
|
||||
margin-top: 0;
|
||||
}
|
||||
/* ---------------------------------- */
|
||||
/* ----- FOR MANAGE PUBLICATIONS ---- */
|
||||
/* ---------------------------------- */
|
||||
section#pubsContainer {
|
||||
margin-top:-8px;
|
||||
padding-left:25px;
|
||||
}
|
||||
section#pubsContainer ul {
|
||||
padding-left:25px;
|
||||
text-indent:-25px;
|
||||
}
|
||||
section#pubsContainer li {
|
||||
margin-bottom:6px;
|
||||
line-height:20px;
|
||||
}
|
||||
section#pubsContainer input {
|
||||
margin-right:8px;
|
||||
}
|
||||
/* ---------------------------------- */
|
||||
/* --------- MISCELLANEOUS -------- */
|
||||
/* ------------------------------- */
|
||||
img#indicator {
|
||||
padding-left:60px;
|
||||
}
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
@import url("autocomplete.css");
|
||||
|
||||
/* Although Javascript hides these on page load, hide here as well to avoid the flash on page load.
|
||||
This needs to be removed to support a non-JS version of the form. */
|
||||
.fullViewOnly,
|
||||
#submit,
|
||||
.or,
|
||||
#requiredLegend {
|
||||
display: none;
|
||||
}
|
||||
form.customForm p.inline label {
|
||||
display: inline;
|
||||
clear: none;
|
||||
float: none;
|
||||
margin-right: 1em;
|
||||
}
|
||||
.verifyMatch {
|
||||
margin-left: .5em;
|
||||
}
|
||||
form.customForm h4 {
|
||||
margin-top: 1em;
|
||||
margin-bottom: .75em;
|
||||
}
|
||||
.acSelector[disabled="disabled"]{
|
||||
border-width: 0;
|
||||
background: none;
|
||||
color: #000;
|
||||
}
|
||||
.disabledSubmit {
|
||||
cursor: default ! important;
|
||||
}
|
||||
span.readOnly {
|
||||
color: #000;
|
||||
}
|
||||
/* special styles for addPublicationToPerson.ftl
|
||||
volume, number, issue fields and start/end page fields */
|
||||
label.vniLabels {
|
||||
padding-left: 50px;
|
||||
}
|
||||
input.vniInputs {
|
||||
margin-left: 57px;
|
||||
}
|
||||
label.sepLabels {
|
||||
padding-left: 31px;
|
||||
}
|
||||
input.sepInputs {
|
||||
margin-left: 57px;
|
||||
}
|
|
@ -0,0 +1,642 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
var customForm = {
|
||||
|
||||
/* *** Initial page setup *** */
|
||||
|
||||
onLoad: function() {
|
||||
|
||||
if (this.disableFormInUnsupportedBrowsers()) {
|
||||
return;
|
||||
}
|
||||
this.mixIn();
|
||||
this.initObjects();
|
||||
this.initPage();
|
||||
},
|
||||
|
||||
disableFormInUnsupportedBrowsers: function() {
|
||||
var disableWrapper = $('#ie67DisableWrapper');
|
||||
|
||||
// Check for unsupported browsers only if the element exists on the page
|
||||
if (disableWrapper.length) {
|
||||
if (vitro.browserUtils.isIELessThan8()) {
|
||||
disableWrapper.show();
|
||||
$('.noIE67').hide();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
mixIn: function() {
|
||||
// Mix in the custom form utility methods
|
||||
$.extend(this, vitro.customFormUtils);
|
||||
|
||||
// Get the custom form data from the page
|
||||
$.extend(this, customFormData);
|
||||
},
|
||||
|
||||
// On page load, create references for easy access to form elements.
|
||||
// NB These must be assigned after the elements have been loaded onto the page.
|
||||
initObjects: function(){
|
||||
|
||||
this.form = $('form.customForm');
|
||||
this.fullViewOnly = $('.fullViewOnly');
|
||||
this.button = $('#submit');
|
||||
this.requiredLegend = $('#requiredLegend');
|
||||
this.typeSelector = this.form.find('select#typeSelector');
|
||||
this.typeSelectorInput = this.form.find('input#typeSelectorInput');
|
||||
this.typeSelectorSpan = this.form.find('span#typeSelectorSpan');
|
||||
this.or = $('span.or');
|
||||
this.cancel = this.form.find('.cancel');
|
||||
this.acHelpTextClass = 'acSelectorWithHelpText';
|
||||
// this.verifyMatch is referenced in bindEventListeners to size and open
|
||||
// the verify popup window. Although there could be multiple verifyMatch objects
|
||||
// selecting one and binding the event works for all of them
|
||||
this.verifyMatch = this.form.find('.verifyMatch');
|
||||
|
||||
// find all the acSelector input elements
|
||||
this.acSelectors = [] ;
|
||||
|
||||
this.form.find('.acSelector').each(function() {
|
||||
customForm.acSelectors.push($(this));
|
||||
});
|
||||
|
||||
// find all the acSelection div elements
|
||||
this.acSelections = new Object();
|
||||
|
||||
this.form.find('.acSelection').each(function() {
|
||||
var groupName = $(this).attr('acGroupName');
|
||||
customForm.acSelections[groupName] = $(this);
|
||||
});
|
||||
|
||||
// 2-stage forms with only one ac field will not have the acTypes defined
|
||||
// so create an object for when the user selects a type via the typeSelector
|
||||
if ( this.acTypes == undefined || this.acTypes == null ) {
|
||||
this.acTypes = new Object();
|
||||
}
|
||||
|
||||
// forms with multi ac fields will have this defined in customFormData
|
||||
// this is helpful when the type to display is not a single word, like "Subject Area"
|
||||
this.hasMultipleTypeNames = false;
|
||||
if ( this.multipleTypeNames != undefined || this.multipleTypeNames != null ) {
|
||||
this.hasMultipleTypeNames = true;
|
||||
}
|
||||
// Used with the cancel link. If the user cancels after a type selection, this check
|
||||
// ensures that any a/c fields (besides the one associated with the type) will be reset
|
||||
this.clearAcSelections = false;
|
||||
|
||||
},
|
||||
|
||||
// Set up the form on page load
|
||||
initPage: function() {
|
||||
|
||||
if (!this.editMode) {
|
||||
this.editMode = 'add'; // edit vs add: default to add
|
||||
}
|
||||
|
||||
//Flag to clear label of selected object from autocomplete on submission
|
||||
//This is used in the case where the label field is submitted only when a new object is being created
|
||||
if(!this.flagClearLabelForExisting) {
|
||||
this.flagClearLabelForExisting = null;
|
||||
}
|
||||
|
||||
if (!this.formSteps) { // Don't override formSteps specified in form data
|
||||
if ( !this.fullViewOnly.length || this.editMode === 'edit' || this.editMode === 'repair' ) {
|
||||
this.formSteps = 1;
|
||||
// there may also be a 3-step form - look for this.subTypeSelector
|
||||
}
|
||||
else {
|
||||
this.formSteps = 2;
|
||||
}
|
||||
}
|
||||
|
||||
if(!this.doNotRemoveOriginalObject) {
|
||||
this.doNotRemoveOriginalObject = false;
|
||||
}
|
||||
|
||||
this.bindEventListeners();
|
||||
|
||||
$.each(this.acSelectors, function() {
|
||||
customForm.initAutocomplete($(this));
|
||||
});
|
||||
|
||||
this.initElementData();
|
||||
|
||||
this.initFormView();
|
||||
|
||||
},
|
||||
|
||||
initFormView: function() {
|
||||
|
||||
var typeVal = this.typeSelector.val();
|
||||
|
||||
// Put this case first, because in edit mode with
|
||||
// validation errors we just want initFormFullView.
|
||||
// if ((!this.supportEdit) && (this.editMode == 'edit' || this.editMode == 'repair')) {
|
||||
if (this.editMode == 'edit' || this.editMode == 'repair') {
|
||||
this.initFormWithValidationErrors();
|
||||
this.initFormFullView();
|
||||
}
|
||||
else if (this.findValidationErrors()) {
|
||||
this.initFormWithValidationErrors();
|
||||
}
|
||||
|
||||
// If type is already selected when the page loads (Firefox retains value
|
||||
// on a refresh), go directly to full view. Otherwise user has to reselect
|
||||
// twice to get to full view.
|
||||
else if ( this.formSteps == 1 || typeVal.length ) {
|
||||
this.initFormFullView();
|
||||
}
|
||||
else {
|
||||
this.initFormTypeView();
|
||||
}
|
||||
},
|
||||
|
||||
initFormTypeView: function() {
|
||||
|
||||
this.setType(); // empty any previous values (perhaps not needed)
|
||||
this.hideFields(this.fullViewOnly);
|
||||
this.button.hide();
|
||||
this.or.hide();
|
||||
this.requiredLegend.hide();
|
||||
|
||||
this.cancel.unbind('click');
|
||||
},
|
||||
|
||||
initFormFullView: function() {
|
||||
|
||||
this.setType();
|
||||
this.fullViewOnly.show();
|
||||
this.or.show();
|
||||
this.requiredLegend.show();
|
||||
this.button.show();
|
||||
this.setLabels();
|
||||
|
||||
// Set the initial autocomplete help text in the acSelector fields.
|
||||
$.each(this.acSelectors, function() {
|
||||
customForm.addAcHelpText($(this));
|
||||
});
|
||||
|
||||
this.cancel.unbind('click');
|
||||
if (this.formSteps > 1) {
|
||||
this.cancel.click(function() {
|
||||
customForm.clearFormData(); // clear any input and validation errors
|
||||
customForm.initFormTypeView();
|
||||
customForm.clearAcSelections = true;
|
||||
return false;
|
||||
});
|
||||
// In one-step forms, if there is a type selection field, but no value is selected,
|
||||
// hide the acSelector field. The type selection must be made first so that the
|
||||
// autocomplete type can be determined. If a type selection has been made,
|
||||
// unhide the acSelector field.
|
||||
} else if (this.typeSelector.length) {
|
||||
this.typeSelector.val() ? this.fullViewOnly.show() : this.hideFields(this.fullViewOnly);
|
||||
}
|
||||
if ( this.acSelectOnly ) {
|
||||
this.disableSubmit();
|
||||
}
|
||||
},
|
||||
|
||||
initFormWithValidationErrors: function() {
|
||||
// Call initFormFullView first, because showAutocompleteSelection needs
|
||||
// acType, which is set in initFormFullView.
|
||||
this.initFormFullView();
|
||||
|
||||
$.each(this.acSelectors, function() {
|
||||
var $acSelection = customForm.acSelections[$(this).attr('acGroupName')];
|
||||
var uri = $acSelection.find('input.acUriReceiver').val(),
|
||||
label = $(this).val();
|
||||
if (uri && uri != ">SUBMITTED VALUE WAS BLANK<") {
|
||||
customForm.showAutocompleteSelection(label, uri, $(this));
|
||||
}
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
// Bind event listeners that persist over the life of the page. Event listeners
|
||||
// that depend on the view should be initialized in the view setup method.
|
||||
bindEventListeners: function() {
|
||||
|
||||
this.typeSelector.change(function() {
|
||||
var typeVal = $(this).val();
|
||||
this.acCache = {};
|
||||
|
||||
// If an autocomplete selection has been made, undo it.
|
||||
// NEED TO LINK THE TYPE SELECTOR TO THE ACSELECTOR IT'S ASSOCIATED WITH
|
||||
// BECAUSE THERE COULD BE MORE THAN ONE AC FIELD. ASSOCIATION IS MADE VIA
|
||||
// THE SPECIAL "acGroupName" ATTRIBUTE WHICH IS SHARED AMONG THE SELECT AND
|
||||
// THE INPUT AND THE AC SELECTION DIV.
|
||||
if (customForm.editMode != "edit") {
|
||||
customForm.undoAutocompleteSelection($(this));
|
||||
}
|
||||
// Reinitialize view. If no type selection in a two-step form, go back to type view;
|
||||
// otherwise, reinitialize full view.
|
||||
if (!typeVal.length && customForm.formSteps > 1) {
|
||||
customForm.initFormTypeView();
|
||||
}
|
||||
else {
|
||||
customForm.initFormFullView();
|
||||
}
|
||||
});
|
||||
|
||||
this.verifyMatch.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;
|
||||
});
|
||||
|
||||
// loop through all the acSelectors
|
||||
$.each(this.acSelectors, function() {
|
||||
$(this).focus(function() {
|
||||
customForm.deleteAcHelpText($(this));
|
||||
});
|
||||
$(this).blur(function() {
|
||||
customForm.addAcHelpText($(this));
|
||||
});
|
||||
});
|
||||
|
||||
this.form.submit(function() {
|
||||
//TODO: update the following
|
||||
//custom submission for edit mode in case where existing object should not remove original object
|
||||
//if edit mode and custom flag and original uri not equivalent to new uri, then
|
||||
//clear out label field entirely
|
||||
//originally checked edit mode but want to add to work the same way in case an existing object
|
||||
//is selected since the n3 now governs how labels
|
||||
if(customForm.flagClearLabelForExisting != null) {
|
||||
//Find the elements that have had autocomplete executed, tagged by class "userSelected"
|
||||
customForm.form.find('.acSelection.userSelected').each(function() {
|
||||
var groupName = $(this).attr("acGroupName");
|
||||
var inputs = $(this).find("input.acUriReceiver");
|
||||
//if user selected, then clear out the label since we only
|
||||
//want to submit the label as value on form if it's a new label
|
||||
if(inputs.length && $(inputs.eq(0)).attr(customForm.flagClearLabelForExisting)) {
|
||||
var $selectorInput = $("input.acSelector[acGroupName='" + groupName + "']");
|
||||
var $displayInput = $("input.display[acGroupName='" + groupName + "']");
|
||||
$displayInput.val($selectorInput.val());
|
||||
$selectorInput.val('');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
customForm.deleteAcHelpText();
|
||||
});
|
||||
},
|
||||
|
||||
initAutocomplete: function(selectedObj) {
|
||||
this.getAcFilter();
|
||||
//If specific individuals are to be filtered out, add them here
|
||||
//to the filtering list
|
||||
this.getAcFilterForIndividuals();
|
||||
this.acCache = {};
|
||||
|
||||
$(selectedObj).autocomplete({
|
||||
minLength: 3,
|
||||
source: function(request, response) {
|
||||
//Reset the URI of the input to one that says new uri required
|
||||
//That will be overwritten if value selected from autocomplete
|
||||
//We do this everytime the user types anything in the autocomplete box
|
||||
customForm.initDefaultBlankURI(selectedObj);
|
||||
if (request.term in customForm.acCache) {
|
||||
// console.log('found term in cache');
|
||||
response(customForm.acCache[request.term]);
|
||||
return;
|
||||
}
|
||||
// console.log('not getting term from cache');
|
||||
$.ajax({
|
||||
url: customForm.acUrl,
|
||||
dataType: 'json',
|
||||
data: {
|
||||
term: request.term,
|
||||
type: customForm.acTypes[$(selectedObj).attr('acGroupName')],
|
||||
multipleTypes:(customForm.acMultipleTypes == undefined || customForm.acMultipleTypes == null)? null: customForm.acMultipleTypes
|
||||
},
|
||||
complete: function(xhr, status) {
|
||||
// Not sure why, but we need an explicit json parse here.
|
||||
var results = $.parseJSON(xhr.responseText),
|
||||
filteredResults = customForm.filterAcResults(results);
|
||||
customForm.acCache[request.term] = filteredResults;
|
||||
response(filteredResults);
|
||||
}
|
||||
});
|
||||
},
|
||||
select: function(event, ui) {
|
||||
customForm.showAutocompleteSelection(ui.item.label, ui.item.uri, $(selectedObj));
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// Store original or base text with elements that will have text substitutions.
|
||||
// Generally the substitution cannot be made on the current value, since that value
|
||||
// may have changed from the original. So we store the original text with the element to
|
||||
// use as a base for substitutions.
|
||||
initElementData: function() {
|
||||
|
||||
this.placeholderText = '###';
|
||||
this.labelsWithPlaceholders = this.form.find('label, .label').filter(function() {
|
||||
return $(this).html().match(customForm.placeholderText);
|
||||
});
|
||||
this.labelsWithPlaceholders.each(function(){
|
||||
$(this).data('baseText', $(this).html());
|
||||
});
|
||||
|
||||
this.button.data('baseText', this.button.val());
|
||||
|
||||
},
|
||||
//get autocomplete filter with sparql query
|
||||
getAcFilter: function() {
|
||||
|
||||
if (!this.sparqlForAcFilter) {
|
||||
//console.log('autocomplete filtering turned off');
|
||||
this.acFilter = null;
|
||||
return;
|
||||
}
|
||||
|
||||
//console.log("sparql for autocomplete filter: " + this.sparqlForAcFilter);
|
||||
|
||||
// Define this.acFilter here, so in case the sparql query fails
|
||||
// we don't get an error when referencing it later.
|
||||
this.acFilter = [];
|
||||
$.ajax({
|
||||
url: customForm.sparqlQueryUrl,
|
||||
dataType: "json",
|
||||
data: {
|
||||
query: customForm.sparqlForAcFilter
|
||||
},
|
||||
success: function(data, status, xhr) {
|
||||
customForm.setAcFilter(data);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
setAcFilter: function(data) {
|
||||
|
||||
var key = data.head.vars[0];
|
||||
|
||||
$.each(data.results.bindings, function() {
|
||||
customForm.acFilter.push(this[key].value);
|
||||
});
|
||||
},
|
||||
|
||||
filterAcResults: function(results) {
|
||||
var filteredResults;
|
||||
|
||||
if (!this.acFilter || !this.acFilter.length) {
|
||||
//console.log('no autocomplete filtering applied');
|
||||
return results;
|
||||
}
|
||||
|
||||
filteredResults = [];
|
||||
$.each(results, function() {
|
||||
if ($.inArray(this.uri, customForm.acFilter) == -1) {
|
||||
//console.log('adding ' + this.label + ' to filtered results');
|
||||
filteredResults.push(this);
|
||||
}
|
||||
else {
|
||||
//console.log('filtering out ' + this.label);
|
||||
}
|
||||
});
|
||||
return filteredResults;
|
||||
},
|
||||
//To filter out specific individuals, not part of a query
|
||||
//Pass in list of individuals to be filtered out
|
||||
getAcFilterForIndividuals: function() {
|
||||
|
||||
if (!this.acFilterForIndividuals || !this.acFilterForIndividuals.length) {
|
||||
this.acFilterForIndividuals = null;
|
||||
return;
|
||||
}
|
||||
//add this list to the ac filter list
|
||||
customForm.acFilter = customForm.acFilter.concat(this.acFilterForIndividuals);
|
||||
|
||||
},
|
||||
|
||||
showAutocompleteSelection: function(label, uri, selectedObj) {
|
||||
// hide the acSelector field and set it's value to the selected ac item
|
||||
this.hideFields($(selectedObj).parent());
|
||||
$(selectedObj).val(label);
|
||||
|
||||
var $acDiv = this.acSelections[$(selectedObj).attr('acGroupName')];
|
||||
|
||||
// provides a way to monitor selection in other js files, e.g. to hide fields upon selection
|
||||
$acDiv.addClass("userSelected");
|
||||
|
||||
// If the form has a type selector, add type name to label in add mode. In edit mode, use typeSelectorSpan
|
||||
// html. The second case is an "else if" and not an else because the template may not be passing the label
|
||||
// to the acSelection macro or it may not be using the macro at all and the label is hard-coded in the html.
|
||||
if ( this.typeSelector.length && ($acDiv.attr('acGroupName') == this.typeSelector.attr('acGroupName')) ) {
|
||||
$acDiv.find('label').html('Selected ' + this.typeName + ':');
|
||||
}
|
||||
else if ( this.typeSelectorSpan.html() && ($acDiv.attr('acGroupName') == this.typeSelectorInput.attr('acGroupName')) ) {
|
||||
$acDiv.find('label').html('Selected ' + this.typeSelectorSpan.html() + ':');
|
||||
}
|
||||
else if ( $acDiv.find('label').html() == '' ) {
|
||||
$acDiv.find('label').html('Selected ' + this.multipleTypeNames[$(selectedObj).attr('acGroupName')] + ':');
|
||||
}
|
||||
|
||||
$acDiv.show();
|
||||
$acDiv.find("input").val(uri);
|
||||
$acDiv.find("span").html(label);
|
||||
$acDiv.find("a.verifyMatch").attr('href', this.baseHref + uri);
|
||||
|
||||
$changeLink = $acDiv.find('a.changeSelection');
|
||||
$changeLink.click(function() {
|
||||
customForm.undoAutocompleteSelection($acDiv);
|
||||
});
|
||||
|
||||
if ( this.acSelectOnly ) {
|
||||
//On initialization in this mode, submit button is disabled
|
||||
this.enableSubmit();
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
undoAutocompleteSelection: function(selectedObj) {
|
||||
// The test is not just for efficiency: undoAutocompleteSelection empties the acSelector value,
|
||||
// which we don't want to do if user has manually entered a value, since he may intend to
|
||||
// change the type but keep the value. If no new value has been selected, form initialization
|
||||
// below will correctly empty the value anyway.
|
||||
|
||||
var $acSelectionObj = null;
|
||||
var $acSelector = null;
|
||||
|
||||
// Check to see if the parameter is the typeSelector. If it is, we need to get the acSelection div
|
||||
// that is associated with it. Also, when the type is changed, we need to determine whether the user
|
||||
// has selected an existing individual in the corresponding name field or typed the label for a new
|
||||
// individual. If the latter, we do not want to clear the value on type change. The clearAcSelectorVal
|
||||
// boolean controls whether the acSelector value gets cleared.
|
||||
|
||||
var clearAcSelectorVal = true;
|
||||
|
||||
if ( $(selectedObj).attr('id') == "typeSelector" ) {
|
||||
$acSelectionObj = customForm.acSelections[$(selectedObj).attr('acGroupName')];
|
||||
if ( $acSelectionObj.is(':hidden') ) {
|
||||
clearAcSelectorVal = false;
|
||||
}
|
||||
// if the type is being changed after a cancel, any additional a/c fields that may have been set
|
||||
// by the user should be "undone". Only loop through these if this is not the initial type selection
|
||||
if ( customForm.clearAcSelections ) {
|
||||
$.each(customForm.acSelections, function(i, acS) {
|
||||
var $checkSelection = customForm.acSelections[i];
|
||||
if ( $checkSelection.is(':hidden') && $checkSelection.attr('acGroupName') != $acSelectionObj.attr('acGroupName') ) {
|
||||
customForm.resetAcSelection($checkSelection);
|
||||
$acSelector = customForm.getAcSelector($checkSelection);
|
||||
$acSelector.parent('p').show();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
else {
|
||||
$acSelectionObj = $(selectedObj);
|
||||
}
|
||||
|
||||
$acSelector = this.getAcSelector($acSelectionObj);
|
||||
$acSelector.parent('p').show();
|
||||
this.resetAcSelection($acSelectionObj);
|
||||
if ( clearAcSelectorVal == true ) {
|
||||
$acSelector.val('');
|
||||
$("input.display[acGroupName='" + $acSelectionObj.attr('acGroupName') + "']").val("");
|
||||
}
|
||||
customForm.addAcHelpText($acSelector);
|
||||
|
||||
//Resetting so disable submit button again for object property autocomplete
|
||||
if ( this.acSelectOnly ) {
|
||||
this.disableSubmit();
|
||||
}
|
||||
this.clearAcSelections = false;
|
||||
},
|
||||
|
||||
// this is essentially a subtask of undoAutocompleteSelection
|
||||
resetAcSelection: function(selectedObj) {
|
||||
this.hideFields($(selectedObj));
|
||||
$(selectedObj).removeClass('userSelected');
|
||||
$(selectedObj).find("input.acUriReceiver").val(this.blankSentinel);
|
||||
$(selectedObj).find("span").text('');
|
||||
$(selectedObj).find("a.verifyMatch").attr('href', this.baseHref);
|
||||
},
|
||||
|
||||
// loops through the array of acSelector fields and returns the one
|
||||
// associated with the selected object
|
||||
getAcSelector: function(selectedObj){
|
||||
var $selector = null
|
||||
$.each(this.acSelectors, function() {
|
||||
if ( $(this).attr('acGroupName') == $(selectedObj).attr('acGroupName') ) {
|
||||
$selector = $(this);
|
||||
}
|
||||
});
|
||||
return $selector;
|
||||
},
|
||||
|
||||
// Set type uri for autocomplete, and type name for labels and button text.
|
||||
// Note: we still need this in edit mode, to set the text values.
|
||||
setType: function() {
|
||||
var selectedType;
|
||||
|
||||
// If there's no type selector, these values have been specified in customFormData,
|
||||
// and will not change over the life of the form.
|
||||
if (!this.typeSelector.length) {
|
||||
if ( this.editMode == 'edit' && (this.typeSelectorSpan.html() != null && this.typeSelectorInput.val() != null) ) {
|
||||
this.typeName = this.typeSelectorSpan.html();
|
||||
this.acTypes[this.typeSelectorInput.attr('acGroupName')] = this.typeSelectorInput.val();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
selectedType = this.typeSelector.find(':selected');
|
||||
var acTypeKey = this.typeSelector.attr('acGroupName');
|
||||
if (selectedType.val().length) {
|
||||
this.acTypes[acTypeKey] = selectedType.val();
|
||||
this.typeName = selectedType.html();
|
||||
}
|
||||
// reset to empty values; may not need
|
||||
else {
|
||||
delete this.acTypes[acTypeKey];
|
||||
this.typeName = '';
|
||||
}
|
||||
},
|
||||
|
||||
// Set field labels based on type selection. Although these won't change in edit
|
||||
// mode, it's easier to specify the text here than in the jsp.
|
||||
setLabels: function() {
|
||||
var typeName = this.getTypeNameForLabels();
|
||||
|
||||
this.labelsWithPlaceholders.each(function() {
|
||||
var newLabel = $(this).data('baseText').replace(customForm.placeholderText, typeName);
|
||||
$(this).html(newLabel);
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
getTypeNameForLabels: function(selectedObj) {
|
||||
// If this.acType is empty, we are either in a one-step form with no type yet selected,
|
||||
// or in repair mode in a two-step form with no type selected. Use the default type
|
||||
// name specified in the form data.
|
||||
if ( !selectedObj || !this.hasMultipleTypeNames ) {
|
||||
return this.acTypes ? this.typeName : this.capitalize(this.defaultTypeName);
|
||||
}
|
||||
else if ( selectedObj && ( $(selectedObj).attr('acGroupName') == this.typeSelector.attr('acGroupName') ) ) {
|
||||
return this.acTypes ? this.typeName : this.capitalize(this.defaultTypeName);
|
||||
}
|
||||
else {
|
||||
var name = customForm.multipleTypeNames[$(selectedObj).attr('id')];
|
||||
return this.capitalize(name);
|
||||
}
|
||||
},
|
||||
|
||||
// Set the initial help text that appears in the autocomplete field and change the class name
|
||||
addAcHelpText: function(selectedObj) {
|
||||
var typeText;
|
||||
// First case applies on page load; second case applies when the type gets changed. With multiple
|
||||
// ac fields there are cases where we also have to check if the help text is already there
|
||||
if (!$(selectedObj).val() || $(selectedObj).hasClass(this.acHelpTextClass) || $(selectedObj).val().substring(0, 18) == "Select an existing" ) {
|
||||
typeText = this.getTypeNameForLabels($(selectedObj));
|
||||
var helpText = "Select an existing " + typeText + " or create a new one.";
|
||||
//Different for object property autocomplete
|
||||
if ( this.acSelectOnly ) {
|
||||
helpText = "Select an existing " + typeText;
|
||||
}
|
||||
$(selectedObj).val(helpText)
|
||||
.addClass(this.acHelpTextClass);
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
deleteAcHelpText: function(selectedObj) {
|
||||
// on submit, no selectedObj gets passed, so we need to check for this
|
||||
if ( selectedObj ) {
|
||||
if ($(selectedObj).hasClass(this.acHelpTextClass)) {
|
||||
$(selectedObj).val('')
|
||||
.removeClass(this.acHelpTextClass);
|
||||
}
|
||||
}
|
||||
else {
|
||||
$.each(this.acSelectors, function() {
|
||||
if ($(this).hasClass(customForm.acHelpTextClass)) {
|
||||
$(this).val('')
|
||||
.removeClass(customForm.acHelpTextClass);
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
disableSubmit: function() {
|
||||
//Disable submit button until selection made
|
||||
this.button.attr('disabled', 'disabled');
|
||||
this.button.addClass('disabledSubmit');
|
||||
},
|
||||
enableSubmit:function() {
|
||||
this.button.removeAttr('disabled');
|
||||
this.button.removeClass('disabledSubmit');
|
||||
},
|
||||
initDefaultBlankURI:function(selectedObj) {
|
||||
//get uri input for selected object and set to value specified as "blank sentinel"
|
||||
//If blank sentinel is neither null nor an empty string, this means if the user edits an
|
||||
//existing relationship to an object and does not select anything from autocomplete
|
||||
//from that object, the old relationship will be removed in n3 processing
|
||||
var $acDiv = this.acSelections[$(selectedObj).attr('acGroupName')];
|
||||
$acDiv.find("input").val(customForm.blankSentinel);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
$(document).ready(function() {
|
||||
customForm.onLoad();
|
||||
});
|
Loading…
Add table
Add a link
Reference in a new issue