Permalink
Browse files

"onLoadFinished" works regardless of "page.open"

  • Loading branch information...
detro committed Sep 26, 2012
1 parent 60ced2c commit e31528adfedd817b5fc685cd1062c62d24192e76
Showing with 79 additions and 43 deletions.
  1. +22 −6 src/modules/webpage.js
  2. +56 −36 src/webpage.cpp
  3. +1 −1 src/webpage.h
View
@@ -162,24 +162,34 @@ function decorateNewPage(opts, page) {
definePageSignalSetter(page, handlers, "onClosing", "closing");
+ // Private callback for "page.open()"
+ definePageSignalSetter(page, handlers, "_onPageOpenFinished", "loadFinished");
+
phantom.__defineErrorSetter__(page, page);
page.onError = phantom.defaultErrorHandler;
page.open = function (url, arg1, arg2, arg3, arg4) {
+ var thisPage = this;
+
if (arguments.length === 1) {
this.openUrl(url, 'get', this.settings);
return;
- }
- if (arguments.length === 2 && typeof arg1 === 'function') {
- this.onLoadFinished = arg1;
+ } else if (arguments.length === 2 && typeof arg1 === 'function') {
+ this._onPageOpenFinished = function() {
+ thisPage._onPageOpenFinished = null; //< Disconnect callback (should fire only once)
+ arg1.apply(thisPage, arguments); //< Invoke the actual callback
+ }
this.openUrl(url, 'get', this.settings);
return;
} else if (arguments.length === 2) {
this.openUrl(url, arg1, this.settings);
return;
} else if (arguments.length === 3 && typeof arg2 === 'function') {
- this.onLoadFinished = arg2;
+ this._onPageOpenFinished = function() {
+ thisPage._onPageOpenFinished = null; //< Disconnect callback (should fire only once)
+ arg2.apply(thisPage, arguments); //< Invoke the actual callback
+ }
this.openUrl(url, arg1, this.settings);
return;
} else if (arguments.length === 3) {
@@ -189,14 +199,20 @@ function decorateNewPage(opts, page) {
}, this.settings);
return;
} else if (arguments.length === 4) {
- this.onLoadFinished = arg3;
+ this._onPageOpenFinished = function() {
+ thisPage._onPageOpenFinished = null; //< Disconnect callback (should fire only once)
+ arg3.apply(thisPage, arguments); //< Invoke the actual callback
+ }
this.openUrl(url, {
operation: arg1,
data: arg2
}, this.settings);
return;
} else if (arguments.length === 5) {
- this.onLoadFinished = arg4;
+ this._onPageOpenFinished = function() {
+ thisPage._onPageOpenFinished = null; //< Disconnect callback (should fire only once)
+ arg4.apply(thisPage, arguments); //< Invoke the actual callback
+ }
this.openUrl(url, {
operation: arg1,
data: arg2,
View
@@ -68,6 +68,7 @@
#define CALLBACKS_OBJECT_NAME "_phantom"
#define INPAGE_CALL_NAME "window.callPhantom"
#define CALLBACKS_OBJECT_INJECTION INPAGE_CALL_NAME" = function() { return window."CALLBACKS_OBJECT_NAME".call.call(_phantom, Array.prototype.splice.call(arguments, 0)); };"
+#define CALLBACKS_OBJECT_PRESENT "typeof(window."CALLBACKS_OBJECT_NAME") !== \"undefined\";"
/**
@@ -270,25 +271,40 @@ public slots:
WebPage::WebPage(QObject *parent, const QUrl &baseUrl)
: REPLCompletable(parent)
- , m_callbacks(NULL)
, m_navigationLocked(false)
, m_mousePos(QPoint(0, 0))
, m_ownsPages(true)
{
setObjectName("WebPage");
+ m_callbacks = new WebpageCallbacks(this);
m_customWebPage = new CustomPage(this);
m_mainFrame = m_customWebPage->mainFrame();
+ m_currentFrame = m_mainFrame;
m_mainFrame->setHtml(BLANK_HTML, baseUrl);
- changeCurrentFrame(m_mainFrame);
Config *phantomCfg = Phantom::instance()->config();
- connect(m_mainFrame, SIGNAL(javaScriptWindowObjectCleared()), this, SLOT(handleJavaScriptWindowObjectCleared()));
+ // NOTE: below you can see that between all the event handlers
+ // we listen for, "SLOT(setupFrame())" is connected to 2 signals:
+ // 1. page.loadFinished
+ // 2. mainFrame.javaScriptWindowObjectCleared
+ // We have found out that, despite our understanding, the event #1 above
+ // fires BEFORE the event #2 when loading a url.
+ // But, if no page load is requested, #2 is the only one to fire.
+ //
+ // So, we call the slot twice to setup the main frame
+ // (no parameter == main frame) but we make sure to do the setup only once.
+ //
+ // @see WebPage::setupFrame(QWebFrame *) for details.
+ connect(m_customWebPage, SIGNAL(loadStarted()), this, SLOT(switchToMainFrame()), Qt::QueuedConnection);
+ connect(m_customWebPage, SIGNAL(loadFinished(bool)), this, SLOT(setupFrame()), Qt::QueuedConnection);
+ connect(m_customWebPage, SIGNAL(frameCreated(QWebFrame*)), this, SLOT(setupFrame(QWebFrame*)), Qt::QueuedConnection);
+ connect(m_mainFrame, SIGNAL(javaScriptWindowObjectCleared()), this, SLOT(setupFrame()));
connect(m_mainFrame, SIGNAL(javaScriptWindowObjectCleared()), SIGNAL(initialized()));
connect(m_mainFrame, SIGNAL(urlChanged(QUrl)), SIGNAL(urlChanged(QUrl)));
connect(m_customWebPage, SIGNAL(loadStarted()), SIGNAL(loadStarted()), Qt::QueuedConnection);
connect(m_customWebPage, SIGNAL(loadFinished(bool)), SLOT(finish(bool)), Qt::QueuedConnection);
- connect(m_customWebPage, SIGNAL(windowCloseRequested()), this, SLOT(close()));
+ connect(m_customWebPage, SIGNAL(windowCloseRequested()), this, SLOT(close()), Qt::QueuedConnection);
// Start with transparent background.
QPalette palette = m_customWebPage->palette();
@@ -531,10 +547,18 @@ QVariantMap WebPage::paperSize() const
QVariant WebPage::evaluateJavaScript(const QString &code)
{
+ QVariant evalResult;
QString function = "(" + code + ")()";
- return m_currentFrame->evaluateJavaScript(
- function,
- QString("phantomjs://webpage.evaluate()"));
+
+ qDebug() << "WebPage - evaluateJavaScript" << function;
+
+ evalResult = m_currentFrame->evaluateJavaScript(
+ function, //< function evaluated
+ QString("phantomjs://webpage.evaluate()")); //< reference source file
+
+ qDebug() << "WebPage - evaluateJavaScript result" << evalResult;
+
+ return evalResult;
}
bool WebPage::javaScriptConfirm(const QString &msg)
@@ -1147,8 +1171,9 @@ QObjectList WebPage::pages() const
{
QObjectList pages;
- foreach(QObject *p, this->findChildren<WebPage *>()) {
- pages << p;
+ QList<WebPage *> childPages = this->findChildren<WebPage *>();
+ for (int i = childPages.length() -1; i >= 0; --i) {
+ pages << childPages.at(i);
}
return pages;
@@ -1158,7 +1183,7 @@ QStringList WebPage::pagesWindowName() const
{
QStringList pagesWindowName;
- foreach (WebPage *p, this->findChildren<WebPage *>()) {
+ foreach (const WebPage *p, this->findChildren<WebPage *>()) {
pagesWindowName << p->windowName();
}
@@ -1167,9 +1192,10 @@ QStringList WebPage::pagesWindowName() const
QObject *WebPage::getPage(const QString &windowName) const
{
- foreach (WebPage *p, this->findChildren<WebPage *>()) {
- if (p->windowName() == windowName) {
- return p;
+ QList<WebPage *> childPages = this->findChildren<WebPage *>();
+ for (int i = childPages.length() -1; i >= 0; --i) {
+ if (childPages.at(i)->windowName() == windowName) {
+ return childPages.at(i);
}
}
return NULL;
@@ -1199,7 +1225,7 @@ QStringList WebPage::framesName() const
{
QStringList framesName;
- foreach(QWebFrame *f, m_currentFrame->childFrames()) {
+ foreach(const QWebFrame *f, m_currentFrame->childFrames()) {
framesName << f->frameName();
}
return framesName;
@@ -1212,14 +1238,16 @@ QStringList WebPage::childFramesName() const //< deprecated
void WebPage::changeCurrentFrame(QWebFrame * const frame)
{
- m_currentFrame = frame;
+ qDebug() << "WebPage - changeCurrentFrame" << "from" << m_currentFrame->frameName() << "to" << frame->frameName();
+ m_currentFrame = frame;
}
bool WebPage::switchToFrame(const QString &frameName)
{
- foreach(QWebFrame * f, m_currentFrame->childFrames()) {
- if (f->frameName() == frameName) {
- this->changeCurrentFrame(f);
+ QList<QWebFrame *> childFrames = m_currentFrame->childFrames();
+ for (int i = childFrames.length() -1; i >= 0; --i) {
+ if (childFrames.at(i)->frameName() == frameName) {
+ this->changeCurrentFrame(childFrames.at(i));
return true;
}
}
@@ -1280,30 +1308,22 @@ QString WebPage::focusedFrameName() const
return m_customWebPage->currentFrame()->frameName();
}
-static void injectCallbacksObjIntoFrames(QWebFrame *frame, WebpageCallbacks *callbacksObject)
+static void injectCallbacksObjIntoFrame(QWebFrame *frame, WebpageCallbacks *callbacksObject)
{
- // Decorate the window object in this frame
- frame->addToJavaScriptWindowObject(CALLBACKS_OBJECT_NAME, callbacksObject, QScriptEngine::QtOwnership);
- frame->evaluateJavaScript(CALLBACKS_OBJECT_INJECTION);
-
- // Decorate the window object in the child frames (recursively)
- foreach (QWebFrame *childFrame, frame->childFrames()) {
- injectCallbacksObjIntoFrames(childFrame, callbacksObject);
+ // Inject object only if it's not already present
+ if (frame->evaluateJavaScript(CALLBACKS_OBJECT_PRESENT).toBool() == false) {
+ // Decorate the window object in this frame (object ownership left to the creator/parent)
+ frame->addToJavaScriptWindowObject(CALLBACKS_OBJECT_NAME, callbacksObject, QScriptEngine::QtOwnership);
+ frame->evaluateJavaScript(CALLBACKS_OBJECT_INJECTION);
}
}
-void WebPage::handleJavaScriptWindowObjectCleared()
+void WebPage::setupFrame(QWebFrame *frame)
{
- // Create Callbacks Holder object, if not already present for this page
- if (!m_callbacks) {
- m_callbacks = new WebpageCallbacks(this);
- }
-
- // Reset focus on the Main Frame
- m_mainFrame->setFocus();
+ qDebug() << "WebPage - setupFrame" << (frame == NULL ? "" : frame->frameName());
- // Inject the Callbacks object in the frame and child-frames (recursively)
- injectCallbacksObjIntoFrames(m_mainFrame, m_callbacks);
+ // Inject the Callbacks object in the main frame
+ injectCallbacksObjIntoFrame(frame == NULL ? m_mainFrame : frame, m_callbacks);
}
void WebPage::initCompletions()
View
@@ -417,7 +417,7 @@ public slots:
private slots:
void finish(bool ok);
- void handleJavaScriptWindowObjectCleared();
+ void setupFrame(QWebFrame *frame = NULL);
private:
QImage renderImage();

0 comments on commit e31528a

Please sign in to comment.