<commit_before>module Browser; module DOM

class MutationObserver
  include Native

  class Record
    include Native

    def type
      case `#@native.type`
      when :attributes    then :attributes
      when :childList     then :tree
      when :characterData then :cdata
      end
    end

    def attributes?; type == :attributes; end
    def tree?;       type == :tree;       end
    def cdata?;      type == :cdata;      end

    def added
      array = if `#@native.addedNodes != null`
        Native::Array.new(`#@native.addedNodes`)
      else
        []
      end

      NodeSet.new($document, array)
    end

    def removed
      array = if `#@native.removedNodes != null`
        Native::Array.new(`#@native.removedNodes`)
      else
        []
      end

      NodeSet.new($document, array)
    end

    def target
      DOM(`#@native.target`)
    end

    alias_native :old, :oldValue
    alias_native :attribute, :attributeName
  end

  def initialize(&block)
    %x{
      var func = function(records) {
        return #{block.call(`records`.map { |r| Browser::DOM::MutationObserver::Record.new(r) })};
      }
    }

    super(`new window.MutationObserver(func)`)
  end

  def observe(target, options = nil)
    unless options
      options = {
        children:   true,
        tree:       true,
        attributes: :old,
        cdata:      :old
      }
    end

    `#@native.observe(#{Native.convert(target)}, #{convert(options)})`

    self
  end

  def take
    `#@native.takeRecords()`.map { |r| Record.new(r) }
  end

  def disconnect
    `#@native.disconnect()`
  end

private
  def convert(hash)
    options = Native(`{}`)

    if hash[:children]
      options[:childList] = true
    end

    if hash[:tree]
      options[:subtree] = true
    end

    if attrs = hash[:attributes]
      options[:attributes] = true

      if attrs == :old
        options[:attributeOldValue] = true
      end
    end

    if filter = hash[:filter]
      options[:attributeFilter] = filter<commit_msg>dom/mutation_observer: cleanup and add documentation<commit_after>module Browser; module DOM

# A {MutationObserver} is a performant way to observe changes in the DOM,
# either on the tree, the attributes or data.
#
# More information about it can be found
# [here](https://developer.mozilla.org/en/docs/Web/API/MutationObserver).
class MutationObserver
  include Native

  # Encapsulates a recorded change.
  class Record
    include Native

    # @!attribute [r] type
    # @return [:attributes, :tree, :cdata] the type of the recorded change
    def type
      case `#@native.type`
      when :attributes    then :attribute
      when :childList     then :tree
      when :characterData then :cdata
      end
    end

    # Returns true if the change happened on attributes.
    def attribute?
      type == :attribute
    end

    # Returns true if the change happened on the tree.
    def tree?
      type == :tree
    end

    # Returns true if the change happened in a CDATA section.
    def cdata?
      type == :cdata
    end

    # @!attribute [r] added
    # @return [NodeSet] the added nodes
    def added
      array = if `#@native.addedNodes != null`
        Native::Array.new(`#@native.addedNodes`)
      else
        []
      end

      NodeSet.new($document, array)
    end

    # @!attribute [r] removed
    # @return [NodeSet] the removed nodes
    def removed
      array = if `#@native.removedNodes != null`
        Native::Array.new(`#@native.removedNodes`)
      else
        []
      end

      NodeSet.new($document, array)
    end

    # @!attribute [r] target
    # @return [Node] the node the mutation affected
    def target
      DOM(`#@native.target`)
    end

    # @!attribute [r] old
    # @return [String] the old value
    alias_native :old, :oldValue

    # @!attribute [r] name
    # @return [String] the name of the attribute
    alias_native :name, :attributeName

    # @!attribute [r] namespace
    # @return [String] the namespace of the attribute
    alias_native :namespace, :attributeNamespace
  end

  # Create a new MutationObserver with the given block.
  #
  # @yieldparam records [Array<Record>] the recorded changes
  def initialize(&block)
    %x{
      var func = function(records) {
        return #{block.call(`records`.map { |r| Browser::DOM::MutationObserver::Record.new(r) })};
      }
    }

    super(`new window.MutationObserver(func)`)
  end

  # Observe the given target with the given options.
  #
  # The supported options are:
  #
  # + **children** - whether to observe changes on the children
  #   of the target or not
  # + **tree** - whether to observe changes on the whole subtree
  #   or not
  # + **attributes** - whether to observe changes to attributes or not,
  #   if the value is `:old` the old value will be saved
  # + **cdata** - whether to observe changes to CDATA sections or not,
  #   if the value is `:old` the old value will be saved
  # + **filter** - array of attribute names to observe
  #
  # @param target [DOM::Node, native] the node to observe
  # @param options [Hash?] the options
  def observe(target, options = nil)
    unless options
      options = {
        children:   true,
        tree:       true,
        attributes: :old,
        cdata:      :old
      }
    end

    `#@native.observe(#{Native.convert(target)}, #{convert(options)})`

    self
  end

  # Empty the observer queue and return its contents.
  #
  # @return [Array<Record>]
  def take
    `#@native.takeRecords()`.map { |r| Record.new(r) }
  end

  # Disconnect the observer, thus stopping observing any changes.
  def disconnect
    `#@native.disconnect()`
  end

private
  def convert(hash)
    options = Native(`{}`)

    if hash[:children]
      options[:childList] = true
    end

    if hash[:tree]
      options[:subtree] = true
    end

    if attrs = hash[:attributes]
      options[:attributes] = true

      if attrs == :old
        options[:attributeOldValue] = true
      end
    end

    if filter = hash[:filter]
      options[:attributeFilter] = filter
{'fraction_non_alphanumeric': 0.11013870541611624, 'fraction_numerical': 0.0, 'mean_word_length': 2.429784824462061, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 1, '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': '6703542', 'n_tokens_mistral': 1832, 'n_tokens_neox': 1778, 'n_words': 571}