Class: Vapir::IE::Element

Inherits:
Object
  • Object
show all
Includes:
Element, Exception, Container
Defined in:
lib/vapir-ie/element.rb

Overview

Base class for html elements. This is not a class that users would normally access.

Direct Known Subclasses

Area, Dd, Div, Dl, Dt, Em, H1, H2, H3, H4, H5, H6, InputElement, Label, Li, Map, Ol, Option, P, Pre, Span, Strong, Ul

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Container

#handling_existence_failure, #log

Class Method Details

.element_object_style(element_object, document_object) ⇒ Object



325
326
327
328
329
330
331
# File 'lib/vapir-ie/element.rb', line 325

def self.element_object_style(element_object, document_object)
  if element_object.nodeType==1
    element_object.currentStyle
  else
    nil
  end
end

Instance Method Details

#after?(other) ⇒ Boolean

Return true if self is contained later in the html than other.

Returns:

  • (Boolean)


88
89
90
# File 'lib/vapir-ie/element.rb', line 88

def after?(other)
  source_index > other.source_index
end

#assert_enabledObject

Checks if this element is enabled or not. Raises ObjectDisabledException if this is disabled.



22
23
24
25
26
27
# File 'lib/vapir-ie/element.rb', line 22

def assert_enabled
  # TODO: dry? copied from common InputElement
  if disabled
    raise Exception::ObjectDisabledException, "#{self.inspect} is disabled"
  end
end

#before?(other) ⇒ Boolean

Return true if self is contained earlier in the html than other.

Returns:

  • (Boolean)


84
85
86
# File 'lib/vapir-ie/element.rb', line 84

def before?(other)
  source_index < other.source_index
end

#click(options = {}) ⇒ Object

Fires the click event on this element.

Options:

  • :wait => true or false. If true, waits for the javascript call to return, and calls the #wait method. If false, does not wait for the javascript to return and does not call #wait. Default is the current config.wait value (which is by default true).

  • :highlight => true or false. Highlights the element while clicking if true. Default is true.



173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
# File 'lib/vapir-ie/element.rb', line 173

