vapir-firefox 1.7.0.rc1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,277 @@
1
+ require 'vapir-common/element'
2
+ require 'vapir-firefox/container'
3
+
4
+ module Vapir
5
+ # Base class for html elements.
6
+ # This is not a class that users would normally access.
7
+ class Firefox::Element
8
+ include Vapir::Firefox::Container
9
+ include Vapir::Element
10
+
11
+ # Creates new instance of Firefox::Element.
12
+ def initialize(how, what, extra={})
13
+ @jssh_socket=extra[:jssh_socket]
14
+ @jssh_socket||= (extra[:browser].jssh_socket if extra[:browser])
15
+ @jssh_socket||= (extra[:container].jssh_socket if extra[:container])
16
+ @jssh_socket||= (what.jssh_socket if how==:element_object)
17
+ unless @jssh_socket
18
+ raise RuntimeError, "No JSSH socket given! Firefox elements need this (specified in the :jssh_socket key of the extra hash)"
19
+ end
20
+ default_initialize(how, what, extra)
21
+ end
22
+
23
+ attr_reader :jssh_socket
24
+
25
+ def outer_html
26
+ # in case doing appendChild of self on the temp_parent_element causes it to be removed from our parentNode, we first copy the list of parentNode's childNodes (our siblings)
27
+ # todo/fix: can use cloneNode instead of all this?
28
+ if parentNode=element_object.parentNode
29
+ parentNode=parentNode.store_rand_temp
30
+ orig_siblings=jssh_socket.object('[]').store_rand_prefix('firewatir_elements')
31
+ parentNode.childNodes.to_array.each do |node|
32
+ orig_siblings.push node
33
+ end
34
+ end
35
+
36
+ temp_parent_element=document_object.createElement('div')
37
+ temp_parent_element.appendChild(element_object)
38
+ self_outer_html=temp_parent_element.innerHTML
39
+
40
+ # reinsert self in parentNode's childNodes if we have disappeared due to the appendChild on different parent
41
+ if parentNode && parentNode.childNodes.length != orig_siblings.length
42
+ while parentNode.childNodes.length > 0
43
+ parentNode.removeChild(parentNode.childNodes[0])
44
+ end
45
+ while orig_siblings.length > 0
46
+ parentNode.appendChild orig_siblings.shift
47
+ end
48
+ end
49
+
50
+ return self_outer_html
51
+ end
52
+ alias outerHTML outer_html
53
+
54
+ # the containing object is what #locate uses to find stuff contained by this element.
55
+ # this is generally the same as the dom object, but different for Browser and Frame.
56
+ alias containing_object element_object
57
+
58
+ # alias ole_object element_object
59
+
60
+ private
61
+ def base_element_class
62
+ Firefox::Element
63
+ end
64
+ def browser_class
65
+ Firefox
66
+ end
67
+
68
+ public
69
+ def current_style_object # currentStyle is IE; document.defaultView.getComputedStyle is mozilla.
70
+ document_object.defaultView.getComputedStyle(element_object, nil)
71
+ end
72
+ alias computed_style_object current_style_object
73
+ alias_deprecated :currentStyle, :current_style_object
74
+
75
+ # Fires the given event on this element.
76
+ # The given event name can be either of the form 'onclick' (for compatibility with IE) or just 'click' (can also be Symbol :onclick or :click)
77
+ # takes options:
78
+ # - :wait => true/false - (default true) whether to wait for the fire event to return, and call #wait (see #wait's documentation).
79
+ # if false, fires the event in a setTimeout(click function, 0) in the browser.
80
+ # - :highlight => true/false - (default true) whether to highlight this Element when firing the event.
81
+ #
82
+ # TODO: Provide ability to specify event parameters like keycode for key events, and click screen
83
+ # coordinates for mouse events.
84
+ def fire_event(event_type, options={})
85
+ options={:wait => true, :highlight => true}.merge(options)
86
+ with_highlight(options) do
87
+ event=create_event_object(event_type, options)
88
+ if !options[:wait]
89
+ raise "need a content window on which to setTimeout if we are not waiting" unless content_window_object
90
+ fire_event_func=jssh_socket.object("(function(element_object, event){return function(){element_object.dispatchEvent(event)};})").pass(element_object, event)
91
+ content_window_object.setTimeout(fire_event_func, 0)
92
+ nil
93
+ else
94
+ result=element_object.dispatchEvent(event)
95
+ wait if exists?
96
+ result
97
+ end
98
+ end
99
+ end
100
+
101
+ private
102
+ # for use with events' button property:
103
+ # https://developer.mozilla.org/en/DOM/event.button
104
+ MouseButtonCodes=
105
+ { :left => 0,
106
+ :middle => 1,
107
+ :right => 2,
108
+ }
109
+
110
+ # returns an object representing an event (a jssh object)
111
+ def create_event_object(event_type, options)
112
+ event_type = event_type.to_s.downcase # in case event_type was given as a symbol
113
+ if event_type =~ /\Aon(.*)\z/i
114
+ event_type = $1
115
+ end
116
+
117
+ # info about event types harvested from:
118
+ # http://www.howtocreate.co.uk/tutorials/javascript/domevents
119
+ # the following sets up the dom event type (dom_event_type{, the function
120
+ # to be called to initialize the event (init_event_func), and the arguments
121
+ # to pass to that function (init_event_args).
122
+ # the arguments list is an array of two-element arrays (a hash would
123
+ # be more appropriate except that order needs to be preserved). only
124
+ # the second element is passed to the function that initializes the event;
125
+ # the first element is just there to identify what the argument is/does
126
+ # for clarity when reading this code.
127
+ case event_type
128
+ when 'keydown', 'keypress', 'keyup'
129
+ dom_event_type = 'KeyEvents'
130
+ init_event_func=:initKeyEvent
131
+ init_event_args=
132
+ [ [:type, event_type],
133
+ [:bubbles, true],
134
+ [:cancelable, true],
135
+ [:windowObject, content_window_object],
136
+ [:ctrlKey, false],
137
+ [:altKey, false],
138
+ [:shiftKey, false],
139
+ [:metaKey, false],
140
+ [:keyCode, 0],
141
+ [:charCode, 0],
142
+ ]
143
+ when 'click', 'dblclick', 'mousedown', 'mousemove', 'mouseout', 'mouseover', 'mouseup'
144
+ dom_event_type = 'MouseEvents'
145
+ init_event_func = :initMouseEvent
146
+ client_center=self.client_center
147
+ init_event_args=
148
+ [ [:type, event_type],
149
+ [:bubbles, true],
150
+ [:cancelable, true],
151
+ [:windowObject, content_window_object], # aka view
152
+ [:detail, event_type=='dblclick' ? 2 : 1], # value is always 2 for double-click; default to 1 for other stuff.
153
+ [:screenX, options[:screenX] || 0], # TODO/fix - use screen_offset (or screen_center) when implemented/exists
154
+ [:screenY, options[:screenY] || 0],
155
+ [:clientX, options[:clientX] || client_center[0]], # by default, assume the mouse is at the center of the element
156
+ [:clientY, options[:clientY] || client_center[1]],
157
+ [:ctrlKey, false],
158
+ [:altKey, false],
159
+ [:shiftKey, false],
160
+ [:metaKey, false],
161
+ [:button, MouseButtonCodes[options[:button] || :left]],
162
+ [:relatedTarget, nil],
163
+ ]
164
+ #when 'abort', 'blur', 'change', 'error', 'focus', 'load', 'reset', 'resize', 'scroll', 'select', 'submit', 'unload'
165
+ else
166
+ dom_event_type = 'HTMLEvents'
167
+ init_event_func=:initEvent
168
+ init_event_args=
169
+ [ [:type, event_type],
170
+ [:bubbles, true],
171
+ [:cancelable, true],
172
+ ]
173
+ end
174
+ event=document_object.createEvent(dom_event_type)
175
+ event.invoke(init_event_func, *init_event_args.map{|arg| arg.last }) # calls to the init*Event method
176
+ return event
177
+ end
178
+ public
179
+
180
+ # Fires the click event on this element.
181
+ #
182
+ # Options:
183
+ # - :wait => true or false. If true, waits for the javascript call to return, and calls the #wait method.
184
+ # If false, does not wait for the javascript to return and does not call #wait.
185
+ # Default is true.
186
+ # - :highlight => true or false. Highlights the element while clicking if true. Default is true.
187
+ def click(options={})
188
+ options={:wait => true, :highlight => true}.merge(options)
189
+ result=nil
190
+ with_highlight(options) do
191
+ assert_enabled if respond_to?(:assert_enabled)
192
+ if options[:wait]
193
+ [:mousedown, :mouseup, :click].each do |event_type|
194
+ # javascript stuff responding to previous events can cause self to stop existing, so check at every subsequent step
195
+ if exists?
196
+ result=fire_event(event_type, options)
197
+ else
198
+ return result
199
+ end
200
+ end
201
+ wait
202
+ else
203
+ mouse_down_event=create_event_object('mousedown', options)
204
+ mouse_up_event=create_event_object('mouseup', options)
205
+ click_event=create_event_object('click', options)
206
+ click_func=jssh_socket.object("(function(element_object, mouse_down_event, mouse_up_event, click_event)
207
+ { return function()
208
+ { element_object.dispatchEvent(mouse_down_event);
209
+ element_object.dispatchEvent(mouse_up_event);
210
+ element_object.dispatchEvent(click_event);
211
+ };
212
+ })").pass(element_object, mouse_down_event, mouse_up_event, click_event)
213
+ content_window_object.setTimeout(click_func, 0)
214
+ end
215
+ end
216
+ result
217
+ end
218
+
219
+ # calls #click with :wait option false.
220
+ # Takes options:
221
+ # - :highlight => true or false. Highlights the element while clicking if true. Default is true.
222
+ def click_no_wait(options={})
223
+ click(options.merge(:wait => false))
224
+ end
225
+
226
+ # Waits for the browser to finish loading, if it is loading. See Firefox#wait.
227
+ def wait(options={})
228
+ @container.wait(options)
229
+ end
230
+
231
+ def self.element_object_style(element_object, document_object)
232
+ if element_object.nodeType==1 #element_object.instanceof(element_object.jssh_socket.Components.interfaces.nsIDOMDocument)
233
+ document_object.defaultView.getComputedStyle(element_object, nil)
234
+ else
235
+ nil
236
+ end
237
+ end
238
+
239
+ # Returns the text content of the element.
240
+ dom_attr :textContent => :text
241
+
242
+ private
243
+ def element_object_exists?
244
+ # parent=@element_object
245
+ # while true
246
+ # return false unless parent # if we encounter a parent such that parentNode is nil, we aren't on the document.
247
+ # return true if parent==document_object # if we encounter the document as a parent, we are on the document.
248
+ # new_parent=parent.parentNode
249
+ # raise(RuntimeError, "Circular reference in parents!") if new_parent==parent
250
+ # parent=new_parent
251
+ # end
252
+ # above is horrendously slow; optimized below.
253
+ return false unless @element_object
254
+ return jssh_socket.object("(function(parent, document_object)
255
+ { while(true)
256
+ { if(!parent)
257
+ { return false;
258
+ }
259
+ if(parent==document_object)
260
+ { return true;
261
+ }
262
+ parent=parent.parentNode;
263
+ }
264
+ })").call(@element_object, container.document_object) # use the container's document so that frames look at their parent document, not their own document
265
+ end
266
+
267
+ # def invoke(js_method)
268
+ # element_object.invoke(js_method)
269
+ # end
270
+
271
+ # def assign(property, value)
272
+ # locate
273
+ # element_object.attr(property).assign(value)
274
+ # end
275
+
276
+ end # Element
277
+ end # Vapir
@@ -0,0 +1,21 @@
1
+ require 'vapir-firefox/elements/input_element'
2
+ require 'vapir-common/elements/elements'
3
+
4
+ module Vapir
5
+ #
6
+ # Description:
7
+ # Class for Button element.
8
+ #
9
+ class Firefox::Button < Firefox::InputElement
10
+ include Vapir::Button
11
+
12
+ # locating should check both of these values if :caption is specified because, unlike IE,
13
+ # ff doesn't make the value of a button be its text content when there's no value.
14
+ # likewise, the #caption method should pick whatever's not blank.
15
+ dom_attr_locate_alias :value, :caption
16
+ dom_attr_locate_alias :textContent, :caption
17
+ def caption
18
+ value.empty? ? text : value
19
+ end
20
+ end # Button
21
+ end # Vapir
@@ -0,0 +1,27 @@
1
+ require 'vapir-firefox/elements/input_element'
2
+ require 'vapir-common/elements/elements'
3
+
4
+ module Vapir
5
+ #
6
+ # Description:
7
+ # Class for FileField element.
8
+ #
9
+ class Firefox::FileField < Firefox::InputElement
10
+ include Vapir::FileField
11
+
12
+ #
13
+ # Description:
14
+ # Sets the path of the file in the textbox.
15
+ #
16
+ # Input:
17
+ # path - Path of the file.
18
+ #
19
+ def set(path)
20
+ assert_exists do
21
+ element_object.value=path
22
+ fire_event("onChange")
23
+ end
24
+ end
25
+
26
+ end # FileField
27
+ end # Vapir
@@ -0,0 +1,8 @@
1
+ require 'vapir-firefox/element'
2
+ require 'vapir-common/elements/elements'
3
+
4
+ module Vapir
5
+ class Firefox::Form < Firefox::Element
6
+ include Vapir::Form
7
+ end # Form
8
+ end # Vapir
@@ -0,0 +1,23 @@
1
+ require 'vapir-firefox/element'
2
+ require 'vapir-common/elements/elements'
3
+ require 'vapir-firefox/page_container'
4
+
5
+ module Vapir
6
+ class Firefox::Frame < Firefox::Element
7
+ include Vapir::Frame
8
+ include Firefox::PageContainer
9
+
10
+ def document_object
11
+ unless @element_object
12
+ # don't use element_object because it does assert_exists, and don't assert_exists
13
+ # unless @element_object isn't defined at all, because element_object_exists? uses
14
+ # the document_object, so that would infinite loop.
15
+ locate!
16
+ end
17
+ @element_object.contentDocument # OR content_window_object.document
18
+ end
19
+ def content_window_object
20
+ element_object.contentWindow
21
+ end
22
+ end # Frame
23
+ end # Vapir
@@ -0,0 +1,12 @@
1
+ require 'vapir-firefox/elements/text_field'
2
+ require 'vapir-common/elements/elements'
3
+
4
+ module Vapir
5
+ #
6
+ # Description:
7
+ # Class for Hidden Field element.
8
+ #
9
+ class Firefox::Hidden < Firefox::TextField
10
+ include Vapir::Hidden
11
+ end # Hidden
12
+ end # Vapir
@@ -0,0 +1,38 @@
1
+ require 'vapir-firefox/element'
2
+ require 'vapir-common/elements/elements'
3
+
4
+ module Vapir
5
+ #
6
+ # Description:
7
+ # Class for Image element.
8
+ #
9
+ class Firefox::Image < Firefox::Element
10
+ include Vapir::Image
11
+
12
+ # this method returns the file created date of the image
13
+ #def file_created_date
14
+ # assert_exists
15
+ # return @o.invoke("fileCreatedDate")
16
+ #end
17
+ # alias fileCreatedDate file_created_date
18
+
19
+ # this method returns the filesize of the image
20
+ #def file_size
21
+ # assert_exists
22
+ # return @o.invoke("fileSize")
23
+ #end
24
+ # alias fileSize file_size
25
+
26
+ # This method attempts to find out if the image was actually loaded by the web browser.
27
+ # If the image was not loaded, the browser is unable to determine some of the properties.
28
+ # We look for these missing properties to see if the image is really there or not.
29
+ # If the Disk cache is full ( tools menu -> Internet options -> Temporary Internet Files) , it may produce incorrect responses.
30
+ #def has_loaded
31
+ # locate
32
+ # raise UnknownObjectException, "Unable to locate image using #{@how} and #{@what}" if @o == nil
33
+ # return false if @o.fileCreatedDate == "" and @o.fileSize.to_i == -1
34
+ # return true
35
+ #end
36
+ # alias hasLoaded? loaded?
37
+ end # Image
38
+ end # Vapir
@@ -0,0 +1,12 @@
1
+ require 'vapir-firefox/element'
2
+ require 'vapir-common/elements/elements'
3
+
4
+ module Vapir
5
+ #
6
+ # Description:
7
+ # Base class containing items that are common between select list, text field, button, hidden, file field classes.
8
+ #
9
+ class Firefox::InputElement < Firefox::Element
10
+ include Vapir::InputElement
11
+ end # Vapir
12
+ end # InputElement
@@ -0,0 +1,30 @@
1
+ require 'vapir-firefox/element'
2
+ require 'vapir-common/elements/elements'
3
+
4
+ module Vapir
5
+ #
6
+ # Description:
7
+ # Class for Link element.
8
+ #
9
+ class Firefox::Link < Firefox::Element
10
+ include Vapir::Link
11
+
12
+ #TODO: if an image is used as part of the link, this will return true
13
+ #def link_has_image
14
+ # assert_exists
15
+ # return true if @o.getElementsByTagName("IMG").length > 0
16
+ # return false
17
+ #end
18
+
19
+ #TODO: this method returns the src of an image, if an image is used as part of the link
20
+ #def src # BUG?
21
+ # assert_exists
22
+ # if @o.getElementsByTagName("IMG").length > 0
23
+ # return @o.getElementsByTagName("IMG")[0.to_s].src
24
+ # else
25
+ # return ""
26
+ # end
27
+ #end
28
+
29
+ end # Link
30
+ end # Vapir
@@ -0,0 +1,89 @@
1
+ require 'vapir-firefox/element'
2
+ require 'vapir-common/elements/elements'
3
+
4
+ module Vapir
5
+ class Firefox::Pre < Firefox::Element
6
+ include Vapir::Pre
7
+ end
8
+
9
+ class Firefox::P < Firefox::Element
10
+ include Vapir::P
11
+ end
12
+
13
+ class Firefox::Div < Firefox::Element
14
+ include Vapir::Div
15
+ end
16
+
17
+ class Firefox::Span < Firefox::Element
18
+ include Vapir::Span
19
+ end
20
+
21
+ class Firefox::Strong < Firefox::Element
22
+ include Vapir::Strong
23
+ end
24
+
25
+ class Firefox::Label < Firefox::Element
26
+ include Vapir::Label
27
+ end
28
+
29
+ class Firefox::Ul < Firefox::Element
30
+ include Vapir::Ul
31
+ end
32
+
33
+ class Firefox::Ol < Firefox::Element
34
+ include Vapir::Ol
35
+ end
36
+
37
+ class Firefox::Li < Firefox::Element
38
+ include Vapir::Li
39
+ end
40
+
41
+ class Firefox::Dl < Firefox::Element
42
+ include Vapir::Dl
43
+ end
44
+
45
+ class Firefox::Dt < Firefox::Element
46
+ include Vapir::Dt
47
+ end
48
+
49
+ class Firefox::Dd < Firefox::Element
50
+ include Vapir::Dd
51
+ end
52
+
53
+ class Firefox::H1 < Firefox::Element
54
+ include Vapir::H1
55
+ end
56
+
57
+ class Firefox::H2 < Firefox::Element
58
+ include Vapir::H2
59
+ end
60
+
61
+ class Firefox::H3 < Firefox::Element
62
+ include Vapir::H3
63
+ end
64
+
65
+ class Firefox::H4 < Firefox::Element
66
+ include Vapir::H4
67
+ end
68
+
69
+ class Firefox::H5 < Firefox::Element
70
+ include Vapir::H5
71
+ end
72
+
73
+ class Firefox::H6 < Firefox::Element
74
+ include Vapir::H6
75
+ end
76
+
77
+ class Firefox::Map < Firefox::Element
78
+ include Vapir::Map
79
+ end
80
+
81
+ class Firefox::Area < Firefox::Element
82
+ include Vapir::Area
83
+ end
84
+
85
+ class Firefox::Em < Firefox::Element
86
+ include Vapir::Em
87
+ end
88
+
89
+ end # Vapir
@@ -0,0 +1,12 @@
1
+ require 'vapir-firefox/element'
2
+ require 'vapir-common/elements/elements'
3
+
4
+ module Vapir
5
+ #
6
+ # Description:
7
+ # Class for Option element.
8
+ #
9
+ class Firefox::Option < Firefox::Element
10
+ include Vapir::Option
11
+ end # Option
12
+ end # Vapir
@@ -0,0 +1,36 @@
1
+ require 'vapir-firefox/elements/input_element'
2
+ require 'vapir-common/elements/elements'
3
+
4
+ module Vapir
5
+ module Firefox::RadioCheckboxCommon
6
+ private
7
+ # radios in firefox seem to be totally unresponsive to css color and border, but
8
+ # they can change size, so use that for the highlight method.
9
+ # see http://www.456bereastreet.com/lab/styling-form-controls-revisited/radio-button/
10
+ def set_highlight(options={})
11
+ assert_exists do
12
+ @original_height=element_object.offsetHeight
13
+ @original_width=element_object.offsetWidth
14
+ element_object.style.height=@original_height+3
15
+ element_object.style.width=@original_width+3
16
+ end
17
+ end
18
+ def clear_highlight(options={})
19
+ element_object.style.height=@original_height
20
+ element_object.style.width=@original_width
21
+ end
22
+ end
23
+ class Firefox::Radio < Firefox::InputElement
24
+ include Vapir::Radio
25
+ include Firefox::RadioCheckboxCommon
26
+ end # Radio
27
+
28
+ #
29
+ # Description:
30
+ # Class for Checkbox element.
31
+ #
32
+ class Firefox::CheckBox < Firefox::InputElement
33
+ include Vapir::CheckBox
34
+ include Firefox::RadioCheckboxCommon
35
+ end # CheckBox
36
+ end # Vapir
@@ -0,0 +1,12 @@
1
+ require 'vapir-firefox/elements/input_element'
2
+ require 'vapir-common/elements/elements'
3
+
4
+ module Vapir
5
+ #
6
+ # Description:
7
+ # Class for SelectList element.
8
+ #
9
+ class Firefox::SelectList < Firefox::InputElement
10
+ include Vapir::SelectList
11
+ end # SelectList
12
+ end # Vapir
@@ -0,0 +1,16 @@
1
+ require 'vapir-firefox/element'
2
+ require 'vapir-common/elements/elements'
3
+
4
+ module Vapir
5
+ class Firefox::Table < Firefox::Element
6
+ include Vapir::Table
7
+
8
+ def self.create_from_element(container, element)
9
+ Vapir::Table.create_from_element(container, element)
10
+ end
11
+ end # Table
12
+
13
+ class Firefox::TBody < Firefox::Element
14
+ include Vapir::TBody
15
+ end
16
+ end # Vapir
@@ -0,0 +1,12 @@
1
+ require 'vapir-firefox/element'
2
+ require 'vapir-common/elements/elements'
3
+
4
+ module Vapir
5
+ #
6
+ # Description:
7
+ # Class for Table Cell.
8
+ #
9
+ class Firefox::TableCell < Firefox::Element
10
+ include Vapir::TableCell
11
+ end # TableCell
12
+ end # Vapir
@@ -0,0 +1,12 @@
1
+ require 'vapir-firefox/element'
2
+ require 'vapir-common/elements/elements'
3
+
4
+ module Vapir
5
+ #
6
+ # Description:
7
+ # Class for Table row element.
8
+ #
9
+ class Firefox::TableRow < Firefox::Element
10
+ include Vapir::TableRow
11
+ end # TableRow
12
+ end # Vapir