poltergeistFork 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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
+ });