diff --git a/config/alfresco/web-client-application-context.xml b/config/alfresco/web-client-application-context.xml
index 2655ec4bd5..cff44dd5eb 100644
--- a/config/alfresco/web-client-application-context.xml
+++ b/config/alfresco/web-client-application-context.xml
@@ -9,6 +9,7 @@
classpath:alfresco/web-client-config.xml
classpath:alfresco/web-client-config-properties.xml
classpath:alfresco/web-client-config-navigation.xml
+ classpath:alfresco/web-client-config-actions.xml
classpath:alfresco/extension/web-client-config-custom.xml
diff --git a/config/alfresco/web-client-config-actions.xml b/config/alfresco/web-client-config-actions.xml
new file mode 100644
index 0000000000..cec89c8457
--- /dev/null
+++ b/config/alfresco/web-client-config-actions.xml
@@ -0,0 +1,126 @@
+
+
+
+
+
+
+
+
+
+
+
+ Write
+ AddChildren
+
+
+ org.alfresco.web.action.evaluator.EditDocHttpEvaluator
+
+
+ edit
+ My Tooltip
+ tooltip
+
+ false
+
+ inlineAction
+ /images/icons/edit_icon.gif
+
+ #{CheckinCheckoutBean.editFile}
+ editDocument
+ http://...
+ new
+
+
+
+ id
+
+
+
+
+
+
+ Write
+
+ org.alfresco.web.action.evaluator.EditDocHttpEvaluator
+ edit
+ /images/icons/edit_icon.gif
+ #{CheckinCheckoutBean.editFile}
+
+ id
+
+
+
+
+
+
+
+ Write
+
+ org.alfresco.web.action.evaluator.EditDocWebDavEvaluator
+ edit
+ /images/icons/edit_icon.gif
+
+ javascript:openDoc('#{actioncontext.webdavUrl}');
+
+
+
+
+
+ Write
+
+ org.alfresco.web.action.evaluator.EditDocCIFSEvaluator
+ edit
+ /images/icons/edit_icon.gif
+
+ #{actioncontext.cifsPath}
+ cifs
+
+
+
+
+
+
+
+
+
+ false
+ inlineAction
+
+
+
+
+
+
+
+ CheckOut
+
+ checkout
+ /images/icons/CheckOut_icon.gif
+ #{CheckinCheckoutBean.setupContentAction}
+ checkoutFile
+
+
+
+
+
+
+
+
diff --git a/config/alfresco/web-client-config.xml b/config/alfresco/web-client-config.xml
index 6e23c9a6bf..26bb0345d8 100644
--- a/config/alfresco/web-client-config.xml
+++ b/config/alfresco/web-client-config.xml
@@ -12,6 +12,7 @@
+
diff --git a/source/java/org/alfresco/web/bean/BrowseBean.java b/source/java/org/alfresco/web/bean/BrowseBean.java
index 8ab5dcd336..7787052bda 100644
--- a/source/java/org/alfresco/web/bean/BrowseBean.java
+++ b/source/java/org/alfresco/web/bean/BrowseBean.java
@@ -895,10 +895,6 @@ public class BrowseBean implements IContextListener
{
editLinkType = Application.getClientConfig(
FacesContext.getCurrentInstance()).getEditLinkType();
- if (editLinkType == null)
- {
- editLinkType = "http";
- }
}
return editLinkType;
diff --git a/source/java/org/alfresco/web/config/ActionsConfigElement.java b/source/java/org/alfresco/web/config/ActionsConfigElement.java
new file mode 100644
index 0000000000..999f564871
--- /dev/null
+++ b/source/java/org/alfresco/web/config/ActionsConfigElement.java
@@ -0,0 +1,231 @@
+/*
+ * 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.config;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.alfresco.config.ConfigElement;
+import org.alfresco.config.ConfigException;
+import org.alfresco.config.element.ConfigElementAdapter;
+import org.alfresco.web.action.ActionEvaluator;
+
+/**
+ * Action config element.
+ *
+ * @author Kevin Roast
+ */
+public class ActionsConfigElement extends ConfigElementAdapter
+{
+ public static final String CONFIG_ELEMENT_ID = "actions";
+
+ private Map actionDefs = new HashMap(32, 1.0f);
+ private Map actionGroups = new HashMap(16, 1.0f);
+
+ /**
+ * Default constructor
+ */
+ public ActionsConfigElement()
+ {
+ super(CONFIG_ELEMENT_ID);
+ }
+
+ /**
+ * @param name
+ */
+ public ActionsConfigElement(String name)
+ {
+ super(name);
+ }
+
+ /**
+ * @see org.alfresco.config.element.ConfigElementAdapter#getChildren()
+ */
+ public List getChildren()
+ {
+ throw new ConfigException("Reading the Actions config via the generic interfaces is not supported");
+ }
+
+ /**
+ * @see org.alfresco.config.element.ConfigElementAdapter#combine(org.alfresco.config.ConfigElement)
+ */
+ public ConfigElement combine(ConfigElement configElement)
+ {
+ ActionsConfigElement existingElement = (ActionsConfigElement)configElement;
+ ActionsConfigElement combinedElement = new ActionsConfigElement();
+
+ //
+ // TODO: implement to allow override of config elements
+ //
+
+ return null;
+ }
+
+ /*package*/ void addActionDefinition(ActionDefinition actionDef)
+ {
+ actionDefs.put(actionDef.getId(), actionDef);
+ }
+
+ public ActionDefinition getActionDefinition(String id)
+ {
+ return actionDefs.get(id);
+ }
+
+ /*package*/ void addActionGroup(ActionGroup group)
+ {
+ actionGroups.put(group.getId(), group);
+ }
+
+ public ActionGroup getActionGroup(String id)
+ {
+ return actionGroups.get(id);
+ }
+
+
+ /**
+ * Simple class representing the definition of a UI action.
+ *
+ * @author Kevin Roast
+ */
+ public static class ActionDefinition
+ {
+ public ActionDefinition(String id)
+ {
+ if (id == null || id.length() == 0)
+ {
+ throw new IllegalArgumentException("ActionDefinition ID is mandatory.");
+ }
+ this.id = id;
+ }
+
+ public String getId()
+ {
+ return id;
+ }
+
+ public void addAllowPermission(String permission)
+ {
+ if (permissionAllow == null)
+ {
+ permissionAllow = new ArrayList(2);
+ }
+ permissionAllow.add(permission);
+ }
+
+ public void addDenyPermission(String permission)
+ {
+ if (permissionDeny == null)
+ {
+ permissionDeny = new ArrayList(1);
+ }
+ permissionDeny.add(permission);
+ }
+
+ public List getAllowPermissions()
+ {
+ return permissionAllow;
+ }
+
+ public List getDenyPermissions()
+ {
+ return permissionDeny;
+ }
+
+ public void addParam(String name, String value)
+ {
+ if (params == null)
+ {
+ params = new HashMap(1, 1.0f);
+ }
+ params.put(name, value);
+ }
+
+ public Map getParams()
+ {
+ return params;
+ }
+
+ private String id;
+ private List permissionAllow = null;
+ private List permissionDeny = null;
+ private Map params = null;
+
+ public ActionEvaluator Evaluator = null;
+ public String Label;
+ public String LabelMsg;
+ public String Tooltip;
+ public String TooltipMsg;
+ public boolean ShowLink;
+ public String Style;
+ public String StyleClass;
+ public String Image;
+ public String ActionListener;
+ public String Action;
+ public String Href;
+ public String Target;
+ }
+
+
+ /**
+ * Simple class representing a group of UI actions.
+ *
+ * @author Kevin Roast
+ */
+ public static class ActionGroup implements Iterable
+ {
+ public ActionGroup(String id)
+ {
+ if (id == null || id.length() == 0)
+ {
+ throw new IllegalArgumentException("ActionGroup ID is mandatory.");
+ }
+ this.id = id;
+ }
+
+ public String getId()
+ {
+ return id;
+ }
+
+ public void addAction(ActionDefinition actionDef)
+ {
+ actions.put(actionDef.getId(), actionDef);
+ }
+
+ /**
+ * @return Iterator to the ActionDefinition objects referenced by this group
+ */
+ public Iterator iterator()
+ {
+ return actions.values().iterator();
+ }
+
+ private String id;
+
+ /** the action definitions, we use a linked hashmap to ensure we do not have more
+ than one action with the same Id and that the insertion order is preserved */
+ private Map actions = new LinkedHashMap(8, 1.0f);
+
+ public boolean ShowLink;
+ public String Style;
+ public String StyleClass;
+ }
+}
diff --git a/source/java/org/alfresco/web/config/ActionsElementReader.java b/source/java/org/alfresco/web/config/ActionsElementReader.java
new file mode 100644
index 0000000000..95698b19cb
--- /dev/null
+++ b/source/java/org/alfresco/web/config/ActionsElementReader.java
@@ -0,0 +1,263 @@
+/*
+ * 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.config;
+
+import java.util.Iterator;
+
+import org.alfresco.config.ConfigElement;
+import org.alfresco.config.ConfigException;
+import org.alfresco.config.xml.elementreader.ConfigElementReader;
+import org.alfresco.web.action.ActionEvaluator;
+import org.alfresco.web.config.ActionsConfigElement.ActionDefinition;
+import org.alfresco.web.config.ActionsConfigElement.ActionGroup;
+import org.dom4j.Element;
+
+/**
+ * Config Element Reader for the "Action" config blocks.
+ *
+ * @author Kevin Roast
+ */
+public class ActionsElementReader implements ConfigElementReader
+{
+ public static final String ELEMENT_ACTION = "action";
+ public static final String ELEMENT_ACTIONGROUP = "action-group";
+ public static final String ELEMENT_PERMISSIONS = "permissions";
+ public static final String ELEMENT_PERMISSION = "permission";
+ public static final String ELEMENT_EVALUATOR = "evaluator";
+ public static final String ELEMENT_LABEL = "label";
+ public static final String ELEMENT_LABELMSG = "label-msg";
+ public static final String ELEMENT_TOOLTIP = "tooltip";
+ public static final String ELEMENT_TOOLTIPMSG = "tooltip-msg";
+ public static final String ELEMENT_SHOWLINK = "show-link";
+ public static final String ELEMENT_STYLE = "style";
+ public static final String ELEMENT_STYLECLASS = "style-class";
+ public static final String ELEMENT_IMAGE = "image";
+ public static final String ELEMENT_ACTIONLISTENER = "action-listener";
+ public static final String ELEMENT_HREF = "href";
+ public static final String ELEMENT_TARGET = "target";
+ public static final String ELEMENT_PARAMS = "params";
+ public static final String ELEMENT_PARAM = "param";
+ public static final String ATTRIBUTE_ID = "id";
+ public static final String ATTRIBUTE_IDREF = "idref";
+ public static final String ATTRIBUTE_NAME = "name";
+ public static final String ATTRIBUTE_ALLOW = "allow";
+
+
+ /**
+ * @see org.alfresco.config.xml.elementreader.ConfigElementReader#parse(org.dom4j.Element)
+ */
+ @SuppressWarnings("unchecked")
+ public ConfigElement parse(Element element)
+ {
+ ActionsConfigElement configElement = new ActionsConfigElement();
+
+ if (element != null)
+ {
+ if (ActionsConfigElement.CONFIG_ELEMENT_ID.equals(element.getName()) == false)
+ {
+ throw new ConfigException("ActionsElementReader can only parse config elements of type 'Actions'");
+ }
+
+ Iterator actionItr = element.elementIterator(ELEMENT_ACTION);
+ while (actionItr.hasNext())
+ {
+ // work on each 'action' element in turn
+ Element actionElement = actionItr.next();
+
+ // parse the action definition for the element
+ ActionDefinition actionDef = parseActionDefinition(actionElement);
+
+ // add our finished action def to the map of all actions
+ configElement.addActionDefinition(actionDef);
+ }
+
+ Iterator actionGroupItr = element.elementIterator(ELEMENT_ACTIONGROUP);
+ while (actionGroupItr.hasNext())
+ {
+ // work on each 'action-group' element in turn
+ Element groupElement = actionGroupItr.next();
+ String groupId = groupElement.attributeValue(ATTRIBUTE_ID);
+ if (groupId == null || groupId.length() == 0)
+ {
+ throw new ConfigException("'action-group' config element specified without mandatory 'id' attribute.");
+ }
+
+ // build a structure to represent the action group
+ ActionGroup actionGroup = new ActionGroup(groupId);
+
+ // loop round each action ref and add them to the list for this action group
+ Iterator actionRefItr = groupElement.elementIterator(ELEMENT_ACTION);
+ while (actionRefItr.hasNext())
+ {
+ Element actionRefElement = actionRefItr.next();
+
+ // look for an action referred to be Id - this is the common use-case
+ ActionDefinition def = null;
+ String idRef = actionRefElement.attributeValue(ATTRIBUTE_IDREF);
+ if (idRef != null && idRef.length() != 0)
+ {
+ // try to find the referenced action by Id
+ def = configElement.getActionDefinition(idRef);
+ if (def == null)
+ {
+ throw new ConfigException("Action group '" + groupId +
+ "' cannot find action definition referenced by '" + idRef + "'");
+ }
+ }
+ else
+ {
+ // look for an action defined directly rather than referenced by Id
+ String id = actionRefElement.attributeValue(ATTRIBUTE_ID);
+ if (id != null && id.length() != 0)
+ {
+ def = parseActionDefinition(actionRefElement);
+ }
+ }
+ if (def != null)
+ {
+ actionGroup.addAction(def);
+ }
+ }
+
+ // get simple string properties for the action group
+ actionGroup.Style = groupElement.elementTextTrim(ELEMENT_STYLE);
+ actionGroup.StyleClass = groupElement.elementTextTrim(ELEMENT_STYLECLASS);
+ if (groupElement.element(ELEMENT_SHOWLINK) != null)
+ {
+ actionGroup.ShowLink = Boolean.parseBoolean(groupElement.element(ELEMENT_SHOWLINK).getTextTrim());
+ }
+
+ // add the action group to the map of all action groups
+ configElement.addActionGroup(actionGroup);
+ }
+ }
+
+ return configElement;
+ }
+
+ /**
+ * Parse an ActionDefinition from the specific config element.
+ *
+ * @param actionElement The config element containing the action def
+ *
+ * @return The populated ActionDefinition
+ */
+ public ActionDefinition parseActionDefinition(Element actionElement)
+ {
+ String actionId = actionElement.attributeValue(ATTRIBUTE_ID);
+ if (actionId == null || actionId.length() == 0)
+ {
+ throw new ConfigException("'action' config element specified without mandatory 'id' attribute.");
+ }
+
+ // build a structure to represent the action definition
+ ActionDefinition actionDef = new ActionDefinition(actionId);
+
+ // look for the permissions element - it can contain many permission
+ Element permissionsElement = actionElement.element(ELEMENT_PERMISSIONS);
+ if (permissionsElement != null)
+ {
+ // read and process each permission element
+ Iterator permissionItr = permissionsElement.elementIterator(ELEMENT_PERMISSION);
+ while (permissionItr.hasNext())
+ {
+ Element permissionElement = permissionItr.next();
+ boolean allow = true;
+ if (permissionElement.attributeValue(ATTRIBUTE_ALLOW) != null)
+ {
+ allow = Boolean.parseBoolean(permissionElement.attributeValue(ATTRIBUTE_ALLOW));
+ }
+ String permissionValue = permissionElement.getTextTrim();
+ if (allow)
+ {
+ actionDef.addAllowPermission(permissionValue);
+ }
+ else
+ {
+ actionDef.addDenyPermission(permissionValue);
+ }
+ }
+ }
+
+ // find and construct the specified evaluator class
+ Element evaluatorElement = actionElement.element(ELEMENT_EVALUATOR);
+ if (evaluatorElement != null)
+ {
+ Object evaluator;
+ String className = evaluatorElement.getTextTrim();
+ try
+ {
+ Class clazz = Class.forName(className);
+ evaluator = clazz.newInstance();
+ }
+ catch (Throwable err)
+ {
+ throw new ConfigException("Unable to construct action '" +
+ actionId + "' evaluator classname: " +className);
+ }
+ if (evaluator instanceof ActionEvaluator == false)
+ {
+ throw new ConfigException("Action '" + actionId + "' evaluator class '" +
+ className + "' does not implement ActionEvaluator interface.");
+ }
+ actionDef.Evaluator = (ActionEvaluator)evaluator;
+ }
+
+ // find any parameter values that the action requires
+ Element paramsElement = actionElement.element(ELEMENT_PARAMS);
+ if (paramsElement != null)
+ {
+ Iterator paramsItr = paramsElement.elementIterator(ELEMENT_PARAM);
+ while (paramsItr.hasNext())
+ {
+ Element paramElement = paramsItr.next();
+ String name = paramElement.attributeValue(ATTRIBUTE_NAME);
+ if (name == null || name.length() == 0)
+ {
+ throw new ConfigException("Action '" + actionId +
+ "' param does not have mandatory 'name' attribute.");
+ }
+ String value = paramElement.getTextTrim();
+ if (value == null || value.length() == 0)
+ {
+ throw new ConfigException("Action '" + actionId + "' param '" + name + "'" +
+ "' does not have a value.");
+ }
+ actionDef.addParam(name, value);
+ }
+ }
+
+ // get simple string properties for the action
+ actionDef.Label = actionElement.elementTextTrim(ELEMENT_LABEL);
+ actionDef.LabelMsg = actionElement.elementTextTrim(ELEMENT_LABELMSG);
+ actionDef.Tooltip = actionElement.elementTextTrim(ELEMENT_TOOLTIP);
+ actionDef.TooltipMsg = actionElement.elementTextTrim(ELEMENT_TOOLTIPMSG);
+ actionDef.Href = actionElement.elementTextTrim(ELEMENT_HREF);
+ actionDef.Target = actionElement.elementTextTrim(ELEMENT_TARGET);
+ actionDef.Action = actionElement.elementTextTrim(ELEMENT_ACTION);
+ actionDef.ActionListener = actionElement.elementTextTrim(ELEMENT_ACTIONLISTENER);
+ actionDef.Image = actionElement.elementTextTrim(ELEMENT_IMAGE);
+ actionDef.Style = actionElement.elementTextTrim(ELEMENT_STYLE);
+ actionDef.StyleClass = actionElement.elementTextTrim(ELEMENT_STYLECLASS);
+ if (actionElement.element(ELEMENT_SHOWLINK) != null)
+ {
+ actionDef.ShowLink = Boolean.parseBoolean(actionElement.element(ELEMENT_SHOWLINK).getTextTrim());
+ }
+
+ return actionDef;
+ }
+}
diff --git a/source/java/org/alfresco/web/config/ClientConfigElement.java b/source/java/org/alfresco/web/config/ClientConfigElement.java
index 091f30231a..ef2ecfd302 100644
--- a/source/java/org/alfresco/web/config/ClientConfigElement.java
+++ b/source/java/org/alfresco/web/config/ClientConfigElement.java
@@ -35,7 +35,7 @@ public class ClientConfigElement extends ConfigElementAdapter
private boolean shelfVisible = true;
private int searchMinimum = 3;
private String helpUrl = null;
- private String editLinkType = null;
+ private String editLinkType = "http";
private String homeSpacePermission = null;
/**
diff --git a/source/java/org/alfresco/web/ui/common/component/UIActionLink.java b/source/java/org/alfresco/web/ui/common/component/UIActionLink.java
index bb0ac4a88f..5a70bb4fa3 100644
--- a/source/java/org/alfresco/web/ui/common/component/UIActionLink.java
+++ b/source/java/org/alfresco/web/ui/common/component/UIActionLink.java
@@ -62,10 +62,9 @@ public class UIActionLink extends UICommand
this.padding = (Integer)values[1];
this.image = (String)values[2];
this.showLink = (Boolean)values[3];
- this.params = (Map)values[4];
- this.href = (String)values[5];
- this.tooltip = (String)values[6];
- this.target = (String)values[7];
+ this.href = (String)values[4];
+ this.tooltip = (String)values[5];
+ this.target = (String)values[6];
}
/**
@@ -73,16 +72,15 @@ public class UIActionLink extends UICommand
*/
public Object saveState(FacesContext context)
{
- Object values[] = new Object[8];
+ Object values[] = new Object[7];
// standard component attributes are saved by the super class
values[0] = super.saveState(context);
values[1] = this.padding;
values[2] = this.image;
values[3] = this.showLink;
- values[4] = this.params;
- values[5] = this.href;
- values[6] = this.tooltip;
- values[7] = this.target;
+ values[4] = this.href;
+ values[5] = this.tooltip;
+ values[6] = this.target;
return (values);
}
@@ -100,7 +98,7 @@ public class UIActionLink extends UICommand
{
if (this.params == null)
{
- this.params = new HashMap(3, 1.0f);
+ this.params = new HashMap(1, 1.0f);
}
return this.params;
}
@@ -328,6 +326,6 @@ public class UIActionLink extends UICommand
/** the onclick handler */
private String onclick = null;
- /** Map of child param name/values pairs */
+ /** Transient map of currently set param name/values pairs */
private Map params = null;
}
diff --git a/source/java/org/alfresco/web/ui/common/renderer/ActionLinkRenderer.java b/source/java/org/alfresco/web/ui/common/renderer/ActionLinkRenderer.java
index 767225cbc4..d0dc9faf3f 100644
--- a/source/java/org/alfresco/web/ui/common/renderer/ActionLinkRenderer.java
+++ b/source/java/org/alfresco/web/ui/common/renderer/ActionLinkRenderer.java
@@ -27,16 +27,12 @@ import javax.faces.event.ActionEvent;
import org.alfresco.web.ui.common.Utils;
import org.alfresco.web.ui.common.component.UIActionLink;
import org.alfresco.web.ui.common.component.UIMenu;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
/**
* @author kevinr
*/
public class ActionLinkRenderer extends BaseRenderer
{
- private static Log logger = LogFactory.getLog(ActionLinkRenderer.class);
-
// ------------------------------------------------------------------------------
// Renderer implementation
@@ -55,8 +51,7 @@ public class ActionLinkRenderer extends BaseRenderer
// on the request which match our params and set them into the component
UIActionLink link = (UIActionLink)component;
Map destParams = link.getParameterMap();
- destParams.clear();
- Map actionParams = getParameterMap(link);
+ Map actionParams = getParameterComponents(link);
if (actionParams != null)
{
for (String name : actionParams.keySet())
@@ -122,7 +117,7 @@ public class ActionLinkRenderer extends BaseRenderer
{
// generate JavaScript to set a hidden form field and submit
// a form which request attributes that we can decode
- linkBuf.append(Utils.generateFormSubmit(context, link, Utils.getActionHiddenFieldName(context, link), link.getClientId(context), getParameterMap(link)));
+ linkBuf.append(Utils.generateFormSubmit(context, link, Utils.getActionHiddenFieldName(context, link), link.getClientId(context), getParameterComponents(link)));
}
linkBuf.append('"');
@@ -270,7 +265,7 @@ public class ActionLinkRenderer extends BaseRenderer
if (link.getHref() == null)
{
buf.append(" getParameterMap(UIComponent component)
+ protected static Map getParameterComponents(UIComponent component)
{
Map params = null;
if (component.getChildCount() != 0)
{
- params = new HashMap(3, 1.0f);
+ params = new HashMap(component.getChildCount(), 1.0f);
for (Iterator i=component.getChildren().iterator(); i.hasNext(); /**/)
{
UIComponent child = (UIComponent)i.next();