capybara 3.19.1 → 3.20.0
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.
- 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>
|