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.markup.html.form;
018
019import org.apache.wicket.markup.ComponentTag;
020import org.apache.wicket.markup.MarkupStream;
021import org.apache.wicket.markup.head.IHeaderResponse;
022import org.apache.wicket.markup.head.OnEventHeaderItem;
023import org.apache.wicket.model.IModel;
024import org.apache.wicket.util.string.Strings;
025
026/**
027 * A form button.
028 * <p>
029 * Within a form, you can nest Button components. Note that you don't have to do this to let the
030 * form work (a simple &lt;input type="submit".. suffices), but if you want to have different kinds
031 * of submit behavior it might be a good idea to use Buttons.
032 * </p>
033 * <p>
034 * The model property is used to set the &quot;value&quot; attribute. It will thus be the label of
035 * the button that shows up for end users. If you want the attribute to keep it's markup attribute
036 * value, don't provide a model, or let it return an empty string.
037 * </p>
038 * <p>
039 * When you add a Wicket Button to a form, and that button is clicked, by default the button's
040 * onSubmit method is called first, and after that the form's onSubmit method is called. If you want
041 * to change this (e.g. you don't want to call the form's onSubmit method, or you want it called
042 * before the button's onSubmit method), you can override Form.delegateSubmit.
043 * </p>
044 * <p>
045 * One other option you should know of is the 'defaultFormProcessing' property of Button components.
046 * When you set this to false (default is true), all validation and formupdating is bypassed and the
047 * onSubmit method of that button is called directly, and the onSubmit method of the parent form is
048 * not called. A common use for this is to create a cancel button.
049 * </p>
050 * 
051 * @author Jonathan Locke
052 * @author Eelco Hillenius
053 * 
054 */
055public class Button extends FormComponent<String> implements IFormSubmittingComponent
056{
057        private static final long serialVersionUID = 1L;
058
059        /**
060         * If false, all standard processing like validating and model updating is skipped.
061         */
062        private boolean defaultFormProcessing = true;
063
064        /**
065         * Constructor without a model. Buttons without models leave the markup attribute
066         * &quot;value&quot;. Provide a model if you want to set the button's label dynamically.
067         * 
068         * @see org.apache.wicket.Component#Component(String)
069         */
070        public Button(String id)
071        {
072                this(id, null);
073        }
074
075        /**
076         * Constructor taking an model for rendering the 'label' of the button (the value attribute of
077         * the input/button tag). Use a {@link org.apache.wicket.model.StringResourceModel} for a
078         * localized value.
079         * 
080         * @param id
081         *            Component id
082         * @param model
083         *            The model property is used to set the &quot;value&quot; attribute. It will thus be
084         *            the label of the button that shows up for end users. If you want the attribute to
085         *            keep it's markup attribute value, don't provide a model, or let it return an empty
086         *            string.
087         */
088        public Button(final String id, final IModel<String> model)
089        {
090                super(id, model);
091
092                setVersioned(true);
093                setOutputMarkupId(true);
094
095                // don't double encode the value. it is encoded by ComponentTag.writeOutput()
096                setEscapeModelStrings(false);
097        }
098
099        /**
100         * Override of the default initModel behaviour. This component <strong>will not</strong> use any
101         * compound model a parent, but only a model that is explicitly set.
102         * 
103         * @see org.apache.wicket.Component#initModel()
104         */
105        @Override
106        protected IModel<String> initModel()
107        {
108                return null;
109        }
110
111        /**
112         * Override to not throw exception if there is no parent form.
113         * 
114         * @return the parent form or {@code null}
115         */
116        @Override
117        public Form<?> getForm()
118        {
119                return Form.findForm(this);
120        }
121
122        /**
123         * Gets the defaultFormProcessing property. When false (default is true), all validation and
124         * formupdating is bypassed and the onSubmit method of that button is called directly, and the
125         * onSubmit method of the parent form is not called. A common use for this is to create a cancel
126         * button.
127         * 
128         * @return defaultFormProcessing
129         */
130        @Override
131        public final boolean getDefaultFormProcessing()
132        {
133                return defaultFormProcessing;
134        }
135
136        /**
137         * Sets the defaultFormProcessing property. When false (default is true), all validation and
138         * form updating is bypassed and the onSubmit method of that button is called directly, and the
139         * onSubmit method of the parent form is not called. A common use for this is to create a cancel
140         * button.
141         * 
142         * @param defaultFormProcessing
143         *            defaultFormProcessing
144         * @return This
145         */
146        @Override
147        public final Button setDefaultFormProcessing(boolean defaultFormProcessing)
148        {
149                if (this.defaultFormProcessing != defaultFormProcessing)
150                {
151                        addStateChange();
152                }
153
154                this.defaultFormProcessing = defaultFormProcessing;
155                return this;
156        }
157
158        /**
159         * This method does nothing, as any model of a button is only used to display the button's label
160         * (by setting it's markup attribute &quot;value&quot;).
161         * 
162         * @see org.apache.wicket.markup.html.form.FormComponent#updateModel()
163         */
164        @Override
165        public void updateModel()
166        {
167        }
168
169        /**
170         * Gets any script that should rendered as a &quot;click&quot; event handler for the button.
171         * Returns null by default, override this method to provide any script.
172         * 
173         * @return Any onClick JavaScript that should be used, returns null by default
174         */
175        protected String getOnClickScript()
176        {
177                return null;
178        }
179
180        /**
181         * Processes the component tag. A <tt>value</tt> attribute is added with the value of the model
182         * object, if available.
183         * 
184         * <p>
185         * <b>NOTE</b>. For a <tt>&lt;button&gt;</tt> the <tt>value</tt> attribute is not rendered,
186         * markup needs to be added within the button to display the button's label.
187         * </p>
188         * 
189         * @param tag
190         *            Tag to modify
191         * @see org.apache.wicket.Component#onComponentTag(ComponentTag)
192         */
193        @Override
194        protected void onComponentTag(final ComponentTag tag)
195        {
196                // Default handling for component tag
197                super.onComponentTag(tag);
198
199                if ("input".equals(tag.getName()))
200                {
201                        String value = getDefaultModelObjectAsString();
202                        if (Strings.isEmpty(value) == false)
203                        {
204                                tag.put("value", value);
205                        }
206                }
207        }
208
209        /**
210         * Adds a <tt>click</tt> event handler if the subclass specified javascript.
211         */
212        @Override
213        public void renderHead(IHeaderResponse response)
214        {
215                super.renderHead(response);
216
217                // If the subclass specified javascript, use that
218                final String onClickJavaScript = getOnClickScript();
219                if (onClickJavaScript != null)
220                {
221                        response.render(OnEventHeaderItem.forComponent(this, "click", onClickJavaScript));
222                }
223        }
224
225        @Override
226        public void onComponentTagBody(MarkupStream markupStream, ComponentTag openTag)
227        {
228                if ("button".equals(openTag.getName()))
229                {
230                        String modelObjectAsString = getDefaultModelObjectAsString();
231                        if (Strings.isEmpty(modelObjectAsString) == false) {
232                                replaceComponentTagBody(markupStream, openTag, modelObjectAsString);
233                                return;
234                        }
235                }
236
237                super.onComponentTagBody(markupStream, openTag);
238        }
239
240        @Override
241        public void onError()
242        {
243        }
244
245        /**
246         * Override this method to provide special submit handling in a multi-button form. It is called
247         * whenever the user clicks this particular button, except if validation fails. This method will
248         * be called <em>before</em> {@link Form#onSubmit()}.
249         */
250        @Override
251        public void onSubmit()
252        {
253        }
254
255        /**
256         * Override this method to provide special submit handling in a multi-button form. It is called
257         * whenever the user clicks this particular button, except if validation fails. This method will
258         * be called <em>after</em> {@link Form#onSubmit()}.
259         */
260        @Override
261        public void onAfterSubmit()
262        {
263        }
264}