<commit_before>#= require ./renderer

class Turbolinks.SnapshotRenderer extends Turbolinks.Renderer
  constructor: (@currentSnapshot, @newSnapshot, @isPreview) ->
    @currentHeadDetails = @currentSnapshot.headDetails
    @newHeadDetails = @newSnapshot.headDetails
    @newBody = @newSnapshot.bodyElement

  render: (callback) ->
    if @shouldRender()
      @mergeHead()
      @renderView =>
        @replaceBody()
        @focusFirstAutofocusableElement() unless @isPreview
        callback()
    else
      @invalidateView()

  mergeHead: ->
    @copyNewHeadStylesheetElements()
    @copyNewHeadScriptElements()
    @removeCurrentHeadProvisionalElements()
    @copyNewHeadProvisionalElements()

  replaceBody: ->
    @activateBodyScriptElements()
    @importBodyPermanentElements()
    @assignNewBody()

  shouldRender: ->
    @newSnapshot.isVisitable() and @trackedElementsAreIdentical()

  trackedElementsAreIdentical: ->
    @currentHeadDetails.getTrackedElementSignature() is @newHeadDetails.getTrackedElementSignature()

  copyNewHeadStylesheetElements: ->
    for element in @getNewHeadStylesheetElements()
      document.head.appendChild(element)

  copyNewHeadScriptElements: ->
    for element in @getNewHeadScriptElements()
      document.head.appendChild(@createScriptElement(element))

  removeCurrentHeadProvisionalElements: ->
    for element in @getCurrentHeadProvisionalElements()
      document.head.removeChild(element)

  copyNewHeadProvisionalElements: ->
    for element in @getNewHeadProvisionalElements()
      document.head.appendChild(element)

  importBodyPermanentElements: ->
    for replaceableElement in @getNewBodyPermanentElements()
      if permanentElement = @findCurrentBodyPermanentElement(replaceableElement)
        importPermanentElement(permanentElement, replaceableElement)

  activateBodyScriptElements: ->
    for replaceableElement in @getNewBodyScriptElements()
      element = @createScriptElement(replaceableElement)
      replaceableElement.parentNode.replaceChild(element, replaceableElement)

  assignNewBody: ->
    document.body = @newBody

  focusFirstAutofocusableElement: ->
    @findFirstAutofocusableElement()?.focus()

  getNewHeadStylesheetElements: ->
    @newHeadDetails.getStylesheetElementsNotInDetails(@currentHeadDetails)

  getNewHeadScriptElements: ->
    @newHeadDetails.getScriptElementsNotInDetails(@currentHeadDetails)

  getCurrentHeadProvisionalElements: ->
    @currentHeadDetails.getProvisionalElements()

  getNewHeadProvisionalElements: ->
    @newHeadDetails.getProvisionalElements()

  getNewBodyPermanentElements: ->
    @newBody.querySelectorAll("[id][data-turbolinks-permanent]")

  findCurrentBodyPermanentElement: (element) ->
    document.body.querySelector("##{element.id}[data-turbolinks-permanent]")

  getNewBodyScriptElements: ->
    @newBody.querySelectorAll("script")

  findFirstAutofocusableElement: ->
    document.body.querySelector("[autofocus]")

  importPermanentElement = (permanentElement, replaceableElement) ->
    permanentElement.parentNode.replaceChild(permanentElement.cloneNode(true), permanentElement)
    replaceableElement.parentNode.replaceChild(permanentElement, replaceableElement)
    permanentElement<commit_msg>Replace permanent elements with placeholders before the body swap<commit_after>#= require ./renderer

class Turbolinks.SnapshotRenderer extends Turbolinks.Renderer
  constructor: (@currentSnapshot, @newSnapshot, @isPreview) ->
    @currentHeadDetails = @currentSnapshot.headDetails
    @newHeadDetails = @newSnapshot.headDetails
    @currentBody = @currentSnapshot.bodyElement
    @newBody = @newSnapshot.bodyElement

  render: (callback) ->
    if @shouldRender()
      @mergeHead()
      @renderView =>
        @replaceBody()
        @focusFirstAutofocusableElement() unless @isPreview
        callback()
    else
      @invalidateView()

  mergeHead: ->
    @copyNewHeadStylesheetElements()
    @copyNewHeadScriptElements()
    @removeCurrentHeadProvisionalElements()
    @copyNewHeadProvisionalElements()

  replaceBody: ->
    permanentElements = @extractCurrentBodyPermanentElements()
    @activateNewBodyScriptElements()
    @assignNewBody()
    @replaceNewBodyPermanentElements(permanentElements)
    @replacePlaceholdersForPermanentElements(permanentElements)

  shouldRender: ->
    @newSnapshot.isVisitable() and @trackedElementsAreIdentical()

  trackedElementsAreIdentical: ->
    @currentHeadDetails.getTrackedElementSignature() is @newHeadDetails.getTrackedElementSignature()

  copyNewHeadStylesheetElements: ->
    for element in @getNewHeadStylesheetElements()
      document.head.appendChild(element)

  copyNewHeadScriptElements: ->
    for element in @getNewHeadScriptElements()
      document.head.appendChild(@createScriptElement(element))

  removeCurrentHeadProvisionalElements: ->
    for element in @getCurrentHeadProvisionalElements()
      document.head.removeChild(element)

  copyNewHeadProvisionalElements: ->
    for element in @getNewHeadProvisionalElements()
      document.head.appendChild(element)

  extractCurrentBodyPermanentElements: ->
    for permanentElement in @getCurrentBodyPermanentElements() when @findNewBodyPermanentElementById(permanentElement.id)
      placeholder = createPlaceholderForPermanentElement(permanentElement)
      replaceElementWithElement(permanentElement, placeholder)
      permanentElement

  replaceNewBodyPermanentElements: (permanentElements) ->
    for permanentElement in permanentElements
      if newElement = @findNewBodyPermanentElementById(permanentElement.id)
        replaceElementWithElement(newElement, permanentElement)

  replacePlaceholdersForPermanentElements: (permanentElements) ->
    for permanentElement in permanentElements
      if placeholder = @findPlaceholderById(permanentElement.id)
        clonedElement = permanentElement.cloneNode(true)
        replaceElementWithElement(placeholder, clonedElement)

  activateNewBodyScriptElements: ->
    for inertScriptElement in @getNewBodyScriptElements()
      activatedScriptElement = @createScriptElement(inertScriptElement)
      replaceElementWithElement(inertScriptElement, activatedScriptElement)

  assignNewBody: ->
    document.body = @newBody

  focusFirstAutofocusableElement: ->
    @findFirstAutofocusableElement()?.focus()

  getNewHeadStylesheetElements: ->
    @newHeadDetails.getStylesheetElementsNotInDetails(@currentHeadDetails)

  getNewHeadScriptElements: ->
    @newHeadDetails.getScriptElementsNotInDetails(@currentHeadDetails)

  getCurrentHeadProvisionalElements: ->
    @currentHeadDetails.getProvisionalElements()

  getNewHeadProvisionalElements: ->
    @newHeadDetails.getProvisionalElements()

  getCurrentBodyPermanentElements: ->
    @currentBody.querySelectorAll("[id][data-turbolinks-permanent]")

  findNewBodyPermanentElementById: (id) ->
    @newBody.querySelector("##{id}[data-turbolinks-permanent]")

  findPlaceholderById: (id) ->
    @currentBody.querySelector("meta[name=turbolinks-permanent-placeholder][content='#{id}']")

  getNewBodyScriptElements: ->
    @newBody.querySelectorAll("script")

  findFirstAutofocusableElement: ->
    @newBody.querySelector("[autofocus]")

createPlaceholderForPermanentElement = (permanentElement) ->
  placeholder = document.createElement("meta")
  placeholder.setAttribute("name", "turbolinks-permanent-placeholder")
  placeholder.setAttribute("content", permanentElement.id)
  placeholder

replaceElementWithElement = (fromElement, toElement) ->
  if parentElement = fromElement.parentNode
    parentElement.replaceChild(toElement, fromElement)
    toElement
{'fraction_non_alphanumeric': 0.08905818993826349, 'fraction_numerical': 0.0, 'mean_word_length': 5.5132591958939265, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 55, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5817601', 'n_tokens_mistral': 2068, 'n_tokens_neox': 2045, 'n_words': 291}