diff options
author | Ingo Kegel <ingo.kegel@ej-technologies.com> | 2014-10-28 13:45:19 +0300 |
---|---|---|
committer | Henri Sara <hesara@vaadin.com> | 2016-06-01 13:32:57 +0300 |
commit | c0babd786c4d2dd3bb22e343691ce4b3aded0c3f (patch) | |
tree | b2b53691e163bdb6d794248ce2cb8008b602d4c6 | |
parent | fb63a60cc40133a0062dd77b9694d80b1b39155c (diff) | |
download | vaadin-framework-c0babd786c4d2dd3bb22e343691ce4b3aded0c3f.tar.gz vaadin-framework-c0babd786c4d2dd3bb22e343691ce4b3aded0c3f.zip |
New login form (#8171)
The legacy LoginForm is substituted with the new one which is compatible
in API.
The patch contains modified code from the addon
https://vaadin.com/directory#addon/loginform
Change-Id: I2178291c97c2f66840f832a0bf932271534beb49
7 files changed, 566 insertions, 232 deletions
diff --git a/all/src/main/templates/release-notes.html b/all/src/main/templates/release-notes.html index 9d942d3134..a6ff88e79e 100644 --- a/all/src/main/templates/release-notes.html +++ b/all/src/main/templates/release-notes.html @@ -116,6 +116,9 @@ <li>The return type of BootstrapHandler.getWidgetsetForUI() has changed.</li> <li>Vaadin shared no longer depends on a custom build of Guava. Any project that depends on Guava as a transitive dependency should use standard Guava.</li> <li>Valo theme field error styles now apply to NativeSelect, ListSelect and TwinColSelect as well.</li> + <li>The LoginForm component has been rewritten to better support auto-completion of passwords on modern browsers. + Its API, look and DOM structure have changed somewhat, so any application level customizations of LoginForm need changes. + See also <a href="http://dev.vaadin.com/ticket/8171">#8171</a></li> <li>The way we handle GWT dependencies has been completely changed. See <a href="#gwtdep">this section</a> for more details</li> </ul> <h3 id="knownissues">Known Issues and Limitations</h3> diff --git a/client/src/main/java/com/vaadin/client/ui/loginform/LoginFormConnector.java b/client/src/main/java/com/vaadin/client/ui/loginform/LoginFormConnector.java new file mode 100644 index 0000000000..da80287826 --- /dev/null +++ b/client/src/main/java/com/vaadin/client/ui/loginform/LoginFormConnector.java @@ -0,0 +1,194 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package com.vaadin.client.ui.loginform; + +import com.google.gwt.dom.client.Element; +import com.google.gwt.event.dom.client.ClickEvent; +import com.google.gwt.event.dom.client.ClickHandler; +import com.google.gwt.event.dom.client.KeyCodes; +import com.google.gwt.event.dom.client.KeyDownEvent; +import com.google.gwt.event.dom.client.KeyDownHandler; +import com.google.gwt.user.client.DOM; +import com.google.gwt.user.client.ui.FocusWidget; +import com.google.gwt.user.client.ui.FormPanel; +import com.vaadin.client.ComponentConnector; +import com.vaadin.client.ConnectorHierarchyChangeEvent; +import com.vaadin.client.communication.StateChangeEvent; +import com.vaadin.client.ui.AbstractSingleComponentContainerConnector; +import com.vaadin.client.ui.VTextField; +import com.vaadin.client.ui.button.ButtonConnector; +import com.vaadin.client.ui.nativebutton.NativeButtonConnector; +import com.vaadin.client.ui.textfield.TextFieldConnector; +import com.vaadin.shared.Connector; +import com.vaadin.shared.ui.Connect; +import com.vaadin.shared.ui.loginform.LoginFormConstants; +import com.vaadin.shared.ui.loginform.LoginFormRpc; +import com.vaadin.shared.ui.loginform.LoginFormState; +import com.google.gwt.core.client.Scheduler; + +@Connect(com.vaadin.ui.LoginForm.class) +public class LoginFormConnector extends + AbstractSingleComponentContainerConnector { + + private VTextField passwordField; + private VTextField userField; + private LoginFormRpc loginFormRpc; + + @Override + public void updateCaption(ComponentConnector connector) { + + } + + @Override + public VLoginForm getWidget() { + return (VLoginForm) super.getWidget(); + } + + @Override + protected void init() { + super.init(); + + loginFormRpc = getRpcProxy(LoginFormRpc.class); + getWidget().addSubmitCompleteHandler(new FormPanel.SubmitCompleteHandler() { + @Override + public void onSubmitComplete(FormPanel.SubmitCompleteEvent event) { + valuesChanged(); + loginFormRpc.submitCompleted(); + } + }); + } + + @Override + public LoginFormState getState() { + return (LoginFormState) super.getState(); + } + + @Override + public void onConnectorHierarchyChange(ConnectorHierarchyChangeEvent event) { + ComponentConnector content = getContent(); + if (content != null) { + getWidget().setWidget(getContentWidget()); + } + } + + @Override + public void onStateChanged(StateChangeEvent stateChangeEvent) { + super.onStateChanged(stateChangeEvent); + + LoginFormState state = getState(); + userField = configureTextField(state.userNameFieldConnector, "username"); + passwordField = configureTextField(state.passwordFieldConnector, + "password"); + addSubmitButtonClickHandler(state.loginButtonConnector); + getWidget().setAction( + getResourceUrl(LoginFormConstants.LOGIN_RESOURCE_NAME)); + } + + private VTextField configureTextField(Connector connector, String id) { + if (connector != null) { + VTextField textField = ((TextFieldConnector) connector).getWidget(); + + textField.addKeyDownHandler(new SubmitKeyHandler()); + + Element element = textField.getElement(); + String externalId = element.getId(); + if (externalId == null || externalId.isEmpty() + || externalId.startsWith("gwt-")) { + element.setId(id); + } + DOM.setElementAttribute(element, "name", id); + DOM.setElementAttribute(element, "autocomplete", "on"); + + return textField; + } else { + return null; + } + } + + private void loginLater() { + Scheduler.get().scheduleFixedDelay(new Scheduler.RepeatingCommand() { + @Override + public boolean execute() { + login(); + return false; + } + }, 100); + } + + private void login() { + getWidget().submit(); + } + + private void addSubmitButtonClickHandler(Connector buttonConnector) { + if (buttonConnector instanceof ButtonConnector) { + addSubmitButtonClickHandler(((ButtonConnector) buttonConnector) + .getWidget()); + } else if (buttonConnector instanceof NativeButtonConnector) { + addSubmitButtonClickHandler(((NativeButtonConnector) buttonConnector) + .getWidget()); + } + } + + private void addSubmitButtonClickHandler(FocusWidget button) { + button.addClickHandler(new ClickHandler() { + @Override + public void onClick(ClickEvent event) { + login(); + } + }); + } + + private void valuesChanged() { + if (passwordField != null) { + passwordField.valueChange(true); + } + if (userField != null) { + userField.valueChange(true); + } + } + + private class SubmitKeyHandler implements KeyDownHandler { + + private int previousKeyCode; + + @Override + public void onKeyDown(KeyDownEvent event) { + int keyCode = event.getNativeKeyCode(); + if (keyCode == KeyCodes.KEY_ENTER) { + if (isInAutoComplete()) { + previousKeyCode = keyCode; + } else { + loginLater(); + } + } else { + previousKeyCode = keyCode; + } + } + + private boolean isInAutoComplete() { + switch (previousKeyCode) { + case KeyCodes.KEY_PAGEUP: + case KeyCodes.KEY_PAGEDOWN: + case KeyCodes.KEY_UP: + case KeyCodes.KEY_DOWN: + return true; + default: + return false; + } + } + } +} diff --git a/client/src/main/java/com/vaadin/client/ui/loginform/VLoginForm.java b/client/src/main/java/com/vaadin/client/ui/loginform/VLoginForm.java new file mode 100644 index 0000000000..e3dccd1ba5 --- /dev/null +++ b/client/src/main/java/com/vaadin/client/ui/loginform/VLoginForm.java @@ -0,0 +1,27 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package com.vaadin.client.ui.loginform; + +import com.google.gwt.user.client.ui.FormPanel; + +public class VLoginForm extends FormPanel { + + public VLoginForm() { + getElement().setId("loginForm"); + setMethod(METHOD_POST); + } +} diff --git a/server/src/main/java/com/vaadin/ui/LoginForm.java b/server/src/main/java/com/vaadin/ui/LoginForm.java index 1f0e3fc3b3..9df5f7343e 100644 --- a/server/src/main/java/com/vaadin/ui/LoginForm.java +++ b/server/src/main/java/com/vaadin/ui/LoginForm.java @@ -13,181 +13,48 @@ * License for the specific language governing permissions and limitations under * the License. */ + package com.vaadin.ui; -import java.io.IOException; +import java.io.ByteArrayInputStream; +import java.io.InputStream; import java.io.Serializable; +import java.io.UnsupportedEncodingException; import java.lang.reflect.Method; import java.util.HashMap; -import java.util.Iterator; import java.util.Map; -import com.vaadin.server.ConnectorResource; -import com.vaadin.server.ExternalResource; -import com.vaadin.server.VaadinRequest; -import com.vaadin.server.VaadinResponse; -import com.vaadin.server.VaadinService; -import com.vaadin.server.VaadinServletService; -import com.vaadin.shared.ApplicationConstants; +import com.vaadin.server.StreamResource; +import com.vaadin.shared.ui.loginform.LoginFormConstants; +import com.vaadin.shared.ui.loginform.LoginFormRpc; +import com.vaadin.shared.ui.loginform.LoginFormState; /** - * LoginForm is a Vaadin component to handle common problem among Ajax - * applications: browsers password managers don't fill dynamically created forms - * like all those UI elements created by Vaadin. + * Login form with auto-completion and auto-fill for all major browsers. You can + * derive from this class and implement the + * {@link #createContent(com.vaadin.ui.TextField, com.vaadin.ui.PasswordField, com.vaadin.ui.Button)} + * method to build the layout using the text fields and login button that are + * passed to that method. The supplied components are specially treated so that + * they work with password managers. * <p> - * For developer it is easy to use: add component to a desired place in you UI - * and add LoginListener to validate form input. Behind the curtain LoginForm - * creates an iframe with static html that browsers detect. + * If you need to change the URL as part of the login procedure, call + * {@link #setLoginMode(LoginMode)} with the argument {@link LoginMode#DEFERRED} + * in your implementation of + * {@link #createContent(com.vaadin.ui.TextField, com.vaadin.ui.PasswordField, com.vaadin.ui.Button) + * createContent}. * <p> - * Login form is by default 100% width and height, so consider using it inside a - * sized {@link Panel} or {@link Window}. + * To customize the fields or to replace them with your own implementations, you + * can override {@link #createUsernameField()}, {@link #createPasswordField()} + * and {@link #createLoginButton()}. These methods are called automatically and + * cannot be called by your code. Captions can be reset by overriding + * {@link #getUsernameFieldCaption()}, {@link #getPasswordFieldCaption()} and + * {@link #getLoginButtonCaption()}. * <p> - * Login page html can be overridden by replacing protected getLoginHTML method. - * As the login page is actually an iframe, styles must be handled manually. By - * default component tries to guess the right place for theme css. - * + * Note that the API of LoginForm changed significantly in Vaadin 7.7. + * * @since 5.3 - * @deprecated As of 7.0. This component no longer fulfills its duty reliably in - * the supported browsers and a {@link VerticalLayout} with two - * {@link TextField}s can be used instead. */ -@Deprecated -public class LoginForm extends CustomComponent { - - private String usernameCaption = "Username"; - private String passwordCaption = "Password"; - private String loginButtonCaption = "Login"; - - private Embedded iframe = new Embedded(); - - @Override - public boolean handleConnectorRequest(final VaadinRequest request, - final VaadinResponse response, String path) throws IOException { - if (!path.equals("login")) { - return super.handleConnectorRequest(request, response, path); - } - final StringBuilder responseBuilder = new StringBuilder(); - - getUI().accessSynchronously(new Runnable() { - @Override - public void run() { - String method = VaadinServletService.getCurrentServletRequest() - .getMethod(); - if (method.equalsIgnoreCase("post")) { - responseBuilder.append(handleLogin(request)); - } else { - responseBuilder.append(getLoginHTML()); - } - } - }); - - if (responseBuilder.length() > 0) { - response.setContentType("text/html; charset=utf-8"); - response.setCacheTime(-1); - response.getWriter().write(responseBuilder.toString()); - return true; - } else { - return false; - } - } - - private String handleLogin(VaadinRequest request) { - // Ensure UI.getCurrent() works in listeners - - Map<String, String[]> parameters = VaadinService.getCurrentRequest() - .getParameterMap(); - - HashMap<String, String> params = new HashMap<String, String>(); - // expecting single params - for (Iterator<String> it = parameters.keySet().iterator(); it.hasNext();) { - String key = it.next(); - String value = (parameters.get(key))[0]; - params.put(key, value); - } - LoginEvent event = new LoginEvent(LoginForm.this, params); - fireEvent(event); - - return "<html><body>Login form handled." - + "<script type='text/javascript'>parent.parent.vaadin.forceSync();" - + "</script></body></html>"; - } - - public LoginForm() { - iframe.setType(Embedded.TYPE_BROWSER); - iframe.setSizeFull(); - setSizeFull(); - setCompositionRoot(iframe); - addStyleName("v-loginform"); - } - - @Override - public void beforeClientResponse(boolean initial) { - // Generate magic URL now when UI id and connectorId are known - iframe.setSource(new ExternalResource( - ApplicationConstants.APP_PROTOCOL_PREFIX - + ApplicationConstants.APP_PATH + '/' - + ConnectorResource.CONNECTOR_PATH + '/' - + getUI().getUIId() + '/' + getConnectorId() + "/login")); - super.beforeClientResponse(initial); - } - - /** - * Returns byte array containing login page html. If you need to override - * the login html, use the default html as basis. Login page sets its target - * with javascript. - * - * @return byte array containing login page html - */ - protected String getLoginHTML() { - return "<!DOCTYPE html>\n" - + "<html>" - + "<head><script type='text/javascript'>" - + "var setTarget = function() {" - + "var uri = window.location;" - + "var f = document.getElementById('loginf');" - + "document.forms[0].action = uri;document.forms[0].username.focus();};" - + "" - + "var styles = window.parent.document.styleSheets;" - + "for(var j = 0; j < styles.length; j++) {\n" - + "if(styles[j].href) {" - + "var stylesheet = document.createElement('link');\n" - + "stylesheet.setAttribute('rel', 'stylesheet');\n" - + "stylesheet.setAttribute('type', 'text/css');\n" - + "stylesheet.setAttribute('href', styles[j].href);\n" - + "document.getElementsByTagName('head')[0].appendChild(stylesheet);\n" - + "}" - + "}\n" - + "function submitOnEnter(e) { var keycode = e.keyCode || e.which;" - + " if (keycode == 13) {document.forms[0].submit();} } \n" - + "</script>" - + "</head><body onload='setTarget();' style='margin:0;padding:0; background:transparent;' class=\"" - + ApplicationConstants.GENERATED_BODY_CLASSNAME - + "\">" - + "<div class='v-app v-app-loginpage " - + getUIThemeClassName() - + "' style=\"background:transparent;\">" - + "<iframe name='logintarget' style='width:0;height:0;" - + "border:0;margin:0;padding:0;display:block'></iframe>" - + "<form id='loginf' target='logintarget' onkeypress=\"submitOnEnter(event)\" method=\"post\">" - + "<div>" - + usernameCaption - + "</div><div >" - + "<input class='v-textfield v-widget' style='display:block;' type='text' name='username'></div>" - + "<div>" - + passwordCaption - + "</div>" - + "<div><input class='v-textfield v-widget' style='display:block;' type='password' name='password'></div>" - + "<div><div onclick=\"document.forms[0].submit();\" tabindex=\"0\" class=\"v-button\" role=\"button\" ><span class=\"v-button-wrap\"><span class=\"v-button-caption\">" - + loginButtonCaption - + "</span></span></div></div></form></div>" + "</body></html>"; - } - - private String getUIThemeClassName() { - if (getUI() != null) { - return getUI().getTheme(); - } - return ""; - } +public class LoginForm extends AbstractSingleComponentContainer { /** * This event is sent when login form is submitted. @@ -225,14 +92,28 @@ public class LoginForm extends CustomComponent { * This method is fired on each login form post. * * @param event + * Login event */ - public void onLogin(LoginForm.LoginEvent event); + public void onLogin(LoginEvent event); } - private static final Method ON_LOGIN_METHOD; + /** + * Internal stream source for the login URL - always returns "Success" and + * ignores the values received. + */ + private static class LoginStreamSource implements StreamResource.StreamSource { + @Override + public InputStream getStream() { + try { + return new ByteArrayInputStream("<html>Success</html>".toString().getBytes( + "UTF-8")); + } catch (UnsupportedEncodingException e) { + return null; + } + + } + } - private static final String UNDEFINED_HEIGHT = "140px"; - private static final String UNDEFINED_WIDTH = "200px"; static { try { @@ -245,121 +126,268 @@ public class LoginForm extends CustomComponent { } } + private static final Method ON_LOGIN_METHOD; + + private boolean initialized; + + private String usernameCaption = "Username"; + private String passwordCaption = "Password"; + private String loginButtonCaption = "Login"; + /** - * Adds LoginListener to handle login logic + * Customize the user name field. Only for overriding, do not call. * - * @param listener + * @return the user name field + * @since 7.7 */ - public void addLoginListener(LoginListener listener) { - addListener(LoginEvent.class, listener, ON_LOGIN_METHOD); + protected TextField createUsernameField() { + checkInitialized(); + TextField field = new TextField(getUsernameCaption()); + field.focus(); + return field; } /** - * @deprecated As of 7.0, replaced by - * {@link #addLoginListener(LoginListener)} - **/ - @Deprecated - public void addListener(LoginListener listener) { - addLoginListener(listener); + * Returns the caption set with {@link #setUsernameCaption(String)}. Note + * that this method might not match what is shown to the user if + * {@link #createUsernameField()} has been overridden. + * + * @return user name field caption + */ + public String getUsernameCaption() { + return usernameCaption; } /** - * Removes LoginListener + * Set the caption of the user name field. Note that the caption can only be + * set with this method before the login form has been initialized + * (attached). + * <p> + * As an alternative to calling this method, the method + * {@link #createUsernameField()} can be overridden. * - * @param listener + * @param cap + * new caption */ - public void removeLoginListener(LoginListener listener) { - removeListener(LoginEvent.class, listener, ON_LOGIN_METHOD); + public void setUsernameCaption(String cap) { + usernameCaption = cap; } /** - * @deprecated As of 7.0, replaced by - * {@link #removeLoginListener(LoginListener)} - **/ - @Deprecated - public void removeListener(LoginListener listener) { - removeLoginListener(listener); + * Customize the password field. Only for overriding, do not call. + * + * @return the password field + * @since 7.7 + */ + protected PasswordField createPasswordField() { + checkInitialized(); + return new PasswordField(getPasswordCaption()); } - @Override - public void setWidth(float width, Unit unit) { - super.setWidth(width, unit); - if (iframe != null) { - if (width < 0) { - iframe.setWidth(UNDEFINED_WIDTH); - } else { - iframe.setWidth("100%"); - } - } + /** + * Returns the caption set with {@link #setPasswordCaption(String)}. Note + * that this method might not match what is shown to the user if + * {@link #createPasswordField()} has been overridden. + * + * @return password field caption + */ + public String getPasswordCaption() { + return passwordCaption; } - @Override - public void setHeight(float height, Unit unit) { - super.setHeight(height, unit); - if (iframe != null) { - if (height < 0) { - iframe.setHeight(UNDEFINED_HEIGHT); - } else { - iframe.setHeight("100%"); - } - } + /** + * Set the caption of the password field. Note that the caption can only be + * set with this method before the login form has been initialized + * (attached). + * <p> + * As an alternative to calling this method, the method + * {@link #createPasswordField()} can be overridden. + * + * @param cap new caption + */ + public void setPasswordCaption(String cap) { + passwordCaption = cap; + ; } /** - * Returns the caption for the user name field. + * Customize the login button. Only for overriding, do not call. * - * @return String + * @return the login button + * @since 7.7 */ - public String getUsernameCaption() { - return usernameCaption; + protected Button createLoginButton() { + checkInitialized(); + return new Button(getLoginButtonCaption()); } /** - * Sets the caption to show for the user name field. The caption cannot be - * changed after the form has been shown to the user. + * Returns the caption set with {@link #setLoginButtonCaption(String)}. Note + * that this method might not match what is shown to the user if + * {@link #createLoginButton()} has been overridden. * - * @param usernameCaption + * @return login button caption */ - public void setUsernameCaption(String usernameCaption) { - this.usernameCaption = usernameCaption; + public String getLoginButtonCaption() { + return loginButtonCaption; } /** - * Returns the caption for the password field. + * Set the caption of the login button. Note that the caption can only be + * set with this method before the login form has been initialized + * (attached). + * <p> + * As an alternative to calling this method, the method + * {@link #createLoginButton()} can be overridden. * - * @return String + * @param cap new caption */ - public String getPasswordCaption() { - return passwordCaption; + public void setLoginButtonCaption(String cap) { + loginButtonCaption = cap; + } + + @Override + protected LoginFormState getState() { + return (LoginFormState) super.getState(); + } + + @Override + public void attach() { + super.attach(); + init(); + } + + private void checkInitialized() { + if (initialized) { + throw new IllegalStateException( + "Already initialized. The create methods may not be called explicitly."); + } } /** - * Sets the caption to show for the password field. The caption cannot be - * changed after the form has been shown to the user. + * Create the content for the login form with the supplied user name field, + * password field and the login button. You cannot use any other text fields + * or buttons for this purpose. To replace these components with your own + * implementations, override {@link #createUsernameField()}, + * {@link #createPasswordField()} and {@link #createLoginButton()}. If you + * only want to change the default captions, override + * {@link #getUsernameFieldCaption()}, {@link #getPasswordFieldCaption()} + * and {@link #getLoginButtonCaption()}. You do not have to use the login + * button in your layout. * - * @param passwordCaption + * @param userNameField + * the user name text field + * @param passwordField + * the password field + * @param loginButton + * the login button + * @return content component + * @since 7.7 */ - public void setPasswordCaption(String passwordCaption) { - this.passwordCaption = passwordCaption; + protected Component createContent(TextField userNameField, + PasswordField passwordField, Button loginButton) { + VerticalLayout layout = new VerticalLayout(); + layout.setSpacing(true); + layout.setMargin(true); + layout.addComponent(userNameField); + layout.addComponent(passwordField); + layout.addComponent(loginButton); + return layout; + } + + private void init() { + if (initialized) { + return; + } + + LoginFormState state = getState(); + state.userNameFieldConnector = createUsernameField(); + state.passwordFieldConnector = createPasswordField(); + state.loginButtonConnector = createLoginButton(); + + StreamResource resource = new StreamResource(new LoginStreamSource(), + LoginFormConstants.LOGIN_RESOURCE_NAME); + resource.setMIMEType("text/html; charset=utf-8"); + resource.setCacheTime(-1); + setResource(LoginFormConstants.LOGIN_RESOURCE_NAME, resource); + + registerRpc(new LoginFormRpc() { + @Override + public void submitCompleted() { + login(); + } + }); + + initialized = true; + + setContent(createContent(getUsernameField(), getPasswordField(), + getLoginButton())); + } + + private TextField getUsernameField() { + return (TextField) getState().userNameFieldConnector; + } + + private PasswordField getPasswordField() { + return (PasswordField) getState().passwordFieldConnector; + } + + private Button getLoginButton() { + return (Button) getState().loginButtonConnector; + } + + /* + * (non-Javadoc) + * + * Handle the login. In deferred mode, this method is called after the dummy + * POST request that triggers the password manager has been completed. In + * direct mode (the default setting), it is called directly when the user + * hits the enter key or clicks on the login button. In the latter case, you + * cannot change the URL in the method or the password manager will not be + * triggered. + */ + private void login() { + HashMap<String, String> params = new HashMap<String, String>(); + params.put("username", getUsernameField().getValue()); + params.put("password", getPasswordField().getValue()); + LoginEvent event = new LoginEvent(LoginForm.this, params); + fireEvent(event); } /** - * Returns the caption for the login button. + * Adds LoginListener to handle login logic * - * @return String + * @param listener */ - public String getLoginButtonCaption() { - return loginButtonCaption; + public void addLoginListener(LoginListener listener) { + addListener(LoginEvent.class, listener, ON_LOGIN_METHOD); + } + + /** + * @deprecated As of 7.0, replaced by + * {@link #addLoginListener(LoginListener)} + **/ + @Deprecated + public void addListener(LoginListener listener) { + addLoginListener(listener); } /** - * Sets the caption (button text) to show for the login button. The caption - * cannot be changed after the form has been shown to the user. + * Removes LoginListener * - * @param loginButtonCaption + * @param listener */ - public void setLoginButtonCaption(String loginButtonCaption) { - this.loginButtonCaption = loginButtonCaption; + public void removeLoginListener(LoginListener listener) { + removeListener(LoginEvent.class, listener, ON_LOGIN_METHOD); + } + + /** + * @deprecated As of 7.0, replaced by + * {@link #removeLoginListener(LoginListener)} + **/ + @Deprecated + public void removeListener(LoginListener listener) { + removeLoginListener(listener); } } diff --git a/shared/src/main/java/com/vaadin/shared/ui/loginform/LoginFormConstants.java b/shared/src/main/java/com/vaadin/shared/ui/loginform/LoginFormConstants.java new file mode 100644 index 0000000000..9f0c256881 --- /dev/null +++ b/shared/src/main/java/com/vaadin/shared/ui/loginform/LoginFormConstants.java @@ -0,0 +1,31 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.shared.ui.loginform; + +import java.io.Serializable; + +/** + * Constants for LoginForm + * + * @since 7.7 + * @author Vaadin Ltd + */ +public class LoginFormConstants implements Serializable { + + public static final String LOGIN_RESOURCE_NAME = "loginForm"; + +} + diff --git a/shared/src/main/java/com/vaadin/shared/ui/loginform/LoginFormRpc.java b/shared/src/main/java/com/vaadin/shared/ui/loginform/LoginFormRpc.java new file mode 100644 index 0000000000..76f88170a5 --- /dev/null +++ b/shared/src/main/java/com/vaadin/shared/ui/loginform/LoginFormRpc.java @@ -0,0 +1,23 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package com.vaadin.shared.ui.loginform; + +import com.vaadin.shared.communication.ServerRpc; + +public interface LoginFormRpc extends ServerRpc { + void submitCompleted(); +} diff --git a/shared/src/main/java/com/vaadin/shared/ui/loginform/LoginFormState.java b/shared/src/main/java/com/vaadin/shared/ui/loginform/LoginFormState.java new file mode 100644 index 0000000000..1dee06a12d --- /dev/null +++ b/shared/src/main/java/com/vaadin/shared/ui/loginform/LoginFormState.java @@ -0,0 +1,28 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package com.vaadin.shared.ui.loginform; + +import com.vaadin.shared.AbstractComponentState; +import com.vaadin.shared.Connector; +import com.vaadin.shared.communication.URLReference; + +public class LoginFormState extends AbstractComponentState { + public Connector userNameFieldConnector; + public Connector passwordFieldConnector; + public Connector loginButtonConnector; + public URLReference loginResource; +} |