New Document Wizard
The new document wizard was written with the intend of encapsulating powerful, existing techniques into a HippoCMS module that allows for easy configuration and extension.
Table of contents
The Wizard model
Big picture
Basically the wizard is just a Cform. It presents the user a form with widgets and after a successful submit, the entered values will be used to created a data set that is in turn used to create the new document. This data set will contain information about the location of the new document, the filename of the new document, document type values like workflow-name or the empty document source. It can also contain webdav:properties or values that will be injected directly into the new document, using an xpath.
The wizard model
The module is configured by a single xml file. This file is used to instantiate a component tree of wizard components, the wizard model. Every component in this model is a nl.hippo.cms.wizard.components.Component. This model is
used to create the Cforms model/binding/template, hold the values of the Cforms widgets and fill the wizard result object with sensible values.
The model has a strict hierarchy, starting with the Wizard instance as the root node. A wizard contains a map of Engine instances, engines can be seen as a collection of methods to create a new document.
You can, for example, configure an engine that lets the user select a document type from a dropdown as a way of creating a new document, and then another engine that lets users create new documents by importing them with an upload widget. Engines are displayed to the user as tabs.
As mentioned, engines contain a map of ways to create a new document, called resources. Resources are presented in a select-box. By selecting a resource, the user will be presented with the widgets associated with that resource. So, every resource contains a map of widgets, which can in turn contain widgets themselves.
In short, the hierarchy is:
<wizard>
<engines>
<resources>
<widgets/>
</resource>
</engine>
</wizard>
Components
Components have multiple purposes in different arias of the wizard. They represent an abstraction for cforms' model/binding/template components, they act as a pojo for the cform and they have a way of filling the wizard result with their values, making sure that only the intended components are used in the result aggregation process.
Every component has the following properties
- id: used for internal lookup and default i18n key
- path: string value that is used to create the new document path
- label: specific i18n key
- labelCatalogue: specific i18n catalogue value
- skip: skip this component during fillResult process
Component aspects
Component aspects provide a way to reuse the entered value of a component for a different purpose, like proppatching a cms:caption property with the component's value. Aspects can be attached to every wizard component, currently the aspects can only be applied to the newly created document.
Wizard model in action
An object called a WizardResult is used to act as a dataset for all the actions in the new document creation process, which is still done in flowscript, as not to break with current functionality.
After a form is successfully submit, the flowscript will create a new WizardResult instance and pass that to Wizard.fillResult() method. The Wizard will add it's own values to the wizard result and pass it on to it's child components, making sure only the components that were in the selected component path are used. For convenience, a Spring WebApplicationContext is passed next to the WizardResult, so components have complete control over how they handle their fillResult process.
The most important part of the fillResult process is that path creation. For example, first the wizard will add its path value to the result: addPath("/content") Then the selected Engine will add its value to the result: addPath("engine"). Now the internal result path is "/content/engine". Then the selected resource will add its value: addPath("/content/local/resource"). This will override the previous internal path value, which will now be "/content/local/resource". Then the Resource will release the fillResult process on the widgets, which get their path values from the values entered into the widgets.
Configuration
Build properties
The wizard has two build properties:
- cms.wizard.configuration.src: location of the configuration file, can be anywhere in the HippoCMS context (extensions://, repository://, etc.)
- cms.wizard.configuration.xsl: (optional) location of xsl file that converts the cms.wizard.configuration.src file into a wizard configuration
As default mode (properties can be left empty) the wizard will use the types model to configure the wizard.
Wizard configuration syntax
Namespaces
The configuration file uses the following namespaces, reflecting the wizard model component's interfaces and packages.
- xmlns:wizard="http://hippo.nl/cms/wizard"
- xmlns:engine="http://hippo.nl/cms/wizard/engine"
- xmlns:resource="http://hippo.nl/cms/wizard/resource"
- xmlns:widget="http://hippo.nl/cms/wizard/widget"
- xmlns:aspect="http://hippo.nl/cms/wizard/aspect"
Each element within these namespaces will instantiate a new Component/Aspect that will be wired to the model. The objects are created by the following procedure:
var package = lookupPackageByNamespace(namespaceURI); var interface = lookupInterfaceByNamespace(namespaceURI); var class = localname.capitalizeFirstChar(); var newComponent = Class.forName(package + class + interface).newInstance();
Component attributes
Every component element can contain the following attributes
- @id: component id, not required
- @path: set a path value
- @label: i18n key
- @labelCatalogue: i18n key catalogue
- @skip: flag to skip component during fillResult
Elements
<wizard:newDocument>
Root element
- @default-result-action: optional, defines the default action to execute after a new document is created. Set to "add" or "edit".
<engine:configuration>
Default engine
<resource:hippo>
Create a Hippo type resource (uses types model to lookup data)
- @type: required, reference to the @type value in the types model
- @name: Optional, if filled its value will be used to lookup the widget by id and use it's value as the new filename, else a unique filename will be created
<widget:constant>
Invisible widget with constant value
- @value: required
<widget:categoryConstant>
Widget used by the sitemenu2configuration (default config) process.
The value references the @category in the types model and is used to get the path value from the CMS locationmap during fillResult.
- @value: required
<widget:string>
Simple input field widget
<widget:string>
Simple input field widget
- @displayformat: required, configures the way the date is formated in the date picker
- @outputformat: required, configures the way the date is used stored in the XML or within the path
<widget:select>
Simple select widget, contains items
- @src: optional, use this to resolve items from an external source. Any source in the HippoCMS context can be used.
- @xsl: optional, if set it will be used to transform the @src into a list of items.
<widget:item>
Child element of a select. Can contain widgets itself.
- @value: required
<widget:categorySelectItem>
Widget used by the sitemenu2configuration (default config) process.
The value references the @category in the types model and is used to get the path value from the CMS locationmap during fillResult.
<aspect:property>
Uses the attached component's value to patch a webdav property on the new document
- @name: required, name of the property
- @namespace: optional, http://hippo.nl/cms/1.0
is used as default
<aspect:xpath>
Uses the attached component's value to inject it into the new document using an xpath
- @xpath: required, xpath where value should be injected. Currently only element/text().
TODO: create schema