<commit_before>#
# Renders the given page-data into iframe and keeps track of it.
#

require! {
  Promise: bluebird
  Reloader: '../../../vendor/bower_components/livereload-js/src/reloader.coffee'.Reloader
  Timer: '../../../vendor/bower_components/livereload-js/src/timer.coffee'.Timer
  './MappingAlgorithm.ls'
  './SerializablePageDiff.ls'
}

class Renderer
  (@page-data) ->
    @iframe = generate-iframe @page-data

    @_promise = load-and-snapshot-page-data @page-data, @iframe
    .then (@snapshot) ~>
      # Register @reloader on the new iframe content window
      @reloader = new Reloader @iframe.content-window, {log: -> , error: ->}, Timer

      # Hack: we don't call @reloader.reload, must provide set its options explicitly.
      @reloader.options = {}

      return @ # resolve the current renderer

  #
  # Kick-start the iframe rendering by putting the iframe into a DOM target
  #
  render: (target) ->
    target.insert-before @iframe, null
    return @_promise

  #
  # Given changed CSS detected by livereload, update the snapshot and returns
  # a promise that resolves to differences between 'before' and 'after' applying the new stylesheets
  #
  applyCSS: (path) ->
    # Invoke reloader to livereload CSS.
    # The style tags may be manipulated here.
    @reloader.reload-stylesheet path

    # Check if all contents loaded
    return register-load-callbacks @iframe.content-window.document
    .then ~>
      # Wait for pseudo element style to be visible in getComputedStyle
      # https://github.com/akoenig/angular-deckgrid/issues/27#issuecomment-38924697
      #
      Promise.delay 100

    .then ~>
      # Take another page snapshot, update @snapshot and return diff
      iframe-document = @iframe.content-window.document
      walker = iframe-document.create-tree-walker iframe-document.body,
        NodeFilter.SHOW_ELEMENT

      idx = 0
      differences = []
      while current-node = walker.next-node!
        # Calculate new snapshot and the element difference
        new-elem-snapshot = new ElementSnapshot current-node, @iframe.content-window
        element-diff = new-elem-snapshot.diff @snapshot[idx]

        if element-diff
          # Secretly store the diff-id in DOM
          current-node._seess-diff-id = differences.length
          differences.push element-diff
        else
          delete current-node._seess-diff-id

        # Update snapshot
        @snapshot[idx] = new-elem-snapshot
        idx += 1

      # Return SerializablePageDiff instance or null
      if differences.length is 0
        return null
      else
        return new SerializablePageDiff do
          dom: generate-detached-html @iframe
          doctype: @page-data.doctype
          diffs: differences

  #
  # Given the new DOM, update the snapshot and perform HTML diff algorithm
  # to generate difference.
  # Returns a promise that resolves to the page differences.
  #
  applyHTML: (new-html) ->

    # Update @page-data with a new instance with the new HTML
    @page-data = new PageData do
      html: new-html
      url: @page-data.url
      width: @page-data.width
      height: @page-data.height
      scroll-top: @page-data.scroll-top
      doctype: @page-data.doctype

    new-iframe = generate-iframe @page-data

    # Load iframe
    @_promise = load-and-snapshot-page-data @page-data, new-iframe
    .then (new-snapshot) ~>
      # Register @reloader on the new iframe content window
      @reloader = new Reloader @iframe.content-window, {log: -> , error: ->}, Timer

      # Calculate diff
      matcher = new MappingAlgorithm.diffX @iframe.content-window.document, new-iframe.content-window.document

      diffs = []
      for elem-snapshot in new-snapshot
        matched-old-elem = matcher.to-old-node elem-snapshot.elem
        unless matched-old-elem
          # No matched old element; the element is new!
          diffs.push new ElementDifference elem-snapshot, ElementDifference.TYPE_ADDED

        else
          # Corresponding old element found; calculate element difference
          old-elem-snapshot = @snapshot[matched-old-elem._seess-snapshot-idx]
          elem-diff = elem-snapshot.diff old-elem-snapshot
          if elem-diff
            # Secretly store the diff-id in DOM
            elem-snapshot.elem._seess-diff-id = diffs.length
            diffs.push elem-diff
          else
            delete elem-snapshot.elem._seess-diff-id


          # Mark the referred old element snapshot
          @snapshot[matched-old-elem._seess-snapshot-idx] = \REFERRED
<commit_msg>Change Renderer#applyHTML to match the new API of MappingAlgorithm module<commit_after>#
# Renders the given page-data into iframe and keeps track of it.
#

require! {
  Promise: bluebird
  Reloader: '../../../vendor/bower_components/livereload-js/src/reloader.coffee'.Reloader
  Timer: '../../../vendor/bower_components/livereload-js/src/timer.coffee'.Timer
  './MappingAlgorithm.ls'
  './SerializablePageDiff.ls'
}

