poltergeist 0.6.0 → 0.7.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 +77 -40
- data/lib/capybara/poltergeist.rb +11 -11
- data/lib/capybara/poltergeist/browser.rb +35 -12
- data/lib/capybara/poltergeist/client.rb +9 -12
- data/lib/capybara/poltergeist/client/agent.coffee +99 -6
- data/lib/capybara/poltergeist/client/browser.coffee +57 -79
- data/lib/capybara/poltergeist/client/compiled/agent.js +179 -19
- data/lib/capybara/poltergeist/client/compiled/browser.js +109 -81
- data/lib/capybara/poltergeist/client/compiled/connection.js +8 -1
- data/lib/capybara/poltergeist/client/compiled/main.js +75 -34
- data/lib/capybara/poltergeist/client/compiled/node.js +32 -39
- data/lib/capybara/poltergeist/client/compiled/web_page.js +118 -41
- data/lib/capybara/poltergeist/client/main.coffee +11 -23
- data/lib/capybara/poltergeist/client/node.coffee +16 -33
- data/lib/capybara/poltergeist/client/web_page.coffee +57 -26
- data/lib/capybara/poltergeist/driver.rb +36 -6
- data/lib/capybara/poltergeist/errors.rb +4 -15
- data/lib/capybara/poltergeist/json.rb +25 -0
- data/lib/capybara/poltergeist/network_traffic.rb +6 -0
- data/lib/capybara/poltergeist/network_traffic/request.rb +26 -0
- data/lib/capybara/poltergeist/network_traffic/response.rb +40 -0
- data/lib/capybara/poltergeist/node.rb +10 -6
- data/lib/capybara/poltergeist/version.rb +1 -1
- data/lib/capybara/poltergeist/web_socket_server.rb +3 -0
- metadata +112 -23
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# Poltergeist - A PhantomJS driver for Capybara #
|
2
2
|
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.7.0
|
4
4
|
|
5
5
|
[](http://travis-ci.org/jonleighton/poltergeist)
|
6
6
|
[](https://gemnasium.com/jonleighton/poltergeist)
|
@@ -18,47 +18,31 @@ require 'capybara/poltergeist'
|
|
18
18
|
Capybara.javascript_driver = :poltergeist
|
19
19
|
```
|
20
20
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
`Transfer-Encoding: chunked`
|
26
|
-
([commit](https://github.com/rack/rack/commit/50cdd0bf000a9ffb3eb3760fda2ff3e1ad18f3a7)).
|
27
|
-
This has been observed to cause problems,
|
28
|
-
probably due to race conditions in Qt's HTTP handling code, so you are
|
29
|
-
recommended to avoid this by specifying your own server setup for
|
30
|
-
Capybara:
|
31
|
-
|
32
|
-
``` ruby
|
33
|
-
Capybara.server do |app, port|
|
34
|
-
require 'rack/handler/thin'
|
35
|
-
Thin::Logging.silent = true
|
36
|
-
Thin::Server.new('0.0.0.0', port, app).start
|
37
|
-
end
|
38
|
-
```
|
39
|
-
|
40
|
-
If you're using Rails 3.0, this affects you. If you're using Rails 3.1+,
|
41
|
-
this doesn't affect you.
|
21
|
+
If you were previously using the `:rack_test` driver, be aware that
|
22
|
+
your app will now run in a separate thread and this can have
|
23
|
+
consequences for transactional tests. [See the Capybara README for more
|
24
|
+
detail](https://github.com/jnicklas/capybara/blob/master/README.md#transactions-and-database-setup).
|
42
25
|
|
43
26
|
## Installing PhantomJS ##
|
44
27
|
|
45
|
-
You need PhantomJS 1.
|
46
|
-
need Qt, or
|
28
|
+
You need at least PhantomJS 1.6.0, but 1.6.1 is recommended as there some issues with the former.
|
29
|
+
There are *no other external dependencies* (you don't need Qt, or a running X
|
30
|
+
server, etc.)
|
47
31
|
|
48
32
|
### Mac ###
|
49
33
|
|
50
|
-
* *
|
51
|
-
* *
|
34
|
+
* *Manual install*: [Download this](http://code.google.com/p/phantomjs/downloads/detail?name=phantomjs-1.6.1-macosx-static.zip&can=2&q=)
|
35
|
+
* *Homebrew*: `brew install phantomjs`
|
52
36
|
|
53
37
|
### Linux ###
|
54
38
|
|
55
39
|
* Download the [32
|
56
|
-
bit](http://code.google.com/p/phantomjs/downloads/detail?name=phantomjs-1.
|
40
|
+
bit](http://code.google.com/p/phantomjs/downloads/detail?name=phantomjs-1.6.1-linux-i686-dynamic.tar.bz2&can=2&q=)
|
57
41
|
or [64
|
58
|
-
bit](http://code.google.com/p/phantomjs/downloads/detail?name=phantomjs-1.
|
42
|
+
bit](http://code.google.com/p/phantomjs/downloads/detail?name=phantomjs-1.6.1-linux-x86_64-dynamic.tar.bz2&can=2&q=)
|
59
43
|
binary.
|
60
|
-
* Extract it: `sudo tar
|
61
|
-
* Link it: `sudo ln -s /usr/local/phantomjs
|
44
|
+
* Extract it: `sudo tar xvjf phantomjs-1.6.1-linux-*-dynamic.tar.gz -C /usr/local`
|
45
|
+
* Link it: `sudo ln -s /usr/local/phantomjs-1.6.1-linux*/bin/phantomjs /usr/local/bin/phantomjs`
|
62
46
|
|
63
47
|
(Note that you cannot copy the `/usr/local/phantomjs/bin/phantomjs`
|
64
48
|
binary elsewhere on its own as it dynamically links with other files in
|
@@ -69,7 +53,7 @@ binary elsewhere on its own as it dynamically links with other files in
|
|
69
53
|
Do this as a last resort if the binaries don't work for you. It will
|
70
54
|
take quite a long time as it has to build WebKit.
|
71
55
|
|
72
|
-
* Download [the source tarball](http://code.google.com/p/phantomjs/downloads/detail?name=phantomjs-1.
|
56
|
+
* Download [the source tarball](http://code.google.com/p/phantomjs/downloads/detail?name=phantomjs-1.6.1-source.zip&can=2&q=)
|
73
57
|
* Extract and cd in
|
74
58
|
* `./build.sh`
|
75
59
|
|
@@ -79,7 +63,7 @@ Supported: MRI 1.8.7, MRI 1.9.2, MRI 1.9.3, JRuby 1.8, JRuby 1.9.
|
|
79
63
|
|
80
64
|
Not supported:
|
81
65
|
|
82
|
-
* Rubinius
|
66
|
+
* Rubinius
|
83
67
|
* Windows
|
84
68
|
|
85
69
|
Contributions are welcome in order to move 'unsupported'
|
@@ -90,11 +74,11 @@ items into the 'supported' list.
|
|
90
74
|
There are no special steps to take. You don't need Xvfb or any running X
|
91
75
|
server at all.
|
92
76
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
77
|
+
Depending on your tests, one thing that you may need is some fonts. If
|
78
|
+
you're getting errors on a CI that don't occur during development then
|
79
|
+
try taking some screenshots - it may well be missing fonts throwing
|
80
|
+
things off kilter. Your distro will have various font packages available
|
81
|
+
to install.
|
98
82
|
|
99
83
|
## What's supported? ##
|
100
84
|
|
@@ -126,9 +110,28 @@ When this option is enabled, you can insert `page.driver.debug` into
|
|
126
110
|
your tests to pause the test and launch a browser which gives you the
|
127
111
|
WebKit inspector to view your test run with.
|
128
112
|
|
129
|
-
|
130
|
-
|
131
|
-
|
113
|
+
[Read more
|
114
|
+
here](http://jonathanleighton.com/articles/2012/poltergeist-0-6-0/)
|
115
|
+
|
116
|
+
### Setting request headers ###
|
117
|
+
|
118
|
+
Additional HTTP request headers can be set like so:
|
119
|
+
|
120
|
+
``` ruby
|
121
|
+
page.driver.headers = {
|
122
|
+
"Cookie" => "foo=bar",
|
123
|
+
"Host" => "foo.com"
|
124
|
+
}
|
125
|
+
```
|
126
|
+
|
127
|
+
They will be cleared between tests, so you do not have to do this manually.
|
128
|
+
|
129
|
+
### Inspecting network traffic ###
|
130
|
+
|
131
|
+
You can inspect the network traffic (i.e. what resources have been
|
132
|
+
loaded) on the current page by calling `page.driver.network_traffic`.
|
133
|
+
This returns an array of request objects. A request object has a
|
134
|
+
`response_parts` method containing data about the response chunks.
|
132
135
|
|
133
136
|
## Customization ##
|
134
137
|
|
@@ -150,6 +153,11 @@ end
|
|
150
153
|
when communicating with PhantomJS. `nil` means wait forever. Default
|
151
154
|
is 30.
|
152
155
|
* `:inspector` (Boolean, String) - See 'Remote Debugging', above.
|
156
|
+
* `:js_errors` (Boolean) - When false, Javascript errors do not get re-raised in Ruby.
|
157
|
+
* `:window_size` (Array) - The dimensions of the browser window in which to test, expressed
|
158
|
+
as a 2-element array, e.g. [1024, 768]. Default: [1024, 768]
|
159
|
+
* `:phantomjs_options` (Array) - Additional [command line options](http://code.google.com/p/phantomjs/wiki/Interface#Command-line_Options)
|
160
|
+
to be passed to PhantomJS, e.g. `['--load-images=no', '--ignore-ssl-errors=yes']`
|
153
161
|
|
154
162
|
## Bugs ##
|
155
163
|
|
@@ -173,6 +181,35 @@ makes debugging easier). Running `rake autocompile` will watch the
|
|
173
181
|
|
174
182
|
## Changes ##
|
175
183
|
|
184
|
+
### 0.7.0 ###
|
185
|
+
|
186
|
+
#### Features ####
|
187
|
+
|
188
|
+
* Added an option `:js_errors`, allowing poltergeist to continue
|
189
|
+
running after JS errors. (John Griffin & Tom Stuart) [Issue #62] [Issue #69]
|
190
|
+
* Added an option `:window_size`, allowing users to specify
|
191
|
+
dimensions to which the browser window will be resized.
|
192
|
+
(Tom Stuart) [Issue #53]
|
193
|
+
* Capybara 1.0 is no longer supported. Capybara ~> 1.1 is required.
|
194
|
+
* Added ability to set arbitrary http request headers
|
195
|
+
* Inspect network traffic on the page via
|
196
|
+
`page.driver.network_traffic` (Doug McInnes) [Issue #77]
|
197
|
+
* Added an option `:phantomjs_options`, allowing users to specify
|
198
|
+
additional command-line options passed to phantomjs executable.
|
199
|
+
(wynst) [Issue #97]
|
200
|
+
* Scroll element into viewport if needed on click (Gabriel Sobrinho)
|
201
|
+
[Issue #83]
|
202
|
+
* Added status code support. (Dmitriy Nesteryuk and Jon Leighton) [Issue #37]
|
203
|
+
|
204
|
+
#### Bug fixes ###
|
205
|
+
|
206
|
+
* Fix issue with `ClickFailed` exception happening with a negative
|
207
|
+
co-ordinate (which should be impossible). (Jon Leighton, Gabriel
|
208
|
+
Sobrinho, Tom Stuart) [Issue #60]
|
209
|
+
* Fix issue with `undefined method map for "[]":String`, which
|
210
|
+
happened when dealing with pages that include JS rewriting
|
211
|
+
Array.prototype.toJSON. (Tom Stuart) [Issue #63]
|
212
|
+
|
176
213
|
### 0.6.0 ###
|
177
214
|
|
178
215
|
#### Features ####
|
data/lib/capybara/poltergeist.rb
CHANGED
@@ -2,17 +2,17 @@ require 'capybara'
|
|
2
2
|
|
3
3
|
module Capybara
|
4
4
|
module Poltergeist
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
5
|
+
require 'capybara/poltergeist/driver'
|
6
|
+
require 'capybara/poltergeist/browser'
|
7
|
+
require 'capybara/poltergeist/node'
|
8
|
+
require 'capybara/poltergeist/server'
|
9
|
+
require 'capybara/poltergeist/web_socket_server'
|
10
|
+
require 'capybara/poltergeist/client'
|
11
|
+
require 'capybara/poltergeist/util'
|
12
|
+
require 'capybara/poltergeist/inspector'
|
13
|
+
require 'capybara/poltergeist/spawn'
|
14
|
+
require 'capybara/poltergeist/json'
|
15
|
+
require 'capybara/poltergeist/network_traffic'
|
16
16
|
require 'capybara/poltergeist/errors'
|
17
17
|
end
|
18
18
|
end
|
@@ -2,12 +2,13 @@ require 'multi_json'
|
|
2
2
|
|
3
3
|
module Capybara::Poltergeist
|
4
4
|
class Browser
|
5
|
-
attr_reader :server, :client, :logger
|
5
|
+
attr_reader :server, :client, :logger, :js_errors
|
6
6
|
|
7
|
-
def initialize(server, client, logger = nil)
|
8
|
-
@server
|
9
|
-
@client
|
10
|
-
@logger
|
7
|
+
def initialize(server, client, logger = nil, js_errors = true)
|
8
|
+
@server = server
|
9
|
+
@client = client
|
10
|
+
@logger = logger
|
11
|
+
@js_errors = js_errors
|
11
12
|
end
|
12
13
|
|
13
14
|
def restart
|
@@ -15,14 +16,18 @@ module Capybara::Poltergeist
|
|
15
16
|
client.restart
|
16
17
|
end
|
17
18
|
|
18
|
-
def visit(url)
|
19
|
-
command 'visit', url
|
19
|
+
def visit(url, headers)
|
20
|
+
command 'visit', url, headers
|
20
21
|
end
|
21
22
|
|
22
23
|
def current_url
|
23
24
|
command 'current_url'
|
24
25
|
end
|
25
26
|
|
27
|
+
def status_code
|
28
|
+
command 'status_code'
|
29
|
+
end
|
30
|
+
|
26
31
|
def body
|
27
32
|
command 'body'
|
28
33
|
end
|
@@ -79,6 +84,7 @@ module Capybara::Poltergeist
|
|
79
84
|
def within_frame(id, &block)
|
80
85
|
command 'push_frame', id
|
81
86
|
yield
|
87
|
+
ensure
|
82
88
|
command 'pop_frame'
|
83
89
|
end
|
84
90
|
|
@@ -103,29 +109,46 @@ module Capybara::Poltergeist
|
|
103
109
|
end
|
104
110
|
|
105
111
|
def render(path, options = {})
|
106
|
-
command 'render', path, !!options[:full]
|
112
|
+
command 'render', path.to_s, !!options[:full]
|
107
113
|
end
|
108
114
|
|
109
115
|
def resize(width, height)
|
110
116
|
command 'resize', width, height
|
111
117
|
end
|
112
118
|
|
119
|
+
def network_traffic
|
120
|
+
command('network_traffic').values.map do |event|
|
121
|
+
NetworkTraffic::Request.new(
|
122
|
+
event['request'],
|
123
|
+
event['responseParts'].map { |response| NetworkTraffic::Response.new(response) }
|
124
|
+
)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
def equals(page_id, id, other_id)
|
129
|
+
command('equals', page_id, id, other_id)
|
130
|
+
end
|
131
|
+
|
113
132
|
def command(name, *args)
|
114
133
|
message = { 'name' => name, 'args' => args }
|
115
134
|
log message.inspect
|
116
135
|
|
117
|
-
json =
|
136
|
+
json = JSON.load(server.send(JSON.dump(message)))
|
118
137
|
log json.inspect
|
119
138
|
|
120
139
|
if json['error']
|
121
140
|
if json['error']['name'] == 'Poltergeist.JavascriptError'
|
122
|
-
|
141
|
+
error = JavascriptError.new(json['error'])
|
142
|
+
if js_errors
|
143
|
+
raise error
|
144
|
+
else
|
145
|
+
log error
|
146
|
+
end
|
123
147
|
else
|
124
148
|
raise BrowserError.new(json['error'])
|
125
149
|
end
|
126
|
-
else
|
127
|
-
json['response']
|
128
150
|
end
|
151
|
+
json['response']
|
129
152
|
|
130
153
|
rescue DeadClient
|
131
154
|
restart
|
@@ -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.6.0'
|
5
5
|
PHANTOMJS_NAME = 'phantomjs'
|
6
6
|
|
7
7
|
def self.start(*args)
|
@@ -10,12 +10,13 @@ module Capybara::Poltergeist
|
|
10
10
|
client
|
11
11
|
end
|
12
12
|
|
13
|
-
attr_reader :pid, :port, :path, :
|
13
|
+
attr_reader :pid, :port, :path, :window_size, :phantomjs_options
|
14
14
|
|
15
|
-
def initialize(port,
|
16
|
-
@port
|
17
|
-
@
|
18
|
-
@
|
15
|
+
def initialize(port, options = {})
|
16
|
+
@port = port
|
17
|
+
@path = options[:path] || PHANTOMJS_NAME
|
18
|
+
@window_size = options[:window_size] || [1024, 768]
|
19
|
+
@phantomjs_options = options[:phantomjs_options] || []
|
19
20
|
|
20
21
|
pid = Process.pid
|
21
22
|
at_exit { stop if Process.pid == pid }
|
@@ -47,14 +48,10 @@ module Capybara::Poltergeist
|
|
47
48
|
def command
|
48
49
|
@command ||= begin
|
49
50
|
parts = [path]
|
50
|
-
|
51
|
-
if inspector
|
52
|
-
parts << "--remote-debugger-port=#{inspector.port}"
|
53
|
-
parts << "--remote-debugger-autorun=yes"
|
54
|
-
end
|
55
|
-
|
51
|
+
parts.concat phantomjs_options
|
56
52
|
parts << PHANTOMJS_SCRIPT
|
57
53
|
parts << port
|
54
|
+
parts.concat window_size
|
58
55
|
parts
|
59
56
|
end
|
60
57
|
end
|
@@ -7,8 +7,18 @@ class PoltergeistAgent
|
|
7
7
|
@windows = []
|
8
8
|
this.pushWindow(window)
|
9
9
|
|
10
|
-
externalCall: (name,
|
11
|
-
|
10
|
+
externalCall: (name, args) ->
|
11
|
+
try
|
12
|
+
{ value: this[name].apply(this, args) }
|
13
|
+
catch error
|
14
|
+
{ error: { message: error.toString(), stack: error.stack } }
|
15
|
+
|
16
|
+
@stringify: (object) ->
|
17
|
+
JSON.stringify object, (key, value) ->
|
18
|
+
if Array.isArray(this[key])
|
19
|
+
return this[key]
|
20
|
+
else
|
21
|
+
return value
|
12
22
|
|
13
23
|
pushWindow: (new_window) ->
|
14
24
|
@windows.push(new_window)
|
@@ -55,10 +65,10 @@ class PoltergeistAgent
|
|
55
65
|
get: (id) ->
|
56
66
|
@nodes[id] or= new PoltergeistAgent.Node(this, @elements[id])
|
57
67
|
|
58
|
-
nodeCall: (id, name,
|
68
|
+
nodeCall: (id, name, args) ->
|
59
69
|
node = this.get(id)
|
60
70
|
throw new PoltergeistAgent.ObsoleteNode if node.isObsolete()
|
61
|
-
node[name].apply(node,
|
71
|
+
node[name].apply(node, args)
|
62
72
|
|
63
73
|
class PoltergeistAgent.ObsoleteNode
|
64
74
|
toString: -> "PoltergeistAgent.ObsoleteNode"
|
@@ -91,7 +101,33 @@ class PoltergeistAgent.Node
|
|
91
101
|
|
92
102
|
changed: ->
|
93
103
|
event = document.createEvent('HTMLEvents')
|
94
|
-
event.initEvent(
|
104
|
+
event.initEvent('change', true, false)
|
105
|
+
@element.dispatchEvent(event)
|
106
|
+
|
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
|
95
131
|
@element.dispatchEvent(event)
|
96
132
|
|
97
133
|
insideBody: ->
|
@@ -120,6 +156,9 @@ class PoltergeistAgent.Node
|
|
120
156
|
else
|
121
157
|
@element.getAttribute(name)
|
122
158
|
|
159
|
+
scrollIntoView: ->
|
160
|
+
@element.scrollIntoViewIfNeeded()
|
161
|
+
|
123
162
|
value: ->
|
124
163
|
if @element.tagName == 'SELECT' && @element.multiple
|
125
164
|
option.value for option in @element.children when option.selected
|
@@ -130,8 +169,20 @@ class PoltergeistAgent.Node
|
|
130
169
|
if (@element.maxLength >= 0)
|
131
170
|
value = value.substr(0, @element.maxLength)
|
132
171
|
|
133
|
-
@element.value =
|
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
|
+
|
134
183
|
this.changed()
|
184
|
+
this.input()
|
185
|
+
this.trigger('blur')
|
135
186
|
|
136
187
|
isMultiple: ->
|
137
188
|
@element.multiple
|
@@ -209,6 +260,48 @@ class PoltergeistAgent.Node
|
|
209
260
|
selector += ".#{className}"
|
210
261
|
selector
|
211
262
|
|
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
|
+
isDOMEqual: (other_id) ->
|
303
|
+
@element == @agent.get(other_id).element
|
304
|
+
|
212
305
|
window.__poltergeist = new PoltergeistAgent
|
213
306
|
|
214
307
|
document.addEventListener(
|