diff --git a/config/alfresco/web-client-application-context.xml b/config/alfresco/web-client-application-context.xml
index 1a3c05c9b8..30cf4245b2 100644
--- a/config/alfresco/web-client-application-context.xml
+++ b/config/alfresco/web-client-application-context.xml
@@ -42,12 +42,6 @@
-
-
-
-
-
-
diff --git a/source/java/org/alfresco/web/app/servlet/ajax/InvokeCommand.java b/source/java/org/alfresco/web/app/servlet/ajax/InvokeCommand.java
index b5da969d0a..ea3f979a2b 100644
--- a/source/java/org/alfresco/web/app/servlet/ajax/InvokeCommand.java
+++ b/source/java/org/alfresco/web/app/servlet/ajax/InvokeCommand.java
@@ -16,6 +16,9 @@
*/
package org.alfresco.web.app.servlet.ajax;
+import java.lang.annotation.*;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
@@ -25,7 +28,7 @@ import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import javax.faces.el.EvaluationException;
-import javax.faces.el.MethodBinding;
+import javax.faces.el.VariableResolver;
import javax.faces.render.RenderKit;
import javax.faces.render.RenderKitFactory;
import javax.servlet.ServletException;
@@ -51,59 +54,68 @@ import org.alfresco.web.bean.repository.Repository;
*/
public class InvokeCommand extends BaseAjaxCommand
{
- public void execute(final FacesContext facesContext,
- final String expression,
- final HttpServletRequest request,
- final HttpServletResponse response)
- throws ServletException, IOException
- {
- // setup the JSF response writer.
-
- // NOTE: it doesn't seem to matter what the content type of the response is (at least with Dojo),
- // it determines it's behaviour from the mimetype specified in the AJAX call on the client,
- // therefore, for now we will always return a content type of text/xml.
- // In the future we may use annotations on the method to be called to specify what content
- // type should be used for the response.
- // NOTE: JSF only seems to support XML and HTML content types by default so this will
- // also need to be addressed if other content types need to be returned i.e. JSON.
-
- OutputStream os = response.getOutputStream();
- UIViewRoot viewRoot = facesContext.getViewRoot();
- RenderKitFactory renderFactory = (RenderKitFactory)FactoryFinder.
- getFactory(FactoryFinder.RENDER_KIT_FACTORY);
- RenderKit renderKit = renderFactory.getRenderKit(facesContext,
- viewRoot.getRenderKitId());
- ResponseWriter writer = renderKit.createResponseWriter(
- new OutputStreamWriter(os), MimetypeMap.MIMETYPE_XML, "UTF-8");
- facesContext.setResponseWriter(writer);
- // must be text/xml otherwise IE doesn't parse the response properly into responseXML
- response.setContentType(MimetypeMap.MIMETYPE_XML);
- // create the JSF binding expression
- String bindingExpr = makeBindingExpression(expression);
-
- if (logger.isDebugEnabled())
- logger.debug("Invoking method represented by " + bindingExpr);
-
+ /////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Annotation for a bean method that handles an ajax request.
+ */
+ @Retention(RetentionPolicy.RUNTIME)
+ @Target(ElementType.METHOD)
+ public @interface ResponseMimetype
+ {
+ public String value() default MimetypeMap.MIMETYPE_XML;
+ }
+
+ /////////////////////////////////////////////////////////////////////////////
+
+ public void execute(final FacesContext facesContext,
+ final String expression,
+ final HttpServletRequest request,
+ final HttpServletResponse response)
+ throws ServletException, IOException
+ {
+
+
UserTransaction tx = null;
+ ResponseWriter writer = null;
try
{
- // create the method binding from the expression
- MethodBinding binding = facesContext.getApplication().createMethodBinding(
- bindingExpr, new Class[] {});
+ final VariableResolver vr = facesContext.getApplication().getVariableResolver();
+
+ final int indexOfDot = expression.indexOf('.');
+ final String variableName = expression.substring(0, indexOfDot);
+ final String methodName = expression.substring(indexOfDot + 1);
+
+ if (logger.isDebugEnabled())
+ logger.debug("Invoking method represented by " + expression +
+ " on variable " + variableName +
+ " with method " + methodName);
+
+ final Object bean = vr.resolveVariable(facesContext, variableName);
+ final Method method = bean.getClass().getMethod(methodName);
+
+ final String responseMimetype =
+ (method.isAnnotationPresent(ResponseMimetype.class)
+ ? method.getAnnotation(ResponseMimetype.class).value()
+ : MimetypeMap.MIMETYPE_XML);
+
+ if (logger.isDebugEnabled())
+ logger.debug("invoking method " + method +
+ " with repsonse mimetype " + responseMimetype);
+ writer = this.setupResponseWriter(responseMimetype,
+ response,
+ facesContext);
+
+ // setup the transaction
+ tx = Repository.getUserTransaction(facesContext);
+ tx.begin();
- if (binding != null)
- {
- // setup the transaction
- tx = Repository.getUserTransaction(facesContext);
- tx.begin();
-
- // invoke the method
- binding.invoke(facesContext, new Object[] {});
-
- // commit
- tx.commit();
- }
+ // invoke the method
+ method.invoke(bean);
+
+ // commit
+ tx.commit();
}
catch (Throwable err)
{
@@ -118,6 +130,14 @@ public class InvokeCommand extends BaseAjaxCommand
err = cause;
}
}
+ else if (err instanceof InvocationTargetException)
+ {
+ final Throwable cause = ((InvocationTargetException)err).getCause();
+ if (cause != null)
+ {
+ err = cause;
+ }
+ }
logger.error(err);
throw new AlfrescoRuntimeException("Failed to execute method " + expression +
@@ -127,4 +147,26 @@ public class InvokeCommand extends BaseAjaxCommand
// force the output back to the client
writer.close();
}
+
+ /** setup the JSF response writer. */
+ private ResponseWriter setupResponseWriter(final String mimetype,
+ final HttpServletResponse response,
+ final FacesContext facesContext)
+ throws IOException
+ {
+ final OutputStream os = response.getOutputStream();
+ final UIViewRoot viewRoot = facesContext.getViewRoot();
+ final RenderKitFactory renderFactory = (RenderKitFactory)
+ FactoryFinder.getFactory(FactoryFinder.RENDER_KIT_FACTORY);
+ final RenderKit renderKit =
+ renderFactory.getRenderKit(facesContext, viewRoot.getRenderKitId());
+ final ResponseWriter writer =
+ renderKit.createResponseWriter(new OutputStreamWriter(os),
+ mimetype,
+ "UTF-8");
+ facesContext.setResponseWriter(writer);
+ // must be text/xml otherwise IE doesn't parse the response properly into responseXML
+ response.setContentType(mimetype);
+ return writer;
+ }
}
diff --git a/source/java/org/alfresco/web/bean/wcm/AVMEditBean.java b/source/java/org/alfresco/web/bean/wcm/AVMEditBean.java
index 719f77fec8..b4bed422a0 100644
--- a/source/java/org/alfresco/web/bean/wcm/AVMEditBean.java
+++ b/source/java/org/alfresco/web/bean/wcm/AVMEditBean.java
@@ -233,7 +233,7 @@ public class AVMEditBean
{
private final FormsService ts = FormsService.getInstance();
- public Document getContent()
+ public Document load()
{
try
{
@@ -247,7 +247,8 @@ public class AVMEditBean
}
}
- public void setContent(final Document d)
+ public void save(final Document d,
+ final String[] uploadedFilePaths)
{
AVMEditBean.this.setEditorOutput(this.ts.writeXMLToString(d));
}
diff --git a/source/java/org/alfresco/web/bean/wcm/CreateWebContentWizard.java b/source/java/org/alfresco/web/bean/wcm/CreateWebContentWizard.java
index c9a78adc85..190f46962e 100644
--- a/source/java/org/alfresco/web/bean/wcm/CreateWebContentWizard.java
+++ b/source/java/org/alfresco/web/bean/wcm/CreateWebContentWizard.java
@@ -84,6 +84,7 @@ public class CreateWebContentWizard extends BaseContentWizard
protected FormInstanceData formInstanceData = null;
protected boolean formSelectDisabled = false;
protected boolean startWorkflow = false;
+ protected String[] uploadedFilePaths = null;
/** AVM service bean reference */
protected AVMService avmService;
@@ -144,6 +145,7 @@ public class CreateWebContentWizard extends BaseContentWizard
this.formName = null;
this.mimeType = MimetypeMap.MIMETYPE_XML;
this.formInstanceData = null;
+ this.uploadedFilePaths = null;
this.renditions = null;
this.startWorkflow = false;
@@ -161,6 +163,14 @@ public class CreateWebContentWizard extends BaseContentWizard
this.formSelectDisabled = true;
}
}
+
+ // reset the preview layer
+ String path = this.avmBrowseBean.getCurrentPath();
+ path = path.replaceFirst(AVMConstants.STORE_MAIN, AVMConstants.STORE_PREVIEW);
+ path = path.split(":")[0] + ":/" + AVMConstants.DIR_APPBASE;
+ if (LOGGER.isDebugEnabled())
+ LOGGER.debug("reseting layer " + path);
+ this.avmSyncService.resetLayer(path);
}
@Override
@@ -190,6 +200,7 @@ public class CreateWebContentWizard extends BaseContentWizard
{
LOGGER.debug("clearing form instance data");
this.formInstanceData = null;
+ this.uploadedFilePaths = null;
this.renditions = null;
}
return super.back();
@@ -231,6 +242,23 @@ public class CreateWebContentWizard extends BaseContentWizard
AVMConstants.STORE_MAIN),
AVMDifference.NEWER));
}
+
+ for (String path : this.uploadedFilePaths)
+ {
+ diffList.add(new AVMDifference(-1, path,
+ -1, path.replaceFirst(AVMConstants.STORE_PREVIEW,
+ AVMConstants.STORE_MAIN),
+ AVMDifference.NEWER));
+ }
+
+ if (LOGGER.isDebugEnabled())
+ {
+ for (AVMDifference diff : diffList)
+ {
+ LOGGER.debug("updating " + AVMConstants.STORE_MAIN +
+ " with " + diff.getSourcePath());
+ }
+ }
this.avmSyncService.update(diffList, null, true, true, true, true, null, null);
// reset all paths and structures to the main store
@@ -411,11 +439,6 @@ public class CreateWebContentWizard extends BaseContentWizard
fileName = sb[1];
}
- if (LOGGER.isDebugEnabled())
- LOGGER.debug("reseting layer " + path.split(":")[0] + ":/" + AVMConstants.DIR_APPBASE);
-
- this.avmSyncService.resetLayer(path.split(":")[0] + ":/" + AVMConstants.DIR_APPBASE);
-
if (LOGGER.isDebugEnabled())
LOGGER.debug("creating all directories in path " + path);
@@ -577,7 +600,7 @@ public class CreateWebContentWizard extends BaseContentWizard
{
private final FormsService ts = FormsService.getInstance();
- public Document getContent()
+ public Document load()
{
try
{
@@ -591,9 +614,11 @@ public class CreateWebContentWizard extends BaseContentWizard
}
}
- public void setContent(final Document d)
+ public void save(final Document d,
+ final String[] uploadedFilePaths)
{
CreateWebContentWizard.this.setContent(ts.writeXMLToString(d));
+ CreateWebContentWizard.this.uploadedFilePaths = uploadedFilePaths;
}
};
}
diff --git a/source/java/org/alfresco/web/forms/FormProcessor.java b/source/java/org/alfresco/web/forms/FormProcessor.java
index 25861d2c14..aa92b49a07 100644
--- a/source/java/org/alfresco/web/forms/FormProcessor.java
+++ b/source/java/org/alfresco/web/forms/FormProcessor.java
@@ -35,9 +35,11 @@ public interface FormProcessor
*/
public interface InstanceData
{
- public Document getContent();
-
- public void setContent(final Document d);
+
+ public Document load();
+
+ public void save(final Document d,
+ final String[] uploadedFilePaths);
}
/////////////////////////////////////////////////////////////////////////////
diff --git a/source/java/org/alfresco/web/forms/FormsService.java b/source/java/org/alfresco/web/forms/FormsService.java
index f16dcd5d18..e39d8b755d 100644
--- a/source/java/org/alfresco/web/forms/FormsService.java
+++ b/source/java/org/alfresco/web/forms/FormsService.java
@@ -89,9 +89,6 @@ public final class FormsService
private static FormsService INSTANCE;
private static DocumentBuilder documentBuilder;
- /** internal storage of forms, keyed by the form name */
- private HashMap forms = new HashMap();
-
private static final RenderingEngine[] RENDERING_ENGINES = new RenderingEngine[]
{
new FreeMarkerRenderingEngine(),
@@ -101,8 +98,6 @@ public final class FormsService
private final ContentService contentService;
private final NodeService nodeService;
- private final FileFolderService fileFolderService;
- private final DictionaryService dictionaryService;
private final NamespaceService namespaceService;
private final SearchService searchService;
private final AVMService avmService;
@@ -112,16 +107,12 @@ public final class FormsService
/** instantiated using spring */
public FormsService(final ContentService contentService,
final NodeService nodeService,
- final FileFolderService fileFolderService,
- final DictionaryService dictionaryService,
final NamespaceService namespaceService,
final SearchService searchService,
final AVMService avmService)
{
this.contentService = contentService;
this.nodeService = nodeService;
- this.fileFolderService = fileFolderService;
- this.dictionaryService = dictionaryService;
this.namespaceService = namespaceService;
this.searchService = searchService;
this.avmService = avmService;
diff --git a/source/java/org/alfresco/web/forms/RenderingEngine.java b/source/java/org/alfresco/web/forms/RenderingEngine.java
index 922fa1d901..9797ca8524 100644
--- a/source/java/org/alfresco/web/forms/RenderingEngine.java
+++ b/source/java/org/alfresco/web/forms/RenderingEngine.java
@@ -37,6 +37,11 @@ public interface RenderingEngine
extends Exception
{
+ public RenderingException(final String msg)
+ {
+ super(msg);
+ }
+
public RenderingException(final Exception cause)
{
super(cause);
diff --git a/source/java/org/alfresco/web/forms/XSLFORenderingEngine.java b/source/java/org/alfresco/web/forms/XSLFORenderingEngine.java
index ff19168eeb..05e4738657 100644
--- a/source/java/org/alfresco/web/forms/XSLFORenderingEngine.java
+++ b/source/java/org/alfresco/web/forms/XSLFORenderingEngine.java
@@ -22,9 +22,6 @@ import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.sax.SAXResult;
-import org.alfresco.service.cmr.repository.ContentService;
-import org.alfresco.service.cmr.repository.NodeRef;
-import org.alfresco.service.cmr.repository.NodeService;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.w3c.dom.*;
@@ -33,9 +30,7 @@ import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.apps.Fop;
import org.apache.fop.apps.FOPException;
import org.apache.fop.apps.FopFactory;
-import org.apache.fop.apps.FormattingResults;
import org.apache.fop.apps.MimeConstants;
-import org.apache.fop.apps.PageSequenceResults;
/**
* A rendering engine which uses xsl-fo templates to generate renditions of
@@ -49,6 +44,33 @@ public class XSLFORenderingEngine
private static final Log LOGGER = LogFactory.getLog(XSLFORenderingEngine.class);
+ private static final Map MIME_TYPES =
+ new HashMap();
+ static
+ {
+ MIME_TYPES.put(MimeConstants.MIME_PDF, MimeConstants.MIME_PDF);
+
+ MIME_TYPES.put(MimeConstants.MIME_POSTSCRIPT, MimeConstants.MIME_POSTSCRIPT);
+ MIME_TYPES.put(MimeConstants.MIME_EPS, MimeConstants.MIME_POSTSCRIPT);
+
+ MIME_TYPES.put(MimeConstants.MIME_PLAIN_TEXT, MimeConstants.MIME_PLAIN_TEXT);
+
+ MIME_TYPES.put(MimeConstants.MIME_RTF, MimeConstants.MIME_RTF);
+ MIME_TYPES.put(MimeConstants.MIME_RTF_ALT1, MimeConstants.MIME_RTF);
+ MIME_TYPES.put(MimeConstants.MIME_RTF_ALT2, MimeConstants.MIME_RTF);
+
+ MIME_TYPES.put(MimeConstants.MIME_MIF, MimeConstants.MIME_MIF);
+ MIME_TYPES.put("application/x-mif", MimeConstants.MIME_MIF);
+
+ MIME_TYPES.put(MimeConstants.MIME_SVG, MimeConstants.MIME_SVG);
+ MIME_TYPES.put("image/svg", MimeConstants.MIME_SVG);
+
+ MIME_TYPES.put(MimeConstants.MIME_GIF, MimeConstants.MIME_GIF);
+ MIME_TYPES.put(MimeConstants.MIME_PNG, MimeConstants.MIME_PNG);
+ MIME_TYPES.put(MimeConstants.MIME_JPEG, MimeConstants.MIME_JPEG);
+ MIME_TYPES.put(MimeConstants.MIME_TIFF, MimeConstants.MIME_TIFF);
+ };
+
public XSLFORenderingEngine()
{
super();
@@ -72,16 +94,21 @@ public class XSLFORenderingEngine
RenderingEngine.RenderingException
{
Result result = null;
+ String mimetype = MIME_TYPES.get(ret.getMimetypeForRendition());
+ if (mimetype == null)
+ {
+ throw new RenderingEngine.RenderingException("mimetype " + ret.getMimetypeForRendition() +
+ " is not supported by " + this.getName());
+ }
try
{
final FopFactory fopFactory = FopFactory.newInstance();
final FOUserAgent foUserAgent = fopFactory.newFOUserAgent();
- final Fop fop = fopFactory.newFop(ret.getMimetypeForRendition(),
+ final Fop fop = fopFactory.newFop(mimetype,
foUserAgent,
out);
// Resulting SAX events (the generated FO) must be piped through to FOP
result = new SAXResult(fop.getDefaultHandler());
-
}
catch (FOPException fope)
{
diff --git a/source/java/org/alfresco/web/forms/xforms/SchemaFormBuilder.java b/source/java/org/alfresco/web/forms/xforms/SchemaFormBuilder.java
index 56dcde1a50..da0b8820ed 100644
--- a/source/java/org/alfresco/web/forms/xforms/SchemaFormBuilder.java
+++ b/source/java/org/alfresco/web/forms/xforms/SchemaFormBuilder.java
@@ -390,7 +390,6 @@ public class SchemaFormBuilder
formContentWrapper,
schema,
rootElementDecl,
- rootElementDecl.getTypeDefinition(),
"/" + getElementName(rootElementDecl, xForm));
if (importedInstanceDocumentElement != null)
{
@@ -1058,9 +1057,9 @@ public class SchemaFormBuilder
final Element formSection,
final XSModel schema,
final XSElementDeclaration elementDecl,
- XSTypeDefinition controlType,
- final String pathToRoot) {
-
+ final String pathToRoot)
+ {
+ XSTypeDefinition controlType = elementDecl.getTypeDefinition();
if (controlType == null)
{
// TODO!!! Figure out why this happens... for now just warn...
@@ -1664,7 +1663,6 @@ public class SchemaFormBuilder
repeatContentWrapper,
schema,
element,
- element.getTypeDefinition(),
path);
final SchemaUtil.Occurance elementOccurs = SchemaUtil.getOccurance(element);
diff --git a/source/java/org/alfresco/web/forms/xforms/XFormsBean.java b/source/java/org/alfresco/web/forms/xforms/XFormsBean.java
index ca94279ab3..a56a62c04e 100644
--- a/source/java/org/alfresco/web/forms/xforms/XFormsBean.java
+++ b/source/java/org/alfresco/web/forms/xforms/XFormsBean.java
@@ -16,50 +16,51 @@
*/
package org.alfresco.web.forms.xforms;
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.util.Collection;
-import java.util.Map;
-import java.util.HashMap;
-import java.util.LinkedList;
-
+import java.io.*;
+import java.util.*;
+import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
-import javax.faces.context.ExternalContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
import org.alfresco.repo.avm.AVMNodeConverter;
+import org.alfresco.repo.content.MimetypeMap;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.avm.AVMNodeDescriptor;
import org.alfresco.service.cmr.avm.AVMService;
-import org.alfresco.web.bean.wcm.AVMConstants;
-import org.alfresco.web.forms.*;
-import org.w3c.dom.Document;
-import org.w3c.dom.Node;
+import org.alfresco.util.TempFileProvider;
+import org.alfresco.web.app.Application;
import org.alfresco.web.app.servlet.FacesHelper;
+import org.alfresco.web.app.servlet.ajax.InvokeCommand;
+import org.alfresco.web.bean.FileUploadBean;
import org.alfresco.web.bean.repository.Repository;
import org.alfresco.web.bean.wcm.AVMBrowseBean;
+import org.alfresco.web.bean.wcm.AVMConstants;
+import org.alfresco.web.forms.*;
import org.alfresco.web.ui.common.Utils;
+import org.apache.commons.fileupload.FileItem;
+import org.apache.commons.fileupload.disk.DiskFileItemFactory;
+import org.apache.commons.fileupload.servlet.ServletFileUpload;
+import org.apache.commons.fileupload.servlet.ServletRequestContext;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
import org.chiba.xml.xforms.ChibaBean;
import org.chiba.xml.xforms.Instance;
import org.chiba.xml.xforms.XFormsElement;
import org.chiba.xml.xforms.connector.http.AbstractHTTPConnector;
import org.chiba.xml.xforms.core.ModelItem;
-import org.chiba.xml.xforms.exception.XFormsException;
import org.chiba.xml.xforms.events.XFormsEvent;
import org.chiba.xml.xforms.events.XFormsEventFactory;
+import org.chiba.xml.xforms.exception.XFormsException;
import org.chiba.xml.xforms.ui.BoundElement;
import org.chiba.xml.xforms.ui.Upload;
-
+import org.springframework.util.FileCopyUtils;
import org.w3c.dom.*;
import org.w3c.dom.bootstrap.DOMImplementationRegistry;
-import org.w3c.dom.ls.*;
import org.w3c.dom.events.Event;
import org.w3c.dom.events.EventListener;
import org.w3c.dom.events.EventTarget;
+import org.w3c.dom.ls.*;
import org.xml.sax.SAXException;
/**
@@ -72,9 +73,10 @@ public class XFormsBean
private Form form;
private FormProcessor.InstanceData instanceData = null;
- private ChibaBean chibaBean;
+ private final ChibaBean chibaBean = new ChibaBean();
private SchemaFormBuilder schemaFormBuilder = null;
- private final LinkedList eventLog = new LinkedList();
+ private final HashMap uploads = new HashMap();
+ private final List eventLog = new LinkedList();
/** @return the form */
public Form getForm()
@@ -105,7 +107,6 @@ public class XFormsBean
{
LOGGER.debug("initializing " + this + " with form " + this.form.getName());
}
- this.chibaBean = new ChibaBean();
final FacesContext facesContext = FacesContext.getCurrentInstance();
final ExternalContext externalContext = facesContext.getExternalContext();
final HttpServletRequest request = (HttpServletRequest)
@@ -139,7 +140,7 @@ public class XFormsBean
final Document schemaDocument = this.form.getSchema();
this.rewriteInlineURIs(schemaDocument, cwdAVMPath);
final Document xformsDocument =
- this.schemaFormBuilder.buildXForm(instanceData.getContent(),
+ this.schemaFormBuilder.buildXForm(instanceData.load(),
schemaDocument,
this.form.getSchemaRootElementName());
@@ -290,20 +291,29 @@ public class XFormsBean
* handles submits and sets the instance data.
*/
public void handleAction()
- throws Exception
{
LOGGER.debug(this + ".handleAction");
- final FacesContext context = FacesContext.getCurrentInstance();
- final HttpServletRequest request = (HttpServletRequest)
- context.getExternalContext().getRequest();
- final FormsService formsService = FormsService.getInstance();
- final Document result = formsService.parseXML(request.getInputStream());
- this.schemaFormBuilder.removePrototypeNodes(result.getDocumentElement());
- this.instanceData.setContent(result);
+ try
+ {
+ final FacesContext context = FacesContext.getCurrentInstance();
+ final HttpServletRequest request = (HttpServletRequest)
+ context.getExternalContext().getRequest();
+ final FormsService formsService = FormsService.getInstance();
+ final Document result = formsService.parseXML(request.getInputStream());
+ this.schemaFormBuilder.removePrototypeNodes(result.getDocumentElement());
- final ResponseWriter out = context.getResponseWriter();
- formsService.writeXML(result, out);
- out.close();
+ final String[] uploadedFilePaths = (String[])
+ this.uploads.values().toArray(new String[0]);
+ this.instanceData.save(result, uploadedFilePaths);
+
+ final ResponseWriter out = context.getResponseWriter();
+ formsService.writeXML(result, out);
+ out.close();
+ }
+ catch (Throwable t)
+ {
+ LOGGER.error(t);
+ }
}
/**
@@ -329,6 +339,7 @@ public class XFormsBean
/**
* Provides data for a file picker widget.
*/
+ @InvokeCommand.ResponseMimetype(value=MimetypeMap.MIMETYPE_XML)
public void getFilePickerData()
throws Exception
{
@@ -347,7 +358,10 @@ public class XFormsBean
}
else
{
- currentPath = AVMConstants.buildAbsoluteAVMPath(browseBean.getCurrentPath(),
+ final String previewStorePath =
+ browseBean.getCurrentPath().replaceFirst(AVMConstants.STORE_MAIN,
+ AVMConstants.STORE_PREVIEW);
+ currentPath = AVMConstants.buildAbsoluteAVMPath(previewStorePath,
currentPath);
}
LOGGER.debug(this + ".getFilePickerData(" + currentPath + ")");
@@ -403,6 +417,94 @@ public class XFormsBean
FormsService.getInstance().writeXML(result, out);
out.close();
}
+
+ @InvokeCommand.ResponseMimetype(value=MimetypeMap.MIMETYPE_HTML)
+ public void uploadFile()
+ throws Exception
+ {
+ LOGGER.debug(this + ".uploadFile()");
+ final FacesContext facesContext = FacesContext.getCurrentInstance();
+ final ExternalContext externalContext = facesContext.getExternalContext();
+ final HttpServletRequest request = (HttpServletRequest)
+ externalContext.getRequest();
+ final HttpSession session = (HttpSession)
+ externalContext.getSession(true);
+ final AVMBrowseBean browseBean = (AVMBrowseBean)
+ session.getAttribute("AVMBrowseBean");
+
+ final ServletFileUpload upload =
+ new ServletFileUpload(new DiskFileItemFactory());
+ upload.setHeaderEncoding("UTF-8");
+ final List fileItems = upload.parseRequest(request);
+ final FileUploadBean bean = new FileUploadBean();
+ String uploadId = null;
+ String currentPath = null;
+ String filename = null;
+ InputStream fileInputStream = null;
+ for (FileItem item : fileItems)
+ {
+ LOGGER.debug("item = " + item);
+ if (item.isFormField() && item.getFieldName().equals("id"))
+ {
+ uploadId = item.getString();
+ LOGGER.debug("uploadId is " + uploadId);
+ }
+ else if (item.isFormField() && item.getFieldName().equals("currentPath"))
+ {
+ final String previewStorePath =
+ browseBean.getCurrentPath().replaceFirst(AVMConstants.STORE_MAIN,
+ AVMConstants.STORE_PREVIEW);
+ currentPath = AVMConstants.buildAbsoluteAVMPath(previewStorePath,
+ item.getString());
+ LOGGER.debug("currentPath is " + currentPath);
+ }
+ else
+ {
+ filename = item.getName();
+ int idx = filename.lastIndexOf('\\');
+ if (idx == -1)
+ {
+ idx = filename.lastIndexOf('/');
+ }
+ if (idx != -1)
+ {
+ filename = filename.substring(idx + File.separator.length());
+ }
+ fileInputStream = item.getInputStream();
+ LOGGER.debug("parsed file " + filename);
+ }
+ }
+
+ final ServiceRegistry serviceRegistry =
+ Repository.getServiceRegistry(facesContext);
+ final AVMService avmService = serviceRegistry.getAVMService();
+ LOGGER.debug("saving file " + filename + " to " + currentPath);
+
+ FileCopyUtils.copy(fileInputStream,
+ avmService.createFile(currentPath, filename));
+
+ this.uploads.put(uploadId, currentPath + "/" + filename);
+
+ LOGGER.debug("upload complete. sending response");
+ final FormsService formsService = FormsService.getInstance();
+ final Document result = formsService.newDocument();
+ final Element htmlEl = result.createElement("html");
+ result.appendChild(htmlEl);
+ final Element bodyEl = result.createElement("body");
+ htmlEl.appendChild(bodyEl);
+
+ final Element scriptEl = result.createElement("script");
+ bodyEl.appendChild(scriptEl);
+ scriptEl.setAttribute("type", "text/javascript");
+ final Node scriptText =
+ result.createTextNode("window.parent.FilePickerWidget." +
+ "_upload_completeHandler('" + uploadId + "');");
+ scriptEl.appendChild(scriptText);
+
+ final ResponseWriter out = facesContext.getResponseWriter();
+ formsService.writeXML(result, out);
+ out.close();
+ }
private void swapRepeatItems(final XFormsElement from,
final XFormsElement to)
diff --git a/source/test-resources/xforms/unit-tests/simple-test/components-test.xsd b/source/test-resources/xforms/unit-tests/simple-test/components-test.xsd
index f8ad82d964..f193e1e0ad 100644
--- a/source/test-resources/xforms/unit-tests/simple-test/components-test.xsd
+++ b/source/test-resources/xforms/unit-tests/simple-test/components-test.xsd
@@ -2,9 +2,9 @@
-
+
-
+
1 - eno
@@ -55,8 +55,8 @@
-
-
+
+
diff --git a/source/web/scripts/ajax/xforms.js b/source/web/scripts/ajax/xforms.js
index c0955f3f41..3eaf9a182d 100644
--- a/source/web/scripts/ajax/xforms.js
+++ b/source/web/scripts/ajax/xforms.js
@@ -237,8 +237,10 @@ dojo.declare("alfresco.xforms.FilePicker",
render: function(attach_point)
{
this.domNode = document.createElement("div");
+ attach_point.appendChild(this.domNode);
this.domNode.setAttribute("id", this.id + "-widget");
this.domNode.style.width = "100%";
+
this.domNode.widget = this;
this.domNode.addEventListener("heightChanged",
function(event)
@@ -247,7 +249,6 @@ dojo.declare("alfresco.xforms.FilePicker",
event.target.offsetHeight + "px";
},
false);
- attach_point.appendChild(this.domNode);
//XXXarielb support readonly and disabled
this.widget = new FilePickerWidget(this.domNode, this.getInitialValue(), false);
this.widget.render();
@@ -1853,14 +1854,18 @@ function _findElementById(node, id)
// " in " + (node ? node.nodeName : null) +
// "(" + (node ? node.getAttribute("id") : null) + ")");
if (node.getAttribute("id") == id)
+ {
return node;
+ }
for (var i = 0; i < node.childNodes.length; i++)
{
if (node.childNodes[i].nodeType == dojo.dom.ELEMENT_NODE)
{
var n = _findElementById(node.childNodes[i], id);
if (n)
+ {
return n;
+ }
}
}
return null;
@@ -1875,8 +1880,7 @@ function create_ajax_request(target, serverMethod, methodArgs, load, error)
result.load = load;
dojo.event.connect(result, "load", function(type, data, evt)
{
-// _hide_errors();
- ajax_request_load_handler(this);
+ ajax_request_load_handler(result);
});
result.error = error || function(type, e)
{
@@ -1906,9 +1910,7 @@ function _show_error(msg)
errorDiv.setAttribute("id", "alfresco-xforms-error");
dojo.html.setClass(errorDiv, "infoText statusErrorText");
errorDiv.style.padding = "2px";
- errorDiv.style.borderColor = "#003366";
- errorDiv.style.borderWidth = "1px";
- errorDiv.style.borderStyle = "solid";
+ errorDiv.style.border = "1px solid #003366";
var alfUI = document.getElementById("alfresco-xforms-ui");
dojo.dom.prependChild(errorDiv, alfUI);
}
@@ -1971,20 +1973,19 @@ function ajax_loader_update_display()
function ajax_request_load_handler(req)
{
- var ajaxLoader = _get_ajax_loader_element();
- var index = -1;
- for (var i = 0; i < _ajax_requests.length; i++)
- {
- if (_ajax_requests[i] == req)
- {
- index = i;
- break;
- }
- }
- if (index == -1)
+ var index = _ajax_requests.indexOf(req);
+ if (index != -1)
_ajax_requests.splice(index, 1);
else
- throw new Error("unable to find " + req.url);
+ {
+ var urls = [];
+ for (var i = 0; i < _ajax_requests.length; i++)
+ {
+ urls.push(_ajax_requests[i].url);
+ }
+ throw new Error("unable to find " + req.url +
+ " in [" + urls.join(", ") + "]");
+ }
ajax_loader_update_display();
}
@@ -2078,6 +2079,61 @@ function FilePickerWidget(node, value, readonly)
this.readonly = readonly || false;
}
+FilePickerWidget._uploads = [];
+FilePickerWidget._handleUpload = function(id, fileInput, webappRelativePath, widget)
+{
+ id = id.substring(0, id.indexOf("-widget"));
+ var d = fileInput.ownerDocument;
+ var iframe = d.createElement("iframe");
+ iframe.style.display = "none";
+ iframe.name = id + "_upload_frame";
+ iframe.id = iframe.name;
+ document.body.appendChild(iframe);
+ // makes it possible to target the frame properly in ie.
+ window.frames[id + "_upload_frame"].name = iframe.name;
+
+ FilePickerWidget._uploads[id] =
+ {
+ widget:widget,
+ path: fileInput.value,
+ webappRelativePath: webappRelativePath,
+ fileName: fileInput.value.substring(fileInput.value.lastIndexOf("/") + 1)
+ };
+
+ var form = document.createElement("form");
+ form.style.display = "none";
+ d.body.appendChild(form);
+ form.id = id + "_upload_form";
+ form.name = form.id;
+ form.method = "post";
+ form.encoding = "multipart/form-data";
+ form.enctype = "multipart/form-data";
+ form.target = iframe.name;
+ form.action = WEBAPP_CONTEXT + "/ajax/invoke/XFormsBean.uploadFile";
+ form.appendChild(fileInput.cloneNode(true));
+
+ var rp = d.createElement("input");
+ form.appendChild(rp);
+ rp.type = "hidden";
+ rp.name = "id";
+ rp.value = id;
+
+ var rp = d.createElement("input");
+ form.appendChild(rp);
+ rp.type = "hidden";
+ rp.name = "currentPath";
+ rp.value = webappRelativePath;
+
+ form.submit();
+}
+
+FilePickerWidget._upload_completeHandler = function(id)
+{
+ var upload = FilePickerWidget._uploads[id];
+ upload.widget._upload_completeHandler(upload.fileName,
+ upload.webappRelativePath);
+}
+
FilePickerWidget.prototype = {
getValue: function()
{
@@ -2102,6 +2158,46 @@ render: function()
{
this._showSelectedValue();
},
+_showStatus: function(text)
+{
+ var d = this.node.ownerDocument;
+ if (!this.statusDiv || !this.statusDiv.parentNode)
+ {
+ this.statusDiv = d.createElement("div");
+ this.node.insertBefore(this.statusDiv, this.node.firstChild);
+ dojo.html.setClass(this.statusDiv, "infoText");
+ this.statusDiv.style.padding = "2px";
+ this.statusDiv.style.border = "1px solid #003366";
+ this.statusDiv.style.fontWeight = "bold";
+ this.statusDiv.style.margin = "2px 5%";
+ this.statusDiv.style.textAlign = "center";
+ this.statusDiv.appendChild(d.createTextNode(text));
+ this.node.style.height = (parseInt(this.node.style.height) +
+ parseInt(this.statusDiv.style.marginTop) +
+ parseInt(this.statusDiv.style.marginBottom) +
+ this.statusDiv.offsetHeight) + "px";
+ var event = d.createEvent("UIEvents");
+ event.initUIEvent("heightChanged", true, true, window, 0);
+ this.node.dispatchEvent(event);
+ }
+ else
+ {
+ this.statusDiv.firstChild.nodeValue = text;
+ }
+},
+_hideStatus: function()
+{
+ if (this.statusDiv)
+ {
+ this.node.style.height = (parseInt(this.node.style.height) -
+ this.statusDiv.offsetHeight) + "px";
+ dojo.dom.removeChildren(this.statusDiv);
+ dojo.dom.removeNode(this.statusDiv);
+ var event = d.createEvent("UIEvents");
+ event.initUIEvent("heightChanged", true, true, window, 0);
+ this.node.dispatchEvent(event);
+ }
+},
_showSelectedValue: function()
{
var d = this.node.ownerDocument;
@@ -2110,23 +2206,31 @@ _showSelectedValue: function()
this.node.style.height = "20px";
this.node.style.lineHeight = this.node.style.height;
+ this.node.style.position = "relative";
+ this.node.style.whiteSpace = "nowrap";
+
var event = d.createEvent("UIEvents");
event.initUIEvent("heightChanged", true, true, window, 0);
this.node.dispatchEvent(event);
- this.node.appendChild(d.createTextNode(this.value == null
- ? ""
- : this.value));
+ this.selectedPathInput = d.createElement("input");
+ this.node.appendChild(this.selectedPathInput);
+ this.selectedPathInput.type = "text";
+ this.selectedPathInput.value = this.value == null ? "" : this.value;
+ dojo.event.connect(this.selectedPathInput, "onblur", this, this._selectPathInput_changeHandler);
+
this.selectButton = d.createElement("input");
this.node.appendChild(this.selectButton);
this.selectButton.filePickerWidget = this;
this.selectButton.type = "button";
this.selectButton.value = this.value == null ? "Select" : "Change";
this.selectButton.disabled = this.readonly;
- this.selectButton.style.marginLeft = "10px";
- this.selectButton.style.position = "absolute";
- this.selectButton.style.right = "10px";
- this.selectButton.style.top = (.5 * this.node.offsetHeight) - (.5 * this.selectButton.offsetHeight) + "px";
+ this.selectButton.style.margin = "0px 10px 0px 10px";
+ this.selectedPathInput.style.width = (this.node.offsetWidth -
+ this.selectButton.offsetWidth -
+ parseInt(this.selectButton.style.marginRight) -
+ parseInt(this.selectButton.style.marginLeft))
+ + "px";
dojo.event.connect(this.selectButton,
"onclick",
function(event)
@@ -2134,6 +2238,11 @@ _showSelectedValue: function()
var w = event.target.filePickerWidget;
w._navigateToNode(w.getValue() || "");
});
+
+},
+_selectPathInput_changeHandler: function(event)
+{
+ this.setValue(event.target.value);
},
_navigateToNode: function(path)
{
@@ -2149,9 +2258,19 @@ _navigateToNode: function(path)
},
_showPicker: function(data)
{
- dojo.dom.removeChildren(this.node);
+ while (this.node.hasChildNodes() &&
+ this.node.lastChild != this.statusDiv)
+ {
+ this.node.removeChild(this.node.lastChild);
+ }
+
var d = this.node.ownerDocument;
- this.node.style.height = "200px";
+ this.node.style.height = (200 +
+ (this.statusDiv
+ ? (parseInt(this.statusDiv.style.height) +
+ parseInt(this.statusDiv.style.marginTop) +
+ parseInt(this.statusDiv.style.marginBottom))
+ : 0) + "px");
var event = d.createEvent("UIEvents");
event.initUIEvent("heightChanged", true, true, window, 0);
this.node.dispatchEvent(event);
@@ -2221,13 +2340,37 @@ _showPicker: function(data)
headerMenuTriggerImage.style.marginLeft = "4px";
headerMenuTriggerImage.align = "absmiddle";
- var headerRightLink = d.createElement("a");
- headerRightLink.setAttribute("webappRelativePath", currentPath);
- headerRightLink.filePickerWidget = this;
- headerRightLink.setAttribute("href", "javascript:void(0)");
+ var headerRightDiv = d.createElement("div");
+
+ var addContentLink = d.createElement("a");
+ headerRightDiv.appendChild(addContentLink);
+ addContentLink.setAttribute("webappRelativePath", currentPath);
+ addContentLink.filePickerWidget = this;
+ addContentLink.setAttribute("href", "javascript:void(0)");
+ dojo.event.connect(addContentLink,
+ "onclick",
+ function(event)
+ {
+ var t = event.target;
+ t.filePickerWidget._showAddContentPanel(t, t.getAttribute("webappRelativePath"));
+ });
+
+ var addContentImage = d.createElement("img");
+ addContentImage.style.borderWidth = "0px";
+ addContentImage.style.margin = "0px 2px 0px 2px";
+ addContentImage.align = "absmiddle";
+ addContentImage.setAttribute("src", WEBAPP_CONTEXT + "/images/icons/add.gif");
+ addContentLink.appendChild(addContentImage);
+ addContentLink.appendChild(d.createTextNode("Add Content"));
+
+ var navigateToParentLink = d.createElement("a");
+ headerRightDiv.appendChild(navigateToParentLink);
+ navigateToParentLink.setAttribute("webappRelativePath", currentPath);
+ navigateToParentLink.filePickerWidget = this;
+ navigateToParentLink.setAttribute("href", "javascript:void(0)");
if (currentPathName != "/")
{
- dojo.event.connect(headerRightLink,
+ dojo.event.connect(navigateToParentLink,
"onclick",
function(event)
{
@@ -2239,24 +2382,26 @@ _showPicker: function(data)
w._navigateToNode(parentPath);
});
}
+
var navigateToParentNodeImage = d.createElement("img");
navigateToParentNodeImage.style.borderWidth = "0px";
navigateToParentNodeImage.style.opacity = (currentPathName == "/" ? .3 : 1);
- navigateToParentNodeImage.style.marginRight = "2px";
+ navigateToParentNodeImage.style.margin = "0px 2px 0px 2px";
+ navigateToParentNodeImage.align = "absmiddle";
navigateToParentNodeImage.setAttribute("src", WEBAPP_CONTEXT + "/images/icons/up.gif");
- headerRightLink.appendChild(navigateToParentNodeImage);
- headerRightLink.appendChild(d.createTextNode("Go up"));
+ navigateToParentLink.appendChild(navigateToParentNodeImage);
+ navigateToParentLink.appendChild(d.createTextNode("Go up"));
- headerRightLink.style.position = "absolute";
- headerRightLink.style.height = headerDiv.style.height;
- headerRightLink.style.lineHeight = headerRightLink.style.height;
- headerRightLink.style.top = "0px";
- headerRightLink.style.right = "0px";
- headerRightLink.style.paddingRight = "2px";
- headerDiv.appendChild(headerRightLink);
+ headerRightDiv.style.position = "absolute";
+ headerRightDiv.style.height = headerDiv.style.height;
+ headerRightDiv.style.lineHeight = headerRightDiv.style.height;
+ headerRightDiv.style.top = "0px";
+ headerRightDiv.style.right = "0px";
+ headerRightDiv.style.paddingRight = "2px";
+ headerDiv.appendChild(headerRightDiv);
- var contentDiv = d.createElement("div");
- this.node.appendChild(contentDiv);
+ this.contentDiv = d.createElement("div");
+ this.node.appendChild(this.contentDiv);
var footerDiv = d.createElement("div");
this.node.appendChild(footerDiv);
@@ -2278,11 +2423,11 @@ _showPicker: function(data)
w._showSelectedValue();
});
-
- contentDiv.style.height = (this.node.offsetHeight -
- footerDiv.offsetHeight -
- headerDiv.offsetHeight - 10) + "px";
- contentDiv.style.overflowY = "auto";
+ this.contentDiv.style.height = (this.node.offsetHeight -
+ (this.statusDiv ? this.statusDiv.offsetHeight : 0) -
+ footerDiv.offsetHeight -
+ headerDiv.offsetHeight - 10) + "px";
+ this.contentDiv.style.overflowY = "auto";
var childNodes = data.getElementsByTagName("child-node");
for (var i = 0; i < childNodes.length; i++)
{
@@ -2295,7 +2440,7 @@ _showPicker: function(data)
var row = d.createElement("div");
row.setAttribute("id", name + "-row");
- contentDiv.appendChild(row);
+ this.contentDiv.appendChild(row);
row.rowIndex = i;
row.style.position = "relative";
row.style.height = "20px";
@@ -2368,6 +2513,57 @@ _showPicker: function(data)
});
}
},
+_showAddContentPanel: function(addContentLink, currentPath)
+{
+ var d = this.node.ownerDocument;
+ this.addContentDiv = d.createElement("div");
+ this.contentDiv.style.opacity = .3;
+ this.node.insertBefore(this.addContentDiv, this.contentDiv);
+ this.addContentDiv.style.backgroundColor = "lightgrey";
+ this.addContentDiv.style.position = "absolute";
+ this.addContentDiv.style.left = "10%";
+ this.addContentDiv.style.right = "10%";
+ this.addContentDiv.style.width = "80%";
+ this.addContentDiv.style.marginLeft = "4px";
+ this.addContentDiv.style.lineHeight = "20px";
+ var e = d.createElement("div");
+ e.style.marginLeft = "4px";
+ this.addContentDiv.appendChild(e);
+ e.appendChild(d.createTextNode("Upload a file to " + currentPath + " :"));
+
+ var fileInputDiv = d.createElement("div");
+ this.addContentDiv.appendChild(fileInputDiv);
+ fileInput = d.createElement("input");
+ fileInputDiv.appendChild(fileInput);
+ fileInput.widget = this;
+ fileInput.style.margin = "4px 4px";
+ fileInput.name = this.node.getAttribute("id") + "_file_input";
+ fileInput.type = "file";
+ fileInput.size = "35";
+ fileInput.setAttribute("webappRelativePath", currentPath);
+ dojo.event.connect(fileInput,
+ "onchange",
+ function(event)
+ {
+ var w = event.target.widget;
+ FilePickerWidget._handleUpload(w.node.getAttribute("id"),
+ event.target,
+ event.target.getAttribute("webappRelativePath"),
+ w);
+ if (w.addContentDiv)
+ {
+ dojo.dom.removeChildren(w.addContentDiv);
+ dojo.dom.removeNode(w.addContentDiv);
+ w.addContentDiv = null;
+ }
+ });
+},
+_upload_completeHandler: function(fileName, webappRelativePath)
+{
+ this._showStatus("Successfully uploaded " + fileName +
+ " into " + webappRelativePath);
+ this._navigateToNode(webappRelativePath);
+},
_closeParentPathMenu: function()
{
if (this.parentPathMenu)