lib/watir/locator.rb in watir-2.0.1 vs lib/watir/locator.rb in watir-2.0.2.rc1
- old
+ new
@@ -1,10 +1,14 @@
module Watir
class Locator
include Watir
include Watir::Exception
+ def document
+ @document ||= @container.document
+ end
+
def normalize_specifiers!(specifiers)
specifiers.each do |how, what|
case how
when :index
what = what.to_i
@@ -26,24 +30,59 @@
def match_with_specifiers?(element)
@specifiers.all? {|how, what| how == :index || match?(element, how, what)}
end
+ def has_excluding_specifiers?
+ @specifiers.keys.any? {|specifier| [:css, :xpath, :ole_object].include? specifier}
+ end
+
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.
+ # In addition, IE's getElementById() will also return an element
+ # where the :name matches, so we will only return the results of
+ # getElementById() if the matching element actually HAS a matching
+ # :id.
+ 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
+ end
+
+ nil
+ end
+
def locate_by_xpath_css_ole
if @specifiers[:xpath]
return @container.element_by_xpath(@specifiers[:xpath])
elsif @specifiers[:css]
return @container.element_by_css(@specifiers[:css])
elsif @specifiers[:ole_object]
return @specifiers[:ole_object]
+ end
+ end
+
+ def create_element ole_object
+ if @klass == Element
+ element = Element.new(ole_object)
+ else
+ element = @klass.new(@container, @specifiers, nil)
+ element.ole_object = ole_object
+ def element.locate; @o; end
end
+ element
end
end
class TaggedElementLocator < Locator
def initialize(container, tag, klass)
@@ -51,19 +90,12 @@
@tag = tag
@klass = klass || Element
end
def each_element tag
- @container.document.getElementsByTagName(tag).each do |ole_object|
- if @klass == Element
- element = Element.new(ole_object)
- else
- element = @klass.new(@container, @specifiers, nil)
- element.ole_object = ole_object
- def element.locate; @o; end unless @klass == TableRow
- end
- yield element
+ document.getElementsByTagName(tag).each do |ole_object|
+ yield create_element ole_object
end
end
def each
each_element(@tag) do |element|
@@ -72,11 +104,13 @@
end
nil
end
def locate
- return locate_by_xpath_css_ole if @specifiers[:xpath] || @specifiers[:css] || @specifiers[:ole_object]
+ el = locate_by_id
+ return el if el
+ return locate_by_xpath_css_ole if has_excluding_specifiers?
count = Watir::IE.base_index - 1
each do |element|
count += 1
return element.ole_object if count == @specifiers[:index]
@@ -87,56 +121,55 @@
def match?(element, how, what)
begin
method = element.method(how)
rescue NameError
raise MissingWayOfFindingObjectException,
- "#{how} is an unknown way of finding a <#{@tag}> element (#{what})"
+ "#{how} is an unknown way of finding a <#{@tag || @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}> element (#{what})"
+ "#{how} is an unknown way of finding a <#{@tag || @tags.join(", ")}> element (#{what})"
end
end
end
class FrameLocator < TaggedElementLocator
def initialize(container)
- @container = container
- @tags = Frame::TAG
+ super(container, Frame::TAG, Frame)
end
def each_element tag
- frames = @container.document.frames
+ frames = document.frames
i = 0
- @container.document.getElementsByTagName(tag).each do |ole_object|
- frame = Frame.new(@container, @specifiers, nil)
- frame.ole_object = ole_object
+ document.getElementsByTagName(tag).each do |ole_object|
+ frame = create_element ole_object
frame.document = frames.item(i)
- def frame.locate; @o; end
yield frame
i += 1
end
end
def each
- @tags.each do |tag|
- each_element(tag) do |element|
+ @tag.each do |t|
+ each_element(t) do |element|
next unless match_with_specifiers?(element)
yield element
end
end
nil
end
def locate
- return locate_by_xpath_css_ole if @specifiers[:xpath] || @specifiers[:css] || @specifiers[:ole_object]
+ # do not locate frames by getElementById 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]
@@ -148,46 +181,35 @@
def initialize(container)
super(container, 'FORM', Form)
end
def each_element(tag)
- @container.document.forms.each do |form|
- form_element = Form.new(@container, @specifiers, nil)
- form_element.ole_object = form
- def form_element.locate; @o; end
- yield form_element
+ document.forms.each do |form|
+ yield create_element form
end
end
end
class InputElementLocator < Locator
-
- attr_accessor :document, :element, :elements, :klass
-
def initialize container, types, klass
@container = container
@types = types
- @elements = nil
@klass = klass || Element
end
def each_element
- @elements.each do |object|
- if @klass == Element
- element = Element.new(object)
- else
- element = @klass.new(@container, @specifiers, nil)
- element.ole_object = object
- def element.locate; @o; end
- end
- yield element
+ elements = locate_by_name || @container.__ole_inner_elements
+ elements.each do |object|
+ yield create_element object
end
nil
end
def locate
- return locate_by_xpath_css_ole if @specifiers[:xpath] || @specifiers[:css] || @specifiers[:ole_object]
+ el = locate_by_id
+ return el if el
+ return locate_by_xpath_css_ole if has_excluding_specifiers?
count = Watir::IE.base_index - 1
each do |element|
count += 1
return element.ole_object if count == @specifiers[:index]
@@ -212,32 +234,17 @@
end
what.matches(attribute)
end
- def fast_locate
- # Searching through all elements returned by ole_inner_elements
- # is *significantly* slower than IE's getElementById() and
- # getElementsByName() calls when how is :id or :name. However
- # IE doesn't match Regexps, so first we make sure what is a String.
- # In addition, IE's getElementById() will also return an element
- # where the :name matches, so we will only return the results of
- # getElementById() if the matching element actually HAS a matching
- # :id.
+ private
- the_id = @specifiers[:id]
- if the_id && the_id.class == String &&
- @specifiers[:index] == Watir::IE.base_index && @specifiers.length == 2
- @element = @document.getElementById(the_id) rescue nil
- # Return if our fast match really HAS a matching :id
- return true if @element && @element.invoke('id') == the_id && @types.include?(@element.getAttribute('type'))
- end
-
+ def locate_by_name
the_name = @specifiers[:name]
if the_name && the_name.class == String
- @elements = @document.getElementsByName(the_name) rescue nil
- end
- false
+ return document.getElementsByName(the_name) rescue nil
+ end
+ nil
end
end
# This is like the TaggedElementLocator but
# get all the elements by forcing @tag to be '*'