class Renderer
  (@page-data) ->
    @iframe = generate-iframe @page-data

    @_promise = load-and-snapshot-page-data @page-data, @iframe
    .then (@snapshot) ~>
      # Register @reloader on the new iframe content window
      @reloader = new Reloader @iframe.content-window, {log: -> , error: ->}, Timer

      # Hack: we don't call @reloader.reload, must provide set its options explicitly.
      @reloader.options = {}

      return @ # resolve the current renderer

  #
  # Kick-start the iframe rendering by putting the iframe into a DOM target
  #
  render: (target) ->
    target.insert-before @iframe, null
    return @_promise

  #
  # Given changed CSS detected by livereload, update the snapshot and returns
  # a promise that resolves to differences between 'before' and 'after' applying the new stylesheets
  #
  applyCSS: (path) ->
    # Invoke reloader to livereload CSS.
    # The style tags may be manipulated here.
    @reloader.reload-stylesheet path

    # Check if all contents loaded
    return register-load-callbacks @iframe.content-window.document
    .then ~>
      # Wait for pseudo element style to be visible in getComputedStyle
      # https://github.com/akoenig/angular-deckgrid/issues/27#issuecomment-38924697
      #
      Promise.delay 100

    .then ~>
      # Take another page snapshot, update @snapshot and return diff
      iframe-document = @iframe.content-window.document
      walker = iframe-document.create-tree-walker iframe-document.body,
        NodeFilter.SHOW_ELEMENT

      idx = 0
      differences = []
      while current-node = walker.next-node!
        # Calculate new snapshot and the element difference
        new-elem-snapshot = new ElementSnapshot current-node, @iframe.content-window
        element-diff = new-elem-snapshot.diff @snapshot[idx]

        if element-diff
          # Secretly store the diff-id in DOM
          current-node._seess-diff-id = differences.length
          differences.push element-diff
        else
          delete current-node._seess-diff-id

        # Update snapshot
        @snapshot[idx] = new-elem-snapshot
        idx += 1

      # Return SerializablePageDiff instance or null
      if differences.length is 0
        return null
      else
        return new SerializablePageDiff do
          dom: generate-detached-html @iframe
          doctype: @page-data.doctype
          diffs: differences

  #
  # Given the new DOM, update the snapshot and perform HTML diff algorithm
  # to generate difference.
  # Returns a promise that resolves to the page differences.
  #
  applyHTML: (new-html) ->

    # Update @page-data with a new instance with the new HTML
    @page-data = new PageData do
      html: new-html
      url: @page-data.url
      width: @page-data.width
      height: @page-data.height
      scroll-top: @page-data.scroll-top
      doctype: @page-data.doctype

    new-iframe = generate-iframe @page-data

    # Load iframe
    @_promise = load-and-snapshot-page-data @page-data, new-iframe
    .then (new-snapshot) ~>
      # Register @reloader on the new iframe content window
      @reloader = new Reloader @iframe.content-window, {log: -> , error: ->}, Timer

      # Match the DOM nodes using Valiente's bottom-up algorithm,
      # then map the rest of nodes using diffX, as suggested in discussion section of diffX paper.
      #
      map-set = MappingAlgorithm.valiente @iframe.content-window.document.body, new-iframe.content-window.document.body
      MappingAlgorithm.diffX @iframe.content-window.document.body, new-iframe.content-window.document.body, map-set

      # Calculate diff
      #
      diffs = []
      for elem-snapshot in new-snapshot
        matched-old-elem = map-set.get-node-to elem-snapshot.elem
        unless matched-old-elem
          # No matched old element; the element is new!
          diffs.push new ElementDifference elem-snapshot, ElementDifference.TYPE_ADDED

        else
          # Corresponding old element found; calculate element difference
          old-elem-snapshot = @snapshot[matched-old-elem._seess-snapshot-idx]
          elem-diff = elem-snapshot.diff old-elem-snapshot
          if elem-diff
            # Secretly store the diff-id in DOM
            elem-snapshot.elem._seess-diff-id = diffs.length
            diffs.push elem-diff
          else
            delete elem-snapshot.elem._seess-diff-id


          # Mark the referred old element snapshot
          @snapshot[matched-old-elem._seess-snapshot-idx] = \REFERRED

{'fraction_non_alphanumeric': 0.0929054054054054, 'fraction_numerical': 0.0033783783783783786, 'mean_word_length': 2.5137240356083086, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 27, 'https://': 2, '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': '806437', 'n_tokens_mistral': 2799, 'n_tokens_neox': 2690, 'n_words': 780}