 +      nodetype.setDocument(opts.contentDocument);
 +      cli.setEvalFunction(opts.jsEnvironment.evalFunction);
 +
++      // Create a FocusManager for the various parts to register with
++      if (!opts.focusManager) {
++        opts.debug = true;
++        opts.focusManager = new FocusManager({
++          debug: true,
++          document: opts.chromeDocument
++        });
++      }
++
 +      opts.inputter = new Inputter(opts);
 +      opts.inputter.update();
-+      if (opts.popup) {
-+        opts.inputter.addPopupListener(opts.popup);
++      if (opts.gcliTerm) {
++        opts.focusManager.onFocus.add(opts.gcliTerm.show, opts.gcliTerm);
++        opts.focusManager.onBlur.add(opts.gcliTerm.hide, opts.gcliTerm);
++        opts.focusManager.addMonitoredElement(opts.gcliTerm.hintNode, 'gcliTerm');
 +      }
 +
 +      if (opts.hintElement) {

+     * - jsEnvironment.evalFunction: 'eval' in a sandbox
+     * - inputElement: GCLITerm.inputNode
+     * - completeElement: GCLITerm.completeNode
+     * - popup: GCLITerm.hintPopup
+     * - hintElement: GCLITerm.hintNode
+     * - inputBackgroundElement: GCLITerm.inputStack
+     */

+  this.history = options.history = options.history || new History(options);
+  this._scrollingThroughHistory = false;
+
+  // Cursor position affects hint severity.
+  this.onMouseUp = function(ev) {
+    this.completer.update(this.getInputState());
+  }.bind(this);
+  event.addListener(this.element, 'mouseup', this.onMouseUp);
+
+  this.focusManager = options.focusManager;
+  if (this.focusManager) {
+    this.focusManager.addMonitoredElement(this.element, 'input');
+  }
+
+  this.requ.inputChange.add(this.onInputChange, this);
+
+  setTimeout(function() {
+    if (this.doc.activeElement === this.element && this.focusManager) {
+      this.focusManager.reportFocus('startup');
+    }
+  }.bind(this), 100);
+}
+
+/**
+ * Unregister all event listeners
+ */
+Inputter.prototype.destroy = function() {
+  this.requ.inputChange.remove(this.onInputChange, this);
+  if (this.focusManager) {
+    this.focusManager.removeMonitoredElement(this.element, 'input');
+  }
+
+  event.removeListener(this.element, 'keydown', this.onKeyDown);
+  event.removeListener(this.element, 'keyup', this.onKeyUp);
+  delete this.onKeyDown;
+  delete this.onKeyUp;
+};
+
+/**
+ * Utility to add an element into the DOM after the input element
+ */
+Inputter.prototype.appendAfter = function(element) {
+  this.element.parentNode.insertBefore(element, this.element.nextSibling);
+};
+
+/**
