locatine 0.02535 → 0.02539

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 47bfe24e1d440f14261360ee0a4b262a7b495624
4
- data.tar.gz: ac4af7f07c3db70cbbb745cc68702701f97e442a
3
+ metadata.gz: 63c1d452b58e6881483141749a4cd5fc572a1a34
4
+ data.tar.gz: 5436ddbbd222888ab16ef121750e871be2d0b330
5
5
  SHA512:
6
- metadata.gz: 62e7a41f9b48b5187bff739b44591632e4a0e98dd69ec72f1683eaeca4d48347d16c78aeb97082db53d7d2a32ba38d743d0abc0dc7f4a7fb330ba86fd5203b4f
7
- data.tar.gz: be450e5dd42e70b9fc0050c5349932fe43901377d35ef2d6c719fabc22419e2dc80eabb4f3415f3133e58fcc6a1d7cd0c9d6cb2cb5148f9a4a7fd1d642d62173
6
+ metadata.gz: 875b40b1ebc3294dc60868c4f029a3eb2c37b984509002c30fadecad20d7e26f0df207eab8ed3466cc7021777d9a89baa6a0a6c4ba7dc655bea1109b573031cb
7
+ data.tar.gz: 9c36756f4c0388acf60d1009ed79ebed732b2401daa387930a3f61c8c97b745f2c1bc0bdeeced30e300543d88b09459c7bdf0f7320ef4630dbd47e83c9b58550
data/README.md CHANGED
@@ -16,7 +16,7 @@ That's it.
16
16
 
17
17
  ## Stage of development:
18
18
 
19
- Version of Locatine is **0.02535** only. It means so far this is an alfa. You can use it in a real project if you are a risky person.
19
+ Version of Locatine is **0.02539** only. It means so far this is an alfa. You can use it in a real project if you are a risky person.
20
20
 
21
21
  ## Installation
22
22
 
@@ -98,7 +98,8 @@ Locatine::Search.new(json: "./Locatine_files/default.json",
98
98
  visual_search: false,
99
99
  no_fail: false,
100
100
  trusted: [],
101
- untrusted: [])
101
+ untrusted: [],
102
+ autolearn: nil)
102
103
  ```
103
104
 
104
105
  ### json
@@ -241,7 +242,7 @@ vars = {tag: random_tag} # The tag
241
242
  vars = {attribute_name: random_attr} # If attribute is dynamic (use name of the attribute)
242
243
  # And two lines work with visual_search == true only
243
244
  vars = {css_option: random_value} # If your css is dynamic
244
- vars = {x: random_x} # x, y, width, height for element size and position
245
+ vars = {x: random_x} # x, y for element position
245
246
  ```
246
247
 
247
248
  And if you do not like it you can do:
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "Locatine app",
3
- "version": "0.02535",
3
+ "version": "0.02539",
4
4
  "description": "Messaging from browser to main app",
5
5
  "devtools_page": "devtools.html",
6
6
  "permissions": ["activeTab", "storage", "contextMenus", "tabs"],
@@ -5,53 +5,36 @@ module Locatine
5
5
  module DataGenerate
6
6
  private
7
7
 
8
- def real_text_of(element)
9
- element.text == element.inner_html ? element.text : ''
10
- end
11
-
12
8
  def mesure(element)
13
9
  xy = element.location
14
10
  wh = element.size
15
11
  return xy.x, xy.y, wh.width, wh.height
16
12
  end
17
13
 
18
- def get_dynamic_tag(element, vars)
19
- tag = element.tag_name
20
- tag = "\#{tag}" if vars[:tag] == tag
14
+ def get_dynamic_tag(tag, vars)
15
+ tag = "\#{tag}" if vars[:tag].to_s.casecmp(tag).zero?
21
16
  push_hash('tag', tag, 'tag')
22
17
  end
23
18
 
