Created
March 7, 2011 23:43
-
-
Save mraible/859534 to your computer and use it in GitHub Desktop.
What it took to implement extensionless URL with Wicket.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Index: wicket/src/main/webapp/decorators/default.jsp | |
=================================================================== | |
--- wicket/src/main/webapp/decorators/default.jsp (revision 242) | |
+++ wicket/src/main/webapp/decorators/default.jsp (revision ) | |
@@ -69,7 +69,7 @@ | |
<h2 class="accessibility">Navigation</h2> | |
<ul class="clearfix"> | |
<li><a href="${ctx}/" title="Home"><span>Home</span></a></li> | |
- <li><a href="${ctx}/app/users" title="View Users"><span>Users</span></a></li> | |
+ <li><a href="${ctx}/users" title="View Users"><span>Users</span></a></li> | |
</ul> | |
</div> | |
</div><!-- end nav --> | |
Index: wicket/src/main/java/org/appfuse/web/rootmount/RawPathUtil.java | |
=================================================================== | |
--- wicket/src/main/java/org/appfuse/web/rootmount/RawPathUtil.java (revision ) | |
+++ wicket/src/main/java/org/appfuse/web/rootmount/RawPathUtil.java (revision ) | |
@@ -0,0 +1,51 @@ | |
+package org.appfuse.web.rootmount; | |
+ | |
+import org.apache.wicket.protocol.http.request.InvalidUrlException; | |
+ | |
+import java.io.UnsupportedEncodingException; | |
+import java.net.URLDecoder; | |
+ | |
+/** | |
+ * Utilities to work with raw paths as given to {@link RootMountedUrlCodingStrategy#accepts(String)}. | |
+ * <p> | |
+ * Assumes that the servlet container is configured to work with UTF-8 URLs. | |
+ * | |
+ * @author Erik van Oosten | |
+ */ | |
+public class RawPathUtil { | |
+ | |
+ /** | |
+ * Decode and split the path into its path parts. | |
+ * | |
+ * @param rawPath the raw request path (can be empty or null) | |
+ * @return the path split on "/", or null when rawPath is empty or null | |
+ * @throws org.apache.wicket.protocol.http.request.InvalidUrlException when the URL could not be decoded | |
+ */ | |
+ public static String[] splitToPathParts(String rawPath) { | |
+ if (rawPath == null || rawPath.length() == 0) { | |
+ return null; | |
+ } | |
+ try { | |
+ return URLDecoder.decode(rawPath, "UTF-8").split("/"); | |
+ } catch (UnsupportedEncodingException e) { | |
+ throw new InvalidUrlException("Could not decode URL"); | |
+ } | |
+ } | |
+ | |
+ /** | |
+ * Decode and give the first path part. | |
+ * | |
+ * @param rawPath the raw request path (can be empty or null) | |
+ * @return the first path part or null when there is none | |
+ * @throws org.apache.wicket.protocol.http.request.InvalidUrlException when the URL could not be decoded | |
+ */ | |
+ public static String firstPathPath(String rawPath) { | |
+ String[] pathParts = splitToPathParts(rawPath); | |
+ if (pathParts == null || pathParts.length == 0) { | |
+ return null; | |
+ } | |
+ String firstPathPart = pathParts[0]; | |
+ return firstPathPart == null || firstPathPart.length() == 0 ? null : firstPathPart; | |
+ } | |
+ | |
+} | |
Index: wicket/src/main/java/org/appfuse/web/Application.java | |
=================================================================== | |
--- wicket/src/main/java/org/appfuse/web/Application.java (revision 190) | |
+++ wicket/src/main/java/org/appfuse/web/Application.java (revision ) | |
@@ -1,5 +1,7 @@ | |
package org.appfuse.web; | |
+import org.apache.wicket.request.IRequestCycleProcessor; | |
+import org.appfuse.web.pages.DefaultUrlCodingStrategy; | |
import org.appfuse.web.pages.Index; | |
import org.appfuse.web.pages.UserForm; | |
import org.appfuse.web.pages.UserList; | |
@@ -7,8 +9,24 @@ | |
import org.apache.wicket.settings.IRequestCycleSettings; | |
import org.apache.wicket.spring.injection.annot.SpringComponentInjector; | |
import org.apache.wicket.protocol.http.WebApplication; | |
+import org.appfuse.web.rootmount.RootMountedUrlCodingStrategy; | |
+import org.appfuse.web.rootmount.RootWebRequestProcessor; | |
+import java.util.ArrayList; | |
+import java.util.List; | |
+ | |
public class Application extends WebApplication { | |
+ | |
+ private List<RootMountedUrlCodingStrategy> rootMounts = new ArrayList<RootMountedUrlCodingStrategy>(); | |
+ | |
+ /** | |
+ * Constructor | |
+ */ | |
+ public Application() { | |
+ // NOTE: there is no need to synchronize this list as it is written to from the init() method. | |
+ rootMounts = new ArrayList<RootMountedUrlCodingStrategy>(10); | |
+ } | |
+ | |
@Override | |
public void init() { | |
super.init(); | |
@@ -22,11 +40,35 @@ | |
getMarkupSettings().setStripWicketTags(true); | |
// make bookmarkable pages for easy linking from Menu/SiteMesh | |
- mountBookmarkablePage("/users", UserList.class); | |
- mountBookmarkablePage("/userform", UserForm.class); | |
+ //mountBookmarkablePage("/index", Index.class); | |
+ mountOnRoot(new DefaultUrlCodingStrategy("/users", UserList.class)); | |
+ mountOnRoot(new DefaultUrlCodingStrategy("/userform", UserForm.class)); | |
} | |
public Class<Index> getHomePage() { | |
return Index.class; | |
} | |
+ | |
+ /** | |
+ * Mount a target url strategy no the root URL. | |
+ * | |
+ * @param strategy the strategy (not null) | |
+ */ | |
+ private void mountOnRoot(RootMountedUrlCodingStrategy strategy) { | |
+ rootMounts.add(strategy); | |
+ | |
+ // Also add to the wicket mounts so that it can be found when searched by target page class. | |
+ mount(strategy); | |
-} | |
\ No newline at end of file | |
+ } | |
+ | |
+ @Override | |
+ protected IRequestCycleProcessor newRequestCycleProcessor() { | |
+ | |
+ return new RootWebRequestProcessor(rootMounts); | |
+ | |
+ // Alternative that redirects all unknown requests to the not found page. | |
+ // Please read {@link RootWebRequestProcessor class comment} before you enable this. | |
+ // | |
+ // return new RootWebRequestProcessor(rootMounts, NotFoundPage.class); | |
+ } | |
+} | |
\ No newline at end of file | |
Index: wicket/src/main/java/org/appfuse/web/rootmount/RootMountedUrlCodingStrategy.java | |
=================================================================== | |
--- wicket/src/main/java/org/appfuse/web/rootmount/RootMountedUrlCodingStrategy.java (revision ) | |
+++ wicket/src/main/java/org/appfuse/web/rootmount/RootMountedUrlCodingStrategy.java (revision ) | |
@@ -0,0 +1,34 @@ | |
+package org.appfuse.web.rootmount; | |
+ | |
+import org.apache.wicket.request.target.coding.IRequestTargetUrlCodingStrategy; | |
+ | |
+/** | |
+ * A TargetUrlCodingStrategy that can be mounted on the root. | |
+ * | |
+ * <p>Every implementation of RootMountedUrlCodingStrategy MUST | |
+ * remove the mount path from the URL upon an encode.</p> | |
+ * | |
+ * @author Erik van Oosten | |
+ */ | |
+public interface RootMountedUrlCodingStrategy extends IRequestTargetUrlCodingStrategy { | |
+ | |
+ /** | |
+ * Determine whether the path is accepted by this URL coding strategy. | |
+ * <p> | |
+ * Note: for each request that is not handled by the regular wicket mounts, this method is | |
+ * called twice. Result caching is left to the implementation. | |
+ * <p> | |
+ * Note 2: there is no guarantee that this method is only invoked twice per request, there might be more. | |
+ * <p> | |
+ * Note 3: during the first invocation in a request, | |
+ * {@link org.apache.wicket.Application#get() Application.get()}, | |
+ * {@link org.apache.wicket.Session#get() Session.get()} and | |
+ * {@link org.apache.wicket.RequestCycle#get() RequestCycle.get()} return null. | |
+ * | |
+ * @param rawPath the complete raw path (could be null or empty) | |
+ * (See also {@link RawPathUtil}.) | |
+ * @return true when the path is accepted by this URL coding strategy, false otherwise | |
+ */ | |
+ boolean accepts(String rawPath); | |
+ | |
+} | |
Index: wicket/src/main/java/org/appfuse/web/pages/DefaultUrlCodingStrategy.java | |
=================================================================== | |
--- wicket/src/main/java/org/appfuse/web/pages/DefaultUrlCodingStrategy.java (revision ) | |
+++ wicket/src/main/java/org/appfuse/web/pages/DefaultUrlCodingStrategy.java (revision ) | |
@@ -0,0 +1,26 @@ | |
+package org.appfuse.web.pages; | |
+ | |
+import org.apache.wicket.Page; | |
+import org.appfuse.web.rootmount.RootMountedBookmarkablePageRequestTargetUrlCodingStrategy; | |
+ | |
+/** | |
+ * Url Strategy for allowing any page to be mounted as at the root context. | |
+ */ | |
+public class DefaultUrlCodingStrategy extends RootMountedBookmarkablePageRequestTargetUrlCodingStrategy { | |
+ | |
+ /** | |
+ * Constructor. | |
+ * | |
+ * @param mountPath the internal 'fake' mount path, its exact value does not matter as long as | |
+ * it is a unique mount path in the entire application (not null) | |
+ * @param bookmarkablePageClass type of target page (not null) See constructor of base class. | |
+ * @param <P> type of target page | |
+ */ | |
+ public <P extends Page> DefaultUrlCodingStrategy(String mountPath, Class<P> bookmarkablePageClass) { | |
+ super(mountPath, bookmarkablePageClass, null); | |
+ } | |
+ | |
+ public boolean accepts(String rawPath) { | |
+ return true; | |
+ } | |
+} | |
Index: wicket/src/main/java/org/appfuse/web/rootmount/RootWebRequestProcessor.java | |
=================================================================== | |
--- wicket/src/main/java/org/appfuse/web/rootmount/RootWebRequestProcessor.java (revision ) | |
+++ wicket/src/main/java/org/appfuse/web/rootmount/RootWebRequestProcessor.java (revision ) | |
@@ -0,0 +1,201 @@ | |
+package org.appfuse.web.rootmount; | |
+ | |
+import org.apache.wicket.Page; | |
+import org.apache.wicket.Request; | |
+import org.apache.wicket.protocol.http.request.urlcompressing.UrlCompressingWebCodingStrategy; | |
+import org.apache.wicket.protocol.http.request.urlcompressing.UrlCompressingWebRequestProcessor; | |
+import org.apache.wicket.request.IRequestCodingStrategy; | |
+import org.apache.wicket.request.target.coding.IRequestTargetUrlCodingStrategy; | |
+import org.apache.wicket.request.target.coding.QueryStringUrlCodingStrategy; | |
+import org.apache.wicket.util.string.Strings; | |
+ | |
+import java.util.List; | |
+ | |
+/** | |
+ * Url coding web request processor to catch parameters directly on the root mount path. | |
+ * For example used to support URLs of the form http://www.example.com/member. | |
+ * | |
+ * <p>To use root mounts, make sure your application overrides | |
+ * {@link org.apache.wicket.protocol.http.WebApplication#newRequestCycleProcessor} | |
+ * and returns an instance of this. Secondly, these root mounts <strong>MUST</strong> be mounted directly via | |
+ * {@link org.apache.wicket.protocol.http.WebApplication#mount(org.apache.wicket.request.target.coding.IRequestTargetUrlCodingStrategy)}. | |
+ * For example use {@link org.appfuse.web.Application#mountOnRoot(RootMountedUrlCodingStrategy)}. | |
+ * | |
+ * <p>In addition you may want to configure ignorePaths as described below. | |
+ * | |
+ * <p>The following request handlers are considered in order: | |
+ * <ol> | |
+ * <li>As in Wicket's normal request handling: all normal page mounts (created with the | |
+ * WebApplication#mount* methods), mounted resources, call backs to Link's, ajax requests, etc. | |
+ * <li>Pages mounted as given to the constructor of this. They are tried in the order as given. | |
+ * <li>The not-found page (when not null). | |
+ * <li>Fall back to the servlet container to handle non-Wicket content (this includes servlets configured | |
+ * in web.xml and all static content in the WEB-INF folder). | |
+ * </ol> | |
+ * | |
+ * <p>To speed up URL processing, it is <strong>RECOMMENDED</strong> to move all non-Wicket content (i.e. servlets | |
+ * and static content in the WEB-INF directory) behind a clear URL path and let the Wicket filter ignore these URLs. | |
+ * You <strong>MUST</strong> do this if you want to combine non-Wicket content with the optional not-found page. | |
+ * | |
+ * <p>Here is an example fragment of the <code>ignorePath</code> parameter that makes the Wicket filter ignore all | |
+ * request for <code>/favicon.ico</code>, <code>/robots.txt</code> and requests of which the path starts with | |
+ * <code>/static/</code> and <code>/servletpath/</code>: | |
+ * <pre> | |
+ * <!-- The Wicket application filter. --> | |
+ * <filter> | |
+ * <filter-name>wicket.filter</filter-name> | |
+ * <filter-class>org.apache.wicket.protocol.http.WicketFilter</filter-class> | |
+ * <init-param> | |
+ * <param-name>applicationFactoryClassName</param-name> | |
+ * <param-value>org.apache.wicket.spring.SpringWebApplicationFactory</param-value> | |
+ * </init-param> | |
+ * <init-param> | |
+ * <param-name>ignorePaths</param-name> | |
+ * <param-value>favicon.ico,robots.txt,static/,servletpath/</param-value> | |
+ * </init-param> | |
+ * </filter> | |
+ * </pre> | |
+ * You can find this XML in your WEB.xml. (The example XML above uses Spring to instantiate the application class.) | |
+ * | |
+ * <p>See class comment of {@link org.apache.wicket.protocol.http.request.urlcompressing.UrlCompressingWebRequestProcessor} for more information on the | |
+ * purpose of the base class. Alternatively, this could extend | |
+ * {@link org.apache.wicket.protocol.http.WebRequestCycleProcessor}. | |
+ * | |
+ * @author Erik van Oosten | |
+ */ | |
+public class RootWebRequestProcessor extends UrlCompressingWebRequestProcessor { | |
+ | |
+ private List<RootMountedUrlCodingStrategy> rootMounts; | |
+ private Class<? extends Page> notFoundPage; | |
+ | |
+ /** | |
+ * Constructor. | |
+ * | |
+ * @param rootMounts a list of root mounts in the order in which they are tried (not null) | |
+ * The list must be immutable or an implementation of something like | |
+ * {@link java.util.concurrent.CopyOnWriteArrayList}. | |
+ */ | |
+ public <P extends Page> RootWebRequestProcessor(List<RootMountedUrlCodingStrategy> rootMounts) { | |
+ this(rootMounts, null); | |
+ } | |
+ | |
+ /** | |
+ * Constructor. | |
+ * | |
+ * @param rootMounts a list of root mounts in the order in which they are tried (not null) | |
+ * The list must be immutable or an implementation of something like | |
+ * {@link java.util.concurrent.CopyOnWriteArrayList}. | |
+ * @param notFoundPage the page to forward to when none of the root mounts accepts the current request, or null | |
+ * to fall through to the servlet container. When this value is non-null, and you have non-wicket content, | |
+ * you <strong>MUST</strong> configure ignorePaths in the web.xml as described in the | |
+ * {@link org.appfuse.web.rootmount.RootWebRequestProcessor class comment} (for performance this is recommended anyway). | |
+ */ | |
+ public <P extends Page> RootWebRequestProcessor(List<RootMountedUrlCodingStrategy> rootMounts, Class<P> notFoundPage) { | |
+ this.rootMounts = rootMounts; | |
+ this.notFoundPage = notFoundPage; | |
+ } | |
+ | |
+ @Override | |
+ protected IRequestCodingStrategy newRequestCodingStrategy() { | |
+ return new FallbackUrlRequestCodingStrategy(); | |
+ } | |
+ | |
+ /** | |
+ * Url coding web strategy to catch parameters directly on the root mount path. | |
+ * Forwards all unmounted requests to the FallbackUrlPage. | |
+ */ | |
+ private class FallbackUrlRequestCodingStrategy extends UrlCompressingWebCodingStrategy { | |
+ | |
+ /** | |
+ * During a simple request cycle this method is invoked twice: | |
+ * 1. by Wicket's filter to determine whether we have a request that needs | |
+ * to be handled by Wicket at all (returning a non-null value is sufficient) | |
+ * (This step is skipped for resources and the home page.) | |
+ * 2. by Wicket's request handling (from WebRequestCycle) to actually start | |
+ * processing the request. In this second invocation the 'fake' mount path | |
+ * is present in the path argument, therefore Wicket is able to get the | |
+ * correct url coding strategy (in the call to the super class), and there | |
+ * is no need to call {@link #findRootMount(String)} again. | |
+ * <p> | |
+ * This is also invoked during form processing and from mock requests (WicketTester). | |
+ * | |
+ * @param path the relative path (the requested uri, minus query string, | |
+ * context path, and filterPath. Relative, no leading '/'. | |
+ * @return the url coding strategy to use or null when this is not a Wicket request | |
+ */ | |
+ @Override | |
+ public IRequestTargetUrlCodingStrategy urlCodingStrategyForPath(String path) { | |
+ IRequestTargetUrlCodingStrategy strategy = super.urlCodingStrategyForPath(path); | |
+ | |
+ // Wicket could not find a (mounted) target for the given path, lets see if it is | |
+ // mounted on the root path. | |
+ if (strategy == null && !Strings.isEmpty(path)) { | |
+ | |
+ // Determine the target and return the URL coding strategy (if any) | |
+ RootMountedUrlCodingStrategy rootStrategy = findRootMount(path); | |
+ | |
+ if (rootStrategy == null) { | |
+ if (notFoundPage != null) { | |
+ // Forward to the not found page | |
+ strategy = new QueryStringUrlCodingStrategy("", notFoundPage); | |
+ } | |
+ } else { | |
+ strategy = rootStrategy; | |
+ } | |
+ } | |
+ | |
+ return strategy; | |
+ } | |
+ | |
+ /** | |
+ * Note that method may be invoked by Wicket for many different cases. Often however, the | |
+ * number of invocations is limited to once per request. | |
+ * | |
+ * @param request the request (not null) | |
+ * @return the path for this request (not null) | |
+ */ | |
+ @Override | |
+ protected String getRequestPath(Request request) { | |
+ // Get the real path of the request. | |
+ String path = request.getPath(); | |
+ | |
+ // Empty path is reserved for home page; | |
+ // no need to see if it is a root mounted path. | |
+ if (!Strings.isEmpty(path)) { | |
+ // Recompute the regular wicket url coding strategy | |
+ IRequestTargetUrlCodingStrategy wicketStrategy = | |
+ super.urlCodingStrategyForPath(path); | |
+ // Is this a regular Wicket path? If so, just leave it alone. | |
+ if (wicketStrategy == null) { | |
+ | |
+ // If not, it might be a root path. | |
+ RootMountedUrlCodingStrategy strategy = findRootMount(path); | |
+ if (strategy != null) { | |
+ // It is a root path; add the internal 'fake' mount path | |
+ // so that Wicket doesn't get confused. | |
+ path = strategy.getMountPath() + "/" + path; | |
+ } | |
+ } | |
+ } | |
+ | |
+ return path; | |
+ } | |
+ } | |
+ | |
+ /** | |
+ * Iterate over the root mounted url coding strategies to see if any accepts this path. | |
+ * | |
+ * @param path the relative path (the requested uri, minus query string, | |
+ * context path, and filterPath. Relative, no leading '/'. | |
+ * @return the first root mounted url coding strategies that accepts this path, or null when there are none | |
+ */ | |
+ private RootMountedUrlCodingStrategy findRootMount(String path) { | |
+ for (RootMountedUrlCodingStrategy rootMount : rootMounts) { | |
+ if (rootMount.accepts(path)) { | |
+ return rootMount; | |
+ } | |
+ } | |
+ return null; | |
+ } | |
+ | |
+} | |
Index: wicket/src/main/java/org/appfuse/web/rootmount/RootMountedBookmarkablePageRequestTargetUrlCodingStrategy.java | |
=================================================================== | |
--- wicket/src/main/java/org/appfuse/web/rootmount/RootMountedBookmarkablePageRequestTargetUrlCodingStrategy.java (revision ) | |
+++ wicket/src/main/java/org/appfuse/web/rootmount/RootMountedBookmarkablePageRequestTargetUrlCodingStrategy.java (revision ) | |
@@ -0,0 +1,47 @@ | |
+package org.appfuse.web.rootmount; | |
+ | |
+import org.apache.wicket.IRequestTarget; | |
+import org.apache.wicket.Page; | |
+import org.apache.wicket.request.target.coding.BookmarkablePageRequestTargetUrlCodingStrategy; | |
+ | |
+/** | |
+ * BookmarkablePageRequestTargetUrlCodingStrategy that mounts on the root. | |
+ * | |
+ * <p>An internal 'fake' mount path is used to do URL routing within Wicket. The internal mount path | |
+ * is removed when the URL is encoded. It is therefore never visible outside the Wicket application. | |
+ * | |
+ * <p>Note that the original | |
+ * {@link org.apache.wicket.request.target.coding.BookmarkablePageRequestTargetUrlCodingStrategy#encode(org.apache.wicket.IRequestTarget)} | |
+ * is final and can therefore not be overridden here. Therefore, a patched version is needed. | |
+ * | |
+ * @author Erik van Oosten | |
+ */ | |
+public abstract class RootMountedBookmarkablePageRequestTargetUrlCodingStrategy | |
+ extends BookmarkablePageRequestTargetUrlCodingStrategy | |
+ implements RootMountedUrlCodingStrategy { | |
+ | |
+ /** | |
+ * Constructor. | |
+ * | |
+ * @param mountPath the internal 'fake' mount path, its exact value does not matter as long as | |
+ * it is a unique mount path in the entire application (not null) | |
+ * @param bookmarkablePageClass type of target page (not null) See constructor of base class. | |
+ * @param pageMapName the page map name or null for none | |
+ * @param <P> type of target page | |
+ */ | |
+ protected <P extends Page> RootMountedBookmarkablePageRequestTargetUrlCodingStrategy( | |
+ String mountPath, Class<P> bookmarkablePageClass, String pageMapName) { | |
+ | |
+ super(mountPath, bookmarkablePageClass, pageMapName); | |
+ } | |
+ | |
+ @Override | |
+ public CharSequence encode(IRequestTarget requestTarget) { | |
+ // Get the original URL (includes the internal mount path). | |
+ String url = super.encode(requestTarget).toString(); | |
+ // Remove the internal mount path to directly mount on "/". | |
+ // Note the +1 to also remove the '/' | |
+ return url.substring(getMountPath().length() + 1); | |
+ } | |
+ | |
+} | |
\ No newline at end of file | |
Index: wicket/src/main/webapp/WEB-INF/web.xml | |
=================================================================== | |
--- wicket/src/main/webapp/WEB-INF/web.xml (revision 163) | |
+++ wicket/src/main/webapp/WEB-INF/web.xml (revision ) | |
@@ -51,6 +51,10 @@ | |
<param-name>configuration</param-name> | |
<param-value>development</param-value> | |
</init-param> | |
+ <init-param> | |
+ <param-name>ignorePaths</param-name> | |
+ <param-value>images/,scripts/,styles/,dwr/,crossdomain.xml,favicon.ico</param-value> | |
+ </init-param> | |
</filter> | |
<context-param> | |
@@ -67,7 +71,6 @@ | |
<filter-name>encodingFilter</filter-name> | |
<url-pattern>/*</url-pattern> | |
</filter-mapping> | |
- | |
<filter-mapping> | |
<filter-name>messageFilter</filter-name> | |
<url-pattern>/*</url-pattern> | |
@@ -79,15 +82,13 @@ | |
<filter-name>lazyLoadingFilter</filter-name> | |
<url-pattern>/*</url-pattern> | |
</filter-mapping>--> | |
- | |
<filter-mapping> | |
<filter-name>sitemesh</filter-name> | |
<url-pattern>/*</url-pattern> | |
</filter-mapping> | |
- | |
<filter-mapping> | |
<filter-name>wicket</filter-name> | |
- <url-pattern>/app/*</url-pattern> | |
+ <url-pattern>/*</url-pattern> | |
</filter-mapping> | |
<listener> | |
@@ -108,10 +109,6 @@ | |
<url-pattern>/dwr/*</url-pattern> | |
</servlet-mapping> | |
- <welcome-file-list> | |
- <welcome-file>index.jsp</welcome-file> | |
- </welcome-file-list> | |
- | |
<error-page> | |
<error-code>404</error-code> | |
<location>/404.jsp</location> | |
Index: wicket/src/main/java/org/appfuse/web/pages/UserForm.html | |
=================================================================== | |
--- wicket/src/main/java/org/appfuse/web/pages/UserForm.html (revision 181) | |
+++ wicket/src/main/java/org/appfuse/web/pages/UserForm.html (revision ) | |
@@ -53,5 +53,5 @@ | |
</form> | |
<script type="text/javascript"> | |
- Form.focusFirstElement($('userForm')); | |
+ Form.focusFirstElement(document.forms[0]); | |
</script> | |
\ No newline at end of file |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment