       parent.insertBefore scriptElement.cloneNode(true), nextSibling
     null
   
+  # Replaces an element's contents with some HTML.
+  #
+  # The JavaScript inside the HTML's <script> tags will be executed. 
+  #
+  # @param {HTMLElement} element the element whose contents will be replaced
+  # @param {String}
+  replaceHtml: (element, html) ->
+    element.innerHTML = html
+    @runScripts element
+    @wire element
+
+  # The closest form element wrapping a node.
+  #
+  # @param {HTMLElement} element the element whose parent chain will be searched
+  # @return {HTMLFormElement} the element's closest parent form, or null if the
+  #     element is not wrapped in a <form>
+  parentForm: (element) ->
+    while element
+      return element if element.nodeName == 'FORM'
+      element = element.parentNode
+    null
+  
   # Do AJAX.
   #
   # @param {String} url the request URL (e.g., "http://localhost/path/to.html")

PwnFx.registerEffect 'render', PwnFxRender


# Fires off an AJAX request (almost) every time when an element changes.
#
# The text / HTML returned by the request is placed in another element.
#
# Element attributes:
#   data-pwnfx-refresh: URL to perform an AJAX request to
#   data-pwnfx-refresh-method: the HTTP method of AJAX request (default: POST)
#   data-pwnfx-refresh-ms: interval between a change on the source element and
#                          AJAX refresh requests (default: 200ms)
#   data-pwnfx-target: the element populated with the AJAX response
class PwnFxRefresh
  constructor: (element, xhrUrl, scopeId) ->
    targetSelector = '#' + element.getAttribute('data-pwnfx-refresh-target') 
    refreshInterval = parseInt(
        element.getAttribute('data-pwnfx-refresh-ms') || '200');
    xhrMethod = element.getAttribute('data-pwnfx-refresh-method') || 'POST'
    xhrForm = @parentForm element
    
    onXhrData = (data) ->
      scope = PwnFx.resolveScope scopeId, element
      for targetElement in PwnFx.queryScope(scope, targetSelector)
        targetElement.innerHTML = data
        PwnFx.runScripts targetElement
        PwnFx.wire targetElement
            
    refreshPending = false
    refreshOldValue = null
    ajaxRefresh = ->
      refreshPending = false
      PwnFx.xhr xhrUrl, xhrMethod, xhrForm, onXhrData
      
    onChange = ->

    xhr = new XMLHttpRequest
    xhr.onload = @_xhr_onload
    xhr.pwnfxOnData = onData
    xhr.open method, url
    xhr.setRequestHeader 'X-Requested-With', 'XMLHttpRequest'
    if form
      xhr.send new FormData(form)
    else
      xhr.send null
  
  # Called when an XHR request issued by PwnFx.xhr works out.
  _xhr_onload: ->
