001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.wicket.behavior;
018
019import java.io.Serializable;
020
021import org.apache.wicket.AttributeModifier;
022import org.apache.wicket.model.IModel;
023import org.apache.wicket.util.string.Strings;
024
025/**
026 * AttributeModifier that appends the given value, rather than replace it. This is especially useful
027 * for adding CSS classes to markup elements, or adding JavaScript snippets to existing element
028 * handlers.
029 * 
030 * <pre>
031 *     &lt;a href=&quot;#&quot; wicket:id=&quot;foo&quot; class=&quot;link&quot; onmouseover=&quot;doSomething()&quot;&gt;
032 * </pre>
033 * 
034 * can be modified with these AttributeAppenders:
035 * 
036 * <pre>
037 * link.add(new AttributeAppender(&quot;class&quot;, Model.of(&quot;hot&quot;)));
038 * link.add(new AttributeAppender(&quot;onmouseover&quot;, Model.of(&quot;foo();return false;&quot;)).setSeparator(&quot;;&quot;));
039 * </pre>
040 * 
041 * this will result in the following markup:
042 * 
043 * <pre>
044 *     &lt;a href=&quot;#&quot; wicket:id=&quot;foo&quot; class=&quot;link hot&quot; onmouseover=&quot;doSomething();foo();return false;&quot;&gt;
045 * </pre>
046 * 
047 * @see AttributeModifier#append(String, IModel)
048 * @see AttributeModifier#append(String, Serializable)
049 * @see AttributeModifier#prepend(String, IModel)
050 * @see AttributeModifier#prepend(String, Serializable)
051 * 
052 * @author Martijn Dashorst
053 */
054public class AttributeAppender extends AttributeModifier
055{
056        private static final long serialVersionUID = 1L;
057
058        /**
059         * Separator between the current value and the concatenated value, typically a space ' ' or
060         * colon ';'.
061         */
062        private String separator;
063
064        /**
065         * Creates an attribute modifier that concatenates the {@code replaceModel} to the attribute's
066         * current value, optionally separated by the {@link #getSeparator() separator}.
067         * 
068         * @param attribute
069         * @param replaceModel
070         */
071        public AttributeAppender(String attribute, IModel<?> replaceModel)
072        {
073                super(attribute, replaceModel);
074        }
075
076        /**
077         * Creates an attribute modifier that appends the {@code value} to the attribute's current
078         * value, optionally separated by the {@link #getSeparator() separator}.
079         * 
080         * @param attribute
081         * @param value
082         */
083        public AttributeAppender(String attribute, Serializable value)
084        {
085                super(attribute, value);
086        }
087
088        /**
089         * Creates an AttributeModifier that appends the value to the current value of the
090         * attribute, and will add the attribute when it is not there already.
091         *
092         * @param attribute
093         *            the attribute to append the appendModels value to
094         * @param value
095         *            the value to append
096         * @param separator
097         *            the separator string, comes between the original value and the append value
098         */
099        public AttributeAppender(String attribute, Serializable value, String separator)
100        {
101                super(attribute, value);
102                setSeparator(separator);
103        }
104
105        /**
106         * Creates an AttributeModifier that appends the appendModel's value to the current value of the
107         * attribute, and will add the attribute when it is not there already.
108         * 
109         * @param attribute
110         *            the attribute to append the appendModels value to
111         * @param appendModel
112         *            the model supplying the value to append
113         * @param separator
114         *            the separator string, comes between the original value and the append value
115         */
116        public AttributeAppender(String attribute, IModel<?> appendModel, String separator)
117        {
118                super(attribute, appendModel);
119                setSeparator(separator);
120        }
121
122        /**
123         * Gets the separator used by attribute appenders and prependers.
124         * 
125         * @return the separator used by attribute appenders and prependers.
126         */
127        public String getSeparator()
128        {
129                return separator;
130        }
131
132        /**
133         * Sets the separator used by attribute appenders and prependers.
134         * 
135         * @param separator
136         *            a space, semicolon or other character used to separate the current value and the
137         *            appended/prepended value.
138         * @return this
139         */
140        public AttributeAppender setSeparator(String separator)
141        {
142                this.separator = separator;
143                return this;
144        }
145
146        @Override
147        protected Serializable newValue(String currentValue, String appendValue)
148        {
149                // Short circuit when one of the values is empty: return the other value.
150                if (Strings.isEmpty(currentValue))
151                {
152                        return appendValue;
153                }
154                else if (Strings.isEmpty(appendValue))
155                {
156                        return currentValue;
157                }
158                StringBuilder sb = new StringBuilder(currentValue);
159                sb.append((getSeparator() == null ? "" : getSeparator()));
160                sb.append(appendValue);
161                return sb.toString();
162        }
163
164        @Override
165        public String toString()
166        {
167                String attributeModifier = super.toString();
168                attributeModifier = attributeModifier.substring(0, attributeModifier.length() - 2) +
169                        ", separator=" + separator + "]";
170                return attributeModifier;
171        }
172}