--- /dev/null
+package com.itmill.toolkit.tests.tickets;
+
+import java.io.ByteArrayInputStream;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.Map;
+
+import com.itmill.toolkit.Application;
+import com.itmill.toolkit.terminal.ApplicationResource;
+import com.itmill.toolkit.terminal.DownloadStream;
+import com.itmill.toolkit.terminal.ParameterHandler;
+import com.itmill.toolkit.terminal.URIHandler;
+import com.itmill.toolkit.ui.Button;
+import com.itmill.toolkit.ui.CustomComponent;
+import com.itmill.toolkit.ui.Embedded;
+import com.itmill.toolkit.ui.ExpandLayout;
+import com.itmill.toolkit.ui.Label;
+import com.itmill.toolkit.ui.Panel;
+import com.itmill.toolkit.ui.Window;
+import com.itmill.toolkit.ui.Button.ClickEvent;
+import com.itmill.toolkit.ui.Window.Notification;
+
+/**
+ * Proof of concept how to create a decent login screen that works with browsers
+ * PW managers. (Browsers don't autofill generated login forms)
+ *
+ * TODO generalize js to work inside iframes (if toolkit is inside iframe)
+ *
+ * TODO extract login form to a external template.
+ *
+ * TODO theme
+ *
+ * TODO refine docs, make LoginBox a standard toolkit component
+ *
+ * TODO article
+ *
+ */
+public class Ticket1362Login extends Application {
+
+ public class LoginBox extends CustomComponent {
+
+ Embedded iframe = new Embedded();
+
+ ApplicationResource loginPage = new ApplicationResource() {
+
+ private byte[] loginHTML = (""
+ + "<html>"
+ + "<head><script type='text/javascript'>"
+ + "var setTarget = function() {document.getElementById('loginf').action = top.location;};"
+ + "</script></head>"
+ + "<body onload='setTarget();'>"
+ + "Iframe generated by LoginBox. PW managers can autofill form. Form handled by LoginBox "
+ + "that will fire LoginEvents. Will post into another iframe, from where the script "
+ + "will find toolkit client that will be force synced. <form id='loginf' target='logintarget'>"
+ + "Username : <input type='text' name='username'>"
+ + "Password : <input type='password' name='password'>"
+ + "<input type='submit' value='login'>" + "</form>"
+ + "<iframe name='logintarget'></iframe>" + "</body>"
+ + "</html>").getBytes();
+
+ public Application getApplication() {
+ return LoginBox.this.getApplication();
+ }
+
+ public int getBufferSize() {
+ return loginHTML.length;
+ }
+
+ public long getCacheTime() {
+ return 0;
+ }
+
+ public String getFilename() {
+ return "login.html";
+ }
+
+ public DownloadStream getStream() {
+ return new DownloadStream(new ByteArrayInputStream(loginHTML),
+ getMIMEType(), getFilename());
+ }
+
+ public String getMIMEType() {
+ return "text/html";
+ }
+ };
+
+ private ParameterHandler paramHandler = new ParameterHandler() {
+
+ public void handleParameters(Map parameters) {
+ if (parameters.containsKey("username")) {
+ getWindow().addURIHandler(uriHandler);
+
+ HashMap params = new HashMap();
+ // expecting single params
+ for (Iterator it = parameters.keySet().iterator(); it
+ .hasNext();) {
+ String key = (String) it.next();
+ String value = ((String[]) parameters.get(key))[0];
+ params.put(key, value);
+ }
+ LoginEvent event = new LoginEvent(params);
+ for (Iterator iterator = listeners.iterator(); iterator
+ .hasNext();) {
+ LoginListener listener = (LoginListener) iterator
+ .next();
+ listener.onLogin(event);
+ }
+ }
+ }
+ };
+
+ private URIHandler uriHandler = new URIHandler() {
+ public DownloadStream handleURI(URL context, String relativeUri) {
+ if (window != null) {
+ window.removeURIHandler(this);
+ }
+ return new DownloadStream(
+ new ByteArrayInputStream(
+ "<html><body>Login form handeled.<script type='text/javascript'>top.itmill.forceSync();</script></body></html>"
+ .getBytes()), "text/html",
+ "loginSuccesfull.html");
+ }
+ };
+
+ private LinkedList listeners = new LinkedList();
+
+ private Window window;
+
+ LoginBox() {
+ iframe.setType(Embedded.TYPE_BROWSER);
+ iframe.setSizeFull();
+ setCompositionRoot(iframe);
+ }
+
+ public void attach() {
+ super.attach();
+ getApplication().addResource(loginPage);
+ getWindow().addParameterHandler(paramHandler);
+ iframe.setSource(loginPage);
+ }
+
+ public void detach() {
+ getApplication().removeResource(loginPage);
+ getWindow().removeParameterHandler(paramHandler);
+ // store window temporary to properly remove uri handler once
+ // response is handled. (May happen if login handler removes login
+ // box
+ window = getWindow();
+ super.detach();
+ }
+
+ /**
+ * This event is sent when login form is submitted.
+ */
+ public class LoginEvent {
+
+ private Map params;
+
+ private LoginEvent(Map params) {
+ this.params = params;
+ }
+
+ /**
+ * Returns form value by field name.
+ *
+ * @param name
+ * @return value in given field
+ */
+ public String getLoginParameter(String name) {
+ if (params.containsKey(name)) {
+ return (String) params.get(name);
+ } else {
+ return null;
+ }
+ }
+ }
+
+ /**
+ * Adds LoginListener to handle login logic
+ *
+ * @param listener
+ */
+ public void addLoginListener(LoginListener listener) {
+ listeners.add(listener);
+ }
+
+ /**
+ * Removes LoginListener
+ *
+ * @param listener
+ */
+ public void removeLoginListener(LoginListener listener) {
+ listeners.remove(listener);
+ }
+
+ }
+
+ /**
+ * Login listener is a class capable to listen LoginEvents sent from
+ * LoginBox
+ */
+ public interface LoginListener {
+ /**
+ * This method is fired on each login form post.
+ *
+ * @param event
+ */
+ public void onLogin(LoginBox.LoginEvent event);
+ }
+
+ final static String GUEST = "guest";
+
+ LoginBox loginBox = new LoginBox();
+
+ Label currentUser = new Label(GUEST);
+
+ private Panel mainPanel;
+
+ private ExpandLayout el;
+
+ public void init() {
+
+ final Window mainWin = new Window(
+ "Test app with password manager savvy login functionality");
+
+ el = new ExpandLayout();
+
+ currentUser.setCaption("Currennt user");
+ el.addComponent(currentUser);
+
+ el.addComponent(loginBox);
+ el.expand(loginBox);
+
+ mainWin.setLayout(el);
+
+ setMainWindow(mainWin);
+
+ mainPanel = new Panel("Test app");
+ mainPanel.setSizeFull();
+ mainPanel.addComponent(new Label("User is logged in"));
+ mainPanel.addComponent(new Button("Logout", new Button.ClickListener() {
+
+ public void buttonClick(ClickEvent event) {
+ Ticket1362Login.this.close();
+ }
+ }));
+
+ loginBox.addLoginListener(new LoginListener() {
+ public void onLogin(LoginBox.LoginEvent event) {
+ String pw = event.getLoginParameter("password");
+ String username = event.getLoginParameter("username");
+ if (pw.equals("1234")) {
+ setUser(username);
+ currentUser.setValue(username);
+ currentUser.getWindow().showNotification(
+ "Logged in user: " + username);
+ getMainWindow().getLayout().replaceComponent(loginBox,
+ mainPanel);
+ el.expand(mainPanel);
+ } else {
+ getMainWindow().showNotification(
+ "Wrong password. Hint, try '1234' ",
+ Notification.TYPE_WARNING_MESSAGE);
+ }
+ }
+ });
+
+ }
+
+}
\ No newline at end of file