Skip to content

Loading…

Implement within_window #314

Merged
merged 15 commits into from

5 participants

@mhoran

Resolves issue #129. Uses the same mechanism as the Capybara Selenium driver to determine which window to switch to: http://git.io/XrUlqw#L89. Note that I've defined window_handle and window_handles on the Driver instead of the Browser, which is incompatible with the (unofficial?) Selenium API.

@mhoran

if you have any pointers to any refactoring that may help get this pulled in, that'd be great.

Though I no longer need support for this for any current project, I do know that the community is in general interested in support.

@jferris
thoughtbot, inc. member

Hey Matt,

Sorry to take so long to review this. It's a pretty big change, and I wanted to make sure I looked through it carefully. I just have one question: how will extra windows be closed at the end of each scenario? I assume we'll want to clean them up in reset somehow.

@mhoran

Good point, @jferris. I went ahead and rebased from master to get started on this, but my work didn't apply cleanly. I've gotten things to the point where they compile, but the test suite hangs towards the end. It looks like this is going to take some time to straighten out, and I don't have much of that right now. I'll try to take care of it when I can, though.

@mhoran

I traced down the deadlock to #308. In some cases, the TCPServer used in the suite may receive two simultaneous connections, which blocks the thread. I've fixed this in my branch and am moving on to the reset! functionality.

@mhoran

I've made the necessary changes to clear new windows on reset. Please let me know if you have any additional questions or concerns.

@masone

Thanks for your effort @mhoran
I have just tested mhoran:master with my application I am currently testing with the Selenium driver. I stumbled upon two problems.

With the Selenium driver, I used to be able to query the window by its title.

within_window('Window title') do
end

I get a "Unable to locate window" error when querying by title so I ended up doing something similar like you do it in the tests.

within_window(page.driver.browser.get_window_handles.last) do
end

The second thing may be very specific to my application. I want to test my Facebook dialogs (FB.ui in the Javascript SDK). I log in with a user, open a dialog, click a button in the dialog. Problem is, that the dialog shows a quite generic error instead of the actual content. The popups is triggered via Javascript from my site but the HTML is loaded directly from Facebook. The visiting user has an active session at Facebook and is authenticated with OAuth via the Javascript SDK.
It works well when using the Selenium driver. Since I have no idea how capybara-webkit works, my best guess would be that it has to do with sessions / cookies. Does that ring any bells?

I'd be very happy to be able to test my dialogs with webkit.
Let me know if I can be of any help!

@jferris
thoughtbot, inc. member

@mhoran I got a number of "too many open files" failures when trying to merge this. I'll try to look at those and get this merged this week.

@jferris
thoughtbot, inc. member

@masone my plan is to merge this as-is, once I've figured out the errors. It seems like finding windows by title isn't part of the core capybara API, since this passes the window specs. I'd be interested in supporting it, though, if you'd like to open another pull request.

@mhoran

@masone, my guess is this is a timing issue. If the new window hasn't loaded by the time you select by title, it will fail. This mechanism should probably be made more robust, but I don't think it would be straightforward to do so. I'll look into it, though.

@jferris, I bet the deleteLater is never happening when the driver is reset. This would leave file descriptors and signals connected, which could lead to too many open files.

@mhoran

@masone, I've set up a test project using Facebook auth and within_window via title selector here: http://git.io/38bFwA.

There are a few caveats. First, the reason you may be getting the generic error is that your hostname within capybara-webkit may not match that configured in your Facebook application settings. See the monkey patch in features/support/server.rb.

Secondly, the DOM may have not completely loaded at the time the within_window command is received, so although capybara-webkit may think the page has loaded (and therefore accepts the command), title querying doesn't find the page. I've added a sleep to the corresponding step definition to work around this. Of course, that's not great, so I recommend the window_handle route.

@mhoran

@jferris, I just pushed up a possible fix for the too many open files failures. it seems that deleteLater never does anything because capybara-webkit is single threaded, and control never returns to the main loop. Using delete is safe in this situation because there's no chance that another thread will try to access the object.

I had to remove the disconnect from PageLoadingCommand as this was causing a segmentation fault after the delete. Deleting an object automatically disconnects all signals, so this should be fine.

Note that deleteLater is currently used throughout the project, and my guess is it's not working as expected elsewhere.

@mhoran

I cleaned up the commits a bit and also refactored the previous "too many open files" fix so that the disconnect can remain in place. The PageLoadingCommand doesn't need the actual page that's loading, just a signal that the current page has loaded, so I've wired it up to the WebPageManager instead.

@mhoran

@masone, I was actually able to track down the issue with find window by title (and URL). As expected, it's a race condition between the loading of a new window and the issuance of the within_window command. The specs for this functionality pass because the content is available before the within_window command is issued. However, in the real world, this won't always be the case, and so the feature is brittle.

PageLoadingCommand needs to be extended to be aware of whether it has created a new window which is loading. I began looking into this, but seeing as how this is a massive pull request as is, I'd like to hold off on that until later. For now, you can use either the window handle method, the window name method, or simply sleep until the new window has loaded.

@mhoran

Turns out deleteLater actually does work, but my debugging wasn't showing the deallocation. I'm using deleteLater now as this is a bit safer.

The "too many open files" fix turned out to be ensuring that the NetworkAccessManager is created with the WebPage as its parent, so when it is deleted in reset the NetworkAccessManager gets deallocated. I tested this with lsof and both memory and open files were equivalent to that of the commit before the introduction of within_window support.

@piotrze

I've switched to webkit and Your branch mhoran:master fixed my tests with window_handles method. Good work.

@mhoran

Rebased to current master.

@jferris jferris merged commit 1264113 into thoughtbot:master
@jferris
thoughtbot, inc. member

Thanks for all your work, Matt. I merged this into master.

@jacklenehan

I'm working on a project using within_window and it seems like cookies aren't being preserved between windows - a user that's signed in on window A isn't signed in on (new) window B. Do you guys have any ideas? Thanks y'all.

@jferris
thoughtbot, inc. member

I haven't heard that one before, so it seems like you should open a new issue. If you have a failing test case or a sample of code that shows the behavior, that would be helpful. A pull request would also be awesome.

@mhoran

The issue is that the NetworkCookieJar is not shared between windows. I've written a test, though I'm not convinced it's failing properly. The proper test may require resolution of the outstanding issue where new commands can be issued before a new window has finished loading. (New commands on that window will block, but commands in the existing window will execute.)

I'll spend some time this weekend getting this worked out, unless someone else gets to it first.

@jferris
thoughtbot, inc. member

