comparison vendor/jcalderonzumba/gastonjs/src/Client/browser.js @ 0:c75dbcec494b

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