From b412aba06d093d5896eecbf6da9639a558495c32 Mon Sep 17 00:00:00 2001 From: Ariya Hidayat Date: Thu, 8 Sep 2011 13:25:44 -0700 Subject: [PATCH 1/8] bootstrap.js: Reindent properly. --- src/bootstrap.js | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/bootstrap.js b/src/bootstrap.js index c85a0982..eb454509 100644 --- a/src/bootstrap.js +++ b/src/bootstrap.js @@ -104,9 +104,9 @@ function require (name) { * @param destination Path of the destination file */ exports.copy = function (source, destination) { - if (!fs._copy(source, destination)) { - throw "Unable to copy file '" + source + "' at '" + destination + "'"; - } + if (!fs._copy(source, destination)) { + throw "Unable to copy file '" + source + "' at '" + destination + "'"; + } }; /** Copy a directory tree. @@ -116,9 +116,9 @@ function require (name) { * @param destination Path of the destination directory tree */ exports.copyTree = function (source, destination) { - if (!fs._copyTree(source, destination)) { - throw "Unable to copy directory tree '" + source + "' at '" + destination + "'"; - } + if (!fs._copyTree(source, destination)) { + throw "Unable to copy directory tree '" + source + "' at '" + destination + "'"; + } }; /** Move a file. @@ -128,8 +128,8 @@ function require (name) { * @param destination Path of the destination file */ exports.move = function (source, destination) { - fs.copy(source, destination); - fs.remove(source); + fs.copy(source, destination); + fs.remove(source); }; /** Removes a file. @@ -138,9 +138,9 @@ function require (name) { * @param path Path of the file to remove */ exports.remove = function (path) { - if (!fs._remove(path)) { - throw "Unable to remove file '" + path + "'"; - } + if (!fs._remove(path)) { + throw "Unable to remove file '" + path + "'"; + } }; /** Removes a directory. @@ -149,9 +149,9 @@ function require (name) { * @param path Path of the directory to remove */ exports.removeDirectory = function (path) { - if (!fs._removeDirectory(path)) { - throw "Unable to remove directory '" + path + "'"; - } + if (!fs._removeDirectory(path)) { + throw "Unable to remove directory '" + path + "'"; + } }; /** Removes a directory tree. @@ -160,13 +160,13 @@ function require (name) { * @param path Path of the directory tree to remove */ exports.removeTree = function (path) { - if (!fs._removeTree(path)) { - throw "Unable to remove directory tree '" + path + "'"; - } + if (!fs._removeTree(path)) { + throw "Unable to remove directory tree '" + path + "'"; + } }; exports.touch = function (path) { - fs.write(path, "", 'a'); + fs.write(path, "", 'a'); }; } From 2b83a522516af90f14d179699d8b6bdb6b5f74dd Mon Sep 17 00:00:00 2001 From: Ariya Hidayat Date: Thu, 8 Sep 2011 17:32:31 -0700 Subject: [PATCH 2/8] Implement require('webpage'). This is mostly based on Ivan's work, see https://github.com/ariya/phantomjs/pull/153 window.WebPage still works, it is not recommended and will be deprecated. http://code.google.com/p/phantomjs/issues/detail?id=47 --- src/bootstrap.js | 156 +++++++++++++++++++++++++++++++++++++++++++- src/phantom.cpp | 7 +- src/phantomjs.pro | 1 - src/phantomjs.qrc | 1 - src/webpage-shim.js | 147 ----------------------------------------- 5 files changed, 158 insertions(+), 154 deletions(-) diff --git a/src/bootstrap.js b/src/bootstrap.js index eb454509..1de4c5b5 100644 --- a/src/bootstrap.js +++ b/src/bootstrap.js @@ -4,7 +4,10 @@ /* This file is part of the PhantomJS project from Ofi Labs. + Copyright (C) 2011 Ariya Hidayat Copyright (C) 2011 Ivan De Marino + Copyright (C) 2011 James Roe + Copyright (C) 2011 execjosh, http://execjosh.blogspot.com Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: @@ -30,10 +33,159 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -function require (name) { +function require(name) { var exports; + if (name === 'webpage') { + + exports = function (opts) { + var page = phantom.createWebPage(), + handlers = {}; + + function checkType(o, type) { + return typeof o === type; + } + + function isObject(o) { + return checkType(o, 'object'); + } + + function isUndefined(o) { + return checkType(o, 'undefined'); + } + + function isUndefinedOrNull(o) { + return isUndefined(o) || null === o; + } + + function copyInto(target, source) { + if (target === source || isUndefinedOrNull(source)) { + return target; + } + + target = target || {}; + + // Copy into objects only + if (isObject(target)) { + // Make sure source exists + source = source || {}; + + if (isObject(source)) { + var i, newTarget, newSource; + for (i in source) { + if (source.hasOwnProperty(i)) { + newTarget = target[i]; + newSource = source[i]; + + if (newTarget && isObject(newSource)) { + // Deep copy + newTarget = copyInto(target[i], newSource); + } else { + newTarget = newSource; + } + + if (!isUndefined(newTarget)) { + target[i] = newTarget; + } + } + } + } else { + target = source; + } + } + + return target; + } + + function defineSetter(handlerName, signalName) { + page.__defineSetter__(handlerName, function (f) { + if (handlers && typeof handlers[signalName] === 'function') { + try { + this[signalName].disconnect(handlers[signalName]); + } catch (e) {} + } + handlers[signalName] = f; + this[signalName].connect(handlers[signalName]); + }); + } + + // deep copy + page.settings = JSON.parse(JSON.stringify(phantom.defaultPageSettings)); + + defineSetter("onInitialized", "initialized"); + + defineSetter("onLoadStarted", "loadStarted"); + + defineSetter("onLoadFinished", "loadFinished"); + + defineSetter("onResourceRequested", "resourceRequested"); + + defineSetter("onResourceReceived", "resourceReceived"); + + defineSetter("onAlert", "javaScriptAlertSent"); + + defineSetter("onConsoleMessage", "javaScriptConsoleMessageSent"); + + page.open = function (url, arg1, arg2, arg3, arg4) { + if (arguments.length === 1) { + this.openUrl(url, 'get', this.settings); + return; + } + if (arguments.length === 2 && typeof arg1 === 'function') { + this.onLoadFinished = arg1; + 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.openUrl(url, arg1, this.settings); + return; + } else if (arguments.length === 3) { + this.openUrl(url, { + operation: arg1, + data: arg2 + }, this.settings); + return; + } else if (arguments.length === 4) { + this.onLoadFinished = arg3; + this.openUrl(url, { + operation: arg1, + data: arg2 + }, this.settings); + return; + } + 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(arguments.callee); + } catch (e) {} + } + }); + + // Append the script tag to the body + this._appendScriptElement(scriptUrl); + }; + + // Copy options into page + if (opts) { + page = copyInto(page, opts); + } + + return page; + }; + } + if (name === 'fs') { exports = phantom.createFilesystem(); @@ -178,3 +330,5 @@ function require (name) { return exports; } +// Legacy way to use WebPage +window.WebPage = require('webpage'); diff --git a/src/phantom.cpp b/src/phantom.cpp index 3b64c631..a614b5f4 100644 --- a/src/phantom.cpp +++ b/src/phantom.cpp @@ -112,11 +112,10 @@ Phantom::Phantom(QObject *parent) m_page->mainFrame()->addToJavaScriptWindowObject("phantom", this); // Load all the required JavaScript 'shims' - QString jsShims[2] = { - ":/bootstrap.js", - ":/webpage-shim.js" + QString jsShims[1] = { + ":/bootstrap.js" }; - for (int i = 0, len = 2; i < len; ++i) { + for (int i = 0, len = 1; i < len; ++i) { QFile f(jsShims[i]); f.open(QFile::ReadOnly); //< It's OK to assume this succeed. If it doesn't, we have a bigger problem. m_page->mainFrame()->evaluateJavaScript(QString::fromUtf8(f.readAll())); diff --git a/src/phantomjs.pro b/src/phantomjs.pro index 4f91ea9b..6c476b63 100644 --- a/src/phantomjs.pro +++ b/src/phantomjs.pro @@ -36,7 +36,6 @@ SOURCES += phantom.cpp \ config.cpp OTHER_FILES += usage.txt \ - webpage-shim.js \ bootstrap.js \ configurator.js diff --git a/src/phantomjs.qrc b/src/phantomjs.qrc index ccce5f8f..820461f7 100644 --- a/src/phantomjs.qrc +++ b/src/phantomjs.qrc @@ -3,7 +3,6 @@ phantomjs-icon.png coffee-script.js usage.txt - webpage-shim.js bootstrap.js configurator.js diff --git a/src/webpage-shim.js b/src/webpage-shim.js index d8a5fd26..c4269974 100644 --- a/src/webpage-shim.js +++ b/src/webpage-shim.js @@ -33,150 +33,3 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -// This allows creating a new web page using the construct "new WebPage", -// which feels more natural than "phantom.createWebPage()". -window.WebPage = function (opts) { - var page = phantom.createWebPage(), - handlers = {}; - - function checkType(o, type) { - return typeof o === type; - } - - function isObject(o) { - return checkType(o, 'object'); - } - - function isUndefined(o) { - return checkType(o, 'undefined'); - } - - function isUndefinedOrNull(o) { - return isUndefined(o) || null === o; - } - - function copyInto(target, source) { - if (target === source || isUndefinedOrNull(source)) { - return target; - } - - target = target || {}; - - // Copy into objects only - if (isObject(target)) { - // Make sure source exists - source = source || {}; - - if (isObject(source)) { - var i, newTarget, newSource; - for (i in source) { - if (source.hasOwnProperty(i)) { - newTarget = target[i]; - newSource = source[i]; - - if (newTarget && isObject(newSource)) { - // Deep copy - newTarget = copyInto(target[i], newSource); - } else { - newTarget = newSource; - } - - if (!isUndefined(newTarget)) { - target[i] = newTarget; - } - } - } - } else { - target = source; - } - } - - return target; - } - - function defineSetter(handlerName, signalName) { - page.__defineSetter__(handlerName, function (f) { - if (handlers && typeof handlers[signalName] === 'function') { - try { - this[signalName].disconnect(handlers[signalName]); - } catch (e) {} - } - handlers[signalName] = f; - this[signalName].connect(handlers[signalName]); - }); - } - - // deep copy - page.settings = JSON.parse(JSON.stringify(phantom.defaultPageSettings)); - - defineSetter("onInitialized", "initialized"); - - defineSetter("onLoadStarted", "loadStarted"); - - defineSetter("onLoadFinished", "loadFinished"); - - defineSetter("onResourceRequested", "resourceRequested"); - - defineSetter("onResourceReceived", "resourceReceived"); - - defineSetter("onAlert", "javaScriptAlertSent"); - - defineSetter("onConsoleMessage", "javaScriptConsoleMessageSent"); - - page.open = function (url, arg1, arg2, arg3, arg4) { - if (arguments.length === 1) { - this.openUrl(url, 'get', this.settings); - return; - } - if (arguments.length === 2 && typeof arg1 === 'function') { - this.onLoadFinished = arg1; - 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.openUrl(url, arg1, this.settings); - return; - } else if (arguments.length === 3) { - this.openUrl(url, { - operation: arg1, - data: arg2 - }, this.settings); - return; - } else if (arguments.length === 4) { - this.onLoadFinished = arg3; - this.openUrl(url, { - operation: arg1, - data: arg2 - }, this.settings); - return; - } - 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(arguments.callee); - } catch (e) {} - } - }); - - // Append the script tag to the body - this._appendScriptElement(scriptUrl); - }; - - // Copy options into page - if (opts) { - page = copyInto(page, opts); - } - - return page; -}; From 4fb37aa0ccb344622d3e3f20488b8f17f067f943 Mon Sep 17 00:00:00 2001 From: Ariya Hidayat Date: Thu, 8 Sep 2011 17:37:01 -0700 Subject: [PATCH 3/8] Create FileSystem instance only when needed. --- src/phantom.cpp | 6 +++++- src/phantom.h | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/phantom.cpp b/src/phantom.cpp index a614b5f4..1a7592df 100644 --- a/src/phantom.cpp +++ b/src/phantom.cpp @@ -48,6 +48,7 @@ Phantom::Phantom(QObject *parent) , m_terminated(false) , m_returnValue(0) , m_netAccessMan(0) + , m_filesystem(0) { // second argument: script name QStringList args = QApplication::arguments(); @@ -200,7 +201,10 @@ QObject *Phantom::createWebPage() QObject *Phantom::createFilesystem() { - return &m_filesystem; + if (!m_filesystem) + m_filesystem = new FileSystem(this); + + return m_filesystem; } bool Phantom::injectJs(const QString &jsFilePath) { diff --git a/src/phantom.h b/src/phantom.h index 7f4b2fab..619ecdd4 100644 --- a/src/phantom.h +++ b/src/phantom.h @@ -87,7 +87,7 @@ private: QString m_script; NetworkAccessManager *m_netAccessMan; QVariantMap m_defaultPageSettings; - FileSystem m_filesystem; + FileSystem *m_filesystem; QList > m_pages; Config m_config; }; From a62299214d481964818fd2918a9ec9d5da2c7533 Mon Sep 17 00:00:00 2001 From: Ariya Hidayat Date: Thu, 8 Sep 2011 17:49:05 -0700 Subject: [PATCH 4/8] Fix braces placement to follow the coding style. --- src/cookiejar.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/cookiejar.cpp b/src/cookiejar.cpp index 368aecff..6844dba0 100644 --- a/src/cookiejar.cpp +++ b/src/cookiejar.cpp @@ -34,11 +34,12 @@ CookieJar::CookieJar(QString cookieFile) : QNetworkCookieJar() - { - m_cookieFile = cookieFile; - } +{ + m_cookieFile = cookieFile; +} -bool CookieJar::setCookiesFromUrl(const QList & cookieList, const QUrl & url) { +bool CookieJar::setCookiesFromUrl(const QList & cookieList, const QUrl & url) +{ QSettings settings(m_cookieFile, QSettings::IniFormat); settings.beginGroup(url.host()); @@ -52,7 +53,8 @@ bool CookieJar::setCookiesFromUrl(const QList & cookieList, cons return true; } -QList CookieJar::cookiesForUrl(const QUrl & url) const { +QList CookieJar::cookiesForUrl(const QUrl & url) const +{ QSettings settings(m_cookieFile, QSettings::IniFormat); QList cookieList; @@ -66,4 +68,3 @@ QList CookieJar::cookiesForUrl(const QUrl & url) const { return cookieList; } - From 64bc80d0804d62bdae80e14056731edaec7afd2d Mon Sep 17 00:00:00 2001 From: Ariya Hidayat Date: Thu, 8 Sep 2011 17:54:53 -0700 Subject: [PATCH 5/8] Add simple tests for require(). http://code.google.com/p/phantomjs/issues/detail?id=47 --- test/module-spec.js | 18 ++++++++++++++++++ test/run-tests.js | 1 + 2 files changed, 19 insertions(+) create mode 100644 test/module-spec.js diff --git a/test/module-spec.js b/test/module-spec.js new file mode 100644 index 00000000..03451f25 --- /dev/null +++ b/test/module-spec.js @@ -0,0 +1,18 @@ +describe("module loading using require", function() { + + it("should work for 'webpage' module", function() { + expect(typeof require('webpage')).toEqual('function'); + }); + + it("should work for 'fs' module", function() { + expect(typeof require('fs')).toEqual('object'); + }); + + it("should throw an error for an unknown module", function() { + var module = 'foobar'; + expect(function(){ + var foo = require(module); + }).toThrow("Unknown module " + module + " for require()"); + }); + +}); diff --git a/test/run-tests.js b/test/run-tests.js index 5c19464d..d136dae0 100644 --- a/test/run-tests.js +++ b/test/run-tests.js @@ -56,6 +56,7 @@ function expectHasPropertyString(o, name) { // Load specs var fs = require('fs'); phantom.injectJs("./phantom-spec.js"); +phantom.injectJs("./module-spec.js"); phantom.injectJs("./webpage-spec.js"); phantom.injectJs("./fs-spec-01.js"); //< Filesystem Specs 01 (Basic) phantom.injectJs("./fs-spec-02.js"); //< Filesystem Specs 02 (Attributes) From e67428382193d21d752b334e2e154312aa2e4440 Mon Sep 17 00:00:00 2001 From: Ariya Hidayat Date: Thu, 8 Sep 2011 21:37:40 -0700 Subject: [PATCH 6/8] Fix the proxy option example (http is not needed). This was mentioned in http://code.google.com/p/phantomjs/issues/detail?id=19 --- src/usage.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/usage.txt b/src/usage.txt index 2f67d7c2..2791906d 100644 --- a/src/usage.txt +++ b/src/usage.txt @@ -6,7 +6,7 @@ Options: --config=/path/to/config Specifies path to a JSON-formatted config file. --load-images=[yes|no] Loads all inlined images (default is 'yes'). --load-plugins=[yes|no] Loads all plugins (i.e. 'Flash', 'Silverlight', ...) (default is 'no'). - --proxy=address:port Sets the network proxy (e.g. "--proxy=http://192.168.1.42:8080"). + --proxy=address:port Sets the network proxy (e.g. "--proxy=192.168.1.42:8080"). --auth=username:password Sets the authentication username and password (e.g. "--auth=username:password"). --disk-cache=[yes|no] Enables disk cache (at desktop services cache storage location, default is 'no'). --max-disk-cache-size=size Limits the size of disk cache (in KB). From f7162f7302ad32c3b8b0e7a6ba35c16effaa16f9 Mon Sep 17 00:00:00 2001 From: Ariya Hidayat Date: Thu, 8 Sep 2011 22:35:07 -0700 Subject: [PATCH 7/8] Fix coding style (brace placement and indentation with spaces). --- src/webpage.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/webpage.cpp b/src/webpage.cpp index 62a73603..461d4343 100644 --- a/src/webpage.cpp +++ b/src/webpage.cpp @@ -353,9 +353,7 @@ QImage WebPage::renderImage() frameRect = m_clipRect; if(!m_scrollPosition.isNull()) - { - m_mainFrame->setScrollPosition(m_scrollPosition); - } + m_mainFrame->setScrollPosition(m_scrollPosition); // m_webPage->setViewportSize(m_mainFrame->contentsSize()); QImage buffer(frameRect.size(), QImage::Format_ARGB32); From d844d5404f429d426909532c03ecc69de27490b1 Mon Sep 17 00:00:00 2001 From: Ariya Hidayat Date: Thu, 8 Sep 2011 23:36:06 -0700 Subject: [PATCH 8/8] Fix wrong viewport size due to commit 6e39625e. http://code.google.com/p/phantomjs/issues/detail?id=217 --- src/webpage.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/webpage.cpp b/src/webpage.cpp index 461d4343..6e81cb61 100644 --- a/src/webpage.cpp +++ b/src/webpage.cpp @@ -237,6 +237,7 @@ void WebPage::setScrollPosition(const QVariantMap &size) int top = size.value("top").toInt(); int left = size.value("left").toInt(); m_scrollPosition = QPoint(left,top); + m_mainFrame->setScrollPosition(m_scrollPosition); } QVariantMap WebPage::scrollPosition() const @@ -345,16 +346,15 @@ bool WebPage::render(const QString &fileName) } QImage WebPage::renderImage() - { - QSize viewportSize = m_webPage->viewportSize(); - QRect frameRect = QRect(QPoint(0, 0), viewportSize); + QSize contentsSize = m_mainFrame->contentsSize(); + contentsSize -= QSize(m_scrollPosition.x(), m_scrollPosition.y()); + QRect frameRect = QRect(QPoint(0, 0), contentsSize); if (!m_clipRect.isNull()) frameRect = m_clipRect; - if(!m_scrollPosition.isNull()) - m_mainFrame->setScrollPosition(m_scrollPosition); - // m_webPage->setViewportSize(m_mainFrame->contentsSize()); + QSize viewportSize = m_webPage->viewportSize(); + m_webPage->setViewportSize(contentsSize); QImage buffer(frameRect.size(), QImage::Format_ARGB32); buffer.fill(qRgba(255, 255, 255, 0));