Working on custom forms in freemarker.

This commit is contained in:
bdc34 2010-11-17 17:40:04 +00:00
parent aba71e6913
commit 0b2dc61fbe
8 changed files with 398 additions and 47 deletions

View file

@ -0,0 +1,88 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.controller.freemarker;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpSession;
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.EditConfiguration;
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.EditSubmission;
import freemarker.template.ObjectWrapper;
import freemarker.template.TemplateModelException;
/**
* This controller is intended to place N3 editing data into the
* FM data model and output the FM template for the form.
*/
public class N3EditFormController extends FreemarkerHttpServlet{
@Override
protected ResponseValues processRequest(VitroRequest vreq) {
try{
//get edit objects
HttpSession session = vreq.getSession(false);
if( session == null )
throw new Exception("Cannot get session");
EditConfiguration editConfig = EditConfiguration.getConfigFromSession(session, vreq);
if(editConfig == null )
throw new Exception("Cannot get EditConfiguration from session");
EditSubmission editSubmission = EditSubmission.getEditSubmissionFromSession(session, editConfig);
//add edit info to the template data model and call template
Map<String,Object> map = makeEditDataMap(editConfig, editSubmission);
//how do I add css or js?
//The jsp is adding css and js like this:
/*
List<String> customJs = new ArrayList<String>(Arrays.asList(JavaScript.JQUERY_UI.path(),
JavaScript.CUSTOM_FORM_UTILS.path(),
"/edit/forms/js/customFormWithAutocomplete.js"
));
request.setAttribute("customJs", customJs);
List<String> customCss = new ArrayList<String>(Arrays.asList(Css.JQUERY_UI.path(),
Css.CUSTOM_FORM.path(),
"/edit/forms/css/customFormWithAutocomplete.css"
));
request.setAttribute("customCss", customCss);
*/
//What needs to happen??
//map.put(???);
return new TemplateResponseValues(editConfig.getTemplate(), map);
}catch(Exception ex){
return new ExceptionResponseValues(ex);
}
}
/**
* This method get data out of the editConfig and editSubmission for the template.
* @throws TemplateModelException
*/
private Map<String, Object> makeEditDataMap(EditConfiguration editConfig,
EditSubmission editSubmission) throws TemplateModelException {
Map<String,Object> map = new HashMap<String,Object>();
//This dosen't seem to be the right thing:
map.put("editConfig", ObjectWrapper.BEANS_WRAPPER.wrap(editConfig));
//<@dump var="editConfig"/> outputs:
/*
* Template variable dump
Variable name: editConfig
Type: string
Value: edu.cornell.mannlib.vitro.webapp.edit.n3editing.EditConfiguration@1e60601
*/
if( editSubmission != null)
map.put("editSubmission", ObjectWrapper.BEANS_WRAPPER.wrap(editSubmission));
return map;
}
}

View file

