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();