poltergeistFork 0.0.1
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 +7 -0
- data/LICENSE +22 -0
- data/README.md +425 -0
- data/lib/capybara/poltergeist/browser.rb +426 -0
- data/lib/capybara/poltergeist/client.rb +151 -0
- data/lib/capybara/poltergeist/client/agent.coffee +423 -0
- data/lib/capybara/poltergeist/client/browser.coffee +497 -0
- data/lib/capybara/poltergeist/client/cmd.coffee +17 -0
- data/lib/capybara/poltergeist/client/compiled/agent.js +587 -0
- data/lib/capybara/poltergeist/client/compiled/browser.js +687 -0
- data/lib/capybara/poltergeist/client/compiled/cmd.js +31 -0
- data/lib/capybara/poltergeist/client/compiled/connection.js +25 -0
- data/lib/capybara/poltergeist/client/compiled/main.js +228 -0
- data/lib/capybara/poltergeist/client/compiled/node.js +88 -0
- data/lib/capybara/poltergeist/client/compiled/web_page.js +539 -0
- data/lib/capybara/poltergeist/client/connection.coffee +11 -0
- data/lib/capybara/poltergeist/client/main.coffee +99 -0
- data/lib/capybara/poltergeist/client/node.coffee +70 -0
- data/lib/capybara/poltergeist/client/pre/agent.js +587 -0
- data/lib/capybara/poltergeist/client/pre/browser.js +688 -0
- data/lib/capybara/poltergeist/client/pre/cmd.js +31 -0
- data/lib/capybara/poltergeist/client/pre/connection.js +25 -0
- data/lib/capybara/poltergeist/client/pre/main.js +228 -0
- data/lib/capybara/poltergeist/client/pre/node.js +88 -0
- data/lib/capybara/poltergeist/client/pre/web_page.js +540 -0
- data/lib/capybara/poltergeist/client/web_page.coffee +372 -0
- data/lib/capybara/poltergeist/command.rb +17 -0
- data/lib/capybara/poltergeist/cookie.rb +35 -0
- data/lib/capybara/poltergeist/driver.rb +394 -0
- data/lib/capybara/poltergeist/errors.rb +183 -0
- data/lib/capybara/poltergeist/inspector.rb +46 -0
- data/lib/capybara/poltergeist/json.rb +25 -0
- data/lib/capybara/poltergeist/network_traffic.rb +7 -0
- data/lib/capybara/poltergeist/network_traffic/error.rb +19 -0
- data/lib/capybara/poltergeist/network_traffic/request.rb +27 -0
- data/lib/capybara/poltergeist/network_traffic/response.rb +40 -0
- data/lib/capybara/poltergeist/node.rb +177 -0
- data/lib/capybara/poltergeist/server.rb +36 -0
- data/lib/capybara/poltergeist/utility.rb +9 -0
- data/lib/capybara/poltergeist/version.rb +5 -0
- data/lib/capybara/poltergeist/web_socket_server.rb +107 -0
- data/lib/capybara/poltergeistFork.rb +27 -0
- metadata +268 -0
@@ -0,0 +1,11 @@
|
|
1
|
+
class Poltergeist.Connection
|
2
|
+
constructor: (@owner, @port) ->
|
3
|
+
@socket = new WebSocket "ws://127.0.0.1:#{@port}/"
|
4
|
+
@socket.onmessage = this.commandReceived
|
5
|
+
@socket.onclose = -> phantom.exit()
|
6
|
+
|
7
|
+
commandReceived: (message) =>
|
8
|
+
@owner.runCommand(JSON.parse(message.data))
|
9
|
+
|
10
|
+
send: (message) ->
|
11
|
+
@socket.send(JSON.stringify(message))
|
@@ -0,0 +1,99 @@
|
|
1
|
+
class Poltergeist
|
2
|
+
constructor: (port, width, height) ->
|
3
|
+
@browser = new Poltergeist.Browser(width, height)
|
4
|
+
@connection = new Poltergeist.Connection(this, port)
|
5
|
+
|
6
|
+
# The QtWebKit bridge doesn't seem to like Function.prototype.bind
|
7
|
+
that = this
|
8
|
+
phantom.onError = (message, stack) -> that.onError(message, stack)
|
9
|
+
|
10
|
+
@running = false
|
11
|
+
|
12
|
+
runCommand: (command) ->
|
13
|
+
@running = true
|
14
|
+
command = new Poltergeist.Cmd(this, command.id, command.name, command.args)
|
15
|
+
try
|
16
|
+
command.run(@browser)
|
17
|
+
catch error
|
18
|
+
if error instanceof Poltergeist.Error
|
19
|
+
this.sendError(command.id, error)
|
20
|
+
else
|
21
|
+
this.sendError(command.id, new Poltergeist.BrowserError(error.toString(), error.stack))
|
22
|
+
|
23
|
+
sendResponse: (command_id, response) ->
|
24
|
+
this.send(command_id: command_id, response: response)
|
25
|
+
|
26
|
+
sendError: (command_id, error) ->
|
27
|
+
this.send(
|
28
|
+
command_id: command_id,
|
29
|
+
error:
|
30
|
+
name: error.name || 'Generic',
|
31
|
+
args: error.args && error.args() || [error.toString()]
|
32
|
+
)
|
33
|
+
|
34
|
+
send: (data) ->
|
35
|
+
# Prevents more than one response being sent for a single
|
36
|
+
# command. This can happen in some scenarios where an error
|
37
|
+
# is raised but the script can still continue.
|
38
|
+
if @running
|
39
|
+
@connection.send(data)
|
40
|
+
@running = false
|
41
|
+
return true
|
42
|
+
return false
|
43
|
+
|
44
|
+
# This is necessary because the remote debugger will wrap the
|
45
|
+
# script in a function, causing the Poltergeist variable to
|
46
|
+
# become local.
|
47
|
+
window.Poltergeist = Poltergeist
|
48
|
+
|
49
|
+
class Poltergeist.Error
|
50
|
+
|
51
|
+
class Poltergeist.ObsoleteNode extends Poltergeist.Error
|
52
|
+
name: "Poltergeist.ObsoleteNode"
|
53
|
+
args: -> []
|
54
|
+
toString: -> this.name
|
55
|
+
|
56
|
+
class Poltergeist.InvalidSelector extends Poltergeist.Error
|
57
|
+
constructor: (@method, @selector) ->
|
58
|
+
name: "Poltergeist.InvalidSelector"
|
59
|
+
args: -> [@method, @selector]
|
60
|
+
|
61
|
+
class Poltergeist.FrameNotFound extends Poltergeist.Error
|
62
|
+
constructor: (@frameName) ->
|
63
|
+
name: "Poltergeist.FrameNotFound"
|
64
|
+
args: -> [@frameName]
|
65
|
+
|
66
|
+
class Poltergeist.MouseEventFailed extends Poltergeist.Error
|
67
|
+
constructor: (@eventName, @selector, @position) ->
|
68
|
+
name: "Poltergeist.MouseEventFailed"
|
69
|
+
args: -> [@eventName, @selector, @position]
|
70
|
+
|
71
|
+
class Poltergeist.JavascriptError extends Poltergeist.Error
|
72
|
+
constructor: (@errors) ->
|
73
|
+
name: "Poltergeist.JavascriptError"
|
74
|
+
args: -> [@errors]
|
75
|
+
|
76
|
+
class Poltergeist.BrowserError extends Poltergeist.Error
|
77
|
+
constructor: (@message, @stack) ->
|
78
|
+
name: "Poltergeist.BrowserError"
|
79
|
+
args: -> [@message, @stack]
|
80
|
+
|
81
|
+
class Poltergeist.StatusFailError extends Poltergeist.Error
|
82
|
+
constructor: (@url) ->
|
83
|
+
name: "Poltergeist.StatusFailError"
|
84
|
+
args: -> [@url]
|
85
|
+
|
86
|
+
class Poltergeist.NoSuchWindowError extends Poltergeist.Error
|
87
|
+
name: "Poltergeist.NoSuchWindowError"
|
88
|
+
args: -> []
|
89
|
+
|
90
|
+
# We're using phantom.libraryPath so that any stack traces
|
91
|
+
# report the full path.
|
92
|
+
phantom.injectJs("#{phantom.libraryPath}/web_page.js")
|
93
|
+
phantom.injectJs("#{phantom.libraryPath}/node.js")
|
94
|
+
phantom.injectJs("#{phantom.libraryPath}/connection.js")
|
95
|
+
phantom.injectJs("#{phantom.libraryPath}/cmd.js")
|
96
|
+
phantom.injectJs("#{phantom.libraryPath}/browser.js")
|
97
|
+
|
98
|
+
system = require 'system'
|
99
|
+
new Poltergeist(system.args[1], system.args[2], system.args[3])
|
@@ -0,0 +1,70 @@
|
|
1
|
+
# Proxy object for forwarding method calls to the node object inside the page.
|
2
|
+
|
3
|
+
class Poltergeist.Node
|
4
|
+
@DELEGATES = ['allText', 'visibleText', 'getAttribute', 'value', 'set', 'setAttribute', 'isObsolete',
|
5
|
+
'removeAttribute', 'isMultiple', 'select', 'tagName', 'find', 'getAttributes',
|
6
|
+
'isVisible', 'isInViewport', 'position', 'trigger', 'parentId', 'parentIds', 'mouseEventTest',
|
7
|
+
'scrollIntoView', 'isDOMEqual', 'isDisabled', 'deleteText', 'containsSelection',
|
8
|
+
'path', 'getProperty']
|
9
|
+
|
10
|
+
constructor: (@page, @id) ->
|
11
|
+
|
12
|
+
parent: ->
|
13
|
+
new Poltergeist.Node(@page, this.parentId())
|
14
|
+
|
15
|
+
for name in @DELEGATES
|
16
|
+
do (name) =>
|
17
|
+
this.prototype[name] = (args...) ->
|
18
|
+
@page.nodeCall(@id, name, args)
|
19
|
+
|
20
|
+
mouseEventPosition: ->
|
21
|
+
viewport = @page.viewportSize()
|
22
|
+
pos = this.position()
|
23
|
+
|
24
|
+
middle = (start, end, size) ->
|
25
|
+
start + ((Math.min(end, size) - start) / 2)
|
26
|
+
|
27
|
+
{
|
28
|
+
x: middle(pos.left, pos.right, viewport.width),
|
29
|
+
y: middle(pos.top, pos.bottom, viewport.height)
|
30
|
+
}
|
31
|
+
|
32
|
+
mouseEvent: (name) ->
|
33
|
+
this.scrollIntoView()
|
34
|
+
pos = this.mouseEventPosition()
|
35
|
+
test = this.mouseEventTest(pos.x, pos.y)
|
36
|
+
if test.status == 'success'
|
37
|
+
if name == 'rightclick'
|
38
|
+
@page.mouseEvent('click', pos.x, pos.y, 'right')
|
39
|
+
this.trigger('contextmenu')
|
40
|
+
else
|
41
|
+
@page.mouseEvent(name, pos.x, pos.y)
|
42
|
+
pos
|
43
|
+
else
|
44
|
+
throw new Poltergeist.MouseEventFailed(name, test.selector, pos)
|
45
|
+
|
46
|
+
dragTo: (other) ->
|
47
|
+
this.scrollIntoView()
|
48
|
+
|
49
|
+
position = this.mouseEventPosition()
|
50
|
+
otherPosition = other.mouseEventPosition()
|
51
|
+
|
52
|
+
@page.mouseEvent('mousedown', position.x, position.y)
|
53
|
+
@page.mouseEvent('mouseup', otherPosition.x, otherPosition.y)
|
54
|
+
|
55
|
+
dragBy: (x, y) ->
|
56
|
+
this.scrollIntoView()
|
57
|
+
|
58
|
+
position = this.mouseEventPosition()
|
59
|
+
|
60
|
+
final_pos =
|
61
|
+
x: position.x + x
|
62
|
+
y: position.y + y
|
63
|
+
|
64
|
+
@page.mouseEvent('mousedown', position.x, position.y)
|
65
|
+
@page.mouseEvent('mouseup', final_pos.x, final_pos.y)
|
66
|
+
|
67
|
+
|
68
|
+
isEqual: (other) ->
|
69
|
+
@page == other.page && this.isDOMEqual(other.id)
|
70
|
+
|
@@ -0,0 +1,587 @@
|
|
1
|
+
var PoltergeistAgent;
|
2
|
+
|
3
|
+
PoltergeistAgent = (function() {
|
4
|
+
PoltergeistAgent.JSON || (PoltergeistAgent.JSON = {
|
5
|
+
parse: JSON.parse,
|
6
|
+
stringify: JSON.stringify
|
7
|
+
});
|
8
|
+
|
9
|
+
function PoltergeistAgent() {
|
10
|
+
this.elements = [];
|
11
|
+
this.nodes = {};
|
12
|
+
}
|
13
|
+
|
14
|
+
PoltergeistAgent.prototype.externalCall = function(name, args) {
|
15
|
+
var error, error1;
|
16
|
+
try {
|
17
|
+
return {
|
18
|
+
value: this[name].apply(this, args)
|
19
|
+
};
|
20
|
+
} catch (error1) {
|
21
|
+
error = error1;
|
22
|
+
return {
|
23
|
+
error: {
|
24
|
+
message: error.toString(),
|
25
|
+
stack: error.stack
|
26
|
+
}
|
27
|
+
};
|
28
|
+
}
|
29
|
+
};
|
30
|
+
|
31
|
+
PoltergeistAgent.stringify = function(object) {
|
32
|
+
var error, error1;
|
33
|
+
try {
|
34
|
+
return PoltergeistAgent.JSON.stringify(object, function(key, value) {
|
35
|
+
if (Array.isArray(this[key])) {
|
36
|
+
return this[key];
|
37
|
+
} else {
|
38
|
+
return value;
|
39
|
+
}
|
40
|
+
});
|
41
|
+
} catch (error1) {
|
42
|
+
error = error1;
|
43
|
+
if (error instanceof TypeError) {
|
44
|
+
return '"(cyclic structure)"';
|
45
|
+
} else {
|
46
|
+
throw error;
|
47
|
+
}
|
48
|
+
}
|
49
|
+
};
|
50
|
+
|
51
|
+
PoltergeistAgent.prototype.currentUrl = function() {
|
52
|
+
return window.location.href.replace(/\ /g, '%20');
|
53
|
+
};
|
54
|
+
|
55
|
+
PoltergeistAgent.prototype.find = function(method, selector, within) {
|
56
|
+
var el, error, error1, i, j, len, results, results1, xpath;
|
57
|
+
if (within == null) {
|
58
|
+
within = document;
|
59
|
+
}
|
60
|
+
try {
|
61
|
+
if (method === "xpath") {
|
62
|
+
xpath = document.evaluate(selector, within, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
|
63
|
+
results = (function() {
|
64
|
+
var j, ref, results1;
|
65
|
+
results1 = [];
|
66
|
+
for (i = j = 0, ref = xpath.snapshotLength; 0 <= ref ? j < ref : j > ref; i = 0 <= ref ? ++j : --j) {
|
67
|
+
results1.push(xpath.snapshotItem(i));
|
68
|
+
}
|
69
|
+
return results1;
|
70
|
+
})();
|
71
|
+
} else {
|
72
|
+
results = within.querySelectorAll(selector);
|
73
|
+
}
|
74
|
+
results1 = [];
|
75
|
+
for (j = 0, len = results.length; j < len; j++) {
|
76
|
+
el = results[j];
|
77
|
+
results1.push(this.register(el));
|
78
|
+
}
|
79
|
+
return results1;
|
80
|
+
} catch (error1) {
|
81
|
+
error = error1;
|
82
|
+
if (error.code === DOMException.SYNTAX_ERR || error.code === 51) {
|
83
|
+
throw new PoltergeistAgent.InvalidSelector;
|
84
|
+
} else {
|
85
|
+
throw error;
|
86
|
+
}
|
87
|
+
}
|
88
|
+
};
|
89
|
+
|
90
|
+
PoltergeistAgent.prototype.register = function(element) {
|
91
|
+
this.elements.push(element);
|
92
|
+
return this.elements.length - 1;
|
93
|
+
};
|
94
|
+
|
95
|
+
PoltergeistAgent.prototype.documentSize = function() {
|
96
|
+
return {
|
97
|
+
height: document.documentElement.scrollHeight || document.documentElement.clientHeight,
|
98
|
+
width: document.documentElement.scrollWidth || document.documentElement.clientWidth
|
99
|
+
};
|
100
|
+
};
|
101
|
+
|
102
|
+
PoltergeistAgent.prototype.get = function(id) {
|
103
|
+
var base;
|
104
|
+
return (base = this.nodes)[id] || (base[id] = new PoltergeistAgent.Node(this, this.elements[id]));
|
105
|
+
};
|
106
|
+
|
107
|
+
PoltergeistAgent.prototype.nodeCall = function(id, name, args) {
|
108
|
+
var node;
|
109
|
+
node = this.get(id);
|
110
|
+
if (node.isObsolete()) {
|
111
|
+
throw new PoltergeistAgent.ObsoleteNode;
|
112
|
+
}
|
113
|
+
return node[name].apply(node, args);
|
114
|
+
};
|
115
|
+
|
116
|
+
PoltergeistAgent.prototype.beforeUpload = function(id) {
|
117
|
+
return this.get(id).setAttribute('_poltergeist_selected', '');
|
118
|
+
};
|
119
|
+
|
120
|
+
PoltergeistAgent.prototype.afterUpload = function(id) {
|
121
|
+
return this.get(id).removeAttribute('_poltergeist_selected');
|
122
|
+
};
|
123
|
+
|
124
|
+
PoltergeistAgent.prototype.clearLocalStorage = function() {
|
125
|
+
return localStorage.clear();
|
126
|
+
};
|
127
|
+
|
128
|
+
return PoltergeistAgent;
|
129
|
+
|
130
|
+
})();
|
131
|
+
|
132
|
+
PoltergeistAgent.ObsoleteNode = (function() {
|
133
|
+
function ObsoleteNode() {}
|
134
|
+
|
135
|
+
ObsoleteNode.prototype.toString = function() {
|
136
|
+
return "PoltergeistAgent.ObsoleteNode";
|
137
|
+
};
|
138
|
+
|
139
|
+
return ObsoleteNode;
|
140
|
+
|
141
|
+
})();
|
142
|
+
|
143
|
+
PoltergeistAgent.InvalidSelector = (function() {
|
144
|
+
function InvalidSelector() {}
|
145
|
+
|
146
|
+
InvalidSelector.prototype.toString = function() {
|
147
|
+
return "PoltergeistAgent.InvalidSelector";
|
148
|
+
};
|
149
|
+
|
150
|
+
return InvalidSelector;
|
151
|
+
|
152
|
+
})();
|
153
|
+
|
154
|
+
PoltergeistAgent.Node = (function() {
|
155
|
+
Node.EVENTS = {
|
156
|
+
FOCUS: ['blur', 'focus', 'focusin', 'focusout'],
|
157
|
+
MOUSE: ['click', 'dblclick', 'mousedown', 'mouseenter', 'mouseleave', 'mousemove', 'mouseover', 'mouseout', 'mouseup', 'contextmenu'],
|
158
|
+
FORM: ['submit']
|
159
|
+
};
|
160
|
+
|
161
|
+
function Node(agent, element1) {
|
162
|
+
this.agent = agent;
|
163
|
+
this.element = element1;
|
164
|
+
}
|
165
|
+
|
166
|
+
Node.prototype.parentId = function() {
|
167
|
+
return this.agent.register(this.element.parentNode);
|
168
|
+
};
|
169
|
+
|
170
|
+
Node.prototype.parentIds = function() {
|
171
|
+
var ids, parent;
|
172
|
+
ids = [];
|
173
|
+
parent = this.element.parentNode;
|
174
|
+
while (parent !== document) {
|
175
|
+
ids.push(this.agent.register(parent));
|
176
|
+
parent = parent.parentNode;
|
177
|
+
}
|
178
|
+
return ids;
|
179
|
+
};
|
180
|
+
|
181
|
+
Node.prototype.find = function(method, selector) {
|
182
|
+
return this.agent.find(method, selector, this.element);
|
183
|
+
};
|
184
|
+
|
185
|
+
Node.prototype.isObsolete = function() {
|
186
|
+
var obsolete;
|
187
|
+
obsolete = (function(_this) {
|
188
|
+
return function(element) {
|
189
|
+
var parent;
|
190
|
+
if ((parent = element.parentNode) != null) {
|
191
|
+
if (parent === document) {
|
192
|
+
return false;
|
193
|
+
} else {
|
194
|
+
return obsolete(parent);
|
195
|
+
}
|
196
|
+
} else {
|
197
|
+
return true;
|
198
|
+
}
|
199
|
+
};
|
200
|
+
})(this);
|
201
|
+
return obsolete(this.element);
|
202
|
+
};
|
203
|
+
|
204
|
+
Node.prototype.changed = function() {
|
205
|
+
var element, event;
|
206
|
+
event = document.createEvent('HTMLEvents');
|
207
|
+
event.initEvent('change', true, false);
|
208
|
+
if (this.element.nodeName === 'OPTION') {
|
209
|
+
element = this.element.parentNode;
|
210
|
+
if (element.nodeName === 'OPTGROUP') {
|
211
|
+
element = element.parentNode;
|
212
|
+
}
|
213
|
+
element;
|
214
|
+
} else {
|
215
|
+
element = this.element;
|
216
|
+
}
|
217
|
+
return element.dispatchEvent(event);
|
218
|
+
};
|
219
|
+
|
220
|
+
Node.prototype.input = function() {
|
221
|
+
var event;
|
222
|
+
event = document.createEvent('HTMLEvents');
|
223
|
+
event.initEvent('input', true, false);
|
224
|
+
return this.element.dispatchEvent(event);
|
225
|
+
};
|
226
|
+
|
227
|
+
Node.prototype.keyupdowned = function(eventName, keyCode) {
|
228
|
+
var event;
|
229
|
+
event = document.createEvent('UIEvents');
|
230
|
+
event.initEvent(eventName, true, true);
|
231
|
+
event.keyCode = keyCode;
|
232
|
+
event.which = keyCode;
|
233
|
+
event.charCode = 0;
|
234
|
+
return this.element.dispatchEvent(event);
|
235
|
+
};
|
236
|
+
|
237
|
+
Node.prototype.keypressed = function(altKey, ctrlKey, shiftKey, metaKey, keyCode, charCode) {
|
238
|
+
var event;
|
239
|
+
event = document.createEvent('UIEvents');
|
240
|
+
event.initEvent('keypress', true, true);
|
241
|
+
event.window = this.agent.window;
|
242
|
+
event.altKey = altKey;
|
243
|
+
event.ctrlKey = ctrlKey;
|
244
|
+
event.shiftKey = shiftKey;
|
245
|
+
event.metaKey = metaKey;
|
246
|
+
event.keyCode = keyCode;
|
247
|
+
event.charCode = charCode;
|
248
|
+
event.which = keyCode;
|
249
|
+
return this.element.dispatchEvent(event);
|
250
|
+
};
|
251
|
+
|
252
|
+
Node.prototype.insideBody = function() {
|
253
|
+
return this.element === document.body || document.evaluate('ancestor::body', this.element, null, XPathResult.BOOLEAN_TYPE, null).booleanValue;
|
254
|
+
};
|
255
|
+
|
256
|
+
Node.prototype.allText = function() {
|
257
|
+
return this.element.textContent;
|
258
|
+
};
|
259
|
+
|
260
|
+
Node.prototype.visibleText = function() {
|
261
|
+
if (this.isVisible()) {
|
262
|
+
if (this.element.nodeName === "TEXTAREA") {
|
263
|
+
return this.element.textContent;
|
264
|
+
} else {
|
265
|
+
return this.element.innerText || this.element.textContent;
|
266
|
+
}
|
267
|
+
}
|
268
|
+
};
|
269
|
+
|
270
|
+
Node.prototype.deleteText = function() {
|
271
|
+
var range;
|
272
|
+
range = document.createRange();
|
273
|
+
range.selectNodeContents(this.element);
|
274
|
+
window.getSelection().removeAllRanges();
|
275
|
+
window.getSelection().addRange(range);
|
276
|
+
return window.getSelection().deleteFromDocument();
|
277
|
+
};
|
278
|
+
|
279
|
+
Node.prototype.getProperty = function(name) {
|
280
|
+
return this.element[name];
|
281
|
+
};
|
282
|
+
|
283
|
+
Node.prototype.getAttributes = function() {
|
284
|
+
var attr, attrs, j, len, ref;
|
285
|
+
attrs = {};
|
286
|
+
ref = this.element.attributes;
|
287
|
+
for (j = 0, len = ref.length; j < len; j++) {
|
288
|
+
attr = ref[j];
|
289
|
+
attrs[attr.name] = attr.value.replace("\n", "\\n");
|
290
|
+
}
|
291
|
+
return attrs;
|
292
|
+
};
|
293
|
+
|
294
|
+
Node.prototype.getAttribute = function(name) {
|
295
|
+
if (name === 'checked' || name === 'selected') {
|
296
|
+
return this.element[name];
|
297
|
+
} else {
|
298
|
+
return this.element.getAttribute(name);
|
299
|
+
}
|
300
|
+
};
|
301
|
+
|
302
|
+
Node.prototype.scrollIntoView = function() {
|
303
|
+
this.element.scrollIntoViewIfNeeded();
|
304
|
+
if (!this.isInViewport()) {
|
305
|
+
return this.element.scrollIntoView();
|
306
|
+
}
|
307
|
+
};
|
308
|
+
|
309
|
+
Node.prototype.value = function() {
|
310
|
+
var j, len, option, ref, results1;
|
311
|
+
if (this.element.tagName === 'SELECT' && this.element.multiple) {
|
312
|
+
ref = this.element.children;
|
313
|
+
results1 = [];
|
314
|
+
for (j = 0, len = ref.length; j < len; j++) {
|
315
|
+
option = ref[j];
|
316
|
+
if (option.selected) {
|
317
|
+
results1.push(option.value);
|
318
|
+
}
|
319
|
+
}
|
320
|
+
return results1;
|
321
|
+
} else {
|
322
|
+
return this.element.value;
|
323
|
+
}
|
324
|
+
};
|
325
|
+
|
326
|
+
Node.prototype.set = function(value) {
|
327
|
+
var char, j, keyCode, len;
|
328
|
+
if (this.element.readOnly) {
|
329
|
+
return;
|
330
|
+
}
|
331
|
+
if (this.element.maxLength >= 0) {
|
332
|
+
value = value.substr(0, this.element.maxLength);
|
333
|
+
}
|
334
|
+
this.trigger('focus');
|
335
|
+
this.element.value = '';
|
336
|
+
if (this.element.type === 'number') {
|
337
|
+
this.element.value = value;
|
338
|
+
} else {
|
339
|
+
for (j = 0, len = value.length; j < len; j++) {
|
340
|
+
char = value[j];
|
341
|
+
keyCode = this.characterToKeyCode(char);
|
342
|
+
this.keyupdowned('keydown', keyCode);
|
343
|
+
this.element.value += char;
|
344
|
+
this.keypressed(false, false, false, false, char.charCodeAt(0), char.charCodeAt(0));
|
345
|
+
this.keyupdowned('keyup', keyCode);
|
346
|
+
}
|
347
|
+
}
|
348
|
+
this.changed();
|
349
|
+
this.input();
|
350
|
+
return this.trigger('blur');
|
351
|
+
};
|
352
|
+
|
353
|
+
Node.prototype.isMultiple = function() {
|
354
|
+
return this.element.multiple;
|
355
|
+
};
|
356
|
+
|
357
|
+
Node.prototype.setAttribute = function(name, value) {
|
358
|
+
return this.element.setAttribute(name, value);
|
359
|
+
};
|
360
|
+
|
361
|
+
Node.prototype.removeAttribute = function(name) {
|
362
|
+
return this.element.removeAttribute(name);
|
363
|
+
};
|
364
|
+
|
365
|
+
Node.prototype.select = function(value) {
|
366
|
+
if (this.isDisabled()) {
|
367
|
+
return false;
|
368
|
+
} else if (value === false && !this.element.parentNode.multiple) {
|
369
|
+
return false;
|
370
|
+
} else {
|
371
|
+
this.trigger('focus', this.element.parentNode);
|
372
|
+
this.element.selected = value;
|
373
|
+
this.changed();
|
374
|
+
this.trigger('blur', this.element.parentNode);
|
375
|
+
return true;
|
376
|
+
}
|
377
|
+
};
|
378
|
+
|
379
|
+
Node.prototype.tagName = function() {
|
380
|
+
return this.element.tagName;
|
381
|
+
};
|
382
|
+
|
383
|
+
Node.prototype.isVisible = function(element) {
|
384
|
+
var style;
|
385
|
+
if (element == null) {
|
386
|
+
element = this.element;
|
387
|
+
}
|
388
|
+
while (element) {
|
389
|
+
style = window.getComputedStyle(element);
|
390
|
+
if (style.display === 'none' || style.visibility === 'hidden' || parseFloat(style.opacity) === 0) {
|
391
|
+
return false;
|
392
|
+
}
|
393
|
+
element = element.parentElement;
|
394
|
+
}
|
395
|
+
return true;
|
396
|
+
};
|
397
|
+
|
398
|
+
Node.prototype.isInViewport = function() {
|
399
|
+
var rect;
|
400
|
+
rect = this.element.getBoundingClientRect();
|
401
|
+
return rect.top >= 0 && rect.left >= 0 && rect.bottom <= window.innerHeight && rect.right <= window.innerWidth;
|
402
|
+
};
|
403
|
+
|
404
|
+
Node.prototype.isDisabled = function() {
|
405
|
+
return this.element.disabled || this.element.tagName === 'OPTION' && this.element.parentNode.disabled;
|
406
|
+
};
|
407
|
+
|
408
|
+
Node.prototype.path = function() {
|
409
|
+
var elements, selectors;
|
410
|
+
elements = this.parentIds().reverse().map((function(_this) {
|
411
|
+
return function(id) {
|
412
|
+
return _this.agent.get(id);
|
413
|
+
};
|
414
|
+
})(this));
|
415
|
+
elements.push(this);
|
416
|
+
selectors = elements.map(function(el) {
|
417
|
+
var prev_siblings;
|
418
|
+
prev_siblings = el.find('xpath', "./preceding-sibling::" + (el.tagName()));
|
419
|
+
return (el.tagName()) + "[" + (prev_siblings.length + 1) + "]";
|
420
|
+
});
|
421
|
+
return "//" + selectors.join('/');
|
422
|
+
};
|
423
|
+
|
424
|
+
Node.prototype.containsSelection = function() {
|
425
|
+
var selectedNode;
|
426
|
+
selectedNode = document.getSelection().focusNode;
|
427
|
+
if (!selectedNode) {
|
428
|
+
return false;
|
429
|
+
}
|
430
|
+
if (selectedNode.nodeType === 3) {
|
431
|
+
selectedNode = selectedNode.parentNode;
|
432
|
+
}
|
433
|
+
return this.element.contains(selectedNode);
|
434
|
+
};
|
435
|
+
|
436
|
+
Node.prototype.frameOffset = function() {
|
437
|
+
var offset, rect, style, win;
|
438
|
+
win = window;
|
439
|
+
offset = {
|
440
|
+
top: 0,
|
441
|
+
left: 0
|
442
|
+
};
|
443
|
+
while (win.frameElement) {
|
444
|
+
rect = win.frameElement.getClientRects()[0];
|
445
|
+
style = win.getComputedStyle(win.frameElement);
|
446
|
+
win = win.parent;
|
447
|
+
offset.top += rect.top + parseInt(style.getPropertyValue("padding-top"), 10);
|
448
|
+
offset.left += rect.left + parseInt(style.getPropertyValue("padding-left"), 10);
|
449
|
+
}
|
450
|
+
return offset;
|
451
|
+
};
|
452
|
+
|
453
|
+
Node.prototype.position = function() {
|
454
|
+
var frameOffset, pos, rect;
|
455
|
+
rect = this.element.getClientRects()[0] || this.element.getBoundingClientRect();
|
456
|
+
if (!rect) {
|
457
|
+
throw new PoltergeistAgent.ObsoleteNode;
|
458
|
+
}
|
459
|
+
frameOffset = this.frameOffset();
|
460
|
+
pos = {
|
461
|
+
top: rect.top + frameOffset.top,
|
462
|
+
right: rect.right + frameOffset.left,
|
463
|
+
left: rect.left + frameOffset.left,
|
464
|
+
bottom: rect.bottom + frameOffset.top,
|
465
|
+
width: rect.width,
|
466
|
+
height: rect.height
|
467
|
+
};
|
468
|
+
return pos;
|
469
|
+
};
|
470
|
+
|
471
|
+
Node.prototype.trigger = function(name, element) {
|
472
|
+
var event;
|
473
|
+
if (element == null) {
|
474
|
+
element = this.element;
|
475
|
+
}
|
476
|
+
if (Node.EVENTS.MOUSE.indexOf(name) !== -1) {
|
477
|
+
event = document.createEvent('MouseEvent');
|
478
|
+
event.initMouseEvent(name, true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
|
479
|
+
} else if (Node.EVENTS.FOCUS.indexOf(name) !== -1) {
|
480
|
+
event = this.obtainEvent(name);
|
481
|
+
} else if (Node.EVENTS.FORM.indexOf(name) !== -1) {
|
482
|
+
event = this.obtainEvent(name);
|
483
|
+
} else {
|
484
|
+
throw "Unknown event";
|
485
|
+
}
|
486
|
+
return element.dispatchEvent(event);
|
487
|
+
};
|
488
|
+
|
489
|
+
Node.prototype.obtainEvent = function(name) {
|
490
|
+
var event;
|
491
|
+
event = document.createEvent('HTMLEvents');
|
492
|
+
event.initEvent(name, true, true);
|
493
|
+
return event;
|
494
|
+
};
|
495
|
+
|
496
|
+
Node.prototype.mouseEventTest = function(x, y) {
|
497
|
+
var el, frameOffset, origEl;
|
498
|
+
frameOffset = this.frameOffset();
|
499
|
+
x -= frameOffset.left;
|
500
|
+
y -= frameOffset.top;
|
501
|
+
el = origEl = document.elementFromPoint(x, y);
|
502
|
+
while (el) {
|
503
|
+
if (el === this.element) {
|
504
|
+
return {
|
505
|
+
status: 'success'
|
506
|
+
};
|
507
|
+
} else {
|
508
|
+
el = el.parentNode;
|
509
|
+
}
|
510
|
+
}
|
511
|
+
return {
|
512
|
+
status: 'failure',
|
513
|
+
selector: origEl && this.getSelector(origEl)
|
514
|
+
};
|
515
|
+
};
|
516
|
+
|
517
|
+
Node.prototype.getSelector = function(el) {
|
518
|
+
var className, classes, j, len, ref, ref1, selector;
|
519
|
+
selector = el.tagName !== 'HTML' ? this.getSelector(el.parentNode) + ' ' : '';
|
520
|
+
selector += el.tagName.toLowerCase();
|
521
|
+
if (el.id) {
|
522
|
+
selector += "#" + el.id;
|
523
|
+
}
|
524
|
+
classes = el.classList || ((ref = el.getAttribute('class')) != null ? (ref1 = ref.trim()) != null ? ref1.split(/\s+/) : void 0 : void 0) || [];
|
525
|
+
for (j = 0, len = classes.length; j < len; j++) {
|
526
|
+
className = classes[j];
|
527
|
+
if (className !== '') {
|
528
|
+
selector += "." + className;
|
529
|
+
}
|
530
|
+
}
|
531
|
+
return selector;
|
532
|
+
};
|
533
|
+
|
534
|
+
Node.prototype.characterToKeyCode = function(character) {
|
535
|
+
var code, specialKeys;
|
536
|
+
code = character.toUpperCase().charCodeAt(0);
|
537
|
+
specialKeys = {
|
538
|
+
96: 192,
|
539
|
+
45: 189,
|
540
|
+
61: 187,
|
541
|
+
91: 219,
|
542
|
+
93: 221,
|
543
|
+
92: 220,
|
544
|
+
59: 186,
|
545
|
+
39: 222,
|
546
|
+
44: 188,
|
547
|
+
46: 190,
|
548
|
+
47: 191,
|
549
|
+
127: 46,
|
550
|
+
126: 192,
|
551
|
+
33: 49,
|
552
|
+
64: 50,
|
553
|
+
35: 51,
|
554
|
+
36: 52,
|
555
|
+
37: 53,
|
556
|
+
94: 54,
|
557
|
+
38: 55,
|
558
|
+
42: 56,
|
559
|
+
40: 57,
|
560
|
+
41: 48,
|
561
|
+
95: 189,
|
562
|
+
43: 187,
|
563
|
+
123: 219,
|
564
|
+
125: 221,
|
565
|
+
124: 220,
|
566
|
+
58: 186,
|
567
|
+
34: 222,
|
568
|
+
60: 188,
|
569
|
+
62: 190,
|
570
|
+
63: 191
|
571
|
+
};
|
572
|
+
return specialKeys[code] || code;
|
573
|
+
};
|
574
|
+
|
575
|
+
Node.prototype.isDOMEqual = function(other_id) {
|
576
|
+
return this.element === this.agent.get(other_id).element;
|
577
|
+
};
|
578
|
+
|
579
|
+
return Node;
|
580
|
+
|
581
|
+
})();
|
582
|
+
|
583
|
+
window.__poltergeist = new PoltergeistAgent;
|
584
|
+
|
585
|
+
document.addEventListener('DOMContentLoaded', function() {
|
586
|
+
return console.log('__DOMContentLoaded');
|
587
|
+
});
|