def click(options={})
  options={:wait => config.wait, :highlight => true}.merge(options)
  result=nil
  with_highlight(options) do
    assert_enabled if respond_to?(:assert_enabled)
    if options[:wait]
      # we're putting all of the clicking actions in an array so that we can more easily separate out the 
      # overhead of checking existence and returning if existence fails. 
      actions=
       [ proc { fire_event('mousedown', options) },
         proc { fire_event('mouseup', options) },
         #proc { fire_event('click', options) },
         proc { element_object.respond_to?(:click) ? element_object.click : fire_event('click', options)
           # TODO/fix: this calls the 'click' function if there is one, but that doesn't pass information 
           # like button/clientX/etc. figure out how to pass that to the event that click fires. 
           # we can't just use the fire_event, because the click function does more than that. for example,
           # a link won't be followed just from firing the onclick event; the click function has to be called. 
           },
       ]
      actions.each do |action|
        # javascript stuff responding to previous events can cause self to stop existing, so check at every subsequent step
        handling_existence_failure(:handle => proc{ return result }) do
          result=action.call
        end
      end
      wait
      result
    else
      document_object.parentWindow.setTimeout("
        (function(tagName, uniqueNumber, event_options)
        { var event_object=document.createEventObject();
          for(key in event_options)
          { event_object[key]=event_options[key];
          }
          var candidate_elements=document.getElementsByTagName(tagName);
          for(var i=0;i<candidate_elements.length;++i)
          { var element=candidate_elements[i];
            if(element.uniqueNumber==uniqueNumber)
            { element.fireEvent('onmousedown', event_object);
              element.fireEvent('onmouseup', event_object);
              //element.fireEvent('onclick', event_object); // #TODO/fix - same as above with click() vs fireEvent('onclick', ...)
              element.click ? element.click() : element.fireEvent('onclick', event_object);
            }
          }
        })(#{self.tagName.inspect}, #{element_object.uniqueNumber.inspect}, #{create_event_object_json(options)})
      ", 0)
      nil
    end
  end
  result
end

#click_no_wait(options = {}) ⇒ Object

calls #click with :wait option false. Takes options:

  • :highlight => true or false. Highlights the element while clicking if true. Default is true.



228
229
230
# File 'lib/vapir-ie/element.rb', line 228

def click_no_wait(options={})
  with_config(:wait => false) { click(options) }
end

#enabled?Boolean

Returns:

  • (Boolean)


18
19
20
# File 'lib/vapir-ie/element.rb', line 18

def enabled?
  !disabled
end

#fire_event(event_type, options = {}) ⇒ Object

Executes a user defined “fireEvent” for objects with JavaScript events tied to them such as DHTML menus.

usage: allows a generic way to fire javascript events on page objects such as "onMouseOver", "onClick", etc.
raises: UnknownObjectException  if the object is not found
        ObjectDisabledException if the object is currently disabled


236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
# File 'lib/vapir-ie/element.rb', line 236

def fire_event(event_type, options={})
  event_type = event_type.to_s.downcase # in case event_type was given as a symbol
  unless event_type =~ /\Aon(.*)\z/i
    event_type = "on"+event_type
  end
  
  options={:highlight => true, :wait => config.wait}.merge(options)
  with_highlight(options) do
    assert_enabled if respond_to?(:assert_enabled)
    if options[:wait]
      # we need to pass fireEvent two arguments - the event type, and the event object. 
      # we can't do this directly. there is a bug or something, the result of which is 
      # that if we pass the WIN32OLE that is the return from document.createEventObject,
      # none of the information about it actually gets passed. its button attribute is
      # 0 regardless of what it was set to; same with clientx, clientY, and everything else. 
      # this seems to be an issue only with passing arguments which are WIN32OLEs to 
      # functions that are native functions (as opposed to functions defined by a user
      # in javascript). so, a workaround is to make a function that is written in javascript
      # that wraps around the native function and just passes the arguments to it. this
      # causes the objects to be passed correctly. to illustrate, compare: 
      #  window.alert(document.createEventObject)
      # this causes an alert to appear with the text "[object]"
      #  window.eval("alert_wrapped=function(message){alert(message);}")
      #  window.alert_wrapped(document.createEventObject)
      # this causes an alert to appear with the text "[object Event]"
      # so, information is lost in the first one, where it's passed straight
      # to the native function but not in the second one where the native function
      # is wrapped in a javascript function. 
      #
      # a generic solution follows, but it doesn't work. I'm leaving it in here in case
      # I can figure out something to do with it later:
      #window.eval("watir_wrap_native_for_win32ole=function(object, functionname)
      #             { var args=[];
      #               for(var i=2; i<arguments.length; ++i)
      #               { args.push(arguments[i]);
      #               }
      #               return object[functionname].apply(object, args);
      #             }")
      #
      # the problem with the above, using apply, is that it sometimse raises: 
      # WIN32OLERuntimeError: watir_wrap_native_for_win32ole
      #     OLE error code:0 in <Unknown>
      #       <No Description>
      #     HRESULT error code:0x80020101
      # 
      # so, instead, implementing to a version that doesn't use apply but 
      # therefore has to have  fixed number of arguments. 
      # TODO: move this to its own function? will when I run into a need for it outside of here, I guess. 
      window=document_object.parentWindow
      window.eval("watir_wrap_native_for_win32ole_two_args=function(object, functionname, arg1, arg2)
        { return object[functionname](arg1, arg2);
        }")
      # then use it, passing the event object. 
      # thus the buttons and mouse position and all that are successfully passed. 
      event_object= create_event_object(event_type, options)
      result=window.watir_wrap_native_for_win32ole_two_args(element_object, 'fireEvent', event_type, event_object)
      wait
      result
    else
      document_object.parentWindow.setTimeout("
        (function(tagName, uniqueNumber, event_type, event_options)
        { var event_object=document.createEventObject();
          for(key in event_options)
          { event_object[key]=event_options[key];
          }
          var candidate_elements=document.getElementsByTagName(tagName);
          for(var i=0;i<candidate_elements.length;++i)
          { if(candidate_elements[i].uniqueNumber==uniqueNumber)
            { candidate_elements[i].fireEvent(event_type, event_object);
            }
          }
        })(#{self.tagName.inspect}, #{element_object.uniqueNumber.inspect}, #{event_type.to_s.inspect}, #{create_event_object_json(options)})
      ", 0)
      nil
    end
  end
end

#fire_event_no_wait(event, options = {}) ⇒ Object

Executes a user defined “fireEvent” for objects with JavaScript events tied to them such as DHTML menus.

usage: allows a generic way to fire javascript events on page objects such as "onMouseOver", "onClick", etc.
raises: UnknownObjectException  if the object is not found
        ObjectDisabledException if the object is currently disabled


317
318
319
# File 'lib/vapir-ie/element.rb', line 317

def fire_event_no_wait(event, options={})
  with_config(:wait => false) { fire_event(event, options) }
end

#scroll_offsetObject

returns a two-element Vector containing the current scroll offset of this element relative to any scrolling parents. this is basically stolen from prototype - see www.prototypejs.org/api/element/cumulativescrolloffset



337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
# File 'lib/vapir-ie/element.rb', line 337

def scroll_offset
  # override the #scroll_offset defined in vapir-common because it calls #respond_to? which is very slow on WIN32OLE 
  xy=Vector[0,0]
  el=element_object
  begin
    begin
      if (scroll_left=el.scrollLeft).is_a?(Numeric) && (scroll_top=el.scrollTop).is_a?(Numeric)
        xy+=Vector[scroll_left, scroll_top]
      end
    rescue WIN32OLERuntimeError, NoMethodError
      # doesn't respond to those; do nothing. 
    end
    el=el.parentNode
  end while el
  xy
end

#text_after_beginObject

text after the start of the element but before all other content in the element

msdn.microsoft.com/en-us/library/ms536427(VS.85).aspx



53
54
55
# File 'lib/vapir-ie/element.rb', line 53

def text_after_begin
  element_object.getAdjacentText("afterBegin")
end

#text_after_endObject Also known as: before_text

text immediately before this element

msdn.microsoft.com/en-us/library/ms536427(VS.85).aspx



65
66
67
# File 'lib/vapir-ie/element.rb', line 65

def text_after_end
  element_object.getAdjacentText("afterEnd")
end

#text_before_beginObject Also known as: after_text

text immediately before this element

msdn.microsoft.com/en-us/library/ms536427(VS.85).aspx



47
48
49
# File 'lib/vapir-ie/element.rb', line 47

def text_before_begin
  element_object.getAdjacentText("beforeBegin")
end

#text_before_endObject

text immediately before the end of the element but after all other content in the element

msdn.microsoft.com/en-us/library/ms536427(VS.85).aspx



59
60
61
# File 'lib/vapir-ie/element.rb', line 59

def text_before_end
  element_object.getAdjacentText("beforeEnd")
end

#wait(options = {}) ⇒ Object



321
322
323
# File 'lib/vapir-ie/element.rb', line 321

def wait(options={})
  @container.wait(options) if config.wait
end