24
- def get_dynamic_text(element, vars)
25
- attrs = []
26
- real_text_of(element).split(/['" ]/).each do |word|
19
+ def text_array(text)
20
+ text.to_s.tr("\n", ' ').split(/['" ]/)
21
+ end
22
+
23
+ def get_dynamic_text(text, vars)
24
+ attrs = text_array(text).map do |word|
27
25
  final = if !vars[:text].to_s.strip.empty?
28
26
  word.gsub(vars[:text].to_s, "\#{text}")
29
27
  else
30
28
  word
31
29
  end
32
- attrs.push push_hash('text', final, 'text') unless final.empty?
30
+ push_hash('text', final, 'text') unless final.empty?
33
31
  end
34
- attrs
35
- end
36
-
37
- def process_dimension(name, value, vars)
38
- s_name = name.to_s
39
- value = value.to_s.gsub(vars[name], "\#{#{s_name}}") if vars[name]
40
- value
32
+ attrs.compact
41
33
  end
42
34
 
43
- def processed_dimensions(element, vars)
44
- x, y, width, height = mesure(element)
45
- x = process_dimension(:x, x, vars)
46
- y = process_dimension(:y, y, vars)
47
- width = process_dimension(:width, width, vars)
48
- height = process_dimension(:height, height, vars)
49
- return x, y, width, height
50
- end
51
-
52
- def get_dimensions(element, vars)
35
+ def get_dimensions(element)
53
36
  resolution = window_size
54
- x, y, w, h = processed_dimensions(element, vars)
37
+ x, y, w, h = mesure(element)
55
38
  push_hash(resolution, "#{x}*#{y}*#{w}*#{h}", 'dimensions')
56
39
  end
57
40
 
@@ -79,22 +62,6 @@ module Locatine
79
62
  end
80
63
  attrs
81
64
  end
82
-
83
- ##
84
- # Collecting attributes of the element
85
- def get_attributes(element)
86
- attributes = element.attributes
87
- array = []
88
- attributes.each_pair do |name, value|
89
- next if name.to_s == 'locatineclass' # Should never happen
90
-
91
- value.split(/['" ]/).reject(&:empty?).uniq.each do |part|
92
- array.push('name' => name.to_s, 'type' => 'attribute',
93
- 'value' => part)
94
- end
95
- end
96
- array
97
- end
98
65
  end
99
66
  end
100
67
  end
@@ -5,27 +5,49 @@ module Locatine
5
5
  module DataLogic
6
6
  private
7
7
 
8
- def get_dynamic_attributes(element, vars)
8
+ def get_dynamic_attributes(data, vars)
9
9
  attrs = []
10
- get_attributes(element).each do |hash|
11
- value = vars[hash['name'].to_sym]
12
- hash['value'].gsub!(value, "\#{#{hash['name']}}") if value
13
- attrs.push hash
10
+ data.each do |hash|
11
+ hash.each_pair do |key, full_value|
12
+ full_value.split(' ').each do |value|
13
+ next if key == 'locatineclass'
14
+
15
+ attrs.push some_attribute(value, key, vars)
16
+ end
17
+ end
14
18
  end
15
19
  attrs
16
20
  end
17
21
 
22
+ def some_attribute(value, key, vars)
23
+ replace = vars[key.to_sym]
24
+ push_hash(key,
25
+ replace ? value.gsub(replace, "\#{#{key}}") : value,
26
+ 'attribute')
27
+ end
28
+
29
+ def get_element_raw(element)
30
+ element = element.to_subtype.wd.wd if element.tag_name == 'iframe'
31
+ script = File.read("#{HOME}/large_scripts/element.js")
32
+ engine.execute_script(script, element)
33
+ end
34
+
18
35
  ##
19
36
  # Generating array of hashes representing data of the element
20
37
  def get_element_info(element, vars, depth)
21
- attrs = get_dynamic_attributes(element, vars)
22
- attrs.push get_dynamic_tag(element, vars)
23
- attrs += get_dynamic_text(element, vars)
24
- attrs += get_dynamic_css(element, vars) if depth.to_i.zero? && visual?
25
- attrs.push get_dimensions(element, vars) if depth.to_i.zero? && visual?
38
+ data = get_element_raw(element)
39
+ attrs = get_dynamic_attributes(data['attrs'], vars)
40
+ attrs.push get_dynamic_tag(data['tag'], vars)
41
+ attrs += get_dynamic_text(data['text'], vars)
42
+ attrs += get_dynamic_css(element, vars) if looking?(depth)
43
+ attrs.push get_dimensions(element) if looking?(depth)
26
44
  attrs
27
45
  end
28
46
 
47
+ def looking?(depth)
48
+ depth.to_i.zero? && visual?
49
+ end
50
+
29
51
  ##
30
52
  # Generating data for group of elements
31
53
  def generate_data(result, vars)
@@ -4,20 +4,14 @@ module Locatine
4
4
  # Default settings for search are living here
5
5
  module Defaults
6
6
  private
7
+
7
8
  def default_init_config
8
- { json: './Locatine_files/default.json',
9
- depth: 3,
10
- browser: nil,
11
- learn: ENV['LEARN'].nil? ? false : true,
12
- stability_limit: 10,
13
- scope: 'Default',
14
- tolerance: 67,
15
- visual_search: false,
16
- no_fail: false,
17
- trusted: [],
18
- untrusted: [],
19
- autolearn: nil
20
- }
9
+ { json: './Locatine_files/default.json', depth: 3,
10
+ browser: nil, learn: ENV['LEARN'].nil? ? false : true,
11
+ stability_limit: 10, scope: 'Default',
12
+ tolerance: 67, visual_search: false,
13
+ no_fail: false, trusted: [],
14
+ untrusted: [], autolearn: nil }
21
15
  end
22
16
 
23
17
  def import_browser(browser)
@@ -38,7 +32,7 @@ module Locatine
38
32
 
39
33
  def import_config(config)
40
34
  config.each_pair do |key, value|
41
- self.instance_variable_set("@#{key.to_s}", value)
35
+ instance_variable_set("@#{key}", value)
42
36
  end
43
37
  end
44
38
  end
@@ -20,6 +20,7 @@ module Locatine
20
20
 
21
21
  def what_was_selected(element, attributes, vars)
22
22
  tag, index = tag_index
23
+ # TODO: ELEMENT COULD BE ALREADY LOST HERE. WE HAVE BUG AROUND THAT CODE
23
24
  send_to_app('locatineconfirmed', 'ok')
24
25
  mass_highlight_turn(element, false) if element
25
26
  element, attributes = working_on_selected(tag, index, vars, attributes)
@@ -54,7 +54,7 @@ module Locatine
54
54
  def working_on_selected(tag, index, vars, attributes)
55
55
  send_working(tag, index)
56
56
  element, new_attributes = selected_element(tag, index, vars, attributes)
57
- warn_dropping(tag, index) unless element
57
+ warn_dropping(tag, index) unless element[0].locate.located?
58
58
 
59
59
  warn_type(tag) if @type && !element
60
60
 
@@ -8,57 +8,60 @@ module Locatine
8
8
  module FindByGuess
9
9
  private
10
10
 
11
- def main_guess(name)
11
+ def all_similar(name, page, vars)
12
12
  all = []
13
- name.split(' ').each do |part|
14
- all += guess_by_part(part)
13
+ array = generate_hash_array(name)
14
+ array.each do |hash|
15
+ all += catch(page, hash, vars, 0)
15
16
  end
16
17
  all
17
18
  end
18
19
 
19
- def guess_by_part(part)
20
- all = []
21
- tag_xpath = "//#{part}#{not_magic_div}"
22
- text_xpath = "//*[contains(text(),'#{part}')]#{not_magic_div}"
23
- attr_xpath = "//*[@*[contains(., '#{part}')]]#{not_magic_div}"
24
- all += find_by_locator(xpath: tag_xpath).to_a
25
- all += find_by_locator(xpath: text_xpath).to_a
26
- all += find_by_locator(xpath: attr_xpath).to_a
27
- all
20
+ def all_suggested(all, name, scope)
21
+ if all.empty?
22
+ send_no_guess(name, scope)
23
+ return nil
24
+ end
25
+ suggested = most_common_of(all).map do |element|
26
+ engine.elements(tag_name: element['tag'])[element['index'].to_i]
27
+ end
28
+ send_no_guess(name, scope) if suggested.length > 1
29
+ suggested
28
30
  end
29
31
 
30
- def full_guess(all, vars, name)
31
- max = all.count(all.max_by { |i| all.count(i) })
32
- if max >= name.split(' ').length
33
- guess = (all.select { |i| all.count(i) == max }).uniq
34
- guess_data = generate_data(guess, vars)
35
- found_by_data = find_by_data(guess_data, vars)
36
- end
37
- return found_by_data, guess_data.to_h
32
+ def main_guess(name, scope, page, vars)
33
+ all = all_similar(name, page, vars)
34
+ all_suggested(all, name, scope)
38
35
  end
39
36
 
40
- def check_guess(all, vars, name, scope)
41
- guess, guess_data = full_guess(all, vars, name)
42
- if guess.nil? || (engine.elements.length / guess.length <= 4)
43
- send_no_guess(name, scope)
44
- guess = nil
45
- guess_data = {}
46
- else
47
- send_has_guess(guess.length, name, scope)
37
+ def guessing(name, scope, page, vars)
38
+ suggested = main_guess(name, scope, page, vars)
39
+ suggest, attributes = final_of_all(suggested, vars) if suggested
40
+ return suggest, attributes
41
+ end
42
+
43
+ def find_by_guess(scope, name, vars, iteration = 0)
44
+ html = take_html
45
+ page = take_dom
46
+ suggest, attributes = guessing(name, scope, page, vars)
47
+ if html != take_html && iteration < 5
48
+ return find_by_guess(scope, name, vars, iteration + 1)
48
49
  end
49
- return guess, guess_data
50
+
51
+ warn_highly_unstable if iteration == 5
52
+ send_has_guess(name, scope) if suggest
53
+ return suggest, attributes.to_h
50
54
  end
51
55
 
52
- def find_by_guess(scope, name, vars)
53
- @cold_time = 0
54
- all = main_guess(name)
55
- if all.empty?
56
- send_no_guess(name, scope)
57
- else
58
- guess, guess_data = check_guess(all, vars, name, scope)
56
+ def generate_hash_array(name)
57
+ array = []
58
+ name.split(' ').each do |part|
59
+ array.push push_hash(part, '', 'attribute')
60
+ array.push push_hash('', part, 'attribute')
61
+ array.push push_hash('text', part, 'text')
62
+ array.push push_hash('tag', part, 'tag')
59
63
  end
60
- @cold_time = nil
61
- return guess, guess_data.to_h
64
+ array
62
65
  end
63
66
  end
64
67
  end
@@ -49,36 +49,6 @@ module Locatine
49
49
  correct_method_detected(results)
50
50
  end
51
51
 
52
- ##
53
- # Getting elements by tag
54
- def find_by_tag(hash, vars, depth = 0)
55
- correction = '//*' if depth.to_i > 0
56
- xpath = "//*[self::#{process_string(hash['value'], vars)}]"
57
- find_by_locator(xpath: "#{xpath}#{correction}#{not_magic_div}")
58
- end
59
-
60
- ##
61
- # Getting elements by text
62
- def find_by_text(hash, vars, depth = 0)
63
- correction = '//*' if depth.to_i > 0
64
- value = process_string(hash['value'], vars)
65
- xpath = "//*[contains(text(), '#{value}')]"
66
- find_by_locator(xpath: "#{xpath}#{correction}#{not_magic_div}")
67
- end
68
-
69
- ##
70
- # Getting elements by attribute
71
- def find_by_attribute(hash, vars, depth = 0)
72
- correction = '//*' if depth.to_i > 0
73
- full_part = '//*[@*'
74
- hash['name'].split('_').each do |part|
75
- full_part += "[contains(name(), '#{part}')]"
76
- end
77
- value = process_string(hash['value'], vars)
78
- xpath = full_part + "[contains(., '#{value}')]]"
79
- find_by_locator(xpath: "#{xpath}#{correction}#{not_magic_div}")
80
- end
81
-
82
52
  ##
83
53
  # Getting all the elements via stored information
84
54
  def find_by_data(data, vars)
@@ -7,13 +7,34 @@ module Locatine
7
7
 
8
8
  ##
9
9
  # Getting all the elements via black magic
10
- def find_by_magic(name, scope, data, vars)
10
+ def find_by_magic(name, scope, data, vars, iteration = 0)
11
+ html = take_html
12
+ page = take_dom
13
+ suggested = magic_elements(name, scope, data, vars, page)
14
+ warn_unstable if page_changed?(page, html)
15
+ if html != take_html && iteration < 5
16
+ return find_by_magic(name, scope, data, vars, iteration + 1)
17
+ end
18
+
19
+ warn_highly_unstable if iteration == 5
20
+ suggest_by_all(suggested, data, vars, name, scope)
21
+ end
22
+
23
+ def page_changed?(page, html)
24
+ html != take_html || page != take_dom
25
+ end
26
+
27
+ ##
28
+ # We are taking every element that look at least a bit similar to one we
29
+ # are looking for
30
+ def magic_elements(name, scope, data, vars, page)
11
31
  warn_element_lost(name, scope)
12
- @cold_time = 0
13
- all = all_options(data, vars)
14
- @cold_time = nil
32
+ all = select_from_page(page, data, vars)
15
33
  raise_not_found(name, scope) if all.empty? && !@current_no_f
16
- suggest_by_all(all, data, vars, name, scope)
34
+ suggested = most_common_of(all).map do |element|
35
+ engine.elements(tag_name: element['tag'])[element['index'].to_i]
36
+ end
37
+ suggested
17
38
  end
18
39
 
19
40
  def similar_enough(data, attributes)
@@ -23,16 +44,14 @@ module Locatine
23
44
  sameness >= 100 - @current_t
24
45
  end
25
46
 
26
- def best_of_all(all, vars)
27
- max = all.count(all.max_by { |i| all.count(i) })
28
- suggest = (all.select { |i| all.count(i) == max }).uniq unless max.zero?
29
- attributes = generate_data(suggest, vars) unless suggest.nil?
47
+ def final_of_all(suggest, vars)
48
+ attributes = generate_data(suggest, vars) unless suggest.empty?
30
49
  return suggest, attributes
31
50
  end
32
51
 
33
52
  def suggest_by_all(all, data, vars, name, scope)
34
- suggest, attributes = best_of_all(all, vars)
35
- ok = similar_enough(data, attributes) unless suggest.nil?
53
+ suggest, attributes = final_of_all(all, vars)
54
+ ok = similar_enough(data, attributes) unless suggest.empty?
36
55
  raise_not_similar(name, scope) if !ok && !@current_no_f
37
56
  if ok
38
57
  warn_lost_found(name, scope)
@@ -41,76 +60,6 @@ module Locatine
41
60
  warn_not_found(name, scope)
42
61
  return nil, nil
43
62
  end
44
-
45
- def all_options(data, vars)
46
- all = []
47
- data.each_pair do |depth, array|
48
- get_trusted(array).each do |hash|
49
- all += one_option_array(hash, vars, depth).to_a
50
- end
51
- end
52
- all += full_find_by_css(data, vars) if visual?
53
- all += find_by_dimensions(data, vars) if visual?
54
- all
55
- end
56
-
57
- def min_max_by_size(middle, size)
58
- min = middle - (size.to_i * (200 - @current_t)) / 200
59
- max = middle + (size.to_i * (200 - @current_t)) / 200
60
- return min, max
61
- end
62
-
63
- def middle(sizes)
64
- x = sizes[0].to_i + (sizes[2].to_i / 2)
65
- y = sizes[1].to_i + (sizes[3].to_i / 2)
66
- return x, y
67
- end
68
-
69
- def dimension_search_field(sizes)
70
- x, y = middle(sizes)
71
- x_min, x_max = min_max_by_size(x, sizes[2])
72
- y_min, y_max = min_max_by_size(y, sizes[3])
73
- return x_min, x_max, y_min, y_max
74
- end
75
-
76
- def retrieve_mesures(data)
77
- size = window_size
78
- dimensions = data['0'].map do |i|
79
- i if (i['type'] == 'dimensions') && (i['name'] == size)
80
- end
81
- dimensions.compact
82
- end
83
-
84
- def sizez_from_dimensions(dimensions, vars)
85
- result = []
86
- dimensions.first['value'].split('*').each do |value|
87
- result.push(process_string(value, vars))
88
- end
89
- result
90
- end
91
-
92
- def find_by_dimensions(data, vars)
93
- dimensions = retrieve_mesures(data)
94
- if !dimensions.empty?
95
- sizes = sizez_from_dimensions(dimensions, vars)
96
- xmi, xma, ymi, yma = dimension_search_field(sizes)
97
- script = File.read("#{HOME}/large_scripts/dimensions.js")
98
- engine.execute_script(script, xmi, xma, ymi, yma).compact
99
- else
100
- []
101
- end
102
- end
103
-
104
- def one_option_array(hash, vars, depth)
105
- case hash['type']
106
- when 'tag'
107
- find_by_tag(hash, vars, depth)
108
- when 'text'
109
- find_by_text(hash, vars, depth)
110
- when 'attribute'
111
- find_by_attribute(hash, vars, depth)
112
- end
113
- end
114
63
  end
115
64
  end
116
65
  end
@@ -51,8 +51,9 @@ module Locatine
51
51
  end
52
52
 
53
53
  def locator_search(locator, vars)
54
- result = find_by_locator(locator) if locator != {}
54
+ result = find_by_locator(locator) unless locator == {}
55
55
  attributes = generate_data(result, vars) if result
56
+ warn_broken_locator(locator) if locator.to_h != {} && !result
56
57
  return result, attributes
57
58
  end
58
59
 
@@ -16,6 +16,11 @@ module Locatine
16
16
  (@iframe || @browser)
17
17
  end
18
18
 
19
+ def take_html
20
+ engine.locate
21
+ engine.html
22
+ end
23
+
19
24
  def time
20
25
  t = Time.now
21
26
  "#{t.year}.#{t.month}.#{t.day} #{t.hour.to_s.rjust(2, '0')}:"\
@@ -90,6 +95,13 @@ module Locatine
90
95
  raise_no_var(thevar) unless value
91
96
  process_string(str.gsub('#{' + thevar + '}', value.to_s), vars)
92
97
  end
98
+
99
+ def most_common_of(all)
100
+ max = all.count(all.max_by { |i| all.count(i) })
101
+ return (all.select { |i| all.count(i) == max }).uniq unless max.zero?
102
+
103
+ []
104
+ end
93
105
  end
94
106
  end
95
107
  end
@@ -0,0 +1,126 @@
1
+ module Locatine
2
+ module ForSearch
3
+ ##
4
+ # Methods about getting full information about opened page>
5
+ # And methods for stalkibg around the page in oreder to find something.
6
+ module PageWork
7
+ private
8
+
9
+ def matcher
10
+ { 'tag' => ->(data) { take_by_tag(*data) },
11
+ 'text' => ->(data) { take_by_text(*data) },
12
+ 'attribute' => ->(data) { take_by_attribute(*data) },
13
+ 'css' => ->(data) { take_by_css(*data) } }
14
+ end
15
+
16
+ def take_dom
17
+ script = File.read("#{HOME}/large_scripts/page.js")
18
+ engine.execute_script(script)
19
+ end
20
+
21
+ def select_from_page(page, data, vars)
22
+ all = [] # No result is a valid result too
23
+ data.each_pair do |depth, array|
24
+ get_trusted(array).each do |hash|
25
+ all += catch(page, hash, vars, depth)
26
+ end
27
+ end
28
+ all
29
+ end
30
+
31
+ def catch(page, hash, vars, depth)
32
+ all = []
33
+ hash['value'] = process_string(hash['value'], vars)
34
+ page.each do |element|
35
+ all += take_match(element, depth, hash, vars)
36
+ all += catch(element['children'], hash, vars, depth)
37
+ end
38
+ all.uniq
39
+ end
40
+
41
+ def take_match(element, depth, hash, vars)
42
+ if hash['type'] == 'dimensions'
43
+ return take_by_dimensions(hash, element, depth, vars)
44
+ end
45
+
46
+ matcher.fetch(hash['type']).call([hash, element, depth])
47
+ end
48
+
49
+ def take_by_tag(hash, elt, depth)
50
+ return kids([elt], depth) if elt['tag'].downcase.include?(hash['value'])
51
+
52
+ []
53
+ end
54
+
55
+ def take_by_text(hash, elt, depth)
56
+ return kids([elt], depth) if elt['text'].include?(hash['value'])
57
+
58
+ []
59
+ end
60
+
61
+ def take_attribute_check(hash, elt)
62
+ if !hash['name'].to_s.empty? && !hash['value'].to_s.empty?
63
+ return elt['attrs'][hash['name']].to_s
64
+ end
65
+
66
+ elt['attrs'].to_s
67
+ end
68
+
69
+ def take_by_attribute(hash, elt, depth)
70
+ str = hash['value'].to_s.empty? ? hash['name'].to_s : hash['value'].to_s
71
+ ok = take_attribute_check(hash, elt).include?(str)
72
+ return kids([elt], depth) if ok
73
+
74
+ []
75
+ end
76
+
77
+ def dimensions_for_search(hash, vars)
78
+ values = hash['value'].split('*').map(&:to_i)
79
+ values[0] = vars[:x].to_i if vars[:x]
80
+ values[1] = vars[:y].to_i if vars[:y]
81
+ values
82
+ end
83
+
84
+ def dimensions_from_page(elt)
85
+ [elt['coordinates']['top'].to_i, elt['coordinates']['bottom'].to_i,
86
+ elt['coordinates']['left'].to_i, elt['coordinates']['right'].to_i]
87
+ end
88
+
89
+ def take_by_dimensions(hash, elt, depth, vars)
90
+ return [] if !visual? || hash['name'] != window_size
91
+
92
+ return kids([elt], depth) if in_recatngle?(hash, elt, vars)
93
+
94
+ []
95
+ end
96
+
97
+ def in_recatngle?(hash, elt, vars)
98
+ cleft, ctop, cwidth, cheight = dimensions_for_search(hash, vars)
99
+ top, bottom, left, right = dimensions_from_page(elt)
100
+ (cleft >= left) && (cleft + cwidth <= right) &&
101
+ (ctop >= top) && (ctop + cheight <= bottom)
102
+ end
103
+
104
+ def take_by_css(hash, elt, depth)
105
+ return [] unless visual?
106
+
107
+ string = "#{hash['name']}: #{hash['value']}"
108
+ return kids([elt], depth) if elt['style'].include?(string)
109
+
110
+ []
111
+ end
112
+
113
+ # If depth != 0 we should return all children subchildren.
114
+ def kids(array, depth)
115
+ answer = []
116
+ return array if depth.to_i.zero?
117
+
118
+ array.each do |one|
119
+ answer += one['children']
120
+ answer += kids(one['children'], depth)
121
+ end
122
+ answer
123
+ end
124
+ end
125
+ end
126
+ end
@@ -68,8 +68,8 @@ module Locatine
68
68
  push_title "Locatine has no good guess for #{name} in #{scope}."
69
69
  end
70
70
 
71
- def send_has_guess(length, name, scope)
72
- push_title "#{length} #{verb(length)} guessed as #{name} in #{scope}."
71
+ def send_has_guess(name, scope)
72
+ push_title "Something is guessed as #{name} in #{scope}."
73
73
  end
74
74
 
75
75
  def send_selecting(name, scope)
@@ -137,6 +137,19 @@ module Locatine
137
137
  send_warn "Something was found as #{data} but we cannot highlight it"
138
138
  end
139
139
 
140
+ def warn_broken_locator(locator)
141
+ send_warn "Can find nothing using #{locator}"
142
+ end
143
+
144
+ def warn_unstable
145
+ send_warn 'It seems that page is unstable. It may lead to problems '\
146
+ 'with resolving elements'
147
+ end
148
+
149
+ def warn_highly_unstable
150
+ send_warn 'It seems that page is HIGHLY unstable. No guaranties now.'
151
+ end
152
+
140
153
  def warn_much_highlight(size)
141
154
  send_warn "Only the first 50 elements of #{size} were highlighted."
142
155
  end
@@ -18,7 +18,7 @@ module Locatine
18
18
  max = (array.max_by { |i| i['stability'].to_i }) if array
19
19
  return max['stability'] if max
20
20
 
21
- return 0
21
+ 0
22
22
  end
23
23
 
24
24
  def generate_xpath(data, vars)
@@ -41,16 +41,9 @@ module Locatine
41
41
  when 'text'
42
42
  "[contains(text(), '#{value}')]"
43
43
  when 'attribute'
44
- generate_xpath_part_from_attribute(hash, value)
44
+ "[contains(@#{hash['name']}, '#{value}')]"
45
45
  end
46
46
  end
47
-
48
- def generate_xpath_part_from_attribute(hash, value)
49
- full = '[@*'
50
- hash['name'].split('_')
51
- .each { |part| full += "[contains(name(), '#{part}')]" }
52
- full + "[contains(., '#{value}')]]"
53
- end
54
47
  end
55
48
  end
56
49
  end
@@ -0,0 +1,31 @@
1
+
2
+ function one_element(target){
3
+ console.log("TARGET ==", target);
4
+
5
+ let element = {};
6
+ let attribute = {};
7
+
8
+ element = {attrs: [], text: "", tag: ""};
9
+ if (target.childNodes){
10
+ for (let i = 0; i < target.childNodes.length; ++i){
11
+ if (target.childNodes[i].nodeType === 3){
12
+ element.text += target.childNodes[i].textContent;
13
+ }
14
+ }
15
+ } else {
16
+ element.text = target.textContent
17
+ }
18
+ element.tag = target.tagName.toLowerCase();
19
+ let atts = target.attributes;
20
+ if (atts) {
21
+ for (var k = 0, n = atts.length; k < n; k++){
22
+ att = atts[k];
23
+ attribute = {};
24
+ attribute[att.nodeName] = att.nodeValue;
25
+ element.attrs.push(attribute);
26
+ }
27
+ }
28
+ return element;
29
+ }
30
+ let x = one_element(arguments[0]);
31
+ return x;
@@ -0,0 +1,60 @@
1
+
2
+ function walk(elm) {
3
+ let node;
4
+
5
+ const tagName = elm.tagName.toLowerCase();
6
+ const array = Array.prototype.slice.call( document.getElementsByTagName(tagName) );
7
+ const index = array.indexOf(elm);
8
+ const relative = elm.getBoundingClientRect();
9
+
10
+ // init item
11
+ const item = {tag: tagName,
12
+ index: index,
13
+ style: getComputedStyle(elm).cssText,
14
+ text: "",
15
+ attrs: {},
16
+ coordinates: {top:0, bottom:0, left:0, right:0},
17
+ children: []};
18
+
19
+ // text for item
20
+ if (elm.childNodes) {
21
+ for (let z = 0; z < elm.childNodes.length; ++z){
22
+ if (elm.childNodes[z].nodeType === 3){
23
+ item.text += elm.childNodes[z].textContent;
24
+ }
25
+ }
26
+ } else {
27
+ item.text = elm.textContent
28
+ }
29
+
30
+ // attributes for item
31
+ atts = elm.attributes;
32
+ if (atts) {
33
+ for (var att, k = 0, n = atts.length; k < n; k++){
34
+ att = atts[k];
35
+ item.attrs[att.nodeName] = att.nodeValue;
36
+ }
37
+ }
38
+
39
+ item.coordinates.top = relative["top"] + window.scrollY;
40
+ item.coordinates.bottom = relative["bottom"] + window.scrollY;
41
+ item.coordinates.left = relative["left"] + window.scrollX;
42
+ item.coordinates.right = relative["right"] + window.scrollX;
43
+
44
+ // Handle child elements (not magic ones)
45
+ for (node = elm.firstChild; node; node = node.nextSibling) {
46
+ if (node.nodeType === 1) { // 1 == Element
47
+ if (node.attributes['id']) {
48
+ if (node.attributes['id'].value !== 'locatine_magic_div') {
49
+ item.children.push(walk(node))
50
+ }
51
+ } else {
52
+ item.children.push(walk(node))
53
+ }
54
+ }
55
+ }
56
+
57
+ return item;
58
+ }
59
+ let result = walk(document.body);
60
+ return [result];
@@ -10,11 +10,11 @@ require 'locatine/for_search/saying'
10
10
  require 'locatine/for_search/helpers'
11
11
  require 'locatine/for_search/defaults'
12
12
  require 'locatine/for_search/file_work'
13
+ require 'locatine/for_search/page_work'
13
14
  require 'locatine/for_search/listening'
14
15
  require 'locatine/for_search/highlight'
15
16
  require 'locatine/for_search/data_logic'
16
17
  require 'locatine/for_search/find_logic'
17
- require 'locatine/for_search/find_by_css'
18
18
  require 'locatine/for_search/name_helper'
19
19
  require 'locatine/for_search/dialog_logic'
20
20
  require 'locatine/for_search/find_by_magic'
@@ -36,11 +36,11 @@ module Locatine
36
36
  include Locatine::ForSearch::Helpers
37
37
  include Locatine::ForSearch::Defaults
38
38
  include Locatine::ForSearch::FileWork
39
+ include Locatine::ForSearch::PageWork
39
40
  include Locatine::ForSearch::DataLogic
40
41
  include Locatine::ForSearch::Listening
41
42
  include Locatine::ForSearch::FindLogic
42
43
  include Locatine::ForSearch::Highlight
43
- include Locatine::ForSearch::FindByCss
44
44
  include Locatine::ForSearch::NameHelper
45
45
  include Locatine::ForSearch::FindByMagic
46
46
  include Locatine::ForSearch::DialogLogic
@@ -1,6 +1,6 @@
1
1
  module Locatine
2
2
  # constants here...
3
- VERSION = '0.02535'.freeze
3
+ VERSION = '0.02539'.freeze
4
4
  NAME = 'locatine'.freeze
5
5
  HOME = if File.readable?("#{Dir.pwd}/lib/#{Locatine::NAME}")
6
6
  "#{Dir.pwd}/lib/#{Locatine::NAME}"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: locatine
3
3
  version: !ruby/object:Gem::Version
4
- version: '0.02535'
4
+ version: '0.02539'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sergei Seleznev
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-06-20 00:00:00.000000000 Z
11
+ date: 2019-09-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -142,7 +142,6 @@ files:
142
142
  - lib/locatine/for_search/dialog_logic.rb
143
143
  - lib/locatine/for_search/element_selection.rb
144
144
  - lib/locatine/for_search/file_work.rb
145
- - lib/locatine/for_search/find_by_css.rb
146
145
  - lib/locatine/for_search/find_by_guess.rb
147
146
  - lib/locatine/for_search/find_by_locator.rb
148
147
  - lib/locatine/for_search/find_by_magic.rb
@@ -152,11 +151,14 @@ files:
152
151
  - lib/locatine/for_search/listening.rb
153
152
  - lib/locatine/for_search/merge.rb
154
153
  - lib/locatine/for_search/name_helper.rb
154
+ - lib/locatine/for_search/page_work.rb
155
155
  - lib/locatine/for_search/public.rb
156
156
  - lib/locatine/for_search/saying.rb
157
157
  - lib/locatine/for_search/xpath_generator.rb
158
158
  - lib/locatine/large_scripts/css.js
159
159
  - lib/locatine/large_scripts/dimensions.js
160
+ - lib/locatine/large_scripts/element.js
161
+ - lib/locatine/large_scripts/page.js
160
162
  - lib/locatine/scope.rb
161
163
  - lib/locatine/search.rb
162
164
  - lib/locatine/version.rb
@@ -1,47 +0,0 @@
1
- module Locatine
2
- module ForSearch
3
- ##
4
- # Looking for elements by css values
5
- module FindByCss
6
- private
7
-
8
- def css_array_by_data(data, vars)
9
- q_css = []
10
- get_trusted(data['0']).each do |hash|
11
- if hash['type'] == 'css'
12
- value = process_string(hash['value'], vars) if vars[hash['name']]
13
- q_css.push("#{hash['name']}: #{value || hash['value']}")
14
- end
15
- end
16
- q_css
17
- end
18
-
19
- def return_caught_elements(caught)
20
- all = []
21
- caught.each do |i|
22
- @help_hash[i[0]] ||= engine.elements(tag_name: i[0].downcase).to_a
23
- elm = @help_hash[i[0]][i[1].to_i]
24
- all.push(elm) if elm
25
- end
26
- all
27
- end
28
-
29
- def select_elements_from_raws_by_css(q_css, raws)
30
- all = []
31
- @help_hash = {}
32
- q_css.each do |item|
33
- caught = (raws.select { |i| i[2].include?(item) })
34
- all += return_caught_elements(caught)
35
- end
36
- all
37
- end
38
-
39
- def full_find_by_css(data, vars)
40
- q_css = css_array_by_data(data, vars)
41
- script = File.read("#{HOME}/large_scripts/css.js")
42
- raws = engine.execute_script(script)
43
- select_elements_from_raws_by_css(q_css, raws)
44
- end
45
- end
46
- end
47
- end