eyes_selenium 3.14.3 → 3.14.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/lib/applitools/selenium/border_aware_element_content_location_provider.rb +2 -0
- data/lib/applitools/selenium/browser.rb +66 -56
- data/lib/applitools/selenium/context_based_scale_provider.rb +2 -0
- data/lib/applitools/selenium/css_transform/css_transform.rb +21 -0
- data/lib/applitools/selenium/css_translate_element_position_provider.rb +48 -0
- data/lib/applitools/selenium/css_translate_position_provider.rb +29 -10
- data/lib/applitools/selenium/dom_capture/dom_capture.rb +113 -0
- data/lib/applitools/selenium/dom_capture/dom_capture_script.rb +103 -0
- data/lib/applitools/selenium/driver.rb +9 -2
- data/lib/applitools/selenium/element.rb +2 -0
- data/lib/applitools/selenium/element_position_provider.rb +3 -1
- data/lib/applitools/selenium/entire_element_screenshot.rb +20 -0
- data/lib/applitools/selenium/eyes.rb +203 -396
- data/lib/applitools/selenium/eyes_screenshot.rb +60 -0
- data/lib/applitools/selenium/eyes_target_locator.rb +12 -24
- data/lib/applitools/selenium/fixed_cut_provider.rb +48 -0
- data/lib/applitools/selenium/frame.rb +11 -1
- data/lib/applitools/selenium/frame_chain.rb +9 -1
- data/lib/applitools/selenium/full_page_capture_algorithm.rb +85 -50
- data/lib/applitools/selenium/fullpage_screenshot.rb +37 -0
- data/lib/applitools/selenium/keyboard.rb +2 -0
- data/lib/applitools/selenium/mouse.rb +2 -0
- data/lib/applitools/selenium/move_to_region_visibility_strategy.rb +2 -0
- data/lib/applitools/selenium/nop_region_visibility_strategy.rb +2 -0
- data/lib/applitools/selenium/region_provider.rb +91 -0
- data/lib/applitools/selenium/sauce/driver.rb +2 -0
- data/lib/applitools/selenium/scroll_position_provider.rb +13 -2
- data/lib/applitools/selenium/takes_screenshot_image_provider.rb +5 -3
- data/lib/applitools/selenium/target.rb +32 -6
- data/lib/applitools/selenium/viewport_screenshot.rb +46 -0
- data/lib/applitools/selenium/viewport_size.rb +2 -0
- data/lib/applitools/version.rb +3 -1
- data/lib/eyes_selenium.rb +4 -9
- metadata +16 -27
- data/lib/applitools/capybara.rb +0 -8
- data/lib/applitools/poltergeist/applitools_compatible.rb +0 -32
- data/lib/applitools/poltergeist/driver.rb +0 -11
- data/lib/applitools/selenium/capybara/capybara_settings.rb +0 -23
- data/lib/applitools/selenium/capybara/driver.rb +0 -37
- data/lib/applitools/selenium/eyes_full_page_screenshot.rb +0 -47
- data/lib/applitools/selenium/eyes_web_driver_screenshot.rb +0 -341
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: eed17b1ab4d0917d2cb7f0048435f2b8b5b5a41c29607bfc82caa0da521e071e
|
4
|
+
data.tar.gz: d8398e29b30ba60e8d033608d0e70193413866e5509c057206357840b58ca0e9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 214c9dd3f2085254d46241980ca5a416a4b4f70cda46f54a65adf36b85198d53db267fb9d8275c5d98f1f9543e06343dcbe36938d80eab7c1b1fe2e4e013bc20
|
7
|
+
data.tar.gz: 824ea45b22311de40906cd2a2e19b8652d7eff6b778e6f43379acc7f600397e7d5ad0a49ee55909e29303d585241200c16771e976e346546dbe8c51f8e680064
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: false
|
2
|
+
|
1
3
|
module Applitools::Selenium
|
2
4
|
# @!visibility private
|
3
5
|
class Browser
|
@@ -69,7 +71,15 @@ module Applitools::Selenium
|
|
69
71
|
end
|
70
72
|
|
71
73
|
def chrome?
|
72
|
-
|
74
|
+
running_browser_name == :chrome
|
75
|
+
end
|
76
|
+
|
77
|
+
def firefox?
|
78
|
+
running_browser_name == :firefox
|
79
|
+
end
|
80
|
+
|
81
|
+
def running_browser_name
|
82
|
+
@driver.__getobj__.browser
|
73
83
|
end
|
74
84
|
|
75
85
|
def user_agent
|
@@ -149,62 +159,62 @@ module Applitools::Selenium
|
|
149
159
|
set_transform("translate(-#{point.left}px, -#{point.top}px)")
|
150
160
|
end
|
151
161
|
|
152
|
-
# Takes a full page screenshot.
|
162
|
+
# # Takes a full page screenshot.
|
163
|
+
# #
|
164
|
+
# # @return [ChunkyPNG::Canvas] image The result of the screenshot.
|
165
|
+
# def fullpage_screenshot
|
166
|
+
# # Scroll to the top/left corner of the screen.
|
167
|
+
# original_scroll_position = current_scroll_position
|
168
|
+
# scroll_to(Applitools::Base::Point::TOP_LEFT)
|
169
|
+
# if current_scroll_position != Applitools::Base::Point::TOP_LEFT
|
170
|
+
# raise 'Could not scroll to the top/left corner of the screen!'
|
171
|
+
# end
|
153
172
|
#
|
154
|
-
#
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
process_screenshot_part(screenshot_part, size_factor)
|
201
|
-
end
|
202
|
-
screenshot = Applitools::Utils::ImageUtils.stitch_images(page_size, parts)
|
203
|
-
end
|
204
|
-
set_transform(original_transform) if @eyes.use_css_transition
|
205
|
-
scroll_to(original_scroll_position)
|
206
|
-
screenshot
|
207
|
-
end
|
173
|
+
# # Translate to top/left of the page (notice this is different from JavaScript scrolling).
|
174
|
+
# if @eyes.use_css_transition
|
175
|
+
# original_transform = current_transform
|
176
|
+
# translate_to(Applitools::Base::Point::TOP_LEFT)
|
177
|
+
# end
|
178
|
+
#
|
179
|
+
# # Take screenshot of the (0,0) tile.
|
180
|
+
# screenshot = @driver.visible_screenshot
|
181
|
+
#
|
182
|
+
# # Normalize screenshot width/height.
|
183
|
+
# size_factor = 1
|
184
|
+
# page_size = entire_page_size
|
185
|
+
# factor = image_normalization_factor(screenshot)
|
186
|
+
# if factor == 0.5
|
187
|
+
# size_factor = 2
|
188
|
+
# page_size.width *= size_factor
|
189
|
+
# page_size.height *= size_factor
|
190
|
+
# page_size.width = [page_size.width, screenshot.width].max
|
191
|
+
# end
|
192
|
+
#
|
193
|
+
# # NOTE: this is required! Since when calculating the screenshot parts for full size, we use a screenshot size
|
194
|
+
# # which is a bit smaller (see comment below).
|
195
|
+
# if screenshot.width < page_size.width || screenshot.height < page_size.height
|
196
|
+
# # We use a smaller size than the actual screenshot size in order to eliminate duplication of bottom scroll bars,
|
197
|
+
# # as well as footer-like elements with fixed position.
|
198
|
+
# max_scrollbar_size = @eyes.use_css_transition ? 0 : MAX_SCROLLBAR_SIZE
|
199
|
+
# height = [screenshot.height - (max_scrollbar_size * size_factor), MIN_SCREENSHOT_PART_HEIGHT * size_factor].max
|
200
|
+
# screenshot_part_size = Applitools::Base::Dimension.new(screenshot.width, height)
|
201
|
+
#
|
202
|
+
# sub_regions = Applitools::Base::Region.new(0, 0, page_size.width,
|
203
|
+
# page_size.height).subregions(screenshot_part_size)
|
204
|
+
# parts = sub_regions.map do |screenshot_part|
|
205
|
+
# # Skip (0,0), as we already got the screenshot.
|
206
|
+
# if screenshot_part.left.zero? && screenshot_part.top.zero?
|
207
|
+
# next Applitools::Base::ImagePosition.new(screenshot, Applitools::Base::Point::TOP_LEFT)
|
208
|
+
# end
|
209
|
+
#
|
210
|
+
# process_screenshot_part(screenshot_part, size_factor)
|
211
|
+
# end
|
212
|
+
# screenshot = Applitools::Utils::ImageUtils.stitch_images(page_size, parts)
|
213
|
+
# end
|
214
|
+
# set_transform(original_transform) if @eyes.use_css_transition
|
215
|
+
# scroll_to(original_scroll_position)
|
216
|
+
# screenshot
|
217
|
+
# end
|
208
218
|
|
209
219
|
private
|
210
220
|
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Applitools
|
4
|
+
module CssTransform
|
5
|
+
private
|
6
|
+
|
7
|
+
def get_position_from_transform(transform)
|
8
|
+
regexp = /^translate\(\s*(\-?)([\d, \.]+)px,\s*(\-?)([\d, \.]+)px\s*\)/
|
9
|
+
data = regexp.match(transform)
|
10
|
+
|
11
|
+
raise Applitools::EyesError.new "Can't parse CSS transition: #{transform}!" unless data
|
12
|
+
x = data[2].to_f.round
|
13
|
+
y = data[4].to_f.round
|
14
|
+
|
15
|
+
x *= -1 unless data[1].empty?
|
16
|
+
y *= -1 unless data[3].empty?
|
17
|
+
|
18
|
+
Applitools::Location.new(x, y)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'element_position_provider'
|
4
|
+
require_relative 'css_transform/css_transform'
|
5
|
+
|
6
|
+
module Applitools::Selenium
|
7
|
+
# @!visibility private
|
8
|
+
class CssTranslateElementPositionProvider < ElementPositionProvider
|
9
|
+
include Applitools::CssTransform
|
10
|
+
|
11
|
+
# Gets the current position.
|
12
|
+
#
|
13
|
+
# @return [Applitools::Location] The location.
|
14
|
+
def current_position
|
15
|
+
position = super.offset_negative transforms_offset
|
16
|
+
logger.info "Current position is #{position}"
|
17
|
+
position
|
18
|
+
end
|
19
|
+
|
20
|
+
def position=(location)
|
21
|
+
super
|
22
|
+
out_of_eyes = location.dup.offset_negative(current_position)
|
23
|
+
return if out_of_eyes == Applitools::Location::TOP_LEFT
|
24
|
+
logger.info "Moving element by #{out_of_eyes} to fit in the eyes region"
|
25
|
+
|
26
|
+
Applitools::Utils::EyesSeleniumUtils.element_translate_to(
|
27
|
+
driver,
|
28
|
+
element,
|
29
|
+
transforms_offset.offset_negative(out_of_eyes)
|
30
|
+
)
|
31
|
+
logger.info 'Done scrolling element!'
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def transforms_offset
|
37
|
+
logger.info 'Getting element transforms...'
|
38
|
+
transforms = Applitools::Utils::EyesSeleniumUtils.current_element_transforms(driver, element)
|
39
|
+
logger.info "Current transforms: #{transforms}"
|
40
|
+
transform_positions = transforms.values.compact.select { |s| !s.empty? }
|
41
|
+
.map { |s| get_position_from_transform(s) }
|
42
|
+
transform_positions.each do |p|
|
43
|
+
raise Applitools::EyesError.new 'Got different css positions!' unless p == transform_positions[0]
|
44
|
+
end
|
45
|
+
transform_positions[0] || Applitools::Location::TOP_LEFT.dup
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -1,6 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'css_transform/css_transform'
|
4
|
+
|
1
5
|
module Applitools::Selenium
|
2
6
|
class CssTranslatePositionProvider
|
3
7
|
extend Forwardable
|
8
|
+
include Applitools::CssTransform
|
4
9
|
|
5
10
|
def_delegators 'Applitools::EyesLogger', :logger, :log_handler, :log_handler=
|
6
11
|
|
@@ -33,7 +38,7 @@ module Applitools::Selenium
|
|
33
38
|
#
|
34
39
|
# @param [Applitools::Location] value The location.
|
35
40
|
def restore_state(value)
|
36
|
-
transforms = value.values.select { |el| !el.empty? }
|
41
|
+
transforms = value.values.compact.select { |el| !el.empty? }
|
37
42
|
Applitools::Utils::EyesSeleniumUtils.set_transforms(executor, value)
|
38
43
|
if transforms.empty?
|
39
44
|
self.last_state_position = Applitools::Location::TOP_LEFT
|
@@ -62,7 +67,7 @@ module Applitools::Selenium
|
|
62
67
|
# Gets the entire size of the frame.
|
63
68
|
#
|
64
69
|
# @return [Applitools::RectangleSize] The entire size of the frame.
|
65
|
-
def entire_size
|
70
|
+
def entire_size(_image_width, _image_height)
|
66
71
|
viewport_size = Applitools::Utils::EyesSeleniumUtils.extract_viewport_size(executor)
|
67
72
|
result = Applitools::Utils::EyesSeleniumUtils.current_frame_content_entire_size(executor)
|
68
73
|
logger.info "Entire size: #{result}"
|
@@ -73,19 +78,33 @@ module Applitools::Selenium
|
|
73
78
|
result.height = [viewport_size.height, result.height].min if disable_vertical
|
74
79
|
logger.info "Actual size to scroll: #{result}"
|
75
80
|
result
|
81
|
+
|
82
|
+
# return result unless executor.frame_chain.empty?
|
83
|
+
|
84
|
+
# spp = Applitools::Selenium::ScrollPositionProvider.new(executor)
|
85
|
+
# original_scroll_position = spp.current_position
|
86
|
+
# spp.scroll_to_bottom_right
|
87
|
+
# bottom_right_position = spp.current_position
|
88
|
+
# spp.restore_state(original_scroll_position)
|
89
|
+
# Applitools::RectangleSize.new(bottom_right_position.x + image_width, bottom_right_position.y + image_height)
|
76
90
|
end
|
77
91
|
|
78
92
|
private
|
79
93
|
|
80
94
|
attr_accessor :executor, :disable_horizontal, :disable_vertical, :max_width, :max_height
|
81
95
|
|
82
|
-
def get_position_from_transform(transform)
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
96
|
+
# def get_position_from_transform(transform)
|
97
|
+
# regexp = /^translate\(\s*(\-?)([\d, \.]+)px,\s*(\-?)([\d, \.]+)px\s*\)/
|
98
|
+
# data = regexp.match(transform)
|
99
|
+
#
|
100
|
+
# raise Applitools::EyesError.new "Can't parse CSS transition: #{transform}!" unless data
|
101
|
+
# x = data[2].to_f.round
|
102
|
+
# y = data[4].to_f.round
|
103
|
+
#
|
104
|
+
# x *= (-1) unless data[1].empty?
|
105
|
+
# y *= (-1) unless data[3].empty?
|
106
|
+
#
|
107
|
+
# Applitools::Location.new(x, y)
|
108
|
+
# end
|
90
109
|
end
|
91
110
|
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
# frozen_string_literal: false
|
2
|
+
|
3
|
+
require 'benchmark'
|
4
|
+
require 'timeout'
|
5
|
+
|
6
|
+
require 'css_parser'
|
7
|
+
include Benchmark
|
8
|
+
module Applitools::Selenium
|
9
|
+
module DomCapture
|
10
|
+
CSS_DOWNLOAD_TIMEOUT = 2 # 2 seconds
|
11
|
+
DOM_CAPTURE_TIMEOUT = 10 # 10 seconds
|
12
|
+
|
13
|
+
extend self
|
14
|
+
|
15
|
+
def get_window_dom(driver, logger)
|
16
|
+
args_obj = {
|
17
|
+
'styleProps' => %w(
|
18
|
+
background-color background-image background-size color border-width
|
19
|
+
border-color border-style padding margin
|
20
|
+
),
|
21
|
+
'attributeProps' => nil,
|
22
|
+
'rectProps' => %w(width height top left),
|
23
|
+
'ignoredTagNames' => %w(HEAD SCRIPT)
|
24
|
+
}
|
25
|
+
dom_tree = ''
|
26
|
+
if Timeout.respond_to?(:timeout)
|
27
|
+
Timeout.timeout(DOM_CAPTURE_TIMEOUT) do
|
28
|
+
dom_tree = driver.execute_script(Applitools::Selenium::DomCapture::DOM_CAPTURE_SCRIPT, args_obj)
|
29
|
+
get_frame_dom(driver, { 'childNodes' => [dom_tree], 'tagName' => 'OUTER_HTML' }, logger)
|
30
|
+
end
|
31
|
+
else
|
32
|
+
timeout(DOM_CAPTURE_TIMEOUT) do
|
33
|
+
dom_tree = driver.execute_script(Applitools::Selenium::DomCapture::DOM_CAPTURE_SCRIPT, args_obj)
|
34
|
+
get_frame_dom(driver, { 'childNodes' => [dom_tree], 'tagName' => 'OUTER_HTML' }, logger)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
dom_tree
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def get_frame_dom(driver, dom_tree, logger)
|
43
|
+
tag_name = dom_tree['tagName']
|
44
|
+
return unless tag_name
|
45
|
+
frame_index = 0
|
46
|
+
loop(driver, dom_tree, logger) do |dom_sub_tree|
|
47
|
+
# this block is called if IFRAME found
|
48
|
+
driver.switch_to.frame(index: frame_index)
|
49
|
+
get_frame_dom(driver, dom_sub_tree, logger)
|
50
|
+
driver.switch_to.parent_frame
|
51
|
+
frame_index += 1
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def loop(driver, dom_tree, logger)
|
56
|
+
child_nodes = dom_tree['childNodes']
|
57
|
+
return unless child_nodes
|
58
|
+
iterate_child_nodes = proc do |node_childs|
|
59
|
+
node_childs.each do |node|
|
60
|
+
if node['tagName'].casecmp('IFRAME') == 0
|
61
|
+
yield(node) if block_given?
|
62
|
+
else
|
63
|
+
node['css'] = get_frame_bundled_css(driver, logger) if node['tagName'].casecmp('HTML') == 0
|
64
|
+
iterate_child_nodes.call(node['childNodes']) unless node['childNodes'].nil?
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
iterate_child_nodes.call(child_nodes)
|
69
|
+
end
|
70
|
+
|
71
|
+
def get_frame_bundled_css(driver, logger)
|
72
|
+
base_url = URI.parse(driver.current_url)
|
73
|
+
parser = CssParser::Parser.new import: true, absolute_paths: true
|
74
|
+
css_threads = []
|
75
|
+
css_items = []
|
76
|
+
driver.execute_script(Applitools::Selenium::DomCapture::CSS_CAPTURE_SCRIPT).each_with_index do |item, i|
|
77
|
+
if (v = item['text'])
|
78
|
+
css_items[i] = [v]
|
79
|
+
elsif (v = item['href'])
|
80
|
+
target_url = URI.parse(v)
|
81
|
+
url_to_load = target_url.absolute? ? target_url : base_url.merge(target_url)
|
82
|
+
css_threads << Thread.new(url_to_load) do |url|
|
83
|
+
if Timeout.respond_to?(:timeout)
|
84
|
+
Timeout.timeout(CSS_DOWNLOAD_TIMEOUT) do
|
85
|
+
css_string, = parser.send(:read_remote_file, url)
|
86
|
+
css_items[i] = [css_string, { base_uri: url }]
|
87
|
+
end
|
88
|
+
else
|
89
|
+
timeout(CSS_DOWNLOAD_TIMEOUT) do
|
90
|
+
css_string, = parser.send(:read_remote_file, url)
|
91
|
+
css_items[i] = [css_string, { base_uri: url }]
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
begin
|
98
|
+
css_threads.each(&:join)
|
99
|
+
rescue CssParser::CircularReferenceError => e
|
100
|
+
logger.respond_to?(:error) && logger.error("Got a circular reference error! #{e.message}")
|
101
|
+
rescue CssParser::RemoteFileError => e
|
102
|
+
logger.respond_to?(:error) && logger.error("File download error - #{e.message}")
|
103
|
+
rescue StandardError => e
|
104
|
+
logger.respond_to?(:error) && logger.error("#{e.class} - #{e.message}")
|
105
|
+
end
|
106
|
+
|
107
|
+
css_items.each { |css| parser.add_block!(*css) if css && css[0] }
|
108
|
+
css_result = ''
|
109
|
+
parser.each_rule_set { |s| css_result.concat(s.to_s) }
|
110
|
+
css_result
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
#
|
3
|
+
module Applitools::Selenium
|
4
|
+
module DomCapture
|
5
|
+
CSS_CAPTURE_SCRIPT = <<-SCRIPT
|
6
|
+
function extractCssResources() {
|
7
|
+
return Array.from(document.querySelectorAll('link[rel="stylesheet"],style')).map(el => {
|
8
|
+
if (el.tagName.toUpperCase() === 'LINK') {
|
9
|
+
return {"href": el.getAttribute('href')};
|
10
|
+
} else {
|
11
|
+
return {"text": el.textContent};
|
12
|
+
}
|
13
|
+
});
|
14
|
+
}
|
15
|
+
return extractCssResources();
|
16
|
+
SCRIPT
|
17
|
+
DOM_CAPTURE_SCRIPT = <<-SCRIPT
|
18
|
+
function captureFrame({ styleProps, attributeProps, rectProps, ignoredTagNames }) {
|
19
|
+
const NODE_TYPES = {
|
20
|
+
ELEMENT: 1,
|
21
|
+
TEXT: 3,
|
22
|
+
};
|
23
|
+
function filter(x) {
|
24
|
+
return !!x;
|
25
|
+
}
|
26
|
+
function notEmptyObj(obj) {
|
27
|
+
return Object.keys(obj).length ? obj : undefined;
|
28
|
+
}
|
29
|
+
function iframeToJSON(el) {
|
30
|
+
const obj = elementToJSON(el);
|
31
|
+
try {
|
32
|
+
if (el.contentDocument) {
|
33
|
+
obj.childNodes = [captureNode(el.contentDocument.documentElement)];
|
34
|
+
}
|
35
|
+
} catch (ex) {
|
36
|
+
} finally {
|
37
|
+
return obj;
|
38
|
+
}
|
39
|
+
}
|
40
|
+
function elementToJSON(el) {
|
41
|
+
const tagName = el.tagName.toUpperCase();
|
42
|
+
if (ignoredTagNames.indexOf(tagName) > -1) return null;
|
43
|
+
const computedStyle = window.getComputedStyle(el);
|
44
|
+
const boundingClientRect = el.getBoundingClientRect();
|
45
|
+
const style = {};
|
46
|
+
for (const p of styleProps) style[p] = computedStyle.getPropertyValue(p);
|
47
|
+
const rect = {};
|
48
|
+
for (const p of rectProps) rect[p] = boundingClientRect[p];
|
49
|
+
const attributes = {};
|
50
|
+
if (!attributeProps) {
|
51
|
+
if (el.hasAttributes()) {
|
52
|
+
var attrs = el.attributes;
|
53
|
+
for (const p of attrs) {
|
54
|
+
attributes[p.name] = p.value;
|
55
|
+
}
|
56
|
+
}
|
57
|
+
}
|
58
|
+
else {
|
59
|
+
if (attributeProps.all) {
|
60
|
+
for (const p of attributeProps.all) {
|
61
|
+
if (el.hasAttribute(p)) attributes[p] = el.getAttribute(p);
|
62
|
+
}
|
63
|
+
}
|
64
|
+
if (attributeProps[tagName]) {
|
65
|
+
for (const p of attributeProps[tagName]) {
|
66
|
+
if (el.hasAttribute(p)) attributes[p] = el.getAttribute(p);
|
67
|
+
}
|
68
|
+
}
|
69
|
+
}
|
70
|
+
return {
|
71
|
+
tagName,
|
72
|
+
style: notEmptyObj(style),
|
73
|
+
rect: notEmptyObj(rect),
|
74
|
+
attributes: notEmptyObj(attributes),
|
75
|
+
childNodes: Array.prototype.map.call(el.childNodes, captureNode).filter(filter),
|
76
|
+
};
|
77
|
+
}
|
78
|
+
function captureTextNode(node) {
|
79
|
+
return {
|
80
|
+
tagName: '#text',
|
81
|
+
text: node.textContent,
|
82
|
+
};
|
83
|
+
}
|
84
|
+
function captureNode(node) {
|
85
|
+
switch (node.nodeType) {
|
86
|
+
case NODE_TYPES.TEXT:
|
87
|
+
return captureTextNode(node);
|
88
|
+
case NODE_TYPES.ELEMENT:
|
89
|
+
if (node.tagName.toUpperCase() === 'IFRAME') {
|
90
|
+
return iframeToJSON(node);
|
91
|
+
} else {
|
92
|
+
return elementToJSON(node);
|
93
|
+
}
|
94
|
+
default:
|
95
|
+
return null;
|
96
|
+
}
|
97
|
+
}
|
98
|
+
return captureNode(document.documentElement);
|
99
|
+
}
|
100
|
+
return captureFrame(arguments[0]);
|
101
|
+
SCRIPT
|
102
|
+
end
|
103
|
+
end
|