diff --git a/resources/static/dialog/controllers/authenticate_controller.js b/resources/static/dialog/controllers/authenticate_controller.js
index c025f0e65cb942f13be574f18f970f5ef6d595de..f6b4157abf13b4ff7ecc28e060dcdc2aaa96fe04 100644
--- a/resources/static/dialog/controllers/authenticate_controller.js
+++ b/resources/static/dialog/controllers/authenticate_controller.js
@@ -51,7 +51,7 @@
     return helpers.getAndValidateEmail("#email");
   }
 
-  function checkEmail(el, event) {
+  function checkEmail(event) {
     var email = getEmail(),
         self = this;
 
@@ -69,7 +69,7 @@
     }, self.getErrorDialog(errors.isEmailRegistered));
   }
 
-  function createUser(el, event) {
+  function createUser(event) {
     var self=this,
         email = getEmail();
 
@@ -80,7 +80,7 @@
     }
   }
 
-  function authenticate(el, event) {
+  function authenticate(event) {
     var email = getEmail(),
         pass = helpers.getAndValidatePassword("#password"),
         self = this;
@@ -96,7 +96,7 @@
     }
   }
 
-  function resetPassword(el, event) {
+  function resetPassword(event) {
     var email = getEmail();
 
     cancelEvent(event);
@@ -117,17 +117,14 @@
     if (event) event.preventDefault();
   }
 
-  function enterEmailState(el, event) {
-    // Enter key, do nothing
-    if (event && event.which === 13) return;
-
+  function enterEmailState(el) {
     if (!el.is(":disabled")) {
       this.submit = checkEmail;
       animateSwap(".returning:visible,.newuser:visible,.forgot:visible", ".start");
     }
   }
 
-  function enterPasswordState(el, event) {
+  function enterPasswordState(event) {
     cancelEvent(event);
     var self=this;
 
@@ -138,7 +135,7 @@
     });
   }
 
-  function forgotPasswordState(el, event) {
+  function forgotPasswordState(event) {
     cancelEvent(event);
 
     this.submit = resetPassword;
@@ -147,14 +144,14 @@
     animateSwap(".start:visible,.newuser:visible,.returning:visible", ".forgot");
   }
 
-  function cancelForgotPassword(el, event) {
+  function cancelForgotPassword(event) {
     cancelEvent(event);
 
     dom.removeAttr("#email", "disabled");
     enterPasswordState.call(this);
   }
 
-  function createUserState(el, event) {
+  function createUserState(event) {
     cancelEvent(event);
 
     var self=this;
@@ -165,33 +162,35 @@
   }
 
 
+  function emailKeyUp(event) {
+    var newEmail = dom.getInner(event.target);
+    if (newEmail !== lastEmail) {
+      lastEmail = newEmail;
+      enterEmailState.call(this, $(event.target));
+    }
+  }
+
   PageController.extend("Authenticate", {}, {
-    init: function(el, options) {
-      options = options || {};
-
-      this._super(el, {
-        bodyTemplate: "authenticate",
-        bodyVars: {
-          sitename: user.getHostname(),
-          email: options.email || ""
-        }
+    start: function(options) {
+      var self=this;
+      self.renderDialog("authenticate", {
+        sitename: user.getHostname(),
+        email: options.email || ""
       });
 
-      this.submit = checkEmail;
+      self.submit = checkEmail;
       // If we already have an email address, check if it is valid, if so, show
       // password.
-      if (options.email) this.submit();
-    },
+      if (options.email) self.submit();
 
-    "#email keyup": function(el, event) {
-      var newEmail = el.val();
-      if (newEmail !== lastEmail) {
-        lastEmail = newEmail;
-        enterEmailState.call(this, el);
-      }
+
+      self.bind("#email", "keyup", emailKeyUp);
+      self.bind("#forgotPassword", "click", forgotPasswordState);
+      self.bind("#cancel_forgot_password", "click", cancelForgotPassword);
+
+      self._super();
     },
-    "#forgotPassword click": forgotPasswordState,
-    "#cancel_forgot_password click": cancelForgotPassword,
+
     checkEmail: checkEmail,
     createUser: createUser,
     authenticate: authenticate,
diff --git a/resources/static/dialog/controllers/checkregistration_controller.js b/resources/static/dialog/controllers/checkregistration_controller.js
index c6269895c6fac9ad34aae20185fc5c0bc179a17c..78038e68307bdbd6c4743a07c4063fe9f1408983 100644
--- a/resources/static/dialog/controllers/checkregistration_controller.js
+++ b/resources/static/dialog/controllers/checkregistration_controller.js
@@ -52,17 +52,11 @@
       self.verifier = options.verifier;
       self.verificationMessage = options.verificationMessage;
 
-      dom.bindEvent("#back", "click", self.cancel.bind(self));
+      self.bind("#back", "click", self.cancel);
 
       self._super();
     },
 
-    stop: function() {
-      dom.unbindEvent("#back", "click");
-
-      this._super();
-    },
-
     startCheck: function() {
       var self=this;
       user[self.verifier](self.email, function(status) {
diff --git a/resources/static/dialog/controllers/dialog_controller.js b/resources/static/dialog/controllers/dialog_controller.js
index 9efb1d683554618f92b77130bc7d8aa32a552622..4cb10c89d956c07e5427e4e0a0a847044b6a7285 100644
--- a/resources/static/dialog/controllers/dialog_controller.js
+++ b/resources/static/dialog/controllers/dialog_controller.js
@@ -67,6 +67,9 @@
 
         var self=this;
 
+        self.domEvents = [];
+        self._super();
+
         // keep track of where we are and what we do on success and error
         self.onsuccess = null;
         self.onerror = null;
@@ -117,7 +120,7 @@
 
         self.doCheckAuth();
 
-        dom.bindEvent(win, "unload", function() {
+        self.bind(win, "unload", function() {
           // do this only if something else hasn't
           // declared success
           if (!self.success) {
@@ -226,12 +229,11 @@
       doConfirmUser: function(email) {
         this.confirmEmail = email;
 
-        this.element.checkregistration({
+        var controller = this.element.checkregistration({
           email: email,
           verifier: "waitForUserValidation",
           verificationMessage: "user_confirmed"
-        });
-        var controller = this.element.controller("checkregistration");
+        }).controller();
         controller.startCheck();
       },
 
@@ -278,12 +280,11 @@
       doConfirmEmail: function(email) {
         this.confirmEmail = email;
 
-        this.element.checkregistration({
+        var controller = this.element.checkregistration({
           email: email,
           verifier: "waitForEmailValidation",
           verificationMessage: "email_confirmed"
-        });
-        var controller = this.element.controller("checkregistration");
+        }).controller();
         controller.startCheck();
       },
 
diff --git a/resources/static/dialog/controllers/page_controller.js b/resources/static/dialog/controllers/page_controller.js
index 816724e04acd5596d6c7c68911ab34edbcfc5c07..0c66dfe58a7a493af9ab55833d836c9de01b12d6 100644
--- a/resources/static/dialog/controllers/page_controller.js
+++ b/resources/static/dialog/controllers/page_controller.js
@@ -42,6 +42,16 @@
       dom = bid.DOM,
       screens = bid.Screens;
 
+   function onSubmit(event) {
+     event.stopPropagation();
+     event.preventDefault();
+
+     if (this.validate()) {
+       this.submit();
+     }
+     return false;
+   }
+
 
   $.Controller.extend("PageController", {
     }, {
@@ -50,6 +60,8 @@
 
       var self=this;
 
+      this.domEvents = [];
+
       if(options.bodyTemplate) {
         self.renderDialog(options.bodyTemplate, options.bodyVars);
       }
@@ -67,15 +79,12 @@
 
     start: function() {
       var self=this;
-      // XXX move all of these, bleck.
-      dom.bindEvent("form", "submit", self.onSubmit.bind(self));
-      dom.bindEvent("#thisIsNotMe", "click", self.close.bind(self, "notme"));
+      self.bind("form", "submit", onSubmit);
+      self.bind("#thisIsNotMe", "click", self.close.bind(self, "notme"));
     },
 
     stop: function() {
-      dom.unbindEvent("form", "submit");
-      dom.unbindEvent("input", "keyup");
-      dom.unbindEvent("#thisIsNotMe", "click");
+      this.unbindAll();
 
       dom.removeClass("body", "waiting");
     },
@@ -85,6 +94,28 @@
       this._super();
     },
 
+    bind: function(target, type, callback, context) {
+      var self=this,
+          cb = callback.bind(context || this);
+
+      dom.bindEvent(target, type, cb);
+
+      self.domEvents.push({
+        target: target,
+        type: type,
+        cb: cb
+      });
+    },
+
+    unbindAll: function() {
+      var self=this,
+          evt;
+
+      while(evt = self.domEvents.pop()) {
+        dom.unbindEvent(evt.target, evt.type, evt.cb);
+      }
+    },
+
     renderDialog: function(body, body_vars) {
       screens.form(body, body_vars);
       $("#wait, #error").stop().fadeOut(ANIMATION_TIME);
@@ -104,7 +135,7 @@
       /**
        * TODO XXX - Use the error-display for this.
        */
-      dom.bindEvent("#openMoreInfo", "click", function(event) {
+      this.bind("#openMoreInfo", "click", function(event) {
         event.preventDefault();
 
         $("#moreInfo").slideDown();
@@ -112,28 +143,11 @@
       });
     },
 
-    onSubmit: function(event) {
-      event.stopPropagation();
-      event.preventDefault();
-
-      if (this.validate()) {
-        this.submit();
-      }
-      return false;
-    },
-
     validate: function() {
       return true;
     },
 
     submit: function() {
-    //  this.close("submit");
-    },
-
-    doWait: function(info) {
-      this.renderWait("wait", info);
-
-      dom.addClass("body", "waiting");
     },
 
     close: function(message, data) {
diff --git a/resources/static/dialog/controllers/pickemail_controller.js b/resources/static/dialog/controllers/pickemail_controller.js
index 987756cd63d4c935447c9c11d7c4ab02fee3da3a..57bcb677c286b282dab402dc4fd14f9e63116f4a 100644
--- a/resources/static/dialog/controllers/pickemail_controller.js
+++ b/resources/static/dialog/controllers/pickemail_controller.js
@@ -44,7 +44,6 @@
       storage = bid.Storage,
       helpers = bid.Helpers,
       dom = bid.DOM,
-      body = $("body"),
       assertion;
 
   function animateSwap(fadeOutSelector, fadeInSelector, callback) {
@@ -57,10 +56,10 @@
 
 
   function cancelEvent(event) {
-    if (event) event.preventDefault();
+    event && event.preventDefault();
   }
 
-  function pickEmailState(element, event) {
+  function pickEmailState(event) {
     cancelEvent(event);
 
     var self=this;
@@ -75,7 +74,7 @@
     });
   }
 
-  function addEmailState(element, event) {
+  function addEmailState(event) {
     cancelEvent(event);
 
     this.submit = addEmail;
@@ -136,41 +135,39 @@
 
 
   PageController.extend("Pickemail", {}, {
-    init: function(el, options) {
+    start: function(options) {  
       var origin = user.getOrigin(),
           self=this;
 
       options = options || {};
 
       self.allowPersistent = options.allow_persistent;
-
-      self._super(el, {
-        bodyTemplate: "pickemail",
-        bodyVars: {
-          identities: user.getStoredEmailKeypairs(),
-          // XXX ideal is to get rid of self and have a User function
-          // that takes care of getting email addresses AND the last used email
-          // for self site.
-          siteemail: storage.site.get(origin, "email"),
-          allow_persistent: options.allow_persistent || false,
-          remember: storage.site.get(origin, "remember") || false
-        }
+      self.renderDialog("pickemail", {
+        identities: user.getStoredEmailKeypairs(),
+        // XXX ideal is to get rid of self and have a User function
+        // that takes care of getting email addresses AND the last used email
+        // for self site.
+        siteemail: storage.site.get(origin, "email"),
+        allow_persistent: options.allow_persistent || false,
+        remember: storage.site.get(origin, "remember") || false
       });
-      body.css("opacity", "1");
+      dom.getElements("body").css("opacity", "1");
 
       if (dom.getElements("#selectEmail input[type=radio]:visible").length === 0) {
         // If there is only one email address, the radio button is never shown,
         // instead focus the sign in button so that the user can click enter.
         // issue #412
-        $("#signInButton").focus();
+        dom.focus("#signInButton");
       }
 
+      self.bind("#useNewEmail", "click", addEmailState);
+      self.bind("#cancelNewEmail", "click", pickEmailState);
+
+      self._super();
+
       pickEmailState.call(self);
     },
 
-    "#useNewEmail click": addEmailState,
-    "#cancelNewEmail click": pickEmailState,
-
     signIn: signIn,
     addEmail: addEmail
   });
diff --git a/resources/static/dialog/controllers/required_email_controller.js b/resources/static/dialog/controllers/required_email_controller.js
index 0e6dfea3d017d9e529c3a51e9f32f4ef46eb8595..812c48dacf826bb3c9919630f98a6e90758c91fa 100644
--- a/resources/static/dialog/controllers/required_email_controller.js
+++ b/resources/static/dialog/controllers/required_email_controller.js
@@ -144,24 +144,15 @@
           showPassword: showPassword
         });
 
-        dom.bindEvent("#sign_in", "click", signIn.bind(self));
-        dom.bindEvent("#verify_address", "click", verifyAddress.bind(self));
-        dom.bindEvent("#forgotPassword", "click", forgotPassword.bind(self));
-        dom.bindEvent("#cancel", "click", cancel.bind(self));
+        self.bind("#sign_in", "click", signIn);
+        self.bind("#verify_address", "click", verifyAddress);
+        self.bind("#forgotPassword", "click", forgotPassword);
+        self.bind("#cancel", "click", cancel);
       }
 
       self._super();
     },
 
-    stop: function() {
-      dom.unbindEvent("#sign_in", "click");
-      dom.unbindEvent("#verify_address", "click");
-      dom.unbindEvent("#forgotPassword", "click");
-      dom.unbindEvent("#cancel", "click");
-
-      this._super();
-    },
-
     signIn: signIn,
     verifyAddress: verifyAddress,
     forgotPassword: forgotPassword,
diff --git a/resources/static/test/qunit/controllers/page_controller_unit_test.js b/resources/static/test/qunit/controllers/page_controller_unit_test.js
index 8d898fc49c23c4af2d5a91ec91f522f185cbc339..00a21936d653f47ba720231944d7815aee559cf3 100644
--- a/resources/static/test/qunit/controllers/page_controller_unit_test.js
+++ b/resources/static/test/qunit/controllers/page_controller_unit_test.js
@@ -197,5 +197,40 @@ steal.plugins("jquery").then("/dialog/controllers/page_controller", function() {
 
   });
 
+  test("bind DOM Events", function() {
+    controller = el.page().controller();
+
+   controller.bind("body", "click", function(event) {
+      event.preventDefault();
+
+      strictEqual(this, controller, "context is correct");
+      start();
+   });
+
+   $("body").trigger("click");
+   stop();
+  });
+
+  test("unbindAll removes all listeners", function() {
+    controller = el.page().controller();
+    var listenerCalled = false;
+
+    controller.bind("body", "click", function(event) {
+      event.preventDefault();
+
+      listenerCalled = true;
+    });
+
+    controller.unbindAll();
+
+    $("body").trigger("click");
+    stop();
+
+    setTimeout(function() {
+      equal(listenerCalled, false, "all events are unbound, listener should not be called");
+      start();
+    }, 100);
+  });
+
 });