From 5b6f2731c4b813b24dde277a37a1b987204c7b18 Mon Sep 17 00:00:00 2001 From: Ivan De Marino Date: Tue, 7 Jun 2011 17:20:22 +0100 Subject: [PATCH 01/13] Added support for "page.click()" and "page.loadJsFile()". * click() accepts a "querySelectorAll" input - can click on multiple things in one call * loadJsFile() is synchronous at loading JS in the page * added 2 examples in JavaScript to show how to use (and test) the new methods * NOTE: someone will have to generate the .coffee version - I tried using "http://ricostacruz.com/js2coffee/" but it hangs and I'm not willing to learn why :P - I don't like Coffee Script. --- examples/click_around_google.js | 20 +++++++++++++++++++ examples/injectme.js | 25 ++++++++++++++++++++++++ src/consts.h | 6 ++++++ src/webpage.cpp | 34 ++++++++++++++++++++++++++------- src/webpage.h | 2 ++ 5 files changed, 80 insertions(+), 7 deletions(-) create mode 100644 examples/click_around_google.js create mode 100644 examples/injectme.js diff --git a/examples/click_around_google.js b/examples/click_around_google.js new file mode 100644 index 00000000..a1fabd1a --- /dev/null +++ b/examples/click_around_google.js @@ -0,0 +1,20 @@ +// test the "page.click(QUERY SELECTOR)" api +// NOTE: This test will need to be updated if Google changes it's DOM :-P + +var page = new WebPage(); + +page.open("http://www.google.com/", function(status) { + if ( status === "success" ) { + // render before doing anything + page.render("click_around_google-before.png"); + + // click on the Google 'settings bolt' + page.click("#gbg5"); + page.render("click_around_google-clicked_on_gbg5.png"); + + // click on 'more' + page.click("#gbztm"); + page.render("click_around_google-clicked_on_gbztm.png"); + } + phantom.exit(); +}); diff --git a/examples/injectme.js b/examples/injectme.js new file mode 100644 index 00000000..cc1af9c0 --- /dev/null +++ b/examples/injectme.js @@ -0,0 +1,25 @@ +// Use 'page.loadJsFile()' to load the script itself in the Page context + +if ( typeof(phantom) !== "undefined" ) { + var page = new WebPage(); + + // Route "console.log()" calls from within the Page context to the main Phantom context (i.e. current "this") + page.onConsoleMessage = function(msg) { + console.log(msg); + }; + + page.onAlert = function(msg) { + console.log(msg); + }; + + console.log("* Script running in the Phantom context."); + console.log("* Script will 'inject' itself in a page..."); + page.open("about:blank", function(status) { + if ( status === "success" ) { + console.log(page.loadJsFile("injectme.js") ? "... done injecting itself!" : "... fail! Check the $PWD?!"); + } + phantom.exit(); + }); +} else { + alert("* Script running in the Page context."); +} diff --git a/src/consts.h b/src/consts.h index 4e51d30f..86079ac5 100644 --- a/src/consts.h +++ b/src/consts.h @@ -36,4 +36,10 @@ #define PHANTOMJS_VERSION_PATCH 0 #define PHANTOMJS_VERSION_STRING "1.2.0" +#define JS_ELEMENT_CLICK "(function (el) { " \ + "var ev = document.createEvent('MouseEvents');" \ + "ev.initEvent(\"click\", true, true);" \ + "el.dispatchEvent(ev);" \ + "})(this);" + #endif // CONSTS_H diff --git a/src/webpage.cpp b/src/webpage.cpp index b0977669..058a648d 100644 --- a/src/webpage.cpp +++ b/src/webpage.cpp @@ -49,6 +49,8 @@ #include +#include "consts.h" + class CustomPage: public QWebPage { public: @@ -433,12 +435,6 @@ bool WebPage::renderPdf(const QString &fileName) #if QT_VERSION >= QT_VERSION_CHECK(4, 6, 0) -#define ELEMENT_CLICK "(function (el) { " \ - "var ev = document.createEvent('MouseEvents');" \ - "ev.initEvent('click', true, true);" \ - "el.dispatchEvent(ev);" \ - "})(this)" - void WebPage::uploadFile(const QString &selector, const QString &fileName) { QWebElement el = m_mainFrame->findFirstElement(selector); @@ -446,6 +442,30 @@ void WebPage::uploadFile(const QString &selector, const QString &fileName) return; m_webPage->m_uploadFile = fileName; - el.evaluateJavaScript(ELEMENT_CLICK); + el.evaluateJavaScript(JS_ELEMENT_CLICK); } + +void WebPage::click(const QString &selector) { + // Execute the equivalent of "querySelectorAll" + QWebElementCollection webElements = m_mainFrame->findAllElements(selector); + // Click on every element found by the previous selector (if any) + foreach ( QWebElement el, webElements ) { + el.evaluateJavaScript(JS_ELEMENT_CLICK); + } +} + #endif + +bool WebPage::loadJsFile(const QString &jsFilePath) { + if ( !jsFilePath.isEmpty()) { + QFile jsFile; + jsFile.setFileName(jsFilePath); + if ( jsFile.open(QFile::ReadOnly) ) { + // Execute JS code in the context of the document + m_mainFrame->evaluateJavaScript( QString::fromUtf8(jsFile.readAll()) ); + jsFile.close(); + return true; + } + } + return false; +} diff --git a/src/webpage.h b/src/webpage.h index c13328a9..3dd7e608 100644 --- a/src/webpage.h +++ b/src/webpage.h @@ -69,10 +69,12 @@ public slots: void openUrl(const QString &address, const QVariant &op, const QVariantMap &settings); QVariant evaluate(const QString &code); bool render(const QString &fileName); + bool loadJsFile(const QString &jsFilePath); // moc does not understand QT_VERSION_CHECK and hence the encoded hex #if QT_VERSION >= 0x040600 void uploadFile(const QString &selector, const QString &fileName); + void click(const QString &selector); #endif signals: From ce0577adff0f7a28f7b9ef386ec7ae5ea3f5e63a Mon Sep 17 00:00:00 2001 From: Ivan De Marino Date: Tue, 7 Jun 2011 23:22:41 +0100 Subject: [PATCH 02/13] "loadJsFile()" -> "injectJs" * According to Issue #32 (http://code.google.com/p/phantomjs/issues/detail?id=32) I added a "lookup logic" that searchs for the file following those steps: *# Search for file at given path (relative to PWD or absolute - no difference) *# Is file there? Inject it *# Is file not there? Try looking for it in "scriptLookupDir" *# Is file there? Inject it *# Is file not there? abort * "scriptLookupDir" is an extra property for WebPage, that, as by it's name, defines a place where to look to script to inject * Script can alter the scriptLookupDir, if they want * Updated "injectme.js" accordingly --- examples/injectme.js | 2 +- src/phantom.cpp | 3 +++ src/webpage.cpp | 23 +++++++++++++++++++++-- src/webpage.h | 8 ++++++-- 4 files changed, 31 insertions(+), 5 deletions(-) diff --git a/examples/injectme.js b/examples/injectme.js index cc1af9c0..8d93c9ce 100644 --- a/examples/injectme.js +++ b/examples/injectme.js @@ -16,7 +16,7 @@ if ( typeof(phantom) !== "undefined" ) { console.log("* Script will 'inject' itself in a page..."); page.open("about:blank", function(status) { if ( status === "success" ) { - console.log(page.loadJsFile("injectme.js") ? "... done injecting itself!" : "... fail! Check the $PWD?!"); + console.log(page.injectJs("injectme.js") ? "... done injecting itself!" : "... fail! Check the $PWD?!"); } phantom.exit(); }); diff --git a/src/phantom.cpp b/src/phantom.cpp index ea005fca..679ecebc 100644 --- a/src/phantom.cpp +++ b/src/phantom.cpp @@ -34,6 +34,8 @@ #include #include +#include +#include #include #include "consts.h" @@ -230,6 +232,7 @@ QObject *Phantom::createWebPage() WebPage *page = new WebPage(this); page->applySettings(m_defaultPageSettings); page->setNetworkAccessManager(m_netAccessMan); + page->setScriptLookupDir(QFileInfo(m_scriptFile).dir().absolutePath()); return page; } diff --git a/src/webpage.cpp b/src/webpage.cpp index 058a648d..b3ef00dd 100644 --- a/src/webpage.cpp +++ b/src/webpage.cpp @@ -160,6 +160,17 @@ void WebPage::setContent(const QString &content) m_mainFrame->setHtml(content); } + +QString WebPage::scriptLookupDir() const +{ + return m_scriptLookupDir; +} + +void WebPage::setScriptLookupDir(const QString &dirPath) +{ + m_scriptLookupDir = dirPath; +} + void WebPage::applySettings(const QVariantMap &def) { QWebSettings *opt = m_webPage->settings(); @@ -456,10 +467,18 @@ void WebPage::click(const QString &selector) { #endif -bool WebPage::loadJsFile(const QString &jsFilePath) { - if ( !jsFilePath.isEmpty()) { +bool WebPage::injectJs(const QString &jsFilePath) { + // Don't do anything if an empty string is passed + if (!jsFilePath.isEmpty()) { QFile jsFile; + + // Is file in the PWD? jsFile.setFileName(jsFilePath); + if (!jsFile.exists()) { + // File is not in the PWD. Is it in the lookup directory? + jsFile.setFileName( m_scriptLookupDir + '/' + jsFilePath ); + } + if ( jsFile.open(QFile::ReadOnly) ) { // Execute JS code in the context of the document m_mainFrame->evaluateJavaScript( QString::fromUtf8(jsFile.readAll()) ); diff --git a/src/webpage.h b/src/webpage.h index 3dd7e608..225a0420 100644 --- a/src/webpage.h +++ b/src/webpage.h @@ -42,6 +42,7 @@ class WebPage: public QObject { Q_OBJECT Q_PROPERTY(QString content READ content WRITE setContent) + Q_PROPERTY(QString scriptLookupDir READ scriptLookupDir WRITE setScriptLookupDir) Q_PROPERTY(QVariantMap viewportSize READ viewportSize WRITE setViewportSize) Q_PROPERTY(QVariantMap paperSize READ paperSize WRITE setPaperSize) Q_PROPERTY(QVariantMap clipRect READ clipRect WRITE setClipRect) @@ -55,6 +56,9 @@ public: QString content() const; void setContent(const QString &content); + QString scriptLookupDir() const; + void setScriptLookupDir(const QString &dirPath); + void setViewportSize(const QVariantMap &size); QVariantMap viewportSize() const; @@ -64,12 +68,11 @@ public: void setPaperSize(const QVariantMap &size); QVariantMap paperSize() const; - public slots: void openUrl(const QString &address, const QVariant &op, const QVariantMap &settings); QVariant evaluate(const QString &code); bool render(const QString &fileName); - bool loadJsFile(const QString &jsFilePath); + bool injectJs(const QString &jsFilePath); // moc does not understand QT_VERSION_CHECK and hence the encoded hex #if QT_VERSION >= 0x040600 @@ -92,6 +95,7 @@ private: QWebFrame *m_mainFrame; QRect m_clipRect; QVariantMap m_paperSize; // For PDF output via render() + QString m_scriptLookupDir; QImage renderImage(); bool renderPdf(const QString &fileName); From 60793e4c6b1bc08167de0e763039fbbc637bd780 Mon Sep 17 00:00:00 2001 From: Ivan De Marino Date: Tue, 7 Jun 2011 23:39:12 +0100 Subject: [PATCH 03/13] Renaming "page.handlers" to "page._handlers": more common for "private" stuff. --- src/bootstrap.js | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/bootstrap.js b/src/bootstrap.js index ff7aece9..38ef2ef1 100644 --- a/src/bootstrap.js +++ b/src/bootstrap.js @@ -7,36 +7,36 @@ window.WebPage = function() { page.settings = JSON.parse(JSON.stringify(phantom.defaultPageSettings)); // private, don't touch this - page.handlers = {}; + page._handlers = {}; page.__defineSetter__("onLoadStarted", function(f) { - if (this.handlers && typeof this.handlers.loadStarted === 'function') { + if (this._handlers && typeof this._handlers.loadStarted === 'function') { try { - this.loadStarted.disconnect(this.handlers.loadStarted); + this.loadStarted.disconnect(this._handlers.loadStarted); } catch (e) {} } - this.handlers.loadStarted = f; - this.loadStarted.connect(this.handlers.loadStarted); + this._handlers.loadStarted = f; + this.loadStarted.connect(this._handlers.loadStarted); }); page.__defineSetter__("onLoadFinished", function(f) { - if (this.handlers && typeof this.handlers.loadFinished === 'function') { + if (this._handlers && typeof this._handlers.loadFinished === 'function') { try { - this.loadFinished.disconnect(this.handlers.loadFinished); + this.loadFinished.disconnect(this._handlers.loadFinished); } catch (e) {} } - this.handlers.loadFinished = f; - this.loadFinished.connect(this.handlers.loadFinished); + this._handlers.loadFinished = f; + this.loadFinished.connect(this._handlers.loadFinished); }); page.__defineSetter__("onResourceRequested", function(f) { - if (this.handlers && typeof this.handlers.resourceRequested === 'function') { + if (this._handlers && typeof this._handlers.resourceRequested === 'function') { try { - this.resourceRequested.disconnect(this.handlers.resourceRequested); + this.resourceRequested.disconnect(this._handlers.resourceRequested); } catch (e) {} } - this.handlers.resourceRequested = f; - this.resourceRequested.connect(this.handlers.resourceRequested); + this._handlers.resourceRequested = f; + this.resourceRequested.connect(this._handlers.resourceRequested); }); page.onAlert = function (msg) {}; From 7be25c9a1396510387583fda456b8ce0285da912 Mon Sep 17 00:00:00 2001 From: Ivan De Marino Date: Thu, 9 Jun 2011 16:11:39 +0100 Subject: [PATCH 04/13] Added "includeJs()" to "page". * It includes a script in the page * It uses a callback to ensure any code dependent on the include runs afterwards * It uses the signal "javaScriptAlertSent" to do the trick (is there another way to be notified of the "onLoad" event from outside the page context?) * It uses a "private" slot "_appendScriptElement" to pass the script url in the page context (is there a better way?) --- examples/phantomwebintro.js | 19 +++++++++++++++++++ src/bootstrap.js | 17 +++++++++++++++++ src/consts.h | 5 +++++ src/webpage.cpp | 4 ++++ src/webpage.h | 1 + 5 files changed, 46 insertions(+) create mode 100644 examples/phantomwebintro.js diff --git a/examples/phantomwebintro.js b/examples/phantomwebintro.js new file mode 100644 index 00000000..062a51dd --- /dev/null +++ b/examples/phantomwebintro.js @@ -0,0 +1,19 @@ +// Read the Phantom webpage '#intro' element text using jQuery and "includeJs" + +var page = new WebPage(); + +page.onConsoleMessage = function(msg) { + console.log(msg); +}; + +page.open("http://www.phantomjs.org", function(status) { + if ( status === "success" ) { + page.includeJs("http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js", function() { + page.evaluate(function() { + console.log("$(\"#intro\").text() -> " + $("#intro").text()); + }); + phantom.exit(); + }); + } +}); + diff --git a/src/bootstrap.js b/src/bootstrap.js index e9126dca..daa5f46d 100644 --- a/src/bootstrap.js +++ b/src/bootstrap.js @@ -83,5 +83,22 @@ window.WebPage = function() { throw "Wrong use of WebPage#open"; }; + page.includeJs = function(scriptUrl, onScriptLoaded) { + // Register temporary signal handler for 'alert()' + this.javaScriptAlertSent.connect(function(msgFromAlert) { + if ( msgFromAlert === scriptUrl ) { + // Resource loaded, time to fire the callback + onScriptLoaded(scriptUrl); + // And disconnect the signal handler + try { + this.javaScriptAlertSent.disconnect(this); + } catch (e) {} + } + }); + + // Append the script tag to the body + this._appendScriptElement(scriptUrl); + }; + return page; } diff --git a/src/consts.h b/src/consts.h index 86079ac5..6708791c 100644 --- a/src/consts.h +++ b/src/consts.h @@ -42,4 +42,9 @@ "el.dispatchEvent(ev);" \ "})(this);" +#define JS_APPEND_SCRIPT_ELEMENT "var el = document.createElement('script');" \ + "el.onload = function() { alert('%1'); };" \ + "el.src = '%1';" \ + "document.body.appendChild(el);" + #endif // CONSTS_H diff --git a/src/webpage.cpp b/src/webpage.cpp index 3041631d..13979919 100644 --- a/src/webpage.cpp +++ b/src/webpage.cpp @@ -514,3 +514,7 @@ bool WebPage::injectJs(const QString &jsFilePath) { } return false; } + +void WebPage::_appendScriptElement(const QString &scriptUrl) { + m_mainFrame->evaluateJavaScript( QString(JS_APPEND_SCRIPT_ELEMENT).arg(scriptUrl) ); +} diff --git a/src/webpage.h b/src/webpage.h index d1714ad0..24be48d4 100644 --- a/src/webpage.h +++ b/src/webpage.h @@ -73,6 +73,7 @@ public slots: QVariant evaluate(const QString &code); bool render(const QString &fileName); bool injectJs(const QString &jsFilePath); + void _appendScriptElement(const QString &scriptUrl); // moc does not understand QT_VERSION_CHECK and hence the encoded hex #if QT_VERSION >= 0x040600 From 7a4ea47c1dafe027fbe4ecc0c7c18fe24ec89206 Mon Sep 17 00:00:00 2001 From: Ivan De Marino Date: Thu, 9 Jun 2011 18:07:37 +0100 Subject: [PATCH 05/13] Normalie user-provided script path --- src/webpage.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/webpage.cpp b/src/webpage.cpp index 13979919..addc4cfe 100644 --- a/src/webpage.cpp +++ b/src/webpage.cpp @@ -498,6 +498,8 @@ bool WebPage::injectJs(const QString &jsFilePath) { if (!jsFilePath.isEmpty()) { QFile jsFile; + // Normalise User-provided path + jsFilePath = QDir::fromNativeSeparators(jsFilePath); // Is file in the PWD? jsFile.setFileName(jsFilePath); if (!jsFile.exists()) { From bf3aa06e1943cff58509210e0eeeb7d0fbd875be Mon Sep 17 00:00:00 2001 From: Ivan De Marino Date: Fri, 10 Jun 2011 16:50:49 +0100 Subject: [PATCH 06/13] More work on "injectJs" * "injectJs()" now supports ".coffee" input * "injectJs()" is now available for the "phantom" object as well * CSConverter is now a singleton embedded in the Utils static class * The code used by "injectJs()" is now centralised in the Utils static class --- src/consts.h | 1 + src/csconverter.cpp | 3 +-- src/main.cpp | 2 ++ src/phantom.cpp | 32 +++++++------------------------ src/phantom.h | 1 + src/utils.cpp | 46 +++++++++++++++++++++++++++++++++++++++++++++ src/utils.h | 5 +++++ src/webpage.cpp | 24 +++-------------------- 8 files changed, 66 insertions(+), 48 deletions(-) diff --git a/src/consts.h b/src/consts.h index 6708791c..3d2cfd2e 100644 --- a/src/consts.h +++ b/src/consts.h @@ -35,6 +35,7 @@ #define PHANTOMJS_VERSION_MINOR 2 #define PHANTOMJS_VERSION_PATCH 0 #define PHANTOMJS_VERSION_STRING "1.2.0" +#define COFFEE_SCRIPT_EXTENSION ".coffee" #define JS_ELEMENT_CLICK "(function (el) { " \ "var ev = document.createEvent('MouseEvents');" \ diff --git a/src/csconverter.cpp b/src/csconverter.cpp index ab84e612..68983392 100644 --- a/src/csconverter.cpp +++ b/src/csconverter.cpp @@ -52,8 +52,7 @@ CSConverter::CSConverter(QObject *parent) QString CSConverter::convert(const QString &script) { setProperty("source", script); - QWebFrame *frame = m_webPage.mainFrame(); - QVariant result = frame->evaluateJavaScript("this.CoffeeScript.compile(converter.source)"); + QVariant result = m_webPage.mainFrame()->evaluateJavaScript("this.CoffeeScript.compile(converter.source)"); if (result.type() == QVariant::String) return result.toString(); return QString(); diff --git a/src/main.cpp b/src/main.cpp index f2ec00f2..48333eae 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -58,6 +58,8 @@ int main(int argc, char** argv) Phantom phantom; if (phantom.execute()) { app.exec(); + } else { + exit(EXIT_FAILURE); } return phantom.returnValue(); } diff --git a/src/phantom.cpp b/src/phantom.cpp index 64a33984..5dcc2c42 100644 --- a/src/phantom.cpp +++ b/src/phantom.cpp @@ -186,31 +186,9 @@ QVariantMap Phantom::defaultPageSettings() const bool Phantom::execute() { - if (m_scriptFile.isEmpty()) - return false; - - QFile file; - file.setFileName(m_scriptFile); - if (!file.open(QFile::ReadOnly)) { - std::cerr << "Can't open '" << qPrintable(m_scriptFile) << "'" << std::endl << std::endl; - exit(1); - return false; - } - m_script = QString::fromUtf8(file.readAll()); - file.close(); - - if (m_scriptFile.endsWith(".coffee")) { - if (!m_converter) - m_converter = new CSConverter(this); - m_script = m_converter->convert(m_script); - } - - if (m_script.startsWith("#!")) { - m_script.prepend("//"); - } - - m_page->mainFrame()->evaluateJavaScript(m_script); - return !m_terminated; + return !m_scriptFile.isEmpty() && //< script filename provided + Utils::injectJsInFrame(m_scriptFile, QDir::currentPath(), m_page->mainFrame()) && //< script injected + !m_terminated; //< not terminated } int Phantom::returnValue() const @@ -243,6 +221,10 @@ void Phantom::exit(int code) QApplication::instance()->exit(code); } +bool Phantom::injectJs(const QString &jsFilePath) { + return Utils::injectJsInFrame(jsFilePath, QDir::currentPath(), m_page->mainFrame()); +} + void Phantom::printConsoleMessage(const QString &msg) { std::cout << qPrintable(msg) << std::endl; diff --git a/src/phantom.h b/src/phantom.h index 07f68225..3393a80a 100644 --- a/src/phantom.h +++ b/src/phantom.h @@ -58,6 +58,7 @@ public: public slots: QObject *createWebPage(); + bool injectJs(const QString &jsFilePath); void exit(int code = 0); private slots: diff --git a/src/utils.cpp b/src/utils.cpp index bde5a419..5920c363 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -31,7 +31,9 @@ #include #include #include +#include +#include "consts.h" #include "utils.h" // public: @@ -67,6 +69,50 @@ void Utils::messageHandler(QtMsgType type, const char *msg) } } +QString Utils::coffee2js(const QString &script) +{ + // We need only one instance of the CSConverter to survive for the whole life of PhantomJS + static CSConverter *coffeeScriptConverter = NULL; + if ( !coffeeScriptConverter ) { + coffeeScriptConverter = new CSConverter(); + } + + return coffeeScriptConverter->convert(script); +} + +bool Utils::injectJsInFrame(const QString &jsFilePath, const QString &scriptLookupDir, QWebFrame *targetFrame) +{ + // Don't do anything if an empty string is passed + if (!jsFilePath.isEmpty()) { + QFile jsFile; + + // Is file in the PWD? + jsFile.setFileName(QDir::fromNativeSeparators(jsFilePath)); //< Normalise User-provided path + if (!jsFile.exists()) { + // File is not in the PWD. Is it in the lookup directory? + jsFile.setFileName( scriptLookupDir + '/' + QDir::fromNativeSeparators(jsFilePath) ); + } + + if ( jsFile.open(QFile::ReadOnly) ) { + QString scriptBody = QString::fromUtf8(jsFile.readAll()); + // Remove CLI script heading + if (scriptBody.startsWith("#!")) { + scriptBody.prepend("//"); + } + + // Execute JS code in the context of the document + targetFrame->evaluateJavaScript(jsFile.fileName().endsWith(COFFEE_SCRIPT_EXTENSION) ? + Utils::coffee2js(scriptBody) : //< convert from Coffee Script + scriptBody); + jsFile.close(); + return true; + } else { + std::cerr << "Can't open '" << qPrintable(jsFilePath) << "'" << std::endl << std::endl; + } + } + return false; +} + // private: Utils::Utils() { diff --git a/src/utils.h b/src/utils.h index 4ff9a5cf..65548fde 100644 --- a/src/utils.h +++ b/src/utils.h @@ -31,6 +31,9 @@ #define UTILS_H #include +#include + +#include "csconverter.h" /** * Aggregate common utility functions. @@ -42,6 +45,8 @@ class Utils public: static void showUsage(); static void messageHandler(QtMsgType type, const char *msg); + static QString coffee2js(const QString &script); + static bool injectJsInFrame(const QString &jsFilePath, const QString &scriptLookupDir, QWebFrame *targetFrame); private: Utils(); //< This class shouldn't be instantiated diff --git a/src/webpage.cpp b/src/webpage.cpp index addc4cfe..553134b8 100644 --- a/src/webpage.cpp +++ b/src/webpage.cpp @@ -43,6 +43,8 @@ #include #include +#include "utils.h" + #if QT_VERSION >= QT_VERSION_CHECK(4, 6, 0) #include #endif @@ -494,27 +496,7 @@ void WebPage::click(const QString &selector) { #endif bool WebPage::injectJs(const QString &jsFilePath) { - // Don't do anything if an empty string is passed - if (!jsFilePath.isEmpty()) { - QFile jsFile; - - // Normalise User-provided path - jsFilePath = QDir::fromNativeSeparators(jsFilePath); - // Is file in the PWD? - jsFile.setFileName(jsFilePath); - if (!jsFile.exists()) { - // File is not in the PWD. Is it in the lookup directory? - jsFile.setFileName( m_scriptLookupDir + '/' + jsFilePath ); - } - - if ( jsFile.open(QFile::ReadOnly) ) { - // Execute JS code in the context of the document - m_mainFrame->evaluateJavaScript( QString::fromUtf8(jsFile.readAll()) ); - jsFile.close(); - return true; - } - } - return false; + return Utils::injectJsInFrame(jsFilePath, m_scriptLookupDir, m_mainFrame); } void WebPage::_appendScriptElement(const QString &scriptUrl) { From 52677f4f0174ad8479c2dafb41e83b1dfe58c8e1 Mon Sep 17 00:00:00 2001 From: Ivan De Marino Date: Fri, 10 Jun 2011 16:53:11 +0100 Subject: [PATCH 07/13] Removing "page.click()" for now. There is need for a discussion to decide how to do this. --- examples/click_around_google.js | 20 -------------------- src/webpage.cpp | 9 --------- src/webpage.h | 1 - 3 files changed, 30 deletions(-) delete mode 100644 examples/click_around_google.js diff --git a/examples/click_around_google.js b/examples/click_around_google.js deleted file mode 100644 index a1fabd1a..00000000 --- a/examples/click_around_google.js +++ /dev/null @@ -1,20 +0,0 @@ -// test the "page.click(QUERY SELECTOR)" api -// NOTE: This test will need to be updated if Google changes it's DOM :-P - -var page = new WebPage(); - -page.open("http://www.google.com/", function(status) { - if ( status === "success" ) { - // render before doing anything - page.render("click_around_google-before.png"); - - // click on the Google 'settings bolt' - page.click("#gbg5"); - page.render("click_around_google-clicked_on_gbg5.png"); - - // click on 'more' - page.click("#gbztm"); - page.render("click_around_google-clicked_on_gbztm.png"); - } - phantom.exit(); -}); diff --git a/src/webpage.cpp b/src/webpage.cpp index 553134b8..ebccafa4 100644 --- a/src/webpage.cpp +++ b/src/webpage.cpp @@ -484,15 +484,6 @@ void WebPage::uploadFile(const QString &selector, const QString &fileName) el.evaluateJavaScript(JS_ELEMENT_CLICK); } -void WebPage::click(const QString &selector) { - // Execute the equivalent of "querySelectorAll" - QWebElementCollection webElements = m_mainFrame->findAllElements(selector); - // Click on every element found by the previous selector (if any) - foreach ( QWebElement el, webElements ) { - el.evaluateJavaScript(JS_ELEMENT_CLICK); - } -} - #endif bool WebPage::injectJs(const QString &jsFilePath) { diff --git a/src/webpage.h b/src/webpage.h index 24be48d4..19eec472 100644 --- a/src/webpage.h +++ b/src/webpage.h @@ -78,7 +78,6 @@ public slots: // moc does not understand QT_VERSION_CHECK and hence the encoded hex #if QT_VERSION >= 0x040600 void uploadFile(const QString &selector, const QString &fileName); - void click(const QString &selector); #endif signals: From a0f8f2491d2f40e6f21bffcb261507371dbb56a5 Mon Sep 17 00:00:00 2001 From: Ivan De Marino Date: Tue, 7 Jun 2011 23:22:41 +0100 Subject: [PATCH 08/13] "loadJsFile()" -> "injectJs" * According to Issue #32 (http://code.google.com/p/phantomjs/issues/detail?id=32) I added a "lookup logic" that searchs for the file following those steps: *# Search for file at given path (relative to PWD or absolute - no difference) *# Is file there? Inject it *# Is file not there? Try looking for it in "scriptLookupDir" *# Is file there? Inject it *# Is file not there? abort * "scriptLookupDir" is an extra property for WebPage, that, as by it's name, defines a place where to look to script to inject * Script can alter the scriptLookupDir, if they want * Updated "injectme.js" accordingly --- examples/injectme.js | 2 +- src/phantom.cpp | 3 +++ src/webpage.cpp | 23 +++++++++++++++++++++-- src/webpage.h | 8 ++++++-- 4 files changed, 31 insertions(+), 5 deletions(-) diff --git a/examples/injectme.js b/examples/injectme.js index cc1af9c0..8d93c9ce 100644 --- a/examples/injectme.js +++ b/examples/injectme.js @@ -16,7 +16,7 @@ if ( typeof(phantom) !== "undefined" ) { console.log("* Script will 'inject' itself in a page..."); page.open("about:blank", function(status) { if ( status === "success" ) { - console.log(page.loadJsFile("injectme.js") ? "... done injecting itself!" : "... fail! Check the $PWD?!"); + console.log(page.injectJs("injectme.js") ? "... done injecting itself!" : "... fail! Check the $PWD?!"); } phantom.exit(); }); diff --git a/src/phantom.cpp b/src/phantom.cpp index e486f741..64a33984 100644 --- a/src/phantom.cpp +++ b/src/phantom.cpp @@ -34,6 +34,8 @@ #include #include +#include +#include #include #include "consts.h" @@ -230,6 +232,7 @@ QObject *Phantom::createWebPage() WebPage *page = new WebPage(this); page->applySettings(m_defaultPageSettings); page->setNetworkAccessManager(m_netAccessMan); + page->setScriptLookupDir(QFileInfo(m_scriptFile).dir().absolutePath()); return page; } diff --git a/src/webpage.cpp b/src/webpage.cpp index 896e972e..3041631d 100644 --- a/src/webpage.cpp +++ b/src/webpage.cpp @@ -162,6 +162,17 @@ void WebPage::setContent(const QString &content) m_mainFrame->setHtml(content); } + +QString WebPage::scriptLookupDir() const +{ + return m_scriptLookupDir; +} + +void WebPage::setScriptLookupDir(const QString &dirPath) +{ + m_scriptLookupDir = dirPath; +} + void WebPage::applySettings(const QVariantMap &def) { QWebSettings *opt = m_webPage->settings(); @@ -482,10 +493,18 @@ void WebPage::click(const QString &selector) { #endif -bool WebPage::loadJsFile(const QString &jsFilePath) { - if ( !jsFilePath.isEmpty()) { +bool WebPage::injectJs(const QString &jsFilePath) { + // Don't do anything if an empty string is passed + if (!jsFilePath.isEmpty()) { QFile jsFile; + + // Is file in the PWD? jsFile.setFileName(jsFilePath); + if (!jsFile.exists()) { + // File is not in the PWD. Is it in the lookup directory? + jsFile.setFileName( m_scriptLookupDir + '/' + jsFilePath ); + } + if ( jsFile.open(QFile::ReadOnly) ) { // Execute JS code in the context of the document m_mainFrame->evaluateJavaScript( QString::fromUtf8(jsFile.readAll()) ); diff --git a/src/webpage.h b/src/webpage.h index f278f5d5..d1714ad0 100644 --- a/src/webpage.h +++ b/src/webpage.h @@ -42,6 +42,7 @@ class WebPage: public QObject { Q_OBJECT Q_PROPERTY(QString content READ content WRITE setContent) + Q_PROPERTY(QString scriptLookupDir READ scriptLookupDir WRITE setScriptLookupDir) Q_PROPERTY(QVariantMap viewportSize READ viewportSize WRITE setViewportSize) Q_PROPERTY(QVariantMap paperSize READ paperSize WRITE setPaperSize) Q_PROPERTY(QVariantMap clipRect READ clipRect WRITE setClipRect) @@ -55,6 +56,9 @@ public: QString content() const; void setContent(const QString &content); + QString scriptLookupDir() const; + void setScriptLookupDir(const QString &dirPath); + void setViewportSize(const QVariantMap &size); QVariantMap viewportSize() const; @@ -64,12 +68,11 @@ public: void setPaperSize(const QVariantMap &size); QVariantMap paperSize() const; - public slots: void openUrl(const QString &address, const QVariant &op, const QVariantMap &settings); QVariant evaluate(const QString &code); bool render(const QString &fileName); - bool loadJsFile(const QString &jsFilePath); + bool injectJs(const QString &jsFilePath); // moc does not understand QT_VERSION_CHECK and hence the encoded hex #if QT_VERSION >= 0x040600 @@ -93,6 +96,7 @@ private: QWebFrame *m_mainFrame; QRect m_clipRect; QVariantMap m_paperSize; // For PDF output via render() + QString m_scriptLookupDir; QImage renderImage(); bool renderPdf(const QString &fileName); From 11c8322718c6b4fdac395dc189480bf4f114528f Mon Sep 17 00:00:00 2001 From: Ivan De Marino Date: Tue, 7 Jun 2011 23:39:12 +0100 Subject: [PATCH 09/13] Renaming "page.handlers" to "page._handlers": more common for "private" stuff. --- src/bootstrap.js | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/bootstrap.js b/src/bootstrap.js index 347a9c42..e9126dca 100644 --- a/src/bootstrap.js +++ b/src/bootstrap.js @@ -7,36 +7,36 @@ window.WebPage = function() { page.settings = JSON.parse(JSON.stringify(phantom.defaultPageSettings)); // private, don't touch this - page.handlers = {}; + page._handlers = {}; page.__defineSetter__("onLoadStarted", function(f) { - if (this.handlers && typeof this.handlers.loadStarted === 'function') { + if (this._handlers && typeof this._handlers.loadStarted === 'function') { try { - this.loadStarted.disconnect(this.handlers.loadStarted); + this.loadStarted.disconnect(this._handlers.loadStarted); } catch (e) {} } - this.handlers.loadStarted = f; - this.loadStarted.connect(this.handlers.loadStarted); + this._handlers.loadStarted = f; + this.loadStarted.connect(this._handlers.loadStarted); }); page.__defineSetter__("onLoadFinished", function(f) { - if (this.handlers && typeof this.handlers.loadFinished === 'function') { + if (this._handlers && typeof this._handlers.loadFinished === 'function') { try { - this.loadFinished.disconnect(this.handlers.loadFinished); + this.loadFinished.disconnect(this._handlers.loadFinished); } catch (e) {} } - this.handlers.loadFinished = f; - this.loadFinished.connect(this.handlers.loadFinished); + this._handlers.loadFinished = f; + this.loadFinished.connect(this._handlers.loadFinished); }); page.__defineSetter__("onResourceRequested", function(f) { - if (this.handlers && typeof this.handlers.resourceRequested === 'function') { + if (this._handlers && typeof this._handlers.resourceRequested === 'function') { try { - this.resourceRequested.disconnect(this.handlers.resourceRequested); + this.resourceRequested.disconnect(this._handlers.resourceRequested); } catch (e) {} } - this.handlers.resourceRequested = f; - this.resourceRequested.connect(this.handlers.resourceRequested); + this._handlers.resourceRequested = f; + this.resourceRequested.connect(this._handlers.resourceRequested); }); page.__defineSetter__("onResourceReceived", function(f) { From 75403737c4a7c12eaf3573eaa9fca7bbce5be701 Mon Sep 17 00:00:00 2001 From: Ivan De Marino Date: Thu, 9 Jun 2011 16:11:39 +0100 Subject: [PATCH 10/13] Added "includeJs()" to "page". * It includes a script in the page * It uses a callback to ensure any code dependent on the include runs afterwards * It uses the signal "javaScriptAlertSent" to do the trick (is there another way to be notified of the "onLoad" event from outside the page context?) * It uses a "private" slot "_appendScriptElement" to pass the script url in the page context (is there a better way?) --- examples/phantomwebintro.js | 19 +++++++++++++++++++ src/bootstrap.js | 17 +++++++++++++++++ src/consts.h | 5 +++++ src/webpage.cpp | 4 ++++ src/webpage.h | 1 + 5 files changed, 46 insertions(+) create mode 100644 examples/phantomwebintro.js diff --git a/examples/phantomwebintro.js b/examples/phantomwebintro.js new file mode 100644 index 00000000..062a51dd --- /dev/null +++ b/examples/phantomwebintro.js @@ -0,0 +1,19 @@ +// Read the Phantom webpage '#intro' element text using jQuery and "includeJs" + +var page = new WebPage(); + +page.onConsoleMessage = function(msg) { + console.log(msg); +}; + +page.open("http://www.phantomjs.org", function(status) { + if ( status === "success" ) { + page.includeJs("http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js", function() { + page.evaluate(function() { + console.log("$(\"#intro\").text() -> " + $("#intro").text()); + }); + phantom.exit(); + }); + } +}); + diff --git a/src/bootstrap.js b/src/bootstrap.js index e9126dca..daa5f46d 100644 --- a/src/bootstrap.js +++ b/src/bootstrap.js @@ -83,5 +83,22 @@ window.WebPage = function() { throw "Wrong use of WebPage#open"; }; + page.includeJs = function(scriptUrl, onScriptLoaded) { + // Register temporary signal handler for 'alert()' + this.javaScriptAlertSent.connect(function(msgFromAlert) { + if ( msgFromAlert === scriptUrl ) { + // Resource loaded, time to fire the callback + onScriptLoaded(scriptUrl); + // And disconnect the signal handler + try { + this.javaScriptAlertSent.disconnect(this); + } catch (e) {} + } + }); + + // Append the script tag to the body + this._appendScriptElement(scriptUrl); + }; + return page; } diff --git a/src/consts.h b/src/consts.h index 86079ac5..6708791c 100644 --- a/src/consts.h +++ b/src/consts.h @@ -42,4 +42,9 @@ "el.dispatchEvent(ev);" \ "})(this);" +#define JS_APPEND_SCRIPT_ELEMENT "var el = document.createElement('script');" \ + "el.onload = function() { alert('%1'); };" \ + "el.src = '%1';" \ + "document.body.appendChild(el);" + #endif // CONSTS_H diff --git a/src/webpage.cpp b/src/webpage.cpp index 3041631d..13979919 100644 --- a/src/webpage.cpp +++ b/src/webpage.cpp @@ -514,3 +514,7 @@ bool WebPage::injectJs(const QString &jsFilePath) { } return false; } + +void WebPage::_appendScriptElement(const QString &scriptUrl) { + m_mainFrame->evaluateJavaScript( QString(JS_APPEND_SCRIPT_ELEMENT).arg(scriptUrl) ); +} diff --git a/src/webpage.h b/src/webpage.h index d1714ad0..24be48d4 100644 --- a/src/webpage.h +++ b/src/webpage.h @@ -73,6 +73,7 @@ public slots: QVariant evaluate(const QString &code); bool render(const QString &fileName); bool injectJs(const QString &jsFilePath); + void _appendScriptElement(const QString &scriptUrl); // moc does not understand QT_VERSION_CHECK and hence the encoded hex #if QT_VERSION >= 0x040600 From cc45aa7f38c0bc23d41c1b4cbc4947065b0a6e7d Mon Sep 17 00:00:00 2001 From: Ivan De Marino Date: Thu, 9 Jun 2011 18:07:37 +0100 Subject: [PATCH 11/13] Normalie user-provided script path --- src/webpage.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/webpage.cpp b/src/webpage.cpp index 13979919..addc4cfe 100644 --- a/src/webpage.cpp +++ b/src/webpage.cpp @@ -498,6 +498,8 @@ bool WebPage::injectJs(const QString &jsFilePath) { if (!jsFilePath.isEmpty()) { QFile jsFile; + // Normalise User-provided path + jsFilePath = QDir::fromNativeSeparators(jsFilePath); // Is file in the PWD? jsFile.setFileName(jsFilePath); if (!jsFile.exists()) { From bd18d7c838ade10d11aaeb89e7b5a38e708ea06e Mon Sep 17 00:00:00 2001 From: Ivan De Marino Date: Fri, 10 Jun 2011 16:50:49 +0100 Subject: [PATCH 12/13] More work on "injectJs" * "injectJs()" now supports ".coffee" input * "injectJs()" is now available for the "phantom" object as well * CSConverter is now a singleton embedded in the Utils static class * The code used by "injectJs()" is now centralised in the Utils static class --- src/consts.h | 1 + src/csconverter.cpp | 3 +-- src/main.cpp | 2 ++ src/phantom.cpp | 32 +++++++------------------------ src/phantom.h | 1 + src/utils.cpp | 46 +++++++++++++++++++++++++++++++++++++++++++++ src/utils.h | 5 +++++ src/webpage.cpp | 24 +++-------------------- 8 files changed, 66 insertions(+), 48 deletions(-) diff --git a/src/consts.h b/src/consts.h index 6708791c..3d2cfd2e 100644 --- a/src/consts.h +++ b/src/consts.h @@ -35,6 +35,7 @@ #define PHANTOMJS_VERSION_MINOR 2 #define PHANTOMJS_VERSION_PATCH 0 #define PHANTOMJS_VERSION_STRING "1.2.0" +#define COFFEE_SCRIPT_EXTENSION ".coffee" #define JS_ELEMENT_CLICK "(function (el) { " \ "var ev = document.createEvent('MouseEvents');" \ diff --git a/src/csconverter.cpp b/src/csconverter.cpp index ab84e612..68983392 100644 --- a/src/csconverter.cpp +++ b/src/csconverter.cpp @@ -52,8 +52,7 @@ CSConverter::CSConverter(QObject *parent) QString CSConverter::convert(const QString &script) { setProperty("source", script); - QWebFrame *frame = m_webPage.mainFrame(); - QVariant result = frame->evaluateJavaScript("this.CoffeeScript.compile(converter.source)"); + QVariant result = m_webPage.mainFrame()->evaluateJavaScript("this.CoffeeScript.compile(converter.source)"); if (result.type() == QVariant::String) return result.toString(); return QString(); diff --git a/src/main.cpp b/src/main.cpp index f2ec00f2..48333eae 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -58,6 +58,8 @@ int main(int argc, char** argv) Phantom phantom; if (phantom.execute()) { app.exec(); + } else { + exit(EXIT_FAILURE); } return phantom.returnValue(); } diff --git a/src/phantom.cpp b/src/phantom.cpp index 64a33984..5dcc2c42 100644 --- a/src/phantom.cpp +++ b/src/phantom.cpp @@ -186,31 +186,9 @@ QVariantMap Phantom::defaultPageSettings() const bool Phantom::execute() { - if (m_scriptFile.isEmpty()) - return false; - - QFile file; - file.setFileName(m_scriptFile); - if (!file.open(QFile::ReadOnly)) { - std::cerr << "Can't open '" << qPrintable(m_scriptFile) << "'" << std::endl << std::endl; - exit(1); - return false; - } - m_script = QString::fromUtf8(file.readAll()); - file.close(); - - if (m_scriptFile.endsWith(".coffee")) { - if (!m_converter) - m_converter = new CSConverter(this); - m_script = m_converter->convert(m_script); - } - - if (m_script.startsWith("#!")) { - m_script.prepend("//"); - } - - m_page->mainFrame()->evaluateJavaScript(m_script); - return !m_terminated; + return !m_scriptFile.isEmpty() && //< script filename provided + Utils::injectJsInFrame(m_scriptFile, QDir::currentPath(), m_page->mainFrame()) && //< script injected + !m_terminated; //< not terminated } int Phantom::returnValue() const @@ -243,6 +221,10 @@ void Phantom::exit(int code) QApplication::instance()->exit(code); } +bool Phantom::injectJs(const QString &jsFilePath) { + return Utils::injectJsInFrame(jsFilePath, QDir::currentPath(), m_page->mainFrame()); +} + void Phantom::printConsoleMessage(const QString &msg) { std::cout << qPrintable(msg) << std::endl; diff --git a/src/phantom.h b/src/phantom.h index 07f68225..3393a80a 100644 --- a/src/phantom.h +++ b/src/phantom.h @@ -58,6 +58,7 @@ public: public slots: QObject *createWebPage(); + bool injectJs(const QString &jsFilePath); void exit(int code = 0); private slots: diff --git a/src/utils.cpp b/src/utils.cpp index bde5a419..5920c363 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -31,7 +31,9 @@ #include #include #include +#include +#include "consts.h" #include "utils.h" // public: @@ -67,6 +69,50 @@ void Utils::messageHandler(QtMsgType type, const char *msg) } } +QString Utils::coffee2js(const QString &script) +{ + // We need only one instance of the CSConverter to survive for the whole life of PhantomJS + static CSConverter *coffeeScriptConverter = NULL; + if ( !coffeeScriptConverter ) { + coffeeScriptConverter = new CSConverter(); + } + + return coffeeScriptConverter->convert(script); +} + +bool Utils::injectJsInFrame(const QString &jsFilePath, const QString &scriptLookupDir, QWebFrame *targetFrame) +{ + // Don't do anything if an empty string is passed + if (!jsFilePath.isEmpty()) { + QFile jsFile; + + // Is file in the PWD? + jsFile.setFileName(QDir::fromNativeSeparators(jsFilePath)); //< Normalise User-provided path + if (!jsFile.exists()) { + // File is not in the PWD. Is it in the lookup directory? + jsFile.setFileName( scriptLookupDir + '/' + QDir::fromNativeSeparators(jsFilePath) ); + } + + if ( jsFile.open(QFile::ReadOnly) ) { + QString scriptBody = QString::fromUtf8(jsFile.readAll()); + // Remove CLI script heading + if (scriptBody.startsWith("#!")) { + scriptBody.prepend("//"); + } + + // Execute JS code in the context of the document + targetFrame->evaluateJavaScript(jsFile.fileName().endsWith(COFFEE_SCRIPT_EXTENSION) ? + Utils::coffee2js(scriptBody) : //< convert from Coffee Script + scriptBody); + jsFile.close(); + return true; + } else { + std::cerr << "Can't open '" << qPrintable(jsFilePath) << "'" << std::endl << std::endl; + } + } + return false; +} + // private: Utils::Utils() { diff --git a/src/utils.h b/src/utils.h index 4ff9a5cf..65548fde 100644 --- a/src/utils.h +++ b/src/utils.h @@ -31,6 +31,9 @@ #define UTILS_H #include +#include + +#include "csconverter.h" /** * Aggregate common utility functions. @@ -42,6 +45,8 @@ class Utils public: static void showUsage(); static void messageHandler(QtMsgType type, const char *msg); + static QString coffee2js(const QString &script); + static bool injectJsInFrame(const QString &jsFilePath, const QString &scriptLookupDir, QWebFrame *targetFrame); private: Utils(); //< This class shouldn't be instantiated diff --git a/src/webpage.cpp b/src/webpage.cpp index addc4cfe..553134b8 100644 --- a/src/webpage.cpp +++ b/src/webpage.cpp @@ -43,6 +43,8 @@ #include #include +#include "utils.h" + #if QT_VERSION >= QT_VERSION_CHECK(4, 6, 0) #include #endif @@ -494,27 +496,7 @@ void WebPage::click(const QString &selector) { #endif bool WebPage::injectJs(const QString &jsFilePath) { - // Don't do anything if an empty string is passed - if (!jsFilePath.isEmpty()) { - QFile jsFile; - - // Normalise User-provided path - jsFilePath = QDir::fromNativeSeparators(jsFilePath); - // Is file in the PWD? - jsFile.setFileName(jsFilePath); - if (!jsFile.exists()) { - // File is not in the PWD. Is it in the lookup directory? - jsFile.setFileName( m_scriptLookupDir + '/' + jsFilePath ); - } - - if ( jsFile.open(QFile::ReadOnly) ) { - // Execute JS code in the context of the document - m_mainFrame->evaluateJavaScript( QString::fromUtf8(jsFile.readAll()) ); - jsFile.close(); - return true; - } - } - return false; + return Utils::injectJsInFrame(jsFilePath, m_scriptLookupDir, m_mainFrame); } void WebPage::_appendScriptElement(const QString &scriptUrl) { From 22ee075cc24bbd12b2d53eb91af3c550c097a5dd Mon Sep 17 00:00:00 2001 From: Ivan De Marino Date: Fri, 10 Jun 2011 16:53:11 +0100 Subject: [PATCH 13/13] Removing "page.click()" for now. There is need for a discussion to decide how to do this. --- examples/click_around_google.js | 20 -------------------- src/webpage.cpp | 9 --------- src/webpage.h | 1 - 3 files changed, 30 deletions(-) delete mode 100644 examples/click_around_google.js diff --git a/examples/click_around_google.js b/examples/click_around_google.js deleted file mode 100644 index a1fabd1a..00000000 --- a/examples/click_around_google.js +++ /dev/null @@ -1,20 +0,0 @@ -// test the "page.click(QUERY SELECTOR)" api -// NOTE: This test will need to be updated if Google changes it's DOM :-P - -var page = new WebPage(); - -page.open("http://www.google.com/", function(status) { - if ( status === "success" ) { - // render before doing anything - page.render("click_around_google-before.png"); - - // click on the Google 'settings bolt' - page.click("#gbg5"); - page.render("click_around_google-clicked_on_gbg5.png"); - - // click on 'more' - page.click("#gbztm"); - page.render("click_around_google-clicked_on_gbztm.png"); - } - phantom.exit(); -}); diff --git a/src/webpage.cpp b/src/webpage.cpp index 553134b8..ebccafa4 100644 --- a/src/webpage.cpp +++ b/src/webpage.cpp @@ -484,15 +484,6 @@ void WebPage::uploadFile(const QString &selector, const QString &fileName) el.evaluateJavaScript(JS_ELEMENT_CLICK); } -void WebPage::click(const QString &selector) { - // Execute the equivalent of "querySelectorAll" - QWebElementCollection webElements = m_mainFrame->findAllElements(selector); - // Click on every element found by the previous selector (if any) - foreach ( QWebElement el, webElements ) { - el.evaluateJavaScript(JS_ELEMENT_CLICK); - } -} - #endif bool WebPage::injectJs(const QString &jsFilePath) { diff --git a/src/webpage.h b/src/webpage.h index 24be48d4..19eec472 100644 --- a/src/webpage.h +++ b/src/webpage.h @@ -78,7 +78,6 @@ public slots: // moc does not understand QT_VERSION_CHECK and hence the encoded hex #if QT_VERSION >= 0x040600 void uploadFile(const QString &selector, const QString &fileName); - void click(const QString &selector); #endif signals: