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.
Files changed (43) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +22 -0
  3. data/README.md +425 -0
  4. data/lib/capybara/poltergeist/browser.rb +426 -0
  5. data/lib/capybara/poltergeist/client.rb +151 -0
  6. data/lib/capybara/poltergeist/client/agent.coffee +423 -0
  7. data/lib/capybara/poltergeist/client/browser.coffee +497 -0
  8. data/lib/capybara/poltergeist/client/cmd.coffee +17 -0
  9. data/lib/capybara/poltergeist/client/compiled/agent.js +587 -0
  10. data/lib/capybara/poltergeist/client/compiled/browser.js +687 -0
  11. data/lib/capybara/poltergeist/client/compiled/cmd.js +31 -0
  12. data/lib/capybara/poltergeist/client/compiled/connection.js +25 -0
  13. data/lib/capybara/poltergeist/client/compiled/main.js +228 -0
  14. data/lib/capybara/poltergeist/client/compiled/node.js +88 -0
  15. data/lib/capybara/poltergeist/client/compiled/web_page.js +539 -0
  16. data/lib/capybara/poltergeist/client/connection.coffee +11 -0
  17. data/lib/capybara/poltergeist/client/main.coffee +99 -0
  18. data/lib/capybara/poltergeist/client/node.coffee +70 -0
  19. data/lib/capybara/poltergeist/client/pre/agent.js +587 -0
  20. data/lib/capybara/poltergeist/client/pre/browser.js +688 -0
  21. data/lib/capybara/poltergeist/client/pre/cmd.js +31 -0
  22. data/lib/capybara/poltergeist/client/pre/connection.js +25 -0
  23. data/lib/capybara/poltergeist/client/pre/main.js +228 -0
  24. data/lib/capybara/poltergeist/client/pre/node.js +88 -0
  25. data/lib/capybara/poltergeist/client/pre/web_page.js +540 -0
  26. data/lib/capybara/poltergeist/client/web_page.coffee +372 -0
  27. data/lib/capybara/poltergeist/command.rb +17 -0
  28. data/lib/capybara/poltergeist/cookie.rb +35 -0
  29. data/lib/capybara/poltergeist/driver.rb +394 -0
  30. data/lib/capybara/poltergeist/errors.rb +183 -0
  31. data/lib/capybara/poltergeist/inspector.rb +46 -0
  32. data/lib/capybara/poltergeist/json.rb +25 -0
  33. data/lib/capybara/poltergeist/network_traffic.rb +7 -0
  34. data/lib/capybara/poltergeist/network_traffic/error.rb +19 -0
  35. data/lib/capybara/poltergeist/network_traffic/request.rb +27 -0
  36. data/lib/capybara/poltergeist/network_traffic/response.rb +40 -0
  37. data/lib/capybara/poltergeist/node.rb +177 -0
  38. data/lib/capybara/poltergeist/server.rb +36 -0
  39. data/lib/capybara/poltergeist/utility.rb +9 -0
  40. data/lib/capybara/poltergeist/version.rb +5 -0
  41. data/lib/capybara/poltergeist/web_socket_server.rb +107 -0
  42. data/lib/capybara/poltergeistFork.rb +27 -0
  43. 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
+ });