So, I'm clear on how to attach to events:
@ie = WIN32OLE.new( 'InternetExplorer.Application' )
browserEvents = WIN32OLE_EVENT.new( @ie, 'DWebBrowserEvents2' )
browserEvents.on_event { |*args| eventHandler( *args ) }
But how does one detach from events?
I'm working on a little utility that will generate Watir scripts using
IE automation. In the following code I am attaching to the browser
events to capture when a new HTML document is loaded. When a document
is loaded I want to attach to the document's events. When a new
document is loaded I want to detach from the old document's events.
Here's the code so far. At the moment, each newly loaded document adds
to a growing list of event handlers, causing each click to produce
multiple calls to printClickStatement.
Thanks,
-=michael=-
#requires
require 'win32ole'
##//////////////////////////////////////////////////////////////////////
///////////////////////////////
···
##
## Main WatirMaker class. It handles the IE automation, which primarily
means event handling.
##
##//////////////////////////////////////////////////////////////////////
///////////////////////////////
class WatirMaker
##//////////////////////////////////////////////////////////////////////
////////////////////////////
##
## Initializer executed when "new" is called.
##
##//////////////////////////////////////////////////////////////////////
////////////////////////////
def initialize
end
##//////////////////////////////////////////////////////////////////////
////////////////////////////
##
## Handles all events from the browser and the HTML document.
##
##//////////////////////////////////////////////////////////////////////
////////////////////////////
def eventHandler( event, *args )
case event
when "BeforeNavigate2"
webBrowser = args[0]
url = args[1]
frameName = args[3]
if frameName == ""
@webBrowsers = Hash.new
if @documentEventHandlers != nil
@documentEventHandlers.each_value { |value|
value.on_event( 'onclick' ) {} }
end
@documentEventHandlers = Hash.new
end
@webBrowsers[url] = webBrowser
printNavigateComment( url, frameName )
when "NavigateComplete2"
#printNavigateComment( args[1], nil )
when "DocumentComplete"
url = args[1]
webBrowser = @webBrowsers[url]
if ( webBrowser.Type == "HTML Document" &&
!@documentEventHandlers.has_key?( url ) )
@documentEventHandlers[url] =
WIN32OLE_EVENT.new( webBrowser.document,
'HTMLDocumentEvents2' )
@documentEventHandlers[url].on_event( 'onclick' ) { |*args|
printClickStatement( args[0] )
}
end
when "OnQuit"
throw :done
end
end
##//////////////////////////////////////////////////////////////////////
////////////////////////////
##
## Print comment showing the page navigated to.
##
##//////////////////////////////////////////////////////////////////////
////////////////////////////
def printNavigateComment( url, frameName )
puts ""
puts "# frame loaded: '" + frameName + "'" if frameName != nil
puts "# navigated to: '" + url + "'"
puts ""
end
##//////////////////////////////////////////////////////////////////////
////////////////////////////
##
## Print Watir statement for click events.
##
##//////////////////////////////////////////////////////////////////////
////////////////////////////
def printClickStatement( eventObj )
how, what = getHowWhat( eventObj.srcElement )
case eventObj.srcElement.tagName
when "INPUT"
case eventObj.srcElement.getAttribute( "type" )
when "submit"
# TODO: must figure out a way to get the frame that contains
the srcElement. The frame
# will be necessary to properly reference the element.
puts "ie.button( " + how + ", '" + what + "' ).click"
end
end
end
##//////////////////////////////////////////////////////////////////////
////////////////////////////
##
## Returns the "how" and the "what" values.
##
## Note: may need different getHowWhat methods for different element
types because each element
## type supports different "how" values.
##
##//////////////////////////////////////////////////////////////////////
////////////////////////////
def getHowWhat( element )
if element.getAttribute( "id" ) != ""
return ":id", element.getAttribute( "id" )
elsif element.getAttribute( "name" ) != ""
return ":name", element.getAttribute( "name" )
else
# TODO: must get the actual index of the item using the
# IHTMLDocument3::getElementsByTagName method
return ":index", 1
end
end
##//////////////////////////////////////////////////////////////////////
////////////////////////////
##
## Starts recording all interactions with IE.
##
##//////////////////////////////////////////////////////////////////////
////////////////////////////
def startRecording
# initialize IE
@ie = WIN32OLE.new( 'InternetExplorer.Application' )
@ie.visible = TRUE
@ie.gohome
browserEvents = WIN32OLE_EVENT.new( @ie, 'DWebBrowserEvents2' )
browserEvents.on_event { |*args| eventHandler( *args ) }
# print script header
puts
"##/////////////////////////////////////////////////////////////////////
/////////////////////////////"
puts "##"
puts "## Watir script recorded by WatirMaker."
puts "##"
puts
"##/////////////////////////////////////////////////////////////////////
/////////////////////////////"
puts ""
puts "#requires"
puts "require 'watir'"
puts ""
puts "#includes"
puts "include Watir"
puts ""
puts "ie = IE.new"
puts "ie.set_fast_speed()"
puts "ie.ie.gohome"
puts ""
# capture events
catch( :done ) {
loop {
WIN32OLE_EVENT.message_loop
}
}
# IE takes a moment to close.
# Making it invisible in the interim produces a slightly nicer
user experience.
@ie.visible = FALSE
end
end # end class
--
Michael Kelly
Sr. Software Engineer
Eleven Wireless Inc. - The Possibilities are Wireless
http://www.elevenwireless.com <http://www.elevenwireless.com/>