poltergeist 0.7.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.md +201 -62
- data/lib/capybara/poltergeist.rb +1 -1
- data/lib/capybara/poltergeist/browser.rb +36 -4
- data/lib/capybara/poltergeist/client.rb +4 -4
- data/lib/capybara/poltergeist/client/agent.coffee +30 -134
- data/lib/capybara/poltergeist/client/browser.coffee +97 -19
- data/lib/capybara/poltergeist/client/compiled/agent.js +36 -146
- data/lib/capybara/poltergeist/client/compiled/browser.js +114 -19
- data/lib/capybara/poltergeist/client/compiled/node.js +11 -5
- data/lib/capybara/poltergeist/client/compiled/web_page.js +80 -16
- data/lib/capybara/poltergeist/client/node.coffee +11 -6
- data/lib/capybara/poltergeist/client/web_page.coffee +62 -12
- data/lib/capybara/poltergeist/cookie.rb +35 -0
- data/lib/capybara/poltergeist/driver.rb +39 -7
- data/lib/capybara/poltergeist/inspector.rb +18 -7
- data/lib/capybara/poltergeist/server.rb +2 -2
- data/lib/capybara/poltergeist/version.rb +1 -1
- metadata +21 -5
- data/lib/capybara/poltergeist/util.rb +0 -12
@@ -1,7 +1,7 @@
|
|
1
1
|
module Capybara::Poltergeist
|
2
2
|
class Client
|
3
3
|
PHANTOMJS_SCRIPT = File.expand_path('../client/compiled/main.js', __FILE__)
|
4
|
-
PHANTOMJS_VERSION = '1.
|
4
|
+
PHANTOMJS_VERSION = '1.7.0'
|
5
5
|
PHANTOMJS_NAME = 'phantomjs'
|
6
6
|
|
7
7
|
def self.start(*args)
|
@@ -61,11 +61,11 @@ module Capybara::Poltergeist
|
|
61
61
|
def check_phantomjs_version
|
62
62
|
return if @phantomjs_version_checked
|
63
63
|
|
64
|
-
version = `#{path} --version
|
64
|
+
version = `#{path} --version` rescue nil
|
65
65
|
|
66
|
-
if $? != 0
|
66
|
+
if version.nil? || $? != 0
|
67
67
|
raise PhantomJSFailed.new($?)
|
68
|
-
elsif version < PHANTOMJS_VERSION
|
68
|
+
elsif version.chomp < PHANTOMJS_VERSION
|
69
69
|
raise PhantomJSTooOld.new(version)
|
70
70
|
end
|
71
71
|
|
@@ -4,8 +4,6 @@ class PoltergeistAgent
|
|
4
4
|
constructor: ->
|
5
5
|
@elements = []
|
6
6
|
@nodes = {}
|
7
|
-
@windows = []
|
8
|
-
this.pushWindow(window)
|
9
7
|
|
10
8
|
externalCall: (name, args) ->
|
11
9
|
try
|
@@ -14,39 +12,23 @@ class PoltergeistAgent
|
|
14
12
|
{ error: { message: error.toString(), stack: error.stack } }
|
15
13
|
|
16
14
|
@stringify: (object) ->
|
17
|
-
|
18
|
-
|
19
|
-
|
15
|
+
try
|
16
|
+
JSON.stringify object, (key, value) ->
|
17
|
+
if Array.isArray(this[key])
|
18
|
+
return this[key]
|
19
|
+
else
|
20
|
+
return value
|
21
|
+
catch error
|
22
|
+
if error instanceof TypeError
|
23
|
+
'"(cyclic structure)"'
|
20
24
|
else
|
21
|
-
|
22
|
-
|
23
|
-
pushWindow: (new_window) ->
|
24
|
-
@windows.push(new_window)
|
25
|
-
|
26
|
-
@window = new_window
|
27
|
-
@document = @window.document
|
28
|
-
|
29
|
-
null
|
30
|
-
|
31
|
-
popWindow: ->
|
32
|
-
@windows.pop()
|
33
|
-
|
34
|
-
@window = @windows[@windows.length - 1]
|
35
|
-
@document = @window.document
|
36
|
-
|
37
|
-
null
|
38
|
-
|
39
|
-
pushFrame: (id) ->
|
40
|
-
this.pushWindow @document.getElementById(id).contentWindow
|
41
|
-
|
42
|
-
popFrame: ->
|
43
|
-
this.popWindow()
|
25
|
+
throw error
|
44
26
|
|
45
27
|
currentUrl: ->
|
46
28
|
window.location.toString()
|
47
29
|
|
48
|
-
find: (selector, within =
|
49
|
-
results =
|
30
|
+
find: (selector, within = document) ->
|
31
|
+
results = document.evaluate(selector, within, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null)
|
50
32
|
ids = []
|
51
33
|
|
52
34
|
for i in [0...results.snapshotLength]
|
@@ -59,8 +41,8 @@ class PoltergeistAgent
|
|
59
41
|
@elements.length - 1
|
60
42
|
|
61
43
|
documentSize: ->
|
62
|
-
height:
|
63
|
-
width:
|
44
|
+
height: document.documentElement.scrollHeight,
|
45
|
+
width: document.documentElement.scrollWidth
|
64
46
|
|
65
47
|
get: (id) ->
|
66
48
|
@nodes[id] or= new PoltergeistAgent.Node(this, @elements[id])
|
@@ -91,7 +73,7 @@ class PoltergeistAgent.Node
|
|
91
73
|
isObsolete: ->
|
92
74
|
obsolete = (element) =>
|
93
75
|
if element.parentNode?
|
94
|
-
if element.parentNode ==
|
76
|
+
if element.parentNode == document
|
95
77
|
false
|
96
78
|
else
|
97
79
|
obsolete element.parentNode
|
@@ -104,51 +86,15 @@ class PoltergeistAgent.Node
|
|
104
86
|
event.initEvent('change', true, false)
|
105
87
|
@element.dispatchEvent(event)
|
106
88
|
|
107
|
-
input: ->
|
108
|
-
event = document.createEvent('HTMLEvents')
|
109
|
-
event.initEvent('input', true, false)
|
110
|
-
@element.dispatchEvent(event)
|
111
|
-
|
112
|
-
keyupdowned: (eventName, keyCode) ->
|
113
|
-
event = document.createEvent('UIEvents')
|
114
|
-
event.initEvent(eventName, true, true)
|
115
|
-
event.keyCode = keyCode
|
116
|
-
event.which = keyCode
|
117
|
-
event.charCode = 0
|
118
|
-
@element.dispatchEvent(event)
|
119
|
-
|
120
|
-
keypressed: (altKey, ctrlKey, shiftKey, metaKey, keyCode, charCode) ->
|
121
|
-
event = document.createEvent('UIEvents')
|
122
|
-
event.initEvent('keypress', true, true)
|
123
|
-
event.window = @agent.window
|
124
|
-
event.altKey = altKey
|
125
|
-
event.ctrlKey = ctrlKey
|
126
|
-
event.shiftKey = shiftKey
|
127
|
-
event.metaKey = metaKey
|
128
|
-
event.keyCode = keyCode
|
129
|
-
event.charCode = charCode
|
130
|
-
event.which = keyCode
|
131
|
-
@element.dispatchEvent(event)
|
132
|
-
|
133
89
|
insideBody: ->
|
134
|
-
@element ==
|
135
|
-
|
90
|
+
@element == document.body ||
|
91
|
+
document.evaluate('ancestor::body', @element, null, XPathResult.BOOLEAN_TYPE, null).booleanValue
|
136
92
|
|
137
93
|
text: ->
|
138
|
-
|
139
|
-
|
140
|
-
if this.insideBody()
|
141
|
-
el = @element
|
94
|
+
if @element.tagName == 'TEXTAREA'
|
95
|
+
@element.textContent
|
142
96
|
else
|
143
|
-
|
144
|
-
|
145
|
-
results = @agent.document.evaluate('.//text()[not(ancestor::script)]', el, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null)
|
146
|
-
text = ''
|
147
|
-
|
148
|
-
for i in [0...results.snapshotLength]
|
149
|
-
node = results.snapshotItem(i)
|
150
|
-
text += node.textContent if this.isVisible(node.parentNode)
|
151
|
-
text
|
97
|
+
@element.innerText
|
152
98
|
|
153
99
|
getAttribute: (name) ->
|
154
100
|
if name == 'checked' || name == 'selected'
|
@@ -165,25 +111,6 @@ class PoltergeistAgent.Node
|
|
165
111
|
else
|
166
112
|
@element.value
|
167
113
|
|
168
|
-
set: (value) ->
|
169
|
-
if (@element.maxLength >= 0)
|
170
|
-
value = value.substr(0, @element.maxLength)
|
171
|
-
|
172
|
-
@element.value = ''
|
173
|
-
this.trigger('focus')
|
174
|
-
|
175
|
-
for char in value
|
176
|
-
@element.value += char
|
177
|
-
|
178
|
-
keyCode = this.characterToKeyCode(char)
|
179
|
-
this.keyupdowned('keydown', keyCode)
|
180
|
-
this.keypressed(false, false, false, false, char.charCodeAt(0), char.charCodeAt(0))
|
181
|
-
this.keyupdowned('keyup', keyCode)
|
182
|
-
|
183
|
-
this.changed()
|
184
|
-
this.input()
|
185
|
-
this.trigger('blur')
|
186
|
-
|
187
114
|
isMultiple: ->
|
188
115
|
@element.multiple
|
189
116
|
|
@@ -207,7 +134,7 @@ class PoltergeistAgent.Node
|
|
207
134
|
isVisible: (element) ->
|
208
135
|
element = @element unless element
|
209
136
|
|
210
|
-
if
|
137
|
+
if window.getComputedStyle(element).display == 'none'
|
211
138
|
false
|
212
139
|
else if element.parentElement
|
213
140
|
this.isVisible element.parentElement
|
@@ -216,6 +143,7 @@ class PoltergeistAgent.Node
|
|
216
143
|
|
217
144
|
position: ->
|
218
145
|
rect = @element.getClientRects()[0]
|
146
|
+
throw new PoltergeistAgent.ObsoleteNode unless rect
|
219
147
|
|
220
148
|
{
|
221
149
|
top: rect.top,
|
@@ -230,7 +158,7 @@ class PoltergeistAgent.Node
|
|
230
158
|
if Node.EVENTS.MOUSE.indexOf(name) != -1
|
231
159
|
event = document.createEvent('MouseEvent')
|
232
160
|
event.initMouseEvent(
|
233
|
-
name, true, true,
|
161
|
+
name, true, true, window, 0, 0, 0, 0, 0,
|
234
162
|
false, false, false, false, 0, null
|
235
163
|
)
|
236
164
|
else if Node.EVENTS.FOCUS.indexOf(name) != -1
|
@@ -241,6 +169,13 @@ class PoltergeistAgent.Node
|
|
241
169
|
|
242
170
|
@element.dispatchEvent(event)
|
243
171
|
|
172
|
+
focusAndHighlight: ->
|
173
|
+
@element.focus()
|
174
|
+
@element.select()
|
175
|
+
|
176
|
+
blur: ->
|
177
|
+
@element.blur()
|
178
|
+
|
244
179
|
clickTest: (x, y) ->
|
245
180
|
el = origEl = document.elementFromPoint(x, y)
|
246
181
|
|
@@ -260,45 +195,6 @@ class PoltergeistAgent.Node
|
|
260
195
|
selector += ".#{className}"
|
261
196
|
selector
|
262
197
|
|
263
|
-
characterToKeyCode: (character) ->
|
264
|
-
code = character.toUpperCase().charCodeAt(0)
|
265
|
-
specialKeys =
|
266
|
-
96: 192 #`
|
267
|
-
45: 189 #-
|
268
|
-
61: 187 #=
|
269
|
-
91: 219 #[
|
270
|
-
93: 221 #]
|
271
|
-
92: 220 #\
|
272
|
-
59: 186 #;
|
273
|
-
39: 222 #'
|
274
|
-
44: 188 #,
|
275
|
-
46: 190 #.
|
276
|
-
47: 191 #/
|
277
|
-
127: 46 #delete
|
278
|
-
126: 192 #~
|
279
|
-
33: 49 #!
|
280
|
-
64: 50 #@
|
281
|
-
35: 51 ##
|
282
|
-
36: 52 #$
|
283
|
-
37: 53 #%
|
284
|
-
94: 54 #^
|
285
|
-
38: 55 #&
|
286
|
-
42: 56 #*
|
287
|
-
40: 57 #(
|
288
|
-
41: 48 #)
|
289
|
-
95: 189 #_
|
290
|
-
43: 187 #+
|
291
|
-
123: 219 #{
|
292
|
-
125: 221 #}
|
293
|
-
124: 220 #|
|
294
|
-
58: 186 #:
|
295
|
-
34: 222 #"
|
296
|
-
60: 188 #<
|
297
|
-
62: 190 #>
|
298
|
-
63: 191 #?
|
299
|
-
|
300
|
-
specialKeys[code] || code
|
301
|
-
|
302
198
|
isDOMEqual: (other_id) ->
|
303
199
|
@element == @agent.get(other_id).element
|
304
200
|
|
@@ -1,15 +1,20 @@
|
|
1
1
|
class Poltergeist.Browser
|
2
2
|
constructor: (@owner, width, height) ->
|
3
|
-
@width
|
4
|
-
@height
|
5
|
-
@state
|
6
|
-
@
|
3
|
+
@width = width || 1024
|
4
|
+
@height = height || 768
|
5
|
+
@state = 'default'
|
6
|
+
@page_stack = []
|
7
|
+
@page_id = 0
|
7
8
|
|
8
9
|
this.resetPage()
|
9
10
|
|
10
11
|
resetPage: ->
|
11
|
-
|
12
|
-
|
12
|
+
if @page?
|
13
|
+
@page.release()
|
14
|
+
phantom.clearCookies()
|
15
|
+
|
16
|
+
@page = new Poltergeist.WebPage
|
17
|
+
@page.setViewportSize(width: @width, height: @height)
|
13
18
|
|
14
19
|
@page.onLoadStarted = =>
|
15
20
|
@state = 'loading' if @state == 'clicked'
|
@@ -19,18 +24,32 @@ class Poltergeist.Browser
|
|
19
24
|
|
20
25
|
@page.onLoadFinished = (status) =>
|
21
26
|
if @state == 'loading'
|
22
|
-
this.sendResponse(status)
|
27
|
+
this.sendResponse(status: status, click: @last_click)
|
28
|
+
@state = 'default'
|
29
|
+
else if @state == 'awaiting_frame_load'
|
30
|
+
this.sendResponse(true)
|
23
31
|
@state = 'default'
|
24
32
|
|
25
33
|
@page.onInitialized = =>
|
26
34
|
@page_id += 1
|
27
35
|
|
36
|
+
@page.onPageCreated = (sub_page) =>
|
37
|
+
if @state == 'awaiting_sub_page'
|
38
|
+
name = @page_name
|
39
|
+
@state = 'default'
|
40
|
+
@page_name = null
|
41
|
+
|
42
|
+
# At this point subpage isn't fully initialized, so we can't check
|
43
|
+
# its name. Instead, we just schedule another attempt to push the
|
44
|
+
# window.
|
45
|
+
setTimeout((=> this.push_window(name)), 0)
|
46
|
+
|
28
47
|
sendResponse: (response) ->
|
29
48
|
errors = @page.errors()
|
30
49
|
|
31
50
|
if errors.length > 0
|
32
51
|
@page.clearErrors()
|
33
|
-
|
52
|
+
@owner.sendError(new Poltergeist.JavascriptError(errors))
|
34
53
|
else
|
35
54
|
@owner.sendResponse(response)
|
36
55
|
|
@@ -40,9 +59,16 @@ class Poltergeist.Browser
|
|
40
59
|
else
|
41
60
|
throw new Poltergeist.ObsoleteNode
|
42
61
|
|
43
|
-
visit: (url
|
44
|
-
@state
|
45
|
-
@page.
|
62
|
+
visit: (url) ->
|
63
|
+
@state = 'loading'
|
64
|
+
prev_url = @page.currentUrl()
|
65
|
+
|
66
|
+
@page.open(url)
|
67
|
+
|
68
|
+
if /#/.test(url) && prev_url.split('#')[0] == url.split('#')[0]
|
69
|
+
# hashchange occurred, so there will be no onLoadFinished
|
70
|
+
@state = 'default'
|
71
|
+
this.sendResponse 'success'
|
46
72
|
|
47
73
|
current_url: ->
|
48
74
|
this.sendResponse @page.currentUrl()
|
@@ -103,12 +129,40 @@ class Poltergeist.Browser
|
|
103
129
|
@page.execute("function() { #{script} }")
|
104
130
|
this.sendResponse(true)
|
105
131
|
|
106
|
-
push_frame: (
|
107
|
-
@page.pushFrame(
|
108
|
-
|
132
|
+
push_frame: (name) ->
|
133
|
+
if @page.pushFrame(name)
|
134
|
+
if @page.currentUrl() == 'about:blank'
|
135
|
+
@state = 'awaiting_frame_load'
|
136
|
+
else
|
137
|
+
this.sendResponse(true)
|
138
|
+
else
|
139
|
+
# There's currently no PhantomJS callback available for frame creation,
|
140
|
+
# so we have to poll
|
141
|
+
setTimeout((=> this.push_frame(name)), 50)
|
109
142
|
|
110
143
|
pop_frame: ->
|
111
|
-
@page.popFrame()
|
144
|
+
this.sendResponse(@page.popFrame())
|
145
|
+
|
146
|
+
push_window: (name) ->
|
147
|
+
sub_page = @page.getPage(name)
|
148
|
+
|
149
|
+
if sub_page
|
150
|
+
if sub_page.currentUrl() == 'about:blank'
|
151
|
+
sub_page.onLoadFinished = =>
|
152
|
+
sub_page.onLoadFinished = null
|
153
|
+
this.push_window(name)
|
154
|
+
else
|
155
|
+
@page_stack.push(@page)
|
156
|
+
@page = sub_page
|
157
|
+
@page_id += 1
|
158
|
+
this.sendResponse(true)
|
159
|
+
else
|
160
|
+
@page_name = name
|
161
|
+
@state = 'awaiting_sub_page'
|
162
|
+
|
163
|
+
pop_window: ->
|
164
|
+
prev_page = @page_stack.pop()
|
165
|
+
@page = prev_page if prev_page
|
112
166
|
this.sendResponse(true)
|
113
167
|
|
114
168
|
click: (page_id, id) ->
|
@@ -119,11 +173,13 @@ class Poltergeist.Browser
|
|
119
173
|
# state and wait for onLoadFinished before sending a response.
|
120
174
|
@state = 'clicked'
|
121
175
|
|
122
|
-
node.click()
|
176
|
+
@last_click = node.click()
|
123
177
|
|
124
|
-
|
125
|
-
@state
|
126
|
-
|
178
|
+
setTimeout =>
|
179
|
+
if @state != 'loading'
|
180
|
+
@state = 'default'
|
181
|
+
this.sendResponse(@last_click)
|
182
|
+
, 5
|
127
183
|
|
128
184
|
drag: (page_id, id, other_id) ->
|
129
185
|
this.node(page_id, id).dragTo this.node(page_id, other_id)
|
@@ -163,6 +219,28 @@ class Poltergeist.Browser
|
|
163
219
|
network_traffic: ->
|
164
220
|
this.sendResponse(@page.networkTraffic())
|
165
221
|
|
222
|
+
set_headers: (headers) ->
|
223
|
+
# Workaround for https://code.google.com/p/phantomjs/issues/detail?id=745
|
224
|
+
@page.setUserAgent(headers['User-Agent']) if headers['User-Agent']
|
225
|
+
@page.setCustomHeaders(headers)
|
226
|
+
this.sendResponse(true)
|
227
|
+
|
228
|
+
response_headers: ->
|
229
|
+
this.sendResponse(@page.responseHeaders())
|
230
|
+
|
231
|
+
cookies: ->
|
232
|
+
this.sendResponse(@page.cookies())
|
233
|
+
|
234
|
+
# We're using phantom.addCookie so that cookies can be set
|
235
|
+
# before the first page load has taken place.
|
236
|
+
set_cookie: (cookie) ->
|
237
|
+
phantom.addCookie(cookie)
|
238
|
+
this.sendResponse(true)
|
239
|
+
|
240
|
+
remove_cookie: (name) ->
|
241
|
+
@page.deleteCookie(name)
|
242
|
+
this.sendResponse(true)
|
243
|
+
|
166
244
|
exit: ->
|
167
245
|
phantom.exit()
|
168
246
|
|
@@ -5,8 +5,6 @@ PoltergeistAgent = (function() {
|
|
5
5
|
function PoltergeistAgent() {
|
6
6
|
this.elements = [];
|
7
7
|
this.nodes = {};
|
8
|
-
this.windows = [];
|
9
|
-
this.pushWindow(window);
|
10
8
|
}
|
11
9
|
|
12
10
|
PoltergeistAgent.prototype.externalCall = function(name, args) {
|
@@ -25,35 +23,21 @@ PoltergeistAgent = (function() {
|
|
25
23
|
};
|
26
24
|
|
27
25
|
PoltergeistAgent.stringify = function(object) {
|
28
|
-
|
29
|
-
|
30
|
-
|
26
|
+
try {
|
27
|
+
return JSON.stringify(object, function(key, value) {
|
28
|
+
if (Array.isArray(this[key])) {
|
29
|
+
return this[key];
|
30
|
+
} else {
|
31
|
+
return value;
|
32
|
+
}
|
33
|
+
});
|
34
|
+
} catch (error) {
|
35
|
+
if (error instanceof TypeError) {
|
36
|
+
return '"(cyclic structure)"';
|
31
37
|
} else {
|
32
|
-
|
38
|
+
throw error;
|
33
39
|
}
|
34
|
-
}
|
35
|
-
};
|
36
|
-
|
37
|
-
PoltergeistAgent.prototype.pushWindow = function(new_window) {
|
38
|
-
this.windows.push(new_window);
|
39
|
-
this.window = new_window;
|
40
|
-
this.document = this.window.document;
|
41
|
-
return null;
|
42
|
-
};
|
43
|
-
|
44
|
-
PoltergeistAgent.prototype.popWindow = function() {
|
45
|
-
this.windows.pop();
|
46
|
-
this.window = this.windows[this.windows.length - 1];
|
47
|
-
this.document = this.window.document;
|
48
|
-
return null;
|
49
|
-
};
|
50
|
-
|
51
|
-
PoltergeistAgent.prototype.pushFrame = function(id) {
|
52
|
-
return this.pushWindow(this.document.getElementById(id).contentWindow);
|
53
|
-
};
|
54
|
-
|
55
|
-
PoltergeistAgent.prototype.popFrame = function() {
|
56
|
-
return this.popWindow();
|
40
|
+
}
|
57
41
|
};
|
58
42
|
|
59
43
|
PoltergeistAgent.prototype.currentUrl = function() {
|
@@ -63,9 +47,9 @@ PoltergeistAgent = (function() {
|
|
63
47
|
PoltergeistAgent.prototype.find = function(selector, within) {
|
64
48
|
var i, ids, results, _i, _ref;
|
65
49
|
if (within == null) {
|
66
|
-
within =
|
50
|
+
within = document;
|
67
51
|
}
|
68
|
-
results =
|
52
|
+
results = document.evaluate(selector, within, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
|
69
53
|
ids = [];
|
70
54
|
for (i = _i = 0, _ref = results.snapshotLength; 0 <= _ref ? _i < _ref : _i > _ref; i = 0 <= _ref ? ++_i : --_i) {
|
71
55
|
ids.push(this.register(results.snapshotItem(i)));
|
@@ -80,8 +64,8 @@ PoltergeistAgent = (function() {
|
|
80
64
|
|
81
65
|
PoltergeistAgent.prototype.documentSize = function() {
|
82
66
|
return {
|
83
|
-
height:
|
84
|
-
width:
|
67
|
+
height: document.documentElement.scrollHeight,
|
68
|
+
width: document.documentElement.scrollWidth
|
85
69
|
};
|
86
70
|
};
|
87
71
|
|
@@ -140,7 +124,7 @@ PoltergeistAgent.Node = (function() {
|
|
140
124
|
_this = this;
|
141
125
|
obsolete = function(element) {
|
142
126
|
if (element.parentNode != null) {
|
143
|
-
if (element.parentNode ===
|
127
|
+
if (element.parentNode === document) {
|
144
128
|
return false;
|
145
129
|
} else {
|
146
130
|
return obsolete(element.parentNode);
|
@@ -159,61 +143,16 @@ PoltergeistAgent.Node = (function() {
|
|
159
143
|
return this.element.dispatchEvent(event);
|
160
144
|
};
|
161
145
|
|
162
|
-
Node.prototype.input = function() {
|
163
|
-
var event;
|
164
|
-
event = document.createEvent('HTMLEvents');
|
165
|
-
event.initEvent('input', true, false);
|
166
|
-
return this.element.dispatchEvent(event);
|
167
|
-
};
|
168
|
-
|
169
|
-
Node.prototype.keyupdowned = function(eventName, keyCode) {
|
170
|
-
var event;
|
171
|
-
event = document.createEvent('UIEvents');
|
172
|
-
event.initEvent(eventName, true, true);
|
173
|
-
event.keyCode = keyCode;
|
174
|
-
event.which = keyCode;
|
175
|
-
event.charCode = 0;
|
176
|
-
return this.element.dispatchEvent(event);
|
177
|
-
};
|
178
|
-
|
179
|
-
Node.prototype.keypressed = function(altKey, ctrlKey, shiftKey, metaKey, keyCode, charCode) {
|
180
|
-
var event;
|
181
|
-
event = document.createEvent('UIEvents');
|
182
|
-
event.initEvent('keypress', true, true);
|
183
|
-
event.window = this.agent.window;
|
184
|
-
event.altKey = altKey;
|
185
|
-
event.ctrlKey = ctrlKey;
|
186
|
-
event.shiftKey = shiftKey;
|
187
|
-
event.metaKey = metaKey;
|
188
|
-
event.keyCode = keyCode;
|
189
|
-
event.charCode = charCode;
|
190
|
-
event.which = keyCode;
|
191
|
-
return this.element.dispatchEvent(event);
|
192
|
-
};
|
193
|
-
|
194
146
|
Node.prototype.insideBody = function() {
|
195
|
-
return this.element ===
|
147
|
+
return this.element === document.body || document.evaluate('ancestor::body', this.element, null, XPathResult.BOOLEAN_TYPE, null).booleanValue;
|
196
148
|
};
|
197
149
|
|
198
150
|
Node.prototype.text = function() {
|
199
|
-
|
200
|
-
|
201
|
-
return '';
|
202
|
-
}
|
203
|
-
if (this.insideBody()) {
|
204
|
-
el = this.element;
|
151
|
+
if (this.element.tagName === 'TEXTAREA') {
|
152
|
+
return this.element.textContent;
|
205
153
|
} else {
|
206
|
-
|
154
|
+
return this.element.innerText;
|
207
155
|
}
|
208
|
-
results = this.agent.document.evaluate('.//text()[not(ancestor::script)]', el, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
|
209
|
-
text = '';
|
210
|
-
for (i = _i = 0, _ref = results.snapshotLength; 0 <= _ref ? _i < _ref : _i > _ref; i = 0 <= _ref ? ++_i : --_i) {
|
211
|
-
node = results.snapshotItem(i);
|
212
|
-
if (this.isVisible(node.parentNode)) {
|
213
|
-
text += node.textContent;
|
214
|
-
}
|
215
|
-
}
|
216
|
-
return text;
|
217
156
|
};
|
218
157
|
|
219
158
|
Node.prototype.getAttribute = function(name) {
|
@@ -245,26 +184,6 @@ PoltergeistAgent.Node = (function() {
|
|
245
184
|
}
|
246
185
|
};
|
247
186
|
|
248
|
-
Node.prototype.set = function(value) {
|
249
|
-
var char, keyCode, _i, _len;
|
250
|
-
if (this.element.maxLength >= 0) {
|
251
|
-
value = value.substr(0, this.element.maxLength);
|
252
|
-
}
|
253
|
-
this.element.value = '';
|
254
|
-
this.trigger('focus');
|
255
|
-
for (_i = 0, _len = value.length; _i < _len; _i++) {
|
256
|
-
char = value[_i];
|
257
|
-
this.element.value += char;
|
258
|
-
keyCode = this.characterToKeyCode(char);
|
259
|
-
this.keyupdowned('keydown', keyCode);
|
260
|
-
this.keypressed(false, false, false, false, char.charCodeAt(0), char.charCodeAt(0));
|
261
|
-
this.keyupdowned('keyup', keyCode);
|
262
|
-
}
|
263
|
-
this.changed();
|
264
|
-
this.input();
|
265
|
-
return this.trigger('blur');
|
266
|
-
};
|
267
|
-
|
268
187
|
Node.prototype.isMultiple = function() {
|
269
188
|
return this.element.multiple;
|
270
189
|
};
|
@@ -295,7 +214,7 @@ PoltergeistAgent.Node = (function() {
|
|
295
214
|
if (!element) {
|
296
215
|
element = this.element;
|
297
216
|
}
|
298
|
-
if (
|
217
|
+
if (window.getComputedStyle(element).display === 'none') {
|
299
218
|
return false;
|
300
219
|
} else if (element.parentElement) {
|
301
220
|
return this.isVisible(element.parentElement);
|
@@ -307,6 +226,9 @@ PoltergeistAgent.Node = (function() {
|
|
307
226
|
Node.prototype.position = function() {
|
308
227
|
var rect;
|
309
228
|
rect = this.element.getClientRects()[0];
|
229
|
+
if (!rect) {
|
230
|
+
throw new PoltergeistAgent.ObsoleteNode;
|
231
|
+
}
|
310
232
|
return {
|
311
233
|
top: rect.top,
|
312
234
|
right: rect.right,
|
@@ -321,7 +243,7 @@ PoltergeistAgent.Node = (function() {
|
|
321
243
|
var event;
|
322
244
|
if (Node.EVENTS.MOUSE.indexOf(name) !== -1) {
|
323
245
|
event = document.createEvent('MouseEvent');
|
324
|
-
event.initMouseEvent(name, true, true,
|
246
|
+
event.initMouseEvent(name, true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
|
325
247
|
} else if (Node.EVENTS.FOCUS.indexOf(name) !== -1) {
|
326
248
|
event = document.createEvent('HTMLEvents');
|
327
249
|
event.initEvent(name, true, true);
|
@@ -331,6 +253,15 @@ PoltergeistAgent.Node = (function() {
|
|
331
253
|
return this.element.dispatchEvent(event);
|
332
254
|
};
|
333
255
|
|
256
|
+
Node.prototype.focusAndHighlight = function() {
|
257
|
+
this.element.focus();
|
258
|
+
return this.element.select();
|
259
|
+
};
|
260
|
+
|
261
|
+
Node.prototype.blur = function() {
|
262
|
+
return this.element.blur();
|
263
|
+
};
|
264
|
+
|
334
265
|
Node.prototype.clickTest = function(x, y) {
|
335
266
|
var el, origEl;
|
336
267
|
el = origEl = document.elementFromPoint(x, y);
|
@@ -364,47 +295,6 @@ PoltergeistAgent.Node = (function() {
|
|
364
295
|
return selector;
|
365
296
|
};
|
366
297
|
|
367
|
-
Node.prototype.characterToKeyCode = function(character) {
|
368
|
-
var code, specialKeys;
|
369
|
-
code = character.toUpperCase().charCodeAt(0);
|
370
|
-
specialKeys = {
|
371
|
-
96: 192,
|
372
|
-
45: 189,
|
373
|
-
61: 187,
|
374
|
-
91: 219,
|
375
|
-
93: 221,
|
376
|
-
92: 220,
|
377
|
-
59: 186,
|
378
|
-
39: 222,
|
379
|
-
44: 188,
|
380
|
-
46: 190,
|
381
|
-
47: 191,
|
382
|
-
127: 46,
|
383
|
-
126: 192,
|
384
|
-
33: 49,
|
385
|
-
64: 50,
|
386
|
-
35: 51,
|
387
|
-
36: 52,
|
388
|
-
37: 53,
|
389
|
-
94: 54,
|
390
|
-
38: 55,
|
391
|
-
42: 56,
|
392
|
-
40: 57,
|
393
|
-
41: 48,
|
394
|
-
95: 189,
|
395
|
-
43: 187,
|
396
|
-
123: 219,
|
397
|
-
125: 221,
|
398
|
-
124: 220,
|
399
|
-
58: 186,
|
400
|
-
34: 222,
|
401
|
-
60: 188,
|
402
|
-
62: 190,
|
403
|
-
63: 191
|
404
|
-
};
|
405
|
-
return specialKeys[code] || code;
|
406
|
-
};
|
407
|
-
|
408
298
|
Node.prototype.isDOMEqual = function(other_id) {
|
409
299
|
return this.element === this.agent.get(other_id).element;
|
410
300
|
};
|