@mhoran - thanks for looking into this. @halogenandtoast and I started work on a branch that synchronizes page loads between windows. I'll check in with him on that today.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
This page is out of date. Refresh to see the latest.
Showing with 549 additions and 203 deletions.
  1. +16 −2 lib/capybara/driver/webkit.rb
  2. +16 −0 lib/capybara/driver/webkit/browser.rb
  3. +33 −20 spec/browser_spec.rb
  4. +94 −2 spec/driver_spec.rb
  5. +1 −0 spec/integration/driver_spec.rb
  6. +1 −3 src/Body.h
  7. +2 −1 src/ClearCookies.cpp
  8. +1 −3 src/ClearCookies.h
  9. +8 −3 src/Command.cpp
  10. +4 −2 src/Command.h
  11. +7 −3 src/CommandFactory.cpp
  12. +3 −2 src/CommandFactory.h
  13. +11 −7 src/Connection.cpp
  14. +4 −2 src/Connection.h
  15. +2 −1 src/ConsoleMessages.cpp
  16. +1 −3 src/ConsoleMessages.h
  17. +2 −1 src/CurrentUrl.cpp
  18. +1 −3 src/CurrentUrl.h
  19. +2 −1 src/Evaluate.cpp
  20. +1 −3 src/Evaluate.h
  21. +2 −1 src/Execute.cpp
  22. +1 −3 src/Execute.h
  23. +2 −1 src/Find.cpp
  24. +1 −3 src/Find.h
  25. +2 −1 src/FrameFocus.cpp
  26. +1 −2 src/FrameFocus.h
  27. +2 −1 src/GetCookies.cpp
  28. +1 −3 src/GetCookies.h
  29. +11 −0 src/GetWindowHandle.cpp
  30. +10 −0 src/GetWindowHandle.h
  31. +20 −0 src/GetWindowHandles.cpp
  32. +10 −0 src/GetWindowHandles.h
  33. +2 −1 src/Header.cpp
  34. +1 −3 src/Header.h
  35. +2 −1 src/Headers.cpp
  36. +1 −3 src/Headers.h
  37. +4 −3 src/IgnoreSslErrors.cpp
  38. +1 −3 src/IgnoreSslErrors.h
  39. +2 −1 src/Node.cpp
  40. +1 −3 src/Node.h
  41. +2 −1 src/NullCommand.cpp
  42. +1 −3 src/NullCommand.h
  43. +7 −6 src/PageLoadingCommand.cpp
  44. +3 −3 src/PageLoadingCommand.h
  45. +2 −1 src/Render.cpp
  46. +1 −3 src/Render.h
  47. +2 −1 src/RequestedUrl.cpp
  48. +1 −3 src/RequestedUrl.h
  49. +3 −17 src/Reset.cpp
  50. +1 −6 src/Reset.h
  51. +2 −1 src/ResizeWindow.cpp
  52. +1 −3 src/ResizeWindow.h
  53. +2 −3 src/Server.cpp
  54. +0 −2 src/Server.h
  55. +2 −1 src/SetCookie.cpp
  56. +1 −3 src/SetCookie.h
  57. +2 −1 src/SetProxy.cpp
  58. +1 −3 src/SetProxy.h
  59. +3 −2 src/SetSkipImageLoading.cpp
  60. +1 −3 src/SetSkipImageLoading.h
  61. +2 −1 src/Source.cpp
  62. +1 −2 src/Source.h
  63. +2 −1 src/Status.cpp
  64. +1 −3 src/Status.h
  65. +2 −1 src/Url.cpp
  66. +1 −3 src/Url.h
  67. +2 −1 src/Visit.cpp
  68. +1 −3 src/Visit.h
  69. +46 −19 src/WebPage.cpp
  70. +14 −5 src/WebPage.h
  71. +54 −0 src/WebPageManager.cpp
  72. +37 −0 src/WebPageManager.h
  73. +32 −0 src/WindowFocus.cpp
  74. +15 −0 src/WindowFocus.h
  75. +2 −1 src/body.cpp
  76. +4 −2 src/find_command.h
  77. +8 −0 src/webkit_server.pro
