Handle keyboard events for nested dialogs properly

Instead of attaching a keydown listener for each dialog, keep track of the stack of nested dialogs and have the listener always deal with the topmost dialog. Fixes #3505.

(Ideally we wouldn't have nested dialogs at all, but the current Extension Manager implementation requires it. In the future, we might get rid of one level of dialogs there.)

Note that when #3086 (or similar) is merged, we can clean this up a bit by just having the stack hold `Dialog` objects and storing `autoDismiss` in the object.

As an aside, we should add some unit tests for the dialog infrastructure. Maybe the right time to do that is when we review #3086.