From 3314e5a4b09fe721400583d64416ac80eb9070f7 Mon Sep 17 00:00:00 2001 From: hudajkhan Date: Tue, 3 Sep 2013 15:34:02 -0400 Subject: [PATCH 1/4] updates for label management --- .../individual/IndividualResponseBuilder.java | 4 +- .../ManageLabelsForIndividualGenerator.java | 574 ++++++++++++++++++ .../ConceptSparqlUpdatePreprocessor.java | 129 ++++ .../FoafNameToRdfsLabelPreprocessor.java | 17 +- ...ManageLabelsForIndividualPreprocessor.java | 111 ++++ webapp/web/i18n/all.properties | 3 +- .../individual/manageLabelsForIndividual.js | 223 ++++++- .../individual/manageLabelsForIndividual.ftl | 107 ++-- .../manageLabelsForIndividualAddForm.ftl | 29 + .../manageLabelsForIndividualMacros.ftl | 79 +++ ...ageLabelsForIndividualSubmissionErrors.ftl | 14 + .../freemarker/lib/lib-properties.ftl | 11 +- 12 files changed, 1226 insertions(+), 75 deletions(-) create mode 100644 webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/ManageLabelsForIndividualGenerator.java create mode 100644 webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/preprocessors/ConceptSparqlUpdatePreprocessor.java create mode 100644 webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/preprocessors/ManageLabelsForIndividualPreprocessor.java create mode 100644 webapp/web/templates/freemarker/body/individual/manageLabelsForIndividualAddForm.ftl create mode 100644 webapp/web/templates/freemarker/body/individual/manageLabelsForIndividualMacros.ftl create mode 100644 webapp/web/templates/freemarker/body/individual/manageLabelsForIndividualSubmissionErrors.ftl diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/individual/IndividualResponseBuilder.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/individual/IndividualResponseBuilder.java index e63791df5..2ddca87c2 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/individual/IndividualResponseBuilder.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/individual/IndividualResponseBuilder.java @@ -279,7 +279,9 @@ class IndividualResponseBuilder { log.debug("queryStr = " + queryStr); int theCount = 0; try { - ResultSet results = QueryUtils.getQueryResults(queryStr, vreq); + //ResultSet results = QueryUtils.getQueryResults(queryStr, vreq); + //Get query results across all languages in order for template to show manage labels link correctly + ResultSet results = QueryUtils.getLanguageNeutralQueryResults(queryStr, vreq); if (results.hasNext()) { QuerySolution soln = results.nextSolution(); String countStr = soln.get("labelCount").toString(); diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/ManageLabelsForIndividualGenerator.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/ManageLabelsForIndividualGenerator.java new file mode 100644 index 000000000..a9cb131d7 --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/ManageLabelsForIndividualGenerator.java @@ -0,0 +1,574 @@ +/* $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.io.FileNotFoundException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Locale; +import java.util.Map; + +import javax.servlet.http.HttpSession; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import com.hp.hpl.jena.ontology.OntModel; +import com.hp.hpl.jena.query.Dataset; +import com.hp.hpl.jena.query.QueryExecution; +import com.hp.hpl.jena.query.QueryExecutionFactory; +import com.hp.hpl.jena.query.QuerySolution; +import com.hp.hpl.jena.query.ResultSet; +import com.hp.hpl.jena.rdf.model.Literal; +import com.hp.hpl.jena.rdf.model.RDFNode; +import com.hp.hpl.jena.shared.Lock; +import com.hp.hpl.jena.sparql.resultset.ResultSetMem; +import com.hp.hpl.jena.vocabulary.RDFS; +import com.hp.hpl.jena.vocabulary.XSD; + +import edu.cornell.mannlib.vitro.webapp.auth.policy.PolicyHelper; +import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.Actions; +import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.ifaces.RequestActionConstants; +import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.propstmt.AddDataPropertyStatement; +import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.propstmt.AddObjectPropertyStatement; +import edu.cornell.mannlib.vitro.webapp.beans.DataProperty; +import edu.cornell.mannlib.vitro.webapp.beans.DataPropertyStatement; +import edu.cornell.mannlib.vitro.webapp.beans.Individual; +import edu.cornell.mannlib.vitro.webapp.beans.VClass; +import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; +import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder; +import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder.ParamMap; +import edu.cornell.mannlib.vitro.webapp.dao.ModelAccess; +import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary; +import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory; +import edu.cornell.mannlib.vitro.webapp.dao.jena.QueryUtils; +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.FieldVTwo; +import edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.preprocessors.FoafNameToRdfsLabelPreprocessor; +import edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.preprocessors.ManageLabelsForIndividualPreprocessor; +import edu.cornell.mannlib.vitro.webapp.i18n.selection.LocaleSelectionDataGetter; +import edu.cornell.mannlib.vitro.webapp.i18n.selection.LocaleSelectorUtilities; +import edu.cornell.mannlib.vitro.webapp.i18n.selection.SelectedLocale; +import edu.cornell.mannlib.vitro.webapp.web.templatemodels.individual.DataPropertyStatementTemplateModel; + +/** + *This allows the page to show all the labels for a particular individual and sets up code + *enabling the addition of a new label. Links on the page will allow for removal or editing of a given label. + */ +public class ManageLabelsForIndividualGenerator extends BaseEditConfigurationGenerator implements EditConfigurationGenerator { + public static Log log = LogFactory.getLog(ManageLabelsForIndividualGenerator.class); + private static String template = "manageLabelsForIndividual.ftl"; + private HashMap> labelsSortedByLanguage = null; + private List existingLabelLiterals = null; + //list of language names sorted alphabetically + private List existingSortedLanguageNameList = null; + //This would be for the full list and can be used for the existing labels list as well + + private HashMap fullLanguageNameToCodeMap = null; + private static String predicateUri = RDFS.label.getURI(); + @Override + public EditConfigurationVTwo getEditConfiguration(VitroRequest vreq, HttpSession session) { + + EditConfigurationVTwo config = new EditConfigurationVTwo(); + config.setTemplate(this.getTemplate()); + + initBasics(config, vreq); + initPropertyParameters(vreq, session, config); + + //This form is technically not an object property form in the true sense + //or a data property form because it is used to list the various labels + //and allow for adding new labels + //URL to return to is the same page once addition is complete + this.setUrlToReturnTo(config, vreq); + + config.setSubjectUri(EditConfigurationUtils.getSubjectUri(vreq)); + + setVarNames(config); + config.setDatapropKey( EditConfigurationUtils.getDataHash(vreq) ); + //Add n3, fields, etc. in the case where the user wants to add a label + //N3 required should be empty since the addition of a label is optional in this case + config.setN3Required(this.generateN3Required(vreq)); + config.setN3Optional(this.generateN3Optional(vreq)); + this.setUrisAndLiteralsOnForm(config, vreq); + setUrisAndLiteralsInScope(config); + this.setFields(config, vreq, EditConfigurationUtils + .getPredicateUri(vreq)); + + //Get existing labels + //this.initExistingLabels(config, vreq); + + //Add form specific data used to populate template + addFormSpecificData(config, vreq); + //This preprocessor handles getting the correct label language and putting the attribute on the label + config.addEditSubmissionPreprocessor( + new ManageLabelsForIndividualPreprocessor(config)); + //This will handle generating the label from the first name and last name and also make sure to associate + //a language with that label + config.addModelChangePreprocessor(new FoafNameToRdfsLabelPreprocessor()); + + prepare(vreq, config); + return config; + } + + private void setUrlToReturnTo(EditConfigurationVTwo editConfiguration, VitroRequest vreq) { + editConfiguration.setUrlPatternToReturnTo(EditConfigurationUtils.getFormUrlWithoutContext(vreq)); + } + + private void setVarNames(EditConfigurationVTwo editConfiguration) { + editConfiguration.setVarNameForSubject("subject"); + editConfiguration.setVarNameForPredicate("predicate"); + + } + + + private List generateN3Required(VitroRequest vreq) { + List n3Required = new ArrayList(); + return n3Required; + } + + private List generateN3Optional(VitroRequest vreq) { + List n3Optional = new ArrayList(); + String predicateUri = EditConfigurationUtils.getPredicateUri(vreq); + String n3 = "?subject <" + predicateUri + "> ?label "; + //n3 used if the subject is a person + String personN3 = this.N3_PREFIX + "?subject foaf:firstName ?firstName ; foaf:lastName ?lastName ."; + n3Optional.add(n3); + n3Optional.add(personN3); + return n3Optional; + } + + + + private void setFields(EditConfigurationVTwo editConfiguration, VitroRequest vreq, String predicateUri) { + Map fields = new HashMap(); + editConfiguration.setFields(fields); + editConfiguration.addField(new FieldVTwo(). + setName("label"). + setValidators(getLabelValidators(vreq, editConfiguration))); + editConfiguration.addField(new FieldVTwo( + ).setName("newLabelLanguage")); + //no validators since all of this is optional + //there should be error-checking client side though + editConfiguration.addField(new FieldVTwo(). + setName("firstName"). + setValidators(getFirstNameValidators(vreq, editConfiguration))); + + editConfiguration.addField(new FieldVTwo(). + setName("lastName"). + setValidators(getLastNameValidators(vreq, editConfiguration))); + } + + //first and last name have validators if is person is true + private List getFirstNameValidators(VitroRequest vreq, EditConfigurationVTwo config) { + List validators = new ArrayList(); + if(isPersonType(vreq, config)) { + validators.add("nonempty"); + } + return validators; + } + + private List getLastNameValidators(VitroRequest vreq, EditConfigurationVTwo config) { + List validators = new ArrayList(); + if(isPersonType(vreq, config)) { + validators.add("nonempty"); + } + return validators; + } + + //validate label if person is not true + private List getLabelValidators(VitroRequest vreq, EditConfigurationVTwo config) { + List validators = new ArrayList(); + if(!isPersonType(vreq, config)) { + validators.add("nonempty"); + } + return validators; + } + + + + private void setUrisAndLiteralsOnForm(EditConfigurationVTwo config, + VitroRequest vreq) { + List literalsOnForm = new ArrayList(); + literalsOnForm.add("label"); + literalsOnForm.add("newLabelLanguage"); + //optional for person + literalsOnForm.add("firstName"); + literalsOnForm.add("lastName"); + config.setLiteralsOnForm(literalsOnForm); + + } + + + private void setUrisAndLiteralsInScope(EditConfigurationVTwo editConfiguration) { + HashMap> urisInScope = new HashMap>(); + //note that at this point the subject, predicate, and object var parameters have already been processed + urisInScope.put(editConfiguration.getVarNameForSubject(), + Arrays.asList(new String[]{editConfiguration.getSubjectUri()})); + urisInScope.put(editConfiguration.getVarNameForPredicate(), + Arrays.asList(new String[]{editConfiguration.getPredicateUri()})); + editConfiguration.setUrisInScope(urisInScope); + //Uris in scope include subject, predicate, and object var + + editConfiguration.setLiteralsInScope(new HashMap>()); + } + + private void initExistingLabels(EditConfigurationVTwo config, + VitroRequest vreq) { + this.existingLabelLiterals = this.getExistingLabels(config.getSubjectUri(), vreq); + // this.labelsSortedByLanguage = this.getLabelsSortedByLanguage(config,vreq); + //language names sorted for the existing languages + // this.existingSortedLanguageNameList = getExistingSortedLanguageNamesList(); + + //Generate a label to language code hash map + //TODO: + + //HashMap labelToLanguageCode = new HashMap(); + + //this.labels = getExistingLabels(config.getSubjectUri(), vreq); + //this.labelsSortedByLanguage = getLabelsSortedByLanguage(config.getSubjectUri(), vreq); + + } + + + private List getExistingSortedLanguageNamesList() { + HashSet existingLanguages = new HashSet(); + for(Literal l: this.existingLabelLiterals) { + String language = l.getLanguage(); + if(!existingLanguages.contains(language)) { + existingLanguages.add(language); + } + } + List sortedNames = new ArrayList(existingLanguages); + //sort alphabetically + Collections.sort(sortedNames); + return sortedNames; + } + + + private void addFormSpecificData(EditConfigurationVTwo config, + VitroRequest vreq) { + //Get all language codes/labels in the system, and this list is sorted by language name + List> locales = this.getLocales(vreq); + //Get code to label hashmap - we use this to get the language name for the language code returned in the rdf literal + HashMap localeCodeToNameMap = this.getFullCodeToLanguageNameMap(locales); + //the labels already added by the user + ArrayList existingLabels = this.getExistingLabels(config.getSubjectUri(), vreq); + //existing labels keyed by language name and each of the list of labels is sorted by language name + HashMap> existingLabelsByLanguageName = this.getLabelsSortedByLanguageName(existingLabels, localeCodeToNameMap, config, vreq); + //Get available locales for the drop down for adding a new label, also sorted by language name + HashSet existingLanguageNames = new HashSet(existingLabelsByLanguageName.keySet()); + List> availableLocalesForAdd = getAvailableLocales(locales, existingLanguageNames); + + + //Save all locales + config.addFormSpecificData("selectLocaleFullList", locales); + //Save labels sorted by language name, untyped have "untyped" as the language name value + config.addFormSpecificData("labelsSortedByLanguageName", existingLabelsByLanguageName); + config.addFormSpecificData("selectLocale",availableLocalesForAdd); + + + //How do we edit? Will need to see + config.addFormSpecificData("deleteWebpageUrl", "/edit/primitiveDelete"); + + + Individual subject = vreq.getWebappDaoFactory().getIndividualDao().getIndividualByURI(config.getSubjectUri()); + if( subject != null && subject.getName() != null ){ + config.addFormSpecificData("subjectName", subject.getName()); + }else{ + config.addFormSpecificData("subjectName", null); + } + + //Put in whether or not person type + if(isPersonType(vreq, config)) { + //Doing this b/c unsure how freemarker will handle boolean value from JAVA + config.addFormSpecificData("isPersonType", "true"); + } else { + config.addFormSpecificData("isPersonType", "false"); + + } + + //Include whether or not editable to enable edit/remove links and add to show up + config.addFormSpecificData("editable", isEditable(vreq, config)); + } + + + + //Based on what locales have already been selected for labels, return a list of + //locales for which new labels can be added and have these sorted by the name of the language + private List> getAvailableLocales(List> allLocales, + HashSet existingLabelsLanguageNames) { + List> availableLocales = new ArrayList>(); + for(HashMap localeInfo: allLocales) { + String languageName = (String) localeInfo.get("label"); + //If this language label is NOT in the labels sorted by language, then available + //for selection when creating a new label + //The assumption here is we don't want to allow the user to add a new label when a label + //already exists in that language + if(languageName != "untyped" && !existingLabelsLanguageNames.contains(languageName)) { + availableLocales.add(localeInfo); + } + } + //Sort list by language label and return + Collections.sort(availableLocales, new Comparator>() { + public int compare(HashMap h1, HashMap h2) { + String languageName1 = (String) h1.get("label"); + String languageName2 = (String) h2.get("label"); + return languageName1.compareTo(languageName2); + } + }); + + return availableLocales; + } + + + private Object isEditable(VitroRequest vreq, EditConfigurationVTwo config) { + Individual individual = EditConfigurationUtils.getIndividual(vreq, config.getSubjectUri()); + AddDataPropertyStatement adps = new AddDataPropertyStatement( + vreq.getJenaOntModel(), individual.getURI(), + RequestActionConstants.SOME_URI); + AddObjectPropertyStatement aops = new AddObjectPropertyStatement( + vreq.getJenaOntModel(), individual.getURI(), + RequestActionConstants.SOME_URI, + RequestActionConstants.SOME_URI); + return PolicyHelper.isAuthorizedForActions(vreq, new Actions(adps).or(aops)); + } + + + //Copied from NewIndividualFormGenerator + //TODO: Refactor so common code can be used by both generators + public String getFOAFPersonClassURI() { + return "http://xmlns.com/foaf/0.1/Person"; + } + + public boolean isPersonType(VitroRequest vreq, EditConfigurationVTwo config) { + WebappDaoFactory wdf = vreq.getWebappDaoFactory(); + Boolean isPersonType = Boolean.FALSE; + String foafPersonType = getFOAFPersonClassURI(); + List vclasses = this.getVClasses(config, vreq); + if( vclasses != null ){ + for( VClass v: vclasses){ + String typeUri = v.getURI(); + if( foafPersonType.equals(typeUri)) { + isPersonType = Boolean.TRUE; + break; + } + } + } + return isPersonType; + } + + //how to get the type of the individual in question + public List getVClasses(EditConfigurationVTwo config, VitroRequest vreq) { + Individual subject = EditConfigurationUtils.getIndividual(vreq, config.getSubjectUri()); + //Get the vclasses appropriate for this subject + return subject.getVClasses(); + } + + //Languages sorted by language name + private HashMap> getLabelsSortedByLanguageName(List labels, Map localeCodeToNameMap, EditConfigurationVTwo config, + VitroRequest vreq) { + String subjectUri = config.getSubjectUri(); + String propertyUri = config.getPredicateUri(); + + + //Iterate through the labels and create a hashmap + HashMap> labelsHash= new HashMap>(); + + for(Literal l: labels) { + String languageTag = l.getLanguage(); + String languageName = ""; + if(languageTag == "") { + languageName = "untyped"; + } + else if(localeCodeToNameMap.containsKey(languageTag)) { + languageName = localeCodeToNameMap.get(languageTag); + } else { + log.warn("This language tag " + languageTag + " does not have corresponding name in the system and was not processed"); + } + + if(languageName != "") { + if(!labelsHash.containsKey(languageName)) { + labelsHash.put(languageName, new ArrayList()); + } + ArrayList labelsList = (ArrayList)labelsHash.get(languageName); + //This should put the label in the list + //Create label information instance with the required information + //To generate link + DataPropertyStatementTemplateModel dpstm = new DataPropertyStatementTemplateModel(subjectUri, propertyUri, l, + template, vreq); + labelsList.add(new LabelInformation( + l, dpstm.getEditUrl(), dpstm.getDeleteUrl(), languageTag, languageName)); + } + } + + //Sort each label list + LabelInformationComparator lic = new LabelInformationComparator(); + for(String languageName: labelsHash.keySet()) { + List labelInfo = labelsHash.get(languageName); + Collections.sort(labelInfo, lic); + } + return labelsHash; + + } + + + public static class LabelInformationComparator implements Comparator { + + public int compare(LabelInformation l1, LabelInformation l2) { + return l1.getLabelStringValue().compareTo(l2.getLabelStringValue()); + } + } + + + private static String LABEL_QUERY = "" + + "PREFIX rdfs: \n" + + "SELECT DISTINCT ?label WHERE { \n" + + " ?subject rdfs:label ?label \n" + + "} ORDER BY ?label"; + + + private ArrayList getExistingLabels(String subjectUri, VitroRequest vreq) { + String queryStr = QueryUtils.subUriForQueryVar(LABEL_QUERY, "subject", subjectUri); + log.debug("queryStr = " + queryStr); + + ArrayList labels = new ArrayList(); + try { + //We want to get the labels for all the languages, not just the display language + ResultSet results = QueryUtils.getLanguageNeutralQueryResults(queryStr, vreq); + while (results.hasNext()) { + QuerySolution soln = results.nextSolution(); + Literal nodeLiteral = soln.get("label").asLiteral(); + labels.add(nodeLiteral); + + + } + } catch (Exception e) { + log.error(e, e); + } + return labels; +} + + + + //Putting this into a method allows overriding it in subclasses + protected String getEditForm() { + return null; + //return AddEditWebpageFormGenerator.class.getName(); + } + + + protected String getTemplate() { + return template; + } + + + + //get locales + public List> getLocales(VitroRequest vreq) { + List selectables = SelectedLocale.getSelectableLocales(vreq); + if (selectables.isEmpty()) { + return Collections.emptyList(); + } + List> list = new ArrayList>(); + Locale currentLocale = SelectedLocale.getCurrentLocale(vreq); + for (Locale locale : selectables) { + try { + list.add(buildLocaleMap(locale, currentLocale)); + } catch (FileNotFoundException e) { + log.warn("Can't show the Locale selector for '" + locale + + "': " + e); + } + } + + return list; + } + + + + public HashMap getFullCodeToLanguageNameMap(List> localesList) { + HashMap codeToLanguageMap = new HashMap(); + for(Map locale: localesList) { + String code = (String) locale.get("code"); + String label = (String) locale.get("label"); + if(!codeToLanguageMap.containsKey(code)) { + codeToLanguageMap.put(code, label); + } + else { + log.warn("Language code " + code + " for " + label + " was not associated in map becayse label already exists"); + } + } + return codeToLanguageMap; + } + + public List getFullLanguagesNamesSortedList(List> localesList) { + HashSet languageNamesSet = new HashSet(); + for(Map locale: localesList) { + String label = (String) locale.get("label"); + if(!languageNamesSet.contains(label)) { + languageNamesSet.add(label); + } + + } + List languageNames = new ArrayList(languageNamesSet); + Collections.sort(languageNames); + return languageNames; + } + + //copied from locale selection data getter but don't need all this information + private HashMap buildLocaleMap(Locale locale, + Locale currentLocale) throws FileNotFoundException { + HashMap map = new HashMap(); + //Replacing the underscore with a hyphen because that is what is represented in the actual literals + map.put("code", locale.toString().replace("_", "-")); + map.put("label", locale.getDisplayName(currentLocale)); + return map; + } + + //Class used to store the information needed for the template, such as the labels, their languages, their edit links + public class LabelInformation { + private Literal labelLiteral = null; + private String editLinkURL; + private String deleteLinkURL; + private String languageCode; //languageCode + private String languageName; + public LabelInformation(Literal inputLiteral, String inputEditLinkURL, String inputDeleteLinkURL, String inputLanguageCode, String inputLanguageName) { + this.labelLiteral = inputLiteral; + this.editLinkURL = inputEditLinkURL; + this.deleteLinkURL = inputDeleteLinkURL; + this.languageCode = inputLanguageCode; + this.languageName = inputLanguageName; + } + + + public Literal getLabelLiteral() { + return this.labelLiteral; + } + + public String getLabelStringValue() { + return this.labelLiteral.getString(); + } + + public String getEditLinkURL() { + return this.editLinkURL; + } + + public String getDeleteLinkURL() { + return this.deleteLinkURL; + } + public String getLanguageCode() { + return this.languageCode; + } + + public String getLanguageName() { + return this.languageName; + } + } + + private String N3_PREFIX = "@prefix foaf: .\n"; + +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/preprocessors/ConceptSparqlUpdatePreprocessor.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/preprocessors/ConceptSparqlUpdatePreprocessor.java new file mode 100644 index 000000000..04b2d3cad --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/preprocessors/ConceptSparqlUpdatePreprocessor.java @@ -0,0 +1,129 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.preprocessors; + +import javax.servlet.http.HttpServletRequest; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import com.hp.hpl.jena.ontology.OntModel; +import com.hp.hpl.jena.query.Dataset; +import com.hp.hpl.jena.query.Query; +import com.hp.hpl.jena.query.QueryExecution; +import com.hp.hpl.jena.query.QueryExecutionFactory; +import com.hp.hpl.jena.query.QueryFactory; +import com.hp.hpl.jena.query.QuerySolutionMap; +import com.hp.hpl.jena.query.Syntax; +import com.hp.hpl.jena.rdf.model.Literal; +import com.hp.hpl.jena.rdf.model.Model; +import com.hp.hpl.jena.rdf.model.ModelFactory; +import com.hp.hpl.jena.rdf.model.Property; +import com.hp.hpl.jena.rdf.model.ResIterator; +import com.hp.hpl.jena.rdf.model.Resource; +import com.hp.hpl.jena.rdf.model.ResourceFactory; +import com.hp.hpl.jena.rdf.model.Statement; +import com.hp.hpl.jena.shared.Lock; +import com.hp.hpl.jena.vocabulary.RDF; +import com.hp.hpl.jena.vocabulary.RDFS; + +import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary; +import edu.cornell.mannlib.vitro.webapp.dao.jena.DatasetWrapper; +import edu.cornell.mannlib.vitro.webapp.dao.jena.DatasetWrapperFactory; + +//We are representing semantic types from the UMLS Semantic Network as OWL Classes +//and this preprocessor will add the appropriate class information to the TBox + +public class ConceptSparqlUpdatePreprocessor implements ModelChangePreprocessor { + + private static String VIVOCore = "http://vivoweb.org/ontology/core#"; + private static String SKOSConceptType = "http://www.w3.org/2004/02/skos/core#Concept"; + private Log log = LogFactory.getLog(ConceptSparqlUpdatePreprocessor.class); + + private OntModel toUpdateModel = null; + private DatasetWrapperFactory dwf = null; + + //Custom constructor + public ConceptSparqlUpdatePreprocessor(OntModel updateModel, DatasetWrapperFactory inputDwf) { + this.toUpdateModel = updateModel; + this.dwf = inputDwf; + } + + @Override + public void preprocess(Model retractionsModel, Model additionsModel, + HttpServletRequest request) { + //Run a construct query against the additions model + String prefixes = "PREFIX RDFS:<" + RDFS.getURI() + "> " + + "PREFIX OWL: " + + "PREFIX RDF:<" + RDF.getURI() + ">"; + String constructQuery = prefixes + " CONSTRUCT { " + + "?semanticType rdf:type OWL:Class. { " + + "?semanticType rdfs:subClassOf SKOS:Concept . { " + + "?semanticType rdfs:label ?label. { " + + "} WHERE { " + + "?concept rdf:type ?semanticType. { " + + "?semanticType rdfs:label ?label .{ " + + "?semanticType rdfs:subClassOf SKOS:Concept .{ " + + "}"; + + //Execute construct query + Model constructedModel = ModelFactory.createDefaultModel(); + + + log.debug("CONSTRUCT query string " + constructQuery); + + Query query = null; + try { + query = QueryFactory.create(constructQuery, Syntax.syntaxARQ); + } catch(Throwable th){ + log.error("Could not create CONSTRUCT SPARQL query for query " + + "string. " + th.getMessage()); + log.error(constructQuery); + return; + } + + + + DatasetWrapper w = dwf.getDatasetWrapper(); + Dataset dataset = w.getDataset(); + dataset.getLock().enterCriticalSection(Lock.READ); + QueryExecution qe = null; + try { + qe = QueryExecutionFactory.create( + query, dataset); + qe.execConstruct(constructedModel); + } catch (Exception e) { + log.error("Error getting constructed model for query string " + constructQuery); + } finally { + if (qe != null) { + qe.close(); + } + dataset.getLock().leaveCriticalSection(); + w.close(); + } + + //Add constructed model to the designated update model + toUpdateModel.enterCriticalSection(Lock.WRITE); + try { + toUpdateModel.add(constructedModel); + } catch (Exception e) { + log.error("Error adding statements to update model for " + constructQuery); + } finally { + toUpdateModel.leaveCriticalSection(); + } + + //Take this constructed model and remove from the additions model + additionsModel.enterCriticalSection(Lock.WRITE); + try { + additionsModel.remove(constructedModel.listStatements().toList()); + } catch (Exception e) { + log.error("Error removing statements from additions model for " + constructQuery); + } finally { + additionsModel.leaveCriticalSection(); + } + + } + + + +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/preprocessors/FoafNameToRdfsLabelPreprocessor.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/preprocessors/FoafNameToRdfsLabelPreprocessor.java index 49e979740..bbb280f2a 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/preprocessors/FoafNameToRdfsLabelPreprocessor.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/preprocessors/FoafNameToRdfsLabelPreprocessor.java @@ -4,6 +4,7 @@ package edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.preprocess import javax.servlet.http.HttpServletRequest; +import com.hp.hpl.jena.rdf.model.Literal; import com.hp.hpl.jena.rdf.model.Model; import com.hp.hpl.jena.rdf.model.Property; import com.hp.hpl.jena.rdf.model.ResIterator; @@ -30,7 +31,21 @@ public class FoafNameToRdfsLabelPreprocessor implements ModelChangePreprocessor Statement fname = sub.getProperty( firstNameP ); Statement lname = sub.getProperty( lastNameP ); if( fname != null && lname != null && fname.getString() != null && lname.getString() != null ){ - additionsModel.add(sub, rdfsLabelP, lname.getString() + ", " + fname.getString() ); + //Check if there are languages associated with first name and last name and add the language + //attribute to the label + //This preprocessor is used in multiple places, including for managing labels + Literal firstNameLiteral = fname.getLiteral(); + Literal lastNameLiteral = lname.getLiteral(); + String firstNameLanguage = firstNameLiteral.getLanguage(); + String lastNameLanguage = lastNameLiteral.getLanguage(); + String newLabel = lname.getString() + ", " + fname.getString(); + if(firstNameLanguage != null && lastNameLanguage != null && firstNameLanguage.equals(lastNameLanguage)) { + //create a literal with the appropriate value and the language + Literal labelWithLanguage = additionsModel.createLiteral(newLabel, firstNameLanguage); + additionsModel.add(sub, rdfsLabelP, labelWithLanguage); + } else { + additionsModel.add(sub, rdfsLabelP, newLabel ); + } } } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/preprocessors/ManageLabelsForIndividualPreprocessor.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/preprocessors/ManageLabelsForIndividualPreprocessor.java new file mode 100644 index 000000000..bb7967d64 --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/preprocessors/ManageLabelsForIndividualPreprocessor.java @@ -0,0 +1,111 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.preprocessors; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.servlet.http.HttpServletRequest; + +import com.hp.hpl.jena.ontology.OntModel; +import com.hp.hpl.jena.rdf.model.Literal; +import com.hp.hpl.jena.rdf.model.Model; +import com.hp.hpl.jena.rdf.model.Property; +import com.hp.hpl.jena.rdf.model.ResIterator; +import com.hp.hpl.jena.rdf.model.Resource; +import com.hp.hpl.jena.rdf.model.Statement; + +import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary; +/* + * This preprocessor is used to set the language attribute on the label based on the user selection + * on the manage labels page when adding a new label. + */ +import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.BaseEditSubmissionPreprocessorVTwo; +import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.EditConfigurationVTwo; +import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.MultiValueEditSubmission; + +public class ManageLabelsForIndividualPreprocessor extends BaseEditSubmissionPreprocessorVTwo { + + + + + public ManageLabelsForIndividualPreprocessor(EditConfigurationVTwo editConfig) { + super(editConfig); + + } + + @Override + public void preprocess(MultiValueEditSubmission inputSubmission) { + //Check and see if a language was selected by the user, and this is the regular label submission + //TODO: Check if firstname and lastname should be changed here or elsewhere + if(inputSubmission.hasLiteralValue("label") && inputSubmission.hasLiteralValue("newLabelLanguage")) { + Map> literalsFromForm = inputSubmission.getLiteralsFromForm(); + List newLabelLanguages = literalsFromForm.get("newLabelLanguage"); + List labels = literalsFromForm.get("label"); + + //Expecting only one language + if(labels.size() > 0 && newLabelLanguages.size() > 0) { + Literal newLabelLanguage = newLabelLanguages.get(0); + Literal labelLiteral = labels.get(0); + //Get the string + String lang = this.getLanguage(newLabelLanguage.getString()); + String label = labelLiteral.getString(); + //Now add the language category to the literal + Literal labelWithLanguage = inputSubmission.createLiteral(label, + newLabelLanguage.getDatatypeURI(), + lang); + labels = new ArrayList(); + labels.add(labelWithLanguage); + //replace the label with one with language, again assuming only one label being returned + literalsFromForm.put("label", labels); + inputSubmission.setLiteralsFromForm(literalsFromForm); + } + } + //First name and last name would also have a language selected so make sure those literals are also + //correctly typed + if(inputSubmission.hasLiteralValue("firstName") && inputSubmission.hasLiteralValue("lastName") && inputSubmission.hasLiteralValue("newLabelLanguage")) { + Map> literalsFromForm = inputSubmission.getLiteralsFromForm(); + List newLabelLanguages = literalsFromForm.get("newLabelLanguage"); + List firstNames = literalsFromForm.get("firstName"); + List lastNames = literalsFromForm.get("lastName"); + + //Expecting only one language + if(firstNames.size() > 0 && lastNames.size() > 0 && newLabelLanguages.size() > 0) { + Literal newLabelLanguage = newLabelLanguages.get(0); + Literal firstNameLiteral = firstNames.get(0); + Literal lastNameLiteral = lastNames.get(0); + //Get the string + String lang = this.getLanguage(newLabelLanguage.getString()); + String firstNameValue = firstNameLiteral.getString(); + String lastNameValue = lastNameLiteral.getString(); + //Now add the language category to the literal + Literal firstNameWithLanguage = inputSubmission.createLiteral(firstNameValue, + null, + lang); + Literal lastNameWithLanguage = inputSubmission.createLiteral(lastNameValue, + null, + lang); + firstNames = new ArrayList(); + lastNames = new ArrayList(); + firstNames.add(firstNameWithLanguage); + lastNames.add(lastNameWithLanguage); + //replace the label with one with language, again assuming only one label being returned + literalsFromForm.put("firstName", firstNames); + literalsFromForm.put("lastName", lastNames); + inputSubmission.setLiteralsFromForm(literalsFromForm); + } + } + + } + + //The language code returned from JAVA locales has an underscore whereas we need a hyphen + private String getLanguage(String inputLanguageCode) { + if(inputLanguageCode.contains("_")) { + return inputLanguageCode.replace("_", "-"); + } + return inputLanguageCode; + } + +} diff --git a/webapp/web/i18n/all.properties b/webapp/web/i18n/all.properties index 6fb58986b..7980d00a9 100644 --- a/webapp/web/i18n/all.properties +++ b/webapp/web/i18n/all.properties @@ -675,7 +675,8 @@ photo = Photo no_image = no image placeholder_image = placeholder image manage_labels = manage labels - +add_label = Add Label +add_label_for_language = Language unsupported_ie_version = This form is not supported in versions of Internet Explorer below version 8. Please upgrade your browser, or switch to another browser, such as FireFox. # diff --git a/webapp/web/js/individual/manageLabelsForIndividual.js b/webapp/web/js/individual/manageLabelsForIndividual.js index cd91e9033..7eb54c92e 100644 --- a/webapp/web/js/individual/manageLabelsForIndividual.js +++ b/webapp/web/js/individual/manageLabelsForIndividual.js @@ -6,9 +6,10 @@ var manageLabels = { onLoad: function() { - this.mixIn(); + this.mixIn(); + this.initObjects(); this.initPage(); - + var selectedRadio; }, @@ -18,24 +19,86 @@ var manageLabels = { $.extend(this, customFormData); $.extend(this, i18nStrings); }, + + initObjects:function() { + this.addLabelForm = $('#addLabelForm'); + this.showFormButtonWrapper = $('#showAddForm'); + this.showFormButton = $("#showAddFormButton"); + this.addLabelCancel = this.addLabelForm.find(".cancel"); + this.submit = this.addLabelForm.find('input#submit'); + this.labelLanguage = this.addLabelForm.find("#newLabelLanguage"); + this.existingLabelsList = $("#existingLabelsList"); + }, // Initial page setup. Called only at page load. initPage: function() { + //disable submit until user selects a language + this.submit.attr('disabled', 'disabled'); + this.submit.addClass('disabledSubmit'); + if(this.submissionErrorsExist == "false") { + //hide the form to add label + this.addLabelForm.hide(); + //the cancel in add label can be unbound until the form is visible + //this.addLabelCancel.unbind("click"); + } else { + //Display the form + this.onShowAddForm(); - $('input#submit').attr('disabled', 'disabled'); - $('input#submit').addClass('disabledSubmit'); + } + + this.bindEventListeners(); }, bindEventListeners: function() { - $('input:radio').click( function() { - manageLabels.selectedRadio = $(this); - $('input#submit').attr('disabled', ''); - $('input#submit').removeClass('disabledSubmit'); + this.labelLanguage.change( function() { + //if language selected, allow submission, otherwise disallow + var selectedLanguage = manageLabels.labelLanguage.val(); + if(selectedLanguage != "") { + manageLabels.submit.attr('disabled', ''); + manageLabels.submit.removeClass('disabledSubmit'); + } else { + manageLabels.submit.attr('disabled', 'disabled'); + manageLabels.submit.addClass('disabledSubmit'); + } + }); + + //enable form to add label to be displayed or hidden + this.showFormButton.click(function() { + //clear the inputs for the label if the button is being clicked + manageLabels.clearAddForm(); + manageLabels.onShowAddForm(); + }); + + //Check for clicking on existing labels list remove links + //Note addition will refresh the page and removing will remove the item so adding event listeners + //to remove links should keep remove link events in synch with page + + this.existingLabelsList.find("a.remove").click(function(event) { + var message = "Are you sure you wish to delete this label?" + if (!confirm(message)) { + return false; + } + + //First check with confirmation whether or not they want to delete + manageLabels.processLabelDeletion(this); + return false; + }); + + + this.addLabelForm.find("a.cancel").click(function(){ + //clear the add form + manageLabels.clearAddForm(); + //hide the add form + manageLabels.onHideAddForm(); + }); + //TODO: Add method to check that language is selected on submission + + /* $('input#submit').click( function() { manageLabels.processLabel(manageLabels.selectedRadio); $('span.or').hide(); @@ -43,24 +106,47 @@ var manageLabels = { $('span#indicator').removeClass('hidden'); $('input.submit').addClass('disabledSubmit'); $('input.submit').attr('disabled', 'disabled'); - }); + });*/ }, - - processLabel: function(selectedRadio) { - + clearAddForm:function() { + //clear inputs and select + manageLabels.addLabelForm.find("input[type='text'],select").val(""); + //set the button for save to be disabled again + manageLabels.submit.attr('disabled', 'disabled'); + manageLabels.submit.addClass('disabledSubmit'); + }, + onShowAddForm:function() { + manageLabels.addLabelForm.show(); + manageLabels.showFormButtonWrapper.hide(); + manageLabels.addLabelCancel.click(function(){ + //Canceling the add label form will hide the form + manageLabels.addLabelForm.hide(); + manageLabels.showFormButtonWrapper.show(); + }); + }, + + onHideAddForm:function() { + manageLabels.addLabelForm.hide(); + manageLabels.showFormButtonWrapper.show(); + //manageLabels.addLabelCancel.unbind("click"); + }, + //Remove label + processLabelDeletion: function(selectedLink) { + // PrimitiveDelete only handles one statement, so we have to use PrimitiveRdfEdit to handle multiple // retractions if they exist. But PrimitiveRdfEdit also handles assertions, so pass an empty string // for "additions" var add = ""; - var retract = ""; - - $('input:radio').each( function() { - if ( !$(this).is(':checked') ) { - retract += " <" + manageLabels.individualUri + "> " - + "\"" + $(this).attr('id') + "\"" + $(this).attr('tagOrType') + " ." ; - } - }); + var labelValue = $(selectedLink).attr('labelValue'); + var tagOrTypeValue = $(selectedLink).attr('tagOrType'); + if(tagOrTypeValue == "untyped") { + tagOrTypeValue = ""; + } + var retract = "<" + manageLabels.individualUri + "> " + + "\"" + $(selectedLink).attr('labelValue') + "\"" + $(selectedLink).attr('tagOrType') + " ." ; + + retract = retract.substring(0,retract.length -1); @@ -72,28 +158,103 @@ var manageLabels = { retractions: retract }, dataType: 'json', - context: selectedRadio, // context for callback + context: selectedLink, // context for callback complete: function(request, status) { if (status == 'success') { - $('span.or').show(); - $('a.cancel').show(); - $('span#indicator').addClass('hidden'); - window.location = $('a.cancel').attr('href'); + //Remove the label from the list + manageLabels.removeLabelFromList(selectedLink); + manageLabels.updateLocaleSelection(); } else { + //Instead of alert, write error to template alert(manageLabels.errorProcessingLabels); - selectedRadio.removeAttr('checked'); - $('span.or').show(); - $('a.cancel').show(); - $('span#indicator').addClass('hidden'); - $('input.submit').removeClass('disabledSubmit'); - $('input.submit').attr('disabled', ''); + } } }); }, + removeLabelFromList:function(selectedLink) { + var languageName = $(selectedLink).attr("languageName"); + $(selectedLink).parent().remove(); + //See if there are any other remove link + if(languageCode != "untyped") { + //find if there are any other remove links for the same language + var removeLinks = manageLabels.existingLabelsList.find("a.remove[languageName='" + languageName + "']"); + if(removeLinks.length == 0) { + //if there aren't any other labels for this language, also remove the heading + manageLabels.existingLabelsList.find("h3[languageName='" + langaugeName + "']").remove(); + + } + } + + }, + //Determine if there are new locales that can be added to the options once a delete has occurred + updateLocaleSelection:function() { + //Check what languages remain + var existingLanguages = {}; + //Look at which languages are currently represented + manageLabels.existingLabelsList.find("a.remove").each(function(){ + var languageCode = $(this).attr("languageCode"); + if(!(languageCode in existingLanguages)) { + existingLanguages[languageCode] = true; + } + }); + + //Now check against full list, if any in full list not represented, will need to include in dropdown + //This is a list of + var availableLocalesList = []; + var listLen = selectLocalesFullList.length; + var i; + for(i = 0; i < listLen; i++) { + var possibleLanguageInfo = selectLocalesFullList[i]; + var possibleLanguageCode = possibleLanguageInfo["code"]; + var possibleLangaugeLabel = possibleLanguageInfo["label"]; + if(!(possibleLanguageCode in existingLanguages)) { + //manageLabels.addLanguageCode(possibleLanguageCode, possibleLanguageLabel); + availableLocalesList.push(possibleLanguageInfo); + } + } + + //Now sort this list by the label property on the object + availableLocalesList.sort(function(a, b) { + var compA = a["label"]; + var compB = b["label"]; + return compA < compB ? -1 : 1; + }); + //Now replace dropdown with this new list + manageLabels.generateLocalesDropdown(availableLocalesList); + + }, + generateLocalesDropdown:function(availableLocalesList) { + //First check if there are any available locales left, if not then hide the entire add form + //technically, this first part should never be invoked client side because + //this can only happen on ADD not remove, and add will refresh the page + //On the other hand the show add button etc. can be displayed + if(availableLocalesList.length == 0) { + //Hide the add form if there are no locales left that can be added + manageLabels.addLabelForm.hide(); + manageLabels.showFormButtonWrapper.hide(); + } else { + //There are some locales so generate the dropdown accordingly, removing all elements but the first + $("#newLabelLanguage option:gt(0)").remove(); + var i; + var len = availableLocalesList.length; + for(i = 0; i < len; i++) { + var localeInfo = availableLocalesList[i]; + manageLabels.addLocaleInfo(localeInfo); + } + //Put some value in that shows whether neither add button nor add form were shown + //because the form thought there were no available locales + } + }, + + addLocaleInfo:function(localeInfo) { + //Add code to dropdown + //Would we need to regenerate alphabetically? Argh. + manageLabels.labelLanguage.append(""); + } }; diff --git a/webapp/web/templates/freemarker/body/individual/manageLabelsForIndividual.ftl b/webapp/web/templates/freemarker/body/individual/manageLabelsForIndividual.ftl index bf5d84337..6c5492faa 100644 --- a/webapp/web/templates/freemarker/body/individual/manageLabelsForIndividual.ftl +++ b/webapp/web/templates/freemarker/body/individual/manageLabelsForIndividual.ftl @@ -1,62 +1,93 @@ <#-- $This file is distributed under the terms of the license in /doc/license.txt$ --> <#-- Custom form for managing labels for individuals --> +<#import "manageLabelsForIndividualMacros.ftl" as m > +<#assign requiredHint = " *" /> +<#assign subjectUri = editConfiguration.subjectUri/> <#assign labelStr = "" > <#assign languageTag = "" > <#assign labelSeq = [] > -<#if subjectName?? > -

${i18n().manage_labels_for} ${subjectName}

+<#assign submissionErrorsExist = "false"/> +<#assign selectLocalesFullList = {} /> +<#assign editable = false/> +<#if editConfiguration.pageData.editable?has_content> + <#assign editable = editConfiguration.pageData.editable /> + +<#if editSubmission?has_content && editSubmission.submissionExists = true && editSubmission.validationErrors?has_content> + <#assign submissionErrors = editSubmission.validationErrors/> + <#assign submissionErrorsExist = "true" /> + + +<#if editConfiguration.pageData.subjectName?? > +

${i18n().manage_labels_for} ${editConfiguration.pageData.subjectName}

<#else>

${i18n().manage_labels_capitalized}

+ + +

${i18n().manage_labels_intro}

+
-
    - <#list labels as label> - <#-- the query will return labels with their language tag or datatype, if any. So strip those out --> - <#if label?? && ( label?index_of("@") > -1 ) > - <#assign labelStr = label?substring(0, label?index_of("@")) > - <#assign tagOrTypeStr = label?substring(label?index_of("@")) > - <#elseif label?? && ( label?index_of("^^") > -1 ) > - <#assign labelStr = label?substring(0, label?index_of("^^")) > - <#assign tagOrTypeStr = label?substring(label?index_of("^^")) > - <#assign tagOrTypeStr = tagOrTypeStr?replace("^^http","^^ - <#assign tagOrTypeStr = tagOrTypeStr?replace("#string","#string>") > - <#else> - <#assign labelStr = label > - <#assign tagOrTypeStr = "" > - -
  • - - -
  • - <#assign labelSeq = labelSeq + [labelStr]> - + + + +
      + <#if editConfiguration.pageData.labelsSortedByLanguageName?has_content> + <#--List of labelInformation objects as value where key = language name --> + <#assign labelsSorted = editConfiguration.pageData.labelsSortedByLanguageName /> + <#--Keys would be the actual names of languages--> + <#assign labelLanguages = labelsSorted?keys?sort /> + <#assign editGenerator = "editForm=edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.generators.RDFSLabelGenerator" /> + + <#--What we need here is printing out the labels by the language Name and not language code, starting with untyped first--> + <@m.displayExistingLabelsForLanguage "untyped" labelsSorted editable editGenerator/> + <@m.displayExistingTypedLabels labelLanguages labelsSorted editable editGenerator/> + +

    -

    - - or - ${i18n().cancel_link} - -

    -
+

+ + <#if editable> + <#include "manageLabelsForIndividualSubmissionErrors.ftl"> +

+ ${i18n().or} + ${i18n().return_to_profile} +
+ + <#include "manageLabelsForIndividualAddForm.ftl" > + + +

+ + diff --git a/webapp/web/templates/freemarker/body/individual/manageLabelsForIndividualAddForm.ftl b/webapp/web/templates/freemarker/body/individual/manageLabelsForIndividualAddForm.ftl new file mode 100644 index 000000000..e6d6714c3 --- /dev/null +++ b/webapp/web/templates/freemarker/body/individual/manageLabelsForIndividualAddForm.ftl @@ -0,0 +1,29 @@ +<#-- $This file is distributed under the terms of the license in /doc/license.txt$ --> +<#--The form for adding a new label--> +
+

${i18n().add_label}

+

+ + +

+ + + + + + +${i18n().or} +${i18n().cancel_link} + +
\ No newline at end of file diff --git a/webapp/web/templates/freemarker/body/individual/manageLabelsForIndividualMacros.ftl b/webapp/web/templates/freemarker/body/individual/manageLabelsForIndividualMacros.ftl new file mode 100644 index 000000000..35839dada --- /dev/null +++ b/webapp/web/templates/freemarker/body/individual/manageLabelsForIndividualMacros.ftl @@ -0,0 +1,79 @@ +<#-- $This file is distributed under the terms of the license in /doc/license.txt$ --> +<#--LabelsSorted is a hash keyed by language name where the value is a list of LabelInformation class objects--> +<#macro displayExistingLabelsForLanguage lang labelsSorted editable editGenerator> + <#--get label information for this language--> + <#assign labelList = labelsSorted[lang] /> + <#--Reset for every language--> + <#assign labelSeq = []/> + <#list labelList as labelObject> + <#assign labelLiteral = labelObject.labelLiteral /> + <#assign labelStringValue = labelObject.labelStringValue /> + <#--Try label as label literal--> + <#assign label = labelLiteral /> + <#assign labelLang = labelObject.languageName /> + <#assign languageCode = labelObject.languageCode /> + <#assign labelEditLink = labelObject.editLinkURL /> + <#if label?? && ( label?index_of("@") > -1 ) > + <#assign labelStr = label?substring(0, label?index_of("@")) > + <#assign tagOrTypeStr = label?substring(label?index_of("@")) > + <#elseif label?? && ( label?index_of("^^") > -1 ) > + <#assign labelStr = label?substring(0, label?index_of("^^")) > + <#assign tagOrTypeStr = label?substring(label?index_of("^^")) > + <#assign tagOrTypeStr = tagOrTypeStr?replace("^^http","^^ + <#assign tagOrTypeStr = tagOrTypeStr?replace("#string","#string>") > + <#else> + <#assign labelStr = label > + <#assign tagOrTypeStr = "" > + +
  • ${labelStr} <#if labelSeq?seq_contains(labelStr)> (duplicate value) + <#if editable && labelEditLink?has_content> Edit + ${i18n().remove_capitalized} + + +
  • + <#assign labelSeq = labelSeq + [labelStr]> + + + +<#--ignore 'untyped' and display everything--> +<#macro displayExistingTypedLabels langList labelsSorted editable editGenerator> + <#list langList as lang> + <#if lang != "untyped"> +

    ${lang}

    + <#--get label information for this language--> + <#assign labelList = labelsSorted[lang] /> + <#--Reset for every language--> + <#assign labelSeq = []/> + <#list labelList as labelObject> + <#assign labelLiteral = labelObject.labelLiteral /> + <#assign labelStringValue = labelObject.labelStringValue /> + <#--Try label as label literal--> + <#assign label = labelLiteral /> + <#assign labelLang = labelObject.languageName /> + <#assign languageCode = labelObject.languageCode /> + <#assign labelEditLink = labelObject.editLinkURL /> + <#if label?? && ( label?index_of("@") > -1 ) > + <#assign labelStr = label?substring(0, label?index_of("@")) > + <#assign tagOrTypeStr = label?substring(label?index_of("@")) > + <#elseif label?? && ( label?index_of("^^") > -1 ) > + <#assign labelStr = label?substring(0, label?index_of("^^")) > + <#assign tagOrTypeStr = label?substring(label?index_of("^^")) > + <#assign tagOrTypeStr = tagOrTypeStr?replace("^^http","^^ + <#assign tagOrTypeStr = tagOrTypeStr?replace("#string","#string>") > + <#else> + <#assign labelStr = label > + <#assign tagOrTypeStr = "" > + +
  • ${labelStr} <#if labelSeq?seq_contains(labelStr)> (duplicate value) + <#if editable && labelEditLink?has_content> Edit + ${i18n().remove_capitalized} + + +
  • + <#assign labelSeq = labelSeq + [labelStr]> + + + + \ No newline at end of file diff --git a/webapp/web/templates/freemarker/body/individual/manageLabelsForIndividualSubmissionErrors.ftl b/webapp/web/templates/freemarker/body/individual/manageLabelsForIndividualSubmissionErrors.ftl new file mode 100644 index 000000000..ef4f8fe95 --- /dev/null +++ b/webapp/web/templates/freemarker/body/individual/manageLabelsForIndividualSubmissionErrors.ftl @@ -0,0 +1,14 @@ +<#-- $This file is distributed under the terms of the license in /doc/license.txt$ --> +<#if submissionErrors?has_content > + + \ No newline at end of file diff --git a/webapp/web/templates/freemarker/lib/lib-properties.ftl b/webapp/web/templates/freemarker/lib/lib-properties.ftl index 7d360496a..f48adc194 100644 --- a/webapp/web/templates/freemarker/lib/lib-properties.ftl +++ b/webapp/web/templates/freemarker/lib/lib-properties.ftl @@ -209,13 +209,18 @@ name will be used as the label. --> <#-- Label --> <#macro label individual editable labelCount> + <#assign labelPropertyUri = ("http://www.w3.org/2000/01/rdf-schema#label"?url) /> + <#-- Will need to deal with multiple languages as well--> <#local label = individual.nameStatement> ${label.value} <#if (labelCount > 1) && editable > + <#-- Changing this so that manage labels now goes to generator --> - - ${i18n().manage_labels} - + <#--Previous link which went to manage labels controller--> + <#--a id="manageLabels" href="${urls.base}/manageLabels?subjectUri=${individual.uri!}"--> + + ${i18n().manage} <#else> <@editingLinks "label" label editable /> From 9ec7d11cab04b67035986516134c612f2cb879a7 Mon Sep 17 00:00:00 2001 From: hudajkhan Date: Wed, 4 Sep 2013 12:22:46 -0400 Subject: [PATCH 2/4] label management and concept semantic type --- ... => ConceptSemanticTypesPreprocessor.java} | 36 +++++++-------- webapp/web/i18n/all.properties | 3 +- .../individual/manageLabelsForIndividual.js | 46 +++++++++++-------- .../individual/manageLabelsForIndividual.ftl | 10 ++-- .../freemarker/lib/lib-properties.ftl | 6 +-- 5 files changed, 53 insertions(+), 48 deletions(-) rename webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/preprocessors/{ConceptSparqlUpdatePreprocessor.java => ConceptSemanticTypesPreprocessor.java} (78%) diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/preprocessors/ConceptSparqlUpdatePreprocessor.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/preprocessors/ConceptSemanticTypesPreprocessor.java similarity index 78% rename from webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/preprocessors/ConceptSparqlUpdatePreprocessor.java rename to webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/preprocessors/ConceptSemanticTypesPreprocessor.java index 04b2d3cad..b95733b4f 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/preprocessors/ConceptSparqlUpdatePreprocessor.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/preprocessors/ConceptSemanticTypesPreprocessor.java @@ -34,36 +34,35 @@ import edu.cornell.mannlib.vitro.webapp.dao.jena.DatasetWrapperFactory; //We are representing semantic types from the UMLS Semantic Network as OWL Classes //and this preprocessor will add the appropriate class information to the TBox -public class ConceptSparqlUpdatePreprocessor implements ModelChangePreprocessor { +public class ConceptSemanticTypesPreprocessor implements ModelChangePreprocessor { private static String VIVOCore = "http://vivoweb.org/ontology/core#"; private static String SKOSConceptType = "http://www.w3.org/2004/02/skos/core#Concept"; - private Log log = LogFactory.getLog(ConceptSparqlUpdatePreprocessor.class); + private Log log = LogFactory.getLog(ConceptSemanticTypesPreprocessor.class); private OntModel toUpdateModel = null; - private DatasetWrapperFactory dwf = null; //Custom constructor - public ConceptSparqlUpdatePreprocessor(OntModel updateModel, DatasetWrapperFactory inputDwf) { + public ConceptSemanticTypesPreprocessor(OntModel updateModel) { this.toUpdateModel = updateModel; - this.dwf = inputDwf; } @Override public void preprocess(Model retractionsModel, Model additionsModel, HttpServletRequest request) { //Run a construct query against the additions model - String prefixes = "PREFIX RDFS:<" + RDFS.getURI() + "> " + - "PREFIX OWL: " + - "PREFIX RDF:<" + RDF.getURI() + ">"; + String prefixes = "PREFIX rdfs:<" + RDFS.getURI() + "> " + + "PREFIX owl: " + + "PREFIX rdf:<" + RDF.getURI() + ">" + + "PREFIX skos:"; String constructQuery = prefixes + " CONSTRUCT { " + - "?semanticType rdf:type OWL:Class. { " + - "?semanticType rdfs:subClassOf SKOS:Concept . { " + - "?semanticType rdfs:label ?label. { " + + "?semanticType rdf:type owl:Class. " + + "?semanticType rdfs:subClassOf skos:Concept . " + + "?semanticType rdfs:label ?label. " + "} WHERE { " + - "?concept rdf:type ?semanticType. { " + - "?semanticType rdfs:label ?label .{ " + - "?semanticType rdfs:subClassOf SKOS:Concept .{ " + + "?concept rdf:type ?semanticType. " + + "?semanticType rdfs:label ?label . " + + "?semanticType rdfs:subClassOf skos:Concept . " + "}"; //Execute construct query @@ -84,13 +83,11 @@ public class ConceptSparqlUpdatePreprocessor implements ModelChangePreprocessor - DatasetWrapper w = dwf.getDatasetWrapper(); - Dataset dataset = w.getDataset(); - dataset.getLock().enterCriticalSection(Lock.READ); + additionsModel.getLock().enterCriticalSection(Lock.READ); QueryExecution qe = null; try { qe = QueryExecutionFactory.create( - query, dataset); + query, additionsModel); qe.execConstruct(constructedModel); } catch (Exception e) { log.error("Error getting constructed model for query string " + constructQuery); @@ -98,8 +95,7 @@ public class ConceptSparqlUpdatePreprocessor implements ModelChangePreprocessor if (qe != null) { qe.close(); } - dataset.getLock().leaveCriticalSection(); - w.close(); + additionsModel.getLock().leaveCriticalSection(); } //Add constructed model to the designated update model diff --git a/webapp/web/i18n/all.properties b/webapp/web/i18n/all.properties index 7980d00a9..b235c903c 100644 --- a/webapp/web/i18n/all.properties +++ b/webapp/web/i18n/all.properties @@ -675,6 +675,7 @@ photo = Photo no_image = no image placeholder_image = placeholder image manage_labels = manage labels +manage_list_of_labels = manage list of labels add_label = Add Label add_label_for_language = Language unsupported_ie_version = This form is not supported in versions of Internet Explorer below version 8. Please upgrade your browser, or switch to another browser, such as FireFox. @@ -858,6 +859,6 @@ subproperty = subproperty manage_labels_for = Manage Labels for manage_labels_capitalized = Manage Labels -manage_labels_intro = Multiple labels exist for this profile but there should only be one. Select the label you want displayed on the profile page, and the others will be deleted. +manage_labels_intro = In the case where multiple labels exist in the same language, please use the remove link to delete the labels you do not want displayed on the profile page for a given language. processing_icon = processing selection_in_process = Your selection is being processed. diff --git a/webapp/web/js/individual/manageLabelsForIndividual.js b/webapp/web/js/individual/manageLabelsForIndividual.js index 7eb54c92e..7e1c8128c 100644 --- a/webapp/web/js/individual/manageLabelsForIndividual.js +++ b/webapp/web/js/individual/manageLabelsForIndividual.js @@ -32,20 +32,31 @@ var manageLabels = { // Initial page setup. Called only at page load. initPage: function() { - //disable submit until user selects a language - this.submit.attr('disabled', 'disabled'); - this.submit.addClass('disabledSubmit'); + + var disableSubmit = true; if(this.submissionErrorsExist == "false") { //hide the form to add label this.addLabelForm.hide(); - //the cancel in add label can be unbound until the form is visible - //this.addLabelCancel.unbind("click"); + //If the number of available locales is zero, then hide the ability to show the form as well + if(this.numberAvailableLocales == 0) { + manageLabels.showFormButtonWrapper.hide(); + } + } else { //Display the form this.onShowAddForm(); + //Also make sure the save button is enabled in case there is a value selected for the drop down + if(this.labelLanguage.val() != "") { + disableSubmit = false; + } } + if(disableSubmit) { + //disable submit until user selects a language + this.submit.attr('disabled', 'disabled'); + this.submit.addClass('disabledSubmit'); + } this.bindEventListeners(); @@ -88,25 +99,15 @@ var manageLabels = { }); - this.addLabelForm.find("a.cancel").click(function(){ + this.addLabelForm.find("a.cancel").click(function(event){ + event.preventDefault(); //clear the add form manageLabels.clearAddForm(); //hide the add form manageLabels.onHideAddForm(); - + return false; }); - //TODO: Add method to check that language is selected on submission - - /* - $('input#submit').click( function() { - manageLabels.processLabel(manageLabels.selectedRadio); - $('span.or').hide(); - $('a.cancel').hide(); - $('span#indicator').removeClass('hidden'); - $('input.submit').addClass('disabledSubmit'); - $('input.submit').attr('disabled', 'disabled'); - });*/ }, clearAddForm:function() { @@ -179,12 +180,12 @@ var manageLabels = { var languageName = $(selectedLink).attr("languageName"); $(selectedLink).parent().remove(); //See if there are any other remove link - if(languageCode != "untyped") { + if(languageName != "untyped") { //find if there are any other remove links for the same language var removeLinks = manageLabels.existingLabelsList.find("a.remove[languageName='" + languageName + "']"); if(removeLinks.length == 0) { //if there aren't any other labels for this language, also remove the heading - manageLabels.existingLabelsList.find("h3[languageName='" + langaugeName + "']").remove(); + manageLabels.existingLabelsList.find("h3[languageName='" + languageName + "']").remove(); } } @@ -223,6 +224,11 @@ var manageLabels = { var compB = b["label"]; return compA < compB ? -1 : 1; }); + //Re-show the add button and the form if they were hidden before + if(availableLocalesList.length > 0 && manageLabels.showFormButtonWrapper.is(":hidden")) { + manageLabels.showFormButtonWrapper.show(); + } + //Now replace dropdown with this new list manageLabels.generateLocalesDropdown(availableLocalesList); diff --git a/webapp/web/templates/freemarker/body/individual/manageLabelsForIndividual.ftl b/webapp/web/templates/freemarker/body/individual/manageLabelsForIndividual.ftl index 6c5492faa..dea117f5c 100644 --- a/webapp/web/templates/freemarker/body/individual/manageLabelsForIndividual.ftl +++ b/webapp/web/templates/freemarker/body/individual/manageLabelsForIndividual.ftl @@ -17,7 +17,10 @@ <#assign submissionErrors = editSubmission.validationErrors/> <#assign submissionErrorsExist = "true" /> - +<#assign availableLocalesNumber = 0/> +<#if editConfiguration.pageData.selectLocale?has_content> + <#assign availableLocalesNumber = editConfiguration.pageData.selectLocale?size /> + <#if editConfiguration.pageData.subjectName?? >

    ${i18n().manage_labels_for} ${editConfiguration.pageData.subjectName}

    <#else> @@ -64,7 +67,7 @@

    - +