module Browser; module DOM # Allows manipulation of a set of {Node}s. class NodeSet # Create a new {NodeSet} from the given nodes. # # Note that the nodes are flattened and converted with DOM automatically, # this means you can pass {NodeSet}s and {Native::Array}s as well. def self.[](*nodes) new(nodes.flatten.map { |x| DOM(Native.convert(x)) }.uniq) end def initialize(literal) @literal = literal end # Any other method will be called on every node in the set. def method_missing(name, *args, &block) unless @literal.respond_to? name each {|el| el.__send__(name, *args, &block) } return self end result = @literal.__send__ name, *args, &block if `result === #@literal` self elsif Array === result NodeSet.new(result) else result end end def respond_to_missing?(name, *) @literal.respond_to?(name) end # Get the first node matching the given CSS selectors. # # @param rules [Array] the CSS selectors to match with # # @return [Node?] def at_css(*rules) each {|node| if node = node.at_css(*rules) return node end } nil end # Get the first node matching the given XPath. # # @param paths [Array] the XPath to match with # # @return [Node?] def at_xpath(*paths) each {|node| if node = node.at_xpath(*paths) return node end } nil end # Query for children matching the given CSS selector. # # @param path [String] the CSS selector # # @return [NodeSet] def css(path) NodeSet[@literal.map {|node| node.css(path) }] end # Create another {NodeSet} with all the nodes that match the given # expression. # # @param expression [String] a CSS selector # # @return [NodeSet] the new {NodeSet} with the matching nodes def filter(expression) NodeSet[@literal.select { |node| node =~ expression }] end # Search for multiple selectors def search(*what) NodeSet[@literal.map { |node| node.search(*what) }] end # Outer HTML of the entire nodeset def outer_html @literal.map(&:outer_html).join end # Query for children matching the given XPath. # # @param path [String] the XPath # # @return [NodeSet] def xpath(path) NodeSet[@literal.map {|node| node.xpath(path) }] end def to_ary @literal end alias to_a to_ary end end; end