@ -9,6 +9,7 @@ import java.util.Map;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.Field;
import freemarker.template.Configuration; import freemarker.template.Configuration;
import freemarker.template.Template; import freemarker.template.Template;
import freemarker.template.TemplateException; import freemarker.template.TemplateException;
@ -16,6 +17,12 @@ import freemarker.template.TemplateException;
public abstract class BaseEditElement implements EditElement { public abstract class BaseEditElement implements EditElement {
private static final Log log = LogFactory.getLog(BaseEditElement.class); private static final Log log = LogFactory.getLog(BaseEditElement.class);
protected Field field;
public BaseEditElement(Field field){
this.field = field;
}
/** /**
* Utility method for use in EditElements to merge a freemarker template. * Utility method for use in EditElements to merge a freemarker template.
*/ */

View file

@ -10,8 +10,9 @@ import edu.cornell.mannlib.vitro.webapp.edit.n3editing.EditConfiguration;
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.EditSubmission; import edu.cornell.mannlib.vitro.webapp.edit.n3editing.EditSubmission;
import freemarker.template.Configuration; import freemarker.template.Configuration;
/** /**
* All classes that implement this interface must have a public empty constructor that * All classes that implement this interface must have a public constructor that
* will be called with using reflection. * takes a edu.cornell.mannlib.vitro.webapp.edit.n3editing.Field. It will be
* called with using reflection.
*/ */
public interface EditElement { public interface EditElement {
/** /**
@ -37,4 +38,10 @@ public interface EditElement {
* to produce the output. * to produce the output.
*/ */
public String draw(String fieldName, EditConfiguration editConfig, EditSubmission editSub, Configuration fmConfig); public String draw(String fieldName, EditConfiguration editConfig, EditSubmission editSub, Configuration fmConfig);
/**
* We may need a method to get existing URIs and Literals for use in building retraction statements?
*/
// public Map<String,Literal> getExistingLiterals(?);
// public Map<String,Literal> getExistingURIs(?);
} }

View file

@ -97,6 +97,12 @@ public class EditConfiguration {
private ProhibitedFromSearch prohibitedFromSearch; private ProhibitedFromSearch prohibitedFromSearch;
/** Name of freemarker template to generate form. */
String template;
/** URL to submit form to. */
String submitToUrl;
/** /**
* If true, then any dependent resources that are unlinked should be * If true, then any dependent resources that are unlinked should be
* removed using DependentResourceDelete. * removed using DependentResourceDelete.
@ -943,4 +949,20 @@ public class EditConfiguration {
public List<EditSubmissionPreprocessor> getEditSubmissionPreprocessors() { public List<EditSubmissionPreprocessor> getEditSubmissionPreprocessors() {
return editSubmissionPreprocessors; return editSubmissionPreprocessors;
} }
public void setTemplate(String template){
this.template = template;
}
public String getTemplate() {
return this.template;
}
public String getSubmitToUrl() {
return submitToUrl;
}
public void setSubmitToUrl(String submitToUrl) {
this.submitToUrl = submitToUrl;
}
} }

View file

@ -123,6 +123,7 @@ public class Field {
/* *********************** Constructors ************************** */ /* *********************** Constructors ************************** */
public Field(String config, String varName) { public Field(String config, String varName) {
name=varName;
JSONObject jsonObj = null; JSONObject jsonObj = null;
try{ try{
jsonObj = new JSONObject(config); jsonObj = new JSONObject(config);
@ -139,7 +140,7 @@ public class Field {
public Field() {} public Field() {}
private static String[] parameterNames = {"newResource","validators","optionsType","predicateUri","objectClassUri","rangeDatatypeUri","rangeLang","literalOptions","assertions"}; private static String[] parameterNames = {"editElement","newResource","validators","optionsType","predicateUri","objectClassUri","rangeDatatypeUri","rangeLang","literalOptions","assertions"};
static{ Arrays.sort(parameterNames); } static{ Arrays.sort(parameterNames); }
private void setValuesFromJson(JSONObject obj, String fieldName){ private void setValuesFromJson(JSONObject obj, String fieldName){
@ -162,6 +163,7 @@ public class Field {
setLiteralOptions(obj.getJSONArray("literalOptions")); setLiteralOptions(obj.getJSONArray("literalOptions"));
setAssertions(EditConfiguration.JsonArrayToStringList(obj.getJSONArray("assertions"))); setAssertions(EditConfiguration.JsonArrayToStringList(obj.getJSONArray("assertions")));
setEditElement( obj, fieldName);
//check for odd parameters //check for odd parameters
JSONArray names = obj.names(); JSONArray names = obj.names();
@ -178,8 +180,57 @@ public class Field {
} }
/**
* A field may specify a class for additional features.
*/
private void setEditElement(JSONObject fieldConfigObj, String fieldName) {
String className = fieldConfigObj.optString("editElement");
if( className == null || className.isEmpty() )
return;
setOptionsType(Field.OptionsType.UNDEFINED);
Class clz = null;
try {
clz = Class.forName(className);
} catch (ClassNotFoundException e) {
log.error("Java Class " + className + " not found for field " + name);
return;
} catch (SecurityException e) {
log.error("Problem with Java Class " + className + " for field " + name, e);
return;
} catch (IllegalArgumentException e) {
log.error("Problem with Java Class " +className + " for field " + name, e);
return;
}
Class[] types = new Class[]{ Field.class };
Constructor cons;
try {
cons = clz.getConstructor(types);
} catch (SecurityException e) {
log.error("Problem with Java Class " + className + " for field " + name, e);
return;
} catch (NoSuchMethodException e) {
log.error("Java Class " + className + " must have a constructor that takes a Field.", e);
return;
}
Object[] args = new Object[] { this };
Object obj;
try {
obj = cons.newInstance(args);
} catch (Exception e) {
log.error("Problem with Java Class " + className + " for field " + name, e);
return;
}
editElement = (EditElement)obj;
}
/* ****************** Getters and Setters ******************************* */ /* ****************** Getters and Setters ******************************* */
public String getName(){
return name;
}
public List<String> getRetractions() { public List<String> getRetractions() {
return retractions; return retractions;
} }
@ -217,59 +268,40 @@ public class Field {
optionsType = ot; optionsType = ot;
} }
public void setOptionsType(String s) { public void setOptionsType(String s) {
if ("LITERALS".equals(s)) { setOptionsType( getOptionForString(s));
setOptionsType(Field.OptionsType.LITERALS);
} else if ("HARDCODED_LITERALS".equals(s)) {
setOptionsType(Field.OptionsType.HARDCODED_LITERALS);
} else if ("STRINGS_VIA_DATATYPE_PROPERTY".equalsIgnoreCase(s)) {
setOptionsType(Field.OptionsType.STRINGS_VIA_DATATYPE_PROPERTY);
} else if ("INDIVIDUALS_VIA_OBJECT_PROPERTY".equalsIgnoreCase(s)) {
setOptionsType(Field.OptionsType.INDIVIDUALS_VIA_OBJECT_PROPERTY);
} else if ("INDIVIDUALS_VIA_VCLASS".equalsIgnoreCase(s)) {
setOptionsType(Field.OptionsType.INDIVIDUALS_VIA_VCLASS);
} else if ("MONIKERS_VIA_VCLASS".equalsIgnoreCase(s)) {
setOptionsType(Field.OptionsType.MONIKERS_VIA_VCLASS);
} else if ("DATETIME".equalsIgnoreCase(s)) {
setOptionsType(Field.OptionsType.DATETIME);
} else if ("CHILD_VCLASSES".equalsIgnoreCase(s)) {
setOptionsType(Field.OptionsType.CHILD_VCLASSES);
} else if ("CHILD_VCLASSES_WITH_PARENT".equalsIgnoreCase(s)) {
setOptionsType(Field.OptionsType.CHILD_VCLASSES_WITH_PARENT);
} else if ("VCLASSGROUP".equalsIgnoreCase(s)) {
setOptionsType(Field.OptionsType.VCLASSGROUP);
} else if ("FILE".equalsIgnoreCase(s)) {
setOptionsType(Field.OptionsType.FILE);
} else if ("DATE".equalsIgnoreCase(s)) {
setOptionsType(Field.OptionsType.DATE);
} else if ("TIME".equalsIgnoreCase(s)) {
setOptionsType(Field.OptionsType.TIME);
} else if ("UNDEFINED".equalsIgnoreCase(s) || s == null || s.isEmpty()){
setOptionsType(Field.OptionsType.UNDEFINED);
} else {
setSpecalOptionType(s);
}
} }
private void setSpecalOptionType(String s) { public static OptionsType getOptionForString(String s){
try { if( s== null || s.isEmpty() )
Class clz = Class.forName(s); return OptionsType.UNDEFINED;
Object obj = clz.newInstance(); if ("LITERALS".equals(s)) {
editElement = (EditElement)obj; return Field.OptionsType.LITERALS;
} catch (ClassNotFoundException e) { } else if ("HARDCODED_LITERALS".equals(s)) {
log.error("Java Class " + s + " not found for field " + name); return Field.OptionsType.HARDCODED_LITERALS;
setOptionsType(Field.OptionsType.UNDEFINED); } else if ("STRINGS_VIA_DATATYPE_PROPERTY".equalsIgnoreCase(s)) {
} catch (SecurityException e) { return Field.OptionsType.STRINGS_VIA_DATATYPE_PROPERTY;
log.error("Problem with Java Class " + s + " for field " + name, e); } else if ("INDIVIDUALS_VIA_OBJECT_PROPERTY".equalsIgnoreCase(s)) {
setOptionsType(Field.OptionsType.UNDEFINED); return Field.OptionsType.INDIVIDUALS_VIA_OBJECT_PROPERTY;
} catch (IllegalArgumentException e) { } else if ("INDIVIDUALS_VIA_VCLASS".equalsIgnoreCase(s)) {
log.error("Problem with Java Class " + s + " for field " + name, e); return Field.OptionsType.INDIVIDUALS_VIA_VCLASS;
setOptionsType(Field.OptionsType.UNDEFINED); } else if ("MONIKERS_VIA_VCLASS".equalsIgnoreCase(s)) {
} catch (InstantiationException e) { return Field.OptionsType.MONIKERS_VIA_VCLASS;
log.error("Problem with Java Class " + s + " for field " + name, e); } else if ("DATETIME".equalsIgnoreCase(s)) {
setOptionsType(Field.OptionsType.UNDEFINED); return Field.OptionsType.DATETIME;
} catch (IllegalAccessException e) { } else if ("CHILD_VCLASSES".equalsIgnoreCase(s)) {
log.error("Problem with Java Class " + s + " for field " + name, e); return Field.OptionsType.CHILD_VCLASSES;
setOptionsType(Field.OptionsType.UNDEFINED); } else if ("CHILD_VCLASSES_WITH_PARENT".equalsIgnoreCase(s)) {
return Field.OptionsType.CHILD_VCLASSES_WITH_PARENT;
} else if ("VCLASSGROUP".equalsIgnoreCase(s)) {
return Field.OptionsType.VCLASSGROUP;
} else if ("FILE".equalsIgnoreCase(s)) {
return Field.OptionsType.FILE;
} else if ("DATE".equalsIgnoreCase(s)) {
return Field.OptionsType.DATE;
} else if ("TIME".equalsIgnoreCase(s)) {
return Field.OptionsType.TIME;
} else {
return Field.OptionsType.UNDEFINED;
} }
} }
@ -365,4 +397,9 @@ public class Field {
return editElement; return editElement;
} }
/* this is mainly for unit testing */
public void setName(String name){
this.name = name;
}
} }

View file

@ -0,0 +1,59 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.web.widgets;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory;
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.EditConfiguration;
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.SelectListGenerator;
import edu.cornell.mannlib.vitro.webapp.web.directives.WidgetDirective;
import freemarker.core.Environment;
import freemarker.template.SimpleScalar;
public class SelectListWidget extends Widget {
private static final Log log = LogFactory.getLog(SelectListWidget.class);
@Override
protected WidgetTemplateValues process(Environment env, Map params,
HttpServletRequest request, ServletContext context) {
Object obj = params.get("fieldName");
if( obj == null || !(obj instanceof SimpleScalar)){
log.error("SelectListWidget must have a parameter 'fieldName'");
throw new Error("SelectListWidget must have a parameter'fieldName'");
}
String fieldName = ((SimpleScalar)obj).getAsString();
if( fieldName.isEmpty() ){
log.error("SelectListWidget must have a parameter 'fieldName'");
throw new Error("SelectListWidget must have a parameter 'fieldName' of type String");
}
VitroRequest vreq = new VitroRequest(request);
HttpSession session = request.getSession(false);
EditConfiguration editConfig = EditConfiguration.getConfigFromSession(session,request);
WebappDaoFactory wdf;
if (editConfig != null) {
wdf = editConfig.getWdfSelectorForOptons().getWdf(vreq,context);
} else {
wdf = vreq.getWebappDaoFactory();
}
Map<String,String> selectOptions = SelectListGenerator.getOptions(editConfig, fieldName, wdf);
Map<String,Object> rmap = new HashMap<String,Object>();
rmap.put("selectList", selectOptions);
return new WidgetTemplateValues("markup", rmap);
}
}

View file

@ -0,0 +1,114 @@
<%-- $This file is distributed under the terms of the license in /doc/license.txt$ --%>
<%--
This is a test file for the DateTimeWithPrecision EditElement.
--%>
<%@ page import="com.hp.hpl.jena.rdf.model.Model" %>
<%@ page import="edu.cornell.mannlib.vitro.webapp.beans.Individual" %>
<%@ page import="edu.cornell.mannlib.vitro.webapp.beans.DataProperty" %>
<%@ page import="edu.cornell.mannlib.vitro.webapp.beans.DataPropertyStatement" %>
<%@ page import="edu.cornell.mannlib.vitro.webapp.controller.VitroRequest"%>
<%@ page import="java.util.HashMap"%>
<%@ page import="edu.cornell.mannlib.vitro.webapp.beans.ObjectProperty"%>
<%@ page import="edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory"%>
<%@ page import="edu.cornell.mannlib.vitro.webapp.edit.n3editing.EditConfiguration" %>
<%@ page import="edu.cornell.mannlib.vitro.webapp.web.MiscWebUtils"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %>
<%@ taglib prefix="v" uri="http://vitro.mannlib.cornell.edu/vitro/tags" %>
<%
org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger("edu.cornell.mannlib.vitro.jsp.edit.forms.test.dateTimePrecTest.jsp");
log.debug("Starting dateTimePrecTest.jsp");
%>
<%
Individual subject = (Individual)request.getAttribute("subject");
VitroRequest vreq = new VitroRequest(request);
WebappDaoFactory wdf = vreq.getWebappDaoFactory();
%>
<v:jsonset var="n3ForEdit" >
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix vivo: <http://vivo.library.cornell.edu/ns/0.1#> .
@prefix vitro: <http://vitro.mannlib.cornell.edu/ns/vitro/0.7#> .
@prefix core: <http://vivoweb.org/ontology/core#> .
?subject ?predicate ?object .
?object <core:hasDateTimeValue> ?dtX.
?dtX <rdf:type> <core:DateTimeValue> .
?dtX <core:dateTime> ?dtX.value .
?dtX <core:dateTimePrecision> ?dtX.precision .
</v:jsonset>
<c:set var="editjson" scope="request">
{
"formUrl" : "${formUrl}",
"editKey" : "${editKey}",
"urlPatternToReturnTo" : "/individual",
"subject" : [ "subject", "${subjectUriJson}" ],
"predicate" : [ "predicate", "${predicateUriJson}" ],
"object" : [ "object", "${objectUriJson}", "URI" ],
"n3required" : [ "${n3ForEdit}" ],
"n3optional" : [ ],
"newResources" : { "dtX" : "", "object" : "" },
"urisInScope" : { },
"literalsInScope" : { },
"urisOnForm" : [ ],
"literalsOnForm" : [ ],
"filesOnForm" : [ ],
"sparqlForLiterals" : { },
"sparqlForUris" : { },
"sparqlForExistingLiterals" : { },
"sparqlForExistingUris" : { },
"fields" : {
"dtX" : {
"newResource" : "true",
"validators" : [ ],
"optionsType" : "edu.cornell.mannlib.vitro.webapp.edit.elements.DateTimeWithPrecision",
"literalOptions" : [ ],
"predicateUri" : "",
"objectClassUri" : "",
"rangeDatatypeUri" : "",
"rangeLang" : "",
"assertions" : [ "${n3ForEdit}" ]
}
}
}
</c:set>
<%
EditConfiguration editConfig = EditConfiguration.getConfigFromSession(session,request);
if( editConfig == null ){
editConfig = new EditConfiguration((String)request.getAttribute("editjson"));
EditConfiguration.putConfigInSession(editConfig, session);
}
Model model = (Model)application.getAttribute("jenaOntModel");
String objectUri = (String)request.getAttribute("objectUri");
if( objectUri != null ){
editConfig.prepareForObjPropUpdate(model);
}else{
editConfig.prepareForNonUpdate(model);
}
/* title is used by pre and post form fragments */
request.setAttribute("title", "Edit dateTimePrec entry for " + subject.getName());
%>
<jsp:include page="${preForm}">
<jsp:param name="useTinyMCE" value="false"/>
</jsp:include>
<h2>${title}</h2>
<form action="<c:url value="/edit/processRdfForm2.jsp"/>" >
<v:input id="dtX" />
<v:input type="submit" id="submit" value="submit" cancel="true"/>
</form>
<jsp:include page="${postForm}"/>

View file

@ -0,0 +1,17 @@
<#-- $This file is distributed under the terms of the license in /doc/license.txt$ -->
<#-- SelecListWidget -->
<#macro assets>
<#--
${stylesheets.add("/css/something.css")}
${scripts.add("/js/somejavascript.js")}
-->
</#macro>
<#macro markup>
<#assign keys = selectList?keys>
<#list keys as key>
<option value="${key}" >${selectList[key]}</option>
</#list>
</#macro>