     if remoteNode = body.querySelector('[id="'+nodeId+'"]')
       remoteNode.parentNode.replaceChild(existingNode, remoteNode)
 
-persistPermanentNodes = (body) ->
+persistPermanentNodes = (body, sourceBody) ->
   allNodesToKeep = []
 
-  nodes = document.querySelectorAll("[data-turbolinks-permanent]")
+  nodes = sourceBody.querySelectorAll("[data-turbolinks-permanent]")
   allNodesToKeep.push(node) for node in nodes
 
   keepNodes(body, allNodesToKeep)
   return
 
-getTemporaryNodes = ->
-  node for node in document.querySelectorAll('[data-turbolinks-temporary]')
+getTemporaryNodes = (body)->
+  node for node in body.querySelectorAll('[data-turbolinks-temporary]')
 
 getPermanentNodes = ->
-  node for node in document.querySelectorAll('[data-turbolinks-permanent]')
+  node for node in body.querySelectorAll('[data-turbolinks-permanent]')
 
 getNodesMatchingChangeKeys = (keys, body) ->
   matchingNodes = []

  triggerEvent EVENTS.BEFORE_UNLOAD
  document.title = title

  # TODO: this is a hack that can go away when i refactor changePage params. it's using
  # the supplied document body which i don't want.
  sourceDocument = options.sourceDocument || document
  body = options.body || body

  if options.change
    nodesToBeChanged = [].concat(getNodesMatchingChangeKeys(options.change, sourceDocument),getTemporaryNodes())
    changedNodes = changeNodes(nodesToBeChanged, body)
    setAutofocusElement() if anyAutofocusElement(changedNodes)
    changedNodes
  else
    unless options.flush
      changeNodes(getTemporaryNodes(), body)
      persistPermanentNodes(body)
      if options.keep
        refreshAllExceptWithKeys(options.keep, body)

    document.documentElement.replaceChild body, document.body
    CSRFToken.update csrfToken if csrfToken?

    document.location.href = document.location.href
  else
    window.scrollTo 0, 0

clone = (original) ->
  return original if not original? or typeof original isnt 'object'
