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"
|
||||
|
||||
class WebPage;
|
||||
class CustomPage;
|
||||
class WebServer;
|
||||
|
||||
class Phantom: public REPLCompletable
|
||||
|
@ -133,6 +134,8 @@ private:
|
|||
QList<QPointer<WebServer> > m_servers;
|
||||
Config m_config;
|
||||
QVariantMap m_keyMap;
|
||||
|
||||
friend class CustomPage;
|
||||
};
|
||||
|
||||
#endif // PHANTOM_H
|
||||
|
|
|
@ -181,9 +181,16 @@ protected:
|
|||
|
||||
QWebPage *createWindow (WebWindowType type) {
|
||||
Q_UNUSED(type);
|
||||
WebPage *newPage;
|
||||
|
||||
// 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
|
||||
newPage->applySettings(Phantom::instance()->defaultPageSettings());
|
||||
|
||||
|
@ -264,6 +271,7 @@ WebPage::WebPage(QObject *parent, const QUrl &baseUrl)
|
|||
: REPLCompletable(parent)
|
||||
, m_callbacks(NULL)
|
||||
, m_navigationLocked(false)
|
||||
, m_ownsPages(true)
|
||||
{
|
||||
setObjectName("WebPage");
|
||||
m_customWebPage = new CustomPage(this);
|
||||
|
@ -415,7 +423,6 @@ bool WebPage::navigationLocked()
|
|||
return m_navigationLocked;
|
||||
}
|
||||
|
||||
|
||||
void WebPage::setViewportSize(const QVariantMap &size)
|
||||
{
|
||||
int w = size.value("width").toInt();
|
||||
|
@ -1062,6 +1069,16 @@ QObject *WebPage::getPage(const QString &windowName) const
|
|||
return NULL;
|
||||
}
|
||||
|
||||
bool WebPage::ownsPages() const
|
||||
{
|
||||
return m_ownsPages;
|
||||
}
|
||||
|
||||
void WebPage::setOwnsPages(const bool owns)
|
||||
{
|
||||
m_ownsPages = owns;
|
||||
}
|
||||
|
||||
int WebPage::framesCount() const
|
||||
{
|
||||
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(QObjectList pages READ pages)
|
||||
Q_PROPERTY(QStringList pagesWindowName READ pagesWindowName)
|
||||
Q_PROPERTY(bool ownsPages READ ownsPages WRITE setOwnsPages)
|
||||
Q_PROPERTY(QStringList framesName READ framesName)
|
||||
Q_PROPERTY(QString frameName READ frameName)
|
||||
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
|
||||
* 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
|
||||
* @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
|
||||
* <code>"name"</code> might be provided as second parameter.
|
||||
* 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
|
||||
* @return List (JS Array) containing the <code>'window.name'</code>(s) of
|
||||
|
@ -155,6 +160,26 @@ public:
|
|||
*/
|
||||
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.
|
||||
* 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;
|
||||
bool m_navigationLocked;
|
||||
QPoint m_mousePos;
|
||||
bool m_ownsPages;
|
||||
|
||||
friend class Phantom;
|
||||
friend class CustomPage;
|
||||
|
|
|
@ -6,11 +6,11 @@ describe("Basic Files API (read, write, remove, ...)", function() {
|
|||
FILENAME_ENC = FILENAME + ".enc",
|
||||
FILENAME_BIN = FILENAME + ".bin",
|
||||
ABSENT = "absent-01.test";
|
||||
|
||||
|
||||
it("should be able to create and write a file", function() {
|
||||
try{
|
||||
var f = fs.open(FILENAME, "w");
|
||||
|
||||
|
||||
f.write("hello");
|
||||
f.writeLine("");
|
||||
f.writeLine("world");
|
||||
|
@ -25,31 +25,29 @@ describe("Basic Files API (read, write, remove, ...)", function() {
|
|||
expect(fs.exists(FILENAME_EMPTY)).toBeTruthy();
|
||||
expect(fs.size(FILENAME_EMPTY)).toEqual(0);
|
||||
});
|
||||
|
||||
|
||||
it("should be able to read content from a file", function() {
|
||||
var content = "";
|
||||
try{
|
||||
var f = fs.open(FILENAME, "r");
|
||||
|
||||
content = f.read();
|
||||
|
||||
content = f.read();
|
||||
f.close();
|
||||
} catch (e) { }
|
||||
expect(content).toEqual("hello\nworld\n");
|
||||
});
|
||||
|
||||
|
||||
it("should be able to read/write/append content from a file", function() {
|
||||
var content = "";
|
||||
try{
|
||||
var f = fs.open(FILENAME, "rw+");
|
||||
console.log(f.read().length);
|
||||
f.writeLine("asdf");
|
||||
content = f.read();
|
||||
console.log(content.length);
|
||||
f.close();
|
||||
} catch (e) { }
|
||||
expect(content).toEqual("hello\nworld\nasdf\n");
|
||||
});
|
||||
|
||||
|
||||
it("should be able to copy a file", function() {
|
||||
expect(fs.exists(FILENAME_COPY)).toBeFalsy();
|
||||
fs.copy(FILENAME, FILENAME_COPY);
|
||||
|
@ -77,7 +75,7 @@ describe("Basic Files API (read, write, remove, ...)", function() {
|
|||
fs.remove(FILENAME_COPY);
|
||||
expect(fs.exists(FILENAME_COPY)).toBeFalsy();
|
||||
});
|
||||
|
||||
|
||||
it("should be able to remove an empty file", function() {
|
||||
expect(fs.exists(FILENAME_EMPTY)).toBeTruthy();
|
||||
fs.remove(FILENAME_EMPTY);
|
||||
|
@ -139,4 +137,4 @@ describe("Basic Files API (read, write, remove, ...)", function() {
|
|||
} catch (e) { }
|
||||
expect(content).toEqual(output);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -157,6 +157,7 @@ describe("WebPage object", function() {
|
|||
expectHasFunction(page, 'loadStarted');
|
||||
expectHasFunction(page, 'openUrl');
|
||||
expectHasFunction(page, 'release');
|
||||
expectHasFunction(page, 'close');
|
||||
expectHasFunction(page, 'render');
|
||||
expectHasFunction(page, 'resourceReceived');
|
||||
expectHasFunction(page, 'resourceRequested');
|
||||
|
@ -242,7 +243,7 @@ describe("WebPage object", function() {
|
|||
return page.evaluate(function() {
|
||||
return document.querySelector('input').value;
|
||||
});
|
||||
}
|
||||
};
|
||||
page.sendEvent('keypress', phantom.keys.A);
|
||||
expect(getText()).toEqual("A");
|
||||
page.sendEvent('keypress', phantom.keys.B);
|
||||
|
@ -431,7 +432,7 @@ describe("WebPage object", function() {
|
|||
|
||||
runs(function() {
|
||||
page.evaluate(function() {
|
||||
setTimeout(function() { referenceError }, 0);
|
||||
setTimeout(function() { referenceError(); }, 0);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -440,13 +441,13 @@ describe("WebPage object", function() {
|
|||
runs(function() {
|
||||
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");
|
||||
|
||||
page.evaluate(function() { throw "foo" });
|
||||
page.evaluate(function() { throw "foo"; });
|
||||
expect(lastError).toEqual("foo");
|
||||
|
||||
page.evaluate(function() { throw Error("foo") });
|
||||
page.evaluate(function() { throw Error("foo"); });
|
||||
expect(lastError).toEqual("Error: foo");
|
||||
});
|
||||
});
|
||||
|
@ -462,32 +463,32 @@ describe("WebPage object", function() {
|
|||
caughtError = false;
|
||||
|
||||
try {
|
||||
referenceError
|
||||
referenceError();
|
||||
} catch(e) {
|
||||
caughtError = true;
|
||||
}
|
||||
});
|
||||
|
||||
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() {
|
||||
runs(function() {
|
||||
var e1, e2;
|
||||
|
||||
try {
|
||||
referenceError
|
||||
referenceError();
|
||||
} catch (e) {
|
||||
e1 = e
|
||||
};
|
||||
e1 = e;
|
||||
}
|
||||
|
||||
try {
|
||||
referenceError
|
||||
referenceError();
|
||||
} catch (e) {
|
||||
e2 = e
|
||||
};
|
||||
e2 = e;
|
||||
}
|
||||
|
||||
expect(e1.sourceURL).toMatch(/webpage-spec.js$/);
|
||||
expect(e1.line).toBeGreaterThan(1);
|
||||
|
@ -503,15 +504,15 @@ describe("WebPage object", function() {
|
|||
|
||||
runs(function() {
|
||||
function test() {
|
||||
ErrorHelper.foo()
|
||||
};
|
||||
ErrorHelper.foo();
|
||||
}
|
||||
|
||||
var err;
|
||||
try {
|
||||
test()
|
||||
test();
|
||||
} catch (e) {
|
||||
err = e
|
||||
};
|
||||
err = e;
|
||||
}
|
||||
|
||||
var lines = err.stack.split("\n");
|
||||
|
||||
|
@ -522,8 +523,8 @@ describe("WebPage object", function() {
|
|||
|
||||
page.injectJs(helperFile);
|
||||
|
||||
page.onError = function(message, s) { stack = s };
|
||||
page.evaluate(function() { setTimeout(function() { ErrorHelper.foo() }, 0) });
|
||||
page.onError = function(message, s) { stack = s; };
|
||||
page.evaluate(function() { setTimeout(function() { ErrorHelper.foo(); }, 0); });
|
||||
});
|
||||
|
||||
waits(0);
|
||||
|
@ -531,16 +532,16 @@ describe("WebPage object", function() {
|
|||
runs(function() {
|
||||
expect(stack[0].file).toEqual("./fixtures/error-helper.js");
|
||||
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() {
|
||||
var error;
|
||||
phantom.onError = function(e) { error = e };
|
||||
phantom.onError = function(e) { error = e; };
|
||||
|
||||
runs(function() {
|
||||
setTimeout(function() { zomg }, 0);
|
||||
setTimeout(function() { zomg(); }, 0);
|
||||
});
|
||||
|
||||
waits(0);
|
||||
|
@ -881,7 +882,7 @@ describe("WebPage construction with options", function () {
|
|||
decodedText = page.evaluate(function() {
|
||||
return document.getElementsByTagName('pre')[0].innerText;
|
||||
});
|
||||
page.release();
|
||||
page.close();
|
||||
});
|
||||
it("Should support text codec " + text.codec, function() {
|
||||
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");
|
||||
expect(yahoo).not.toBe(null);
|
||||
yahoo.release();
|
||||
yahoo.close();
|
||||
|
||||
waitsFor(function(){
|
||||
return p.pages.length === 1;
|
||||
|
@ -1101,6 +1102,7 @@ describe("WebPage opening and closing of windows/child-pages", function(){
|
|||
runs(function(){
|
||||
expect(p.pages.length).toEqual(1);
|
||||
expect(p.pagesWindowName).toEqual(["bing"]);
|
||||
p.close();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -1117,9 +1119,15 @@ describe("WebPage closing notification/alerting", function(){
|
|||
|
||||
p.close();
|
||||
|
||||
expect(spy).toHaveBeenCalled(); //< called
|
||||
expect(spy.calls.length).toEqual(1); //< only once
|
||||
expect(spy).toHaveBeenCalledWith(p); //< called passing reference to the closing page 'p'
|
||||
waitsFor(function() {
|
||||
return spy.calls.length === 1;
|
||||
}, "after 2sec 'onClosing' had still not been invoked", 2000);
|
||||
|
||||
runs(function() {
|
||||
expect(spy).toHaveBeenCalled(); //< called
|
||||
expect(spy.calls.length).toEqual(1); //< only once
|
||||
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(){
|
||||
|
@ -1135,8 +1143,88 @@ describe("WebPage closing notification/alerting", function(){
|
|||
window.close();
|
||||
});
|
||||
|
||||
expect(spy).toHaveBeenCalled(); //< called
|
||||
expect(spy.calls.length).toEqual(1); //< only once
|
||||
expect(spy).toHaveBeenCalledWith(p); //< called passing reference to the closing page 'p'
|
||||
waitsFor(function() {
|
||||
return spy.calls.length === 1;
|
||||
}, "after 2sec 'onClosing' had still not been invoked", 2000);
|
||||
|
||||
runs(function() {
|
||||
expect(spy).toHaveBeenCalled(); //< called
|
||||
expect(spy.calls.length).toEqual(1); //< only once
|
||||
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