marta 0.37396 → 0.41245
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/README.md +42 -19
- data/example_project/p_object/test_page.rb +2 -1
- data/example_project/project_itself/iframe.html +5 -0
- data/{lib/marta/data/test.html → example_project/project_itself/index.html} +1 -1
- data/example_project/spec/p_object/pageobjects/MartaTestPage.json +707 -124
- data/example_project/spec/p_object/pageobjects/TheIframe.json +70 -14
- data/example_project/spec/spec_helper.rb +3 -1
- data/lib/marta/black_magic.rb +59 -13
- data/lib/marta/data/element.html +4 -15
- data/lib/marta/data/element.js +25 -226
- data/lib/marta/data/style.css +2 -2
- data/lib/marta/dialogs.rb +52 -4
- data/lib/marta/element_information.rb +86 -0
- data/lib/marta/injector.rb +2 -2
- data/lib/marta/json_2_class.rb +1 -1
- data/lib/marta/lightning.rb +1 -0
- data/lib/marta/marta_app/content.js +8 -0
- data/lib/marta/marta_app/devtools.html +1 -0
- data/lib/marta/marta_app/devtools.js +5 -0
- data/lib/marta/marta_app/manifest.json +3 -2
- data/lib/marta/options_and_paths.rb +1 -10
- data/lib/marta/page_arithmetic.rb +85 -97
- data/lib/marta/public_methods.rb +5 -4
- data/lib/marta/read_write.rb +50 -1
- data/lib/marta/server.rb +0 -18
- data/lib/marta/simple_element_finder.rb +0 -19
- data/lib/marta/version.rb +1 -1
- data/lib/marta/x_path.rb +154 -139
- metadata +7 -3
data/lib/marta/data/style.css
CHANGED
@@ -158,7 +158,7 @@ div[martaclass=marta_div] {
|
|
158
158
|
outline: 2px solid #bbbbbb;
|
159
159
|
background-color: lightgray;
|
160
160
|
position : relative;
|
161
|
-
z-index :
|
161
|
+
z-index : 2147483647;
|
162
162
|
padding: 0;
|
163
163
|
margin: 0px 0px 0px 0px;
|
164
164
|
overflow-y: scroll;
|
@@ -228,7 +228,7 @@ div[martastyle=at_large] {
|
|
228
228
|
width: 100%;
|
229
229
|
pointer-events: visible;
|
230
230
|
display: block;
|
231
|
-
z-index:
|
231
|
+
z-index: 2147483646;
|
232
232
|
}
|
233
233
|
|
234
234
|
div[martastyle=off] {
|
data/lib/marta/dialogs.rb
CHANGED
@@ -4,6 +4,7 @@ require 'marta/lightning'
|
|
4
4
|
require 'marta/injector'
|
5
5
|
require 'marta/public_methods'
|
6
6
|
require 'marta/page_arithmetic'
|
7
|
+
require 'marta/element_information'
|
7
8
|
|
8
9
|
module Marta
|
9
10
|
|
@@ -23,7 +24,7 @@ module Marta
|
|
23
24
|
class MethodSpeaker
|
24
25
|
|
25
26
|
include XPath, Lightning, Injector, PublicMethods, SimpleElementFinder,
|
26
|
-
PageArithmetic
|
27
|
+
PageArithmetic, ElementInformation
|
27
28
|
|
28
29
|
def initialize(method_name, requestor)
|
29
30
|
@class_name = requestor.class_name
|
@@ -83,8 +84,7 @@ module Marta
|
|
83
84
|
def attrs_plus_result
|
84
85
|
if !attrs_exists?
|
85
86
|
@attrs = @result
|
86
|
-
elsif !@
|
87
|
-
!@result['options']['collection']
|
87
|
+
elsif !@result['options']['collection']
|
88
88
|
@attrs = @result
|
89
89
|
else
|
90
90
|
@attrs = make_collection(@attrs, @result)
|
@@ -93,7 +93,17 @@ module Marta
|
|
93
93
|
|
94
94
|
# Asking: "What are you looking for?"
|
95
95
|
def ask_for_elements
|
96
|
-
ask 'element', "Found #{@found} elements for #{@title}", @attrs
|
96
|
+
answer = ask 'element', "Found #{@found} elements for #{@title}", @attrs
|
97
|
+
return answer.class == Hash ? answer_to_hash(answer) : answer
|
98
|
+
end
|
99
|
+
|
100
|
+
# Creating new fashioned hash out of data
|
101
|
+
def answer_to_hash(answer)
|
102
|
+
result = method_structure
|
103
|
+
result['options']['collection'] = answer['collection']
|
104
|
+
what = answer['exclude'] ? 'negative' : 'positive'
|
105
|
+
result[what] = get_attributes(answer['element'])
|
106
|
+
result
|
97
107
|
end
|
98
108
|
|
99
109
|
# Creating data to save when it is a basically defined element
|
@@ -173,8 +183,46 @@ module Marta
|
|
173
183
|
def user_method_dialogs(method_name)
|
174
184
|
dialog_master = MethodSpeaker.new(method_name, self)
|
175
185
|
data = dialog_master.dialog
|
186
|
+
data['meths'][method_name] =
|
187
|
+
dynamise_method(data['vars'], data['meths'][method_name])
|
176
188
|
file_write(self.class_name.to_s, data)
|
177
189
|
data
|
178
190
|
end
|
191
|
+
|
192
|
+
# Massive gsub for attribute
|
193
|
+
def dynamise(variable_name, what)
|
194
|
+
what.each do |entry|
|
195
|
+
entry.each do |value|
|
196
|
+
value.gsub!(self.instance_variable_get("@#{variable_name}"),
|
197
|
+
'#{@' + variable_name + '}')
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
# Marta will search for page variables in attributes of element in order
|
203
|
+
# to create dynamic element by itself. It must be splited. And moved.
|
204
|
+
def dynamise_method(vars, method)
|
205
|
+
vars.each_pair do |variable_name, variable|
|
206
|
+
if variable_name.include?('text')
|
207
|
+
dynamise variable_name, [method['positive']['self']['text'],
|
208
|
+
method['positive']['pappy']['text'],
|
209
|
+
method['positive']['granny']['text'],
|
210
|
+
method['negative']['self']['text'],
|
211
|
+
method['negative']['pappy']['text'],
|
212
|
+
method['negative']['granny']['text']]
|
213
|
+
else
|
214
|
+
[method['positive'], method['negative']].each do |method|
|
215
|
+
method.each_pair do |level, content|
|
216
|
+
content['attributes'].each_pair do |attribute_name, values|
|
217
|
+
if variable_name.include?(attribute_name)
|
218
|
+
dynamise variable_name, [values]
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
222
|
+
end
|
223
|
+
end
|
224
|
+
end
|
225
|
+
method
|
226
|
+
end
|
179
227
|
end
|
180
228
|
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
module Marta
|
2
|
+
|
3
|
+
# Marta is creating a hash of element data. For now it stores
|
4
|
+
# tag, text, and all the attributes.
|
5
|
+
module ElementInformation
|
6
|
+
|
7
|
+
private
|
8
|
+
|
9
|
+
#
|
10
|
+
# We are using helper class which can parse element attributes to our
|
11
|
+
# special hash format.
|
12
|
+
#
|
13
|
+
# @note It is believed that no user will use it
|
14
|
+
class ElementHelper
|
15
|
+
|
16
|
+
def initialize(requestor)
|
17
|
+
@engine = requestor.engine
|
18
|
+
end
|
19
|
+
|
20
|
+
# We can get data of the element or data of any parent.
|
21
|
+
def get_element_info(element, parent_count = 0)
|
22
|
+
parent = ''
|
23
|
+
parent_count.times do
|
24
|
+
parent = parent + '.parentElement'
|
25
|
+
end
|
26
|
+
result = Hash.new
|
27
|
+
attr_script = %Q[
|
28
|
+
var s = {};
|
29
|
+
var attrs = arguments[0]#{parent}.attributes;
|
30
|
+
for (var l = 0; l < attrs.length; ++l) {
|
31
|
+
var a = attrs[l]; s[a.name] = a.value.split(" ");
|
32
|
+
} ;
|
33
|
+
return s;]
|
34
|
+
tag_script = "return arguments[0]#{parent}.tagName"
|
35
|
+
text_script = %Q[
|
36
|
+
if (arguments[0]#{parent}.textContent == arguments[0]#{parent}.innerHTML)
|
37
|
+
{return arguments[0]#{parent}.textContent} else {return ''};]
|
38
|
+
result['tag'] = [@engine.execute_script(tag_script, element)]
|
39
|
+
txt = @engine.execute_script(text_script, element)
|
40
|
+
result['text'] = txt != '' ? [txt] : []
|
41
|
+
result['attributes'] = @engine.execute_script(attr_script, element)
|
42
|
+
result['attributes'].each_pair do |attribute, value|
|
43
|
+
value.uniq!
|
44
|
+
end
|
45
|
+
return result
|
46
|
+
end
|
47
|
+
|
48
|
+
# That class is also stores an empty special format hash.
|
49
|
+
def self.method_structure(collection = false)
|
50
|
+
return {'options' => {'collection' => collection},
|
51
|
+
'positive' => {
|
52
|
+
'self' => {
|
53
|
+
'text'=>[], 'tag' => [], 'attributes' => {}},
|
54
|
+
'pappy' => {
|
55
|
+
'text'=>[], 'tag' => [], 'attributes' => {}},
|
56
|
+
'granny' => {
|
57
|
+
'text'=>[], 'tag' => [], 'attributes' => {}}},
|
58
|
+
'negative' => {
|
59
|
+
'self' => {
|
60
|
+
'text'=>[], 'tag' => [], 'attributes' => {}},
|
61
|
+
'pappy' => {
|
62
|
+
'text'=>[], 'tag' => [], 'attributes' => {}},
|
63
|
+
'granny' => {
|
64
|
+
'text'=>[], 'tag' => [], 'attributes' => {}}}
|
65
|
+
}
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# We are getting three levels of attributes of element,
|
70
|
+
# parent and grandparent
|
71
|
+
def get_attributes(element, requestor = self)
|
72
|
+
result = Hash.new
|
73
|
+
element_helper = ElementHelper.new requestor
|
74
|
+
result['self'] = element_helper.get_element_info element
|
75
|
+
result['pappy'] = element_helper.get_element_info element, 1
|
76
|
+
result['granny'] = element_helper.get_element_info element, 2
|
77
|
+
return result
|
78
|
+
end
|
79
|
+
|
80
|
+
# We can return the default structure of our special format
|
81
|
+
def method_structure(collection = false)
|
82
|
+
ElementHelper.method_structure collection
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
end
|
data/lib/marta/injector.rb
CHANGED
@@ -127,9 +127,9 @@ module Marta
|
|
127
127
|
result = MartaServer.wait_user_dialog_response
|
128
128
|
# We need double check for iframes here. It should be 100% changed.
|
129
129
|
if !result
|
130
|
-
result = engine.execute_script("return document.marta_confirm_mark")
|
130
|
+
result = @engine.execute_script("return document.marta_confirm_mark")
|
131
131
|
end
|
132
|
-
if (!result and
|
132
|
+
if (!result and !@engine.element(id: 'marta_s_everything').exists?)
|
133
133
|
actual_injection
|
134
134
|
end
|
135
135
|
end
|
data/lib/marta/json_2_class.rb
CHANGED
@@ -104,7 +104,7 @@ module Marta
|
|
104
104
|
|
105
105
|
def build_method(name, content)
|
106
106
|
define_singleton_method name.to_sym do
|
107
|
-
learn_status ? method_edit(name) : marta_magic_finder(content)
|
107
|
+
learn_status ? method_edit(name) : marta_magic_finder(content, name)
|
108
108
|
end
|
109
109
|
exact = name + '_exact'
|
110
110
|
define_singleton_method exact.to_sym do
|
data/lib/marta/lightning.rb
CHANGED
@@ -6,6 +6,13 @@ async function port_set(value){
|
|
6
6
|
});
|
7
7
|
};
|
8
8
|
|
9
|
+
function getSelected(value){
|
10
|
+
document.getElementById('marta_show_html').setAttribute('tag', value.tagName);
|
11
|
+
const x = document.getElementsByTagName(value.tagName);
|
12
|
+
const index = Array.prototype.indexOf.call(x, value);
|
13
|
+
document.getElementById('marta_show_html').setAttribute('index', index);
|
14
|
+
};
|
15
|
+
|
9
16
|
async function port_get(){
|
10
17
|
await chrome.storage.sync.get(['port'], function(result) {
|
11
18
|
port = result.port;
|
@@ -22,6 +29,7 @@ document.addEventListener("marta_send", async function(e) {
|
|
22
29
|
//console.log(port);
|
23
30
|
//console.log(e.detail.port);
|
24
31
|
console.log("Marta is acting back. With port = " + port);
|
32
|
+
console.log("Marta is acting back. With mark = " + e.detail.mark);
|
25
33
|
marta_real_send(e.detail.mark, port);
|
26
34
|
});
|
27
35
|
|
@@ -0,0 +1 @@
|
|
1
|
+
<script src="devtools.js"></script>
|
@@ -1,8 +1,9 @@
|
|
1
1
|
{
|
2
2
|
"name": "Marta app",
|
3
|
-
"version": "0.
|
3
|
+
"version": "0.41245",
|
4
4
|
"description": "Messaging from browser to main app",
|
5
|
-
"
|
5
|
+
"devtools_page": "devtools.html",
|
6
|
+
"permissions": ["activeTab", "http://127.0.0.1*/*", "storage", "contextMenus"],
|
6
7
|
"background": {
|
7
8
|
"scripts": ["background.js"],
|
8
9
|
"persistent": true
|
@@ -158,7 +158,7 @@ module Marta
|
|
158
158
|
|
159
159
|
# Marta uses simple rules to set the tolerancy value
|
160
160
|
def self.set_tolerancy(value)
|
161
|
-
@@tolerancy = parameter_set(@@tolerancy, value,
|
161
|
+
@@tolerancy = parameter_set(@@tolerancy, value, 100000)
|
162
162
|
end
|
163
163
|
|
164
164
|
def self.parameter_check_and_set(where, value, default, expected_class)
|
@@ -246,14 +246,5 @@ module Marta
|
|
246
246
|
SettingMaster.port
|
247
247
|
end
|
248
248
|
|
249
|
-
# Marta can call server easily
|
250
|
-
def server
|
251
|
-
SettingMaster.server
|
252
|
-
end
|
253
|
-
|
254
|
-
# Marta knows was the browser started by she
|
255
|
-
def correct_engine?
|
256
|
-
SettingMaster.correct_engine?
|
257
|
-
end
|
258
249
|
end
|
259
250
|
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'marta/element_information'
|
1
2
|
module Marta
|
2
3
|
|
3
4
|
#
|
@@ -15,126 +16,107 @@ module Marta
|
|
15
16
|
# @note It is believed that no user will use it
|
16
17
|
# Now it has only one way to merge hashes
|
17
18
|
# This method is getting common only of two methods in order to generate a
|
18
|
-
# correct hash for collection element.
|
19
|
-
# esoteric. Refactoring is a must here.
|
19
|
+
# correct hash for collection element.
|
20
20
|
class MethodMerger
|
21
21
|
|
22
|
+
include ElementInformation
|
23
|
+
|
22
24
|
# Class is taking two hashes. Sometimes order is valuable
|
23
25
|
def initialize(main_hash, second_hash)
|
24
26
|
@main_hash = main_hash
|
25
27
|
@second_hash = second_hash
|
26
28
|
end
|
27
29
|
|
28
|
-
POSITIVE = ['self', 'pappy', 'granny']
|
29
|
-
NEGATIVE = ['not_self', 'not_pappy', 'not_granny']
|
30
|
-
|
31
30
|
# Main method for adding two elements into a large-wide collection
|
32
31
|
def do_collection
|
33
|
-
result =
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
32
|
+
result = method_structure
|
33
|
+
# Everything is simple for now with options)
|
34
|
+
result['options'] = @main_hash['options']
|
35
|
+
# If we are adding to collection
|
36
|
+
if @second_hash['positive']['self']['tag'] != []
|
37
|
+
result['positive'] = multiply(@main_hash['positive'],
|
38
|
+
@second_hash['positive'])
|
39
|
+
result['negative'] = extract(@main_hash['negative'],
|
40
|
+
@second_hash['positive'])
|
41
|
+
else # If we are excluding from collection
|
42
|
+
result['positive'] = @main_hash['positive']
|
43
|
+
uniqs = extract(@second_hash['negative'], @main_hash['positive'])
|
44
|
+
result['negative'] = summarize(uniqs, @main_hash['negative'])
|
41
45
|
end
|
42
46
|
result
|
43
47
|
end
|
44
48
|
|
45
|
-
#
|
46
|
-
#
|
47
|
-
#
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
if (@second_hash['options'][key] == value) or
|
57
|
-
((@second_hash['options'][key].nil?) and (!value.nil?))
|
58
|
-
temp[key] = value
|
59
|
-
else
|
60
|
-
temp[key] = "*"
|
61
|
-
end
|
62
|
-
if (second_negative != temp[key]) and
|
63
|
-
((second_negative == main_negative) or
|
64
|
-
(main_negative.nil?))
|
65
|
-
temp["not_#{key}"] = second_negative
|
66
|
-
end
|
67
|
-
end
|
68
|
-
temp
|
49
|
+
# When black magic finds something
|
50
|
+
# she's not trusting dynamic attribute anymore. So she's forgetting
|
51
|
+
# unstable attributes and remembering stable and new ones
|
52
|
+
def forget_unstable
|
53
|
+
result = method_structure
|
54
|
+
result['options'] = @main_hash['options']
|
55
|
+
result['positive'] = merge(@main_hash['positive'],
|
56
|
+
@second_hash['positive'])
|
57
|
+
result['negative'] = extract(@main_hash['negative'],
|
58
|
+
@second_hash['positive'])
|
59
|
+
result
|
69
60
|
end
|
70
61
|
|
71
|
-
#
|
72
|
-
def
|
73
|
-
|
74
|
-
first
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
62
|
+
# Recursive operations with method.
|
63
|
+
def do_arithmetic(first, second, what)
|
64
|
+
what == '+' ? result = second : result = Hash.new
|
65
|
+
first.each_pair do |key, value|
|
66
|
+
if value.is_a? Hash
|
67
|
+
result[key] = do_arithmetic(first[key], second[key], what)
|
68
|
+
elsif !second[key].nil? and !value.nil?
|
69
|
+
if what == '+'
|
70
|
+
result[key] = (first[key] + second[key]).uniq
|
71
|
+
elsif what == '&'
|
72
|
+
result[key] = first[key] & second[key]
|
73
|
+
elsif what == '-'
|
74
|
+
result[key] = first[key] - second[key]
|
75
|
+
elsif what == '*'
|
76
|
+
if (second[key] != [])
|
77
|
+
result[key] = first[key] & second[key]
|
78
|
+
end
|
81
79
|
end
|
82
80
|
end
|
83
|
-
|
84
|
-
|
81
|
+
if (second[key] == [] or second[key].nil?) and
|
82
|
+
((what == '+') or (what == '*'))
|
83
|
+
result[key] = first[key]
|
84
|
+
end
|
85
85
|
end
|
86
|
-
|
86
|
+
result
|
87
87
|
end
|
88
88
|
|
89
|
-
#
|
90
|
-
#
|
91
|
-
#
|
92
|
-
#
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
if !first.nil?
|
97
|
-
temp = first
|
98
|
-
end
|
99
|
-
if !second.nil? and !temp.nil?
|
100
|
-
second.each_pair do |key, value|
|
101
|
-
if (temp[key].nil?) or ((temp[key] != value) and
|
102
|
-
(temp[key].class != Array) and (value.class != Array))
|
103
|
-
temp[key] = value
|
104
|
-
elsif (temp[key].class == Array) and (value.class == Array)
|
105
|
-
temp[key] = (value + temp[key]).uniq
|
106
|
-
end
|
107
|
-
end
|
108
|
-
if !first.nil?
|
109
|
-
first.each_pair do |key, value|
|
110
|
-
if second[key].nil? and !value.nil?
|
111
|
-
temp[key] = nil
|
112
|
-
end
|
113
|
-
end
|
114
|
-
end
|
115
|
-
else
|
116
|
-
temp = second
|
117
|
-
end
|
118
|
-
temp
|
89
|
+
# That is not a real merge. We are leaving everything that is the same
|
90
|
+
# or new and deleting everyting that is not the same
|
91
|
+
#
|
92
|
+
# Idea:
|
93
|
+
# merge({a:[1],b:[2],c:[3]},{a:[1],b:[2,3]}) #=> {a:[1],b:[2],c:[3]}
|
94
|
+
def merge(first, second)
|
95
|
+
do_arithmetic(second, first, '*')
|
119
96
|
end
|
120
97
|
|
121
|
-
#
|
122
|
-
#
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
98
|
+
# Simple adding everyting to everything
|
99
|
+
#
|
100
|
+
# Idea:
|
101
|
+
# summarize({a:[1],c:[4]},{a:[2],b:[3]}) #=> {a:[1,2],b:[3],c:[4]}
|
102
|
+
def summarize(first, second)
|
103
|
+
do_arithmetic(second, do_arithmetic(first, second, '+'), '+')
|
104
|
+
end
|
105
|
+
|
106
|
+
# That will leave only the same options in the result
|
107
|
+
#
|
108
|
+
# Idea:
|
109
|
+
# multiply({a:[1,2],b:[2],c:[5]},{a:[1,3],b:[4],d:[0]}) #=> {a:[1],b:[2]}
|
110
|
+
def multiply(first, second)
|
111
|
+
do_arithmetic(first, second, '&')
|
112
|
+
end
|
113
|
+
|
114
|
+
# That will take out of the result all options of second
|
115
|
+
#
|
116
|
+
# Idea
|
117
|
+
# extract({a:[1,2],b:[2],c:[5]},{a:[2],c:[5],d:[0]}) #=> {a:[1],b:[2]}
|
118
|
+
def extract(first, second)
|
119
|
+
do_arithmetic(first, second, '-')
|
138
120
|
end
|
139
121
|
end
|
140
122
|
|
@@ -143,5 +125,11 @@ module Marta
|
|
143
125
|
merger = MethodMerger.new(one, two)
|
144
126
|
merger.do_collection
|
145
127
|
end
|
128
|
+
|
129
|
+
# Forgetting unstable attributes leaving the same ones and new ones
|
130
|
+
def forget_unstable(old_one, new_one)
|
131
|
+
merger = MethodMerger.new(old_one, new_one)
|
132
|
+
merger.forget_unstable
|
133
|
+
end
|
146
134
|
end
|
147
135
|
end
|