From 4e96cd318dd0c1618e4f94cead8af47e8fe1b53f Mon Sep 17 00:00:00 2001 From: hjkhjk54 Date: Wed, 13 Jun 2012 19:37:04 +0000 Subject: [PATCH] page management updates --- .../n3editing/VTwo/EditConfigurationVTwo.java | 41 +++ .../VTwo/MultiValueEditSubmission.java | 10 + .../generators/ManagePageGenerator.java | 239 +++++++++++++++++- .../preprocessors/ManagePagePreprocessor.java | 47 ++++ .../utils/ProcessClassGroupDataGetterN3.java | 56 +++- .../utils/ProcessDataGetterAbstract.java | 16 ++ .../utils/ProcessDataGetterN3.java | 12 + .../utils/ProcessFixedHTMLN3.java | 91 ++++++- ...cessIndividualsForClassesDataGetterN3.java | 56 ++++ .../utils/ProcessSparqlDataGetterN3.java | 57 ++++- ...IndividualsForClassesDataGetterN3Test.java | 30 +++ webapp/web/js/menupage/pageManagementUtils.js | 80 +++++- .../processFixedHTMLDataGetterContent.js | 13 + .../body/pagemanagement/pageList.ftl | 3 + .../pageManagement--customDataScript.ftl | 1 + .../freemarker/edit/forms/pageManagement.ftl | 32 ++- 16 files changed, 756 insertions(+), 28 deletions(-) create mode 100644 webapp/test/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/preprocessors/utils/ProcessIndividualsForClassesDataGetterN3Test.java diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/EditConfigurationVTwo.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/EditConfigurationVTwo.java index 632802ac3..bdf684f48 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/EditConfigurationVTwo.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/EditConfigurationVTwo.java @@ -379,6 +379,31 @@ public class EditConfigurationVTwo { hasBeenPreparedForUpdate = true; } + + /** + * Prepare for a param update: Run SPARQL for existing values. + * This can be used for a direct form which does not correspond directly to either + * data or object property form. + */ + public void prepareForParamUpdate( Model model ){ + if( model == null ) { + log.debug("Model is null and will be throwing an error"); + throw new Error("EditConfiguration.prepareForObjPropUpdate() needs a non-null Model");} + + + basicPrepare(); + + // run SPARQL, sub in values + SparqlEvaluateVTwo sparqlEval = new SparqlEvaluateVTwo( model ); + runSparqlForAdditional( sparqlEval ); + try { + runSparqlForExisting( sparqlEval ); + } catch (Exception e) { + e.printStackTrace(); + } + + hasBeenPreparedForUpdate = true; + } /** * Run SPARQL for Additional values. This can be used for @@ -557,6 +582,14 @@ public class EditConfigurationVTwo { return this; } + public EditConfigurationVTwo addUrisInScope(Map> uriValues) { + if( urisInScope == null ){ + urisInScope = new HashMap>(); + } + urisInScope.putAll(uriValues); + return this; + } + public Map> getLiteralsInScope() { @@ -1135,6 +1168,14 @@ public class EditConfigurationVTwo { literalsInScope.put(key, Arrays.asList(values)); return this; } + + public EditConfigurationVTwo addLiteralsInScope(Map> scopeLiterals) { + if( literalsInScope == null ){ + literalsInScope = new HashMap>(); + } + literalsInScope.putAll(scopeLiterals); + return this; + } public void setUrlToReturnTo(String url){ this.urlToReturnTo = url; diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/MultiValueEditSubmission.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/MultiValueEditSubmission.java index 072cf6ac6..f9c86afe9 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/MultiValueEditSubmission.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/MultiValueEditSubmission.java @@ -304,4 +304,14 @@ public class MultiValueEditSubmission { log.debug("No value found for query parameter " + var); } } + + //Check if a certain key has a value associated that is not null + + public boolean hasLiteralValue(String key) { + return (this.literalsFromForm.containsKey(key) && this.literalsFromForm.get(key) != null); + } + + public boolean hasUriValue(String key) { + return (this.urisFromForm.containsKey(key) && this.urisFromForm.get(key) != null); + } } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/ManagePageGenerator.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/ManagePageGenerator.java index 287099b78..17d7cf375 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/ManagePageGenerator.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/generators/ManagePageGenerator.java @@ -10,7 +10,23 @@ import java.util.Map; import javax.servlet.http.HttpSession; +import net.sf.json.JSONArray; +import net.sf.json.JSONObject; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + import com.hp.hpl.jena.ontology.OntModel; +import com.hp.hpl.jena.rdf.model.Literal; +import com.hp.hpl.jena.rdf.model.Resource; +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.QuerySolution; +import com.hp.hpl.jena.query.QuerySolutionMap; +import com.hp.hpl.jena.query.ResultSet; +import com.hp.hpl.jena.rdf.model.ResourceFactory; import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder; @@ -19,6 +35,8 @@ import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.EditConfigurationUti 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.ManagePagePreprocessor; +import edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.preprocessors.utils.ProcessDataGetterN3; +import edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.preprocessors.utils.ProcessDataGetterN3Utils; import edu.cornell.mannlib.vitro.webapp.utils.dataGetter.DataGetterUtils; import edu.cornell.mannlib.vitro.webapp.utils.menuManagement.MenuManagementDataUtils; @@ -30,6 +48,8 @@ public class ManagePageGenerator extends BaseEditConfigurationGenerator implemen private String template = "pageManagement.ftl"; public static final String defaultDisplayNs = DisplayVocabulary.NAMESPACE.getURI() + "n"; + private Log log = LogFactory.getLog(ManagePageGenerator.class); + @Override public EditConfigurationVTwo getEditConfiguration( VitroRequest vreq, HttpSession session) { EditConfigurationVTwo conf = new EditConfigurationVTwo(); @@ -164,6 +184,10 @@ public class ManagePageGenerator extends BaseEditConfigurationGenerator implemen //Page title pageName or page hasDataGetter dataGetter editConfiguration.setUrlPatternToReturnTo("/individual"); editConfiguration.setEntityToReturnTo(subjectUri); + //Set update version here + //if subject uri = page uri != null or empty, editing existing page + editConfiguration.setParamUpdate(true); + } editConfiguration.setSubjectUri(subjectUri); editConfiguration.setPredicateUri(predicateUri); @@ -177,9 +201,12 @@ public class ManagePageGenerator extends BaseEditConfigurationGenerator implemen //Double-check if this will even work with over-written model in the case of display model? setupModelSelectorsFromVitroRequest(vreq, editConfig); OntModel queryModel = (OntModel)vreq.getAttribute("jenaOntModel"); - - if (editConfig.getSubjectUri() != null) { - editConfig.prepareForObjPropUpdate(queryModel); + if (editConfig.isParamUpdate()) { + //editConfig.prepareForObjPropUpdate(queryModel); + //Set up edit configuration with all the values required + //Retrieve existing values for page and menu item level + editConfig.prepareForParamUpdate(queryModel); + retrieveExistingDataGetterInfo(editConfig, queryModel); } else{ //if no subject uri, this is creating a new page @@ -188,7 +215,140 @@ public class ManagePageGenerator extends BaseEditConfigurationGenerator implemen } - //In the case where this is a new page, need to ensure page gets a new + //This method will get the data getters related to this page + //And retrieve the current information for each of those data getters + private void retrieveExistingDataGetterInfo(EditConfigurationVTwo editConfig, OntModel queryModel) { + String pageUri = editConfig.getSubjectUri(); + executeExistingDataGettersInfo(editConfig, pageUri, queryModel); + + + } + + private void executeExistingDataGettersInfo(EditConfigurationVTwo editConfig, String pageUri, OntModel queryModel) { + //Create json array to be set within form specific data + JSONArray jsonArray = new JSONArray(); + String querystr = getExistingDataGettersQuery(); + //Bind pageUri to query + QuerySolutionMap initialBindings = new QuerySolutionMap(); + initialBindings.add("page", ResourceFactory.createResource(pageUri)); + QueryExecution qe = null; + try{ + Query query = QueryFactory.create(querystr); + qe = QueryExecutionFactory.create(query, queryModel, initialBindings); + ResultSet results = qe.execSelect(); + int counter = 0; + while( results.hasNext()){ + QuerySolution qs = results.nextSolution(); + Resource dg = qs.getResource("dataGetter"); + Resource dgType = qs.getResource("dataGetterType"); + String dgClassName = getClassName(dgType.getURI()); + + processExistingDataGetter(counter, + dg.getURI(), + dgClassName, editConfig, queryModel, jsonArray); + addJSONArrayToFormSpecificData(jsonArray, editConfig); + //Get the util class for this type and add + //Values in scope/Literals and URIs on form/Fields on form that correspond + counter++; + } + + } catch(Exception ex) { + log.error("Error occurred in executing query " + querystr, ex); + } + } + + private void addJSONArrayToFormSpecificData(JSONArray jsonArray, EditConfigurationVTwo editConfig) { + HashMap data = editConfig.getFormSpecificData(); + data.put("existingPageContentUnits", jsonArray.toString()); + + } + + private void processExistingDataGetter(int counter, String dataGetterURI, String dgClassName, + EditConfigurationVTwo editConfig, OntModel queryModel, JSONArray jsonArray) { + ProcessDataGetterN3 pn = ProcessDataGetterN3Utils.getDataGetterProcessorN3(dgClassName, null); + + //Add N3 Optional as well + addExistingN3Optional(editConfig, pn, counter); + // Add URIs on Form and Add Literals On Form + addExistingLiteralsAndUrisOnForm(editConfig, pn, counter); + // Add fields + addExistingFields(editConfig, pn, counter); + //Add new resources - data getters need to be new resources + addExistingDataGetterNewResources(editConfig, pn, counter); + //Add values in scope + addValuesInScope(editConfig, pn, counter, dataGetterURI, queryModel); + //create JSON object and return in form specific dadta + addJSONObjectToArray(dataGetterURI, pn, queryModel, jsonArray); + + } + + //Takes data getter information, packs within JSON object to send back to the form + private void addJSONObjectToArray(String dataGetterURI, ProcessDataGetterN3 pn, OntModel queryModel, JSONArray jsonArray) { + JSONObject jo = pn.getExistingValuesJSON(dataGetterURI, queryModel); + jsonArray.add(jo); + } + + //We're adding everything as optional - even what is considered "required" for a specific data getter + private void addExistingN3Optional(EditConfigurationVTwo editConfig, ProcessDataGetterN3 pn, int counter) { + List n3 = pn.retrieveN3Required(counter); + if(pn.retrieveN3Optional(counter) != null) { + n3.addAll(pn.retrieveN3Optional(counter)); + } + editConfig.addN3Optional(n3); + + } + + private void addExistingLiteralsAndUrisOnForm(EditConfigurationVTwo editConfig, ProcessDataGetterN3 pn, + int counter) { + List literalsOnForm = pn.retrieveLiteralsOnForm(counter); + editConfig.addLiteralsOnForm(literalsOnForm); + List urisOnForm = pn.retrieveUrisOnForm(counter); + editConfig.addUrisOnForm(urisOnForm); + + } + + private void addExistingFields(EditConfigurationVTwo editConfig, ProcessDataGetterN3 pn, int counter) { + List existingFields = pn.retrieveFields(counter); + editConfig.addFields(existingFields); + + } + + private void addExistingDataGetterNewResources(EditConfigurationVTwo editConfig, ProcessDataGetterN3 pn, + int counter) { + //Should we even add new resources? + List newResources = pn.getNewResources(counter); + for(String r: newResources) { + //using default for now but will have to check + editConfig.addNewResource(r, null); + } + + } + + private void addValuesInScope(EditConfigurationVTwo editConfig, + ProcessDataGetterN3 pn, int counter, String dataGetterURI, OntModel queryModel) { + pn.populateExistingValues(dataGetterURI, counter, queryModel); + Map> existingLiteralValues = pn.retrieveExistingLiteralValues(); + Map> existingUriValues = pn.retrieveExistingUriValues(); + editConfig.addLiteralsInScope(existingLiteralValues); + editConfig.addUrisInScope(existingUriValues); + } + + private String getClassName(String dataGetterURI) { + if(dataGetterURI.contains("java:")) { + return dataGetterURI.substring("java:".length()); + } + return dataGetterURI; + } + + //Get the data getter uri and the type of the data getter + private String getExistingDataGettersQuery() { + String query = getSparqlPrefix() + "SELECT ?dataGetter ?dataGetterType WHERE {" + + "?page display:hasDataGetter ?dataGetter . ?dataGetter rdf:type ?dataGetterType .}"; + return query; + } + + + //In the case where this is a new page, need to ensure page gets a new private void setNewResources(EditConfigurationVTwo conf) { //null makes default namespace be triggered //conf.addNewResource("page", defaultDisplayNs); @@ -211,22 +371,67 @@ public class ManagePageGenerator extends BaseEditConfigurationGenerator implemen } - //Get page uri for object private HashMap generateSparqlForExistingUris() { HashMap map = new HashMap(); + map.put("menuItem", getExistingMenuItemQuery()); return map; } + private String getExistingMenuItemQuery() { + String query = getSparqlPrefix() + "SELECT ?menuItem WHERE {?menuItem display:toPage ?page .}"; + return query; + } + + //Page level literals: + //"pageName", "prettyUrl", "menuPosition", "menuLinkText", "customTemplate" + private HashMap generateSparqlForExistingLiterals() { HashMap map = new HashMap(); + map.put("pageName", getExistingPageNameQuery()); + map.put("prettyUrl", getExistingPrettyUrlQuery()); + map.put("menuPosition", getExistingMenuPositionQuery()); + map.put("menuLinkText", getExistingMenuLinkTextQuery()); + map.put("customTemplate", getExistingCustomTemplateQuery()); return map; } - - - + private String getSparqlPrefix() { + return "PREFIX display: \n" + + "PREFIX rdf: "; + } - //Form specific data + private String getExistingPageNameQuery() { + // TODO Auto-generated method stub + String query = getSparqlPrefix() + "SELECT ?pageName WHERE {" + + "?page display:title ?pageName .}"; + return query; + } + +private String getExistingPrettyUrlQuery() { + String query = getSparqlPrefix() + "SELECT ?prettyUrl WHERE {" + + "?page display:urlMapping ?prettyUrl .}"; + return query; + } + +//If menu, return menu position +private String getExistingMenuPositionQuery() { + String menuPositionQuery = getSparqlPrefix() + "SELECT ?menuPosition WHERE {" + + "?menuItem display:toPage ?page . ?menuItem display:menuPosition ?menuPosition. }"; + return menuPositionQuery; + } + +private String getExistingMenuLinkTextQuery() { + String menuPositionQuery = getSparqlPrefix() + "SELECT ?menuLinkText WHERE {" + + "?menuItem display:toPage ?page . ?menuItem display:linkText ?menuLinkText. }"; + return menuPositionQuery; + } + +private String getExistingCustomTemplateQuery() { + String query = getSparqlPrefix() + "SELECT ?customTemplate WHERE {?page display:requiresBodyTemplate ?customTemplate .}"; + return query; +} + +//Form specific data //In this case, need to get all the different data getter TYPES and labels //Also need to pass back the map for the options presented to the user //which is different from the above @@ -242,7 +447,13 @@ public class ManagePageGenerator extends BaseEditConfigurationGenerator implemen //For every type of page, will need some "always required" data addRequiredPageData(vreq, formSpecificData); //For a new page, we will need to add the following data - addNewPageData(vreq, formSpecificData); + //Is param update not + if(editConfiguration.getSubjectUri() != null) { + addExistingPageData(vreq, formSpecificData); + } else { + addNewPageData(vreq, formSpecificData); + } + editConfiguration.setFormSpecificData(formSpecificData); } @@ -261,6 +472,14 @@ public class ManagePageGenerator extends BaseEditConfigurationGenerator implemen MenuManagementDataUtils.includeRequiredSystemData(vreq.getSession().getServletContext(), data); } + private void addExistingPageData(VitroRequest vreq, Map data) { + addNewPageData(vreq, data); + data.put("menuAction", "Edit"); + data.put("title", "Edit Menu Item"); + //Set up pageContentUnits as String - to save later + data.put("existingPageContentUnits", null); + } + private void addNewPageData(VitroRequest vreq, Map data) { data.put("title", "Add Menu Item"); data.put("menuAction", "Add"); diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/preprocessors/ManagePagePreprocessor.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/preprocessors/ManagePagePreprocessor.java index 6496ad9c1..f4fc7e1ae 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/preprocessors/ManagePagePreprocessor.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/preprocessors/ManagePagePreprocessor.java @@ -22,6 +22,7 @@ import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.EditConfigurationUti import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.EditConfigurationVTwo; import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.MultiValueEditSubmission; import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.fields.FieldVTwo; +import edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.EditConfigurationConstants; import edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.generators.ManagePageGenerator; import edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.preprocessors.utils.ProcessDataGetterN3; import edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.preprocessors.utils.ProcessDataGetterN3Utils; @@ -59,6 +60,13 @@ public class ManagePagePreprocessor extends // For query parameters, check whether CUI copySubmissionValues(); processDataGetters(); + //In case of edit, need to force deletion of existing values where necessary + //In our case, values that already exist and will be overwritten will be in submission already + //just as new values will + //Anything left over should be replaced with blank value sentinel as that would + //no longer be on the form and have a value submitted and we can delete that statement + //if it exists + processExistingValues(); } @@ -79,6 +87,45 @@ public class ManagePagePreprocessor extends copyMap.putAll(originalMap); return copyMap; } + + private void processExistingValues() { + //For all literals that were originally in scope that don't have values on the form + //anymore, replace with blank sentinel value + //For those literals, those values will be replaced with form values where overwritten + //And will be deleted where not overwritten which is the behavior we desire + Map> literalsInScope = this.editConfiguration.getLiteralsInScope(); + Map> urisInScope = this.editConfiguration.getUrisInScope(); + List literalKeys = new ArrayList(literalsInScope.keySet()); + + + List uriKeys = new ArrayList(urisInScope.keySet()); + for(String literalName: literalKeys) { + + //if submission already has value for this, then leave be + //otherwise replace with blank value sentinel + if(!submission.hasLiteralValue(literalName)) { + submission.addLiteralToForm(editConfiguration, + editConfiguration.getField(literalName), + literalName, + (new String[] {EditConfigurationConstants.BLANK_SENTINEL})); + } + } + + for(String uriName: uriKeys) { + //these values should never be overwritten or deleted + if(uriName != "page" && uriName != "menuItem" && !uriName.startsWith("dataGetter")) { + if(!submission.hasUriValue(uriName)) { + submission.addLiteralToForm(editConfiguration, + editConfiguration.getField(uriName), + uriName, + (new String[] {EditConfigurationConstants.BLANK_SENTINEL})); + } + } + } + //Other than data getter itself, also get rid of any of the old URIs if any + + } + private void processDataGetters() { convertToJson(); diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/preprocessors/utils/ProcessClassGroupDataGetterN3.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/preprocessors/utils/ProcessClassGroupDataGetterN3.java index fcbc2ff6e..704d89a44 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/preprocessors/utils/ProcessClassGroupDataGetterN3.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/preprocessors/utils/ProcessClassGroupDataGetterN3.java @@ -8,6 +8,16 @@ import java.util.Arrays; import java.util.HashMap; import java.util.Map; +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.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.QuerySolution; +import com.hp.hpl.jena.query.ResultSet; import com.hp.hpl.jena.rdf.model.Literal; import edu.cornell.mannlib.vitro.webapp.dao.DisplayVocabulary; @@ -19,6 +29,8 @@ import net.sf.json.JSONSerializer; public class ProcessClassGroupDataGetterN3 extends ProcessDataGetterAbstract { private static String classType = "java:edu.cornell.mannlib.vitro.webapp.utils.dataGetter.ClassGroupPageData"; private static String classGroupVarBase = "classGroup"; + private Log log = LogFactory.getLog(ProcessClassGroupDataGetterN3.class); + public ProcessClassGroupDataGetterN3(){ } @@ -89,7 +101,49 @@ public class ProcessClassGroupDataGetterN3 extends ProcessDataGetterAbstract { public String getClassType() { return classType; } - + + //for existing values + //TODO: Update + public void populateExistingValues(String dataGetterURI, int counter, OntModel queryModel) { + //First, put dataGetterURI within scope as well + existingUriValues.put(this.getDataGetterVar(counter), new ArrayList(Arrays.asList(dataGetterURI))); + //Sparql queries for values to be executed + //And then placed in the correct place/literal or uri + String querystr = getExistingValuesSparqlQuery(dataGetterURI); + QueryExecution qe = null; + try{ + Query query = QueryFactory.create(querystr); + qe = QueryExecutionFactory.create(query, queryModel); + ResultSet results = qe.execSelect(); + while( results.hasNext()){ + QuerySolution qs = results.nextSolution(); + Literal saveToVarLiteral = qs.getLiteral("saveToVar"); + Literal htmlValueLiteral = qs.getLiteral("htmlValue"); + //Put both literals in existing literals + existingLiteralValues.put(this.getVarName("saveToVar", counter), + new ArrayList(Arrays.asList(saveToVarLiteral, htmlValueLiteral))); + } + } catch(Exception ex) { + log.error("Exception occurred in retrieving existing values with query " + querystr, ex); + } + + + } + + + //?dataGetter a FixedHTMLDataGetter ; display:saveToVar ?saveToVar; display:htmlValue ?htmlValue . + protected String getExistingValuesSparqlQuery(String dataGetterURI) { + String query = this.getSparqlPrefix() + "SELECT ?saveToVar ?htmlValue WHERE {" + + "<" + dataGetterURI + "> display:saveToVar ?saveToVar . \n" + + "<" + dataGetterURI + "> display:htmlValue ?htmlValue . \n" + + "}"; + return query; + } + + public JSONObject getExistingValuesJSON(String dataGetterURI, OntModel queryModel) { + JSONObject jo = new JSONObject(); + return jo; + } } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/preprocessors/utils/ProcessDataGetterAbstract.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/preprocessors/utils/ProcessDataGetterAbstract.java index f17d8f531..b7ab0dbc6 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/preprocessors/utils/ProcessDataGetterAbstract.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/preprocessors/utils/ProcessDataGetterAbstract.java @@ -47,6 +47,22 @@ public abstract class ProcessDataGetterAbstract implements ProcessDataGetterN3 { newResources.add("dataGetter" + counter); return newResources; } + + protected String getSparqlPrefix() { + return "PREFIX display: \n" + + "PREFIX rdf: "; + + } + + //For existing values + protected Map> existingLiteralValues = new HashMap>(); + protected Map> existingUriValues = new HashMap>(); + public Map> retrieveExistingLiteralValues() { + return existingLiteralValues; + } + public Map> retrieveExistingUriValues() { + return existingUriValues; + } } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/preprocessors/utils/ProcessDataGetterN3.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/preprocessors/utils/ProcessDataGetterN3.java index 97ca9df78..2c909e3d1 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/preprocessors/utils/ProcessDataGetterN3.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/preprocessors/utils/ProcessDataGetterN3.java @@ -4,6 +4,12 @@ package edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.preprocess import java.util.ArrayList; import java.util.List; +import java.util.Map; + +import net.sf.json.JSONObject; + +import com.hp.hpl.jena.ontology.OntModel; +import com.hp.hpl.jena.rdf.model.Literal; import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.fields.FieldVTwo; @@ -22,5 +28,11 @@ public interface ProcessDataGetterN3 { public String getVarName(String base, int counter); public String getDataGetterVar(int counter); public List getNewResources(int counter); + + //Get Existing values to put in scope + public Map> retrieveExistingLiteralValues(); + public Map> retrieveExistingUriValues(); + public void populateExistingValues(String dataGetterURI, int counter, OntModel queryModel); + public JSONObject getExistingValuesJSON(String dataGetterURI, OntModel queryModel); } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/preprocessors/utils/ProcessFixedHTMLN3.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/preprocessors/utils/ProcessFixedHTMLN3.java index 01d8a933f..cad9cefec 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/preprocessors/utils/ProcessFixedHTMLN3.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/preprocessors/utils/ProcessFixedHTMLN3.java @@ -2,22 +2,30 @@ package edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.preprocessors.utils; -import java.util.List; import java.util.ArrayList; import java.util.Arrays; -import java.util.HashMap; -import java.util.Map; +import java.util.List; +import net.sf.json.JSONObject; + +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.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.QuerySolution; +import com.hp.hpl.jena.query.ResultSet; import com.hp.hpl.jena.rdf.model.Literal; import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.fields.FieldVTwo; - -import net.sf.json.JSONObject; -import net.sf.json.JSONSerializer; //Returns the appropriate n3 based on data getter public class ProcessFixedHTMLN3 extends ProcessDataGetterAbstract { private static String classType = "java:edu.cornell.mannlib.vitro.webapp.utils.dataGetter.FixedHTMLDataGetter"; - + private Log log = LogFactory.getLog(ProcessFixedHTMLN3.class); + public ProcessFixedHTMLN3(){ } @@ -25,6 +33,7 @@ public class ProcessFixedHTMLN3 extends ProcessDataGetterAbstract { //TODO: ensure correct model returned //We shouldn't use the ACTUAL values here but generate the n3 required + //?dataGetter a FixedHTMLDataGetter ; display:saveToVar ?saveToVar; display:htmlValue ?htmlValue . public List retrieveN3Required(int counter) { String dataGetterVar = getDataGetterVar(counter); String n3 = dataGetterVar + " a <" + classType + ">; \n" + @@ -74,7 +83,73 @@ public class ProcessFixedHTMLN3 extends ProcessDataGetterAbstract { return Arrays.asList(); } - + //For Existing Values in case of editing + + //Execute populate before retrieval + public void populateExistingValues(String dataGetterURI, int counter, OntModel queryModel) { + //First, put dataGetterURI within scope as well + existingUriValues.put(this.getDataGetterVar(counter), new ArrayList(Arrays.asList(dataGetterURI))); + //Sparql queries for values to be executed + //And then placed in the correct place/literal or uri + String querystr = getExistingValuesSparqlQuery(dataGetterURI); + QueryExecution qe = null; + try{ + Query query = QueryFactory.create(querystr); + qe = QueryExecutionFactory.create(query, queryModel); + ResultSet results = qe.execSelect(); + while( results.hasNext()){ + QuerySolution qs = results.nextSolution(); + Literal saveToVarLiteral = qs.getLiteral("saveToVar"); + Literal htmlValueLiteral = qs.getLiteral("htmlValue"); + //Put both literals in existing literals + existingLiteralValues.put(this.getVarName("saveToVar", counter), + new ArrayList(Arrays.asList(saveToVarLiteral))); + existingLiteralValues.put(this.getVarName("htmlValue", counter), + new ArrayList(Arrays.asList(htmlValueLiteral))); + } + } catch(Exception ex) { + log.error("Exception occurred in retrieving existing values with query " + querystr, ex); + } + + + } + + + //?dataGetter a FixedHTMLDataGetter ; display:saveToVar ?saveToVar; display:htmlValue ?htmlValue . + protected String getExistingValuesSparqlQuery(String dataGetterURI) { + String query = this.getSparqlPrefix() + "SELECT ?saveToVar ?htmlValue WHERE {" + + "<" + dataGetterURI + "> display:saveToVar ?saveToVar . \n" + + "<" + dataGetterURI + "> display:htmlValue ?htmlValue . \n" + + "}"; + return query; + } + + + //Method to create a JSON object with existing values to return to form + //There may be a better way to do this without having to run the query twice + //TODO: Refactor code if required + public JSONObject getExistingValuesJSON(String dataGetterURI, OntModel queryModel) { + JSONObject jObject = new JSONObject(); + jObject.element("dataGetterClass", classType); + String querystr = getExistingValuesSparqlQuery(dataGetterURI); + QueryExecution qe = null; + try{ + Query query = QueryFactory.create(querystr); + qe = QueryExecutionFactory.create(query, queryModel); + ResultSet results = qe.execSelect(); + while( results.hasNext()){ + QuerySolution qs = results.nextSolution(); + Literal saveToVarLiteral = qs.getLiteral("saveToVar"); + Literal htmlValueLiteral = qs.getLiteral("htmlValue"); + jObject.element("saveToVar", saveToVarLiteral.getString()); + jObject.element("htmlValue", htmlValueLiteral.getString()); + } + } catch(Exception ex) { + log.error("Exception occurred in retrieving existing values with query " + querystr, ex); + } + return jObject; + + } } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/preprocessors/utils/ProcessIndividualsForClassesDataGetterN3.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/preprocessors/utils/ProcessIndividualsForClassesDataGetterN3.java index cd7f25b31..521e7ba09 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/preprocessors/utils/ProcessIndividualsForClassesDataGetterN3.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/preprocessors/utils/ProcessIndividualsForClassesDataGetterN3.java @@ -9,6 +9,16 @@ import java.util.Arrays; import java.util.HashMap; import java.util.Map; +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.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.QuerySolution; +import com.hp.hpl.jena.query.ResultSet; import com.hp.hpl.jena.rdf.model.Literal; import edu.cornell.mannlib.vitro.webapp.dao.DisplayVocabulary; @@ -23,6 +33,8 @@ public class ProcessIndividualsForClassesDataGetterN3 extends ProcessClassGroup protected JSONObject values = null; int classCount = 0; protected static String individualClassVarNameBase = "classesSelectedInClassGroup"; + private Log log = LogFactory.getLog(ProcessIndividualsForClassesDataGetterN3.class); + public ProcessIndividualsForClassesDataGetterN3(JSONObject jsonObject){ this.values = jsonObject; if(values != null && values.containsKey(individualClassVarNameBase)) { @@ -132,7 +144,51 @@ public class ProcessIndividualsForClassesDataGetterN3 extends ProcessClassGroup public String getClassType() { return classType; } + + //Existing values + //TODO: Correct + + public void populateExistingValues(String dataGetterURI, int counter, OntModel queryModel) { + //First, put dataGetterURI within scope as well + existingUriValues.put(this.getDataGetterVar(counter), new ArrayList(Arrays.asList(dataGetterURI))); + //Sparql queries for values to be executed + //And then placed in the correct place/literal or uri + String querystr = getExistingValuesSparqlQuery(dataGetterURI); + QueryExecution qe = null; + try{ + Query query = QueryFactory.create(querystr); + qe = QueryExecutionFactory.create(query, queryModel); + ResultSet results = qe.execSelect(); + while( results.hasNext()){ + QuerySolution qs = results.nextSolution(); + Literal saveToVarLiteral = qs.getLiteral("saveToVar"); + Literal htmlValueLiteral = qs.getLiteral("htmlValue"); + //Put both literals in existing literals + existingLiteralValues.put(this.getVarName("saveToVar", counter), + new ArrayList(Arrays.asList(saveToVarLiteral, htmlValueLiteral))); + } + } catch(Exception ex) { + log.error("Exception occurred in retrieving existing values with query " + querystr, ex); + } + + + } + + + //?dataGetter a FixedHTMLDataGetter ; display:saveToVar ?saveToVar; display:htmlValue ?htmlValue . + protected String getExistingValuesSparqlQuery(String dataGetterURI) { + String query = this.getSparqlPrefix() + "SELECT ?saveToVar ?htmlValue WHERE {" + + "<" + dataGetterURI + "> display:saveToVar ?saveToVar . \n" + + "<" + dataGetterURI + "> display:htmlValue ?htmlValue . \n" + + "}"; + return query; + } + + public JSONObject getExistingValuesJSON(String dataGetterURI, OntModel queryModel) { + JSONObject jo = new JSONObject(); + return jo; + } } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/preprocessors/utils/ProcessSparqlDataGetterN3.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/preprocessors/utils/ProcessSparqlDataGetterN3.java index 132cf5307..1ef4d1e1d 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/preprocessors/utils/ProcessSparqlDataGetterN3.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/preprocessors/utils/ProcessSparqlDataGetterN3.java @@ -8,6 +8,16 @@ import java.util.Arrays; import java.util.HashMap; import java.util.Map; +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.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.QuerySolution; +import com.hp.hpl.jena.query.ResultSet; import com.hp.hpl.jena.rdf.model.Literal; import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.fields.FieldVTwo; @@ -17,7 +27,8 @@ import net.sf.json.JSONSerializer; //Returns the appropriate n3 based on data getter public class ProcessSparqlDataGetterN3 extends ProcessDataGetterAbstract { private static String classType = "java:edu.cornell.mannlib.vitro.webapp.utils.dataGetter.SparqlQueryDataGetter"; - + private Log log = LogFactory.getLog(ProcessSparqlDataGetterN3.class); + public ProcessSparqlDataGetterN3(){ } @@ -95,8 +106,52 @@ public class ProcessSparqlDataGetterN3 extends ProcessDataGetterAbstract { public List getUriVarNamesBase() { return Arrays.asList("queryModel"); } + + //Existing values + //TODO: Correct + + public void populateExistingValues(String dataGetterURI, int counter, OntModel queryModel) { + //First, put dataGetterURI within scope as well + existingUriValues.put(this.getDataGetterVar(counter), new ArrayList(Arrays.asList(dataGetterURI))); + //Sparql queries for values to be executed + //And then placed in the correct place/literal or uri + String querystr = getExistingValuesSparqlQuery(dataGetterURI); + QueryExecution qe = null; + try{ + Query query = QueryFactory.create(querystr); + qe = QueryExecutionFactory.create(query, queryModel); + ResultSet results = qe.execSelect(); + while( results.hasNext()){ + QuerySolution qs = results.nextSolution(); + Literal saveToVarLiteral = qs.getLiteral("saveToVar"); + Literal htmlValueLiteral = qs.getLiteral("htmlValue"); + //Put both literals in existing literals + existingLiteralValues.put(this.getVarName("saveToVar", counter), + new ArrayList(Arrays.asList(saveToVarLiteral, htmlValueLiteral))); + } + } catch(Exception ex) { + log.error("Exception occurred in retrieving existing values with query " + querystr, ex); + } + + + } + + + //?dataGetter a FixedHTMLDataGetter ; display:saveToVar ?saveToVar; display:htmlValue ?htmlValue . + protected String getExistingValuesSparqlQuery(String dataGetterURI) { + String query = this.getSparqlPrefix() + "SELECT ?saveToVar ?htmlValue WHERE {" + + "<" + dataGetterURI + "> display:saveToVar ?saveToVar . \n" + + "<" + dataGetterURI + "> display:htmlValue ?htmlValue . \n" + + "}"; + return query; + } + + public JSONObject getExistingValuesJSON(String dataGetterURI, OntModel queryModel) { + JSONObject jo = new JSONObject(); + return jo; + } } diff --git a/webapp/test/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/preprocessors/utils/ProcessIndividualsForClassesDataGetterN3Test.java b/webapp/test/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/preprocessors/utils/ProcessIndividualsForClassesDataGetterN3Test.java new file mode 100644 index 000000000..a76abfa73 --- /dev/null +++ b/webapp/test/edu/cornell/mannlib/vitro/webapp/edit/n3editing/configuration/preprocessors/utils/ProcessIndividualsForClassesDataGetterN3Test.java @@ -0,0 +1,30 @@ +package edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.preprocessors.utils; + +import static org.junit.Assert.*; + +import java.util.List; + +import net.sf.json.JSONArray; +import net.sf.json.JSONObject; + +import org.junit.Test; + +public class ProcessIndividualsForClassesDataGetterN3Test { + + @Test + public void testRetrieveN3Required() { + JSONObject jsonObject = new JSONObject(); + JSONArray ja = new JSONArray(); + ja.add("test1"); + ja.add("test2"); + jsonObject.element("classesSelectedInClassGroup", ja); + ProcessIndividualsForClassesDataGetterN3 pn = new ProcessIndividualsForClassesDataGetterN3(jsonObject); + List retrievedN3 = pn.retrieveN3Required(0); + String firstString = retrievedN3.get(0); + //check whether correct type returned + int index = firstString.indexOf(pn.getClassType()); + assert(firstString.indexOf(index) != -1); + } + + +} diff --git a/webapp/web/js/menupage/pageManagementUtils.js b/webapp/web/js/menupage/pageManagementUtils.js index 77a41e0ad..cc005fdd2 100644 --- a/webapp/web/js/menupage/pageManagementUtils.js +++ b/webapp/web/js/menupage/pageManagementUtils.js @@ -2,20 +2,42 @@ var pageManagementUtils = { dataGetterLabelToURI:null,//initialized by custom data + dataGetterURIToLabel:null, //initialized from custom data processDataGetterUtils:processDataGetterUtils,//an external class that should exist before this one dataGetterMap:null, + menuAction:null, // on initial page setup onLoad:function(){ if (this.disableFormInUnsupportedBrowsers()) { return; } this.mixIn(); - this.initDataGetterProcessors(), + this.initReverseURIToLabel(); + this.initDataGetterProcessors(); this.initObjects(); this.bindEventListeners(); this.initDisplay(); - - }, + //if edit, then generate existing content + if(this.menuAction != null) { + this.initExistingContent(); + } + }, + initExistingContent:function() { + this.generateExistingContentSections(); + }, + initReverseURIToLabel:function() { + if(this.dataGetterLabelToURI != null) { + this.dataGetterURIToLabel = {}; + for(var label in this.dataGetterLabelToURI) { + if(label != undefined) { + var uri = this.dataGetterLabelToURI[label]; + this.dataGetterURIToLabel[uri] = label; + } + } + } else { + //Error condition. + } + }, initDataGetterProcessors:function() { //data getter processor map should come in from custom data //Go through each and initialize with their class @@ -268,11 +290,25 @@ var pageManagementUtils = { $newContentObj.find('section#classesInSelectedGroup' + counter).removeClass('hidden'); varOrClass = $newContentObj.find('select#selectClassGroup' + counter + ' option:selected').text(); } - + //For cases where varOrClass might be empty, pass an empty string + if(varOrClass == null || varOrClass==undefined) { + varOrClass = ""; + } pageManagementUtils.createClonedContentContainer($newContentObj, counter, contentTypeLabel, varOrClass); //previously increased by 10, just increasing by 1 here pageManagementUtils.counter++; }, + //For edit, need to have text passed in + //Returns new content object itself + cloneContentAreaForEdit: function(contentType, contentTypeLabel, labelText) { + var counter = pageManagementUtils.counter; + //Clone the object, renaming ids and copying text area values as well + $newContentObj = pageManagementUtils.createCloneObject(contentType, counter); + pageManagementUtils.createClonedContentContainer($newContentObj, counter, contentTypeLabel, labelText); + //previously increased by 10, just increasing by 1 here + pageManagementUtils.counter++; + return $newContentObj; + }, createClonedContentContainer:function($newContentObj, counter, contentTypeLabel, varOrClass) { //Create the container for the new content $newDivContainer = $("
", { @@ -530,6 +566,42 @@ var pageManagementUtils = { var newId = originalId + counter; $(this).attr("id", newId); }); + }, + //To actually generate the content for existing values + generateExistingContentSections:function() { + if(pageManagementUtils.menuAction == "Edit") { + var $existingContent = $("#existingPageContentUnits"); + //create json object from string version json2. + if($existingContent.length > 0) { + var jsonObjectString = $existingContent.val(); + //this returns an array + var JSONContentObjectArray = JSON.parse(jsonObjectString); + var len = JSONContentObjectArray.length; + var i; + for(i = 0; i < len; i++) { + //Get the type of data getter and create the appropriate section/populate + var JSONContentObject = JSONContentObjectArray[i]; + var dataGetterClass = JSONContentObject["dataGetterClass"]; + if(dataGetterClass != null) { + //Get the Label for the URI + var contentType = pageManagementUtils.dataGetterURIToLabel[dataGetterClass]; + //Get the label for this content t + var contentTypeLabel = "test label"; + //Get the processor class for this type + var dataGetterProcessorObject = pageManagementUtils.processDataGetterUtils.dataGetterProcessorMap[contentType]; + var additionalLabelText = dataGetterProcessorObject.retrieveAdditionalLabelText(JSONContentObject); + //Clone the appropriate section for the label + var $newContentObj = pageManagementUtils.cloneContentAreaForEdit(contentType, contentTypeLabel, additionalLabelText); + //Populate the section with the values + dataGetterProcessorObject.populatePageContentSection(JSONContentObject, $newContentObj); + } else { + //error condition + } + } + + } + + } } }; diff --git a/webapp/web/js/menupage/processFixedHTMLDataGetterContent.js b/webapp/web/js/menupage/processFixedHTMLDataGetterContent.js index 577a0e719..6666d07c1 100644 --- a/webapp/web/js/menupage/processFixedHTMLDataGetterContent.js +++ b/webapp/web/js/menupage/processFixedHTMLDataGetterContent.js @@ -14,6 +14,19 @@ var processFixedHTMLDataGetterContent = { //query model should also be an input var returnObject = {saveToVar:saveToVarValue, htmlValue:htmlValue, dataGetterClass:this.dataGetterClass}; return returnObject; + }, + //For an existing set of content where form is already set, fill in the values + populatePageContentSection:function(existingContentObject, pageContentSection) { + var saveToVarValue = existingContentObject["saveToVar"]; + var htmlValue = existingContentObject["htmlValue"]; + //Now find and set value + pageContentSection.find("input[name='saveToVar']").val(saveToVarValue); + pageContentSection.find("textarea[name='htmlValue']").val(htmlValue); + }, + //For the label of the content section for editing, need to add additional value + retrieveAdditionalLabelText:function(existingContentObject) { + var saveToVarValue = existingContentObject["saveToVar"]; + return saveToVarValue; } diff --git a/webapp/web/templates/freemarker/body/pagemanagement/pageList.ftl b/webapp/web/templates/freemarker/body/pagemanagement/pageList.ftl index 1230695fb..35be30050 100644 --- a/webapp/web/templates/freemarker/body/pagemanagement/pageList.ftl +++ b/webapp/web/templates/freemarker/body/pagemanagement/pageList.ftl @@ -26,6 +26,9 @@ <#if pagex.pageUri?has_content> ${(pagex.title)!'-untitled-'} +   + Edit + <#else> No URI defined for page. diff --git a/webapp/web/templates/freemarker/edit/forms/pageManagement--customDataScript.ftl b/webapp/web/templates/freemarker/edit/forms/pageManagement--customDataScript.ftl index b300f0222..a72caa7fb 100644 --- a/webapp/web/templates/freemarker/edit/forms/pageManagement--customDataScript.ftl +++ b/webapp/web/templates/freemarker/edit/forms/pageManagement--customDataScript.ftl @@ -5,6 +5,7 @@ scripts list.-->