mirror of https://github.com/vitalif/phantomjs
Adding property "page.ownsPages".
When set to "true", any page that gets created, is owned by the "page" that control it's lifetime. Also, the pages can be found in the "page.pages[]" array. Default value is "true". Addresses [Issue #151](http://code.google.com/p/phantomjs/issues/detail?id=151)1.7
parent
27dc699919
commit
733d21042b
|
@ -41,6 +41,7 @@
|
||||||
#include "system.h"
|
#include "system.h"
|
||||||
|
|
||||||
class WebPage;
|
class WebPage;
|
||||||
|
class CustomPage;
|
||||||
class WebServer;
|
class WebServer;
|
||||||
|
|
||||||
class Phantom: public REPLCompletable
|
class Phantom: public REPLCompletable
|
||||||
|
@ -133,6 +134,8 @@ private:
|
||||||
QList<QPointer<WebServer> > m_servers;
|
QList<QPointer<WebServer> > m_servers;
|
||||||
Config m_config;
|
Config m_config;
|
||||||
QVariantMap m_keyMap;
|
QVariantMap m_keyMap;
|
||||||
|
|
||||||
|
friend class CustomPage;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // PHANTOM_H
|
#endif // PHANTOM_H
|
||||||
|
|
|
@ -181,9 +181,16 @@ protected:
|
||||||
|
|
||||||
QWebPage *createWindow (WebWindowType type) {
|
QWebPage *createWindow (WebWindowType type) {
|
||||||
Q_UNUSED(type);
|
Q_UNUSED(type);
|
||||||
|
WebPage *newPage;
|
||||||
|
|
||||||
// Create a new "raw" WebPage object
|
// Create a new "raw" WebPage object
|
||||||
WebPage *newPage = new WebPage(m_webPage);
|
if (m_webPage->ownsPages()) {
|
||||||
|
newPage = new WebPage(m_webPage);
|
||||||
|
} else {
|
||||||
|
newPage = new WebPage(Phantom::instance());
|
||||||
|
Phantom::instance()->m_pages.append(newPage);
|
||||||
|
}
|
||||||
|
|
||||||
// Apply default settings
|
// Apply default settings
|
||||||
newPage->applySettings(Phantom::instance()->defaultPageSettings());
|
newPage->applySettings(Phantom::instance()->defaultPageSettings());
|
||||||
|
|
||||||
|
@ -264,6 +271,7 @@ WebPage::WebPage(QObject *parent, const QUrl &baseUrl)
|
||||||
: REPLCompletable(parent)
|
: REPLCompletable(parent)
|
||||||
, m_callbacks(NULL)
|
, m_callbacks(NULL)
|
||||||
, m_navigationLocked(false)
|
, m_navigationLocked(false)
|
||||||
|
, m_ownsPages(true)
|
||||||
{
|
{
|
||||||
setObjectName("WebPage");
|
setObjectName("WebPage");
|
||||||
m_customWebPage = new CustomPage(this);
|
m_customWebPage = new CustomPage(this);
|
||||||
|
@ -415,7 +423,6 @@ bool WebPage::navigationLocked()
|
||||||
return m_navigationLocked;
|
return m_navigationLocked;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void WebPage::setViewportSize(const QVariantMap &size)
|
void WebPage::setViewportSize(const QVariantMap &size)
|
||||||
{
|
{
|
||||||
int w = size.value("width").toInt();
|
int w = size.value("width").toInt();
|
||||||
|
@ -1062,6 +1069,16 @@ QObject *WebPage::getPage(const QString &windowName) const
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool WebPage::ownsPages() const
|
||||||
|
{
|
||||||
|
return m_ownsPages;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WebPage::setOwnsPages(const bool owns)
|
||||||
|
{
|
||||||
|
m_ownsPages = owns;
|
||||||
|
}
|
||||||
|
|
||||||
int WebPage::framesCount() const
|
int WebPage::framesCount() const
|
||||||
{
|
{
|
||||||
return m_customWebPage->currentFrame()->childFrames().count();
|
return m_customWebPage->currentFrame()->childFrames().count();
|
||||||
|
|
|
@ -64,6 +64,7 @@ class WebPage: public REPLCompletable, public QWebFrame::PrintCallback
|
||||||
Q_PROPERTY(QString windowName READ windowName)
|
Q_PROPERTY(QString windowName READ windowName)
|
||||||
Q_PROPERTY(QObjectList pages READ pages)
|
Q_PROPERTY(QObjectList pages READ pages)
|
||||||
Q_PROPERTY(QStringList pagesWindowName READ pagesWindowName)
|
Q_PROPERTY(QStringList pagesWindowName READ pagesWindowName)
|
||||||
|
Q_PROPERTY(bool ownsPages READ ownsPages WRITE setOwnsPages)
|
||||||
Q_PROPERTY(QStringList framesName READ framesName)
|
Q_PROPERTY(QStringList framesName READ framesName)
|
||||||
Q_PROPERTY(QString frameName READ frameName)
|
Q_PROPERTY(QString frameName READ frameName)
|
||||||
Q_PROPERTY(int framesCount READ framesCount)
|
Q_PROPERTY(int framesCount READ framesCount)
|
||||||
|
@ -136,6 +137,8 @@ public:
|
||||||
*
|
*
|
||||||
* NOTE: The ownership of this array is held by the Page: it's not adviced
|
* NOTE: The ownership of this array is held by the Page: it's not adviced
|
||||||
* to have a "long running reference" to this array, as it might change.
|
* to have a "long running reference" to this array, as it might change.
|
||||||
|
* NOTE: If "ownsPages()" is "false", the page will create pages but not
|
||||||
|
* hold any ownership to it. Resource management is than left to the user.
|
||||||
*
|
*
|
||||||
* @brief pages
|
* @brief pages
|
||||||
* @return List (JS Array) containing the Pages that this page
|
* @return List (JS Array) containing the Pages that this page
|
||||||
|
@ -148,6 +151,8 @@ public:
|
||||||
* NOTE: When a page is opened with <code>"window.open"</code>, a window
|
* NOTE: When a page is opened with <code>"window.open"</code>, a window
|
||||||
* <code>"name"</code> might be provided as second parameter.
|
* <code>"name"</code> might be provided as second parameter.
|
||||||
* This provides a useful list of those.
|
* This provides a useful list of those.
|
||||||
|
* NOTE: If "ownsPages()" is "false", the page will create pages but not
|
||||||
|
* hold any ownership of it. Resource management is than left to the user.
|
||||||
*
|
*
|
||||||
* @brief pagesWindowName
|
* @brief pagesWindowName
|
||||||
* @return List (JS Array) containing the <code>'window.name'</code>(s) of
|
* @return List (JS Array) containing the <code>'window.name'</code>(s) of
|
||||||
|
@ -155,6 +160,26 @@ public:
|
||||||
*/
|
*/
|
||||||
QStringList pagesWindowName() const;
|
QStringList pagesWindowName() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns "true" if it owns the pages it creates (and keeps them in "pages[]").
|
||||||
|
* Default value is "true". Can be changed using {@link setOwnsPages()}.
|
||||||
|
*
|
||||||
|
* @brief ownsPages()
|
||||||
|
* @return "true" if it owns the pages it creates in "pages[]", "false" otherwise.
|
||||||
|
*/
|
||||||
|
bool ownsPages() const;
|
||||||
|
/**
|
||||||
|
* Set if, from now on, it should own the pages it creates in "pages[]".
|
||||||
|
* Default value is "true".
|
||||||
|
*
|
||||||
|
* NOTE: When switching from "false" to "true", only the pages created
|
||||||
|
* from that point on will be owned. It's NOT retroactive.
|
||||||
|
*
|
||||||
|
* @brief setOwnsPages
|
||||||
|
* @param owns "true" to make it own the pages it creates in "pages[]", "false" otherwise.
|
||||||
|
*/
|
||||||
|
void setOwnsPages(const bool owns);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the number of Child Frames inside the Current Frame.
|
* Returns the number of Child Frames inside the Current Frame.
|
||||||
* NOTE: The Current Frame changes when focus moves (via API or JS) to a specific child frame.
|
* NOTE: The Current Frame changes when focus moves (via API or JS) to a specific child frame.
|
||||||
|
@ -338,6 +363,7 @@ private:
|
||||||
WebpageCallbacks *m_callbacks;
|
WebpageCallbacks *m_callbacks;
|
||||||
bool m_navigationLocked;
|
bool m_navigationLocked;
|
||||||
QPoint m_mousePos;
|
QPoint m_mousePos;
|
||||||
|
bool m_ownsPages;
|
||||||
|
|
||||||
friend class Phantom;
|
friend class Phantom;
|
||||||
friend class CustomPage;
|
friend class CustomPage;
|
||||||
|
|
|
@ -41,10 +41,8 @@ describe("Basic Files API (read, write, remove, ...)", function() {
|
||||||
var content = "";
|
var content = "";
|
||||||
try{
|
try{
|
||||||
var f = fs.open(FILENAME, "rw+");
|
var f = fs.open(FILENAME, "rw+");
|
||||||
console.log(f.read().length);
|
|
||||||
f.writeLine("asdf");
|
f.writeLine("asdf");
|
||||||
content = f.read();
|
content = f.read();
|
||||||
console.log(content.length);
|
|
||||||
f.close();
|
f.close();
|
||||||
} catch (e) { }
|
} catch (e) { }
|
||||||
expect(content).toEqual("hello\nworld\nasdf\n");
|
expect(content).toEqual("hello\nworld\nasdf\n");
|
||||||
|
|
|
@ -157,6 +157,7 @@ describe("WebPage object", function() {
|
||||||
expectHasFunction(page, 'loadStarted');
|
expectHasFunction(page, 'loadStarted');
|
||||||
expectHasFunction(page, 'openUrl');
|
expectHasFunction(page, 'openUrl');
|
||||||
expectHasFunction(page, 'release');
|
expectHasFunction(page, 'release');
|
||||||
|
expectHasFunction(page, 'close');
|
||||||
expectHasFunction(page, 'render');
|
expectHasFunction(page, 'render');
|
||||||
expectHasFunction(page, 'resourceReceived');
|
expectHasFunction(page, 'resourceReceived');
|
||||||
expectHasFunction(page, 'resourceRequested');
|
expectHasFunction(page, 'resourceRequested');
|
||||||
|
@ -242,7 +243,7 @@ describe("WebPage object", function() {
|
||||||
return page.evaluate(function() {
|
return page.evaluate(function() {
|
||||||
return document.querySelector('input').value;
|
return document.querySelector('input').value;
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
page.sendEvent('keypress', phantom.keys.A);
|
page.sendEvent('keypress', phantom.keys.A);
|
||||||
expect(getText()).toEqual("A");
|
expect(getText()).toEqual("A");
|
||||||
page.sendEvent('keypress', phantom.keys.B);
|
page.sendEvent('keypress', phantom.keys.B);
|
||||||
|
@ -431,7 +432,7 @@ describe("WebPage object", function() {
|
||||||
|
|
||||||
runs(function() {
|
runs(function() {
|
||||||
page.evaluate(function() {
|
page.evaluate(function() {
|
||||||
setTimeout(function() { referenceError }, 0);
|
setTimeout(function() { referenceError(); }, 0);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -440,13 +441,13 @@ describe("WebPage object", function() {
|
||||||
runs(function() {
|
runs(function() {
|
||||||
expect(lastError).toEqual("ReferenceError: Can't find variable: referenceError");
|
expect(lastError).toEqual("ReferenceError: Can't find variable: referenceError");
|
||||||
|
|
||||||
page.evaluate(function() { referenceError2 });
|
page.evaluate(function() { referenceError2(); });
|
||||||
expect(lastError).toEqual("ReferenceError: Can't find variable: referenceError2");
|
expect(lastError).toEqual("ReferenceError: Can't find variable: referenceError2");
|
||||||
|
|
||||||
page.evaluate(function() { throw "foo" });
|
page.evaluate(function() { throw "foo"; });
|
||||||
expect(lastError).toEqual("foo");
|
expect(lastError).toEqual("foo");
|
||||||
|
|
||||||
page.evaluate(function() { throw Error("foo") });
|
page.evaluate(function() { throw Error("foo"); });
|
||||||
expect(lastError).toEqual("Error: foo");
|
expect(lastError).toEqual("Error: foo");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -462,32 +463,32 @@ describe("WebPage object", function() {
|
||||||
caughtError = false;
|
caughtError = false;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
referenceError
|
referenceError();
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
caughtError = true;
|
caughtError = true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(hadError).toEqual(false);
|
expect(hadError).toEqual(false);
|
||||||
expect(page.evaluate(function() { return caughtError })).toEqual(true);
|
expect(page.evaluate(function() { return caughtError; })).toEqual(true);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
})
|
|
||||||
|
|
||||||
it("reports the sourceURL and line of errors", function() {
|
it("reports the sourceURL and line of errors", function() {
|
||||||
runs(function() {
|
runs(function() {
|
||||||
var e1, e2;
|
var e1, e2;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
referenceError
|
referenceError();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
e1 = e
|
e1 = e;
|
||||||
};
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
referenceError
|
referenceError();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
e2 = e
|
e2 = e;
|
||||||
};
|
}
|
||||||
|
|
||||||
expect(e1.sourceURL).toMatch(/webpage-spec.js$/);
|
expect(e1.sourceURL).toMatch(/webpage-spec.js$/);
|
||||||
expect(e1.line).toBeGreaterThan(1);
|
expect(e1.line).toBeGreaterThan(1);
|
||||||
|
@ -503,15 +504,15 @@ describe("WebPage object", function() {
|
||||||
|
|
||||||
runs(function() {
|
runs(function() {
|
||||||
function test() {
|
function test() {
|
||||||
ErrorHelper.foo()
|
ErrorHelper.foo();
|
||||||
};
|
}
|
||||||
|
|
||||||
var err;
|
var err;
|
||||||
try {
|
try {
|
||||||
test()
|
test();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
err = e
|
err = e;
|
||||||
};
|
}
|
||||||
|
|
||||||
var lines = err.stack.split("\n");
|
var lines = err.stack.split("\n");
|
||||||
|
|
||||||
|
@ -522,8 +523,8 @@ describe("WebPage object", function() {
|
||||||
|
|
||||||
page.injectJs(helperFile);
|
page.injectJs(helperFile);
|
||||||
|
|
||||||
page.onError = function(message, s) { stack = s };
|
page.onError = function(message, s) { stack = s; };
|
||||||
page.evaluate(function() { setTimeout(function() { ErrorHelper.foo() }, 0) });
|
page.evaluate(function() { setTimeout(function() { ErrorHelper.foo(); }, 0); });
|
||||||
});
|
});
|
||||||
|
|
||||||
waits(0);
|
waits(0);
|
||||||
|
@ -531,16 +532,16 @@ describe("WebPage object", function() {
|
||||||
runs(function() {
|
runs(function() {
|
||||||
expect(stack[0].file).toEqual("./fixtures/error-helper.js");
|
expect(stack[0].file).toEqual("./fixtures/error-helper.js");
|
||||||
expect(stack[0].line).toEqual(7);
|
expect(stack[0].line).toEqual(7);
|
||||||
expect(stack[0].function).toEqual("bar");
|
expect(stack[0]["function"]).toEqual("bar");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("reports errors that occur in the main context", function() {
|
it("reports errors that occur in the main context", function() {
|
||||||
var error;
|
var error;
|
||||||
phantom.onError = function(e) { error = e };
|
phantom.onError = function(e) { error = e; };
|
||||||
|
|
||||||
runs(function() {
|
runs(function() {
|
||||||
setTimeout(function() { zomg }, 0);
|
setTimeout(function() { zomg(); }, 0);
|
||||||
});
|
});
|
||||||
|
|
||||||
waits(0);
|
waits(0);
|
||||||
|
@ -881,7 +882,7 @@ describe("WebPage construction with options", function () {
|
||||||
decodedText = page.evaluate(function() {
|
decodedText = page.evaluate(function() {
|
||||||
return document.getElementsByTagName('pre')[0].innerText;
|
return document.getElementsByTagName('pre')[0].innerText;
|
||||||
});
|
});
|
||||||
page.release();
|
page.close();
|
||||||
});
|
});
|
||||||
it("Should support text codec " + text.codec, function() {
|
it("Should support text codec " + text.codec, function() {
|
||||||
expect(decodedText.match("^" + text.reference) == text.reference).toEqual(true);
|
expect(decodedText.match("^" + text.reference) == text.reference).toEqual(true);
|
||||||
|
@ -1092,7 +1093,7 @@ describe("WebPage opening and closing of windows/child-pages", function(){
|
||||||
|
|
||||||
var yahoo = p.getPage("yahoo");
|
var yahoo = p.getPage("yahoo");
|
||||||
expect(yahoo).not.toBe(null);
|
expect(yahoo).not.toBe(null);
|
||||||
yahoo.release();
|
yahoo.close();
|
||||||
|
|
||||||
waitsFor(function(){
|
waitsFor(function(){
|
||||||
return p.pages.length === 1;
|
return p.pages.length === 1;
|
||||||
|
@ -1101,6 +1102,7 @@ describe("WebPage opening and closing of windows/child-pages", function(){
|
||||||
runs(function(){
|
runs(function(){
|
||||||
expect(p.pages.length).toEqual(1);
|
expect(p.pages.length).toEqual(1);
|
||||||
expect(p.pagesWindowName).toEqual(["bing"]);
|
expect(p.pagesWindowName).toEqual(["bing"]);
|
||||||
|
p.close();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1117,10 +1119,16 @@ describe("WebPage closing notification/alerting", function(){
|
||||||
|
|
||||||
p.close();
|
p.close();
|
||||||
|
|
||||||
|
waitsFor(function() {
|
||||||
|
return spy.calls.length === 1;
|
||||||
|
}, "after 2sec 'onClosing' had still not been invoked", 2000);
|
||||||
|
|
||||||
|
runs(function() {
|
||||||
expect(spy).toHaveBeenCalled(); //< called
|
expect(spy).toHaveBeenCalled(); //< called
|
||||||
expect(spy.calls.length).toEqual(1); //< only once
|
expect(spy.calls.length).toEqual(1); //< only once
|
||||||
expect(spy).toHaveBeenCalledWith(p); //< called passing reference to the closing page 'p'
|
expect(spy).toHaveBeenCalledWith(p); //< called passing reference to the closing page 'p'
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it("should call 'onClosing' when a page closes on it's own", function(){
|
it("should call 'onClosing' when a page closes on it's own", function(){
|
||||||
var p = require("webpage").create(),
|
var p = require("webpage").create(),
|
||||||
|
@ -1135,8 +1143,88 @@ describe("WebPage closing notification/alerting", function(){
|
||||||
window.close();
|
window.close();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
waitsFor(function() {
|
||||||
|
return spy.calls.length === 1;
|
||||||
|
}, "after 2sec 'onClosing' had still not been invoked", 2000);
|
||||||
|
|
||||||
|
runs(function() {
|
||||||
expect(spy).toHaveBeenCalled(); //< called
|
expect(spy).toHaveBeenCalled(); //< called
|
||||||
expect(spy.calls.length).toEqual(1); //< only once
|
expect(spy.calls.length).toEqual(1); //< only once
|
||||||
expect(spy).toHaveBeenCalledWith(p); //< called passing reference to the closing page 'p'
|
expect(spy).toHaveBeenCalledWith(p); //< called passing reference to the closing page 'p'
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("WebPage closing notification/alerting: closing propagation control", function(){
|
||||||
|
it("should close all 4 pages if parent page is closed (default value for 'ownsPages')", function(){
|
||||||
|
var p = require("webpage").create(),
|
||||||
|
pages,
|
||||||
|
openPagesCount = 0;
|
||||||
|
|
||||||
|
p.onPageCreated = jasmine.createSpy("onPageCreated spy");
|
||||||
|
|
||||||
|
expect(p.ownsPages).toBeTruthy();
|
||||||
|
|
||||||
|
p.evaluate(function() {
|
||||||
|
// yeah, I know globals. YIKES!
|
||||||
|
window.w1 = window.open("http://www.google.com", "google");
|
||||||
|
window.w2 = window.open("http://www.yahoo.com", "yahoo");
|
||||||
|
window.w3 = window.open("http://www.bing.com", "bing");
|
||||||
|
});
|
||||||
|
pages = p.pages;
|
||||||
|
openPagesCount = p.pages.length + 1;
|
||||||
|
expect(p.onPageCreated).toHaveBeenCalled();
|
||||||
|
expect(p.onPageCreated.calls.length).toEqual(3);
|
||||||
|
expect(p.pages.length).toEqual(3);
|
||||||
|
|
||||||
|
p.onClosing = function() { --openPagesCount; };
|
||||||
|
pages[0].onClosing = function() { --openPagesCount; };
|
||||||
|
pages[1].onClosing = function() { --openPagesCount; };
|
||||||
|
pages[2].onClosing = function() { --openPagesCount; };
|
||||||
|
|
||||||
|
p.close();
|
||||||
|
|
||||||
|
waitsFor(function() {
|
||||||
|
return openPagesCount === 0;
|
||||||
|
}, "after 2sec pages were still open", 2000);
|
||||||
|
|
||||||
|
runs(function() {
|
||||||
|
expect(openPagesCount).toBe(0);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should NOT close all 4 pages if parent page is closed, just parent itself ('ownsPages' set to false)", function(){
|
||||||
|
var p = require("webpage").create(),
|
||||||
|
pages,
|
||||||
|
openPagesCount = 0;
|
||||||
|
p.ownsPages = false;
|
||||||
|
|
||||||
|
p.onPageCreated = jasmine.createSpy("onPageCreated spy");
|
||||||
|
|
||||||
|
expect(p.ownsPages).toBeFalsy();
|
||||||
|
|
||||||
|
p.evaluate(function() {
|
||||||
|
// yeah, I know globals. YIKES!
|
||||||
|
window.w1 = window.open("http://www.google.com", "google");
|
||||||
|
window.w2 = window.open("http://www.yahoo.com", "yahoo");
|
||||||
|
window.w3 = window.open("http://www.bing.com", "bing");
|
||||||
|
});
|
||||||
|
pages = p.pages;
|
||||||
|
openPagesCount = 1;
|
||||||
|
expect(p.onPageCreated).toHaveBeenCalled();
|
||||||
|
expect(p.onPageCreated.calls.length).toEqual(3);
|
||||||
|
expect(p.pages.length).toEqual(0);
|
||||||
|
|
||||||
|
p.onClosing = function() { --openPagesCount; };
|
||||||
|
|
||||||
|
p.close();
|
||||||
|
|
||||||
|
waitsFor(function() {
|
||||||
|
return openPagesCount === 0;
|
||||||
|
}, "after 2sec pages were still open", 2000);
|
||||||
|
|
||||||
|
runs(function() {
|
||||||
|
expect(openPagesCount).toBe(0);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
Loading…
Reference in New Issue