Chris@0
|
1 var __indexOf = [].indexOf || function (item) {
|
Chris@0
|
2 for (var i = 0, l = this.length; i < l; i++) {
|
Chris@0
|
3 if (i in this && this[i] === item) return i;
|
Chris@0
|
4 }
|
Chris@0
|
5 return -1;
|
Chris@0
|
6 };
|
Chris@0
|
7
|
Chris@0
|
8 var xpathStringLiteral = function (s) {
|
Chris@0
|
9 if (s.indexOf('"') === -1)
|
Chris@0
|
10 return '"' + s + '"';
|
Chris@0
|
11 if (s.indexOf("'") === -1)
|
Chris@0
|
12 return "'" + s + "'";
|
Chris@0
|
13 return 'concat("' + s.replace(/"/g, '",\'"\',"') + '")';
|
Chris@0
|
14 };
|
Chris@0
|
15
|
Chris@0
|
16 Poltergeist.Browser = (function () {
|
Chris@0
|
17 /**
|
Chris@0
|
18 * Creates the "browser" inside phantomjs
|
Chris@0
|
19 * @param owner
|
Chris@0
|
20 * @param width
|
Chris@0
|
21 * @param height
|
Chris@0
|
22 * @param jsErrors
|
Chris@0
|
23 * @constructor
|
Chris@0
|
24 */
|
Chris@0
|
25 function Browser(owner, width, height, jsErrors) {
|
Chris@0
|
26 this.owner = owner;
|
Chris@0
|
27 this.width = width || 1024;
|
Chris@0
|
28 this.height = height || 768;
|
Chris@0
|
29 this.pages = [];
|
Chris@0
|
30 this.js_errors = (typeof jsErrors === 'boolean') ? jsErrors : true;
|
Chris@2
|
31 this._resourceTimeout = false;
|
Chris@0
|
32 this._debug = false;
|
Chris@0
|
33 this._counter = 0;
|
Chris@0
|
34 this.resetPage();
|
Chris@0
|
35 }
|
Chris@0
|
36
|
Chris@0
|
37 /**
|
Chris@0
|
38 * Resets the browser to a clean slate
|
Chris@0
|
39 */
|
Chris@0
|
40 Browser.prototype.resetPage = function () {
|
Chris@0
|
41 var _ref;
|
Chris@0
|
42 var self = this;
|
Chris@0
|
43
|
Chris@0
|
44 _ref = [0, []];
|
Chris@0
|
45 this._counter = _ref[0];
|
Chris@0
|
46 this.pages = _ref[1];
|
Chris@0
|
47
|
Chris@0
|
48 if (this.page != null) {
|
Chris@0
|
49 if (!this.page.closed) {
|
Chris@0
|
50 if (this.page.currentUrl() !== 'about:blank') {
|
Chris@0
|
51 this.page.clearLocalStorage();
|
Chris@0
|
52 }
|
Chris@0
|
53 this.page.release();
|
Chris@0
|
54 }
|
Chris@0
|
55 phantom.clearCookies();
|
Chris@0
|
56 }
|
Chris@0
|
57
|
Chris@2
|
58 this.page = this.currentPage = new Poltergeist.WebPage(null, this);
|
Chris@0
|
59 this.page.setViewportSize({
|
Chris@0
|
60 width: this.width,
|
Chris@0
|
61 height: this.height
|
Chris@0
|
62 });
|
Chris@2
|
63 };
|
Chris@0
|
64
|
Chris@2
|
65 /**
|
Chris@2
|
66 * Adds given newly opened Poltergeist.WebPage to the list of available windows/frames
|
Chris@2
|
67 * consulted by methods getPageByHandle, window_handle, window_handles, switch_to_window and close_window.
|
Chris@2
|
68 *
|
Chris@2
|
69 * @param {WebPage} page
|
Chris@2
|
70 */
|
Chris@2
|
71 Browser.prototype.registerPage = function (page) {
|
Chris@2
|
72 if (!('handle' in page))
|
Chris@2
|
73 {
|
Chris@2
|
74 page.handle = "" + (this._counter++);
|
Chris@2
|
75 this.pages.push(page);
|
Chris@2
|
76 }
|
Chris@2
|
77 };
|
Chris@2
|
78
|
Chris@2
|
79 /**
|
Chris@2
|
80 * Removes given closed Poltergeist.WebPage from the list of available windows/frames
|
Chris@2
|
81 * consulted by methods getPageByHandle, window_handle, window_handles, switch_to_window and close_window.
|
Chris@2
|
82 *
|
Chris@2
|
83 * @param {Poltergeist.WebPage} page
|
Chris@2
|
84 */
|
Chris@2
|
85 Browser.prototype.unregisterPage = function (page) {
|
Chris@2
|
86 if (('handle' in page) && (page.handle !== null))
|
Chris@2
|
87 {
|
Chris@2
|
88 for (var i = this.pages.length; i--;) {
|
Chris@2
|
89 if (page === this.pages[i]) {
|
Chris@2
|
90 this.pages.splice(i,1);
|
Chris@2
|
91 break;
|
Chris@2
|
92 }
|
Chris@2
|
93 }
|
Chris@2
|
94 page.handle = null;
|
Chris@2
|
95 }
|
Chris@0
|
96 };
|
Chris@0
|
97
|
Chris@0
|
98 /**
|
Chris@0
|
99 * Given a page handle id, tries to get it from the browser page list
|
Chris@0
|
100 * @param handle
|
Chris@0
|
101 * @return {WebPage}
|
Chris@0
|
102 */
|
Chris@0
|
103 Browser.prototype.getPageByHandle = function (handle) {
|
Chris@0
|
104 var filteredPages;
|
Chris@0
|
105
|
Chris@0
|
106 //TODO: perhaps we should throw a PageNotFoundByHandle or something like that..
|
Chris@0
|
107 if (handle === null || typeof handle == "undefined") {
|
Chris@0
|
108 return null;
|
Chris@0
|
109 }
|
Chris@0
|
110
|
Chris@0
|
111 filteredPages = this.pages.filter(function (p) {
|
Chris@0
|
112 return !p.closed && p.handle === handle;
|
Chris@0
|
113 });
|
Chris@0
|
114
|
Chris@0
|
115 if (filteredPages.length === 1) {
|
Chris@0
|
116 return filteredPages[0];
|
Chris@0
|
117 }
|
Chris@0
|
118
|
Chris@0
|
119 return null;
|
Chris@0
|
120 };
|
Chris@0
|
121
|
Chris@0
|
122 /**
|
Chris@0
|
123 * Sends a debug message to the console
|
Chris@0
|
124 * @param message
|
Chris@0
|
125 * @return {*}
|
Chris@0
|
126 */
|
Chris@0
|
127 Browser.prototype.debug = function (message) {
|
Chris@0
|
128 if (this._debug) {
|
Chris@0
|
129 return console.log("poltergeist [" + (new Date().getTime()) + "] " + message);
|
Chris@0
|
130 }
|
Chris@0
|
131 };
|
Chris@0
|
132
|
Chris@0
|
133 /**
|
Chris@0
|
134 * Given a page_id and id, gets if possible the node in such page
|
Chris@0
|
135 * @param page_id
|
Chris@0
|
136 * @param id
|
Chris@0
|
137 * @return {Poltergeist.Node}
|
Chris@0
|
138 */
|
Chris@0
|
139 Browser.prototype.node = function (page_id, id) {
|
Chris@0
|
140 if (this.currentPage.id === page_id) {
|
Chris@0
|
141 return this.currentPage.get(id);
|
Chris@0
|
142 } else {
|
Chris@0
|
143 throw new Poltergeist.ObsoleteNode;
|
Chris@0
|
144 }
|
Chris@0
|
145 };
|
Chris@0
|
146
|
Chris@0
|
147 /**
|
Chris@0
|
148 * Returns the frameUrl related to the frame given by name
|
Chris@0
|
149 * @param frame_name
|
Chris@0
|
150 * @return {*}
|
Chris@0
|
151 */
|
Chris@0
|
152 Browser.prototype.frameUrl = function (frame_name) {
|
Chris@0
|
153 return this.currentPage.frameUrl(frame_name);
|
Chris@0
|
154 };
|
Chris@0
|
155
|
Chris@0
|
156 /**
|
Chris@0
|
157 * This method defines the rectangular area of the web page to be rasterized when render is invoked.
|
Chris@0
|
158 * If no clipping rectangle is set, render will process the entire web page.
|
Chris@0
|
159 * @param full
|
Chris@0
|
160 * @param selector
|
Chris@0
|
161 * @return {*}
|
Chris@0
|
162 */
|
Chris@0
|
163 Browser.prototype.set_clip_rect = function (full, selector) {
|
Chris@0
|
164 var dimensions, clipDocument, rect, clipViewport;
|
Chris@0
|
165
|
Chris@0
|
166 dimensions = this.currentPage.validatedDimensions();
|
Chris@0
|
167 clipDocument = dimensions.document;
|
Chris@0
|
168 clipViewport = dimensions.viewport;
|
Chris@0
|
169
|
Chris@0
|
170 if (full) {
|
Chris@0
|
171 rect = {
|
Chris@0
|
172 left: 0,
|
Chris@0
|
173 top: 0,
|
Chris@0
|
174 width: clipDocument.width,
|
Chris@0
|
175 height: clipDocument.height
|
Chris@0
|
176 };
|
Chris@0
|
177 } else {
|
Chris@0
|
178 if (selector != null) {
|
Chris@0
|
179 rect = this.currentPage.elementBounds(selector);
|
Chris@0
|
180 } else {
|
Chris@0
|
181 rect = {
|
Chris@0
|
182 left: 0,
|
Chris@0
|
183 top: 0,
|
Chris@0
|
184 width: clipViewport.width,
|
Chris@0
|
185 height: clipViewport.height
|
Chris@0
|
186 };
|
Chris@0
|
187 }
|
Chris@0
|
188 }
|
Chris@0
|
189
|
Chris@0
|
190 this.currentPage.setClipRect(rect);
|
Chris@0
|
191 return dimensions;
|
Chris@0
|
192 };
|
Chris@0
|
193
|
Chris@0
|
194 /**
|
Chris@0
|
195 * Kill the browser, i.e kill phantomjs current process
|
Chris@0
|
196 * @return {int}
|
Chris@0
|
197 */
|
Chris@0
|
198 Browser.prototype.exit = function () {
|
Chris@0
|
199 return phantom.exit(0);
|
Chris@0
|
200 };
|
Chris@0
|
201
|
Chris@0
|
202 /**
|
Chris@0
|
203 * Do nothing
|
Chris@0
|
204 */
|
Chris@0
|
205 Browser.prototype.noop = function () {
|
Chris@0
|
206 };
|
Chris@0
|
207
|
Chris@0
|
208 /**
|
Chris@0
|
209 * Throws a new Object error
|
Chris@0
|
210 */
|
Chris@0
|
211 Browser.prototype.browser_error = function () {
|
Chris@0
|
212 throw new Error('zomg');
|
Chris@0
|
213 };
|
Chris@0
|
214
|
Chris@0
|
215 /**
|
Chris@0
|
216 * Visits a page and load its content
|
Chris@0
|
217 * @param serverResponse
|
Chris@0
|
218 * @param url
|
Chris@0
|
219 * @return {*}
|
Chris@0
|
220 */
|
Chris@0
|
221 Browser.prototype.visit = function (serverResponse, url) {
|
Chris@0
|
222 var prevUrl;
|
Chris@0
|
223 var self = this;
|
Chris@0
|
224 this.currentPage.state = 'loading';
|
Chris@2
|
225
|
Chris@2
|
226 if (this._resourceTimeout) {
|
Chris@2
|
227 this.currentPage._native.settings.resourceTimeout = this._resourceTimeout;
|
Chris@2
|
228 this.currentPage._native.onResourceTimeout = function (request) {
|
Chris@2
|
229 console.log('Response (#' + request.id + '): ' + JSON.stringify(request));
|
Chris@2
|
230 };
|
Chris@2
|
231 }
|
Chris@2
|
232
|
Chris@0
|
233 prevUrl = this.currentPage.source === null ? 'about:blank' : this.currentPage.currentUrl();
|
Chris@0
|
234 this.currentPage.open(url);
|
Chris@0
|
235 if (/#/.test(url) && prevUrl.split('#')[0] === url.split('#')[0]) {
|
Chris@0
|
236 this.currentPage.state = 'default';
|
Chris@0
|
237 return this.serverSendResponse({
|
Chris@0
|
238 status: 'success'
|
Chris@0
|
239 }, serverResponse);
|
Chris@0
|
240 } else {
|
Chris@0
|
241 return this.currentPage.waitState('default', function () {
|
Chris@0
|
242 if (self.currentPage.statusCode === null && self.currentPage.status === 'fail') {
|
Chris@0
|
243 return self.owner.serverSendError(new Poltergeist.StatusFailError, serverResponse);
|
Chris@0
|
244 } else {
|
Chris@0
|
245 return self.serverSendResponse({
|
Chris@0
|
246 status: self.currentPage.status
|
Chris@0
|
247 }, serverResponse);
|
Chris@0
|
248 }
|
Chris@0
|
249 });
|
Chris@0
|
250 }
|
Chris@0
|
251 };
|
Chris@0
|
252
|
Chris@0
|
253 /**
|
Chris@0
|
254 * Puts the control of the browser inside the IFRAME given by name
|
Chris@0
|
255 * @param serverResponse
|
Chris@0
|
256 * @param name
|
Chris@0
|
257 * @param timeout
|
Chris@0
|
258 * @return {*}
|
Chris@0
|
259 */
|
Chris@0
|
260 Browser.prototype.push_frame = function (serverResponse, name, timeout) {
|
Chris@0
|
261 var _ref;
|
Chris@0
|
262 var self = this;
|
Chris@0
|
263
|
Chris@0
|
264 if (timeout == null) {
|
Chris@0
|
265 timeout = new Date().getTime() + 2000;
|
Chris@0
|
266 }
|
Chris@0
|
267
|
Chris@0
|
268 //TODO: WTF, else if after a if with return COMMON
|
Chris@0
|
269 if (_ref = this.frameUrl(name), __indexOf.call(this.currentPage.blockedUrls(), _ref) >= 0) {
|
Chris@0
|
270 return this.serverSendResponse(true, serverResponse);
|
Chris@0
|
271 } else if (this.currentPage.pushFrame(name)) {
|
Chris@0
|
272 if (this.currentPage.currentUrl() === 'about:blank') {
|
Chris@0
|
273 this.currentPage.state = 'awaiting_frame_load';
|
Chris@0
|
274 return this.currentPage.waitState('default', function () {
|
Chris@0
|
275 return self.serverSendResponse(true, serverResponse);
|
Chris@0
|
276 });
|
Chris@0
|
277 } else {
|
Chris@0
|
278 return this.serverSendResponse(true, serverResponse);
|
Chris@0
|
279 }
|
Chris@0
|
280 } else {
|
Chris@0
|
281 if (new Date().getTime() < timeout) {
|
Chris@0
|
282 return setTimeout((function () {
|
Chris@0
|
283 return self.push_frame(serverResponse, name, timeout);
|
Chris@0
|
284 }), 50);
|
Chris@0
|
285 } else {
|
Chris@0
|
286 return this.owner.serverSendError(new Poltergeist.FrameNotFound(name), serverResponse);
|
Chris@0
|
287 }
|
Chris@0
|
288 }
|
Chris@0
|
289 };
|
Chris@0
|
290
|
Chris@0
|
291 /**
|
Chris@0
|
292 * Injects a javascript into the current page
|
Chris@0
|
293 * @param serverResponse
|
Chris@0
|
294 * @param extension
|
Chris@0
|
295 * @return {*}
|
Chris@0
|
296 */
|
Chris@0
|
297 Browser.prototype.add_extension = function (serverResponse, extension) {
|
Chris@0
|
298 //TODO: error control when the injection was not possible
|
Chris@0
|
299 this.currentPage.injectExtension(extension);
|
Chris@0
|
300 return this.serverSendResponse('success', serverResponse);
|
Chris@0
|
301 };
|
Chris@0
|
302
|
Chris@0
|
303 /**
|
Chris@0
|
304 * Returns the url we are currently in
|
Chris@0
|
305 * @param serverResponse
|
Chris@0
|
306 * @return {*}
|
Chris@0
|
307 */
|
Chris@0
|
308 Browser.prototype.current_url = function (serverResponse) {
|
Chris@0
|
309 return this.serverSendResponse(this.currentPage.currentUrl(), serverResponse);
|
Chris@0
|
310 };
|
Chris@0
|
311
|
Chris@0
|
312 /**
|
Chris@0
|
313 * Returns the current page window name
|
Chris@0
|
314 * @param serverResponse
|
Chris@0
|
315 * @returns {*}
|
Chris@0
|
316 */
|
Chris@0
|
317 Browser.prototype.window_name = function (serverResponse) {
|
Chris@0
|
318 return this.serverSendResponse(this.currentPage.windowName(), serverResponse);
|
Chris@0
|
319 };
|
Chris@0
|
320
|
Chris@0
|
321 /**
|
Chris@0
|
322 * Returns the status code associated to the page
|
Chris@0
|
323 * @param serverResponse
|
Chris@0
|
324 * @return {*}
|
Chris@0
|
325 */
|
Chris@0
|
326 Browser.prototype.status_code = function (serverResponse) {
|
Chris@0
|
327 if (this.currentPage.statusCode === undefined || this.currentPage.statusCode === null) {
|
Chris@0
|
328 return this.owner.serverSendError(new Poltergeist.StatusFailError("status_code_error"), serverResponse);
|
Chris@0
|
329 }
|
Chris@0
|
330 return this.serverSendResponse(this.currentPage.statusCode, serverResponse);
|
Chris@0
|
331 };
|
Chris@0
|
332
|
Chris@0
|
333 /**
|
Chris@0
|
334 * Returns the source code of the active frame, useful for when inside an IFRAME
|
Chris@0
|
335 * @param serverResponse
|
Chris@0
|
336 * @return {*}
|
Chris@0
|
337 */
|
Chris@0
|
338 Browser.prototype.body = function (serverResponse) {
|
Chris@0
|
339 return this.serverSendResponse(this.currentPage.content(), serverResponse);
|
Chris@0
|
340 };
|
Chris@0
|
341
|
Chris@0
|
342 /**
|
Chris@0
|
343 * Returns the source code of the page all the html
|
Chris@0
|
344 * @param serverResponse
|
Chris@0
|
345 * @return {*}
|
Chris@0
|
346 */
|
Chris@0
|
347 Browser.prototype.source = function (serverResponse) {
|
Chris@0
|
348 return this.serverSendResponse(this.currentPage.source, serverResponse);
|
Chris@0
|
349 };
|
Chris@0
|
350
|
Chris@0
|
351 /**
|
Chris@0
|
352 * Returns the current page title
|
Chris@0
|
353 * @param serverResponse
|
Chris@0
|
354 * @return {*}
|
Chris@0
|
355 */
|
Chris@0
|
356 Browser.prototype.title = function (serverResponse) {
|
Chris@0
|
357 return this.serverSendResponse(this.currentPage.title(), serverResponse);
|
Chris@0
|
358 };
|
Chris@0
|
359
|
Chris@0
|
360 /**
|
Chris@0
|
361 * Finds the elements that match a method of selection and a selector
|
Chris@0
|
362 * @param serverResponse
|
Chris@0
|
363 * @param method
|
Chris@0
|
364 * @param selector
|
Chris@0
|
365 * @return {*}
|
Chris@0
|
366 */
|
Chris@0
|
367 Browser.prototype.find = function (serverResponse, method, selector) {
|
Chris@0
|
368 return this.serverSendResponse({
|
Chris@0
|
369 page_id: this.currentPage.id,
|
Chris@0
|
370 ids: this.currentPage.find(method, selector)
|
Chris@0
|
371 }, serverResponse);
|
Chris@0
|
372 };
|
Chris@0
|
373
|
Chris@0
|
374 /**
|
Chris@0
|
375 * Find elements within a given element
|
Chris@0
|
376 * @param serverResponse
|
Chris@0
|
377 * @param page_id
|
Chris@0
|
378 * @param id
|
Chris@0
|
379 * @param method
|
Chris@0
|
380 * @param selector
|
Chris@0
|
381 * @return {*}
|
Chris@0
|
382 */
|
Chris@0
|
383 Browser.prototype.find_within = function (serverResponse, page_id, id, method, selector) {
|
Chris@0
|
384 return this.serverSendResponse(this.node(page_id, id).find(method, selector), serverResponse);
|
Chris@0
|
385 };
|
Chris@0
|
386
|
Chris@0
|
387 /**
|
Chris@0
|
388 * Returns ALL the text, visible and not visible from the given element
|
Chris@0
|
389 * @param serverResponse
|
Chris@0
|
390 * @param page_id
|
Chris@0
|
391 * @param id
|
Chris@0
|
392 * @return {*}
|
Chris@0
|
393 */
|
Chris@0
|
394 Browser.prototype.all_text = function (serverResponse, page_id, id) {
|
Chris@0
|
395 return this.serverSendResponse(this.node(page_id, id).allText(), serverResponse);
|
Chris@0
|
396 };
|
Chris@0
|
397
|
Chris@0
|
398 /**
|
Chris@0
|
399 * Returns the inner or outer html of a given id
|
Chris@0
|
400 * @param serverResponse
|
Chris@0
|
401 * @param page_id
|
Chris@0
|
402 * @param id
|
Chris@0
|
403 * @param type
|
Chris@0
|
404 * @returns Object
|
Chris@0
|
405 */
|
Chris@0
|
406 Browser.prototype.all_html = function (serverResponse, page_id, id, type) {
|
Chris@0
|
407 return this.serverSendResponse(this.node(page_id, id).allHTML(type), serverResponse);
|
Chris@0
|
408 };
|
Chris@0
|
409
|
Chris@0
|
410 /**
|
Chris@0
|
411 * Returns only the visible text in a given element
|
Chris@0
|
412 * @param serverResponse
|
Chris@0
|
413 * @param page_id
|
Chris@0
|
414 * @param id
|
Chris@0
|
415 * @return {*}
|
Chris@0
|
416 */
|
Chris@0
|
417 Browser.prototype.visible_text = function (serverResponse, page_id, id) {
|
Chris@0
|
418 return this.serverSendResponse(this.node(page_id, id).visibleText(), serverResponse);
|
Chris@0
|
419 };
|
Chris@0
|
420
|
Chris@0
|
421 /**
|
Chris@0
|
422 * Deletes the text in a given element leaving it empty
|
Chris@0
|
423 * @param serverResponse
|
Chris@0
|
424 * @param page_id
|
Chris@0
|
425 * @param id
|
Chris@0
|
426 * @return {*}
|
Chris@0
|
427 */
|
Chris@0
|
428 Browser.prototype.delete_text = function (serverResponse, page_id, id) {
|
Chris@0
|
429 return this.serverSendResponse(this.node(page_id, id).deleteText(), serverResponse);
|
Chris@0
|
430 };
|
Chris@0
|
431
|
Chris@0
|
432 /**
|
Chris@0
|
433 * Gets the value of a given attribute in an element
|
Chris@0
|
434 * @param serverResponse
|
Chris@0
|
435 * @param page_id
|
Chris@0
|
436 * @param id
|
Chris@0
|
437 * @param name
|
Chris@0
|
438 * @return {*}
|
Chris@0
|
439 */
|
Chris@0
|
440 Browser.prototype.attribute = function (serverResponse, page_id, id, name) {
|
Chris@0
|
441 return this.serverSendResponse(this.node(page_id, id).getAttribute(name), serverResponse);
|
Chris@0
|
442 };
|
Chris@0
|
443
|
Chris@0
|
444 /**
|
Chris@0
|
445 * Allows the possibility to set an attribute on a given element
|
Chris@0
|
446 * @param serverResponse
|
Chris@0
|
447 * @param page_id
|
Chris@0
|
448 * @param id
|
Chris@0
|
449 * @param name
|
Chris@0
|
450 * @param value
|
Chris@0
|
451 * @returns {*}
|
Chris@0
|
452 */
|
Chris@0
|
453 Browser.prototype.set_attribute = function (serverResponse, page_id, id, name, value) {
|
Chris@0
|
454 return this.serverSendResponse(this.node(page_id, id).setAttribute(name, value), serverResponse);
|
Chris@0
|
455 };
|
Chris@0
|
456
|
Chris@0
|
457 /**
|
Chris@0
|
458 * Allows the possibility to remove an attribute on a given element
|
Chris@0
|
459 * @param serverResponse
|
Chris@0
|
460 * @param page_id
|
Chris@0
|
461 * @param id
|
Chris@0
|
462 * @param name
|
Chris@0
|
463 * @returns {*}
|
Chris@0
|
464 */
|
Chris@0
|
465 Browser.prototype.remove_attribute = function (serverResponse, page_id, id, name) {
|
Chris@0
|
466 return this.serverSendResponse(this.node(page_id, id).removeAttribute(name), serverResponse);
|
Chris@0
|
467 };
|
Chris@0
|
468
|
Chris@0
|
469 /**
|
Chris@0
|
470 * Returns all the attributes of a given element
|
Chris@0
|
471 * @param serverResponse
|
Chris@0
|
472 * @param page_id
|
Chris@0
|
473 * @param id
|
Chris@0
|
474 * @param name
|
Chris@0
|
475 * @return {*}
|
Chris@0
|
476 */
|
Chris@0
|
477 Browser.prototype.attributes = function (serverResponse, page_id, id, name) {
|
Chris@0
|
478 return this.serverSendResponse(this.node(page_id, id).getAttributes(), serverResponse);
|
Chris@0
|
479 };
|
Chris@0
|
480
|
Chris@0
|
481 /**
|
Chris@0
|
482 * Returns all the way to the document level the parents of a given element
|
Chris@0
|
483 * @param serverResponse
|
Chris@0
|
484 * @param page_id
|
Chris@0
|
485 * @param id
|
Chris@0
|
486 * @return {*}
|
Chris@0
|
487 */
|
Chris@0
|
488 Browser.prototype.parents = function (serverResponse, page_id, id) {
|
Chris@0
|
489 return this.serverSendResponse(this.node(page_id, id).parentIds(), serverResponse);
|
Chris@0
|
490 };
|
Chris@0
|
491
|
Chris@0
|
492 /**
|
Chris@0
|
493 * Returns the element.value of an element given by its page and id
|
Chris@0
|
494 * @param serverResponse
|
Chris@0
|
495 * @param page_id
|
Chris@0
|
496 * @param id
|
Chris@0
|
497 * @return {*}
|
Chris@0
|
498 */
|
Chris@0
|
499 Browser.prototype.value = function (serverResponse, page_id, id) {
|
Chris@0
|
500 return this.serverSendResponse(this.node(page_id, id).value(), serverResponse);
|
Chris@0
|
501 };
|
Chris@0
|
502
|
Chris@0
|
503 /**
|
Chris@0
|
504 * Sets the element.value of an element by the given value
|
Chris@0
|
505 * @param serverResponse
|
Chris@0
|
506 * @param page_id
|
Chris@0
|
507 * @param id
|
Chris@0
|
508 * @param value
|
Chris@0
|
509 * @return {*}
|
Chris@0
|
510 */
|
Chris@0
|
511 Browser.prototype.set = function (serverResponse, page_id, id, value) {
|
Chris@0
|
512 this.node(page_id, id).set(value);
|
Chris@0
|
513 return this.serverSendResponse(true, serverResponse);
|
Chris@0
|
514 };
|
Chris@0
|
515
|
Chris@0
|
516 /**
|
Chris@0
|
517 * Uploads a file to an input file element
|
Chris@0
|
518 * @param serverResponse
|
Chris@0
|
519 * @param page_id
|
Chris@0
|
520 * @param id
|
Chris@0
|
521 * @param file_path
|
Chris@0
|
522 * @return {*}
|
Chris@0
|
523 */
|
Chris@0
|
524 Browser.prototype.select_file = function (serverResponse, page_id, id, file_path) {
|
Chris@0
|
525 var node = this.node(page_id, id);
|
Chris@0
|
526
|
Chris@0
|
527 this.currentPage.beforeUpload(node.id);
|
Chris@0
|
528 this.currentPage.uploadFile('[_poltergeist_selected]', file_path);
|
Chris@0
|
529 this.currentPage.afterUpload(node.id);
|
Chris@0
|
530
|
Chris@0
|
531 return this.serverSendResponse(true, serverResponse);
|
Chris@0
|
532 };
|
Chris@0
|
533
|
Chris@0
|
534 /**
|
Chris@0
|
535 * Sets a value to the selected element (to be used in select elements)
|
Chris@0
|
536 * @param serverResponse
|
Chris@0
|
537 * @param page_id
|
Chris@0
|
538 * @param id
|
Chris@0
|
539 * @param value
|
Chris@0
|
540 * @return {*}
|
Chris@0
|
541 */
|
Chris@0
|
542 Browser.prototype.select = function (serverResponse, page_id, id, value) {
|
Chris@0
|
543 return this.serverSendResponse(this.node(page_id, id).select(value), serverResponse);
|
Chris@0
|
544 };
|
Chris@0
|
545
|
Chris@0
|
546 /**
|
Chris@0
|
547 * Selects an option with the given value
|
Chris@0
|
548 * @param serverResponse
|
Chris@0
|
549 * @param page_id
|
Chris@0
|
550 * @param id
|
Chris@0
|
551 * @param value
|
Chris@0
|
552 * @param multiple
|
Chris@0
|
553 * @return {*}
|
Chris@0
|
554 */
|
Chris@0
|
555 Browser.prototype.select_option = function (serverResponse, page_id, id, value, multiple) {
|
Chris@0
|
556 return this.serverSendResponse(this.node(page_id, id).select_option(value, multiple), serverResponse);
|
Chris@0
|
557 };
|
Chris@0
|
558
|
Chris@0
|
559 /**
|
Chris@0
|
560 *
|
Chris@0
|
561 * @param serverResponse
|
Chris@0
|
562 * @param page_id
|
Chris@0
|
563 * @param id
|
Chris@0
|
564 * @return {*}
|
Chris@0
|
565 */
|
Chris@0
|
566 Browser.prototype.tag_name = function (serverResponse, page_id, id) {
|
Chris@0
|
567 return this.serverSendResponse(this.node(page_id, id).tagName(), serverResponse);
|
Chris@0
|
568 };
|
Chris@0
|
569
|
Chris@0
|
570
|
Chris@0
|
571 /**
|
Chris@0
|
572 * Tells if an element is visible or not
|
Chris@0
|
573 * @param serverResponse
|
Chris@0
|
574 * @param page_id
|
Chris@0
|
575 * @param id
|
Chris@0
|
576 * @return {*}
|
Chris@0
|
577 */
|
Chris@0
|
578 Browser.prototype.visible = function (serverResponse, page_id, id) {
|
Chris@0
|
579 return this.serverSendResponse(this.node(page_id, id).isVisible(), serverResponse);
|
Chris@0
|
580 };
|
Chris@0
|
581
|
Chris@0
|
582 /**
|
Chris@0
|
583 * Tells if an element is disabled
|
Chris@0
|
584 * @param serverResponse
|
Chris@0
|
585 * @param page_id
|
Chris@0
|
586 * @param id
|
Chris@0
|
587 * @return {*}
|
Chris@0
|
588 */
|
Chris@0
|
589 Browser.prototype.disabled = function (serverResponse, page_id, id) {
|
Chris@0
|
590 return this.serverSendResponse(this.node(page_id, id).isDisabled(), serverResponse);
|
Chris@0
|
591 };
|
Chris@0
|
592
|
Chris@0
|
593 /**
|
Chris@0
|
594 * Evaluates a javascript and returns the outcome to the client
|
Chris@0
|
595 * This will be JSON response so your script better be returning objects that can be used
|
Chris@0
|
596 * in JSON.stringify
|
Chris@0
|
597 * @param serverResponse
|
Chris@0
|
598 * @param script
|
Chris@0
|
599 * @return {*}
|
Chris@0
|
600 */
|
Chris@0
|
601 Browser.prototype.evaluate = function (serverResponse, script) {
|
Chris@0
|
602 return this.serverSendResponse(this.currentPage.evaluate("function() { return " + script + " }"), serverResponse);
|
Chris@0
|
603 };
|
Chris@0
|
604
|
Chris@0
|
605 /**
|
Chris@0
|
606 * Executes a javascript and goes back to the client with true if there were no errors
|
Chris@0
|
607 * @param serverResponse
|
Chris@0
|
608 * @param script
|
Chris@0
|
609 * @return {*}
|
Chris@0
|
610 */
|
Chris@0
|
611 Browser.prototype.execute = function (serverResponse, script) {
|
Chris@0
|
612 this.currentPage.execute("function() { " + script + " }");
|
Chris@0
|
613 return this.serverSendResponse(true, serverResponse);
|
Chris@0
|
614 };
|
Chris@0
|
615
|
Chris@0
|
616 /**
|
Chris@0
|
617 * If inside a frame then we will go back to the parent
|
Chris@0
|
618 * Not defined behaviour if you pop and are not inside an iframe
|
Chris@0
|
619 * @param serverResponse
|
Chris@0
|
620 * @return {*}
|
Chris@0
|
621 */
|
Chris@0
|
622 Browser.prototype.pop_frame = function (serverResponse) {
|
Chris@0
|
623 return this.serverSendResponse(this.currentPage.popFrame(), serverResponse);
|
Chris@0
|
624 };
|
Chris@0
|
625
|
Chris@0
|
626 /**
|
Chris@0
|
627 * Gets the window handle id by a given window name
|
Chris@0
|
628 * @param serverResponse
|
Chris@0
|
629 * @param name
|
Chris@0
|
630 * @return {*}
|
Chris@0
|
631 */
|
Chris@0
|
632 Browser.prototype.window_handle = function (serverResponse, name) {
|
Chris@0
|
633 var handle, pageByWindowName;
|
Chris@0
|
634
|
Chris@0
|
635 if (name === null || typeof name == "undefined" || name.length === 0) {
|
Chris@0
|
636 return this.serverSendResponse(this.currentPage.handle, serverResponse);
|
Chris@0
|
637 }
|
Chris@0
|
638
|
Chris@0
|
639 handle = null;
|
Chris@0
|
640
|
Chris@0
|
641 //Lets search the handle by the given window name
|
Chris@0
|
642 var filteredPages = this.pages.filter(function (p) {
|
Chris@0
|
643 return !p.closed && p.windowName() === name;
|
Chris@0
|
644 });
|
Chris@0
|
645
|
Chris@0
|
646 //A bit of error control is always good
|
Chris@0
|
647 if (Array.isArray(filteredPages) && filteredPages.length >= 1) {
|
Chris@0
|
648 pageByWindowName = filteredPages[0];
|
Chris@0
|
649 } else {
|
Chris@0
|
650 pageByWindowName = null;
|
Chris@0
|
651 }
|
Chris@0
|
652
|
Chris@0
|
653 if (pageByWindowName !== null && typeof pageByWindowName != "undefined") {
|
Chris@0
|
654 handle = pageByWindowName.handle;
|
Chris@0
|
655 }
|
Chris@0
|
656
|
Chris@0
|
657 return this.serverSendResponse(handle, serverResponse);
|
Chris@0
|
658 };
|
Chris@0
|
659
|
Chris@0
|
660 /**
|
Chris@0
|
661 * Returns all the window handles of opened windows
|
Chris@0
|
662 * @param serverResponse
|
Chris@0
|
663 * @return {*}
|
Chris@0
|
664 */
|
Chris@0
|
665 Browser.prototype.window_handles = function (serverResponse) {
|
Chris@0
|
666 var handles, filteredPages;
|
Chris@0
|
667
|
Chris@0
|
668 filteredPages = this.pages.filter(function (p) {
|
Chris@0
|
669 return !p.closed;
|
Chris@0
|
670 });
|
Chris@0
|
671
|
Chris@0
|
672 if (filteredPages.length > 0) {
|
Chris@0
|
673 handles = filteredPages.map(function (p) {
|
Chris@0
|
674 return p.handle;
|
Chris@0
|
675 });
|
Chris@0
|
676 if (handles.length === 0) {
|
Chris@0
|
677 handles = null;
|
Chris@0
|
678 }
|
Chris@0
|
679 } else {
|
Chris@0
|
680 handles = null;
|
Chris@0
|
681 }
|
Chris@0
|
682
|
Chris@0
|
683 return this.serverSendResponse(handles, serverResponse);
|
Chris@0
|
684 };
|
Chris@0
|
685
|
Chris@0
|
686 /**
|
Chris@0
|
687 * Tries to switch to a window given by the handle id
|
Chris@0
|
688 * @param serverResponse
|
Chris@0
|
689 * @param handle
|
Chris@0
|
690 * @return {*}
|
Chris@0
|
691 */
|
Chris@0
|
692 Browser.prototype.switch_to_window = function (serverResponse, handle) {
|
Chris@0
|
693 var page;
|
Chris@0
|
694 var self = this;
|
Chris@0
|
695
|
Chris@0
|
696 page = this.getPageByHandle(handle);
|
Chris@0
|
697 if (page === null || typeof page == "undefined") {
|
Chris@0
|
698 throw new Poltergeist.NoSuchWindowError;
|
Chris@0
|
699 }
|
Chris@0
|
700
|
Chris@0
|
701 if (page !== this.currentPage) {
|
Chris@0
|
702 return page.waitState('default', function () {
|
Chris@0
|
703 self.currentPage = page;
|
Chris@0
|
704 return self.serverSendResponse(true, serverResponse);
|
Chris@0
|
705 });
|
Chris@0
|
706 }
|
Chris@0
|
707
|
Chris@0
|
708 return this.serverSendResponse(true, serverResponse);
|
Chris@0
|
709 };
|
Chris@0
|
710
|
Chris@0
|
711 /**
|
Chris@0
|
712 * Opens a new window where we can do stuff
|
Chris@0
|
713 * @param serverResponse
|
Chris@0
|
714 * @return {*}
|
Chris@0
|
715 */
|
Chris@0
|
716 Browser.prototype.open_new_window = function (serverResponse) {
|
Chris@0
|
717 return this.execute(serverResponse, 'window.open()');
|
Chris@0
|
718 };
|
Chris@0
|
719
|
Chris@0
|
720 /**
|
Chris@0
|
721 * Closes the window given by handle name if possible
|
Chris@2
|
722 * NOTE: Closing a page in PhantomJS also closes new windows/frames opened from that page (QWebPage behaviour)
|
Chris@0
|
723 * @param serverResponse
|
Chris@0
|
724 * @param handle
|
Chris@0
|
725 * @return {*}
|
Chris@0
|
726 */
|
Chris@0
|
727 Browser.prototype.close_window = function (serverResponse, handle) {
|
Chris@0
|
728 var page;
|
Chris@0
|
729
|
Chris@0
|
730 page = this.getPageByHandle(handle);
|
Chris@0
|
731 if (page === null || typeof page == "undefined") {
|
Chris@0
|
732 //TODO: should we throw error since we actually could not find the window?
|
Chris@0
|
733 return this.serverSendResponse(false, serverResponse);
|
Chris@0
|
734 }
|
Chris@0
|
735
|
Chris@0
|
736 //TODO: we have to add some control here to actually asses that the release has been done
|
Chris@0
|
737 page.release();
|
Chris@0
|
738 return this.serverSendResponse(true, serverResponse);
|
Chris@0
|
739 };
|
Chris@0
|
740
|
Chris@0
|
741 /**
|
Chris@0
|
742 * Generic mouse event on an element
|
Chris@0
|
743 * @param serverResponse
|
Chris@0
|
744 * @param page_id
|
Chris@0
|
745 * @param id
|
Chris@0
|
746 * @param name
|
Chris@0
|
747 * @return {number}
|
Chris@0
|
748 */
|
Chris@0
|
749 Browser.prototype.mouse_event = function (serverResponse, page_id, id, name) {
|
Chris@0
|
750 var node;
|
Chris@0
|
751 var self = this;
|
Chris@0
|
752 node = this.node(page_id, id);
|
Chris@0
|
753 this.currentPage.state = 'mouse_event';
|
Chris@0
|
754 this.last_mouse_event = node.mouseEvent(name);
|
Chris@0
|
755 return setTimeout(function () {
|
Chris@0
|
756 if (self.currentPage.state === 'mouse_event') {
|
Chris@0
|
757 self.currentPage.state = 'default';
|
Chris@0
|
758 return self.serverSendResponse({
|
Chris@0
|
759 position: self.last_mouse_event
|
Chris@0
|
760 }, serverResponse);
|
Chris@0
|
761 } else {
|
Chris@0
|
762 return self.currentPage.waitState('default', function () {
|
Chris@0
|
763 return self.serverSendResponse({
|
Chris@0
|
764 position: self.last_mouse_event
|
Chris@0
|
765 }, serverResponse);
|
Chris@0
|
766 });
|
Chris@0
|
767 }
|
Chris@0
|
768 }, 5);
|
Chris@0
|
769 };
|
Chris@0
|
770
|
Chris@0
|
771 /**
|
Chris@0
|
772 * Simple click on the element
|
Chris@0
|
773 * @param serverResponse
|
Chris@0
|
774 * @param page_id
|
Chris@0
|
775 * @param id
|
Chris@0
|
776 * @return {*}
|
Chris@0
|
777 */
|
Chris@0
|
778 Browser.prototype.click = function (serverResponse, page_id, id) {
|
Chris@0
|
779 return this.mouse_event(serverResponse, page_id, id, 'click');
|
Chris@0
|
780 };
|
Chris@0
|
781
|
Chris@0
|
782 /**
|
Chris@0
|
783 * Right click on the element
|
Chris@0
|
784 * @param serverResponse
|
Chris@0
|
785 * @param page_id
|
Chris@0
|
786 * @param id
|
Chris@0
|
787 * @return {*}
|
Chris@0
|
788 */
|
Chris@0
|
789 Browser.prototype.right_click = function (serverResponse, page_id, id) {
|
Chris@0
|
790 return this.mouse_event(serverResponse, page_id, id, 'rightclick');
|
Chris@0
|
791 };
|
Chris@0
|
792
|
Chris@0
|
793 /**
|
Chris@0
|
794 * Double click on the element given by page and id
|
Chris@0
|
795 * @param serverResponse
|
Chris@0
|
796 * @param page_id
|
Chris@0
|
797 * @param id
|
Chris@0
|
798 * @return {*}
|
Chris@0
|
799 */
|
Chris@0
|
800 Browser.prototype.double_click = function (serverResponse, page_id, id) {
|
Chris@0
|
801 return this.mouse_event(serverResponse, page_id, id, 'doubleclick');
|
Chris@0
|
802 };
|
Chris@0
|
803
|
Chris@0
|
804 /**
|
Chris@0
|
805 * Executes a mousemove event on the page and given element
|
Chris@0
|
806 * @param serverResponse
|
Chris@0
|
807 * @param page_id
|
Chris@0
|
808 * @param id
|
Chris@0
|
809 * @return {*}
|
Chris@0
|
810 */
|
Chris@0
|
811 Browser.prototype.hover = function (serverResponse, page_id, id) {
|
Chris@0
|
812 return this.mouse_event(serverResponse, page_id, id, 'mousemove');
|
Chris@0
|
813 };
|
Chris@0
|
814
|
Chris@0
|
815 /**
|
Chris@0
|
816 * Triggers a mouse click event on the given coordinates
|
Chris@0
|
817 * @param serverResponse
|
Chris@0
|
818 * @param x
|
Chris@0
|
819 * @param y
|
Chris@0
|
820 * @return {*}
|
Chris@0
|
821 */
|
Chris@0
|
822 Browser.prototype.click_coordinates = function (serverResponse, x, y) {
|
Chris@0
|
823 var response;
|
Chris@0
|
824
|
Chris@0
|
825 this.currentPage.sendEvent('click', x, y);
|
Chris@0
|
826 response = {
|
Chris@0
|
827 click: {
|
Chris@0
|
828 x: x,
|
Chris@0
|
829 y: y
|
Chris@0
|
830 }
|
Chris@0
|
831 };
|
Chris@0
|
832
|
Chris@0
|
833 return this.serverSendResponse(response, serverResponse);
|
Chris@0
|
834 };
|
Chris@0
|
835
|
Chris@0
|
836 /**
|
Chris@0
|
837 * Drags one element into another, useful for nice javascript thingies
|
Chris@0
|
838 * @param serverResponse
|
Chris@0
|
839 * @param page_id
|
Chris@0
|
840 * @param id
|
Chris@0
|
841 * @param other_id
|
Chris@0
|
842 * @return {*}
|
Chris@0
|
843 */
|
Chris@0
|
844 Browser.prototype.drag = function (serverResponse, page_id, id, other_id) {
|
Chris@0
|
845 this.node(page_id, id).dragTo(this.node(page_id, other_id));
|
Chris@0
|
846 return this.serverSendResponse(true, serverResponse);
|
Chris@0
|
847 };
|
Chris@0
|
848
|
Chris@0
|
849 /**
|
Chris@0
|
850 * Triggers an event on the given page and element
|
Chris@0
|
851 * @param serverResponse
|
Chris@0
|
852 * @param page_id
|
Chris@0
|
853 * @param id
|
Chris@0
|
854 * @param event
|
Chris@0
|
855 * @return {*}
|
Chris@0
|
856 */
|
Chris@0
|
857 Browser.prototype.trigger = function (serverResponse, page_id, id, event) {
|
Chris@0
|
858 this.node(page_id, id).trigger(event);
|
Chris@0
|
859 return this.serverSendResponse(event, serverResponse);
|
Chris@0
|
860 };
|
Chris@0
|
861
|
Chris@0
|
862 /**
|
Chris@0
|
863 * Checks if two elements are equal on a dom level
|
Chris@0
|
864 * @param serverResponse
|
Chris@0
|
865 * @param page_id
|
Chris@0
|
866 * @param id
|
Chris@0
|
867 * @param other_id
|
Chris@0
|
868 * @return {*}
|
Chris@0
|
869 */
|
Chris@0
|
870 Browser.prototype.equals = function (serverResponse, page_id, id, other_id) {
|
Chris@0
|
871 return this.serverSendResponse(this.node(page_id, id).isEqual(this.node(page_id, other_id)), serverResponse);
|
Chris@0
|
872 };
|
Chris@0
|
873
|
Chris@0
|
874 /**
|
Chris@0
|
875 * Resets the current page to a clean slate
|
Chris@0
|
876 * @param serverResponse
|
Chris@0
|
877 * @return {*}
|
Chris@0
|
878 */
|
Chris@0
|
879 Browser.prototype.reset = function (serverResponse) {
|
Chris@0
|
880 this.resetPage();
|
Chris@0
|
881 return this.serverSendResponse(true, serverResponse);
|
Chris@0
|
882 };
|
Chris@0
|
883
|
Chris@0
|
884 /**
|
Chris@0
|
885 * Scrolls to a position given by the left, top coordinates
|
Chris@0
|
886 * @param serverResponse
|
Chris@0
|
887 * @param left
|
Chris@0
|
888 * @param top
|
Chris@0
|
889 * @return {*}
|
Chris@0
|
890 */
|
Chris@0
|
891 Browser.prototype.scroll_to = function (serverResponse, left, top) {
|
Chris@0
|
892 this.currentPage.setScrollPosition({
|
Chris@0
|
893 left: left,
|
Chris@0
|
894 top: top
|
Chris@0
|
895 });
|
Chris@0
|
896 return this.serverSendResponse(true, serverResponse);
|
Chris@0
|
897 };
|
Chris@0
|
898
|
Chris@0
|
899 /**
|
Chris@0
|
900 * Sends keys to an element simulating as closest as possible what a user would do
|
Chris@0
|
901 * when typing
|
Chris@0
|
902 * @param serverResponse
|
Chris@0
|
903 * @param page_id
|
Chris@0
|
904 * @param id
|
Chris@0
|
905 * @param keys
|
Chris@0
|
906 * @return {*}
|
Chris@0
|
907 */
|
Chris@0
|
908 Browser.prototype.send_keys = function (serverResponse, page_id, id, keys) {
|
Chris@0
|
909 var key, sequence, target, _i, _len;
|
Chris@0
|
910 target = this.node(page_id, id);
|
Chris@0
|
911 if (!target.containsSelection()) {
|
Chris@0
|
912 target.mouseEvent('click');
|
Chris@0
|
913 }
|
Chris@0
|
914 for (_i = 0, _len = keys.length; _i < _len; _i++) {
|
Chris@0
|
915 sequence = keys[_i];
|
Chris@0
|
916 key = sequence.key != null ? this.currentPage.keyCode(sequence.key) : sequence;
|
Chris@0
|
917 this.currentPage.sendEvent('keypress', key);
|
Chris@0
|
918 }
|
Chris@0
|
919 return this.serverSendResponse(true, serverResponse);
|
Chris@0
|
920 };
|
Chris@0
|
921
|
Chris@0
|
922 /**
|
Chris@0
|
923 * Sends a native phantomjs key event to element
|
Chris@0
|
924 * @param serverResponse
|
Chris@0
|
925 * @param page_id
|
Chris@0
|
926 * @param id
|
Chris@0
|
927 * @param keyEvent
|
Chris@0
|
928 * @param key
|
Chris@0
|
929 * @param modifier
|
Chris@0
|
930 */
|
Chris@0
|
931 Browser.prototype.key_event = function (serverResponse, page_id, id, keyEvent, key, modifier) {
|
Chris@0
|
932 var keyEventModifierMap;
|
Chris@0
|
933 var keyEventModifier;
|
Chris@0
|
934 var target;
|
Chris@0
|
935
|
Chris@0
|
936 keyEventModifierMap = {
|
Chris@0
|
937 'none': 0x0,
|
Chris@0
|
938 'shift': 0x02000000,
|
Chris@0
|
939 'ctrl': 0x04000000,
|
Chris@0
|
940 'alt': 0x08000000,
|
Chris@0
|
941 'meta': 0x10000000
|
Chris@0
|
942 };
|
Chris@0
|
943 keyEventModifier = keyEventModifierMap[modifier];
|
Chris@0
|
944
|
Chris@0
|
945 target = this.node(page_id, id);
|
Chris@0
|
946 if (!target.containsSelection()) {
|
Chris@0
|
947 target.mouseEvent('click');
|
Chris@0
|
948 }
|
Chris@0
|
949 target.page.sendEvent(keyEvent, key, null, null, keyEventModifier);
|
Chris@0
|
950
|
Chris@0
|
951 return this.serverSendResponse(true, serverResponse);
|
Chris@0
|
952 };
|
Chris@0
|
953
|
Chris@0
|
954 /**
|
Chris@0
|
955 * Sends the rendered page in a base64 encoding
|
Chris@0
|
956 * @param serverResponse
|
Chris@0
|
957 * @param format
|
Chris@0
|
958 * @param full
|
Chris@0
|
959 * @param selector
|
Chris@0
|
960 * @return {*}
|
Chris@0
|
961 */
|
Chris@0
|
962 Browser.prototype.render_base64 = function (serverResponse, format, full, selector) {
|
Chris@0
|
963 var encoded_image;
|
Chris@0
|
964 if (selector == null) {
|
Chris@0
|
965 selector = null;
|
Chris@0
|
966 }
|
Chris@0
|
967 this.set_clip_rect(full, selector);
|
Chris@0
|
968 encoded_image = this.currentPage.renderBase64(format);
|
Chris@0
|
969 return this.serverSendResponse(encoded_image, serverResponse);
|
Chris@0
|
970 };
|
Chris@0
|
971
|
Chris@0
|
972 /**
|
Chris@0
|
973 * Renders the current page entirely or a given selection
|
Chris@0
|
974 * @param serverResponse
|
Chris@0
|
975 * @param path
|
Chris@0
|
976 * @param full
|
Chris@0
|
977 * @param selector
|
Chris@0
|
978 * @return {*}
|
Chris@0
|
979 */
|
Chris@0
|
980 Browser.prototype.render = function (serverResponse, path, full, selector) {
|
Chris@0
|
981 var dimensions;
|
Chris@0
|
982 if (selector == null) {
|
Chris@0
|
983 selector = null;
|
Chris@0
|
984 }
|
Chris@0
|
985 dimensions = this.set_clip_rect(full, selector);
|
Chris@0
|
986 this.currentPage.setScrollPosition({
|
Chris@0
|
987 left: 0,
|
Chris@0
|
988 top: 0
|
Chris@0
|
989 });
|
Chris@0
|
990 this.currentPage.render(path);
|
Chris@0
|
991 this.currentPage.setScrollPosition({
|
Chris@0
|
992 left: dimensions.left,
|
Chris@0
|
993 top: dimensions.top
|
Chris@0
|
994 });
|
Chris@0
|
995 return this.serverSendResponse(true, serverResponse);
|
Chris@0
|
996 };
|
Chris@0
|
997
|
Chris@0
|
998
|
Chris@0
|
999 /**
|
Chris@0
|
1000 * Sets the paper size, useful when printing to PDF
|
Chris@0
|
1001 * @param serverResponse
|
Chris@0
|
1002 * @param size
|
Chris@0
|
1003 * @return {*}
|
Chris@0
|
1004 */
|
Chris@0
|
1005 Browser.prototype.set_paper_size = function (serverResponse, size) {
|
Chris@0
|
1006 this.currentPage.setPaperSize(size);
|
Chris@0
|
1007 return this.serverSendResponse(true, serverResponse);
|
Chris@0
|
1008 };
|
Chris@0
|
1009
|
Chris@0
|
1010 /**
|
Chris@0
|
1011 * Sets the zoom factor on the current page
|
Chris@0
|
1012 * @param serverResponse
|
Chris@0
|
1013 * @param zoom_factor
|
Chris@0
|
1014 * @return {*}
|
Chris@0
|
1015 */
|
Chris@0
|
1016 Browser.prototype.set_zoom_factor = function (serverResponse, zoom_factor) {
|
Chris@0
|
1017 this.currentPage.setZoomFactor(zoom_factor);
|
Chris@0
|
1018 return this.serverSendResponse(true, serverResponse);
|
Chris@0
|
1019 };
|
Chris@0
|
1020
|
Chris@0
|
1021 /**
|
Chris@0
|
1022 * Resizes the browser viewport, useful when testing mobile stuff
|
Chris@0
|
1023 * @param serverResponse
|
Chris@0
|
1024 * @param width
|
Chris@0
|
1025 * @param height
|
Chris@0
|
1026 * @return {*}
|
Chris@0
|
1027 */
|
Chris@0
|
1028 Browser.prototype.resize = function (serverResponse, width, height) {
|
Chris@0
|
1029 this.currentPage.setViewportSize({
|
Chris@0
|
1030 width: width,
|
Chris@0
|
1031 height: height
|
Chris@0
|
1032 });
|
Chris@0
|
1033 return this.serverSendResponse(true, serverResponse);
|
Chris@0
|
1034 };
|
Chris@0
|
1035
|
Chris@0
|
1036 /**
|
Chris@0
|
1037 * Gets the browser viewport size
|
Chris@0
|
1038 * Because PhantomJS is headless (nothing is shown)
|
Chris@0
|
1039 * viewportSize effectively simulates the size of the window like in a traditional browser.
|
Chris@0
|
1040 * @param serverResponse
|
Chris@0
|
1041 * @param handle
|
Chris@0
|
1042 * @return {*}
|
Chris@0
|
1043 */
|
Chris@0
|
1044 Browser.prototype.window_size = function (serverResponse, handle) {
|
Chris@0
|
1045 //TODO: add support for window handles
|
Chris@0
|
1046 return this.serverSendResponse(this.currentPage.viewportSize(), serverResponse);
|
Chris@0
|
1047 };
|
Chris@0
|
1048
|
Chris@0
|
1049 /**
|
Chris@0
|
1050 * Returns the network traffic that the current page has generated
|
Chris@0
|
1051 * @param serverResponse
|
Chris@0
|
1052 * @return {*}
|
Chris@0
|
1053 */
|
Chris@0
|
1054 Browser.prototype.network_traffic = function (serverResponse) {
|
Chris@0
|
1055 return this.serverSendResponse(this.currentPage.networkTraffic(), serverResponse);
|
Chris@0
|
1056 };
|
Chris@0
|
1057
|
Chris@0
|
1058 /**
|
Chris@0
|
1059 * Clears the accumulated network_traffic in the current page
|
Chris@0
|
1060 * @param serverResponse
|
Chris@0
|
1061 * @return {*}
|
Chris@0
|
1062 */
|
Chris@0
|
1063 Browser.prototype.clear_network_traffic = function (serverResponse) {
|
Chris@0
|
1064 this.currentPage.clearNetworkTraffic();
|
Chris@0
|
1065 return this.serverSendResponse(true, serverResponse);
|
Chris@0
|
1066 };
|
Chris@0
|
1067
|
Chris@0
|
1068 /**
|
Chris@0
|
1069 * Gets the headers of the current page
|
Chris@0
|
1070 * @param serverResponse
|
Chris@0
|
1071 * @return {*}
|
Chris@0
|
1072 */
|
Chris@0
|
1073 Browser.prototype.get_headers = function (serverResponse) {
|
Chris@0
|
1074 return this.serverSendResponse(this.currentPage.getCustomHeaders(), serverResponse);
|
Chris@0
|
1075 };
|
Chris@0
|
1076
|
Chris@0
|
1077 /**
|
Chris@0
|
1078 * Set headers in the browser
|
Chris@0
|
1079 * @param serverResponse
|
Chris@0
|
1080 * @param headers
|
Chris@0
|
1081 * @return {*}
|
Chris@0
|
1082 */
|
Chris@0
|
1083 Browser.prototype.set_headers = function (serverResponse, headers) {
|
Chris@0
|
1084 if (headers['User-Agent']) {
|
Chris@0
|
1085 this.currentPage.setUserAgent(headers['User-Agent']);
|
Chris@0
|
1086 }
|
Chris@0
|
1087 this.currentPage.setCustomHeaders(headers);
|
Chris@0
|
1088 return this.serverSendResponse(true, serverResponse);
|
Chris@0
|
1089 };
|
Chris@0
|
1090
|
Chris@0
|
1091 /**
|
Chris@0
|
1092 * Given an array of headers, adds them to the page
|
Chris@0
|
1093 * @param serverResponse
|
Chris@0
|
1094 * @param headers
|
Chris@0
|
1095 * @return {*}
|
Chris@0
|
1096 */
|
Chris@0
|
1097 Browser.prototype.add_headers = function (serverResponse, headers) {
|
Chris@0
|
1098 var allHeaders, name, value;
|
Chris@0
|
1099 allHeaders = this.currentPage.getCustomHeaders();
|
Chris@0
|
1100 for (name in headers) {
|
Chris@0
|
1101 if (headers.hasOwnProperty(name)) {
|
Chris@0
|
1102 value = headers[name];
|
Chris@0
|
1103 allHeaders[name] = value;
|
Chris@0
|
1104 }
|
Chris@0
|
1105 }
|
Chris@0
|
1106 return this.set_headers(serverResponse, allHeaders);
|
Chris@0
|
1107 };
|
Chris@0
|
1108
|
Chris@0
|
1109 /**
|
Chris@0
|
1110 * Adds a header to the page temporary or permanently
|
Chris@0
|
1111 * @param serverResponse
|
Chris@0
|
1112 * @param header
|
Chris@0
|
1113 * @param permanent
|
Chris@0
|
1114 * @return {*}
|
Chris@0
|
1115 */
|
Chris@0
|
1116 Browser.prototype.add_header = function (serverResponse, header, permanent) {
|
Chris@0
|
1117 if (!permanent) {
|
Chris@0
|
1118 this.currentPage.addTempHeader(header);
|
Chris@0
|
1119 }
|
Chris@0
|
1120 return this.add_headers(serverResponse, header);
|
Chris@0
|
1121 };
|
Chris@0
|
1122
|
Chris@0
|
1123
|
Chris@0
|
1124 /**
|
Chris@0
|
1125 * Sends back the client the response headers sent from the browser when making
|
Chris@0
|
1126 * the page request
|
Chris@0
|
1127 * @param serverResponse
|
Chris@0
|
1128 * @return {*}
|
Chris@0
|
1129 */
|
Chris@0
|
1130 Browser.prototype.response_headers = function (serverResponse) {
|
Chris@0
|
1131 return this.serverSendResponse(this.currentPage.responseHeaders(), serverResponse);
|
Chris@0
|
1132 };
|
Chris@0
|
1133
|
Chris@0
|
1134 /**
|
Chris@0
|
1135 * Returns the cookies of the current page being browsed
|
Chris@0
|
1136 * @param serverResponse
|
Chris@0
|
1137 * @return {*}
|
Chris@0
|
1138 */
|
Chris@0
|
1139 Browser.prototype.cookies = function (serverResponse) {
|
Chris@0
|
1140 return this.serverSendResponse(this.currentPage.cookies(), serverResponse);
|
Chris@0
|
1141 };
|
Chris@0
|
1142
|
Chris@0
|
1143 /**
|
Chris@0
|
1144 * Sets a cookie in the browser, the format of the cookies has to be the format it says
|
Chris@0
|
1145 * on phantomjs documentation and as such you can set it in other domains, not on the
|
Chris@0
|
1146 * current page
|
Chris@0
|
1147 * @param serverResponse
|
Chris@0
|
1148 * @param cookie
|
Chris@0
|
1149 * @return {*}
|
Chris@0
|
1150 */
|
Chris@0
|
1151 Browser.prototype.set_cookie = function (serverResponse, cookie) {
|
Chris@0
|
1152 return this.serverSendResponse(phantom.addCookie(cookie), serverResponse);
|
Chris@0
|
1153 };
|
Chris@0
|
1154
|
Chris@0
|
1155 /**
|
Chris@0
|
1156 * Remove a cookie set on the current page
|
Chris@0
|
1157 * @param serverResponse
|
Chris@0
|
1158 * @param name
|
Chris@0
|
1159 * @return {*}
|
Chris@0
|
1160 */
|
Chris@0
|
1161 Browser.prototype.remove_cookie = function (serverResponse, name) {
|
Chris@0
|
1162 //TODO: add error control to check if the cookie was properly deleted
|
Chris@0
|
1163 this.currentPage.deleteCookie(name);
|
Chris@0
|
1164 phantom.deleteCookie(name);
|
Chris@0
|
1165 return this.serverSendResponse(true, serverResponse);
|
Chris@0
|
1166 };
|
Chris@0
|
1167
|
Chris@0
|
1168 /**
|
Chris@0
|
1169 * Clear the cookies in the browser
|
Chris@0
|
1170 * @param serverResponse
|
Chris@0
|
1171 * @return {*}
|
Chris@0
|
1172 */
|
Chris@0
|
1173 Browser.prototype.clear_cookies = function (serverResponse) {
|
Chris@0
|
1174 phantom.clearCookies();
|
Chris@0
|
1175 return this.serverSendResponse(true, serverResponse);
|
Chris@0
|
1176 };
|
Chris@0
|
1177
|
Chris@0
|
1178 /**
|
Chris@0
|
1179 * Enables / Disables the cookies on the browser
|
Chris@0
|
1180 * @param serverResponse
|
Chris@0
|
1181 * @param flag
|
Chris@0
|
1182 * @return {*}
|
Chris@0
|
1183 */
|
Chris@0
|
1184 Browser.prototype.cookies_enabled = function (serverResponse, flag) {
|
Chris@0
|
1185 phantom.cookiesEnabled = flag;
|
Chris@0
|
1186 return this.serverSendResponse(true, serverResponse);
|
Chris@0
|
1187 };
|
Chris@0
|
1188
|
Chris@0
|
1189 /**
|
Chris@2
|
1190 * Sets proxy or unsets web proxy
|
Chris@2
|
1191 * @param {Object} serverResponse Phantomjs response object associated to the client request
|
Chris@2
|
1192 * @param {String} ip IP or host name, or null/'' to unset
|
Chris@2
|
1193 * @param {Number} port port number
|
Chris@2
|
1194 * @param {String} proxyType socks5 or anything else for http(s)
|
Chris@2
|
1195 * @param {String} user optional username for proxy authentication
|
Chris@2
|
1196 * @param {String} password optional password for proxy authentication
|
Chris@2
|
1197 * @return {*}
|
Chris@2
|
1198 * @see {@link https://github.com/ariya/phantomjs/pull/11829/commits/84c31822a2e5eba21fe42298ec27ec4ccab95667}
|
Chris@2
|
1199 */
|
Chris@2
|
1200 Browser.prototype.set_proxy = function (serverResponse, ip, port, proxyType, user, password) {
|
Chris@2
|
1201 phantom.setProxy(ip, port, proxyType, user, password);
|
Chris@2
|
1202 return this.serverSendResponse(true, serverResponse);
|
Chris@2
|
1203 };
|
Chris@2
|
1204
|
Chris@2
|
1205 /**
|
Chris@0
|
1206 * US19: DONE
|
Chris@0
|
1207 * Sets a basic authentication credential to access a page
|
Chris@0
|
1208 * THIS SHOULD BE USED BEFORE accessing a page
|
Chris@0
|
1209 * @param serverResponse
|
Chris@0
|
1210 * @param user
|
Chris@0
|
1211 * @param password
|
Chris@0
|
1212 * @return {*}
|
Chris@0
|
1213 */
|
Chris@0
|
1214 Browser.prototype.set_http_auth = function (serverResponse, user, password) {
|
Chris@0
|
1215 this.currentPage.setHttpAuth(user, password);
|
Chris@0
|
1216 return this.serverSendResponse(true, serverResponse);
|
Chris@0
|
1217 };
|
Chris@0
|
1218
|
Chris@0
|
1219 /**
|
Chris@0
|
1220 * Sets the flag whether to fail on javascript errors or not.
|
Chris@0
|
1221 * @param serverResponse
|
Chris@0
|
1222 * @param value
|
Chris@0
|
1223 * @return {*}
|
Chris@0
|
1224 */
|
Chris@0
|
1225 Browser.prototype.set_js_errors = function (serverResponse, value) {
|
Chris@0
|
1226 this.js_errors = value;
|
Chris@0
|
1227 return this.serverSendResponse(true, serverResponse);
|
Chris@0
|
1228 };
|
Chris@0
|
1229
|
Chris@0
|
1230 /**
|
Chris@0
|
1231 * Sets the debug mode to boolean value
|
Chris@0
|
1232 * @param serverResponse
|
Chris@0
|
1233 * @param value
|
Chris@0
|
1234 * @return {*}
|
Chris@0
|
1235 */
|
Chris@0
|
1236 Browser.prototype.set_debug = function (serverResponse, value) {
|
Chris@0
|
1237 this._debug = value;
|
Chris@0
|
1238 return this.serverSendResponse(true, serverResponse);
|
Chris@0
|
1239 };
|
Chris@0
|
1240
|
Chris@0
|
1241 /**
|
Chris@0
|
1242 * Goes back in the history when possible
|
Chris@0
|
1243 * @param serverResponse
|
Chris@0
|
1244 * @return {*}
|
Chris@0
|
1245 */
|
Chris@0
|
1246 Browser.prototype.go_back = function (serverResponse) {
|
Chris@0
|
1247 var self = this;
|
Chris@0
|
1248 if (this.currentPage.canGoBack()) {
|
Chris@0
|
1249 this.currentPage.state = 'loading';
|
Chris@0
|
1250 this.currentPage.goBack();
|
Chris@0
|
1251 return this.currentPage.waitState('default', function () {
|
Chris@0
|
1252 return self.serverSendResponse(true, serverResponse);
|
Chris@0
|
1253 });
|
Chris@0
|
1254 } else {
|
Chris@0
|
1255 return this.serverSendResponse(false, serverResponse);
|
Chris@0
|
1256 }
|
Chris@0
|
1257 };
|
Chris@0
|
1258
|
Chris@0
|
1259 /**
|
Chris@0
|
1260 * Reloads the page if possible
|
Chris@0
|
1261 * @return {*}
|
Chris@0
|
1262 */
|
Chris@0
|
1263 Browser.prototype.reload = function (serverResponse) {
|
Chris@0
|
1264 var self = this;
|
Chris@0
|
1265 this.currentPage.state = 'loading';
|
Chris@0
|
1266 this.currentPage.reload();
|
Chris@0
|
1267 return this.currentPage.waitState('default', function () {
|
Chris@0
|
1268 return self.serverSendResponse(true, serverResponse);
|
Chris@0
|
1269 });
|
Chris@0
|
1270 };
|
Chris@0
|
1271
|
Chris@0
|
1272 /**
|
Chris@0
|
1273 * Goes forward in the browser history if possible
|
Chris@0
|
1274 * @param serverResponse
|
Chris@0
|
1275 * @return {*}
|
Chris@0
|
1276 */
|
Chris@0
|
1277 Browser.prototype.go_forward = function (serverResponse) {
|
Chris@0
|
1278 var self = this;
|
Chris@0
|
1279 if (this.currentPage.canGoForward()) {
|
Chris@0
|
1280 this.currentPage.state = 'loading';
|
Chris@0
|
1281 this.currentPage.goForward();
|
Chris@0
|
1282 return this.currentPage.waitState('default', function () {
|
Chris@0
|
1283 return self.serverSendResponse(true, serverResponse);
|
Chris@0
|
1284 });
|
Chris@0
|
1285 } else {
|
Chris@0
|
1286 return this.serverSendResponse(false, serverResponse);
|
Chris@0
|
1287 }
|
Chris@0
|
1288 };
|
Chris@0
|
1289
|
Chris@0
|
1290 /**
|
Chris@2
|
1291 * Sets the timeout in milliseconds, after which any resource requested will stop
|
Chris@2
|
1292 * trying and proceed with other parts of the page
|
Chris@2
|
1293 * @param serverResponse
|
Chris@2
|
1294 * @param value
|
Chris@2
|
1295 * @return {*}
|
Chris@2
|
1296 */
|
Chris@2
|
1297 Browser.prototype.set_resource_timeout = function (serverResponse, value) {
|
Chris@2
|
1298 this._resourceTimeout = value;
|
Chris@2
|
1299 return this.serverSendResponse(true, serverResponse);
|
Chris@2
|
1300 };
|
Chris@2
|
1301
|
Chris@2
|
1302 /**
|
Chris@0
|
1303 * Sets the urlBlacklist for the given urls as parameters
|
Chris@0
|
1304 * @return {boolean}
|
Chris@0
|
1305 */
|
Chris@0
|
1306 Browser.prototype.set_url_blacklist = function (serverResponse, blackList) {
|
Chris@0
|
1307 this.currentPage.urlBlacklist = Array.prototype.slice.call(blackList);
|
Chris@0
|
1308 return this.serverSendResponse(true, serverResponse);
|
Chris@0
|
1309 };
|
Chris@0
|
1310
|
Chris@0
|
1311 /**
|
Chris@0
|
1312 * Runs a browser command and returns the response back to the client
|
Chris@0
|
1313 * when the command has finished the execution
|
Chris@0
|
1314 * @param command
|
Chris@0
|
1315 * @param serverResponse
|
Chris@0
|
1316 * @return {*}
|
Chris@0
|
1317 */
|
Chris@0
|
1318 Browser.prototype.serverRunCommand = function (command, serverResponse) {
|
Chris@0
|
1319 var commandData;
|
Chris@0
|
1320 var commandArgs;
|
Chris@0
|
1321 var commandName;
|
Chris@0
|
1322
|
Chris@0
|
1323 commandName = command.name;
|
Chris@0
|
1324 commandArgs = command.args;
|
Chris@0
|
1325 this.currentPage.state = 'default';
|
Chris@0
|
1326 commandData = [serverResponse].concat(commandArgs);
|
Chris@0
|
1327
|
Chris@0
|
1328 if (typeof this[commandName] !== "function") {
|
Chris@0
|
1329 //We can not run such command
|
Chris@0
|
1330 throw new Poltergeist.Error();
|
Chris@0
|
1331 }
|
Chris@0
|
1332
|
Chris@0
|
1333 return this[commandName].apply(this, commandData);
|
Chris@0
|
1334 };
|
Chris@0
|
1335
|
Chris@0
|
1336 /**
|
Chris@0
|
1337 * Sends a response back to the client who made the request
|
Chris@0
|
1338 * @param response
|
Chris@0
|
1339 * @param serverResponse
|
Chris@0
|
1340 * @return {*}
|
Chris@0
|
1341 */
|
Chris@0
|
1342 Browser.prototype.serverSendResponse = function (response, serverResponse) {
|
Chris@0
|
1343 var errors;
|
Chris@0
|
1344 errors = this.currentPage.errors;
|
Chris@0
|
1345 this.currentPage.clearErrors();
|
Chris@0
|
1346 if (errors.length > 0 && this.js_errors) {
|
Chris@0
|
1347 return this.owner.serverSendError(new Poltergeist.JavascriptError(errors), serverResponse);
|
Chris@0
|
1348 } else {
|
Chris@0
|
1349 return this.owner.serverSendResponse(response, serverResponse);
|
Chris@0
|
1350 }
|
Chris@0
|
1351 };
|
Chris@0
|
1352
|
Chris@0
|
1353 return Browser;
|
Chris@0
|
1354
|
Chris@0
|
1355 })();
|