diff --git a/src/modules/webpage.js b/src/modules/webpage.js index e2f52c62..d39ff5b1 100644 --- a/src/modules/webpage.js +++ b/src/modules/webpage.js @@ -468,6 +468,9 @@ function decorateNewPage(opts, page) { // @see https://developer.mozilla.org/en/DOM/window.prompt definePageCallbackHandler(page, handlers, "onPrompt", "_getJsPromptCallback"); + // Calls from within the page when some javascript code running to long + definePageCallbackHandler(page, handlers, "onLongRunningScript", "_getJsInterruptCallback"); + page.event = {}; page.event.modifier = { shift: 0x02000000, diff --git a/src/webpage.cpp b/src/webpage.cpp index 89a34da3..2b86f604 100644 --- a/src/webpage.cpp +++ b/src/webpage.cpp @@ -112,7 +112,14 @@ public: public slots: bool shouldInterruptJavaScript() { - QApplication::processEvents(QEventLoop::AllEvents, 42); + m_webPage->javascriptInterrupt(); + + if (m_webPage->m_shouldInterruptJs) { + + // reset our flag + m_webPage->m_shouldInterruptJs = false; + return true; + } return false; } @@ -251,6 +258,7 @@ public: , m_filePickerCallback(NULL) , m_jsConfirmCallback(NULL) , m_jsPromptCallback(NULL) + , m_jsInterruptCallback(NULL) { } @@ -289,6 +297,15 @@ public: } return m_jsPromptCallback; } + + QObject *getJsInterruptCallback() { + qDebug() << "WebpageCallbacks - getJsInterruptCallback"; + + if (!m_jsInterruptCallback) { + m_jsInterruptCallback = new Callback(this); + } + return m_jsInterruptCallback; + } public slots: QVariant call(const QVariantList &arguments) { @@ -303,6 +320,7 @@ private: Callback *m_filePickerCallback; Callback *m_jsConfirmCallback; Callback *m_jsPromptCallback; + Callback *m_jsInterruptCallback; friend class WebPage; }; @@ -314,6 +332,7 @@ WebPage::WebPage(QObject *parent, const QUrl &baseUrl) , m_mousePos(QPoint(0, 0)) , m_ownsPages(true) , m_loadingProgress(0) + , m_shouldInterruptJs(false) { setObjectName("WebPage"); m_callbacks = new WebpageCallbacks(this); @@ -729,6 +748,17 @@ bool WebPage::javaScriptPrompt(const QString &msg, const QString &defaultValue, return false; } +void WebPage::javascriptInterrupt() +{ + if (m_callbacks->m_jsInterruptCallback) { + QVariant res = m_callbacks->m_jsInterruptCallback->call(QVariantList()); + + if (res.canConvert()) { + m_shouldInterruptJs = res.toBool(); + } + } +} + void WebPage::finish(bool ok) { QString status = ok ? "success" : "fail"; @@ -1293,6 +1323,15 @@ QObject *WebPage::_getJsPromptCallback() return m_callbacks->getJsPromptCallback(); } +QObject *WebPage::_getJsInterruptCallback() +{ + if (!m_callbacks) { + m_callbacks = new WebpageCallbacks(this); + } + + return m_callbacks->getJsInterruptCallback(); +} + void WebPage::sendEvent(const QString &type, const QVariant &arg1, const QVariant &arg2, const QString &mouseButton, const QVariant &modifierArg) { Qt::KeyboardModifiers keyboardModifiers(modifierArg.toInt()); @@ -1580,4 +1619,9 @@ void WebPage::updateLoadingProgress(int progress) m_loadingProgress = progress; } +void WebPage::stopJavaScript() +{ + m_shouldInterruptJs = true; +} + #include "webpage.moc" diff --git a/src/webpage.h b/src/webpage.h index e065bb4e..c8188da8 100644 --- a/src/webpage.h +++ b/src/webpage.h @@ -258,6 +258,7 @@ public slots: QObject *_getFilePickerCallback(); QObject *_getJsConfirmCallback(); QObject *_getJsPromptCallback(); + QObject *_getJsInterruptCallback(); void _uploadFile(const QString &selector, const QStringList &fileNames); void sendEvent(const QString &type, const QVariant &arg1 = QVariant(), const QVariant &arg2 = QVariant(), const QString &mouseButton = QString(), const QVariant &modifierArg = QVariant()); @@ -459,6 +460,8 @@ public slots: */ void stop(); + void stopJavaScript(); + signals: void initialized(); void loadStarted(); @@ -497,6 +500,7 @@ private: QString filePicker(const QString &oldFile); bool javaScriptConfirm(const QString &msg); bool javaScriptPrompt(const QString &msg, const QString &defaultValue, QString *result); + void javascriptInterrupt(); private: CustomPage *m_customWebPage; @@ -513,6 +517,7 @@ private: QPoint m_mousePos; bool m_ownsPages; int m_loadingProgress; + bool m_shouldInterruptJs; friend class Phantom; friend class CustomPage; diff --git a/test/webpage-spec-frames/forever.html b/test/webpage-spec-frames/forever.html new file mode 100644 index 00000000..6dcb7752 --- /dev/null +++ b/test/webpage-spec-frames/forever.html @@ -0,0 +1,12 @@ + + + + + + + + \ No newline at end of file diff --git a/test/webpage-spec.js b/test/webpage-spec.js index 88060450..99259313 100644 --- a/test/webpage-spec.js +++ b/test/webpage-spec.js @@ -1307,6 +1307,18 @@ describe("WebPage object", function() { server.close(); }); }); + + it("should interrupt a long-running JavaScript code", function() { + var page = new WebPage(); + + page.onLongRunningScript = function() { + page.stopJavaScript(); + }; + + page.open('../test/webpage-spec-frames/forever.html', function(status) { + expect(status).toEqual('success'); + }); + }); }); describe("WebPage construction with options", function () {