mpeychich-safariwatir 0.3.6
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.
- data/README.rdoc +49 -0
- data/Rakefile +13 -0
- data/lib/safariwatir.rb +541 -0
- data/lib/safariwatir/core_ext.rb +31 -0
- data/lib/safariwatir/scripter.rb +587 -0
- data/lib/watir/exceptions.rb +42 -0
- data/safariwatir.gemspec +31 -0
- data/safariwatir_example.rb +151 -0
- metadata +75 -0
@@ -0,0 +1,31 @@
|
|
1
|
+
# Why shouldn't this be in core Ruby?
|
2
|
+
class Class
|
3
|
+
def def_init(*attrs)
|
4
|
+
constructor = %|def initialize(|
|
5
|
+
constructor << attrs.map{|a| a.to_s }.join(",")
|
6
|
+
constructor << ")\n"
|
7
|
+
attrs.each do |attribute|
|
8
|
+
constructor << "@#{attribute} = #{attribute}\n"
|
9
|
+
end
|
10
|
+
constructor << "end"
|
11
|
+
class_eval(constructor)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class String
|
16
|
+
def quote_safe
|
17
|
+
gsub(/"/, '\"')
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class Object
|
22
|
+
def blank?
|
23
|
+
if respond_to?(:strip)
|
24
|
+
strip.empty?
|
25
|
+
elsif respond_to?(:empty?)
|
26
|
+
empty?
|
27
|
+
else
|
28
|
+
!self
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,587 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/core_ext'
|
2
|
+
require File.dirname(__FILE__) + '/../watir/exceptions'
|
3
|
+
require 'appscript'
|
4
|
+
|
5
|
+
module Watir # :nodoc:
|
6
|
+
ELEMENT_NOT_FOUND = "__safari_watir_element_unfound__"
|
7
|
+
FRAME_NOT_FOUND = "__safari_watir_frame_unfound__"
|
8
|
+
NO_RESPONSE = "__safari_watir_no_response__"
|
9
|
+
TABLE_CELL_NOT_FOUND = "__safari_watir_cell_unfound__"
|
10
|
+
EXTRA_ACTION_SUCCESS = "__safari_watir_extra_action__"
|
11
|
+
|
12
|
+
JS_LIBRARY = %|
|
13
|
+
function dispatchOnChange(element) {
|
14
|
+
var event = document.createEvent('HTMLEvents');
|
15
|
+
event.initEvent('change', true, true);
|
16
|
+
element.dispatchEvent(event);
|
17
|
+
}|
|
18
|
+
|
19
|
+
class JavaScripter # :nodoc:
|
20
|
+
def operate(locator, operation)
|
21
|
+
%|#{locator}
|
22
|
+
if (element) {
|
23
|
+
#{operation}
|
24
|
+
} else {
|
25
|
+
return '#{ELEMENT_NOT_FOUND}';
|
26
|
+
}|
|
27
|
+
end
|
28
|
+
|
29
|
+
def wrap(script)
|
30
|
+
# Needed because createEvent must be called on a document, and the JavaScripter sub-classes
|
31
|
+
# do some transformations to lower-case "document" before we get here at runtime.
|
32
|
+
script.gsub! "DOCUMENT", "document"
|
33
|
+
|
34
|
+
# Needed because I would like to blindly use return statements, but Safari 3 enforces
|
35
|
+
# the ECMAScript standard that return statements are only valid within functions.
|
36
|
+
%|#{JS_LIBRARY}
|
37
|
+
(function() {
|
38
|
+
#{script}
|
39
|
+
})()|
|
40
|
+
end
|
41
|
+
|
42
|
+
def find_cell(cell)
|
43
|
+
return %|getElementById('#{cell.what}')| if cell.how == :id
|
44
|
+
raise RuntimeError, "Unable to use #{cell.how} to find TableCell" unless cell.row
|
45
|
+
|
46
|
+
finder =
|
47
|
+
case cell.row.how
|
48
|
+
when :id:
|
49
|
+
%|getElementById('#{cell.row.what}')|
|
50
|
+
when :index:
|
51
|
+
case cell.row.table.how
|
52
|
+
when :id
|
53
|
+
%|getElementById('#{cell.row.table.what}').rows[#{cell.row.what-1}]|
|
54
|
+
when :index:
|
55
|
+
%|getElementsByTagName('TABLE')[#{cell.row.table.what-1}].rows[#{cell.row.what-1}]|
|
56
|
+
else
|
57
|
+
raise MissingWayOfFindingObjectException, "Table element does not support #{cell.row.table.how}"
|
58
|
+
end
|
59
|
+
else
|
60
|
+
raise MissingWayOfFindingObjectException, "TableRow element does not support #{cell.row.how}"
|
61
|
+
end
|
62
|
+
|
63
|
+
finder + %|.cells[#{cell.what-1}]|
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
class FrameJavaScripter < JavaScripter # :nodoc:
|
68
|
+
def initialize(frame)
|
69
|
+
@page_container = "parent.#{frame.name}"
|
70
|
+
end
|
71
|
+
|
72
|
+
def wrap(script)
|
73
|
+
# add in frame name when referencing parent or document
|
74
|
+
script.gsub! "parent", "parent.#{@page_container}"
|
75
|
+
script.gsub! "document", "#{@page_container}.document"
|
76
|
+
super(script)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
class TableJavaScripter < JavaScripter # :nodoc:
|
81
|
+
def_init :cell
|
82
|
+
|
83
|
+
def wrap(script)
|
84
|
+
script.gsub! "document", "document." + find_cell(@cell)
|
85
|
+
super(script)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
class AppleScripter # :nodoc:
|
90
|
+
include Watir::Exception
|
91
|
+
|
92
|
+
attr_reader :js
|
93
|
+
attr_accessor :typing_lag
|
94
|
+
private :js
|
95
|
+
|
96
|
+
TIMEOUT = 10
|
97
|
+
|
98
|
+
def initialize(scripter = JavaScripter.new, opts={})
|
99
|
+
@js = scripter
|
100
|
+
@appname = opts[:appname] || "Safari"
|
101
|
+
@app = Appscript.app(@appname)
|
102
|
+
@document = @app.documents[1]
|
103
|
+
end
|
104
|
+
|
105
|
+
def ensure_window_ready
|
106
|
+
@app.activate
|
107
|
+
@app.make(:new => :document) if @app.documents.get.size == 0
|
108
|
+
@document = @app.documents[1]
|
109
|
+
end
|
110
|
+
|
111
|
+
def url
|
112
|
+
@document.URL.get
|
113
|
+
end
|
114
|
+
|
115
|
+
def hide
|
116
|
+
# because applescript is stupid and annoying you have
|
117
|
+
# to get all the processes from System Events, grab
|
118
|
+
# the right one for this instance and then set visible
|
119
|
+
# of it to false.
|
120
|
+
se = Appscript.app("System Events")
|
121
|
+
safari = se.processes.get.select do |app|
|
122
|
+
app.name.get == @appname
|
123
|
+
end.first
|
124
|
+
safari.visible.set(false)
|
125
|
+
end
|
126
|
+
|
127
|
+
def close
|
128
|
+
@app.quit
|
129
|
+
end
|
130
|
+
|
131
|
+
def navigate_to(url, &extra_action)
|
132
|
+
page_load(extra_action) do
|
133
|
+
@document.URL.set(url)
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def reload
|
138
|
+
execute(%|window.location.reload()|)
|
139
|
+
end
|
140
|
+
|
141
|
+
def get_text_for(element = @element)
|
142
|
+
execute(element.operate { %|return element.innerText| }, element)
|
143
|
+
end
|
144
|
+
|
145
|
+
def get_html_for(element = @element)
|
146
|
+
execute(element.operate { %|return element.innerHTML| }, element)
|
147
|
+
end
|
148
|
+
|
149
|
+
def operate_by_table_cell(element = @element)
|
150
|
+
%|var element = document;
|
151
|
+
if (element == undefined) {
|
152
|
+
return '#{TABLE_CELL_NOT_FOUND}';
|
153
|
+
}
|
154
|
+
#{yield}|
|
155
|
+
end
|
156
|
+
|
157
|
+
def get_value_for(element = @element)
|
158
|
+
execute(element.operate { %|return element.value;| }, element)
|
159
|
+
end
|
160
|
+
|
161
|
+
def document_text
|
162
|
+
execute(%|return document.getElementsByTagName('BODY').item(0).innerText;|)
|
163
|
+
end
|
164
|
+
|
165
|
+
def document_html
|
166
|
+
execute(%|return document.all[0].outerHTML;|)
|
167
|
+
end
|
168
|
+
|
169
|
+
def document_title
|
170
|
+
execute(%|return document.title;|)
|
171
|
+
end
|
172
|
+
|
173
|
+
def focus(element)
|
174
|
+
execute(element.operate { %|element.focus();| }, element)
|
175
|
+
end
|
176
|
+
|
177
|
+
def blur(element)
|
178
|
+
execute(element.operate { %|element.blur();| }, element)
|
179
|
+
end
|
180
|
+
|
181
|
+
def highlight(element, &block)
|
182
|
+
execute(element.operate do
|
183
|
+
%|element.originalColor = element.style.backgroundColor;
|
184
|
+
element.style.backgroundColor = 'yellow';|
|
185
|
+
end, element)
|
186
|
+
|
187
|
+
@element = element
|
188
|
+
instance_eval(&block)
|
189
|
+
@element = nil
|
190
|
+
|
191
|
+
execute_and_ignore(element.operate { %|element.style.backgroundColor = element.originalColor;| })
|
192
|
+
end
|
193
|
+
|
194
|
+
def element_exists?(element = @element, &block)
|
195
|
+
block ||= Proc.new {}
|
196
|
+
execute(element.operate(&block), element)
|
197
|
+
return true
|
198
|
+
rescue UnknownObjectException
|
199
|
+
return false
|
200
|
+
end
|
201
|
+
|
202
|
+
def select_option(element = @element)
|
203
|
+
execute(element.operate do
|
204
|
+
%|var selected = -1;
|
205
|
+
var previous_selection = 0;
|
206
|
+
for (var i = 0; i < element.options.length; i++) {
|
207
|
+
if (element.options[i].selected) {
|
208
|
+
previous_selection = i;
|
209
|
+
}
|
210
|
+
if (element.options[i].#{element.how} == '#{element.what}') {
|
211
|
+
element.options[i].selected = true;
|
212
|
+
selected = i;
|
213
|
+
}
|
214
|
+
}
|
215
|
+
if (selected == -1) {
|
216
|
+
return '#{ELEMENT_NOT_FOUND}';
|
217
|
+
} else if (previous_selection != selected) {
|
218
|
+
element.selectedIndex = selected;
|
219
|
+
dispatchOnChange(element.options[selected]);
|
220
|
+
}
|
221
|
+
|
|
222
|
+
end, element)
|
223
|
+
end
|
224
|
+
|
225
|
+
def option_exists?(element = @element)
|
226
|
+
element_exists?(element) { handle_option(element) }
|
227
|
+
end
|
228
|
+
|
229
|
+
def handle_option(select_list)
|
230
|
+
%|var option_found = false;
|
231
|
+
for (var i = 0; i < element.options.length; i++) {
|
232
|
+
if (element.options[i].#{select_list.how} == '#{select_list.what}') {
|
233
|
+
option_found = true;
|
234
|
+
}
|
235
|
+
}
|
236
|
+
if (!option_found) {
|
237
|
+
return '#{ELEMENT_NOT_FOUND}';
|
238
|
+
}|
|
239
|
+
end
|
240
|
+
private :handle_option
|
241
|
+
|
242
|
+
def option_selected?(element = @element)
|
243
|
+
element_exists?(element) { handle_selected(element) == "true" }
|
244
|
+
end
|
245
|
+
|
246
|
+
def handle_selected(select_list)
|
247
|
+
%|var selected = false;
|
248
|
+
for (var i = 0; i < element.options.length; i++) {
|
249
|
+
if (element.options[i].#{select_list.how} == '#{select_list.what}' && element.options[i].selected) {
|
250
|
+
selected = true;
|
251
|
+
}
|
252
|
+
}
|
253
|
+
return selected;|
|
254
|
+
end
|
255
|
+
private :handle_option
|
256
|
+
|
257
|
+
def clear_text_input(element = @element)
|
258
|
+
execute(element.operate { %|element.value = '';| }, element)
|
259
|
+
end
|
260
|
+
|
261
|
+
def append_text_input(value, element = @element)
|
262
|
+
sleep typing_lag
|
263
|
+
execute(element.operate do
|
264
|
+
%|element.value += '#{value}';
|
265
|
+
dispatchOnChange(element);
|
266
|
+
element.setSelectionRange(element.value.length, element.value.length);|
|
267
|
+
end, element)
|
268
|
+
end
|
269
|
+
|
270
|
+
def click_element(element = @element)
|
271
|
+
page_load do
|
272
|
+
# Not sure if these events should be either/or. But if you have an image with an onclick, it fires twice without the else clause.
|
273
|
+
execute(element.operate { %|
|
274
|
+
if (element.click) {
|
275
|
+
element.click();
|
276
|
+
} else {
|
277
|
+
if (element.onclick) {
|
278
|
+
var event = DOCUMENT.createEvent('HTMLEvents');
|
279
|
+
event.initEvent('click', true, true);
|
280
|
+
element.onclick(event);
|
281
|
+
} else {
|
282
|
+
var event = DOCUMENT.createEvent('MouseEvents');
|
283
|
+
event.initEvent('click', true, true);
|
284
|
+
element.dispatchEvent(event);
|
285
|
+
}
|
286
|
+
|
287
|
+
}| })
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
291
|
+
def click_link(element = @element)
|
292
|
+
click = %/
|
293
|
+
function baseTarget() {
|
294
|
+
var bases = document.getElementsByTagName('BASE');
|
295
|
+
if (bases.length > 0) {
|
296
|
+
return bases[0].target;
|
297
|
+
} else {
|
298
|
+
return;
|
299
|
+
}
|
300
|
+
}
|
301
|
+
function undefinedTarget(target) {
|
302
|
+
return target == undefined || target == '';
|
303
|
+
}
|
304
|
+
function topTarget(target) {
|
305
|
+
return undefinedTarget(target) || target == '_top';
|
306
|
+
}
|
307
|
+
function nextLocation(element) {
|
308
|
+
var target = element.target;
|
309
|
+
if (undefinedTarget(target) && baseTarget()) {
|
310
|
+
top[baseTarget()].location = element.href;
|
311
|
+
} else if (topTarget(target)) {
|
312
|
+
top.location = element.href;
|
313
|
+
} else {
|
314
|
+
top[target].location = element.href;
|
315
|
+
}
|
316
|
+
}
|
317
|
+
var click = DOCUMENT.createEvent('HTMLEvents');
|
318
|
+
click.initEvent('click', true, true);
|
319
|
+
if (element.onclick) {
|
320
|
+
if (false != element.onclick(click)) {
|
321
|
+
nextLocation(element);
|
322
|
+
}
|
323
|
+
} else {
|
324
|
+
nextLocation(element);
|
325
|
+
}/
|
326
|
+
page_load do
|
327
|
+
execute(js.operate(find_link(element), click))
|
328
|
+
end
|
329
|
+
end
|
330
|
+
|
331
|
+
def operate_on_link(element)
|
332
|
+
js.operate(find_link(element), yield)
|
333
|
+
end
|
334
|
+
|
335
|
+
def find_link(element)
|
336
|
+
case element.how
|
337
|
+
when :index:
|
338
|
+
%|var element = document.getElementsByTagName('A')[#{element.what-1}];|
|
339
|
+
else
|
340
|
+
%|var element = undefined;
|
341
|
+
for (var i = 0; i < document.links.length; i++) {
|
342
|
+
if (document.links[i].#{handle_match(element)}) {
|
343
|
+
element = document.links[i];
|
344
|
+
break;
|
345
|
+
}
|
346
|
+
}|
|
347
|
+
end
|
348
|
+
end
|
349
|
+
private :find_link
|
350
|
+
|
351
|
+
def handle_match(element, how = nil)
|
352
|
+
how = {:text => "text", :url => "href"}[element.how] unless how
|
353
|
+
case element.what
|
354
|
+
when Regexp:
|
355
|
+
%|#{how}.match(/#{element.what.source}/#{element.what.casefold? ? "i":nil})|
|
356
|
+
when String || Symbol:
|
357
|
+
%|#{how} == '#{element.what}'|
|
358
|
+
else
|
359
|
+
raise RuntimeError, "Unable to locate #{element.tag} with #{element.how}"
|
360
|
+
end
|
361
|
+
end
|
362
|
+
private :handle_match
|
363
|
+
|
364
|
+
# Contributed by Kyle Campos
|
365
|
+
def checkbox_is_checked?(element = @element)
|
366
|
+
execute(element.operate { %|return element.checked;| }, element)
|
367
|
+
end
|
368
|
+
|
369
|
+
def element_disabled?(element = @element)
|
370
|
+
execute(element.operate { %|return element.disabled;| }, element)
|
371
|
+
end
|
372
|
+
|
373
|
+
def operate_by_input_value(element)
|
374
|
+
js.operate(%|
|
375
|
+
var elements = document.getElementsByTagName('INPUT');
|
376
|
+
var element = undefined;
|
377
|
+
for (var i = 0; i < elements.length; i++) {
|
378
|
+
if (elements[i].value == '#{element.what}') {
|
379
|
+
element = elements[i];
|
380
|
+
break;
|
381
|
+
}
|
382
|
+
}|, yield)
|
383
|
+
end
|
384
|
+
|
385
|
+
def operate_by_name(element)
|
386
|
+
js.operate(%|
|
387
|
+
var elements = document.getElementsByName('#{element.what}');
|
388
|
+
var element = undefined;
|
389
|
+
for (var i = 0; i < elements.length; i++) {
|
390
|
+
if (elements[i].tagName != 'META' && elements[i].tagName == '#{element.tag}') {
|
391
|
+
#{handle_form_element_name_match(element)}
|
392
|
+
}
|
393
|
+
}|, yield)
|
394
|
+
end
|
395
|
+
|
396
|
+
def operate_by_class(element, &block)
|
397
|
+
operate_by(element, 'className', &block)
|
398
|
+
end
|
399
|
+
|
400
|
+
# Checkboxes/Radios have the same name, different values
|
401
|
+
def handle_form_element_name_match(element)
|
402
|
+
element_capture = %|element = elements[i];break;|
|
403
|
+
if element.by_value
|
404
|
+
%|if (elements[i].value == '#{element.by_value}') {
|
405
|
+
#{element_capture}
|
406
|
+
}|
|
407
|
+
else
|
408
|
+
element_capture
|
409
|
+
end
|
410
|
+
end
|
411
|
+
private :handle_form_element_name_match
|
412
|
+
|
413
|
+
def operate_by_id(element, &block)
|
414
|
+
operate_by(element, 'id', &block)
|
415
|
+
end
|
416
|
+
|
417
|
+
def operate_by_index(element)
|
418
|
+
js.operate(%|var element = document.getElementsByTagName('#{element.tag}')[#{element.what-1}];|, yield)
|
419
|
+
end
|
420
|
+
|
421
|
+
def operate_by_src(element, &block)
|
422
|
+
operate_by(element, 'src', &block)
|
423
|
+
end
|
424
|
+
|
425
|
+
def operate_by_text(element, &block)
|
426
|
+
operate_by(element, 'innerText', &block)
|
427
|
+
end
|
428
|
+
|
429
|
+
def operate_by(element, attribute)
|
430
|
+
js.operate(%|var elements = document.getElementsByTagName('#{element.tag}');
|
431
|
+
var element = undefined;
|
432
|
+
for (var i = 0; i < elements.length; i++) {
|
433
|
+
if (elements[i].#{handle_match(element, attribute)}) {
|
434
|
+
element = elements[i];
|
435
|
+
break;
|
436
|
+
}
|
437
|
+
}|, yield)
|
438
|
+
end
|
439
|
+
|
440
|
+
def submit_form(element)
|
441
|
+
page_load do
|
442
|
+
execute(element.operate { %|element.submit();| })
|
443
|
+
end
|
444
|
+
end
|
445
|
+
|
446
|
+
def click_alert
|
447
|
+
execute_system_events(%|
|
448
|
+
tell window 1
|
449
|
+
if button named "OK" exists then
|
450
|
+
click button named "OK"
|
451
|
+
end if
|
452
|
+
end tell|)
|
453
|
+
end
|
454
|
+
|
455
|
+
def click_security_warning(label)
|
456
|
+
execute_system_events(%|
|
457
|
+
tell window 1
|
458
|
+
tell sheet 1
|
459
|
+
tell group 2
|
460
|
+
if button named "#{label}" exists then
|
461
|
+
click button named "#{label}"
|
462
|
+
return "#{EXTRA_ACTION_SUCCESS}"
|
463
|
+
end if
|
464
|
+
end tell
|
465
|
+
end tell
|
466
|
+
end tell|, true)
|
467
|
+
end
|
468
|
+
|
469
|
+
def for_table(element)
|
470
|
+
AppleScripter.new(TableJavaScripter.new(element))
|
471
|
+
end
|
472
|
+
|
473
|
+
def for_frame(element)
|
474
|
+
# verify the frame exists
|
475
|
+
execute(
|
476
|
+
%|if (parent.#{element.name} == undefined) {
|
477
|
+
return '#{FRAME_NOT_FOUND}';
|
478
|
+
}|, element)
|
479
|
+
AppleScripter.new(FrameJavaScripter.new(element))
|
480
|
+
end
|
481
|
+
|
482
|
+
def speak_value_of(element = @element)
|
483
|
+
speak(get_value_for(element))
|
484
|
+
end
|
485
|
+
|
486
|
+
def speak_text_of(element = @element)
|
487
|
+
speak(element.text)
|
488
|
+
end
|
489
|
+
|
490
|
+
def speak_options_for(element = @element)
|
491
|
+
values = execute(element.operate do
|
492
|
+
%|var values = '';
|
493
|
+
for (var i = 0; i < element.options.length; i++) {
|
494
|
+
if (element.options[i].selected == true) {
|
495
|
+
values += ' ' + element.options[i].text;
|
496
|
+
}
|
497
|
+
}
|
498
|
+
return values|
|
499
|
+
end, element)
|
500
|
+
speak(values)
|
501
|
+
end
|
502
|
+
|
503
|
+
def speak(string)
|
504
|
+
`osascript <<SCRIPT
|
505
|
+
say "#{string.quote_safe}"
|
506
|
+
SCRIPT`
|
507
|
+
nil
|
508
|
+
end
|
509
|
+
|
510
|
+
|
511
|
+
private
|
512
|
+
|
513
|
+
def execute(script, element = nil)
|
514
|
+
response = eval_js(script)
|
515
|
+
case response
|
516
|
+
when NO_RESPONSE:
|
517
|
+
nil
|
518
|
+
when ELEMENT_NOT_FOUND:
|
519
|
+
raise UnknownObjectException, "Unable to locate #{element.tag} element with #{element.how} of #{element.what}"
|
520
|
+
when TABLE_CELL_NOT_FOUND:
|
521
|
+
raise UnknownCellException, "Unable to locate a table cell with #{element.how} of #{element.what}"
|
522
|
+
when FRAME_NOT_FOUND:
|
523
|
+
raise UnknownFrameException, "Unable to locate a frame with name #{element.tag}"
|
524
|
+
else
|
525
|
+
response
|
526
|
+
end
|
527
|
+
end
|
528
|
+
|
529
|
+
def execute_and_ignore(script)
|
530
|
+
eval_js(script)
|
531
|
+
nil
|
532
|
+
end
|
533
|
+
|
534
|
+
# Must have "Enable access for assistive devices" checked in System Preferences > Universal Access
|
535
|
+
def execute_system_events(script, capture_result = false)
|
536
|
+
result = `osascript <<SCRIPT
|
537
|
+
tell application "System Events" to tell process "Safari"
|
538
|
+
#{script}
|
539
|
+
end tell
|
540
|
+
SCRIPT`
|
541
|
+
|
542
|
+
if capture_result && result
|
543
|
+
return result.chomp
|
544
|
+
end
|
545
|
+
end
|
546
|
+
|
547
|
+
def page_load(extra_action = nil)
|
548
|
+
yield
|
549
|
+
sleep 1
|
550
|
+
|
551
|
+
tries = 0
|
552
|
+
TIMEOUT.times do |tries|
|
553
|
+
if "complete" == eval_js("return DOCUMENT.readyState") && !@document.URL.get.blank?
|
554
|
+
sleep 0.4
|
555
|
+
handle_client_redirect
|
556
|
+
break
|
557
|
+
elsif extra_action
|
558
|
+
result = extra_action.call
|
559
|
+
break if result == EXTRA_ACTION_SUCCESS
|
560
|
+
else
|
561
|
+
sleep 1
|
562
|
+
end
|
563
|
+
end
|
564
|
+
raise "Unable to load page within #{TIMEOUT} seconds" if tries == TIMEOUT-1
|
565
|
+
end
|
566
|
+
|
567
|
+
def handle_client_redirect
|
568
|
+
no_redirect_flag = "proceed"
|
569
|
+
redirect = eval_js(
|
570
|
+
%|var elements = DOCUMENT.getElementsByTagName('META');
|
571
|
+
for (var i = 0; i < elements.length; i++) {
|
572
|
+
if ("refresh" == elements[i].httpEquiv && elements[i].content != undefined && elements[i].content.indexOf(";") != "-1") {
|
573
|
+
return elements[i].content;
|
574
|
+
}
|
575
|
+
}
|
576
|
+
return "#{no_redirect_flag}"|)
|
577
|
+
if redirect != no_redirect_flag
|
578
|
+
time_til_redirect = redirect.split(";").first.to_i
|
579
|
+
sleep time_til_redirect
|
580
|
+
end
|
581
|
+
end
|
582
|
+
|
583
|
+
def eval_js(script)
|
584
|
+
@app.do_JavaScript(js.wrap(script), :in => @document)
|
585
|
+
end
|
586
|
+
end # class AppleScripter
|
587
|
+
end
|