<commit_before>module Browser; module DOM

class Element < Node
  def self.create(*args)
    $document.create_element(*args)
  end

  include Event::Target

  target {|value|
    # TODO: oneline rescue

    begin
      DOM(value)
    rescue
      nil
    end
  }

  alias_native :id

  def add_class(name)
    `#@native.className = #{class_names.push(name).uniq.join ' '}`

    self
  end

  def remove_class(name)
    names = class_names
    names.delete(name)

    `#@native.className = #{names.join ' '}`
  end

  alias_native :class_name, :className

  def class_names
    `#@native.className`.split(/\s+/).reject(&:empty?)
  end

  alias attribute attr

  def attribute_nodes
    Native::Array.new(`#@native.attributes`, get: :item) { |e| DOM(e) }
  end

  def attributes(options = {})
    Attributes.new(self, options)
  end

  def get(name, options = {})
    if namespace = options[:namespace]
      `#@native.getAttributeNS(#{namespace.to_s}, #{name.to_s}) || nil`
    else
      `#@native.getAttribute(#{name.to_s}) || nil`
    end
  end

  def set(name, value, options = {})
    if namespace = options[:namespace]
      `#@native.setAttributeNS(#{namespace.to_s}, #{name.to_s}, #{value})`
    else
      `#@native.setAttribute(#{name.to_s}, #{value.to_s})`
    end
  end

  alias [] get
  alias []= set

  alias attr get
  alias attribute get

  alias get_attribute get
  alias set_attribute set

  def key?(name)
    !!self[name]
  end

  def keys
    attributes_nodesmap(&:name)
  end

  def values
    attribute_nodes.map(&:value)
  end

  def each(options = {}, &block)
    return enum_for :each, options unless block

    attributes(options).each(&block)
  end

  def remove_attribute(name)
    `#@native.removeAttribute(name)`
  end

  def size
    Size.new(`#@native.clientWidth`, `#@native.clientHeight`)
  end

  def position
    offset        = self.offset
    parent        = offset.parent
    parent_offset = Position.new(0, 0)

    if style[:position] == :fixed
      unless parent =~ :html
        parent_offset = parent.offset
      end

      parent_offset.y += parent.style['border-top-width'] || 0
      parent_offset.x += parent.style['border-left-width'] || 0
    end

    Position.new(offset.x - parent_offset.x - style['margin-left'] || 0,
                 offset.y - parent_offset.y - style['margin-top'] || 0,
                 parent)
  end

  def offset
    doc  = document
    root = doc.root.to_n
    win  = doc.window.to_n

    %x{
      var box = #@native.getBoundingClientRect(),<commit_msg>dom/element: use offset sizes in #size<commit_after>module Browser; module DOM

class Element < Node
  def self.create(*args)
    $document.create_element(*args)
  end

  include Event::Target

  target {|value|
    # TODO: oneline rescue

    begin
      DOM(value)
    rescue
      nil
    end
  }

  alias_native :id

  def add_class(name)
    `#@native.className = #{class_names.push(name).uniq.join ' '}`

    self
  end

  def remove_class(name)
    names = class_names
    names.delete(name)

    `#@native.className = #{names.join ' '}`
  end

  alias_native :class_name, :className

  def class_names
    `#@native.className`.split(/\s+/).reject(&:empty?)
  end

  alias attribute attr

  def attribute_nodes
    Native::Array.new(`#@native.attributes`, get: :item) { |e| DOM(e) }
  end

  def attributes(options = {})
    Attributes.new(self, options)
  end

  def get(name, options = {})
    if namespace = options[:namespace]
      `#@native.getAttributeNS(#{namespace.to_s}, #{name.to_s}) || nil`
    else
      `#@native.getAttribute(#{name.to_s}) || nil`
    end
  end

  def set(name, value, options = {})
    if namespace = options[:namespace]
      `#@native.setAttributeNS(#{namespace.to_s}, #{name.to_s}, #{value})`
    else
      `#@native.setAttribute(#{name.to_s}, #{value.to_s})`
    end
  end

  alias [] get
  alias []= set

  alias attr get
  alias attribute get

  alias get_attribute get
  alias set_attribute set

  def key?(name)
    !!self[name]
  end

  def keys
    attributes_nodesmap(&:name)
  end

  def values
    attribute_nodes.map(&:value)
  end

  def each(options = {}, &block)
    return enum_for :each, options unless block

    attributes(options).each(&block)
  end

  def remove_attribute(name)
    `#@native.removeAttribute(name)`
  end

  def size(*inc)
    Size.new(`#@native.offsetWidth`, `#@native.offsetHeight`)
  end

  def position
    offset        = self.offset
    parent        = offset.parent
    parent_offset = Position.new(0, 0)

    if style[:position] == :fixed
      unless parent =~ :html
        parent_offset = parent.offset
      end

      parent_offset.y += parent.style['border-top-width'] || 0
      parent_offset.x += parent.style['border-left-width'] || 0
    end

    Position.new(offset.x - parent_offset.x - style['margin-left'] || 0,
                 offset.y - parent_offset.y - style['margin-top'] || 0,
                 parent)
  end

  def offset
    doc  = document
    root = doc.root.to_n
    win  = doc.window.to_n

    %x{
      var box = #@native.getBoundingClientRect(),
{'fraction_non_alphanumeric': 0.13626546239937168, 'fraction_numerical': 0.0023561751423522483, 'mean_word_length': 2.7264081931236284, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 3, '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': '3487353', 'n_tokens_mistral': 1737, 'n_tokens_neox': 1680, 'n_words': 376}