From cabab31ec0d0a8459db105f73af167b5f9226709 Mon Sep 17 00:00:00 2001 From: Ariel Backenroth Date: Tue, 9 Jan 2007 14:42:34 +0000 Subject: [PATCH] adding pager to manage task resources list fixing columns in create form wizard to not move around wildy once files are uploaded fixing some bugs in repeats as a result of the chiba1.3 upgrade. - xpaths were not being resolved for newly created instances (and shouldn't be) - xpaths for nested repeats weren't behaving properly fixed caching issue in edit which was causing the wrong form to be loaded for instance data using alfresco namespace as defined in NamespaceService passing namespace uris and prefixes to js to avoid errors if they should change fixed a bug where the renditions property of forminstancedata was getting duplicate renditions (and thus regenerating way too much stuff when doing an edit) using an italic 'description not set' when description isn't set in several screens. using the avm service to set properties in renderingenginetemplateimpl. upgrading to xalan-2.7.0 in order to be able to use bsf for extension functions. adding the path that was not found to AVMNotFoundExceptions. very helpful when debugging. substantial refactoring of rendering engines in preparation for integration with TemplateService. - implementing a common model as a hash of QNames to objects. for method, providing a simple method wrapper called TemplateProcessorMethod which takes an array of Objects as a parameter, and returns an object. it is up to the template processors to properly convert arguments. a QName is used for the variable name rather than a string in order to include a namespace prefix (needed for xsl, and generally better looking). - for xsl, using javascript bindings for formdatafunctions, which using liveconnect within rhino to call into the xsl rendering engine to evaluate the function. it ends up generating this js block into a xalan:component within the xsl tempalte: // gets the handle to the backing java object which can invoke the function based on id var _xsltp_invoke = java.lang.Class.forName('org.alfresco.web.forms.XSLTRenderingEngine$ProcessorMethodInvoker').newInstance(); // utility to convert js arrays into java function _xsltp_to_java_array(js_array) { var java_array = java.lang.reflect.Array.newInstance(java.lang.Object, js_array.length); for (var i = 0; i < js_array.length; i++) { java_array[i] = js_array[i]; } return java_array; } // js handles to each of the form data functions which uses _xsltp_invoke to call the actual method function _getAVMPath() { return _xsltp_invoke.invokeMethod('_getAVMPath8829055', _xsltp_to_java_array(arguments)); } function parseXMLDocuments() { return _xsltp_invoke.invokeMethod('parseXMLDocuments12235190', _xsltp_to_java_array(arguments)); } function parseXMLDocument() { return _xsltp_invoke.invokeMethod('parseXMLDocument15280968', _xsltp_to_java_array(arguments)); } xml model data is inferred as a root namespace document within the model hash provided. - for freemarker, things pretty much work as they did before, just i now need to convert values by hand to TemplateModels fixed a bug with hidden iframe upload. seems like the complexity of actually cloning the file input element is unnecessary and that simply attaching the node in two places within the dom works just fine. git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@4764 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- .../alfresco/web/bean/wcm/AVMEditBean.java | 18 +- .../web/bean/wcm/CreateFormWizard.java | 5 + .../web/forms/AbstractRenderingEngine.java | 77 --- .../web/forms/FormInstanceDataImpl.java | 4 +- .../web/forms/FreeMarkerRenderingEngine.java | 315 ++++++------ .../alfresco/web/forms/RenderingEngine.java | 17 +- .../web/forms/RenderingEngineTemplate.java | 17 + .../forms/RenderingEngineTemplateImpl.java | 260 ++++++++-- .../org/alfresco/web/forms/RenditionImpl.java | 5 +- .../java/org/alfresco/web/forms/XMLUtil.java | 1 + .../web/forms/XSLFORenderingEngine.java | 10 +- .../web/forms/XSLTRenderingEngine.java | 482 ++++++++++-------- .../web/forms/xforms/SchemaFormBuilder.java | 48 +- .../web/forms/xforms/XFormsProcessor.java | 65 ++- .../web/ui/wcm/component/UIFormProcessor.java | 4 - .../web/ui/wcm/tag/FormProcessorTag.java | 16 +- ...get_company_footer_choices_simple_type.jsp | 4 +- .../output-method-callout.ftl | 46 +- .../output-method-callout.xsl | 64 +-- source/web/css/main.css | 18 +- .../configure-rendering-engines.jsp | 14 +- .../jsp/wcm/create-form-wizard/details.jsp | 15 +- .../select-default-workflow.jsp | 5 +- .../jsp/wcm/create-form-wizard/summary.jsp | 4 +- .../web/jsp/workflow/manage-task-dialog.jsp | 1 + source/web/scripts/ajax/xforms.js | 296 ++++++----- 26 files changed, 1083 insertions(+), 728 deletions(-) delete mode 100644 source/java/org/alfresco/web/forms/AbstractRenderingEngine.java diff --git a/source/java/org/alfresco/web/bean/wcm/AVMEditBean.java b/source/java/org/alfresco/web/bean/wcm/AVMEditBean.java index 17b281420c..85e41d28e8 100644 --- a/source/java/org/alfresco/web/bean/wcm/AVMEditBean.java +++ b/source/java/org/alfresco/web/bean/wcm/AVMEditBean.java @@ -240,11 +240,17 @@ public class AVMEditBean { if (this.form == null) { - final String formName = (String) - this.nodeService.getProperty(this.getAvmNode().getNodeRef(), - WCMAppModel.PROP_PARENT_FORM_NAME); + final PropertyValue pv = + this.avmService.getNodeProperty(-1, + this.getAvmNode().getPath(), + WCMAppModel.PROP_PARENT_FORM_NAME); + + final String formName = (String)pv.getValue(DataTypeDefinition.TEXT); final WebProject wp = new WebProject(this.getAvmNode().getPath()); this.form = wp.getForm(formName); + LOGGER.debug("loaded form " + this.form + + ", form name " + formName + + ", for " + this.getAvmNode().getPath()); } return this.form; } @@ -441,7 +447,10 @@ public class AVMEditBean } catch (Throwable t) { - LOGGER.error(t, t); + LOGGER.error("error regenerating " + rendition.getName() + + ": " + t.getMessage(), t); + Utils.addErrorMessage("error regenerating " + rendition.getName() + + ": " + t.getMessage(), t); } } final NodeRef[] uploadedFiles = this.formProcessorSession.getUploadedFiles(); @@ -539,6 +548,7 @@ public class AVMEditBean setEditorOutput(null); this.instanceDataDocument = null; this.formProcessorSession = null; + this.form = null; } /** diff --git a/source/java/org/alfresco/web/bean/wcm/CreateFormWizard.java b/source/java/org/alfresco/web/bean/wcm/CreateFormWizard.java index afd471c2d8..9b1a0454ee 100644 --- a/source/java/org/alfresco/web/bean/wcm/CreateFormWizard.java +++ b/source/java/org/alfresco/web/bean/wcm/CreateFormWizard.java @@ -501,6 +501,11 @@ public class CreateFormWizard public void addSelectedRenderingEngineTemplate(final ActionEvent event) { final String name = this.getRenderingEngineTemplateName(); + if (name == null || name.length() == 0) + { + Utils.addErrorMessage("Please provide a name for the rendering engine template"); + return; + } final String opp = this.getOutputPathPatternForRendition(); final String mimetype = this.getMimetypeForRendition(); for (RenderingEngineTemplateData retd : this.renderingEngineTemplates) diff --git a/source/java/org/alfresco/web/forms/AbstractRenderingEngine.java b/source/java/org/alfresco/web/forms/AbstractRenderingEngine.java deleted file mode 100644 index ced4a85c0a..0000000000 --- a/source/java/org/alfresco/web/forms/AbstractRenderingEngine.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (C) 2005 Alfresco, Inc. - * - * Licensed under the Mozilla Public License version 1.1 - * with a permitted attribution clause. You may obtain a - * copy of the License at - * - * http://www.alfresco.org/legal/license.txt - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, - * either express or implied. See the License for the specific - * language governing permissions and limitations under the - * License. - */ -package org.alfresco.web.forms; - -import java.util.HashMap; -import java.util.Map; -import javax.faces.context.FacesContext; -import org.alfresco.model.WCMModel; -import org.alfresco.repo.avm.AVMNodeConverter; -import org.alfresco.service.cmr.remote.AVMRemote; -import org.alfresco.service.cmr.repository.ContentService; -import org.alfresco.service.cmr.repository.NodeRef; -import org.alfresco.service.cmr.repository.NodeService; -import org.alfresco.web.bean.wcm.AVMConstants; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.springframework.web.context.WebApplicationContext; -import org.springframework.web.jsf.FacesContextUtils; - -/** - * Provides helper functions for form data renderers. - */ -public abstract class AbstractRenderingEngine - implements RenderingEngine -{ - private static final Log LOGGER = LogFactory.getLog(AbstractRenderingEngine.class); - - protected static final String ALFRESCO_NS = "http://www.alfresco.org/alfresco"; - protected static final String ALFRESCO_NS_PREFIX = "alfresco"; - - protected AbstractRenderingEngine() - { - } - - protected static AVMRemote getAVMRemote() - { - final FacesContext fc = - FacesContext.getCurrentInstance(); - final WebApplicationContext wac = - FacesContextUtils.getRequiredWebApplicationContext(fc); - return (AVMRemote)wac.getBean("avmRemote"); - } - - protected static FormDataFunctions getFormDataFunctions() - { - return new FormDataFunctions(AbstractRenderingEngine.getAVMRemote()); - } - - protected HashMap getStandardParameters(final FormInstanceData formInstanceData, - final Rendition rendition) - { - final String formInstanceDataAvmPath = formInstanceData.getPath(); - final String renditionAvmPath = rendition.getPath(); - final HashMap parameters = new HashMap(); - parameters.put("avm_sandbox_url", AVMConstants.buildStoreUrl(formInstanceDataAvmPath)); - parameters.put("form_instance_data_file_name", AVMNodeConverter.SplitBase(formInstanceDataAvmPath)[1]); - parameters.put("rendition_file_name", AVMNodeConverter.SplitBase(renditionAvmPath)[1]); - parameters.put("parent_path", AVMNodeConverter.SplitBase(formInstanceDataAvmPath)[0]); - final FacesContext fc = FacesContext.getCurrentInstance(); - parameters.put("request_context_path", fc.getExternalContext().getRequestContextPath()); - return parameters; - } -} \ No newline at end of file diff --git a/source/java/org/alfresco/web/forms/FormInstanceDataImpl.java b/source/java/org/alfresco/web/forms/FormInstanceDataImpl.java index 0ddc676fce..ac6be50063 100644 --- a/source/java/org/alfresco/web/forms/FormInstanceDataImpl.java +++ b/source/java/org/alfresco/web/forms/FormInstanceDataImpl.java @@ -114,8 +114,8 @@ public class FormInstanceDataImpl final PropertyValue pv = avmService.getNodeProperty(-1, this.getPath(), WCMAppModel.PROP_RENDITIONS); final Collection renditionPaths = (pv == null - ? Collections.EMPTY_LIST - : pv.getCollection(DataTypeDefinition.TEXT)); + ? Collections.EMPTY_LIST + : pv.getCollection(DataTypeDefinition.TEXT)); final String storeName = AVMConstants.getStoreName(this.getPath()); final List result = new ArrayList(renditionPaths.size()); for (Serializable path : renditionPaths) diff --git a/source/java/org/alfresco/web/forms/FreeMarkerRenderingEngine.java b/source/java/org/alfresco/web/forms/FreeMarkerRenderingEngine.java index 2eb37acb48..f6687d7de6 100644 --- a/source/java/org/alfresco/web/forms/FreeMarkerRenderingEngine.java +++ b/source/java/org/alfresco/web/forms/FreeMarkerRenderingEngine.java @@ -19,16 +19,15 @@ package org.alfresco.web.forms; import freemarker.ext.dom.NodeModel; import freemarker.template.*; import java.io.*; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; import javax.xml.parsers.DocumentBuilder; import org.alfresco.model.ContentModel; import org.alfresco.service.cmr.repository.ContentReader; import org.alfresco.service.cmr.repository.ContentService; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.service.namespace.NamespaceService; +import org.alfresco.service.namespace.QName; import org.alfresco.web.bean.wcm.AVMConstants; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -44,25 +43,16 @@ import org.xml.sax.SAXException; * @author Ariel Backenroth */ public class FreeMarkerRenderingEngine - extends AbstractRenderingEngine + implements RenderingEngine { private static final Log LOGGER = LogFactory.getLog(FreeMarkerRenderingEngine.class); - public FreeMarkerRenderingEngine() - { - super(); - } + public FreeMarkerRenderingEngine() { } - public String getName() - { - return "FreeMarker"; - } + public String getName() { return "FreeMarker"; } - public String getDefaultTemplateFileExtension() - { - return "ftl"; - } + public String getDefaultTemplateFileExtension() { return "ftl"; } /** * Renders the rendition using the configured freemarker template. This @@ -70,15 +60,13 @@ public class FreeMarkerRenderingEngine * a variable named alfresco at the root. the alfresco variable contains a hash of * all parameters and all extension functions. */ - public void render(final FormInstanceData formInstanceData, + public void render(final Map model, final RenderingEngineTemplate ret, - final Rendition rendition) + final OutputStream out) throws IOException, RenderingEngine.RenderingException, SAXException { - final Map parameters = - this.getStandardParameters(formInstanceData, rendition); final Configuration cfg = new Configuration(); cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER); @@ -86,139 +74,12 @@ public class FreeMarkerRenderingEngine final Template t = new Template("freemarker_template", new InputStreamReader(ret.getInputStream()), cfg); + final TemplateHashModel rootModel = this.convertModel(model); - // wrap the xml instance in a model - final TemplateHashModel instanceDataModel = NodeModel.wrap(formInstanceData.getDocument()); - - // build models for each of the extension functions - final HashMap methodModels = - new HashMap(3, 1.0f); - - methodModels.put("parseXMLDocument", new TemplateMethodModel() - { - public Object exec(final List args) - throws TemplateModelException - { - try - { - final FormDataFunctions ef = FreeMarkerRenderingEngine.getFormDataFunctions(); - final String path = - AVMConstants.buildPath(parameters.get("parent_path"), - (String)args.get(0), - AVMConstants.PathRelation.WEBAPP_RELATIVE); - final Document d = ef.parseXMLDocument(path); - return d != null ? d.getDocumentElement() : null; - } - catch (Exception e) - { - throw new TemplateModelException(e); - } - } - }); - - methodModels.put("parseXMLDocuments", new TemplateMethodModel() - { - public Object exec(final List args) - throws TemplateModelException - { - try - { - final FormDataFunctions ef = FreeMarkerRenderingEngine.getFormDataFunctions(); - final String path = - AVMConstants.buildPath(parameters.get("parent_path"), - args.size() == 1 ? "" : (String)args.get(1), - AVMConstants.PathRelation.WEBAPP_RELATIVE); - final Map resultMap = ef.parseXMLDocuments((String)args.get(0), path); - LOGGER.debug("received " + resultMap.size() + " documents in " + path); - - // create a root document for rooting all the results. we do this - // so that each document root element has a common parent node - // and so that xpath axes work properly - final Document rootNodeDocument = XMLUtil.newDocument(); - final Element rootNodeDocumentEl = - rootNodeDocument.createElementNS(ALFRESCO_NS, - ALFRESCO_NS_PREFIX + ":file_list"); - rootNodeDocumentEl.setAttribute("xmlns:" + ALFRESCO_NS_PREFIX, ALFRESCO_NS); - rootNodeDocument.appendChild(rootNodeDocumentEl); - - final List result = new ArrayList(resultMap.size()); - for (Map.Entry e : resultMap.entrySet()) - { - final Element documentEl = e.getValue().getDocumentElement(); - documentEl.setAttribute("xmlns:" + ALFRESCO_NS_PREFIX, ALFRESCO_NS); - documentEl.setAttributeNS(ALFRESCO_NS, - ALFRESCO_NS_PREFIX + ":file_name", - e.getKey()); - final Node n = rootNodeDocument.importNode(documentEl, true); - rootNodeDocumentEl.appendChild(n); - result.add(NodeModel.wrap(n)); - } - return result; - } - catch (Exception e) - { - throw new TemplateModelException(e); - } - } - }); - - // for debugging - methodModels.put("_getAVMPath", new TemplateMethodModel() - { - public Object exec(final List args) - throws TemplateModelException - { - try - { - return AVMConstants.buildPath(parameters.get("parent_path"), - (String)args.get(0), - AVMConstants.PathRelation.WEBAPP_RELATIVE); - } - catch (Exception e) - { - throw new TemplateModelException(e); - } - } - }); - - // build a wrapper for the parameters. this also wraps the extension functions - // so they appear in the namespace alfresco. - final TemplateHashModel parameterModel = new SimpleHash(parameters) - { - - public TemplateModel get(final String key) - throws TemplateModelException - { - return (methodModels.containsKey(key) - ? methodModels.get(key) - : super.get(key)); - } - }; - - // build the root model. anything not in the falsey alfresco namespace will be - // retrieved from the xml file in order to make it behave as close as possible to - // the xsl environment - final TemplateHashModel rootModel = new TemplateHashModel() - { - public TemplateModel get(final String key) - throws TemplateModelException - { - return (ALFRESCO_NS_PREFIX.equals(key) - ? parameterModel - : instanceDataModel.get(key)); - } - - public boolean isEmpty() - { - return false; - } - }; - // process the form - final Writer writer = new OutputStreamWriter(rendition.getOutputStream()); try { - t.process(rootModel, writer); + t.process(rootModel, new OutputStreamWriter(out)); } catch (final TemplateException te) { @@ -227,8 +88,158 @@ public class FreeMarkerRenderingEngine } finally { - writer.flush(); - writer.close(); + out.flush(); + out.close(); + } + } + + private TemplateHashModel convertModel(final Map model) + { + final List rootModelObjects = new LinkedList(); + final SimpleHash result = new SimpleHash() + { + public TemplateModel get(final String key) + throws TemplateModelException + { + TemplateModel result = super.get(key); + if (result == null) + { + for (TemplateHashModel m : rootModelObjects) + { + result = m.get(key); + if (result != null) + { + break; + } + } + } + return result; + } + }; + for (final Map.Entry entry : model.entrySet()) + { + final QName qn = entry.getKey(); + if (qn.equals(RenderingEngine.ROOT_NAMESPACE)) + { + final TemplateModel m = this.convertValue(entry.getValue()); + if (m instanceof TemplateHashModel) + { + rootModelObjects.add((TemplateHashModel)m); + } + else + { + throw new IllegalArgumentException("root namespace values must be convertable to " + TemplateHashModel.class.getName() + + ". converted " + entry.getValue().getClass().getName() + + " to " + m.getClass().getName() + "."); + } + } + else + { + final String[] splitQName = QName.splitPrefixedQName(qn.toPrefixString()); + final String variableName = splitQName[1]; + + //insert + if (NamespaceService.DEFAULT_PREFIX.equals(splitQName[0])) + { + result.put(variableName, this.convertValue(entry.getValue())); + } + else + { + SimpleHash prefixModel = null; + final String prefix = splitQName[0]; + try + { + try + { + prefixModel = (SimpleHash)result.get(prefix); + } + catch (ClassCastException cce) + { + throw new ClassCastException("expected value of " + prefix + + " to be a " + SimpleHash.class.getName() + + ". found a " + result.get(prefix).getClass().getName()); + } + } + catch (TemplateModelException tme) + { + } + if (prefixModel == null) + { + prefixModel = new SimpleHash(); + result.put(prefix, prefixModel); + } + + prefixModel.put(variableName, + this.convertValue(entry.getValue())); + } + } + } + return result; + } + + private TemplateModel convertValue(final Object value) + { + LOGGER.debug("converting value " + value); + if (value == null) + { + return null; + } + else if (value.getClass().isArray()) + { + final Object[] array = (Object[])value; + LOGGER.debug("converting array of " + array.getClass().getComponentType() + + " size " + array.length); + final SimpleSequence result = new SimpleSequence(); + for (int i = 0; i < array.length; i++) + { + result.add(this.convertValue(array[i])); + } + return result; + } + else if (value instanceof String) + { + return new SimpleScalar((String)value); + } + else if (value instanceof Number) + { + return new SimpleNumber((Number)value); + } + else if (value instanceof Boolean) + { + return (Boolean)value ? TemplateBooleanModel.TRUE : TemplateBooleanModel.FALSE; + } + else if (value instanceof Document) + { + return NodeModel.wrap((Document)value); + } + else if (value instanceof Node) + { + return NodeModel.wrap((Node)value); + } + else if (value instanceof RenderingEngine.TemplateProcessorMethod) + { + return new TemplateMethodModel() + { + public Object exec(final List args) + throws TemplateModelException + { + try + { + LOGGER.debug("invoking template processor method " + value + + " with " + args.size() + " arguments"); + final Object result = ((TemplateProcessorMethod)value).exec(args.toArray(new Object[args.size()])); + return FreeMarkerRenderingEngine.this.convertValue(result); + } + catch (Exception e) + { + throw new TemplateModelException(e); + } + } + }; + } + else + { + throw new IllegalArgumentException("unable to convert value " + value.getClass().getName()); } } } diff --git a/source/java/org/alfresco/web/forms/RenderingEngine.java b/source/java/org/alfresco/web/forms/RenderingEngine.java index dccc8329a0..3638f7451a 100644 --- a/source/java/org/alfresco/web/forms/RenderingEngine.java +++ b/source/java/org/alfresco/web/forms/RenderingEngine.java @@ -17,6 +17,7 @@ package org.alfresco.web.forms; import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.namespace.QName; import java.io.IOException; import java.io.OutputStream; import java.io.Serializable; @@ -56,6 +57,18 @@ public interface RenderingEngine ///////////////////////////////////////////////////////////////////////////// + public interface TemplateProcessorMethod + extends Serializable + { + public Object exec(final Object[] arguments) + throws Exception; + } + + ///////////////////////////////////////////////////////////////////////////// + + public final static QName ROOT_NAMESPACE = + QName.createQName(null, "root_namespace"); + /** * Returns the rendering engines name. * @@ -81,8 +94,8 @@ public interface RenderingEngine * @param form the form that collected the xml content. * @param rendition the rendition to serialize to. */ - public void render(final FormInstanceData formInstanceData, + public void render(final Map model, final RenderingEngineTemplate ret, - final Rendition rendition) + final OutputStream out) throws IOException, RenderingException, SAXException; } diff --git a/source/java/org/alfresco/web/forms/RenderingEngineTemplate.java b/source/java/org/alfresco/web/forms/RenderingEngineTemplate.java index 3aa26d2fd9..0a8351108e 100644 --- a/source/java/org/alfresco/web/forms/RenderingEngineTemplate.java +++ b/source/java/org/alfresco/web/forms/RenderingEngineTemplate.java @@ -78,9 +78,26 @@ public interface RenderingEngineTemplate /** * Produces a rendition of the provided formInstanceData. + * + * @param formInstanceData the form instance data for which to produce + * the rendition. */ public Rendition render(final FormInstanceData formInstanceData) throws IOException, SAXException, RenderingEngine.RenderingException; + + /** + * Produces a rendition of the provided formInstanceData to an existing + * rendition. + * + * @param formInstanceData the form instance data for which to produce + * the rendition. + * @param rendition the rendition to rerender + */ + public void render(final FormInstanceData formInstanceData, + final Rendition rendition) + throws IOException, + SAXException, + RenderingEngine.RenderingException; } diff --git a/source/java/org/alfresco/web/forms/RenderingEngineTemplateImpl.java b/source/java/org/alfresco/web/forms/RenderingEngineTemplateImpl.java index 25eb589887..627df2917d 100644 --- a/source/java/org/alfresco/web/forms/RenderingEngineTemplateImpl.java +++ b/source/java/org/alfresco/web/forms/RenderingEngineTemplateImpl.java @@ -30,15 +30,19 @@ import org.alfresco.service.ServiceRegistry; import org.alfresco.service.cmr.avm.AVMService; import org.alfresco.service.cmr.dictionary.DataTypeDefinition; import org.alfresco.service.cmr.repository.*; -import org.alfresco.service.namespace.QName; +import org.alfresco.service.namespace.*; +import org.alfresco.service.cmr.remote.AVMRemote; import org.alfresco.web.app.Application; import org.alfresco.web.bean.repository.Repository; import org.alfresco.web.bean.wcm.AVMConstants; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.w3c.dom.Document; +import org.springframework.web.context.WebApplicationContext; +import org.springframework.web.jsf.FacesContextUtils; +import org.w3c.dom.*; import org.xml.sax.SAXException; + /** * Implementation of a rendering engine template */ @@ -101,11 +105,6 @@ public class RenderingEngineTemplateImpl return this.renditionPropertiesNodeRef; } - /** - * Provides an input stream to the rendering engine template. - * - * @return the input stream to the rendering engine template. - */ public InputStream getInputStream() throws IOException { @@ -131,7 +130,8 @@ public class RenderingEngineTemplateImpl } /** - * Returns the output path to use for renditions. + * Generates an output path for the rendition by compiling the output path pattern + * as a freemarker template. * * @return the output path to use for renditions. */ @@ -183,11 +183,6 @@ public class RenderingEngineTemplateImpl return result; } - /** - * Returns the mime type to use for generated assets. - * - * @return the mime type to use for generated assets. - */ public String getMimetypeForRendition() { final NodeService nodeService = this.getServiceRegistry().getNodeService(); @@ -195,9 +190,6 @@ public class RenderingEngineTemplateImpl WCMAppModel.PROP_MIMETYPE_FOR_RENDITION); } - /** - * Produces a rendition of the provided formInstanceData. - */ public Rendition render(final FormInstanceData formInstanceData) throws IOException, SAXException, @@ -213,14 +205,44 @@ public class RenderingEngineTemplateImpl AVMNodeConverter.SplitBase(renditionAvmPath)[1]); if (LOGGER.isDebugEnabled()) LOGGER.debug("Created file node for file: " + renditionAvmPath); + avmService.addAspect(renditionAvmPath, WCMAppModel.ASPECT_FORM_INSTANCE_DATA); + avmService.addAspect(renditionAvmPath, ContentModel.ASPECT_TITLED); + avmService.addAspect(renditionAvmPath, WCMAppModel.ASPECT_RENDITION); + + final PropertyValue pv = + avmService.getNodeProperty(-1, formInstanceData.getPath(), WCMAppModel.PROP_RENDITIONS); + final Collection renditions = (pv == null + ? new HashSet() + : pv.getCollection(DataTypeDefinition.TEXT)); + renditions.add(AVMConstants.getStoreRelativePath(renditionAvmPath)); + avmService.setNodeProperty(formInstanceData.getPath(), + WCMAppModel.PROP_RENDITIONS, + new PropertyValue(DataTypeDefinition.TEXT, + (Serializable)renditions)); } final Rendition result = new RenditionImpl(AVMNodeConverter.ToNodeRef(-1, renditionAvmPath)); - this.getRenderingEngine().render(formInstanceData, this, result); + this.render(formInstanceData, result); + return result; + } - avmService.addAspect(renditionAvmPath, WCMAppModel.ASPECT_FORM_INSTANCE_DATA); - avmService.addAspect(renditionAvmPath, ContentModel.ASPECT_TITLED); - avmService.addAspect(renditionAvmPath, WCMAppModel.ASPECT_RENDITION); + public void render(final FormInstanceData formInstanceData, + final Rendition rendition) + throws IOException, + SAXException, + RenderingEngine.RenderingException + { + final OutputStream out = rendition.getOutputStream(); + try + { + this.getRenderingEngine().render(this.buildModel(formInstanceData, rendition), + this, + out); + } + finally + { + out.close(); + } final Map props = new HashMap(5, 1.0f); props.put(WCMAppModel.PROP_PARENT_FORM_NAME, @@ -228,13 +250,13 @@ public class RenderingEngineTemplateImpl formInstanceData.getForm().getName())); props.put(ContentModel.PROP_TITLE, new PropertyValue(DataTypeDefinition.TEXT, - AVMNodeConverter.SplitBase(renditionAvmPath)[1])); + AVMNodeConverter.SplitBase(rendition.getPath())[1])); final ResourceBundle bundle = Application.getBundle(FacesContext.getCurrentInstance()); props.put(ContentModel.PROP_DESCRIPTION, new PropertyValue(DataTypeDefinition.TEXT, MessageFormat.format(bundle.getString("default_rendition_description"), this.getTitle(), - AVMConstants.getSandboxRelativePath(renditionAvmPath)))); + AVMConstants.getSandboxRelativePath(rendition.getPath())))); props.put(WCMAppModel.PROP_PARENT_RENDERING_ENGINE_TEMPLATE, new PropertyValue(DataTypeDefinition.NODE_REF, this.nodeRef)); @@ -246,19 +268,187 @@ public class RenderingEngineTemplateImpl new PropertyValue(DataTypeDefinition.TEXT, AVMConstants.getStoreRelativePath(formInstanceData.getPath()))); - avmService.setNodeProperties(renditionAvmPath, props); - - final PropertyValue pv = - avmService.getNodeProperty(-1, formInstanceData.getPath(), WCMAppModel.PROP_RENDITIONS); - Collection renditions = (pv == null - ? new LinkedList() - : pv.getCollection(DataTypeDefinition.TEXT)); - renditions.add(AVMConstants.getStoreRelativePath(renditionAvmPath)); - avmService.setNodeProperty(formInstanceData.getPath(), - WCMAppModel.PROP_RENDITIONS, - new PropertyValue(DataTypeDefinition.TEXT, - (Serializable)renditions)); - return result; + final AVMService avmService = this.getServiceRegistry().getAVMService(); + avmService.setNodeProperties(rendition.getPath(), props); + } + + /** + * Builds the model to pass to the rendering engine. + */ + protected Map buildModel(final FormInstanceData formInstanceData, + final Rendition rendition) + throws IOException, + SAXException + { + final DynamicNamespacePrefixResolver namespacePrefixResolver = + new DynamicNamespacePrefixResolver(); + namespacePrefixResolver.registerNamespace(NamespaceService.ALFRESCO_PREFIX, + NamespaceService.ALFRESCO_URI); + + final String formInstanceDataAvmPath = formInstanceData.getPath(); + final String renditionAvmPath = rendition.getPath(); + final String parentPath = AVMNodeConverter.SplitBase(formInstanceDataAvmPath)[0]; + final String sandboxUrl = AVMConstants.buildStoreUrl(formInstanceDataAvmPath); + final HashMap model = new HashMap(); + // add simple scalar parameters + model.put(QName.createQName(NamespaceService.ALFRESCO_PREFIX, + "avm_sandbox_url", + namespacePrefixResolver), + sandboxUrl); + model.put(XSLTRenderingEngine.PROP_URI_RESOLVER_BASE_URI, + sandboxUrl); + model.put(QName.createQName(NamespaceService.ALFRESCO_PREFIX, + "form_instance_data_file_name", + namespacePrefixResolver), + AVMNodeConverter.SplitBase(formInstanceDataAvmPath)[1]); + model.put(QName.createQName(NamespaceService.ALFRESCO_PREFIX, + "rendition_file_name", + namespacePrefixResolver), + AVMNodeConverter.SplitBase(renditionAvmPath)[1]); + model.put(QName.createQName(NamespaceService.ALFRESCO_PREFIX, + "parent_path", + namespacePrefixResolver), + parentPath); + final FacesContext fc = FacesContext.getCurrentInstance(); + model.put(QName.createQName(NamespaceService.ALFRESCO_PREFIX, + "request_context_path", + namespacePrefixResolver), + fc.getExternalContext().getRequestContextPath()); + + // add methods + final FormDataFunctions fdf = this.getFormDataFunctions(); + model.put(QName.createQName(NamespaceService.ALFRESCO_PREFIX, + "parseXMLDocument", + namespacePrefixResolver), + new RenderingEngine.TemplateProcessorMethod() + { + public Object exec(final Object[] arguments) + throws IOException, + SAXException + { + if (arguments.length != 1) + { + throw new IllegalArgumentException("expected 1 argument to parseXMLDocument. got " + + arguments.length); + + } + if (! (arguments[0] instanceof String)) + { + throw new ClassCastException("expected arguments[0] to be a " + String.class.getName() + + ". got a " + arguments[0].getClass().getName() + "."); + } + String path = (String)arguments[0]; + path = AVMConstants.buildPath(parentPath, + path, + AVMConstants.PathRelation.WEBAPP_RELATIVE); + LOGGER.debug("tpm_parseXMLDocument('" + path + + "'), parentPath = " + parentPath); + final Document d = fdf.parseXMLDocument(path); + return d != null ? d.getDocumentElement() : null; + } + }); + model.put(QName.createQName(NamespaceService.ALFRESCO_PREFIX, + "parseXMLDocuments", + namespacePrefixResolver), + new RenderingEngine.TemplateProcessorMethod() + { + public Object exec(final Object[] arguments) + throws IOException, + SAXException + { + if (arguments.length > 1) + { + throw new IllegalArgumentException("expected zero or one arguments to parseXMLDocuments. got " + + arguments.length); + } + if (! (arguments[0] instanceof String)) + { + throw new ClassCastException("expected arguments[0] to be a " + String.class.getName() + + ". got a " + arguments[0].getClass().getName() + "."); + } + + if (arguments.length == 2 && ! (arguments[1] instanceof String)) + { + throw new ClassCastException("expected arguments[1] to be a " + String.class.getName() + + ". got a " + arguments[1].getClass().getName() + "."); + } + + String path = arguments.length == 2 ? (String)arguments[1] : ""; + path = AVMConstants.buildPath(parentPath, + path, + AVMConstants.PathRelation.WEBAPP_RELATIVE); + final String formName = (String)arguments[0]; + LOGGER.debug("tpm_parseXMLDocuments('" + formName + "','" + path + + "'), parentPath = " + parentPath); + final Map resultMap = fdf.parseXMLDocuments(formName, path); + LOGGER.debug("received " + resultMap.size() + + " documents in " + path + + " with form name " + formName); + + // create a root document for rooting all the results. we do this + // so that each document root element has a common parent node + // and so that xpath axes work properly + final Document rootNodeDocument = XMLUtil.newDocument(); + final Element rootNodeDocumentEl = + rootNodeDocument.createElementNS(NamespaceService.ALFRESCO_URI, + NamespaceService.ALFRESCO_PREFIX + ":file_list"); + rootNodeDocumentEl.setAttribute("xmlns:" + NamespaceService.ALFRESCO_PREFIX, + NamespaceService.ALFRESCO_URI); + rootNodeDocument.appendChild(rootNodeDocumentEl); + + final List result = new ArrayList(resultMap.size()); + for (Map.Entry e : resultMap.entrySet()) + { + final Element documentEl = e.getValue().getDocumentElement(); + documentEl.setAttribute("xmlns:" + NamespaceService.ALFRESCO_PREFIX, + NamespaceService.ALFRESCO_URI); + documentEl.setAttributeNS(NamespaceService.ALFRESCO_URI, + NamespaceService.ALFRESCO_PREFIX + ":file_name", + e.getKey()); + final Node n = rootNodeDocument.importNode(documentEl, true); + rootNodeDocumentEl.appendChild(n); + result.add(n); + } + return result.toArray(new Node[result.size()]); + } + }); + model.put(QName.createQName(NamespaceService.ALFRESCO_PREFIX, + "_getAVMPath", + namespacePrefixResolver), + new RenderingEngine.TemplateProcessorMethod() + { + public Object exec(final Object[] arguments) + { + if (arguments.length != 1) + { + throw new IllegalArgumentException("expected one argument to _getAVMPath. got " + + arguments.length); + } + if (! (arguments[0] instanceof String)) + { + throw new ClassCastException("expected arguments[0] to be a " + String.class.getName() + + ". got a " + arguments[0].getClass().getName() + "."); + } + + final String path = (String)arguments[0]; + LOGGER.debug("tpm_getAVMPAth('" + path + "'), parentPath = " + parentPath); + return AVMConstants.buildPath(parentPath, + path, + AVMConstants.PathRelation.WEBAPP_RELATIVE); + } + }); + + // add the xml document + model.put(RenderingEngine.ROOT_NAMESPACE, formInstanceData.getDocument()); + return model; + } + + protected static FormDataFunctions getFormDataFunctions() + { + final FacesContext fc = FacesContext.getCurrentInstance(); + final WebApplicationContext wac = + FacesContextUtils.getRequiredWebApplicationContext(fc); + return new FormDataFunctions((AVMRemote)wac.getBean("avmRemote")); } private ServiceRegistry getServiceRegistry() diff --git a/source/java/org/alfresco/web/forms/RenditionImpl.java b/source/java/org/alfresco/web/forms/RenditionImpl.java index aafe4c4208..a0ba020bab 100644 --- a/source/java/org/alfresco/web/forms/RenditionImpl.java +++ b/source/java/org/alfresco/web/forms/RenditionImpl.java @@ -161,14 +161,13 @@ public class RenditionImpl this.regenerate(this.getPrimaryFormInstanceData()); } + @Deprecated public void regenerate(final FormInstanceData formInstanceData) throws IOException, RenderingEngine.RenderingException, SAXException { - final RenderingEngineTemplate ret = this.getRenderingEngineTemplate(); - final RenderingEngine engine = ret.getRenderingEngine(); - engine.render(formInstanceData, ret, this); + this.getRenderingEngineTemplate().render(formInstanceData, this); } private ServiceRegistry getServiceRegistry() diff --git a/source/java/org/alfresco/web/forms/XMLUtil.java b/source/java/org/alfresco/web/forms/XMLUtil.java index 4d15a45d03..71f326c0cf 100644 --- a/source/java/org/alfresco/web/forms/XMLUtil.java +++ b/source/java/org/alfresco/web/forms/XMLUtil.java @@ -43,6 +43,7 @@ import org.xml.sax.SAXException; */ public class XMLUtil { + private static final Log LOGGER = LogFactory.getLog(XMLUtil.class); private static DocumentBuilder documentBuilder; diff --git a/source/java/org/alfresco/web/forms/XSLFORenderingEngine.java b/source/java/org/alfresco/web/forms/XSLFORenderingEngine.java index cd0677e0a5..7d0ec6e410 100644 --- a/source/java/org/alfresco/web/forms/XSLFORenderingEngine.java +++ b/source/java/org/alfresco/web/forms/XSLFORenderingEngine.java @@ -22,6 +22,7 @@ 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.namespace.QName; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.fop.apps.FOPException; @@ -86,9 +87,10 @@ public class XSLFORenderingEngine return "fo"; } - public void render(final FormInstanceData formInstanceData, + @Override + public void render(final Map model, final RenderingEngineTemplate ret, - final Rendition rendition) + final OutputStream out) throws IOException, RenderingEngine.RenderingException, SAXException @@ -100,16 +102,14 @@ public class XSLFORenderingEngine throw new RenderingEngine.RenderingException("mimetype " + ret.getMimetypeForRendition() + " is not supported by " + this.getName()); } - final OutputStream out = rendition.getOutputStream(); try { final FopFactory fopFactory = FopFactory.newInstance(); final FOUserAgent foUserAgent = fopFactory.newFOUserAgent(); final Fop fop = fopFactory.newFop(mimetype, foUserAgent, out); // Resulting SAX events (the generated FO) must be piped through to FOP - super.render(new DOMSource(formInstanceData.getDocument()), + super.render(model, ret, - this.getStandardParameters(formInstanceData, rendition), new SAXResult(fop.getDefaultHandler())); } diff --git a/source/java/org/alfresco/web/forms/XSLTRenderingEngine.java b/source/java/org/alfresco/web/forms/XSLTRenderingEngine.java index a1dee73dbb..1a5693adc1 100644 --- a/source/java/org/alfresco/web/forms/XSLTRenderingEngine.java +++ b/source/java/org/alfresco/web/forms/XSLTRenderingEngine.java @@ -35,13 +35,17 @@ import javax.xml.transform.stream.StreamSource; import org.alfresco.service.cmr.repository.ContentService; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.service.namespace.NamespaceService; +import org.alfresco.service.namespace.QName; import org.alfresco.web.bean.wcm.AVMConstants; import org.alfresco.web.forms.XMLUtil; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.xalan.extensions.ExpressionContext; import org.apache.xpath.objects.XObject; -import org.apache.xml.utils.QName; +import org.apache.xml.dtm.ref.DTMNodeProxy; +import org.apache.xml.utils.Constants; +//import org.apache.xml.utils.QName; import org.w3c.dom.*; import org.w3c.dom.traversal.NodeFilter; import org.w3c.dom.traversal.NodeIterator; @@ -55,187 +59,176 @@ import org.apache.bsf.BSFManager; * @author Ariel Backenroth */ public class XSLTRenderingEngine - extends AbstractRenderingEngine + implements RenderingEngine { - private static final Log LOGGER = LogFactory.getLog(XSLTRenderingEngine.class); + ///////////////////////////////////////////////////////////////////////////// - public XSLTRenderingEngine() + public static class ProcessorMethodInvoker { - super(); - } + private final static HashMap PROCESSOR_METHODS = + new HashMap(); + + public ProcessorMethodInvoker() { } - public String getName() - { - return "XSLT"; - } - - public String getDefaultTemplateFileExtension() - { - return "xsl"; - } - - protected static String toAVMPath(final ExpressionContext ec, String path) - throws TransformerException - { - final XObject o = ec.getVariableOrParam(new QName(ALFRESCO_NS, ALFRESCO_NS_PREFIX, "parent_path")); - return o == null ? null : AVMConstants.buildPath(o.toString(), - path, - AVMConstants.PathRelation.WEBAPP_RELATIVE); - } - - /** - * Adapter function used by the xsl tempalte to retrieve an xml asset at the given - * path. - * - * @return the document element for the xml asset at the given path. - */ - public static Node parseXMLDocument(final ExpressionContext ec, final String path) - throws TransformerException, - IOException, - SAXException - { - final FormDataFunctions ef = XSLTRenderingEngine.getFormDataFunctions(); - final Document d = ef.parseXMLDocument(XSLTRenderingEngine.toAVMPath(ec, path)); - return d != null ? d.getDocumentElement() : null; - } - - /** - * Adapter function used by the xsl tempalte to retrieve a xml assets in the - * current directory. - */ - public static NodeIterator parseXMLDocuments(final ExpressionContext ec, - final String formName) - throws TransformerException, - IOException, - SAXException - { - return XSLTRenderingEngine.parseXMLDocuments(ec, formName, ""); - } - - /** - * Adapter function used by the xsl tempalte to retrieve a xml assets at - * the given path. - * - * @return an iterator of the document elements for each of the xml - * assets at the given path. In order to enable xpath expressions to - * properly access siblings, each root element is rooted at a node named - * file-list in the alfresco namespace. - */ - public static NodeIterator parseXMLDocuments(final ExpressionContext ec, - final String formName, - String path) - throws TransformerException, - IOException, - SAXException - { - final FormDataFunctions ef = XSLTRenderingEngine.getFormDataFunctions(); - path = XSLTRenderingEngine.toAVMPath(ec, path); - final Map resultMap = ef.parseXMLDocuments(formName, path); - if (LOGGER.isDebugEnabled()) - LOGGER.debug("received " + resultMap.size() + " documents in " + path); - - // create a root document for rooting all the results. we do this - // so that each document root element has a common parent node - // and so that xpath axes work properly - final Document rootNodeDocument = XMLUtil.newDocument(); - final Element rootNodeDocumentEl = - rootNodeDocument.createElementNS(ALFRESCO_NS, - ALFRESCO_NS_PREFIX + ":file_list"); - rootNodeDocumentEl.setAttribute("xmlns:" + ALFRESCO_NS_PREFIX, ALFRESCO_NS); - rootNodeDocument.appendChild(rootNodeDocumentEl); - - final List documents = new ArrayList(resultMap.size()); - for (Map.Entry mapEntry : resultMap.entrySet()) + private Object[] convertArguments(final Object[] arguments) { - final Element documentEl = mapEntry.getValue().getDocumentElement(); - documentEl.setAttributeNS(ALFRESCO_NS, - ALFRESCO_NS_PREFIX + ":file_name", - mapEntry.getKey()); - final Node n = rootNodeDocument.importNode(documentEl, true); - documents.add(n); - rootNodeDocumentEl.appendChild(n); + final List result = new LinkedList(); + for (int i = 0; i < arguments.length; i++) + { + LOGGER.debug("args[" + i + "] = " + arguments[i] + + "(" + (arguments[i] != null + ? arguments[i].getClass().getName() + : "null") + ")"); + if (arguments[i] == null || + arguments[i] instanceof String || + arguments[i] instanceof Number) + { + result.add(arguments[i]); + } + else if (arguments[i] instanceof DTMNodeProxy) + { + result.add(((DTMNodeProxy)arguments[i]).getStringValue()); + } + else if (arguments[i] instanceof Node) + { + LOGGER.debug("node type is " + ((Node)arguments[i]).getNodeType() + + " content " + ((Node)arguments[i]).getTextContent()); + result.add(((Node)arguments[i]).getNodeValue()); + } + else if (arguments[i] instanceof NodeIterator) + { + Node n = ((NodeIterator)arguments[i]).nextNode(); + while (n != null) + { + LOGGER.debug("iterated to node " + n + " type " + n.getNodeType() + + " value " + n.getNodeValue() + + " tc " + n.getTextContent() + + " nn " + n.getNodeName() + + " sv " + ((org.apache.xml.dtm.ref.DTMNodeProxy)n).getStringValue()); + if (n instanceof DTMNodeProxy) + { + result.add(((DTMNodeProxy)n).getStringValue()); + } + else + { + result.add(n); + } + n = ((NodeIterator)arguments[i]).nextNode(); + } + } + else + { + throw new IllegalArgumentException("unable to convert argument " + arguments[i]); + } + } + + return result.toArray(new Object[result.size()]); } - return new NodeIterator() + public Object invokeMethod(final String id, Object[] arguments) + throws Exception { - private int index = 0; - private boolean detached = false; - - public void detach() - { - if (LOGGER.isDebugEnabled()) - LOGGER.debug("detaching NodeIterator"); - resultMap.clear(); - documents.clear(); - this.detached = true; - } - - public boolean getExpandEntityReferences() - { - return true; + if (!PROCESSOR_METHODS.containsKey(id)) + { + throw new NullPointerException("unable to find method " + id); } - public NodeFilter getFilter() - { - return new NodeFilter() + final TemplateProcessorMethod method = PROCESSOR_METHODS.get(id); + arguments = this.convertArguments(arguments); + LOGGER.debug("invoking " + id + " with " + arguments.length); + + Object result = method.exec(arguments); + LOGGER.debug(id + " returned a " + result); + if (result == null) + { + return null; + } + else if (result.getClass().isArray() && + Node.class.isAssignableFrom(result.getClass().getComponentType())) + { + LOGGER.debug("converting " + result + " to a node iterator"); + final Node[] array = (Node[])result; + return new NodeIterator() { - public short acceptNode(final Node n) + private int index = 0; + private boolean detached = false; + + public void detach() + { + if (LOGGER.isDebugEnabled()) + LOGGER.debug("detaching NodeIterator"); + this.detached = true; + } + + public boolean getExpandEntityReferences() { return true; } + public int getWhatToShow() { return NodeFilter.SHOW_ALL; } + + public Node getRoot() { - return NodeFilter.FILTER_ACCEPT; + return (array.length == 0 + ? null + : array[0].getOwnerDocument().getDocumentElement()); + } + + public NodeFilter getFilter() + { + return new NodeFilter() + { + public short acceptNode(final Node n) + { + return NodeFilter.FILTER_ACCEPT; + } + }; + } + + public Node nextNode() + throws DOMException + { + if (LOGGER.isDebugEnabled()) + LOGGER.debug("NodeIterator.nextNode(" + index + ")"); + if (this.detached) + throw new DOMException(DOMException.INVALID_STATE_ERR, null); + return index == array.length ? null : array[index++]; + } + + public Node previousNode() + throws DOMException + { + if (LOGGER.isDebugEnabled()) + LOGGER.debug("NodeIterator.previousNode(" + index + ")"); + if (this.detached) + throw new DOMException(DOMException.INVALID_STATE_ERR, null); + return index == -1 ? null : array[index--]; } }; } - - public Node getRoot() + else if (result instanceof String || + result instanceof Number || + result instanceof Node) { - return rootNodeDocumentEl; + LOGGER.debug("returning " + result + " as is"); + return result; } - - public int getWhatToShow() + else { - return NodeFilter.SHOW_ALL; + throw new IllegalArgumentException("unable to convert " + result.getClass().getName()); } - - public Node nextNode() - throws DOMException - { - if (LOGGER.isDebugEnabled()) - LOGGER.debug("NodeIterator.nextNode(" + index + ")"); - if (this.detached) - throw new DOMException(DOMException.INVALID_STATE_ERR, null); - if (index == documents.size()) - return null; - return documents.get(index++); - } - - public Node previousNode() - throws DOMException - { - if (LOGGER.isDebugEnabled()) - LOGGER.debug("NodeIterator.previousNode(" + index + ")"); - if (this.detached) - throw new DOMException(DOMException.INVALID_STATE_ERR, null); - if (index == -1) - return null; - return documents.get(index--); - } - }; + } } - /** - * for debugging only. provides the absolute avm path for the given - * path. - */ - public static String _getAVMPath(final ExpressionContext ec, - final String path) - throws TransformerException, - IOException, - SAXException - { - final FormDataFunctions ef = XSLTRenderingEngine.getFormDataFunctions(); - return XSLTRenderingEngine.toAVMPath(ec, path); - } + ///////////////////////////////////////////////////////////////////////////// + + private static final Log LOGGER = LogFactory.getLog(XSLTRenderingEngine.class); + + public static final QName PROP_URI_RESOLVER_BASE_URI = + QName.createQName(NamespaceService.ALFRESCO_URI, "xslt_resolver_base_uri"); + + public XSLTRenderingEngine() { } + + public String getName() { return "XSLT"; } + + public String getDefaultTemplateFileExtension() { return "xsl"; } /** * Adds a script element to the xsl which makes static methods on this @@ -243,22 +236,75 @@ public class XSLTRenderingEngine * * @param xslTemplate the xsl template */ - protected void addScript(final Document xslTemplate) + protected List addScripts(final Map model, + final Document xslTemplate) { + final Map>> methods = + new HashMap>>(); + for (final Map.Entry entry : model.entrySet()) + { + if (entry.getValue() instanceof TemplateProcessorMethod) + { + final String prefix = QName.splitPrefixedQName(entry.getKey().toPrefixString())[0]; + final QName qn = QName.createQName(entry.getKey().getNamespaceURI(), + prefix); + if (!methods.containsKey(qn)) + { + methods.put(qn, new LinkedList()); + } + methods.get(qn).add(entry); + } + } + final Element docEl = xslTemplate.getDocumentElement(); - final String XALAN_NS = "http://xml.apache.org/xalan"; + final String XALAN_NS = Constants.S_BUILTIN_EXTENSIONS_URL; final String XALAN_NS_PREFIX = "xalan"; docEl.setAttribute("xmlns:" + XALAN_NS_PREFIX, XALAN_NS); - docEl.setAttribute("xmlns:" + ALFRESCO_NS_PREFIX, ALFRESCO_NS); - - final Element compEl = xslTemplate.createElementNS(XALAN_NS, XALAN_NS_PREFIX + ":component"); - compEl.setAttribute("prefix", "alfresco"); - docEl.appendChild(compEl); - final Element scriptEl = xslTemplate.createElementNS(XALAN_NS, XALAN_NS_PREFIX + ":script"); - scriptEl.setAttribute("lang", "javaclass"); - scriptEl.setAttribute("src", XALAN_NS_PREFIX + "://" + this.getClass().getName()); - compEl.appendChild(scriptEl); + final List result = new LinkedList(); + for (QName ns : methods.keySet()) + { + final String prefix = ns.getLocalName(); + docEl.setAttribute("xmlns:" + prefix, ns.getNamespaceURI()); + + final Element compEl = xslTemplate.createElementNS(XALAN_NS, + XALAN_NS_PREFIX + ":component"); + compEl.setAttribute("prefix", prefix); + docEl.appendChild(compEl); + String functionNames = null; + final Element scriptEl = xslTemplate.createElementNS(XALAN_NS, + XALAN_NS_PREFIX + ":script"); + scriptEl.setAttribute("lang", "javascript"); + final StringBuilder js = + new StringBuilder("var _xsltp_invoke = java.lang.Class.forName('" + ProcessorMethodInvoker.class.getName() + + "').newInstance();\n" + + "function _xsltp_to_java_array(js_array) {\n" + + "var java_array = java.lang.reflect.Array.newInstance(java.lang.Object, js_array.length);\n" + + "for (var i = 0; i < js_array.length; i++) { java_array[i] = js_array[i]; }\n" + + "return java_array; }\n"); + for (final Map.Entry entry : methods.get(ns)) + { + if (functionNames == null) + { + functionNames = entry.getKey().getLocalName(); + } + else + { + functionNames += " " + entry.getKey().getLocalName(); + } + final String id = entry.getKey().getLocalName() + entry.getValue().hashCode(); + js.append("function " + entry.getKey().getLocalName() + + "() { return _xsltp_invoke.invokeMethod('" + id + + "', _xsltp_to_java_array(arguments)); }\n"); + ProcessorMethodInvoker.PROCESSOR_METHODS.put(id, (TemplateProcessorMethod)entry.getValue()); + result.add(id); + } + LOGGER.debug("generated JavaScript bindings:\n" + js); + scriptEl.appendChild(xslTemplate.createTextNode(js.toString())); + compEl.setAttribute("functions", functionNames); + compEl.appendChild(scriptEl); + } + return result; } /** @@ -268,47 +314,58 @@ public class XSLTRenderingEngine * @param parameters the variables to place within the xsl template * @param xslTemplate the xsl template */ - protected void addParameters(final Map parameters, - final Document xslTemplate) + protected void addParameters(final Map model, + final Document xslTemplate) { final Element docEl = xslTemplate.getDocumentElement(); final String XSL_NS = docEl.getNamespaceURI(); final String XSL_NS_PREFIX = docEl.getPrefix(); - for (Map.Entry e : parameters.entrySet()) + for (Map.Entry e : model.entrySet()) { + if (RenderingEngine.ROOT_NAMESPACE.equals(e.getKey())) + { + continue; + } final Element el = xslTemplate.createElementNS(XSL_NS, XSL_NS_PREFIX + ":variable"); - el.setAttribute("name", ALFRESCO_NS_PREFIX + ':' + e.getKey()); - el.appendChild(xslTemplate.createTextNode(e.getValue())); - docEl.insertBefore(el, docEl.getFirstChild()); + el.setAttribute("name", e.getKey().toPrefixString()); + final Object o = e.getValue(); + if (o instanceof String || o instanceof Number || o instanceof Boolean) + { + el.appendChild(xslTemplate.createTextNode(o.toString())); + docEl.insertBefore(el, docEl.getFirstChild()); + } } } + + protected Source getXMLSource(final Map model) + { + if (!model.containsKey(RenderingEngine.ROOT_NAMESPACE)) + { + return null; + } + final Object o = model.get(RenderingEngine.ROOT_NAMESPACE); + if (!(o instanceof Document)) + { + throw new IllegalArgumentException("expected root namespace object to be a " + Document.class.getName() + + ". found a " + o.getClass().getName()); + } + return new DOMSource((Document)o); + } - public void render(final FormInstanceData formInstanceData, + public void render(final Map model, final RenderingEngineTemplate ret, - final Rendition rendition) + final OutputStream out) throws IOException, RenderingEngine.RenderingException, SAXException { - final OutputStream out = rendition.getOutputStream(); - try - { - this.render(new DOMSource(formInstanceData.getDocument()), - ret, - this.getStandardParameters(formInstanceData, rendition), - new StreamResult(out)); - } - finally - { - out.close(); - } + this.render(model, ret, new StreamResult(out)); } - protected void render(final Source formInstanceDataSource, - final RenderingEngineTemplate ret, - final Map parameters, - final Result result) + public void render(final Map model, + final RenderingEngineTemplate ret, + final Result result) throws IOException, RenderingEngine.RenderingException, SAXException @@ -324,8 +381,10 @@ public class XSLTRenderingEngine { throw new RenderingEngine.RenderingException(sax); } - this.addScript(xslTemplate); - this.addParameters(parameters, xslTemplate); + this.addScripts(model, xslTemplate); + this.addParameters(model, xslTemplate); + + Source xmlSource = this.getXMLSource(model); Transformer t = null; try @@ -344,21 +403,25 @@ public class XSLTRenderingEngine // web application t.setURIResolver(new URIResolver() { - public Source resolve(final String href, final String base) + public Source resolve(final String href, String base) throws TransformerException { - // XXXarielb - dirty - fix this - final String sandBoxUrl = (String)parameters.get("avm_sandbox_url"); - + LOGGER.debug("request to resolve href " + href + + " using base " + base); + if (model.containsKey(PROP_URI_RESOLVER_BASE_URI)) + { + base = (String)model.get(PROP_URI_RESOLVER_BASE_URI); + LOGGER.debug("overriding base with " + base); + } + URI uri = null; try { - uri = new URI(sandBoxUrl + href); + uri = new URI(base + href); } catch (URISyntaxException e) { - throw new TransformerException("unable to create uri " + - sandBoxUrl + href, + throw new TransformerException("unable to create uri " + base + href, e); } try @@ -379,11 +442,16 @@ public class XSLTRenderingEngine try { - t.transform(formInstanceDataSource, result); + t.transform(xmlSource, result); } - catch (TransformerException e) + catch (TransformerException te) { - LOGGER.error(e.getMessageAndLocation()); + LOGGER.error(te.getMessageAndLocation()); + throw new RenderingEngine.RenderingException(te); + } + catch (Exception e) + { + LOGGER.error("unexpected error " + e); throw new RenderingEngine.RenderingException(e); } } diff --git a/source/java/org/alfresco/web/forms/xforms/SchemaFormBuilder.java b/source/java/org/alfresco/web/forms/xforms/SchemaFormBuilder.java index cf31507371..1698ce73b9 100644 --- a/source/java/org/alfresco/web/forms/xforms/SchemaFormBuilder.java +++ b/source/java/org/alfresco/web/forms/xforms/SchemaFormBuilder.java @@ -21,6 +21,7 @@ import java.io.IOException; import java.io.StringWriter; import java.util.*; import javax.xml.transform.*; +import org.alfresco.service.namespace.NamespaceService; import org.alfresco.web.forms.XMLUtil; import org.apache.commons.jxpath.JXPathContext; import org.apache.commons.jxpath.Pointer; @@ -70,16 +71,7 @@ public class SchemaFormBuilder ///////////////////////////////////////////////////////////////////////////// - public final static Log LOGGER = - LogFactory.getLog(SchemaFormBuilder.class); - - - /** Alfresco namespace declaration. */ - private static final String ALFRESCO_NS = - "http://www.alfresco.org/alfresco"; - - /** Alfresco prefix */ - private static final String ALFRESCO_PREFIX = "alfresco"; + private final static Log LOGGER = LogFactory.getLog(SchemaFormBuilder.class); private static final String PROPERTY_PREFIX = "http://www.chiba.org/properties/schemaFormBuilder/"; @@ -433,10 +425,12 @@ public class SchemaFormBuilder { final JXPathContext prototypeContext = JXPathContext.newContext(prototypeDocumentElement); - prototypeContext.registerNamespace("alfresco", SchemaFormBuilder.ALFRESCO_NS); + prototypeContext.registerNamespace(NamespaceService.ALFRESCO_PREFIX, + NamespaceService.ALFRESCO_URI); final JXPathContext instanceContext = JXPathContext.newContext(instanceDocumentElement); - instanceContext.registerNamespace("alfresco", SchemaFormBuilder.ALFRESCO_NS); + instanceContext.registerNamespace(NamespaceService.ALFRESCO_PREFIX, + NamespaceService.ALFRESCO_URI); class PrototypeInsertionData { @@ -457,7 +451,7 @@ public class SchemaFormBuilder new LinkedList(); final Iterator it = - prototypeContext.iteratePointers("//*[@" + SchemaFormBuilder.ALFRESCO_PREFIX + + prototypeContext.iteratePointers("//*[@" + NamespaceService.ALFRESCO_PREFIX + ":prototype='true']"); while (it.hasNext()) { @@ -528,11 +522,11 @@ public class SchemaFormBuilder { for (Element e : l) { - if (e.hasAttributeNS(SchemaFormBuilder.ALFRESCO_NS, "prototype")) + if (e.hasAttributeNS(NamespaceService.ALFRESCO_URI, "prototype")) { - assert "true".equals(e.getAttributeNS(SchemaFormBuilder.ALFRESCO_NS, + assert "true".equals(e.getAttributeNS(NamespaceService.ALFRESCO_URI, "prototype")); - e.removeAttributeNS(SchemaFormBuilder.ALFRESCO_NS, "prototype"); + e.removeAttributeNS(NamespaceService.ALFRESCO_URI, "prototype"); if (l.getLast().equals(e)) { @@ -1687,8 +1681,8 @@ public class SchemaFormBuilder final Element e = (Element)newDefaultInstanceElement.cloneNode(true); if (i == elementOccurs.minimum) { - e.setAttributeNS(SchemaFormBuilder.ALFRESCO_NS, - SchemaFormBuilder.ALFRESCO_PREFIX + ":prototype", + e.setAttributeNS(NamespaceService.ALFRESCO_URI, + NamespaceService.ALFRESCO_PREFIX + ":prototype", "true"); } defaultInstanceElement.appendChild(e); @@ -1990,7 +1984,7 @@ public class SchemaFormBuilder formControl.appendChild(alertElement); this.setXFormsId(alertElement); - String alert = SchemaFormBuilder.extractPropertyFromAnnotation(ALFRESCO_NS, + String alert = SchemaFormBuilder.extractPropertyFromAnnotation(NamespaceService.ALFRESCO_URI, "alert", this.getAnnotation(owner), resourceBundle); @@ -2082,8 +2076,8 @@ public class SchemaFormBuilder NamespaceConstants.XMLSCHEMA_INSTANCE_PREFIX, NamespaceConstants.XMLSCHEMA_INSTANCE_NS); this.addNamespace(envelopeElement, - SchemaFormBuilder.ALFRESCO_PREFIX, - SchemaFormBuilder.ALFRESCO_NS); + NamespaceService.ALFRESCO_PREFIX, + NamespaceService.ALFRESCO_URI); //base if (this.base != null && this.base.length() != 0) @@ -2150,7 +2144,7 @@ public class SchemaFormBuilder final XSAnnotation annotation, final ResourceBundle resourceBundle) { - final String s = SchemaFormBuilder.extractPropertyFromAnnotation(ALFRESCO_NS, + final String s = SchemaFormBuilder.extractPropertyFromAnnotation(NamespaceService.ALFRESCO_URI, "label", annotation, resourceBundle); @@ -2540,7 +2534,7 @@ public class SchemaFormBuilder final XSAnnotation annotation = this.getAnnotation(node); if (annotation == null) return null; - final String s = this.extractPropertyFromAnnotation(ALFRESCO_NS, + final String s = this.extractPropertyFromAnnotation(NamespaceService.ALFRESCO_URI, "hint", annotation, resourceBundle); @@ -2666,16 +2660,16 @@ public class SchemaFormBuilder { //if 0 or 1 -> no constraint (managed by "required") minConstraint = "count(.) >= " + o.minimum; - bindElement.setAttributeNS(ALFRESCO_NS, - ALFRESCO_PREFIX + ":minimum", + bindElement.setAttributeNS(NamespaceService.ALFRESCO_URI, + NamespaceService.ALFRESCO_PREFIX + ":minimum", String.valueOf(o.minimum)); } if (o.maximum > 1) { //if 1 or unbounded -> no constraint maxConstraint = "count(.) <= " + o.maximum; - bindElement.setAttributeNS(ALFRESCO_NS, - ALFRESCO_PREFIX + ":maximum", + bindElement.setAttributeNS(NamespaceService.ALFRESCO_URI, + NamespaceService.ALFRESCO_PREFIX + ":maximum", String.valueOf(o.maximum)); } diff --git a/source/java/org/alfresco/web/forms/xforms/XFormsProcessor.java b/source/java/org/alfresco/web/forms/xforms/XFormsProcessor.java index 8fc179abf6..ff41aa9b1e 100644 --- a/source/java/org/alfresco/web/forms/xforms/XFormsProcessor.java +++ b/source/java/org/alfresco/web/forms/xforms/XFormsProcessor.java @@ -20,6 +20,7 @@ import java.io.*; import javax.faces.context.FacesContext; import javax.servlet.http.HttpServletRequest; +import org.alfresco.service.namespace.NamespaceService; import org.alfresco.web.forms.*; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -28,6 +29,7 @@ import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.alfresco.web.app.servlet.FacesHelper; +import org.chiba.xml.ns.NamespaceConstants; import org.chiba.xml.xforms.exception.XFormsException; public class XFormsProcessor @@ -36,6 +38,26 @@ public class XFormsProcessor private static final Log LOGGER = LogFactory.getLog(XFormsProcessor.class); + private final static String[][] JS_NAMESPACES = + { + { "xforms", NamespaceConstants.XFORMS_NS, NamespaceConstants.XFORMS_PREFIX }, + { "xhtml", NamespaceConstants.XHTML_NS, NamespaceConstants.XHTML_PREFIX }, + { "chiba", NamespaceConstants.CHIBA_NS, NamespaceConstants.CHIBA_PREFIX }, + { "alfresco", NamespaceService.ALFRESCO_URI, NamespaceService.ALFRESCO_PREFIX } + }; + + private final String[] JS_SCRIPTS = + { + "/scripts/tiny_mce/" + (LOGGER.isDebugEnabled() + ? "tiny_mce_src.js" + : "tiny_mce.js"), + "/scripts/ajax/dojo/" + (LOGGER.isDebugEnabled() + ? "dojo.js.uncompressed.js" + : "dojo.js"), + "/scripts/ajax/xforms.js" + }; + + public XFormsProcessor() { } @@ -77,44 +99,51 @@ public class XFormsProcessor throw new ProcessingException(xfe); } - final String cp = fc.getExternalContext().getRequestContextPath(); + final String contextPath = fc.getExternalContext().getRequestContextPath(); final Document result = XMLUtil.newDocument(); + final String xformsUIDivId = "alfresco-xforms-ui"; // this div is where the ui will write to final Element div = result.createElement("div"); - div.setAttribute("id", "alfresco-xforms-ui"); + div.setAttribute("id", xformsUIDivId); result.appendChild(div); Element e = result.createElement("link"); e.setAttribute("rel", "stylesheet"); e.setAttribute("type", "text/css"); - e.setAttribute("href", cp + "/css/xforms.css"); + e.setAttribute("href", contextPath + "/css/xforms.css"); div.appendChild(e); // a script with config information and globals. e = result.createElement("script"); e.setAttribute("type", "text/javascript"); - e.appendChild(result.createTextNode("\ndjConfig = { isDebug: " + LOGGER.isDebugEnabled() + - " };\n" + - "var WEBAPP_CONTEXT = \"" + cp + "\";\n")); + final StringBuilder js = new StringBuilder("\ndjConfig = {isDebug:" + LOGGER.isDebugEnabled() + "};\n"); + js.append("var alfresco_xforms_constants = {};\n"); + js.append("alfresco_xforms_constants.WEBAPP_CONTEXT = '"). + append(contextPath). + append("';\n"); + js.append("alfresco_xforms_constants.XFORMS_UI_DIV_ID = '"). + append(xformsUIDivId). + append("';\n"); + for (String[] ns : JS_NAMESPACES) + { + js.append("alfresco_xforms_constants."). + append(ns[0].toUpperCase()). + append("_NS = '").append(ns[1]).append("';\n"); + js.append("alfresco_xforms_constants."). + append(ns[0].toUpperCase()). + append("_PREFIX = '").append(ns[2]).append("';\n"); + } + e.appendChild(result.createTextNode(js.toString())); + div.appendChild(e); - final String[] scripts = - { - "/scripts/tiny_mce/" + (LOGGER.isDebugEnabled() - ? "tiny_mce_src.js" - : "tiny_mce.js"), - "/scripts/ajax/dojo/" + (LOGGER.isDebugEnabled() - ? "dojo.js.uncompressed.js" - : "dojo.js"), - "/scripts/ajax/xforms.js" - }; // include all our scripts, order is significant - for (int i = 0; i < scripts.length; i++) + for (final String script : JS_SCRIPTS) { e = result.createElement("script"); e.setAttribute("type", "text/javascript"); - e.setAttribute("src", cp + scripts[i]); + e.setAttribute("src", contextPath + script); e.appendChild(result.createTextNode("\n")); div.appendChild(e); } diff --git a/source/java/org/alfresco/web/ui/wcm/component/UIFormProcessor.java b/source/java/org/alfresco/web/ui/wcm/component/UIFormProcessor.java index 5e678fd3e2..990b776fde 100644 --- a/source/java/org/alfresco/web/ui/wcm/component/UIFormProcessor.java +++ b/source/java/org/alfresco/web/ui/wcm/component/UIFormProcessor.java @@ -25,8 +25,6 @@ import javax.faces.el.ValueBinding; import org.alfresco.web.forms.*; import org.alfresco.web.ui.common.Utils; import org.alfresco.web.ui.common.component.SelfRenderingComponent; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; import org.w3c.dom.Document; /** @@ -34,8 +32,6 @@ import org.w3c.dom.Document; */ public class UIFormProcessor extends SelfRenderingComponent { - private static final Log LOGGER = LogFactory.getLog(UIFormProcessor.class); - private Document formInstanceData = null; private Form form = null; diff --git a/source/java/org/alfresco/web/ui/wcm/tag/FormProcessorTag.java b/source/java/org/alfresco/web/ui/wcm/tag/FormProcessorTag.java index 2c5ae44f2a..d5e5db2f52 100644 --- a/source/java/org/alfresco/web/ui/wcm/tag/FormProcessorTag.java +++ b/source/java/org/alfresco/web/ui/wcm/tag/FormProcessorTag.java @@ -29,7 +29,7 @@ public class FormProcessorTag extends BaseComponentTag { private String formInstanceData; - private String templateType; + private String form; private String formProcessorSession; /** @@ -61,10 +61,10 @@ public class FormProcessorTag extends BaseComponentTag final ValueBinding vb = app.createValueBinding(this.formInstanceData); component.setValueBinding("formInstanceData", vb); } - if (this.templateType != null) + if (this.form != null) { - assert this.isValueReference(this.templateType); - final ValueBinding vb = app.createValueBinding(this.templateType); + assert this.isValueReference(this.form); + final ValueBinding vb = app.createValueBinding(this.form); component.setValueBinding("form", vb); } if (this.formProcessorSession != null) @@ -82,7 +82,7 @@ public class FormProcessorTag extends BaseComponentTag { super.release(); this.formInstanceData = null; - this.templateType = null; + this.form = null; this.formProcessorSession = null; } @@ -99,11 +99,11 @@ public class FormProcessorTag extends BaseComponentTag /** * Sets the tempalte type * - * @param templateType the tempalteType for the processor. + * @param form the tempalteType for the processor. */ - public void setForm(final String templateType) + public void setForm(final String form) { - this.templateType = templateType; + this.form = form; } /** diff --git a/source/test-resources/websites/alfresco/ROOT/media/releases/get_company_footer_choices_simple_type.jsp b/source/test-resources/websites/alfresco/ROOT/media/releases/get_company_footer_choices_simple_type.jsp index bfd325a692..de56060252 100644 --- a/source/test-resources/websites/alfresco/ROOT/media/releases/get_company_footer_choices_simple_type.jsp +++ b/source/test-resources/websites/alfresco/ROOT/media/releases/get_company_footer_choices_simple_type.jsp @@ -52,7 +52,7 @@ which wants to update the list of available company footers dynamically. --> @@ -65,7 +65,7 @@ which wants to update the list of available company footers dynamically. - + diff --git a/source/test-resources/xforms/unit-tests/output-method-callout-test/output-method-callout.ftl b/source/test-resources/xforms/unit-tests/output-method-callout-test/output-method-callout.ftl index 0ae0cde40d..3e20f0bf11 100644 --- a/source/test-resources/xforms/unit-tests/output-method-callout-test/output-method-callout.ftl +++ b/source/test-resources/xforms/unit-tests/output-method-callout-test/output-method-callout.ftl @@ -1,4 +1,4 @@ -<#ftl ns_prefixes={"alfresco", "http://www.alfresco.org/alfresco"}> +<#ftl ns_prefixes={"alf", "http://www.alfresco.org"}> Simple Test - +
Generated by output-method-callout.xsl
+ +
+ <xsl:value-of select="$alf:avm_sandbox_url"/> +
+
- <xsl:value-of select="$alfresco:avm_sandbox_url"/> + <xsl:value-of select="$alf:form_instance_data_file_name"/>
- +
- <xsl:value-of select="$alfresco:form_instance_data_file_name"/> + <xsl:value-of select="$alf:rendition_file_name"/>
- +
- <xsl:value-of select="$alfresco:rendition_file_name"/> + <xsl:value-of select="$alf:parent_path"/>
- +
- <xsl:value-of select="$alfresco:parent_path"/> + <xsl:value-of select="$alf:request_context_path"/>
- +
- <xsl:value-of select="$alfresco:request_context_path"/> + <xsl:value-of select="$alf:request_context_path"/><xsl:value-of select="/simple/uri"/>
- +
- <xsl:value-of select="$alfresco:request_context_path"/><xsl:value-of select="/simple/uri"/> + <xsl:value-of select="alf:_getAVMPath('foo')"/>
- +
- <xsl:value-of select="alfresco:_getAVMPath('foo')"/> + <xsl:value-of select="alf:_getAVMPath('/foo')"/>
- - -
- <xsl:value-of select="alfresco:_getAVMPath('/foo')"/> -
- +
My value accessed using /simple/string:
-
My value accessed using alfresco:parseXMLDocument($alfresco:form_instance_data_file_name):
- -
Values from xml files generated by in :
+ +
My value accessed using alf:parseXMLDocument($alf:form_instance_data_file_name):
+ + +
My value accessed using document(concat('/', $alf:form_instance_data_file_name)):
+ + +
Values from xml files generated by in :
    - +
  • - <xsl:value-of select="@alfresco:file_name"/> = <xsl:value-of select="string"/> + <xsl:value-of select="@alf:file_name"/> = <xsl:value-of select="string"/>
    - = + =
  • diff --git a/source/web/css/main.css b/source/web/css/main.css index f2228ebe6b..9f6d5d1399 100644 --- a/source/web/css/main.css +++ b/source/web/css/main.css @@ -628,4 +628,20 @@ a.topToolbarLinkHighlight, a.topToolbarLinkHighlight:link, a.topToolbarLinkHighl height: 330px; width: 220px; overflow: auto; -} \ No newline at end of file +} + +.panelGridRequiredImageColumn +{ + width: 20px; +} + +.panelGridLabelColumn +{ + white-space: nowrap; + width: 25%; +} + +.panelGridValueColumn +{ + width: 100%; +} diff --git a/source/web/jsp/wcm/create-form-wizard/configure-rendering-engines.jsp b/source/web/jsp/wcm/create-form-wizard/configure-rendering-engines.jsp index ee7ba34446..4c9180d8d2 100644 --- a/source/web/jsp/wcm/create-form-wizard/configure-rendering-engines.jsp +++ b/source/web/jsp/wcm/create-form-wizard/configure-rendering-engines.jsp @@ -48,6 +48,7 @@ escape="false" /> width="100%"> @@ -93,6 +94,7 @@ escape="false" /> width="100%"> - - - + columns="2" cellspacing="1" border="0"> + + + - + diff --git a/source/web/jsp/wcm/create-form-wizard/details.jsp b/source/web/jsp/wcm/create-form-wizard/details.jsp index bc1423717d..c82afe71ab 100644 --- a/source/web/jsp/wcm/create-form-wizard/details.jsp +++ b/source/web/jsp/wcm/create-form-wizard/details.jsp @@ -94,8 +94,12 @@ escape="false" /> - + columns="3" + cellpadding="3" + cellspacing="3" + border="0" + width="100%" + columnClasses="panelGridRequiredImageColumn,panelGridLabelColumn,panelGridValueColumn"> + columns="3" + cellpadding="3" + cellspacing="3" + border="0" + columnClasses="panelGridRequiredImageColumn,panelGridLabelColumn,panelGridValueColumn"> + width="100%"> function apply_default_workflow_changed(value) { -document.getElementById("wizard:wizard-body:sdw-pg-2").style.display = value == 'true' ? "block" : "none"; + document.getElementById("wizard:wizard-body:sdw-pg-2").style.display = value == 'true' ? "block" : "none"; } @@ -37,12 +37,13 @@ document.getElementById("wizard:wizard-body:sdw-pg-2").style.display = value == +
     
    + style="margin:5px 0px;height:108px;*height:112px;width:100%;overflow:auto" class="selectListTable"> ${msg.description}: - <${msg.value_not_set}> + ${msg.description_not_set} ${WizardManager.bean.formDescription} @@ -76,7 +76,7 @@
    ${msg.description}: - <${msg.value_not_set}> + ${msg.description_not_set} ${ret.description} diff --git a/source/web/jsp/workflow/manage-task-dialog.jsp b/source/web/jsp/workflow/manage-task-dialog.jsp index 381473fa95..784032f721 100644 --- a/source/web/jsp/workflow/manage-task-dialog.jsp +++ b/source/web/jsp/workflow/manage-task-dialog.jsp @@ -98,6 +98,7 @@ + diff --git a/source/web/scripts/ajax/xforms.js b/source/web/scripts/ajax/xforms.js index f2505e5b7b..03c7885c13 100644 --- a/source/web/scripts/ajax/xforms.js +++ b/source/web/scripts/ajax/xforms.js @@ -4,19 +4,16 @@ dojo.require("dojo.widget.Button"); dojo.require("dojo.lfx.html"); dojo.hostenv.writeIncludes(); -var XFORMS_NS = "http://www.w3.org/2002/xforms"; -var XFORMS_PREFIX = "xf"; -var XHTML_NS = "http://www.w3.org/1999/xhtml"; -var XHTML_NS_PREFIX = "xhtml"; -var CHIBA_NS = "http://chiba.sourceforge.net/xforms"; -var CHIBA_NS_PREFIX = "chiba"; -var ALFRESCO_NS = "http://www.alfresco.org/alfresco"; -var ALFRESCO_NS_PREFIX = "alfresco"; +alfresco_xforms_constants.XFORMS_ERROR_DIV_ID = "alfresco-xforms-error"; +alfresco_xforms_constants.AJAX_LOADER_DIV_ID = "alfresco-ajax-loader"; -var EXPANDED_IMAGE = new Image(); -EXPANDED_IMAGE.src = WEBAPP_CONTEXT + "/images/icons/expanded.gif"; -var COLLAPSED_IMAGE = new Image(); -COLLAPSED_IMAGE.src = WEBAPP_CONTEXT + "/images/icons/collapsed.gif"; +alfresco_xforms_constants.EXPANDED_IMAGE = new Image(); +alfresco_xforms_constants.EXPANDED_IMAGE.src = + alfresco_xforms_constants.WEBAPP_CONTEXT + "/images/icons/expanded.gif"; + +alfresco_xforms_constants.COLLAPSED_IMAGE = new Image(); +alfresco_xforms_constants.COLLAPSED_IMAGE.src = + alfresco_xforms_constants.WEBAPP_CONTEXT + "/images/icons/collapsed.gif"; function _xforms_init() { @@ -146,7 +143,10 @@ dojo.declare("alfresco.xforms.Widget", this.xform.getInstance(), XPathResult.FIRST_ORDERED_NODE_TYPE); if (!result) - throw new Error("unable to resolve xpath /" + xpath + " for " + this.id); + { + dojo.debug("unable to resolve xpath /" + xpath + " for " + this.id); + return null; + } result = (result.nodeType == dojo.dom.ELEMENT_NODE ? dojo.dom.textContent(result) : result.nodeValue); @@ -157,15 +157,18 @@ dojo.declare("alfresco.xforms.Widget", { var binding = this.xform.getBinding(this.xformsNode); var xpath = ''; + var repeatIndices = this.getRepeatIndices(); do { var s = binding.nodeset; if (binding.nodeset == '.') { binding = binding.parent; - var repeatIndices = this.getRepeatIndices(); + } + if (binding.nodeset.match(/.+\[.+\]/)) + { s = binding.nodeset.replace(/([^\[]+)\[.*/, "$1"); - s += '[' + (repeatIndices.pop().index + 1) + ']'; + s += '[' + (repeatIndices.shift().index + 1) + ']'; } xpath = s + (xpath.length != 0 ? '/' + xpath : ""); binding = binding.parent; @@ -175,7 +178,10 @@ dojo.declare("alfresco.xforms.Widget", }, _getLabelNode: function() { - var labels = _getElementsByTagNameNS(this.xformsNode, XFORMS_NS, XFORMS_PREFIX, "label"); + var labels = _getElementsByTagNameNS(this.xformsNode, + alfresco_xforms_constants.XFORMS_NS, + alfresco_xforms_constants.XFORMS_PREFIX, + "label"); for (var i = 0; i < labels.length; i++) { if (labels[i].parentNode == this.xformsNode) @@ -185,7 +191,10 @@ dojo.declare("alfresco.xforms.Widget", }, _getAlertNode: function() { - var labels = _getElementsByTagNameNS(this.xformsNode, XFORMS_NS, XFORMS_PREFIX, "alert"); + var labels = _getElementsByTagNameNS(this.xformsNode, + alfresco_xforms_constants.XFORMS_NS, + alfresco_xforms_constants.XFORMS_PREFIX, + "alert"); for (var i = 0; i < labels.length; i++) { if (labels[i].parentNode == this.xformsNode) @@ -461,12 +470,21 @@ dojo.declare("alfresco.xforms.AbstractSelectWidget", getValues: function() { var binding = this.xform.getBinding(this.xformsNode); - var values = _getElementsByTagNameNS(this.xformsNode, XFORMS_NS, XFORMS_PREFIX, "item"); + var values = _getElementsByTagNameNS(this.xformsNode, + alfresco_xforms_constants.XFORMS_NS, + alfresco_xforms_constants.XFORMS_PREFIX, + "item"); var result = []; for (var v = 0; v < values.length; v++) { - var label = _getElementsByTagNameNS(values[v], XFORMS_NS, XFORMS_PREFIX, "label")[0]; - var value = _getElementsByTagNameNS(values[v], XFORMS_NS, XFORMS_PREFIX, "value")[0]; + var label = _getElementsByTagNameNS(values[v], + alfresco_xforms_constants.XFORMS_NS, + alfresco_xforms_constants.XFORMS_PREFIX, + "label")[0]; + var value = _getElementsByTagNameNS(values[v], + alfresco_xforms_constants.XFORMS_NS, + alfresco_xforms_constants.XFORMS_PREFIX, + "value")[0]; var valid = true; if (binding.constraint) { @@ -721,13 +739,19 @@ dojo.declare("alfresco.xforms.Group", setShowHeader: function(showHeader) { if (showHeader == this.showHeader) + { return; + } this.showHeader = showHeader; if (this.showHeader && this.groupHeaderNode.style.display == "none") + { this.groupHeaderNode.style.display = "block"; + } if (!this.showHeader && this.groupHeaderNode.style.display == "block") + { this.groupHeaderNode.style.display = "none"; + } }, getWidgetsInvalidForSubmit: function() { @@ -753,7 +777,9 @@ dojo.declare("alfresco.xforms.Group", " is " + this.children[i].id + " the same as " + child.id + "?"); if (this.children[i] == child) + { return i; + } } return -1; }, @@ -775,7 +801,9 @@ dojo.declare("alfresco.xforms.Group", child.domContainer.style.top = "0px"; if (this.parent && this.parent.domNode) + { child.domContainer.style.top = this.parent.domNode.style.bottom; + } if (position == this.children.length) { @@ -792,7 +820,8 @@ dojo.declare("alfresco.xforms.Group", if (!(child instanceof alfresco.xforms.Group)) { var requiredImage = document.createElement("img"); - requiredImage.setAttribute("src", WEBAPP_CONTEXT + "/images/icons/required_field.gif"); + requiredImage.setAttribute("src", + alfresco_xforms_constants.WEBAPP_CONTEXT + "/images/icons/required_field.gif"); requiredImage.style.marginLeft = "5px"; requiredImage.style.marginRight = "5px"; child.domContainer.appendChild(requiredImage); @@ -893,12 +922,15 @@ dojo.declare("alfresco.xforms.Group", this.toggleExpandedImage = document.createElement("img"); this.groupHeaderNode.appendChild(this.toggleExpandedImage); - this.toggleExpandedImage.setAttribute("src", EXPANDED_IMAGE.src); + this.toggleExpandedImage.setAttribute("src", alfresco_xforms_constants.EXPANDED_IMAGE.src); this.toggleExpandedImage.align = "absmiddle"; this.toggleExpandedImage.style.marginLeft = "5px"; this.toggleExpandedImage.style.marginRight = "5px"; - dojo.event.connect(this.toggleExpandedImage, "onclick", this, this._toggleExpanded_clickHandler); + dojo.event.connect(this.toggleExpandedImage, + "onclick", + this, + this._toggleExpanded_clickHandler); this.groupHeaderNode.appendChild(document.createTextNode(this.getLabel())); @@ -910,14 +942,18 @@ dojo.declare("alfresco.xforms.Group", }, isExpanded: function() { - return this.toggleExpandedImage.getAttribute("src") == EXPANDED_IMAGE.src; + return this.toggleExpandedImage.getAttribute("src") == alfresco_xforms_constants.EXPANDED_IMAGE.src; }, setExpanded: function(expanded) { - if (expanded == this.isExpanded()) - return; - this.toggleExpandedImage.src = expanded ? EXPANDED_IMAGE.src : COLLAPSED_IMAGE.src; - this.domNode.childContainerNode.style.display = expanded ? "block" : "none"; + if (expanded != this.isExpanded()) + { + this.toggleExpandedImage.src = + (expanded + ? alfresco_xforms_constants.EXPANDED_IMAGE.src + : alfresco_xforms_constants.COLLAPSED_IMAGE.src); + this.domNode.childContainerNode.style.display = expanded ? "block" : "none"; + } }, _toggleExpanded_clickHandler: function(event) { @@ -995,18 +1031,19 @@ dojo.declare("alfresco.xforms.Repeat", insertChildAt: function(child, position) { this.repeatControls.splice(position, 0, document.createElement("div")); - var images = [ - { name: "insertRepeatItemImage", src: "plus", action: this._insertRepeatItemAfter_handler }, - { name: "moveRepeatItemUpImage", src: "arrow_up", action: this._moveRepeatItemUp_handler }, - { name: "moveRepeatItemDownImage", src: "arrow_down", action: this._moveRepeatItemDown_handler }, - { name: "removeRepeatItemImage", src: "minus", action: this._removeRepeatItem_handler } + var images = + [ + { name: "insertRepeatItemImage", src: "plus", action: this._insertRepeatItemAfter_handler }, + { name: "moveRepeatItemUpImage", src: "arrow_up", action: this._moveRepeatItemUp_handler }, + { name: "moveRepeatItemDownImage", src: "arrow_down", action: this._moveRepeatItemDown_handler }, + { name: "removeRepeatItemImage", src: "minus", action: this._removeRepeatItem_handler } ]; var repeatControlsWidth = 0; for (var i = 0; i < images.length; i++) { var img = document.createElement("img"); this.repeatControls[position][images[i].name] = img; - img.setAttribute("src", (WEBAPP_CONTEXT + "/images/icons/" + + img.setAttribute("src", (alfresco_xforms_constants.WEBAPP_CONTEXT + "/images/icons/" + images[i].src + ".gif")); img.style.width = "16px"; img.style.height = "16px"; @@ -1028,9 +1065,14 @@ dojo.declare("alfresco.xforms.Repeat", result.style.border = "1px solid black"; if (result.nextSibling) - result.parentNode.insertBefore(this.repeatControls[position], result.nextSibling); + { + result.parentNode.insertBefore(this.repeatControls[position], + result.nextSibling); + } else + { result.parentNode.appendChild(this.repeatControls[position]); + } dojo.html.setClass(this.repeatControls[position], "xformsRepeatControls"); this.repeatControls[position].style.width = repeatControlsWidth + "px"; @@ -1062,7 +1104,9 @@ dojo.declare("alfresco.xforms.Repeat", { this._selectedIndex = Math.min(this.children.length - 1, this._selectedIndex); if (this.children.length == 0) + { this._selectedIndex = -1; + } return this._selectedIndex; }, _updateDisplay: function() @@ -1080,10 +1124,16 @@ dojo.declare("alfresco.xforms.Repeat", for (var i in bw) { if (! (bw[i] instanceof alfresco.xforms.Trigger)) + { continue; + } + var action = bw[i].getAction(); if (action.getType() != type) + { continue; + } + var propertiesEqual = true; for (var p in properties) { @@ -1095,7 +1145,9 @@ dojo.declare("alfresco.xforms.Repeat", } } if (propertiesEqual) + { return bw[i]; + } } throw new Error("unable to find trigger " + type + ", properties " + properties + @@ -1106,14 +1158,14 @@ dojo.declare("alfresco.xforms.Repeat", { dojo.event.browser.stopEvent(event); var repeat = event.target.repeat; - if (!repeat.isInsertRepeatItemEnabled()) - return; - - var index = repeat.repeatControls.indexOf(event.target.parentNode); - var repeatItem = repeat.getChildAt(index); - this.setFocusedChild(repeatItem); - var trigger = this._getRepeatItemTrigger("insert", { position: "after" }); - this.xform.fireAction(trigger.id); + if (repeat.isInsertRepeatItemEnabled()) + { + var index = repeat.repeatControls.indexOf(event.target.parentNode); + var repeatItem = repeat.getChildAt(index); + this.setFocusedChild(repeatItem); + var trigger = this._getRepeatItemTrigger("insert", { position: "after" }); + this.xform.fireAction(trigger.id); + } }, _headerInsertRepeatItemBefore_handler: function(event) { @@ -1121,11 +1173,12 @@ dojo.declare("alfresco.xforms.Repeat", { dojo.event.browser.stopEvent(event); var repeat = event.target.repeat; - if (!repeat.isInsertRepeatItemEnabled()) - return; - this.setFocusedChild(null); - var trigger = this._getRepeatItemTrigger("insert", { position: "before" }); - this.xform.fireAction(trigger.id); + if (repeat.isInsertRepeatItemEnabled()) + { + this.setFocusedChild(null); + var trigger = this._getRepeatItemTrigger("insert", { position: "before" }); + this.xform.fireAction(trigger.id); + } } }, _removeRepeatItem_handler: function(event) @@ -1231,7 +1284,9 @@ dojo.declare("alfresco.xforms.Repeat", this.headerInsertRepeatItemImage = document.createElement("img"); this.headerInsertRepeatItemImage.repeat = this; this.groupHeaderNode.appendChild(this.headerInsertRepeatItemImage); - this.headerInsertRepeatItemImage.setAttribute("src", WEBAPP_CONTEXT + "/images/icons/plus.gif"); + this.headerInsertRepeatItemImage.setAttribute("src", + alfresco_xforms_constants.WEBAPP_CONTEXT + + "/images/icons/plus.gif"); this.headerInsertRepeatItemImage.style.width = "16px"; this.headerInsertRepeatItemImage.style.height = "16px"; this.headerInsertRepeatItemImage.align = "absmiddle"; @@ -1253,9 +1308,12 @@ dojo.declare("alfresco.xforms.Repeat", handlePrototypeCloned: function(prototypeId) { dojo.debug(this.id + ".handlePrototypeCloned("+ prototypeId +")"); - var chibaData = _getElementsByTagNameNS(this.xformsNode, CHIBA_NS, CHIBA_NS_PREFIX, "data"); + var chibaData = _getElementsByTagNameNS(this.xformsNode, + alfresco_xforms_constants.CHIBA_NS, + alfresco_xforms_constants.CHIBA_PREFIX, + "data"); chibaData = chibaData[chibaData.length - 1]; - dojo.debug(CHIBA_NS_PREFIX + ":data == " + dojo.dom.innerXML(chibaData)); + dojo.debug(alfresco_xforms_constants.CHIBA_PREFIX + ":data == " + dojo.dom.innerXML(chibaData)); var prototypeToClone = dojo.dom.firstElement(chibaData); if (prototypeToClone.getAttribute("id") != prototypeId) throw new Error("unable to locate " + prototypeId + @@ -1308,7 +1366,7 @@ dojo.declare("alfresco.xforms.Repeat", dojo.declare("alfresco.xforms.Trigger", alfresco.xforms.Widget, { - initializer: function(xform, xformsNode) + initializer: function(xform, xformsNode) { // this.inherited("initializer", [ xform, xformsNode ]); }, @@ -1336,8 +1394,8 @@ dojo.declare("alfresco.xforms.Trigger", var c = this.xformsNode.childNodes[i]; if (c.nodeType != dojo.dom.ELEMENT_NODE) continue; - if (c.nodeName == XFORMS_PREFIX + ":label" || - c.nodeName == XFORMS_PREFIX + ":alert") + if (c.nodeName == alfresco_xforms_constants.XFORMS_PREFIX + ":label" || + c.nodeName == alfresco_xforms_constants.XFORMS_PREFIX + ":alert") continue; return new alfresco.xforms.XFormsAction(this.xform, c); } @@ -1352,7 +1410,7 @@ dojo.declare("alfresco.xforms.Trigger", dojo.declare("alfresco.xforms.Submit", alfresco.xforms.Trigger, { - initializer: function(xform, xformsNode) + initializer: function(xform, xformsNode) { // this.inherited("initializer", [ xform, xformsNode ]); var submit_buttons = _xforms_getSubmitButtons(); @@ -1400,7 +1458,7 @@ dojo.declare("alfresco.xforms.Submit", dojo.declare("alfresco.xforms.XFormsAction", null, { - initializer: function(xform, xformsNode) + initializer: function(xform, xformsNode) { this.xform = xform; this.xformsNode = xformsNode; @@ -1408,23 +1466,23 @@ dojo.declare("alfresco.xforms.XFormsAction", for (var i = 0; i < this.xformsNode.attributes.length; i++) { var attr = this.xformsNode.attributes[i]; - if (attr.nodeName.match(new RegExp("^" + XFORMS_PREFIX + ":"))) + if (attr.nodeName.match(new RegExp("^" + alfresco_xforms_constants.XFORMS_PREFIX + ":"))) { - this.properties[attr.nodeName.substring((XFORMS_PREFIX + ":").length)] = + this.properties[attr.nodeName.substring((alfresco_xforms_constants.XFORMS_PREFIX + ":").length)] = attr.nodeValue; } } }, getType: function() { - return this.xformsNode.nodeName.substring((XFORMS_PREFIX + ":").length); + return this.xformsNode.nodeName.substring((alfresco_xforms_constants.XFORMS_PREFIX + ":").length); } }); dojo.declare("alfresco.xforms.XFormsEvent", null, { - initializer: function(node) + initializer: function(node) { this.type = node.nodeName; this.targetId = node.getAttribute("targetId"); @@ -1452,17 +1510,17 @@ dojo.declare("alfresco.xforms.Binding", { this.xformsNode = xformsNode; this.id = this.xformsNode.getAttribute("id"); - this.readonly = this.xformsNode.getAttribute(XFORMS_PREFIX + ":readonly"); - this.required = this.xformsNode.getAttribute(XFORMS_PREFIX + ":required"); - this.nodeset = this.xformsNode.getAttribute(XFORMS_PREFIX + ":nodeset"); - this._type = (this.xformsNode.hasAttribute(XFORMS_PREFIX + ":type") - ? this.xformsNode.getAttribute(XFORMS_PREFIX + ":type") + this.readonly = this.xformsNode.getAttribute(alfresco_xforms_constants.XFORMS_PREFIX + ":readonly"); + this.required = this.xformsNode.getAttribute(alfresco_xforms_constants.XFORMS_PREFIX + ":required"); + this.nodeset = this.xformsNode.getAttribute(alfresco_xforms_constants.XFORMS_PREFIX + ":nodeset"); + this._type = (this.xformsNode.hasAttribute(alfresco_xforms_constants.XFORMS_PREFIX + ":type") + ? this.xformsNode.getAttribute(alfresco_xforms_constants.XFORMS_PREFIX + ":type") : null); - this.constraint = (this.xformsNode.hasAttribute(XFORMS_PREFIX + ":constraint") - ? this.xformsNode.getAttribute(XFORMS_PREFIX + ":constraint") + this.constraint = (this.xformsNode.hasAttribute(alfresco_xforms_constants.XFORMS_PREFIX + ":constraint") + ? this.xformsNode.getAttribute(alfresco_xforms_constants.XFORMS_PREFIX + ":constraint") : null); - this.maximum = parseInt(this.xformsNode.getAttribute(ALFRESCO_NS_PREFIX + ":maximum")); - this.minimum = parseInt(this.xformsNode.getAttribute(ALFRESCO_NS_PREFIX + ":minimum")); + this.maximum = parseInt(this.xformsNode.getAttribute(alfresco_xforms_constants.ALFRESCO_PREFIX + ":maximum")); + this.minimum = parseInt(this.xformsNode.getAttribute(alfresco_xforms_constants.ALFRESCO_PREFIX + ":minimum")); this.parent = parent; this.widgets = {}; }, @@ -1507,7 +1565,7 @@ dojo.declare("alfresco.xforms.XForm", ? bindings[i].parent.id : 'null')); } - var alfUI = document.getElementById("alfresco-xforms-ui"); + var alfUI = document.getElementById(alfresco_xforms_constants.XFORMS_UI_DIV_ID); alfUI.style.width = "100%"; this.rootWidget = new alfresco.xforms.Group(this, alfUI); this.rootWidget.render(alfUI); @@ -1519,15 +1577,15 @@ dojo.declare("alfresco.xforms.XForm", dojo.debug("creating node for " + node.nodeName.toLowerCase()); switch (node.nodeName.toLowerCase()) { - case XFORMS_PREFIX + ":group": + case alfresco_xforms_constants.XFORMS_PREFIX + ":group": return new alfresco.xforms.Group(this, node); - case XFORMS_PREFIX + ":repeat": + case alfresco_xforms_constants.XFORMS_PREFIX + ":repeat": return new alfresco.xforms.Repeat(this, node); - case XFORMS_PREFIX + ":textarea": + case alfresco_xforms_constants.XFORMS_PREFIX + ":textarea": return new alfresco.xforms.TextArea(this, node); - case XFORMS_PREFIX + ":upload": + case alfresco_xforms_constants.XFORMS_PREFIX + ":upload": return new alfresco.xforms.FilePicker(this, node); - case XFORMS_PREFIX + ":input": + case alfresco_xforms_constants.XFORMS_PREFIX + ":input": { var type = this.getBinding(node).getType(); switch (type) @@ -1554,19 +1612,19 @@ dojo.declare("alfresco.xforms.XForm", return new alfresco.xforms.TextField(this, node); } } - case XFORMS_PREFIX + ":select": + case alfresco_xforms_constants.XFORMS_PREFIX + ":select": return new alfresco.xforms.Select(this, node); - case XFORMS_PREFIX + ":select1": + case alfresco_xforms_constants.XFORMS_PREFIX + ":select1": return (this.getBinding(node).getType() == "boolean" ? new alfresco.xforms.Checkbox(this, node) : new alfresco.xforms.Select1(this, node)); - case XFORMS_PREFIX + ":submit": + case alfresco_xforms_constants.XFORMS_PREFIX + ":submit": return new alfresco.xforms.Submit(this, node); - case XFORMS_PREFIX + ":trigger": + case alfresco_xforms_constants.XFORMS_PREFIX + ":trigger": return new alfresco.xforms.Trigger(this, node); - case CHIBA_NS_PREFIX + ":data": - case XFORMS_PREFIX + ":label": - case XFORMS_PREFIX + ":alert": + case alfresco_xforms_constants.CHIBA_PREFIX + ":data": + case alfresco_xforms_constants.XFORMS_PREFIX + ":label": + case alfresco_xforms_constants.XFORMS_PREFIX + ":alert": dojo.debug("ignoring " + node.nodeName); return null; default: @@ -1581,7 +1639,7 @@ dojo.declare("alfresco.xforms.XForm", { dojo.debug("loading " + xformsNode.childNodes[i].nodeName + " into " + parentWidget.id); - if (xformsNode.childNodes[i].getAttribute(ALFRESCO_NS_PREFIX + ":prototype") == "true") + if (xformsNode.childNodes[i].getAttribute(alfresco_xforms_constants.ALFRESCO_PREFIX + ":prototype") == "true") { dojo.debug(xformsNode.childNodes[i].getAttribute("id") + " is a prototype, ignoring"); @@ -1593,7 +1651,9 @@ dojo.declare("alfresco.xforms.XForm", dojo.debug("created " + w.id + " for " + xformsNode.childNodes[i].nodeName); parentWidget.addChild(w); if (w instanceof alfresco.xforms.Group) + { this.loadWidgets(xformsNode.childNodes[i], w); + } } } } @@ -1601,29 +1661,29 @@ dojo.declare("alfresco.xforms.XForm", getModel: function() { return _getElementsByTagNameNS(this.xformsNode, - XFORMS_NS, - XFORMS_PREFIX, + alfresco_xforms_constants.XFORMS_NS, + alfresco_xforms_constants.XFORMS_PREFIX, "model")[0]; }, getInstance: function() { var model = this.getModel(); return _getElementsByTagNameNS(model, - XFORMS_NS, - XFORMS_PREFIX, + alfresco_xforms_constants.XFORMS_NS, + alfresco_xforms_constants.XFORMS_PREFIX, "instance")[0]; }, getBody: function() { var b = _getElementsByTagNameNS(this.xformsNode, - XHTML_NS, - XHTML_NS_PREFIX, + alfresco_xforms_constants.XHTML_NS, + alfresco_xforms_constants.XHTML_PREFIX, "body"); return b[b.length - 1]; }, getBinding: function(node) { - return this._bindings[node.getAttribute(XFORMS_PREFIX + ":bind")]; + return this._bindings[node.getAttribute(alfresco_xforms_constants.XFORMS_PREFIX + ":bind")]; }, getBindings: function() { @@ -1635,7 +1695,7 @@ dojo.declare("alfresco.xforms.XForm", dojo.debug("loading bindings for " + bind.nodeName); for (var i = 0; i < bind.childNodes.length; i++) { - if (bind.childNodes[i].nodeName.toLowerCase() == XFORMS_PREFIX + ":bind") + if (bind.childNodes[i].nodeName.toLowerCase() == alfresco_xforms_constants.XFORMS_PREFIX + ":bind") { var b = new alfresco.xforms.Binding(bind.childNodes[i], parent); result[b.id] = b; @@ -1743,22 +1803,14 @@ dojo.declare("alfresco.xforms.XForm", dojo.debug("cloning prototype " + originalId); var prototypeNode = _findElementById(this.xformsNode, originalId); clone = prototypeNode.cloneNode(true); - var clone = prototypeNode.ownerDocument.createElement(XFORMS_PREFIX + ":group"); - clone.setAttribute(XFORMS_PREFIX + ":appearance", "repeated"); + var clone = prototypeNode.ownerDocument.createElement(alfresco_xforms_constants.XFORMS_PREFIX + ":group"); + clone.setAttribute(alfresco_xforms_constants.XFORMS_PREFIX + ":appearance", "repeated"); for (var j = 0; j < prototypeNode.childNodes.length; j++) { clone.appendChild(prototypeNode.childNodes[j].cloneNode(true)); } clone.setAttribute("id", prototypeId); } -// if (true || originalId == xfe.targetId) -// var clone = xfe.getTarget().handlePrototypeCloned(prototypeId); -// else -// { -// var parentClone = prototypeClones[prototypeClones.length - 1]; - -// var clone = originalWidget.widget.handlePrototypeCloned(prototypeId); -// } clone.parentClone = prototypeClone; prototypeClone = clone; break; @@ -1780,7 +1832,7 @@ dojo.declare("alfresco.xforms.XForm", var e = _findElementById(prototypeClone.parentClone, originalId); if (e) { - e.setAttribute(ALFRESCO_NS_PREFIX + ":prototype", "true"); + e.setAttribute(alfresco_xforms_constants.ALFRESCO_PREFIX + ":prototype", "true"); } } break; @@ -1888,7 +1940,9 @@ function _findElementById(node, id) function create_ajax_request(target, serverMethod, methodArgs, load, error) { - var result = new dojo.io.Request(WEBAPP_CONTEXT + "/ajax/invoke/XFormsBean." + serverMethod, "text/xml"); + var result = new dojo.io.Request(alfresco_xforms_constants.WEBAPP_CONTEXT + + "/ajax/invoke/XFormsBean." + serverMethod, + "text/xml"); result.target = target; result.content = methodArgs; @@ -1908,7 +1962,7 @@ function create_ajax_request(target, serverMethod, methodArgs, load, error) function _hide_errors() { - var errorDiv = document.getElementById("alfresco-xforms-error"); + var errorDiv = document.getElementById(alfresco_xforms_constants.XFORMS_ERROR_DIV_ID); if (errorDiv) { dojo.dom.removeChildren(errorDiv); @@ -1918,19 +1972,24 @@ function _hide_errors() function _show_error(msg) { - var errorDiv = document.getElementById("alfresco-xforms-error"); + var errorDiv = document.getElementById(alfresco_xforms_constants.XFORMS_ERROR_DIV_ID); if (!errorDiv) { errorDiv = document.createElement("div"); - errorDiv.setAttribute("id", "alfresco-xforms-error"); + errorDiv.setAttribute("id", alfresco_xforms_constants.XFORMS_ERROR_DIV_ID); dojo.html.setClass(errorDiv, "infoText statusErrorText xformsError"); - var alfUI = document.getElementById("alfresco-xforms-ui"); + var alfUI = document.getElementById(alfresco_xforms_constants.XFORMS_UI_DIV_ID); dojo.dom.prependChild(errorDiv, alfUI); } + if (errorDiv.style.display == "block") + { errorDiv.appendChild(document.createElement("br")); + } else + { errorDiv.style.display = "block"; + } errorDiv.appendChild(msg); } @@ -1942,11 +2001,11 @@ function send_ajax_request(req) function _get_ajax_loader_element() { - var result = document.getElementById("alfresco-ajax-loader"); + var result = document.getElementById(alfresco_xforms_constants.AJAX_LOADER_DIV_ID); if (result) return result; result = document.createElement("div"); - result.setAttribute("id", "alfresco-ajax-loader"); + result.setAttribute("id", alfresco_xforms_constants.AJAX_LOADER_DIV_ID); dojo.html.setClass(result, "xformsAjaxLoader"); dojo.style.hide(result); document.body.appendChild(result); @@ -2008,7 +2067,8 @@ function _getElementsByTagNameNS(parentNode, ns, nsPrefix, tagName) function _evaluateXPath(xpath, contextNode, result_type) { var xmlDocument = contextNode.ownerDocument; - dojo.debug("evaluating xpath " + xpath + " on node " + contextNode.nodeName + + dojo.debug("evaluating xpath " + xpath + + " on node " + contextNode.nodeName + " in document " + xmlDocument); var result = null; if (xmlDocument.evaluate) @@ -2120,7 +2180,7 @@ FilePickerWidget._handleUpload = function(id, fileInput, webappRelativePath, wid form.encoding = "multipart/form-data"; form.enctype = "multipart/form-data"; form.target = iframe.name; - form.action = WEBAPP_CONTEXT + "/ajax/invoke/XFormsBean.uploadFile"; + form.action = alfresco_xforms_constants.WEBAPP_CONTEXT + "/ajax/invoke/XFormsBean.uploadFile"; form.appendChild(fileInput.cloneNode(true)); var rp = d.createElement("input"); @@ -2164,9 +2224,13 @@ setReadonly: function(r) { this.readonly = r; if (this.selectButton) + { this.selectButton.disabled = this.readonly; + } else if (this.readonly) + { this._showSelectedValue(); + } }, render: function() { @@ -2328,7 +2392,7 @@ _showPicker: function(data) headerMenuTriggerImage = d.createElement("img"); this.headerMenuTriggerLink.appendChild(headerMenuTriggerImage); this.headerMenuTriggerLink.image = headerMenuTriggerImage; - headerMenuTriggerImage.setAttribute("src", WEBAPP_CONTEXT + "/images/icons/menu.gif"); + headerMenuTriggerImage.setAttribute("src", alfresco_xforms_constants.WEBAPP_CONTEXT + "/images/icons/menu.gif"); headerMenuTriggerImage.style.borderWidth = "0px"; headerMenuTriggerImage.style.marginLeft = "4px"; headerMenuTriggerImage.align = "absmiddle"; @@ -2352,7 +2416,7 @@ _showPicker: function(data) addContentImage.style.borderWidth = "0px"; addContentImage.style.margin = "0px 2px 0px 2px"; addContentImage.align = "absmiddle"; - addContentImage.setAttribute("src", WEBAPP_CONTEXT + "/images/icons/add.gif"); + addContentImage.setAttribute("src", alfresco_xforms_constants.WEBAPP_CONTEXT + "/images/icons/add.gif"); addContentLink.appendChild(addContentImage); addContentLink.appendChild(d.createTextNode("Add Content")); @@ -2381,7 +2445,7 @@ _showPicker: function(data) navigateToParentNodeImage.style.opacity = (currentPathName == "/" ? .3 : 1); navigateToParentNodeImage.style.margin = "0px 2px 0px 2px"; navigateToParentNodeImage.align = "absmiddle"; - navigateToParentNodeImage.setAttribute("src", WEBAPP_CONTEXT + "/images/icons/up.gif"); + navigateToParentNodeImage.setAttribute("src", alfresco_xforms_constants.WEBAPP_CONTEXT + "/images/icons/up.gif"); navigateToParentLink.appendChild(navigateToParentNodeImage); navigateToParentLink.appendChild(d.createTextNode("Go up")); @@ -2462,7 +2526,7 @@ _showPicker: function(data) var e = d.createElement("img"); e.align = "absmiddle"; e.style.margin = "0px 4px 0px 4px"; - e.setAttribute("src", WEBAPP_CONTEXT + childNodes[i].getAttribute("image")); + e.setAttribute("src", alfresco_xforms_constants.WEBAPP_CONTEXT + childNodes[i].getAttribute("image")); row.appendChild(e); if (childNodes[i].getAttribute("type") == "directory") @@ -2638,7 +2702,7 @@ _openParentPathMenu: function(target, path) parentNodeImage.align = "absmiddle"; parentNodeImage.style.marginRight = "4px"; parentNodeDiv.appendChild(parentNodeImage); - parentNodeImage.setAttribute("src", WEBAPP_CONTEXT + "/images/icons/space_small.gif"); + parentNodeImage.setAttribute("src", alfresco_xforms_constants.WEBAPP_CONTEXT + "/images/icons/space_small.gif"); parentNodeDiv.appendChild(parentNodeImage); parentNodeDiv.appendChild(d.createTextNode(path)); dojo.event.connect(parentNodeDiv,