lib/watir/locator.rb in watir-2.0.4 vs lib/watir/locator.rb in watir-3.0.0.rc1
- old
+ new
@@ -1,10 +1,32 @@
module Watir
class Locator
include Watir
include Watir::Exception
+ def initialize container, tags, klass
+ @container = container
+ @tags = tags
+ @klass = klass
+ end
+
+ def each
+ if has_excluding_specifiers?
+ locate_elements_by_xpath_css_ole.each do |element|
+ yield element
+ end
+ else
+ @tags.each do |tag|
+ each_element(tag) do |element|
+ next unless type_matches?(element.ole_object) && match_with_specifiers?(element)
+ yield element
+ end
+ end
+ end
+ nil
+ end
+
def document
@document ||= @container.document
end
def normalize_specifiers!(specifiers)
@@ -28,11 +50,15 @@
end
end
def match_with_specifiers?(element)
return true if has_excluding_specifiers?
- @specifiers.all? {|how, what| how == :index || match?(element, how, what)}
+ @specifiers.all? do |how, what|
+ how == :index ||
+ (how.to_s =~ /^data_.*/ && element.send(how) == what) ||
+ match?(element, how, what)
+ end
end
def has_excluding_specifiers?
@specifiers.keys.any? {|specifier| [:css, :xpath, :ole_object].include? specifier}
end
@@ -40,11 +66,11 @@
def set_specifier(how, what=nil)
specifiers = what ? {how => what} : how
@specifiers = {:index => Watir::IE.base_index} # default if not specified
normalize_specifiers! specifiers
end
-
+
def locate_by_id
# Searching through all elements returned by __ole_inner_elements
# is *significantly* slower than IE's getElementById() and
# getElementsByName() calls when how is :id. However
# IE doesn't match Regexps, so first we make sure what is a String.
@@ -55,26 +81,36 @@
the_id = @specifiers[:id]
if the_id && the_id.class == String
element = document.getElementById(the_id) rescue nil
# Return if our fast match really HAS a matching :id
- return element if element && element.invoke('id') == the_id
+ return element if element && element.invoke('id') == the_id && type_matches?(element) && match_with_specifiers?(create_element element)
end
nil
end
- def locate_by_xpath_css_ole
+ def locate_elements_by_xpath_css_ole
+ els = []
+
if @specifiers[:xpath]
- return @container.element_by_xpath(@specifiers[:xpath])
+ els = @container.send(:elements_by_xpath, @specifiers[:xpath])
elsif @specifiers[:css]
- return @container.element_by_css(@specifiers[:css])
+ els = @container.send(:elements_by_css, @specifiers[:css])
elsif @specifiers[:ole_object]
- return @specifiers[:ole_object]
+ return [@specifiers[:ole_object]]
end
+
+ els.select {|element| type_matches?(element) && match_with_specifiers?(create_element element)}
end
+ def type_matches?(el)
+ @tags == ["*"] ||
+ @tags.include?(el.tagName) ||
+ @tags.include?(el.invoke('type')) rescue false
+ end
+
def create_element ole_object
if @klass == Element
element = Element.new(ole_object)
else
element = @klass.new(@container, @specifiers, nil)
@@ -84,34 +120,20 @@
element
end
end
class TaggedElementLocator < Locator
- def initialize(container, tag, klass)
- @container = container
- @tag = tag
- @klass = klass || Element
- end
-
- def each_element tag
+ def each_element(tag)
document.getElementsByTagName(tag).each do |ole_object|
yield create_element ole_object
end
end
- def each
- each_element(@tag) do |element|
- next unless match_with_specifiers?(element)
- yield element
- end
- nil
- end
-
def locate
el = locate_by_id
return el if el
- return locate_by_xpath_css_ole if has_excluding_specifiers?
+ return locate_elements_by_xpath_css_ole[0] if has_excluding_specifiers?
count = Watir::IE.base_index - 1
each do |element|
count += 1
return element.ole_object if count == @specifiers[:index]
@@ -122,83 +144,57 @@
def match?(element, how, what)
begin
method = element.method(how)
rescue NameError
raise MissingWayOfFindingObjectException,
- "#{how} is an unknown way of finding a <#{@tag || @tags.join(", ")}> element (#{what})"
+ "#{how} is an unknown way of finding a <#{@tags.join(", ")}> element (#{what})"
end
case method.arity
when 0
what.matches method.call
when 1
method.call(what)
else
raise MissingWayOfFindingObjectException,
- "#{how} is an unknown way of finding a <#{@tag || @tags.join(", ")}> element (#{what})"
+ "#{how} is an unknown way of finding a <#{@tags.join(", ")}> element (#{what})"
end
end
end
class FrameLocator < TaggedElementLocator
- def initialize(container)
- super(container, Frame::TAG, Frame)
- end
-
- def each_element tag
+ def each_element(tag)
frames = document.frames
i = 0
document.getElementsByTagName(tag).each do |ole_object|
frame = create_element ole_object
frame.document = frames.item(i)
yield frame
i += 1
end
end
- def each
- @tag.each do |t|
- each_element(t) do |element|
- next unless match_with_specifiers?(element)
- yield element
- end
- end
- nil
- end
-
def locate
- # do not locate frames by getElementById since can't get the correct
+ # do not locate frames by getElementById or by xpath since can't get the correct
# 'document' related with that ole_object like it's done in #each_element
- return locate_by_xpath_css_ole if has_excluding_specifiers?
-
count = Watir::IE.base_index - 1
each do |frame|
count += 1
return frame.ole_object, frame.document if count == @specifiers[:index]
end
end
end
class FormLocator < TaggedElementLocator
- def initialize(container)
- super(container, 'FORM', Form)
- end
-
def each_element(tag)
document.forms.each do |form|
yield create_element form
end
end
end
class InputElementLocator < Locator
- def initialize container, types, klass
- @container = container
- @types = types
- @klass = klass || Element
- end
-
def each_element
elements = locate_by_name || @container.__ole_inner_elements
elements.each do |object|
yield create_element object
end
@@ -206,27 +202,33 @@
end
def locate
el = locate_by_id
return el if el
- return locate_by_xpath_css_ole if has_excluding_specifiers?
+ return locate_elements_by_xpath_css_ole[0] if has_excluding_specifiers?
count = Watir::IE.base_index - 1
each do |element|
count += 1
return element.ole_object if count == @specifiers[:index]
end
end
def each
- each_element do |element|
- next unless @types.include?(element.type) && match_with_specifiers?(element)
- yield element
- end
+ if has_excluding_specifiers?
+ locate_elements_by_xpath_css_ole.each do |element|
+ yield element
+ end
+ else
+ each_element do |element|
+ next unless type_matches?(element.ole_object) && match_with_specifiers?(element)
+ yield element
+ end
+ end
nil
end
-
+
# return true if the element matches the provided how and what
def match? element, how, what
begin
attribute = element.send(how)
rescue NoMethodError
@@ -246,13 +248,6 @@
end
nil
end
end
- # This is like the TaggedElementLocator but
- # get all the elements by forcing @tag to be '*'
- class ElementLocator < TaggedElementLocator
- def initialize(container)
- super(container, "*", Element)
- end
- end
end