lib/watir/table.rb in watir-1.6.5 vs lib/watir/table.rb in watir-1.6.6.rc1

- old
+ new

@@ -1,363 +1,396 @@ -module Watir - - # This class is used for dealing with tables. - # Normally a user would not need to create this object as it is returned by the Watir::Container#table method - # - # many of the methods available to this object are inherited from the Element class - # - class Table < Element - include Container - - # Returns the table object containing the element - # * container - an instance of an IE object - # * anElement - a Watir object (TextField, Button, etc.) - def Table.create_from_element(container, element) - element.locate if element.respond_to?(:locate) - o = element.ole_object.parentElement - o = o.parentElement until o.tagName == 'TABLE' - new container, :ole_object, o - end - - # Returns an initialized instance of a table object - # * container - the container - # * how - symbol - how we access the table - # * what - what we use to access the table - id, name index etc - def initialize(container, how, what) - set_container container - @how = how - @what = what - super nil - end - - def locate - if @how == :xpath - @o = @container.element_by_xpath(@what) - elsif @how == :ole_object - @o = @what - else - @o = @container.locate_tagged_element('TABLE', @how, @what) - end - end - - # override the highlight method, as if the tables rows are set to have a background color, - # this will override the table background color, and the normal flash method won't work - def highlight(set_or_clear) - if set_or_clear == :set - begin - @original_border = @o.border.to_i - if @o.border.to_i==1 - @o.border = 2 - else - @o.border = 1 - end - rescue - @original_border = nil - end - else - begin - @o.border= @original_border unless @original_border == nil - @original_border = nil - rescue - # we could be here for a number of reasons... - ensure - @original_border = nil - end - end - super - end - - # this method is used to populate the properties in the to_s method - def table_string_creator - n = [] - n << "rows:".ljust(TO_S_SIZE) + self.row_count.to_s - n << "cols:".ljust(TO_S_SIZE) + self.column_count.to_s - return n - end - private :table_string_creator - - # returns the properties of the object in a string - # raises an ObjectNotFound exception if the object cannot be found - def to_s - assert_exists - r = string_creator - r += table_string_creator - return r.join("\n") - end - - # iterates through the rows in the table. Yields a TableRow object - def each - assert_exists - 1.upto(@o.rows.length) do |i| - yield TableRow.new(@container, :ole_object, _row(i)) - end - end - - # Returns a row in the table - # * index - the index of the row - def [](index) - assert_exists - return TableRow.new(@container, :ole_object, _row(index)) - end - - # Returns the number of rows inside the table, including rows in nested tables. - def row_count - assert_exists - #return table_body.children.length - return @o.getElementsByTagName("TR").length - end - - # Returns the number of rows in the table, not including rows in nested tables. - def row_count_excluding_nested_tables - assert_exists - return @o.rows.length - end - - # This method returns the number of columns in a row of the table. - # Raises an UnknownObjectException if the table doesn't exist. - # * index - the index of the row - def column_count(index=1) - assert_exists - _row(index).cells.length - end - - # This method returns the table as a 2 dimensional array. - # Don't expect too much if there are nested tables, colspan etc. - # Raises an UnknownObjectException if the table doesn't exist. - # http://www.w3.org/TR/html4/struct/tables.html - def to_a - assert_exists - y = [] - table_rows = @o.getElementsByTagName("TR") - for row in table_rows - x = [] - for td in row.getElementsbyTagName("TD") - x << td.innerText.strip - end - y << x - end - return y - end - - def table_body(index=1) - return @o.getElementsByTagName('TBODY')[index] - end - private :table_body - - # returns a watir object - def body(how, what) - return TableBody.new(@container, how, what, self) - end - - # returns a watir object - def bodies - assert_exists - return TableBodies.new(@container, @o) - end - - # returns an ole object - def _row(index) - return @o.invoke("rows").item(index - 1) - end - private :_row - - # Returns an array containing all the text values in the specified column - # Raises an UnknownCellException if the specified column does not exist in every - # Raises an UnknownObjectException if the table doesn't exist. - # row of the table - # * columnnumber - column index to extract values from - def column_values(columnnumber) - return (1..row_count).collect {|i| self[i][columnnumber].text} - end - - # Returns an array containing all the text values in the specified row - # Raises an UnknownObjectException if the table doesn't exist. - # * rownumber - row index to extract values from - def row_values(rownumber) - return (1..column_count(rownumber)).collect {|i| self[rownumber][i].text} - end - - end - - # this class is a collection of the table body objects that exist in the table - # it wouldnt normally be created by a user, but gets returned by the bodies method of the Table object - # many of the methods available to this object are inherited from the Element class - # - class TableBodies < Element - def initialize(container, parent_table) - set_container container - @o = parent_table # in this case, @o is the parent table - end - - # returns the number of TableBodies that exist in the table - def length - assert_exists - return @o.tBodies.length - end - - # returns the n'th Body as a Watir TableBody object - def []n - assert_exists - return TableBody.new(@container, :ole_object, ole_table_body_at_index(n)) - end - - # returns an ole table body - def ole_table_body_at_index(n) - return @o.tBodies.item(n-1) - end - - # iterates through each of the TableBodies in the Table. Yields a TableBody object - def each - 1.upto(@o.tBodies.length) do |i| - yield TableBody.new(@container, :ole_object, ole_table_body_at_index(i)) - end - end - - end - - # this class is a table body - class TableBody < Element - def locate - @o = nil - if @how == :ole_object - @o = @what # in this case, @o is the table body - elsif @how == :index - @o = @parent_table.bodies.ole_table_body_at_index(@what) - end - @rows = [] - if @o - @o.rows.each do |oo| - @rows << TableRow.new(@container, :ole_object, oo) - end - end - end - - def initialize(container, how, what, parent_table=nil) - set_container container - @how = how - @what = what - @parent_table = parent_table - super nil - end - - # returns the specified row as a TableRow object - def [](n) - assert_exists - return @rows[n - 1] - end - - # iterates through all the rows in the table body - def each - locate - 0.upto(@rows.length - 1) { |i| yield @rows[i] } - end - - # returns the number of rows in this table body. - def length - return @rows.length - end - end - - class TableRow < Element - - def locate - @o = nil - if @how == :ole_object - @o = @what - elsif @how == :xpath - @o = @container.element_by_xpath(@what) - else - @o = @container.locate_tagged_element("TR", @how, @what) - end - if @o # cant call the assert_exists here, as an exists? method call will fail - @cells = [] - @o.cells.each do |oo| - @cells << TableCell.new(@container, :ole_object, oo) - end - end - end - - # Returns an initialized instance of a table row - # * o - the object contained in the row - # * container - an instance of an IE object - # * how - symbol - how we access the row - # * what - what we use to access the row - id, index etc. If how is :ole_object then what is a Internet Explorer Raw Row - def initialize(container, how, what) - set_container container - @how = how - @what = what - super nil - end - - # this method iterates through each of the cells in the row. Yields a TableCell object - def each - locate - 0.upto(@cells.length-1) { |i| yield @cells[i] } - end - - # Returns an element from the row as a TableCell object - def [](index) - assert_exists - if @cells.length < index - raise UnknownCellException, "Unable to locate a cell at index #{index}" - end - return @cells[(index - 1)] - end - - # defaults all missing methods to the array of elements, to be able to - # use the row as an array - # def method_missing(aSymbol, *args) - # return @o.send(aSymbol, *args) - # end - def column_count - locate - @cells.length - end - end - - # this class is a table cell - when called via the Table object - class TableCell < Element - include Watir::Exception - include Container - - def locate - if @how == :xpath - @o = @container.element_by_xpath(@what) - elsif @how == :ole_object - @o = @what - else - @o = @container.locate_tagged_element("TD", @how, @what) - end - end - - # Returns an initialized instance of a table cell - # * container - an IE object - # * how - symbol - how we access the cell - # * what - what we use to access the cell - id, name index etc - def initialize(container, how, what) - set_container container - @how = how - @what = what - super nil - end - - def ole_inner_elements - locate - return @o.all - end - private :ole_inner_elements - - def document - locate - return @o - end - - alias to_s text - - def colspan - locate - @o.colSpan - end - - end - +module Watir + + # This class is used for dealing with tables. + # Normally a user would not need to create this object as it is returned by the Watir::Container#table method + # + # many of the methods available to this object are inherited from the Element class + # + class Table < Element + include Container + + # Returns the table object containing the element + # * container - an instance of an IE object + # * anElement - a Watir object (TextField, Button, etc.) + def Table.create_from_element(container, element) + element.locate if element.respond_to?(:locate) + o = element.ole_object.parentElement + o = o.parentElement until o.tagName == 'TABLE' + new container, :ole_object, o + end + + # Returns an initialized instance of a table object + # * container - the container + # * how - symbol - how we access the table + # * what - what we use to access the table - id, name index etc + def initialize(container, how, what) + set_container container + @how = how + @what = what + super nil + end + + def locate + if @how == :xpath + @o = @container.element_by_xpath(@what) + elsif @how == :ole_object + @o = @what + else + @o = @container.locate_tagged_element('TABLE', @how, @what) + end + end + + # override the highlight method, as if the tables rows are set to have a background color, + # this will override the table background color, and the normal flash method won't work + def highlight(set_or_clear) + if set_or_clear == :set + begin + @original_border = @o.border.to_i + if @o.border.to_i==1 + @o.border = 2 + else + @o.border = 1 + end + rescue + @original_border = nil + end + else + begin + @o.border= @original_border unless @original_border == nil + @original_border = nil + rescue + # we could be here for a number of reasons... + ensure + @original_border = nil + end + end + super + end + + # this method is used to populate the properties in the to_s method + def table_string_creator + n = [] + n << "rows:".ljust(TO_S_SIZE) + self.row_count.to_s + n << "cols:".ljust(TO_S_SIZE) + self.column_count.to_s + return n + end + private :table_string_creator + + # returns the properties of the object in a string + # raises an ObjectNotFound exception if the object cannot be found + def to_s + assert_exists + r = string_creator + r += table_string_creator + return r.join("\n") + end + + # iterates through the rows in the table. Yields a TableRow object + def each + assert_exists + 1.upto(@o.rows.length) do |i| + yield TableRow.new(@container, :ole_object, _row(i)) + end + end + + # Returns a row in the table + # * index - the index of the row + def [](index) + assert_exists + return TableRow.new(@container, :ole_object, _row(index)) + end + + # Returns the number of rows inside the table, including rows in nested tables. + def row_count + assert_exists + #return table_body.children.length + return @o.getElementsByTagName("TR").length + end + + # Returns the number of rows in the table, not including rows in nested tables. + def row_count_excluding_nested_tables + assert_exists + return @o.rows.length + end + + # This method returns the number of columns in a row of the table. + # Raises an UnknownObjectException if the table doesn't exist. + # * index - the index of the row + def column_count(index=1) + assert_exists + _row(index).cells.length + end + + # Returns multi-dimensional array of the cell texts in a table. + # + # Works with tr, th, td elements, colspan, rowspan and nested tables. + # Takes an optional parameter *max_depth*, which is by default 1 + def to_a(max_depth=1) + assert_exists + y = [] + @o.rows.each do |row| + y << TableRow.new(@container, :ole_object, row).to_a(max_depth) + end + y + end + + def table_body(index=1) + return @o.getElementsByTagName('TBODY')[index] + end + private :table_body + + # returns a watir object + def body(how, what) + return TableBody.new(@container, how, what, self) + end + + # returns a watir object + def bodies + assert_exists + return TableBodies.new(@container, @o) + end + + # returns an ole object + def _row(index) + return @o.invoke("rows").item(index - 1) + end + private :_row + + # Returns an array containing all the text values in the specified column + # Raises an UnknownCellException if the specified column does not exist in every + # Raises an UnknownObjectException if the table doesn't exist. + # row of the table + # * columnnumber - column index to extract values from + def column_values(columnnumber) + return (1..row_count).collect {|i| self[i][columnnumber].text} + end + + # Returns an array containing all the text values in the specified row + # Raises an UnknownObjectException if the table doesn't exist. + # * rownumber - row index to extract values from + def row_values(rownumber) + return (1..column_count(rownumber)).collect {|i| self[rownumber][i].text} + end + + end + + # this class is a collection of the table body objects that exist in the table + # it wouldnt normally be created by a user, but gets returned by the bodies method of the Table object + # many of the methods available to this object are inherited from the Element class + # + class TableBodies < Element + def initialize(container, parent_table) + set_container container + @o = parent_table # in this case, @o is the parent table + end + + # returns the number of TableBodies that exist in the table + def length + assert_exists + return @o.tBodies.length + end + + # returns the n'th Body as a Watir TableBody object + def []n + assert_exists + return TableBody.new(@container, :ole_object, ole_table_body_at_index(n)) + end + + # returns an ole table body + def ole_table_body_at_index(n) + return @o.tBodies.item(n-1) + end + + # iterates through each of the TableBodies in the Table. Yields a TableBody object + def each + 1.upto(@o.tBodies.length) do |i| + yield TableBody.new(@container, :ole_object, ole_table_body_at_index(i)) + end + end + + end + + # this class is a table body + class TableBody < Element + def locate + @o = nil + if @how == :ole_object + @o = @what # in this case, @o is the table body + elsif @how == :index + @o = @parent_table.bodies.ole_table_body_at_index(@what) + end + @rows = [] + if @o + @o.rows.each do |oo| + @rows << TableRow.new(@container, :ole_object, oo) + end + end + end + + def initialize(container, how, what, parent_table=nil) + set_container container + @how = how + @what = what + @parent_table = parent_table + super nil + end + + # returns the specified row as a TableRow object + def [](n) + assert_exists + return @rows[n - 1] + end + + # iterates through all the rows in the table body + def each + locate + 0.upto(@rows.length - 1) { |i| yield @rows[i] } + end + + # returns the number of rows in this table body. + def length + return @rows.length + end + end + + class TableRow < Element + + def locate + @o = nil + if @how == :ole_object + @o = @what + elsif @how == :xpath + @o = @container.element_by_xpath(@what) + else + @o = @container.locate_tagged_element("TR", @how, @what) + end + if @o # cant call the assert_exists here, as an exists? method call will fail + @cells = [] + @o.cells.each do |oo| + @cells << TableCell.new(@container, :ole_object, oo) + end + end + end + + # Returns an initialized instance of a table row + # * o - the object contained in the row + # * container - an instance of an IE object + # * how - symbol - how we access the row + # * what - what we use to access the row - id, index etc. If how is :ole_object then what is a Internet Explorer Raw Row + def initialize(container, how, what) + set_container container + @how = how + @what = what + super nil + end + + # this method iterates through each of the cells in the row. Yields a TableCell object + def each + locate + 0.upto(@cells.length-1) { |i| yield @cells[i] } + end + + # Returns an element from the row as a TableCell object + def [](index) + assert_exists + if @cells.length < index + raise UnknownCellException, "Unable to locate a cell at index #{index}" + end + return @cells[(index - 1)] + end + + # defaults all missing methods to the array of elements, to be able to + # use the row as an array + # def method_missing(aSymbol, *args) + # return @o.send(aSymbol, *args) + # end + def column_count + locate + @cells.length + end + + # Returns (multi-dimensional) array of the cell texts in table's row. + # + # Works with th, td elements, colspan, rowspan and nested tables. + # Takes an optional parameter *max_depth*, which is by default 1 + def to_a(max_depth=1) + assert_exists + y = [] + @o.cells.each do |cell| + inner_tables = cell.getElementsByTagName("TABLE") + inner_tables.each do |inner_table| + # make sure that the inner table is directly child for this cell + if inner_table?(cell, inner_table) + max_depth -= 1 + y << Table.new(@container, :ole_object, inner_table).to_a(max_depth) if max_depth >= 1 + end + end + + if inner_tables.length == 0 + y << cell.innerText.strip + end + end + y + end + + private + # Returns true if inner_table is direct child + # table for cell and there's not any table-s in between + def inner_table?(cell, inner_table) + parent_element = inner_table.parentElement + if parent_element.uniqueID == cell.uniqueID + return true + elsif parent_element.tagName == "TABLE" + return false + else + return inner_table?(cell, parent_element) + end + end + end + + # this class is a table cell - when called via the Table object + class TableCell < Element + include Watir::Exception + include Container + + def locate + if @how == :xpath + @o = @container.element_by_xpath(@what) + elsif @how == :ole_object + @o = @what + else + @o = @container.locate_tagged_element("TD", @how, @what) + end + end + + # Returns an initialized instance of a table cell + # * container - an IE object + # * how - symbol - how we access the cell + # * what - what we use to access the cell - id, name index etc + def initialize(container, how, what) + set_container container + @how = how + @what = what + super nil + end + + def ole_inner_elements + locate + return @o.all + end + private :ole_inner_elements + + def document + locate + return @o + end + + alias to_s text + + def colspan + locate + @o.colSpan + end + + end + end \ No newline at end of file