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.IRequestListener; 020import org.apache.wicket.markup.ComponentTag; 021import org.apache.wicket.markup.head.IHeaderResponse; 022import org.apache.wicket.markup.head.OnEventHeaderItem; 023import org.apache.wicket.model.IModel; 024 025/** 026 * A link which can be used exactly like a Button to submit a Form. The onclick of the link will use 027 * JavaScript to submit the form. 028 * 029 * <p> 030 * You can use this class 2 ways. First with the constructor without a Form object then this Link 031 * must be inside a Form so that it knows what form to submit to. Second way is to use the Form 032 * constructor then that form will be used to submit to. 033 * </p> 034 * <p> 035 * 036 * <pre> 037 * Form f = new Form("linkForm", new CompoundPropertyModel(mod)); 038 * f.add(new TextField("value1")); 039 * f.add(new SubmitLink("link1") { 040 * protected void onSubmit() { 041 * System.out.println("Link1 was clicked, value1 is: " 042 * + mod.getValue1()); 043 * }; 044 * }); 045 * add(new SubmitLink("link2",f) { 046 * protected void onSubmit() { 047 * System.out.println("Link2 was clicked, value1 is: " 048 * + mod.getValue1()); 049 * }; 050 * }); 051 * 052 * <form wicket:id="linkForm" > 053 * <input wicket:id="value1" type="text" size="30"/> 054 * <a wicket:id="link1">Press link1 to submit</a> 055 * <input type="submit" value="Send"/> 056 * </form> 057 * <a wicket:id="link2">Press link 2 to submit</a> 058 * </pre> 059 * 060 * </p> 061 * <p> 062 * If this link is not placed in a form or given a form to cooperate with, it will fall back to a 063 * normal link behavior, meaning that {@link #onSubmit()} will be called without any other 064 * consequences. 065 * </p> 066 * <p> 067 * To customize the JavaScript code used to submit the form we must override {@link #getTriggerJavaScript()}. 068 * This can be helpful to implement additional client side behaviors like disabling the link during form submission. 069 * </p> 070 * 071 * @author chris 072 * @author jcompagner 073 * @author Igor Vaynberg (ivaynberg) 074 * @author Eelco Hillenius 075 * 076 */ 077public class SubmitLink extends AbstractSubmitLink 078{ 079 private static final long serialVersionUID = 1L; 080 081 /** 082 * With this constructor the SubmitLink must be inside a Form. 083 * 084 * @param id 085 * The id of the submitlink. 086 */ 087 public SubmitLink(String id) 088 { 089 super(id); 090 } 091 092 /** 093 * With this constructor the SubmitLink will submit the {@link Form} that is given when the link 094 * is clicked on. 095 * 096 * The SubmitLink doesn't have to be inside the {@link Form}. But currently if it is outside the 097 * {@link Form} and the SubmitLink is rendered first, then the {@link Form} will have a 098 * generated javascript/css id. The markup javascript/css id that can exist will be overridden. 099 * 100 * @param id 101 * The id of the submitlink. 102 * @param form 103 * The form which this submitlink must submit. 104 */ 105 public SubmitLink(String id, Form<?> form) 106 { 107 super(id, form); 108 } 109 110 111 /** 112 * With this constructor the SubmitLink must be inside a Form. 113 * 114 * @param id 115 * The id of the submitlink. 116 * @param model 117 * The model for this submitlink, It won't be used by the submit link itself, but it 118 * can be used for keeping state 119 */ 120 public SubmitLink(String id, IModel<?> model) 121 { 122 super(id, model); 123 } 124 125 /** 126 * With this constructor the SubmitLink will submit the {@link Form} that is given when the link 127 * is clicked on. 128 * 129 * The SubmitLink doesn't have to be in inside the {@link Form}. But currently if it is outside 130 * the {@link Form} and the SubmitLink will be rendered first. Then the {@link Form} will have a 131 * generated javascript/css id. The markup javascript/css id that can exist will be overridden. 132 * 133 * @param id 134 * The id of the submitlink. 135 * @param model 136 * The model for this submitlink, It won't be used by the submit link itself, but it 137 * can be used for keeping state 138 * @param form 139 * The form which this submitlink must submit. 140 */ 141 public SubmitLink(String id, IModel<?> model, Form<?> form) 142 { 143 super(id, model, form); 144 } 145 146 /** 147 * This method is here as a means to fall back on normal link behavior when this link is not 148 * nested in a form. Not intended to be called by clients directly. 149 * 150 * @see IRequestListener#onRequest() 151 */ 152 public final void onLinkClicked() 153 { 154 onSubmit(); 155 onAfterSubmit(); 156 } 157 158 @Override 159 protected void onComponentTag(ComponentTag tag) 160 { 161 super.onComponentTag(tag); 162 163 if (isEnabledInHierarchy()) 164 { 165 if (tag.getName().equalsIgnoreCase("a") || tag.getName().equalsIgnoreCase("link") 166 || tag.getName().equalsIgnoreCase("area")) 167 { 168 tag.put("href", "#"); 169 } 170 else if (tag.getName().equalsIgnoreCase("button")) 171 { 172 // WICKET-5597 prevent default submit 173 tag.put("type", "button"); 174 } 175 } 176 else 177 { 178 disableLink(tag); 179 } 180 } 181 182 @Override 183 public void renderHead(IHeaderResponse response) 184 { 185 super.renderHead(response); 186 187 if (isEnabledInHierarchy()) 188 { 189 response.render(OnEventHeaderItem.forComponent(this, "click", getTriggerJavaScript())); 190 } 191 } 192 193 /** 194 * Controls whether or not clicking on this link will trigger a javascript submit event, firing 195 * any submit handler added to the form. True by default. 196 * 197 * @return true if form's javascript submit handlers should be invoked, false otherwise 198 */ 199 protected boolean shouldTriggerJavaScriptSubmitEvent() 200 { 201 return true; 202 } 203 204 /** 205 * The JavaScript which triggers this link. Method is non-final so that subclasses can decorate 206 * the provided script by wrapping their own JS around a call to super.getTriggerJavaScript(). 207 * 208 * @return The JavaScript to be executed when the link is clicked. 209 */ 210 protected CharSequence getTriggerJavaScript() 211 { 212 if (getForm() != null) 213 { 214 // find the root form - the one we are really going to submit 215 Form<?> root = getForm().getRootForm(); 216 217 StringBuilder script = new StringBuilder(); 218 script.append(root.getJsForSubmitter(this, shouldTriggerJavaScriptSubmitEvent())); 219 script.append("return false;"); 220 221 return script; 222 } 223 else 224 { 225 return null; 226 } 227 } 228 229 @Override 230 public void onError() 231 { 232 } 233 234 /** 235 * Override this method to provide special submit handling in a multi-button form. This method 236 * will be called <em>after</em> the form's onSubmit method. 237 */ 238 @Override 239 public void onAfterSubmit() 240 { 241 } 242 243 /** 244 * Override this method to provide special submit handling in a multi-button form. This method 245 * will be called <em>before</em> the form's onSubmit method. 246 */ 247 @Override 248 public void onSubmit() 249 { 250 } 251}