capybara 3.19.1 → 3.20.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/History.md +18 -0
- data/README.md +1 -1
- data/lib/capybara/driver/node.rb +4 -0
- data/lib/capybara/node/actions.rb +3 -2
- data/lib/capybara/node/element.rb +11 -0
- data/lib/capybara/node/finders.rb +4 -1
- data/lib/capybara/queries/selector_query.rb +19 -5
- data/lib/capybara/selector.rb +2 -2
- data/lib/capybara/selector/definition/label.rb +27 -10
- data/lib/capybara/selector/definition/link.rb +3 -2
- data/lib/capybara/selenium/atoms/getAttribute.min.js +1 -0
- data/lib/capybara/selenium/atoms/isDisplayed.min.js +1 -0
- data/lib/capybara/selenium/atoms/src/getAttribute.js +161 -0
- data/lib/capybara/selenium/atoms/src/isDisplayed.js +454 -0
- data/lib/capybara/selenium/driver.rb +14 -1
- data/lib/capybara/selenium/driver_specializations/firefox_driver.rb +1 -1
- data/lib/capybara/selenium/driver_specializations/internet_explorer_driver.rb +1 -1
- data/lib/capybara/selenium/driver_specializations/safari_driver.rb +1 -1
- data/lib/capybara/selenium/node.rb +25 -1
- data/lib/capybara/selenium/nodes/safari_node.rb +19 -6
- data/lib/capybara/selenium/patches/atoms.rb +18 -0
- data/lib/capybara/spec/session/all_spec.rb +23 -0
- data/lib/capybara/spec/session/click_link_spec.rb +11 -0
- data/lib/capybara/spec/session/node_spec.rb +78 -5
- data/lib/capybara/spec/session/selectors_spec.rb +8 -0
- data/lib/capybara/spec/views/animated.erb +49 -0
- data/lib/capybara/spec/views/frame_one.erb +1 -0
- data/lib/capybara/spec/views/obscured.erb +9 -9
- data/lib/capybara/version.rb +1 -1
- data/spec/sauce_spec_chrome.rb +1 -0
- data/spec/selenium_spec_chrome.rb +4 -2
- data/spec/selenium_spec_chrome_remote.rb +4 -2
- data/spec/selenium_spec_edge.rb +4 -2
- data/spec/selenium_spec_firefox.rb +4 -11
- data/spec/selenium_spec_firefox_remote.rb +4 -2
- data/spec/selenium_spec_ie.rb +5 -6
- data/spec/selenium_spec_safari.rb +7 -12
- data/spec/server_spec.rb +4 -2
- data/spec/shared_selenium_node.rb +29 -0
- metadata +23 -2
@@ -18,6 +18,7 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
|
|
18
18
|
def load_selenium
|
19
19
|
require 'selenium-webdriver'
|
20
20
|
require 'capybara/selenium/logger_suppressor'
|
21
|
+
require 'capybara/selenium/patches/atoms'
|
21
22
|
warn "Warning: You're using an unsupported version of selenium-webdriver, please upgrade." if Gem.loaded_specs['selenium-webdriver'].version < Gem::Version.new('3.5.0')
|
22
23
|
rescue LoadError => e
|
23
24
|
raise e unless e.message.match?(/selenium-webdriver/)
|
@@ -135,6 +136,18 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
|
|
135
136
|
end
|
136
137
|
end
|
137
138
|
|
139
|
+
def frame_obscured_at?(x:, y:)
|
140
|
+
frame = @frame_handles[current_window_handle].last
|
141
|
+
return false unless frame
|
142
|
+
|
143
|
+
switch_to_frame(:parent)
|
144
|
+
begin
|
145
|
+
return frame.base.obscured?(x: x, y: y)
|
146
|
+
ensure
|
147
|
+
switch_to_frame(frame)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
138
151
|
def switch_to_frame(frame)
|
139
152
|
handles = @frame_handles[current_window_handle]
|
140
153
|
case frame
|
@@ -145,7 +158,7 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
|
|
145
158
|
handles.pop
|
146
159
|
browser.switch_to.parent_frame
|
147
160
|
else
|
148
|
-
handles << frame
|
161
|
+
handles << frame
|
149
162
|
browser.switch_to.frame(frame.native)
|
150
163
|
end
|
151
164
|
end
|
@@ -60,7 +60,7 @@ module Capybara::Selenium::Driver::W3CFirefoxDriver
|
|
60
60
|
# so we have to move to the default_content and iterate back through the frames
|
61
61
|
handles = @frame_handles[current_window_handle]
|
62
62
|
browser.switch_to.default_content
|
63
|
-
handles.tap(&:pop).each { |fh| browser.switch_to.frame(fh) }
|
63
|
+
handles.tap(&:pop).each { |fh| browser.switch_to.frame(fh.native) }
|
64
64
|
end
|
65
65
|
|
66
66
|
private
|
@@ -10,7 +10,7 @@ module Capybara::Selenium::Driver::InternetExplorerDriver
|
|
10
10
|
# so we have to move to the default_content and iterate back through the frames
|
11
11
|
handles = @frame_handles[current_window_handle]
|
12
12
|
browser.switch_to.default_content
|
13
|
-
handles.tap(&:pop).each { |fh| browser.switch_to.frame(fh) }
|
13
|
+
handles.tap(&:pop).each { |fh| browser.switch_to.frame(fh.native) }
|
14
14
|
end
|
15
15
|
|
16
16
|
private
|
@@ -10,7 +10,7 @@ module Capybara::Selenium::Driver::SafariDriver
|
|
10
10
|
# behaves like switch_to_frame(:top)
|
11
11
|
handles = @frame_handles[current_window_handle]
|
12
12
|
browser.switch_to.default_content
|
13
|
-
handles.tap(&:pop).each { |fh| browser.switch_to.frame(fh) }
|
13
|
+
handles.tap(&:pop).each { |fh| browser.switch_to.frame(fh.native) }
|
14
14
|
end
|
15
15
|
|
16
16
|
private
|
@@ -155,7 +155,7 @@ class Capybara::Selenium::Node < Capybara::Driver::Node
|
|
155
155
|
end
|
156
156
|
|
157
157
|
def content_editable?
|
158
|
-
native.attribute('isContentEditable')
|
158
|
+
native.attribute('isContentEditable') == 'true'
|
159
159
|
end
|
160
160
|
|
161
161
|
def ==(other)
|
@@ -166,6 +166,13 @@ class Capybara::Selenium::Node < Capybara::Driver::Node
|
|
166
166
|
driver.evaluate_script GET_XPATH_SCRIPT, self
|
167
167
|
end
|
168
168
|
|
169
|
+
def obscured?(x: nil, y: nil)
|
170
|
+
res = driver.evaluate_script(OBSCURED_OR_OFFSET_SCRIPT, self, x, y)
|
171
|
+
return true if res == true
|
172
|
+
|
173
|
+
driver.frame_obscured_at?(x: res['x'], y: res['y'])
|
174
|
+
end
|
175
|
+
|
169
176
|
protected
|
170
177
|
|
171
178
|
def scroll_if_needed
|
@@ -401,6 +408,23 @@ private
|
|
401
408
|
})(arguments[0], document)
|
402
409
|
JS
|
403
410
|
|
411
|
+
OBSCURED_OR_OFFSET_SCRIPT = <<~'JS'
|
412
|
+
(function(el, x, y) {
|
413
|
+
var box = el.getBoundingClientRect();
|
414
|
+
if (x == null) x = box.width/2;
|
415
|
+
if (y == null) y = box.height/2 ;
|
416
|
+
|
417
|
+
var px = box.left + x,
|
418
|
+
py = box.top + y,
|
419
|
+
e = document.elementFromPoint(px, py);
|
420
|
+
|
421
|
+
if (!el.contains(e))
|
422
|
+
return true;
|
423
|
+
|
424
|
+
return { x: px, y: py };
|
425
|
+
})(arguments[0], arguments[1], arguments[2])
|
426
|
+
JS
|
427
|
+
|
404
428
|
# SettableValue encapsulates time/date field formatting
|
405
429
|
class SettableValue
|
406
430
|
attr_reader :value
|
@@ -16,6 +16,10 @@ class Capybara::Selenium::SafariNode < Capybara::Selenium::Node
|
|
16
16
|
return find_css('th:first-child,td:first-child')[0].click(keys, options)
|
17
17
|
end
|
18
18
|
raise
|
19
|
+
rescue ::Selenium::WebDriver::Error::WebDriverError
|
20
|
+
# Safari doesn't return a specific error here - assume it's an ElementNotInteractableError
|
21
|
+
raise ::Selenium::WebDriver::Error::ElementNotInteractableError,
|
22
|
+
'Non distinct error raised in #click, translated to ElementNotInteractableError for retry'
|
19
23
|
end
|
20
24
|
|
21
25
|
def select_option
|
@@ -54,7 +58,9 @@ class Capybara::Selenium::SafariNode < Capybara::Selenium::Node
|
|
54
58
|
end
|
55
59
|
|
56
60
|
def send_keys(*args)
|
57
|
-
|
61
|
+
if args.none? { |arg| arg.is_a?(Array) || (arg.is_a?(Symbol) && MODIFIER_KEYS.include?(arg)) }
|
62
|
+
return super(*args.map { |arg| arg == :space ? ' ' : arg })
|
63
|
+
end
|
58
64
|
|
59
65
|
native.click
|
60
66
|
_send_keys(args).perform
|
@@ -74,6 +80,11 @@ class Capybara::Selenium::SafariNode < Capybara::Selenium::Node
|
|
74
80
|
end
|
75
81
|
end
|
76
82
|
|
83
|
+
def hover
|
84
|
+
# Workaround issue where hover would sometimes fail - possibly due to mouse not having moved
|
85
|
+
scroll_if_needed { browser_action.move_to(native, 0, 0).move_to(native).perform }
|
86
|
+
end
|
87
|
+
|
77
88
|
private
|
78
89
|
|
79
90
|
def bridge
|
@@ -95,11 +106,7 @@ private
|
|
95
106
|
|
96
107
|
def _send_keys(keys, actions = browser_action, down_keys = ModifierKeysStack.new)
|
97
108
|
case keys
|
98
|
-
when
|
99
|
-
:alt, :left_alt, :right_alt,
|
100
|
-
:shift, :left_shift, :right_shift,
|
101
|
-
:meta, :left_meta, :right_meta,
|
102
|
-
:command
|
109
|
+
when *MODIFIER_KEYS
|
103
110
|
down_keys.press(keys)
|
104
111
|
actions.key_down(keys)
|
105
112
|
when String
|
@@ -117,6 +124,12 @@ private
|
|
117
124
|
actions
|
118
125
|
end
|
119
126
|
|
127
|
+
MODIFIER_KEYS = %i[control left_control right_control
|
128
|
+
alt left_alt right_alt
|
129
|
+
shift left_shift right_shift
|
130
|
+
meta left_meta right_meta
|
131
|
+
command].freeze
|
132
|
+
|
120
133
|
class ModifierKeysStack
|
121
134
|
def initialize
|
122
135
|
@stack = []
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CapybaraAtoms
|
4
|
+
private # rubocop:disable Layout/IndentationWidth
|
5
|
+
|
6
|
+
def read_atom(function)
|
7
|
+
@atoms ||= Hash.new do |hash, key|
|
8
|
+
hash[key] = begin
|
9
|
+
File.read(File.expand_path("../../atoms/#{key}.min.js", __FILE__))
|
10
|
+
rescue Errno::ENOENT
|
11
|
+
super
|
12
|
+
end
|
13
|
+
end
|
14
|
+
@atoms[function]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
::Selenium::WebDriver::Remote::Bridge.prepend CapybaraAtoms unless ENV['DISABLE_CAPYBARA_SELENIUM_OPTIMIZATIONS']
|
@@ -100,6 +100,29 @@ Capybara::SpecHelper.spec '#all' do
|
|
100
100
|
end
|
101
101
|
end
|
102
102
|
|
103
|
+
context 'with obscured filter', requires: [:css] do
|
104
|
+
it 'should only find nodes on top in the viewport when false' do
|
105
|
+
expect(@session.all(:css, 'a.simple', obscured: false).size).to eq(1)
|
106
|
+
end
|
107
|
+
|
108
|
+
it 'should not find nodes on top outside the viewport when false' do
|
109
|
+
expect(@session.all(:link, 'Download Me', obscured: false).size).to eq(0)
|
110
|
+
@session.scroll_to(@session.find_link('Download Me'))
|
111
|
+
expect(@session.all(:link, 'Download Me', obscured: false).size).to eq(1)
|
112
|
+
end
|
113
|
+
|
114
|
+
it 'should find top nodes outside the viewport when true' do
|
115
|
+
expect(@session.all(:link, 'Download Me', obscured: true).size).to eq(1)
|
116
|
+
@session.scroll_to(@session.find_link('Download Me'))
|
117
|
+
expect(@session.all(:link, 'Download Me', obscured: true).size).to eq(0)
|
118
|
+
end
|
119
|
+
|
120
|
+
it 'should only find non-top nodes when true' do
|
121
|
+
# Also need visible: false so visibility is ignored
|
122
|
+
expect(@session.all(:css, 'a.simple', visible: false, obscured: true).size).to eq(1)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
103
126
|
context 'with element count filters' do
|
104
127
|
context ':count' do
|
105
128
|
it 'should succeed when the number of elements founds matches the expectation' do
|
@@ -118,6 +118,17 @@ Capybara::SpecHelper.spec '#click_link' do
|
|
118
118
|
expect { @session.click_link('Normal Anchor', href: nil) }.to raise_error(Capybara::ElementNotFound, /with no href attribute/)
|
119
119
|
end
|
120
120
|
end
|
121
|
+
|
122
|
+
context 'href: false' do
|
123
|
+
it 'should not raise an error on links with no href attribute' do
|
124
|
+
expect { @session.click_link('No Href', href: false) }.not_to raise_error
|
125
|
+
end
|
126
|
+
|
127
|
+
it 'should not raise an error if href attribute exists' do
|
128
|
+
expect { @session.click_link('Blank Href', href: false) }.not_to raise_error
|
129
|
+
expect { @session.click_link('Normal Anchor', href: false) }.not_to raise_error
|
130
|
+
end
|
131
|
+
end
|
121
132
|
end
|
122
133
|
|
123
134
|
it 'should follow relative links' do
|
@@ -251,6 +251,79 @@ Capybara::SpecHelper.spec 'node' do
|
|
251
251
|
end
|
252
252
|
end
|
253
253
|
|
254
|
+
describe '#obscured?', requires: [:css] do
|
255
|
+
it 'should see non visible elements as obscured' do
|
256
|
+
Capybara.ignore_hidden_elements = false
|
257
|
+
expect(@session.find('//div[@id="hidden"]')).to be_obscured
|
258
|
+
expect(@session.find('//div[@id="hidden_via_ancestor"]')).to be_obscured
|
259
|
+
expect(@session.find('//div[@id="hidden_attr"]')).to be_obscured
|
260
|
+
expect(@session.find('//a[@id="hidden_attr_via_ancestor"]')).to be_obscured
|
261
|
+
expect(@session.find('//input[@id="hidden_input"]')).to be_obscured
|
262
|
+
end
|
263
|
+
|
264
|
+
it 'should see non-overlapped elements as not obscured' do
|
265
|
+
@session.visit('/obscured')
|
266
|
+
expect(@session.find(:css, '#cover')).not_to be_obscured
|
267
|
+
end
|
268
|
+
|
269
|
+
it 'should see elements only overlapped by descendants as not obscured' do
|
270
|
+
expect(@session.first(:css, 'p:not(.para)')).not_to be_obscured
|
271
|
+
end
|
272
|
+
|
273
|
+
it 'should see elements outside the viewport as obscured' do
|
274
|
+
@session.visit('/obscured')
|
275
|
+
off = @session.find(:css, '#offscreen')
|
276
|
+
off_wrapper = @session.find(:css, '#offscreen_wrapper')
|
277
|
+
expect(off).to be_obscured
|
278
|
+
expect(off_wrapper).to be_obscured
|
279
|
+
@session.scroll_to(off_wrapper)
|
280
|
+
expect(off_wrapper).not_to be_obscured
|
281
|
+
expect(off).to be_obscured
|
282
|
+
off_wrapper.scroll_to(off)
|
283
|
+
expect(off).not_to be_obscured
|
284
|
+
expect(off_wrapper).not_to be_obscured
|
285
|
+
end
|
286
|
+
|
287
|
+
it 'should see overlapped elements as obscured' do
|
288
|
+
@session.visit('/obscured')
|
289
|
+
expect(@session.find(:css, '#obscured')).to be_obscured
|
290
|
+
end
|
291
|
+
|
292
|
+
it 'should be boolean' do
|
293
|
+
Capybara.ignore_hidden_elements = false
|
294
|
+
expect(@session.first('//a').obscured?).to be false
|
295
|
+
expect(@session.find('//div[@id="hidden"]').obscured?).to be true
|
296
|
+
end
|
297
|
+
|
298
|
+
it 'should work in frames' do
|
299
|
+
@session.visit('/obscured')
|
300
|
+
frame = @session.find(:css, '#frameOne')
|
301
|
+
@session.within_frame(frame) do
|
302
|
+
div = @session.find(:css, '#divInFrameOne')
|
303
|
+
expect(div).to be_obscured
|
304
|
+
@session.scroll_to div
|
305
|
+
expect(div).not_to be_obscured
|
306
|
+
end
|
307
|
+
end
|
308
|
+
|
309
|
+
it 'should work in nested iframes' do
|
310
|
+
@session.visit('/obscured')
|
311
|
+
frame = @session.find(:css, '#nestedFrames')
|
312
|
+
@session.within_frame(frame) do
|
313
|
+
@session.within_frame(:css, '#childFrame') do
|
314
|
+
gcframe = @session.find(:css, '#grandchildFrame2')
|
315
|
+
@session.within_frame(gcframe) do
|
316
|
+
expect(@session.find(:css, '#divInFrameTwo')).to be_obscured
|
317
|
+
end
|
318
|
+
@session.scroll_to(gcframe)
|
319
|
+
@session.within_frame(gcframe) do
|
320
|
+
expect(@session.find(:css, '#divInFrameTwo')).not_to be_obscured
|
321
|
+
end
|
322
|
+
end
|
323
|
+
end
|
324
|
+
end
|
325
|
+
end
|
326
|
+
|
254
327
|
describe '#checked?' do
|
255
328
|
it 'should extract node checked state' do
|
256
329
|
@session.visit('/form')
|
@@ -441,7 +514,7 @@ Capybara::SpecHelper.spec 'node' do
|
|
441
514
|
end
|
442
515
|
|
443
516
|
it 'should retry clicking', requires: [:js] do
|
444
|
-
@session.visit('/
|
517
|
+
@session.visit('/animated')
|
445
518
|
obscured = @session.find(:css, '#obscured')
|
446
519
|
@session.execute_script <<~JS
|
447
520
|
setTimeout(function(){ $('#cover').hide(); }, 700)
|
@@ -450,7 +523,7 @@ Capybara::SpecHelper.spec 'node' do
|
|
450
523
|
end
|
451
524
|
|
452
525
|
it 'should allow to retry longer', requires: [:js] do
|
453
|
-
@session.visit('/
|
526
|
+
@session.visit('/animated')
|
454
527
|
obscured = @session.find(:css, '#obscured')
|
455
528
|
@session.execute_script <<~JS
|
456
529
|
setTimeout(function(){ $('#cover').hide(); }, 3000)
|
@@ -459,7 +532,7 @@ Capybara::SpecHelper.spec 'node' do
|
|
459
532
|
end
|
460
533
|
|
461
534
|
it 'should not retry clicking when wait is disabled', requires: [:js] do
|
462
|
-
@session.visit('/
|
535
|
+
@session.visit('/animated')
|
463
536
|
obscured = @session.find(:css, '#obscured')
|
464
537
|
@session.execute_script <<~JS
|
465
538
|
setTimeout(function(){ $('#cover').hide(); }, 2000)
|
@@ -493,7 +566,7 @@ Capybara::SpecHelper.spec 'node' do
|
|
493
566
|
end
|
494
567
|
|
495
568
|
it 'should retry clicking', requires: [:js] do
|
496
|
-
@session.visit('/
|
569
|
+
@session.visit('/animated')
|
497
570
|
obscured = @session.find(:css, '#obscured')
|
498
571
|
@session.execute_script <<~JS
|
499
572
|
setTimeout(function(){ $('#cover').hide(); }, 700)
|
@@ -527,7 +600,7 @@ Capybara::SpecHelper.spec 'node' do
|
|
527
600
|
end
|
528
601
|
|
529
602
|
it 'should retry clicking', requires: [:js] do
|
530
|
-
@session.visit('/
|
603
|
+
@session.visit('/animated')
|
531
604
|
obscured = @session.find(:css, '#obscured')
|
532
605
|
@session.execute_script <<~JS
|
533
606
|
setTimeout(function(){ $('#cover').hide(); }, 700)
|
@@ -14,10 +14,18 @@ Capybara::SpecHelper.spec Capybara::Selector do
|
|
14
14
|
expect(@session.find(:label, for: 'form_other_title')['for']).to eq 'form_other_title'
|
15
15
|
end
|
16
16
|
|
17
|
+
it 'finds a label for for attribute regex' do
|
18
|
+
expect(@session.find(:label, for: /_other_title/)['for']).to eq 'form_other_title'
|
19
|
+
end
|
20
|
+
|
17
21
|
it 'finds a label from nested input using :for filter with id string' do
|
18
22
|
expect(@session.find(:label, for: 'nested_label').text).to eq 'Nested Label'
|
19
23
|
end
|
20
24
|
|
25
|
+
it 'finds a label from nested input using :for filter with id regexp' do
|
26
|
+
expect(@session.find(:label, for: /nested_lab/).text).to eq 'Nested Label'
|
27
|
+
end
|
28
|
+
|
21
29
|
it 'finds a label from nested input using :for filter with element' do
|
22
30
|
input = @session.find(:id, 'nested_label')
|
23
31
|
expect(@session.find(:label, for: input).text).to eq 'Nested Label'
|
@@ -0,0 +1,49 @@
|
|
1
|
+
<html>
|
2
|
+
<head>
|
3
|
+
<meta http-equiv="Content-type" content="text/html; charset=utf-8"/>
|
4
|
+
<title>with_animation</title>
|
5
|
+
<script src="/jquery.js" type="text/javascript" charset="utf-8"></script>
|
6
|
+
<script>
|
7
|
+
$(document).on('contextmenu', function(e){ e.preventDefault(); });
|
8
|
+
</script>
|
9
|
+
<style>
|
10
|
+
div {
|
11
|
+
width: 400px;
|
12
|
+
height: 400px;
|
13
|
+
position: absolute;
|
14
|
+
}
|
15
|
+
#obscured {
|
16
|
+
z-index: 1;
|
17
|
+
background-color: red;
|
18
|
+
}
|
19
|
+
#cover {
|
20
|
+
z-index: 2;
|
21
|
+
background-color: blue;
|
22
|
+
}
|
23
|
+
#offscreen {
|
24
|
+
top: 2000px;
|
25
|
+
left: 2000px;
|
26
|
+
background-color: green;
|
27
|
+
}
|
28
|
+
#offscreen_wrapper {
|
29
|
+
top: 2000px;
|
30
|
+
left: 2000px;
|
31
|
+
overflow-x: scroll;
|
32
|
+
background-color: yellow;
|
33
|
+
}
|
34
|
+
</style>
|
35
|
+
</head>
|
36
|
+
|
37
|
+
<body id="with_animation">
|
38
|
+
<div id="obscured">
|
39
|
+
<input id="obscured_input"/>
|
40
|
+
</div>
|
41
|
+
<div id="cover"></div>
|
42
|
+
<div id="offscreen_wrapper">
|
43
|
+
<div id="offscreen"></div>
|
44
|
+
</div>
|
45
|
+
</body>
|
46
|
+
|
47
|
+
<iframe id="frameOne" src="/frame_one"></iframe>
|
48
|
+
</html>
|
49
|
+
|
@@ -1,15 +1,13 @@
|
|
1
1
|
<html>
|
2
2
|
<head>
|
3
3
|
<meta http-equiv="Content-type" content="text/html; charset=utf-8"/>
|
4
|
-
<title>
|
5
|
-
<script src="/jquery.js" type="text/javascript" charset="utf-8"></script>
|
6
|
-
<script>
|
7
|
-
$(document).on('contextmenu', function(e){ e.preventDefault(); });
|
8
|
-
</script>
|
4
|
+
<title>Obscured</title>
|
9
5
|
<style>
|
10
6
|
div {
|
11
|
-
width:
|
12
|
-
height:
|
7
|
+
width: 200px;
|
8
|
+
height: 200px;
|
9
|
+
}
|
10
|
+
#cover, #offscreen, #offscreen_wrapper {
|
13
11
|
position: absolute;
|
14
12
|
}
|
15
13
|
#obscured {
|
@@ -17,6 +15,7 @@
|
|
17
15
|
background-color: red;
|
18
16
|
}
|
19
17
|
#cover {
|
18
|
+
top: 0px;
|
20
19
|
z-index: 2;
|
21
20
|
background-color: blue;
|
22
21
|
}
|
@@ -33,12 +32,13 @@
|
|
33
32
|
}
|
34
33
|
</style>
|
35
34
|
</head>
|
36
|
-
|
37
|
-
<body id="with_animation">
|
35
|
+
<body>
|
38
36
|
<div id="obscured">
|
39
37
|
<input id="obscured_input"/>
|
40
38
|
</div>
|
41
39
|
<div id="cover"></div>
|
40
|
+
<iframe id="frameOne" height="10px" src="/frame_one"></iframe>
|
41
|
+
<iframe id="nestedFrames" src="/frame_parent"></iframe>
|
42
42
|
<div id="offscreen_wrapper">
|
43
43
|
<div id="offscreen"></div>
|
44
44
|
</div>
|