View
18 lib/capybara/driver/webkit.rb
@@ -92,8 +92,22 @@ def within_frame(frame_id_or_index)
end
end
- def within_window(handle)
- raise Capybara::NotSupportedByDriverError
+ def within_window(selector)
+ current_window = window_handle
+ browser.window_focus(selector)
+ begin
+ yield
+ ensure
+ browser.window_focus(current_window)
+ end
+ end
+
+ def window_handles
+ browser.get_window_handles
+ end
+
+ def window_handle
+ browser.get_window_handle
end
def wait?
View
16 lib/capybara/driver/webkit/browser.rb
@@ -81,6 +81,22 @@ def set_skip_image_loading(skip_image_loading)
command("SetSkipImageLoading", skip_image_loading)
end
+ def window_focus(selector)
+ command("WindowFocus", selector)
+ end
+
+ def get_window_handles
+ JSON.parse(command('GetWindowHandles'))
+ end
+
+ alias_method :window_handles, :get_window_handles
+
+ def get_window_handle
+ command('GetWindowHandle')
+ end
+
+ alias_method :window_handle, :get_window_handle
+
def command(name, *args)
@connection.puts name
@connection.puts args.size
View
53 spec/browser_spec.rb
@@ -1,8 +1,7 @@
require 'spec_helper'
require 'self_signed_ssl_cert'
require 'stringio'
-require 'capybara/driver/webkit/browser'
-require 'capybara/driver/webkit/connection'
+require 'capybara/driver/webkit'
require 'socket'
require 'base64'
@@ -62,6 +61,18 @@
it 'accepts a self-signed certificate if configured to do so' do
browser_ignore_ssl_err.visit "https://#{@host}:#{@port}/"
end
+
+ it "doesn't accept a self-signed certificate in a new window by default" do
+ browser.execute_script("window.open('about:blank')")
+ browser.window_focus(browser.get_window_handles.last)
+ lambda { browser.visit "https://#{@host}:#{@port}/" }.should raise_error
+ end
+
+ it 'accepts a self-signed certificate in a new window if configured to do so' do
+ browser_ignore_ssl_err.execute_script("window.open('about:blank')")
+ browser_ignore_ssl_err.window_focus(browser_ignore_ssl_err.get_window_handles.last)
+ browser_ignore_ssl_err.visit "https://#{@host}:#{@port}/"
+ end
end
context "skip image loading" do
@@ -72,18 +83,19 @@
@port = @server.addr[1]
@received_requests = []
- @server_thread = Thread.new(@server) do |serv|
- while conn = serv.accept do
- # read request
- request = []
- until (line = conn.readline.strip).empty?
- request << line
- end
+ @server_thread = Thread.new do
+ while conn = @server.accept
+ Thread.new(conn) do |conn|
+ # read request
+ request = []
+ until (line = conn.readline.strip).empty?
+ request << line
+ end
- @received_requests << request.join("\n")
+ @received_requests << request.join("\n")
- # write response
- html = <<-HTML
+ # write response
+ html = <<-HTML
<html>
<head>
<style>
@@ -96,14 +108,15 @@
<img src="/path/to/image"/>
</body>
</html>
- HTML
- conn.write "HTTP/1.1 200 OK\r\n"
- conn.write "Content-Type:text/html\r\n"
- conn.write "Content-Length: %i\r\n" % html.size
- conn.write "\r\n"
- conn.write html
- conn.write("\r\n\r\n")
- conn.close
+ HTML
+ conn.write "HTTP/1.1 200 OK\r\n"
+ conn.write "Content-Type:text/html\r\n"
+ conn.write "Content-Length: %i\r\n" % html.size
+ conn.write "\r\n"
+ conn.write html
+ conn.write("\r\n\r\n")
+ conn.close
+ end
end
end
end
View
96 spec/driver_spec.rb
@@ -211,9 +211,9 @@
subject.find("//*[contains(., 'hello')]").should be_empty
end
- it "has a location of 'about:blank' after reseting" do
+ it "has a blank location after reseting" do
subject.reset!
- subject.current_url.should == "about:blank"
+ subject.current_url.should == ""
end
it "raises an error for an invalid xpath query" do
@@ -1549,4 +1549,96 @@ def which_for(character)
subject.source.should == "Hello\0World"
end
end
+
+ context "javascript new window app" do
+ before(:all) do
+ @app = lambda do |env|
+ request = ::Rack::Request.new(env)
+ if request.path == '/new_window'
+ body = <<-HTML
+ <html>
+ <script type="text/javascript">
+ window.open('http://#{request.host_with_port}/test?#{request.query_string}', 'myWindow');
+ </script>
+ <p>bananas</p>
+ </html>
+ HTML
+ else
+ params = request.params
+ sleep params['sleep'].to_i if params['sleep']
+ body = "<html><head><title>My New Window</title></head><body><p>finished</p></body></html>"
+ end
+ [200,
+ { 'Content-Type' => 'text/html', 'Content-Length' => body.length.to_s },
+ [body]]
+ end
+ end
+
+ it "has the expected text in the new window" do
+ subject.visit("/new_window")
+ subject.within_window(subject.window_handles.last) do
+ subject.find("//p").first.text.should == "finished"
+ end
+ end
+
+ it "waits for the new window to load" do
+ subject.visit("/new_window?sleep=1")
+ subject.within_window(subject.window_handles.last) do
+ subject.find("//p").first.text.should == "finished"
+ end
+ end
+
+ it "waits for the new window to load when the window location has changed" do
+ subject.visit("/new_window?sleep=2")
+ subject.execute_script("setTimeout(function() { window.location = 'about:blank' }, 1000)")
+ subject.within_window(subject.window_handles.last) do
+ subject.find("//p").first.text.should == "finished"
+ end
+ end
+
+ it "switches back to the original window" do
+ subject.visit("/new_window")
+ subject.within_window(subject.window_handles.last) { }
+ subject.find("//p").first.text.should == "bananas"
+ end
+
+ it "supports finding a window by name" do
+ subject.visit("/new_window")
+ subject.within_window('myWindow') do
+ subject.find("//p").first.text.should == "finished"
+ end
+ end
+
+ it "supports finding a window by title" do
+ subject.visit("/new_window")
+ subject.within_window('My New Window') do
+ subject.find("//p").first.text.should == "finished"
+ end
+ end
+
+ it "supports finding a window by url" do
+ subject.visit("/new_window")
+ subject.within_window("http://127.0.0.1:#{subject.server_port}/test?") do
+ subject.find("//p").first.text.should == "finished"
+ end
+ end
+
+ it "raises an error if the window is not found" do
+ expect { subject.within_window('myWindowDoesNotExist') }.
+ to raise_error(Capybara::Driver::Webkit::WebkitInvalidResponseError)
+ end
+
+ it "has a number of window handles equal to the number of open windows" do
+ subject.window_handles.size.should == 1
+ subject.visit("/new_window")
+ subject.window_handles.size.should == 2
+ end
+
+ it "closes new windows on reset" do
+ subject.visit("/new_window")
+ last_handle = subject.window_handles.last
+ subject.reset!
+ subject.window_handles.should_not include(last_handle)
+ end
+ end
end
View
1 spec/integration/driver_spec.rb
@@ -12,6 +12,7 @@
it_should_behave_like "driver with header support"
it_should_behave_like "driver with status code support"
it_should_behave_like "driver with frame support"
+ it_should_behave_like "driver with support for window switching"
it "returns the rack server port" do
@driver.server_port.should eq(@driver.instance_variable_get(:@rack_server).port)
View
4 src/Body.h
@@ -1,12 +1,10 @@
#include "Command.h"
-class WebPage;
-
class Body : public Command {
Q_OBJECT
public:
- Body(WebPage *page, QStringList &arguments, QObject *parent = 0);
+ Body(WebPageManager *, QStringList &arguments, QObject *parent = 0);
virtual void start();
};
View
3 src/ClearCookies.cpp
@@ -1,9 +1,10 @@
#include "ClearCookies.h"
#include "WebPage.h"
+#include "WebPageManager.h"
#include "NetworkCookieJar.h"
#include <QNetworkCookie>
-ClearCookies::ClearCookies(WebPage *page, QStringList &arguments, QObject *parent) : Command(page, arguments, parent) {}
+ClearCookies::ClearCookies(WebPageManager *manager, QStringList &arguments, QObject *parent) : Command(manager, arguments, parent) {}
void ClearCookies::start()
{
View
4 src/ClearCookies.h
@@ -1,11 +1,9 @@
#include "Command.h"
-class WebPage;
-
class ClearCookies : public Command {
Q_OBJECT;
public:
- ClearCookies(WebPage *page, QStringList &arguments, QObject *parent = 0);
+ ClearCookies(WebPageManager *, QStringList &arguments, QObject *parent = 0);
virtual void start();
};
View
11 src/Command.cpp
@@ -1,8 +1,9 @@
#include "Command.h"
#include "WebPage.h"
+#include "WebPageManager.h"
-Command::Command(WebPage *page, QStringList &arguments, QObject *parent) : QObject(parent) {
- m_page = page;
+Command::Command(WebPageManager *manager, QStringList &arguments, QObject *parent) : QObject(parent) {
+ m_manager = manager;
m_arguments = arguments;
}
@@ -10,10 +11,14 @@ void Command::start() {
}
WebPage *Command::page() {
- return m_page;
+ return m_manager->currentPage();
}
QStringList &Command::arguments() {
return m_arguments;
}
+WebPageManager *Command::manager() {
+ return m_manager;
+}
+
View
6 src/Command.h
@@ -6,12 +6,13 @@
#include "Response.h"
class WebPage;
+class WebPageManager;
class Command : public QObject {
Q_OBJECT
public:
- Command(WebPage *page, QStringList &arguments, QObject *parent = 0);
+ Command(WebPageManager *, QStringList &arguments, QObject *parent = 0);
virtual void start();
signals:
@@ -20,10 +21,11 @@ class Command : public QObject {
protected:
WebPage *page();
QStringList &arguments();
+ WebPageManager *manager();
private:
- WebPage *m_page;
QStringList m_arguments;
+ WebPageManager *m_manager;
};
View
10 src/CommandFactory.cpp
@@ -25,14 +25,18 @@
#include "ResizeWindow.h"
#include "IgnoreSslErrors.h"
#include "SetSkipImageLoading.h"
+#include "WindowFocus.h"
+#include "GetWindowHandles.h"
+#include "GetWindowHandle.h"
+#include "WebPageManager.h"
-CommandFactory::CommandFactory(WebPage *page, QObject *parent) : QObject(parent) {
- m_page = page;
+CommandFactory::CommandFactory(WebPageManager *manager, QObject *parent) : QObject(parent) {
+ m_manager = manager;
}
Command *CommandFactory::createCommand(const char *name, QStringList &arguments) {
#include "find_command.h"
arguments.clear();
arguments.append(QString(name));
- return new NullCommand(m_page, arguments);
+ return new NullCommand(m_manager, arguments);
}
View
5 src/CommandFactory.h
@@ -2,15 +2,16 @@
class Command;
class WebPage;
+class WebPageManager;
class CommandFactory : public QObject {
Q_OBJECT
public:
- CommandFactory(WebPage *page, QObject *parent = 0);
+ CommandFactory(WebPageManager *, QObject *parent = 0);
Command *createCommand(const char *name, QStringList &arguments);
private:
- WebPage *m_page;
+ WebPageManager *m_manager;
};
View
18 src/Connection.cpp
@@ -1,5 +1,6 @@
#include "Connection.h"
#include "WebPage.h"
+#include "WebPageManager.h"
#include "CommandParser.h"
#include "CommandFactory.h"
#include "PageLoadingCommand.h"
@@ -7,22 +8,22 @@
#include <QTcpSocket>
-Connection::Connection(QTcpSocket *socket, WebPage *page, QObject *parent) :
+Connection::Connection(QTcpSocket *socket, WebPageManager *manager, QObject *parent) :
QObject(parent) {
m_socket = socket;
- m_page = page;
- m_commandFactory = new CommandFactory(page, this);
+ m_manager = manager;
+ m_commandFactory = new CommandFactory(m_manager, this);
m_commandParser = new CommandParser(socket, m_commandFactory, this);
m_pageSuccess = true;
m_commandWaiting = false;
connect(m_socket, SIGNAL(readyRead()), m_commandParser, SLOT(checkNext()));
connect(m_commandParser, SIGNAL(commandReady(Command *)), this, SLOT(commandReady(Command *)));
- connect(m_page, SIGNAL(pageFinished(bool)), this, SLOT(pendingLoadFinished(bool)));
+ connect(m_manager, SIGNAL(pageFinished(bool)), this, SLOT(pendingLoadFinished(bool)));
}
void Connection::commandReady(Command *command) {
m_queuedCommand = command;
- if (m_page->isLoading())
+ if (currentPage()->isLoading())
m_commandWaiting = true;
else
startCommand();
@@ -31,7 +32,7 @@ void Connection::commandReady(Command *command) {
void Connection::startCommand() {
m_commandWaiting = false;
if (m_pageSuccess) {
- m_runningCommand = new PageLoadingCommand(m_queuedCommand, m_page, this);
+ m_runningCommand = new PageLoadingCommand(m_queuedCommand, m_manager, this);
connect(m_runningCommand, SIGNAL(finished(Response *)), this, SLOT(finishCommand(Response *)));
m_runningCommand->start();
} else {
@@ -47,7 +48,7 @@ void Connection::pendingLoadFinished(bool success) {
void Connection::writePageLoadFailure() {
m_pageSuccess = true;
- QString message = m_page->failureString();
+ QString message = currentPage()->failureString();
writeResponse(new Response(false, message));
}
@@ -69,3 +70,6 @@ void Connection::writeResponse(Response *response) {
delete response;
}
+WebPage *Connection::currentPage() {
+ return m_manager->currentPage();
+}
View
6 src/Connection.h
@@ -8,12 +8,13 @@ class Response;
class CommandParser;
class CommandFactory;
class PageLoadingCommand;
+class WebPageManager;
class Connection : public QObject {
Q_OBJECT
public:
- Connection(QTcpSocket *socket, WebPage *page, QObject *parent = 0);
+ Connection(QTcpSocket *socket, WebPageManager *manager, QObject *parent = 0);
public slots:
void commandReady(Command *command);
@@ -27,11 +28,12 @@ class Connection : public QObject {
QTcpSocket *m_socket;
Command *m_queuedCommand;
- WebPage *m_page;
+ WebPageManager *m_manager;
CommandParser *m_commandParser;
CommandFactory *m_commandFactory;
PageLoadingCommand *m_runningCommand;
bool m_pageSuccess;
bool m_commandWaiting;
+ WebPage *currentPage();
};
View
3 src/ConsoleMessages.cpp
@@ -1,7 +1,8 @@
#include "ConsoleMessages.h"
#include "WebPage.h"
+#include "WebPageManager.h"
-ConsoleMessages::ConsoleMessages(WebPage *page, QStringList &arguments, QObject *parent) : Command(page, arguments, parent) {
+ConsoleMessages::ConsoleMessages(WebPageManager *manager, QStringList &arguments, QObject *parent) : Command(manager, arguments, parent) {
}
void ConsoleMessages::start() {
View
4 src/ConsoleMessages.h
@@ -1,12 +1,10 @@
#include "Command.h"
-class WebPage;
-
class ConsoleMessages : public Command {
Q_OBJECT
public:
- ConsoleMessages(WebPage *page, QStringList &arguments, QObject *parent = 0);
+ ConsoleMessages(WebPageManager *, QStringList &arguments, QObject *parent = 0);
virtual void start();
};
View
3 src/CurrentUrl.cpp
@@ -1,7 +1,8 @@
#include "CurrentUrl.h"
#include "WebPage.h"
+#include "WebPageManager.h"
-CurrentUrl::CurrentUrl(WebPage *page, QStringList &arguments, QObject *parent) : Command(page, arguments, parent) {
+CurrentUrl::CurrentUrl(WebPageManager *manager, QStringList &arguments, QObject *parent) : Command(manager, arguments, parent) {
}
/*
View
4 src/CurrentUrl.h
@@ -1,12 +1,10 @@
#include "Command.h"
-class WebPage;
-
class CurrentUrl : public Command {
Q_OBJECT
public:
- CurrentUrl(WebPage *page, QStringList &arguments, QObject *parent = 0);
+ CurrentUrl(WebPageManager *, QStringList &arguments, QObject *parent = 0);
virtual void start();
private:
View
3 src/Evaluate.cpp
@@ -1,8 +1,9 @@
#include "Evaluate.h"
#include "WebPage.h"
+#include "WebPageManager.h"
#include <iostream>
-Evaluate::Evaluate(WebPage *page, QStringList &arguments, QObject *parent) : Command(page, arguments, parent) {
+Evaluate::Evaluate(WebPageManager *manager, QStringList &arguments, QObject *parent) : Command(manager, arguments, parent) {
m_buffer = "";
}
View
4 src/Evaluate.h
@@ -2,13 +2,11 @@
#include <QVariantList>
-class WebPage;
-
class Evaluate : public Command {
Q_OBJECT
public:
- Evaluate(WebPage *page, QStringList &arguments, QObject *parent = 0);
+ Evaluate(WebPageManager *, QStringList &arguments, QObject *parent = 0);
virtual void start();
private:
View
3 src/Execute.cpp
@@ -1,7 +1,8 @@
#include "Execute.h"
#include "WebPage.h"
+#include "WebPageManager.h"
-Execute::Execute(WebPage *page, QStringList &arguments, QObject *parent) : Command(page, arguments, parent) {
+Execute::Execute(WebPageManager *manager, QStringList &arguments, QObject *parent) : Command(manager, arguments, parent) {
}
void Execute::start() {
View
4 src/Execute.h
@@ -1,12 +1,10 @@
#include "Command.h"
-class WebPage;
-
class Execute : public Command {
Q_OBJECT
public:
- Execute(WebPage *page, QStringList &arguments, QObject *parent = 0);
+ Execute(WebPageManager *, QStringList &arguments, QObject *parent = 0);
virtual void start();
};
View
3 src/Find.cpp
@@ -1,8 +1,9 @@
#include "Find.h"
#include "Command.h"
#include "WebPage.h"
+#include "WebPageManager.h"
-Find::Find(WebPage *page, QStringList &arguments, QObject *parent) : Command(page, arguments, parent) {
+Find::Find(WebPageManager *manager, QStringList &arguments, QObject *parent) : Command(manager, arguments, parent) {
}
void Find::start() {
View
4 src/Find.h
@@ -1,12 +1,10 @@
#include "Command.h"
-class WebPage;
-
class Find : public Command {
Q_OBJECT
public:
- Find(WebPage *page, QStringList &arguments, QObject *parent = 0);
+ Find(WebPageManager *, QStringList &arguments, QObject *parent = 0);
virtual void start();
};
View
3 src/FrameFocus.cpp
@@ -1,8 +1,9 @@
#include "FrameFocus.h"
#include "Command.h"
#include "WebPage.h"
+#include "WebPageManager.h"
-FrameFocus::FrameFocus(WebPage *page, QStringList &arguments, QObject *parent) : Command(page, arguments, parent) {
+FrameFocus::FrameFocus(WebPageManager *manager, QStringList &arguments, QObject *parent) : Command(manager, arguments, parent) {
}
void FrameFocus::start() {
View
3 src/FrameFocus.h
@@ -1,13 +1,12 @@
#include "Command.h"
-class WebPage;
class QWebFrame;
class FrameFocus : public Command {
Q_OBJECT
public:
- FrameFocus(WebPage *page, QStringList &arguments, QObject *parent = 0);
+ FrameFocus(WebPageManager *, QStringList &arguments, QObject *parent = 0);
virtual void start();
private:
View
3 src/GetCookies.cpp
@@ -1,8 +1,9 @@
#include "GetCookies.h"
#include "WebPage.h"
+#include "WebPageManager.h"
#include "NetworkCookieJar.h"
-GetCookies::GetCookies(WebPage *page, QStringList &arguments, QObject *parent) : Command(page, arguments, parent)
+GetCookies::GetCookies(WebPageManager *manager, QStringList &arguments, QObject *parent) : Command(manager, arguments, parent)
{
m_buffer = "";
}
View
4 src/GetCookies.h
@@ -1,12 +1,10 @@
#include "Command.h"
-class WebPage;
-
class GetCookies : public Command {
Q_OBJECT;
public:
- GetCookies(WebPage *page, QStringList &arguments, QObject *parent = 0);
+ GetCookies(WebPageManager *, QStringList &arguments, QObject *parent = 0);
virtual void start();
private:
View
11 src/GetWindowHandle.cpp
@@ -0,0 +1,11 @@
+#include "GetWindowHandle.h"
+#include "WebPage.h"
+#include "WebPageManager.h"
+#include <QStringList>
+
+GetWindowHandle::GetWindowHandle(WebPageManager *manager, QStringList &arguments, QObject *parent) : Command(manager, arguments, parent) {
+}
+
+void GetWindowHandle::start() {
+ emit finished(new Response(true, page()->uuid()));
+}
View
10 src/GetWindowHandle.h
@@ -0,0 +1,10 @@
+#include "Command.h"
+
+class GetWindowHandle : public Command {
+ Q_OBJECT
+
+ public:
+ GetWindowHandle(WebPageManager *, QStringList &arguments, QObject *parent = 0);
+ virtual void start();
+};
+
View
20 src/GetWindowHandles.cpp
@@ -0,0 +1,20 @@
+#include "GetWindowHandles.h"
+#include "WebPageManager.h"
+#include "CommandFactory.h"
+#include "WebPage.h"
+#include <QStringList>
+
+GetWindowHandles::GetWindowHandles(WebPageManager *manager, QStringList &arguments, QObject *parent) : Command(manager, arguments, parent) {
+}
+
+void GetWindowHandles::start() {
+ QString handles = "[";
+ QStringList stringList;
+
+ foreach(WebPage *page, manager()->pages())
+ stringList.append("\"" + page->uuid() + "\"");
+
+ handles += stringList.join(",") + "]";
+
+ emit finished(new Response(true, handles));
+}
View
10 src/GetWindowHandles.h
@@ -0,0 +1,10 @@
+#include "Command.h"
+
+class GetWindowHandles : public Command {
+ Q_OBJECT
+
+ public:
+ GetWindowHandles(WebPageManager *, QStringList &arguments, QObject *parent = 0);
+ virtual void start();
+};
+
View
3 src/Header.cpp
@@ -1,8 +1,9 @@
#include "Header.h"
#include "WebPage.h"
+#include "WebPageManager.h"
#include "NetworkAccessManager.h"
-Header::Header(WebPage *page, QStringList &arguments, QObject *parent) : Command(page, arguments, parent) {
+Header::Header(WebPageManager *manager, QStringList &arguments, QObject *parent) : Command(manager, arguments, parent) {
}
void Header::start() {
View
4 src/Header.h
@@ -1,11 +1,9 @@
#include "Command.h"
-class WebPage;
-
class Header : public Command {
Q_OBJECT
public:
- Header(WebPage *page, QStringList &arguments, QObject *parent = 0);
+ Header(WebPageManager *, QStringList &arguments, QObject *parent = 0);
virtual void start();
};
View
3 src/Headers.cpp
@@ -1,7 +1,8 @@
#include "Headers.h"
#include "WebPage.h"
+#include "WebPageManager.h"
-Headers::Headers(WebPage *page, QStringList &arguments, QObject *parent) : Command(page, arguments, parent) {
+Headers::Headers(WebPageManager *manager, QStringList &arguments, QObject *parent) : Command(manager, arguments, parent) {
}
void Headers::start() {
View
4 src/Headers.h
@@ -1,12 +1,10 @@
#include "Command.h"
-class WebPage;
-
class Headers : public Command {
Q_OBJECT
public:
- Headers(WebPage *page, QStringList &arguments, QObject *parent = 0);
+ Headers(WebPageManager *, QStringList &arguments, QObject *parent = 0);
virtual void start();
};
View
7 src/IgnoreSslErrors.cpp
@@ -1,12 +1,13 @@
#include "IgnoreSslErrors.h"
#include "WebPage.h"
+#include "WebPageManager.h"
-IgnoreSslErrors::IgnoreSslErrors(WebPage *page, QStringList &arguments, QObject *parent) :
- Command(page, arguments, parent) {
+IgnoreSslErrors::IgnoreSslErrors(WebPageManager *manager, QStringList &arguments, QObject *parent) :
+ Command(manager, arguments, parent) {
}
void IgnoreSslErrors::start() {
- page()->ignoreSslErrors();
+ manager()->setIgnoreSslErrors(true);
emit finished(new Response(true));
}
View
4 src/IgnoreSslErrors.h
@@ -1,12 +1,10 @@
#include "Command.h"
-class WebPage;
-
class IgnoreSslErrors : public Command {
Q_OBJECT
public:
- IgnoreSslErrors(WebPage *page, QStringList &arguments, QObject *parent = 0);
+ IgnoreSslErrors(WebPageManager *manager, QStringList &arguments, QObject *parent = 0);
virtual void start();
};
View
3 src/Node.cpp
@@ -1,7 +1,8 @@
#include "Node.h"
#include "WebPage.h"
+#include "WebPageManager.h"
-Node::Node(WebPage *page, QStringList &arguments, QObject *parent) : Command(page, arguments, parent) {
+Node::Node(WebPageManager *manager, QStringList &arguments, QObject *parent) : Command(manager, arguments, parent) {
}
void Node::start() {
View
4 src/Node.h
@@ -1,13 +1,11 @@
#include "Command.h"
#include <QStringList>
-class WebPage;
-
class Node : public Command {
Q_OBJECT
public:
- Node(WebPage *page, QStringList &arguments, QObject *parent = 0);
+ Node(WebPageManager *manager, QStringList &arguments, QObject *parent = 0);
virtual void start();
};
View
3 src/NullCommand.cpp
@@ -1,7 +1,8 @@
#include "NullCommand.h"
#include "WebPage.h"
+#include "WebPageManager.h"
-NullCommand::NullCommand(WebPage *page, QStringList &arguments, QObject *parent) : Command(page, arguments, parent) {}
+NullCommand::NullCommand(WebPageManager *manager, QStringList &arguments, QObject *parent) : Command(manager, arguments, parent) {}
void NullCommand::start() {
QString failure = QString("[Capybara WebKit] Unknown command: ") + arguments()[0] + "\n";
View
4 src/NullCommand.h
@@ -1,11 +1,9 @@
#include "Command.h"
-class WebPage;
-
class NullCommand : public Command {
Q_OBJECT
public:
- NullCommand(WebPage *page, QStringList &arguments, QObject *parent = 0);
+ NullCommand(WebPageManager *, QStringList &arguments, QObject *parent = 0);
virtual void start();
};
View
13 src/PageLoadingCommand.cpp
@@ -1,15 +1,16 @@
#include "PageLoadingCommand.h"
#include "Command.h"
#include "WebPage.h"
+#include "WebPageManager.h"
-PageLoadingCommand::PageLoadingCommand(Command *command, WebPage *page, QObject *parent) : QObject(parent) {
- m_page = page;
+PageLoadingCommand::PageLoadingCommand(Command *command, WebPageManager *manager, QObject *parent) : QObject(parent) {
+ m_manager = manager;
m_command = command;
m_pageLoadingFromCommand = false;
m_pageSuccess = true;
m_pendingResponse = NULL;
- connect(m_page, SIGNAL(loadStarted()), this, SLOT(pageLoadingFromCommand()));
- connect(m_page, SIGNAL(pageFinished(bool)), this, SLOT(pendingLoadFinished(bool)));
+ connect(m_manager, SIGNAL(loadStarted()), this, SLOT(pageLoadingFromCommand()));
+ connect(m_manager, SIGNAL(pageFinished(bool)), this, SLOT(pendingLoadFinished(bool)));
}
void PageLoadingCommand::start() {
@@ -25,7 +26,7 @@ void PageLoadingCommand::pendingLoadFinished(bool success) {
if (m_pageSuccess) {
emit finished(m_pendingResponse);
} else {
- QString message = m_page->failureString();
+ QString message = m_manager->currentPage()->failureString();
emit finished(new Response(false, message));
}
}
@@ -37,7 +38,7 @@ void PageLoadingCommand::pageLoadingFromCommand() {
}
void PageLoadingCommand::commandFinished(Response *response) {
- disconnect(m_page, SIGNAL(loadStarted()), this, SLOT(pageLoadingFromCommand()));
+ disconnect(m_manager, SIGNAL(loadStarted()), this, SLOT(pageLoadingFromCommand()));
m_command->deleteLater();
if (m_pageLoadingFromCommand)
m_pendingResponse = response;
View
6 src/PageLoadingCommand.h
@@ -3,7 +3,7 @@
class Command;
class Response;
-class WebPage;
+class WebPageManager;
/*
* Decorates a Command by deferring the finished() signal until any pending
@@ -19,7 +19,7 @@ class PageLoadingCommand : public QObject {
Q_OBJECT
public:
- PageLoadingCommand(Command *command, WebPage *page, QObject *parent = 0);
+ PageLoadingCommand(Command *command, WebPageManager *page, QObject *parent = 0);
void start();
public slots:
@@ -31,7 +31,7 @@ class PageLoadingCommand : public QObject {
void finished(Response *response);
private:
- WebPage *m_page;
+ WebPageManager *m_manager;
Command *m_command;
Response *m_pendingResponse;
bool m_pageSuccess;
View
3 src/Render.cpp
@@ -1,7 +1,8 @@
#include "Render.h"
#include "WebPage.h"
+#include "WebPageManager.h"
-Render::Render(WebPage *page, QStringList &arguments, QObject *parent) : Command(page, arguments, parent) {
+Render::Render(WebPageManager *manager, QStringList &arguments, QObject *parent) : Command(manager, arguments, parent) {
}
void Render::start() {
View
4 src/Render.h
@@ -1,12 +1,10 @@
#include "Command.h"
#include <QStringList>
-class WebPage;
-
class Render : public Command {
Q_OBJECT
public:
- Render(WebPage *page, QStringList &arguments, QObject *parent = 0);
+ Render(WebPageManager *page, QStringList &arguments, QObject *parent = 0);
virtual void start();
};
View
3 src/RequestedUrl.cpp
@@ -1,7 +1,8 @@
#include "RequestedUrl.h"
#include "WebPage.h"
+#include "WebPageManager.h"
-RequestedUrl::RequestedUrl(WebPage *page, QStringList &arguments, QObject *parent) : Command(page, arguments, parent) {
+RequestedUrl::RequestedUrl(WebPageManager *manager, QStringList &arguments, QObject *parent) : Command(manager, arguments, parent) {
}
void RequestedUrl::start() {
View
4 src/RequestedUrl.h
@@ -1,12 +1,10 @@
#include "Command.h"
-class WebPage;
-
class RequestedUrl : public Command {
Q_OBJECT
public:
- RequestedUrl(WebPage *page, QStringList &arguments, QObject *parent = 0);
+ RequestedUrl(WebPageManager *, QStringList &arguments, QObject *parent = 0);
virtual void start();
};
View
20 src/Reset.cpp
@@ -1,29 +1,15 @@
#include "Reset.h"
#include "WebPage.h"
-#include "NetworkAccessManager.h"
-#include "NetworkCookieJar.h"
+#include "WebPageManager.h"
-Reset::Reset(WebPage *page, QStringList &arguments, QObject *parent) : Command(page, arguments, parent) {
+Reset::Reset(WebPageManager *manager, QStringList &arguments, QObject *parent) : Command(manager, arguments, parent) {
}
void Reset::start() {
page()->triggerAction(QWebPage::Stop);
- NetworkAccessManager* networkAccessManager = qobject_cast<NetworkAccessManager*>(page()->networkAccessManager());
- networkAccessManager->setCookieJar(new NetworkCookieJar());
- networkAccessManager->resetHeaders();
+ manager()->reset();
- page()->setUserAgent(NULL);
- page()->resetResponseHeaders();
- page()->resetConsoleMessages();
- page()->resetWindowSize();
- resetHistory();
emit finished(new Response(true));
}
-void Reset::resetHistory() {
- // Clearing the history preserves the current history item, so set it to blank first.
- page()->currentFrame()->setUrl(QUrl("about:blank"));
- page()->history()->clear();
-}
-
View
7 src/Reset.h
@@ -1,15 +1,10 @@
#include "Command.h"
-class WebPage;
-
class Reset : public Command {
Q_OBJECT
public:
- Reset(WebPage *page, QStringList &arguments, QObject *parent = 0);
+ Reset(WebPageManager *, QStringList &arguments, QObject *parent = 0);
virtual void start();
-
- private:
- void resetHistory();
};
View
3 src/ResizeWindow.cpp
@@ -1,7 +1,8 @@
#include "ResizeWindow.h"
#include "WebPage.h"
+#include "WebPageManager.h"
-ResizeWindow::ResizeWindow(WebPage *page, QStringList &arguments, QObject *parent) : Command(page, arguments, parent) {
+ResizeWindow::ResizeWindow(WebPageManager *manager, QStringList &arguments, QObject *parent) : Command(manager, arguments, parent) {
}
void ResizeWindow::start() {
View
4 src/ResizeWindow.h
@@ -1,12 +1,10 @@
#include "Command.h"
-class WebPage;
-
class ResizeWindow : public Command {
Q_OBJECT
public:
- ResizeWindow(WebPage *page, QStringList &arguments, QObject *parent = 0);
+ ResizeWindow(WebPageManager *, QStringList &arguments, QObject *parent = 0);
virtual void start();
};
View
5 src/Server.cpp
@@ -1,12 +1,11 @@
#include "Server.h"
-#include "WebPage.h"
#include "Connection.h"
+#include "WebPageManager.h"
#include <QTcpServer>
Server::Server(QObject *parent) : QObject(parent) {
m_tcp_server = new QTcpServer(this);
- m_page = new WebPage(this);
}
bool Server::start() {
@@ -20,5 +19,5 @@ quint16 Server::server_port() const {
void Server::handleConnection() {
QTcpSocket *socket = m_tcp_server->nextPendingConnection();
- new Connection(socket, m_page, this);
+ new Connection(socket, new WebPageManager(this), this);
}
View
2 src/Server.h
@@ -1,7 +1,6 @@
#include <QObject>
class QTcpServer;
-class WebPage;
class Server : public QObject {
Q_OBJECT
@@ -16,6 +15,5 @@ class Server : public QObject {
private:
QTcpServer *m_tcp_server;
- WebPage *m_page;
};
View
3 src/SetCookie.cpp
@@ -1,9 +1,10 @@
#include "SetCookie.h"
#include "WebPage.h"
+#include "WebPageManager.h"
#include "NetworkCookieJar.h"
#include <QNetworkCookie>
-SetCookie::SetCookie(WebPage *page, QStringList &arguments, QObject *parent) : Command(page, arguments, parent) {}
+SetCookie::SetCookie(WebPageManager *manager, QStringList &arguments, QObject *parent) : Command(manager, arguments, parent) {}
void SetCookie::start()
{
View
4 src/SetCookie.h
@@ -1,11 +1,9 @@
#include "Command.h"
-class WebPage;
-
class SetCookie : public Command {
Q_OBJECT;
public:
- SetCookie(WebPage *page, QStringList &arguments, QObject *parent = 0);
+ SetCookie(WebPageManager *, QStringList &arguments, QObject *parent = 0);
virtual void start();
};
View
3 src/SetProxy.cpp
@@ -1,9 +1,10 @@
#include "SetProxy.h"
#include "WebPage.h"
+#include "WebPageManager.h"
#include <QNetworkAccessManager>
#include <QNetworkProxy>
-SetProxy::SetProxy(WebPage *page, QStringList &arguments, QObject *parent) : Command(page, arguments, parent) {}
+SetProxy::SetProxy(WebPageManager *manager, QStringList &arguments, QObject *parent) : Command(manager, arguments, parent) {}
void SetProxy::start()
{
View
4 src/SetProxy.h
@@ -1,11 +1,9 @@
#include "Command.h"
-class WebPage;
-
class SetProxy : public Command {
Q_OBJECT;
public:
- SetProxy(WebPage *page, QStringList &arguments, QObject *parent = 0);
+ SetProxy(WebPageManager *, QStringList &arguments, QObject *parent = 0);
virtual void start();
};
View
5 src/SetSkipImageLoading.cpp
@@ -1,8 +1,9 @@
#include "SetSkipImageLoading.h"
#include "WebPage.h"
+#include "WebPageManager.h"
-SetSkipImageLoading::SetSkipImageLoading(WebPage *page, QStringList &arguments, QObject *parent) :
- Command(page, arguments, parent) {
+SetSkipImageLoading::SetSkipImageLoading(WebPageManager *manager, QStringList &arguments, QObject *parent) :
+ Command(manager, arguments, parent) {
}
void SetSkipImageLoading::start() {
View
4 src/SetSkipImageLoading.h
@@ -1,11 +1,9 @@
#include "Command.h"
-class WebPage;
-
class SetSkipImageLoading : public Command {
Q_OBJECT
public:
- SetSkipImageLoading(WebPage *page, QStringList &arguments, QObject *parent = 0);
+ SetSkipImageLoading(WebPageManager *manager, QStringList &arguments, QObject *parent = 0);
virtual void start();
};
View
3 src/Source.cpp
@@ -1,7 +1,8 @@
#include "Source.h"
#include "WebPage.h"
+#include "WebPageManager.h"
-Source::Source(WebPage *page, QStringList &arguments, QObject *parent) : Command(page, arguments, parent) {
+Source::Source(WebPageManager *manager, QStringList &arguments, QObject *parent) : Command(manager, arguments, parent) {
}
void Source::start() {
View
3 src/Source.h
@@ -1,13 +1,12 @@
#include "Command.h"
-class WebPage;
class QNetworkReply;
class Source : public Command {
Q_OBJECT
public:
- Source(WebPage *page, QStringList &arguments, QObject *parent = 0);
+ Source(WebPageManager *, QStringList &arguments, QObject *parent = 0);
virtual void start();
public slots:
View
3 src/Status.cpp
@@ -1,8 +1,9 @@
#include "Status.h"
#include "WebPage.h"
+#include "WebPageManager.h"
#include <sstream>
-Status::Status(WebPage *page, QStringList &arguments, QObject *parent) : Command(page, arguments, parent) {
+Status::Status(WebPageManager *manager, QStringList &arguments, QObject *parent) : Command(manager, arguments, parent) {
}
void Status::start() {
View
4 src/Status.h
@@ -1,12 +1,10 @@
#include "Command.h"
-class WebPage;
-
class Status : public Command {
Q_OBJECT
public:
- Status(WebPage *page, QStringList &arguments, QObject *parent = 0);
+ Status(WebPageManager *, QStringList &arguments, QObject *parent = 0);
virtual void start();
};
View
3 src/Url.cpp
@@ -1,7 +1,8 @@
#include "Url.h"
#include "WebPage.h"
+#include "WebPageManager.h"
-Url::Url(WebPage *page, QStringList &arguments, QObject *parent) : Command(page, arguments, parent) {
+Url::Url(WebPageManager *manager, QStringList &arguments, QObject *parent) : Command(manager, arguments, parent) {
}
void Url::start() {
View
4 src/Url.h
@@ -1,12 +1,10 @@
#include "Command.h"
-class WebPage;
-
class Url : public Command {
Q_OBJECT
public:
- Url(WebPage *page, QStringList &arguments, QObject *parent = 0);
+ Url(WebPageManager *, QStringList &arguments, QObject *parent = 0);
virtual void start();
};
View
3 src/Visit.cpp
@@ -1,8 +1,9 @@
#include "Visit.h"
#include "Command.h"
#include "WebPage.h"
+#include "WebPageManager.h"
-Visit::Visit(WebPage *page, QStringList &arguments, QObject *parent) : Command(page, arguments, parent) {
+Visit::Visit(WebPageManager *manager, QStringList &arguments, QObject *parent) : Command(manager, arguments, parent) {
}
void Visit::start() {
View
4 src/Visit.h
@@ -1,12 +1,10 @@
#include "Command.h"
-class WebPage;
-
class Visit : public Command {
Q_OBJECT
public:
- Visit(WebPage *page, QStringList &arguments, QObject *parent = 0);
+ Visit(WebPageManager *manager, QStringList &arguments, QObject *parent = 0);
virtual void start();
};
View
65 src/WebPage.cpp
@@ -1,4 +1,5 @@
#include "WebPage.h"
+#include "WebPageManager.h"
#include "JavascriptInvocation.h"
#include "NetworkAccessManager.h"
#include "NetworkCookieJar.h"
@@ -6,14 +7,18 @@
#include <QResource>
#include <iostream>
#include <QWebSettings>
+#include <QUuid>
+
+WebPage::WebPage(WebPageManager *manager, QObject *parent) : QWebPage(parent) {
+ m_loading = false;
+ m_manager = manager;
+ m_uuid = QUuid::createUuid().toString();
+ m_lastStatus = 0;
-WebPage::WebPage(QObject *parent) : QWebPage(parent) {
setForwardUnsupportedContent(true);
loadJavascript();
setUserStylesheet();
- m_loading = false;
- m_ignoreSslErrors = false;
this->setCustomNetworkAccessManager();
connect(this, SIGNAL(loadStarted()), this, SLOT(loadStarted()));
@@ -22,7 +27,13 @@ WebPage::WebPage(QObject *parent) : QWebPage(parent) {
this, SLOT(frameCreated(QWebFrame *)));
connect(this, SIGNAL(unsupportedContent(QNetworkReply*)),
this, SLOT(handleUnsupportedContent(QNetworkReply*)));
+ connect(this, SIGNAL(pageFinished(bool)),
+ m_manager, SLOT(emitPageFinished(bool)));
+ connect(this, SIGNAL(loadStarted()),
+ m_manager, SLOT(emitLoadStarted()));
resetWindowSize();
+
+ settings()->setAttribute(QWebSettings::JavascriptCanOpenWindows, true);
}
void WebPage::resetWindowSize() {
@@ -31,8 +42,8 @@ void WebPage::resetWindowSize() {
}
void WebPage::setCustomNetworkAccessManager() {
- NetworkAccessManager *manager = new NetworkAccessManager();
- manager->setCookieJar(new NetworkCookieJar());
+ NetworkAccessManager *manager = new NetworkAccessManager(this);
+ manager->setCookieJar(new NetworkCookieJar(this));
this->setNetworkAccessManager(manager);
connect(manager, SIGNAL(finished(QNetworkReply *)), this, SLOT(replyFinished(QNetworkReply *)));
connect(manager, SIGNAL(sslErrors(QNetworkReply *, QList<QSslError>)),
@@ -209,14 +220,10 @@ void WebPage::replyFinished(QNetworkReply *reply) {
}
void WebPage::handleSslErrorsForReply(QNetworkReply *reply, const QList<QSslError> &errors) {
- if (m_ignoreSslErrors)
+ if (m_manager->ignoreSslErrors())
reply->ignoreSslErrors(errors);
}
-void WebPage::ignoreSslErrors() {
- m_ignoreSslErrors = true;
-}
-
void WebPage::setSkipImageLoading(bool skip) {
settings()->setAttribute(QWebSettings::AutoLoadImages, !skip);
}
@@ -225,15 +232,6 @@ int WebPage::getLastStatus() {
return m_lastStatus;
}
-void WebPage::resetResponseHeaders() {
- m_lastStatus = 0;
- m_pageHeaders = QString();
-}
-
-void WebPage::resetConsoleMessages() {
- m_consoleMessages.clear();
-}
-
QString WebPage::pageHeaders() {
return m_pageHeaders;
}
@@ -242,3 +240,32 @@ void WebPage::handleUnsupportedContent(QNetworkReply *reply) {
UnsupportedContentHandler *handler = new UnsupportedContentHandler(this, reply);
Q_UNUSED(handler);
}
+
+QWebPage *WebPage::createWindow(WebWindowType type) {
+ Q_UNUSED(type);
+ return m_manager->createPage(this);
+}
+
+QString WebPage::uuid() {
+ return m_uuid;
+}
+
+QString WebPage::getWindowName() {
+ QVariant windowName = mainFrame()->evaluateJavaScript("window.name");
+
+ if (windowName.isValid())
+ return windowName.toString();
+ else
+ return "";
+}
+
+bool WebPage::matchesWindowSelector(QString selector) {
+ return (selector == getWindowName() ||
+ selector == mainFrame()->title() ||
+ selector == mainFrame()->url().toString() ||
+ selector == uuid());
+}
+
+void WebPage::setFocus() {
+ m_manager->setCurrentPage(this);
+}
View
19 src/WebPage.h
@@ -1,25 +1,31 @@
+#ifndef _WEBPAGE_H
+#define _WEBPAGE_H
#include <QtWebKit>
+class WebPageManager;
+
class WebPage : public QWebPage {
Q_OBJECT
public:
- WebPage(QObject *parent = 0);
+ WebPage(WebPageManager *, QObject *parent = 0);
QVariant invokeCapybaraFunction(const char *name, QStringList &arguments);
QVariant invokeCapybaraFunction(QString &name, QStringList &arguments);
QString failureString();
QString userAgentForUrl(const QUrl &url ) const;
void setUserAgent(QString userAgent);
int getLastStatus();
- void resetResponseHeaders();
void setCustomNetworkAccessManager();
bool render(const QString &fileName);
virtual bool extension (Extension extension, const ExtensionOption *option=0, ExtensionReturn *output=0);
- void ignoreSslErrors();
void setSkipImageLoading(bool skip);
QString consoleMessages();
- void resetConsoleMessages();
void resetWindowSize();
+ QWebPage *createWindow(WebWindowType type);
+ QString uuid();
+ QString getWindowName();
+ bool matchesWindowSelector(QString);
+ void setFocus();
public slots:
bool shouldInterruptJavaScript();
@@ -52,7 +58,10 @@ class WebPage : public QWebPage {
void setUserStylesheet();
int m_lastStatus;
QString m_pageHeaders;
- bool m_ignoreSslErrors;
QStringList m_consoleMessages;
+ QString m_uuid;
+ WebPageManager *m_manager;
};
+#endif //_WEBPAGE_H
+
View
54 src/WebPageManager.cpp
@@ -0,0 +1,54 @@
+#include "WebPageManager.h"
+#include "WebPage.h"
+#include <stdio.h>
+
+WebPageManager::WebPageManager(QObject *parent) : QObject(parent) {
+ m_ignoreSslErrors = false;
+ createPage(this)->setFocus();
+}
+
+void WebPageManager::append(WebPage *value) {
+ m_pages.append(value);
+}
+
+QList<WebPage *> WebPageManager::pages() {
+ return m_pages;
+}
+
+void WebPageManager::setCurrentPage(WebPage *page) {
+ m_currentPage = page;
+}
+
+WebPage *WebPageManager::currentPage() {
+ return m_currentPage;
+}
+
+WebPage *WebPageManager::createPage(QObject *parent) {
+ WebPage *page = new WebPage(this, parent);
+ append(page);
+ return page;
+}
+
+void WebPageManager::emitPageFinished(bool success) {
+ if (currentPage() == sender())
+ emit pageFinished(success);
+}
+
+void WebPageManager::emitLoadStarted() {
+ if (currentPage() == sender())
+ emit loadStarted();
+}
+
+void WebPageManager::setIgnoreSslErrors(bool value) {
+ m_ignoreSslErrors = value;
+}
+
+bool WebPageManager::ignoreSslErrors() {
+ return m_ignoreSslErrors;
+}
+
+void WebPageManager::reset() {
+ m_pages.first()->deleteLater();
+ m_pages.clear();
+ createPage(this)->setFocus();
+}
View
37 src/WebPageManager.h
@@ -0,0 +1,37 @@
+#ifndef _WEBPAGEMANAGER_H
+#define _WEBPAGEMANAGER_H
+#include <QList>
+#include <QObject>
+
+class WebPage;
+
+class WebPageManager : public QObject {
+ Q_OBJECT
+
+ public:
+ WebPageManager(QObject *parent = 0);
+ void append(WebPage *value);
+ QList<WebPage *> pages();
+ void setCurrentPage(WebPage *);
+ WebPage *currentPage();
+ WebPage *createPage(QObject *parent);
+ void setIgnoreSslErrors(bool);
+ bool ignoreSslErrors();
+ void reset();
+
+ public slots:
+ void emitPageFinished(bool);
+ void emitLoadStarted();
+
+ signals:
+ void pageFinished(bool);
+ void loadStarted();
+
+ private:
+ QList<WebPage *> m_pages;
+ WebPage *m_currentPage;
+ bool m_ignoreSslErrors;
+};
+
+#endif // _WEBPAGEMANAGER_H
+
View
32 src/WindowFocus.cpp