func (u *UI) promptRemove(name string, callback func(yes bool)) {
	u.dom.RemoveChildren(u.removeName)
	u.dom.AppendChild(u.removeName, u.dom.NewText(name), nil)
	u.dom.OnClick(u.removeYes, func() {
		u.dom.RemoveChildren(u.removeName)
		u.removeYes = u.dom.RemoveEventListeners(u.removeYes)
		u.removeNo = u.dom.RemoveEventListeners(u.removeNo)
		u.dom.Close(u.removeDialog)
		callback(true)
	})
	u.dom.OnClick(u.removeNo, func() {
		u.dom.RemoveChildren(u.removeName)
		u.removeYes = u.dom.RemoveEventListeners(u.removeYes)
		u.removeNo = u.dom.RemoveEventListeners(u.removeNo)
		u.dom.Close(u.removeDialog)
		callback(false)
	})
	u.dom.ShowModal(u.removeDialog)
}
promptRemove displays a dialog prompting the user to confirm that a key
should be removed. callback is invoked when the dialog is closed; the yes
parameter indicates if the user clicked Yes.
package optionsui
import (
	"crypto/rand"
	"encoding/base64"
	"fmt"
	"math"
	"math/big"
	"sort"
	"time"
	"github.com/google/chrome-ssh-agent/go/dom"
	"github.com/google/chrome-ssh-agent/go/keys"
	"github.com/google/chrome-ssh-agent/go/keys/testdata"
	"github.com/gopherjs/gopherjs/js"
	"github.com/kr/pretty"
)
type UI struct {
	mgr              keys.Manager
	dom              *dom.DOM
	passphraseDialog *js.Object
	passphraseInput  *js.Object
	passphraseOk     *js.Object
	passphraseCancel *js.Object
	addButton        *js.Object
	addDialog        *js.Object
	addName          *js.Object
	addKey           *js.Object
	addOk            *js.Object
	addCancel        *js.Object
	removeDialog     *js.Object
	removeName       *js.Object
	removeYes        *js.Object
	removeNo         *js.Object
	errorText        *js.Object
	keysData         *js.Object
	keys             []*displayedKey
}
func New(mgr keys.Manager, domObj *dom.DOM) *UI {
	result := &UI{
		mgr:              mgr,
		dom:              domObj,
		passphraseDialog: domObj.GetElement("passphraseDialog"),
		passphraseInput:  domObj.GetElement("passphrase"),
		passphraseOk:     domObj.GetElement("passphraseOk"),
		passphraseCancel: domObj.GetElement("passphraseCancel"),
		addButton:        domObj.GetElement("add"),
		addDialog:        domObj.GetElement("addDialog"),
		addName:          domObj.GetElement("addName"),
		addKey:           domObj.GetElement("addKey"),
		addOk:            domObj.GetElement("addOk"),
		addCancel:        domObj.GetElement("addCancel"),
		removeDialog:     domObj.GetElement("removeDialog"),
		removeName:       domObj.GetElement("removeName"),
		removeYes:        domObj.GetElement("removeYes"),
		removeNo:         domObj.GetElement("removeNo"),
		errorText:        domObj.GetElement("errorMessage"),
		keysData:         domObj.GetElement("keysData"),
	}
	result.dom.OnDOMContentLoaded(result.updateKeys)
	result.dom.OnClick(result.addButton, result.add)
	return result
}
func (u *UI) setError(err error) {
	u.dom.RemoveChildren(u.errorText)
	if err != nil {
		u.dom.AppendChild(u.errorText, u.dom.NewText(err.Error()), nil)
	}
}
func (u *UI) add() {
	u.promptAdd(func(name, privateKey string, ok bool) {
		if !ok {
			return
		}
		u.mgr.Add(name, privateKey, func(err error) {
			if err != nil {
				u.setError(fmt.Errorf("failed to add key: %v", err))
				return
			}
			u.setError(nil)
			u.updateKeys()
		})
	})
}
func (u *UI) promptAdd(callback func(name, privateKey string, ok bool)) {
	u.dom.OnClick(u.addOk, func() {
		n := u.dom.Value(u.addName)
		k := u.dom.Value(u.addKey)
		u.dom.SetValue(u.addName, "")
		u.dom.SetValue(u.addKey, "")
		u.addOk = u.dom.RemoveEventListeners(u.addOk)
		u.addCancel = u.dom.RemoveEventListeners(u.addCancel)
		u.dom.Close(u.addDialog)
		callback(n, k, true)
	})
	u.dom.OnClick(u.addCancel, func() {
		u.dom.SetValue(u.addName, "")
		u.dom.SetValue(u.addKey, "")
		u.addOk = u.dom.RemoveEventListeners(u.addOk)
		u.addCancel = u.dom.RemoveEventListeners(u.addCancel)
		u.dom.Close(u.addDialog)
		callback("", "", false)
	})
	u.dom.ShowModal(u.addDialog)
}
func (u *UI) load(id keys.ID, encrypted bool) {
	prompt := u.promptPassphrase
	if !encrypted {
		prompt = func(callback func(passphrase string, ok bool)) {
			callback("", true)
		}
	}
	prompt(func(passphrase string, ok bool) {
		if !ok {
			return
		}
		u.mgr.Load(id, passphrase, func(err error) {
			if err != nil {
				u.setError(fmt.Errorf("failed to load key: %v", err))
				return
			}
			u.setError(nil)
			u.updateKeys()
		})
	})
}
func (u *UI) promptPassphrase(callback func(passphrase string, ok bool)) {
	u.dom.OnClick(u.passphraseOk, func() {
		p := u.dom.Value(u.passphraseInput)
		u.dom.SetValue(u.passphraseInput, "")
		u.passphraseOk = u.dom.RemoveEventListeners(u.passphraseOk)
		u.passphraseCancel = u.dom.RemoveEventListeners(u.passphraseCancel)
		u.dom.Close(u.passphraseDialog)
		callback(p, true)
	})
	u.dom.OnClick(u.passphraseCancel, func() {
		u.dom.SetValue(u.passphraseInput, "")
		u.passphraseOk = u.dom.RemoveEventListeners(u.passphraseOk)
		u.passphraseCancel = u.dom.RemoveEventListeners(u.passphraseCancel)
		u.dom.Close(u.passphraseDialog)
		callback("", false)
	})
	u.dom.ShowModal(u.passphraseDialog)
}
func (u *UI) unload(key *keys.LoadedKey) {
	u.mgr.Unload(key, func(err error) {
		if err != nil {
			u.setError(fmt.Errorf("failed to unload key: %v", err))
			return
		}
		u.setError(nil)
		u.updateKeys()
	})
}