     reader.readAsText file
 
 
-whenPresent = (getElem, onSuccess, onError, attemptsRemaining = 10000) ->
-  elem = getElem()
-
-  if elem?
-    onSuccess elem
-  else if attemptsRemaining
-    requestAnimationFrame ->
-      whenPresent getElem, onSuccess, onError, attemptsRemaining - 1
-  else
-    onError()
+whenPresent = (getElem, attemptsRemaining = 10000) ->
+  new Promise (resolve, reject) ->
+    elem = getElem()
+
+    if elem?
+      resolve elem
+    else if attemptsRemaining
+      requestAnimationFrame ->
+        whenPresent(getElem, attemptsRemaining - 1).then resolve, reject
+    else
+      reject()
 
 editors = new WeakMap()
 mutationObserverOptions =

    editor

setUpEditor = (id, html, onMutate) ->
  whenPresent (-> document.getElementById id),
    ((elem) -> getEditorFor(elem, onMutate).writeHtml html, true),
    ((err) -> console.error "Could not write after 10,000 attempts:", id, html),
    10000

refreshDocList = -> sync.listDocs().then (docs) ->
  app.ports.listDocs.send docs

  refreshDocList()

app.ports.downloadDoc.subscribe ({filename, contentType}) ->
  whenPresent((-> document.getElementById "document-page"), 10000)
    .then ((elem) ->
      clone = document.getElementById("document-page").cloneNode true

      for editable in clone.querySelectorAll("[contentEditable=true]")
