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.ajax.markup.html.form;
018
019import org.apache.wicket.Component;
020import org.apache.wicket.ajax.AjaxRequestTarget;
021import org.apache.wicket.ajax.attributes.AjaxRequestAttributes;
022import org.apache.wicket.ajax.form.AjaxFormSubmitBehavior;
023import org.apache.wicket.markup.html.form.Button;
024import org.apache.wicket.markup.html.form.Form;
025import org.apache.wicket.model.IModel;
026import org.slf4j.Logger;
027import org.slf4j.LoggerFactory;
028
029/**
030 * A button that submits the form via Ajax. <br>
031 * Note that an HTML type attribute of "submit" is automatically changed to "button"- Use
032 * {@link AjaxFallbackButton} if you want to support non-Ajax form submits too.
033 * 
034 * @since 1.3
035 * 
036 * @author Igor Vaynberg (ivaynberg)
037 */
038public abstract class AjaxButton extends Button
039{
040        private static final long serialVersionUID = 1L;
041
042        private static final Logger logger = LoggerFactory.getLogger(AjaxButton.class);
043
044        private final Form<?> form;
045
046        /**
047         * Construct.
048         * 
049         * @param id
050         */
051        public AjaxButton(String id)
052        {
053                this(id, null, null);
054        }
055
056        /**
057         * 
058         * Construct.
059         * 
060         * @param id
061         * @param model
062         *            model used to set <code>value</code> markup attribute
063         */
064        public AjaxButton(String id, IModel<String> model)
065        {
066                this(id, model, null);
067        }
068
069        /**
070         * 
071         * Construct.
072         * 
073         * @param id
074         * @param form
075         */
076        public AjaxButton(String id, Form<?> form)
077        {
078                this(id, null, form);
079        }
080
081
082        /**
083         * Construct.
084         * 
085         * @param id
086         * @param model
087         *            model used to set <code>value</code> markup attribute
088         * @param form
089         */
090        public AjaxButton(String id, IModel<String> model, final Form<?> form)
091        {
092                super(id, model);
093                this.form = form;
094        }
095
096        @Override
097        protected void onInitialize()
098        {
099                super.onInitialize();
100
101                add(newAjaxFormSubmitBehavior("click"));
102        }
103
104        protected AjaxFormSubmitBehavior newAjaxFormSubmitBehavior(String event)
105        {
106                return new AjaxFormSubmitBehavior(form, event)
107                {
108                        private static final long serialVersionUID = 1L;
109
110                        @Override
111                        protected void onSubmit(AjaxRequestTarget target)
112                        {
113                                AjaxButton.this.onSubmit(target);
114                        }
115
116                        @Override
117                        protected void onAfterSubmit(AjaxRequestTarget target)
118                        {
119                                AjaxButton.this.onAfterSubmit(target);
120                        }
121
122                        @Override
123                        protected void onError(AjaxRequestTarget target)
124                        {
125                                AjaxButton.this.onError(target);
126                        }
127
128                        @Override
129                        protected void updateAjaxAttributes(AjaxRequestAttributes attributes)
130                        {
131                                super.updateAjaxAttributes(attributes);
132
133                                // do not allow normal form submit to happen
134                                attributes.setPreventDefault(true);
135
136                                AjaxButton.this.updateAjaxAttributes(attributes);
137                        }
138                        
139                        @Override
140                        protected boolean shouldTriggerJavaScriptSubmitEvent()
141                        {
142                                return AjaxButton.this.shouldTriggerJavaScriptSubmitEvent();
143                        }
144
145                        @Override
146                        public boolean getDefaultProcessing()
147                        {
148                                return AjaxButton.this.getDefaultFormProcessing();
149                        }
150                        
151                        @Override
152                        public boolean getStatelessHint(Component component)
153                        {
154                                return AjaxButton.this.getStatelessHint();
155                        }
156                };
157        }
158
159        /**
160         * Controls whether or not a JS <code>submit</code> should be triggered on the submitting form.
161         * False by default.
162         * 
163         * @return true if <code>submit</code> should be triggered, false otherwise
164         */
165        protected boolean shouldTriggerJavaScriptSubmitEvent()
166        {
167                return false;
168        }
169
170        protected void updateAjaxAttributes(AjaxRequestAttributes attributes)
171        {
172        }
173
174        /**
175         * Returns the form if it was set in constructor, otherwise returns the form nearest in parent
176         * hierarchy.
177         * 
178         * @see org.apache.wicket.markup.html.form.FormComponent#getForm()
179         */
180        @Override
181        public Form<?> getForm()
182        {
183                if (form != null)
184                {
185                        return form;
186                }
187                else
188                {
189                        return super.getForm();
190                }
191        }
192
193        /**
194         * This method is never called.
195         * 
196         * @see #onSubmit(AjaxRequestTarget)
197         */
198        @Override
199        public final void onSubmit()
200        {
201                logger.warn("unexpected invocation of #onSubmit() on {}", this);
202        }
203
204        @Override
205        public final void onAfterSubmit()
206        {
207                logger.warn("unexpected invocation of #onAfterSubmit() on {}", this);
208        }
209
210        /**
211         * This method is never called.
212         * 
213         * @see #onError(AjaxRequestTarget)
214         */
215        @Override
216        public final void onError()
217        {
218                logger.warn("unexpected invocation of #onError() on {}", this);
219        }
220
221        /**
222         * Listener method invoked on form submit with no errors, before {@link Form#onSubmit()}.
223         * 
224         * @param target
225         */
226        protected void onSubmit(AjaxRequestTarget target)
227        {
228        }
229
230        /**
231         * Listener method invoked on form submit with no errors, after {@link Form#onSubmit()}.
232         *
233         * @param target
234         */
235        protected void onAfterSubmit(AjaxRequestTarget target)
236        {
237        }
238
239        /**
240         * Listener method invoked on form submit with errors
241         *
242         * @param target
243         */
244        protected void onError(AjaxRequestTarget target)
245        {
246        }
247
248        @Override
249        protected boolean getStatelessHint()
250        {
251                return false;
252        }
253}