Browse files

Adding "page.onFilePicker" callback.

This addresses [Issue #843](http://code.google.com/p/phantomjs/issues/detail?id=843).
Important: this doesn't change the ability to use
"page.uploadFile", that will keep working as expected.
  • Loading branch information...
1 parent 1fa9c04 commit eadb03a978838ee5af642217b5a1c5de4774cb9d @detro detro committed Oct 29, 2012
Showing with 121 additions and 5 deletions.
  1. +4 −1 src/callback.cpp
  2. +3 −0 src/modules/webpage.js
  3. +57 −4 src/webpage.cpp
  4. +2 −0 src/webpage.h
  5. +55 −0 test/webpage-spec.js
View
5 src/callback.cpp
@@ -29,6 +29,8 @@
#include "callback.h"
+#include <QDebug>
+
Callback::Callback(QObject* parent)
: QObject(parent)
{
@@ -38,6 +40,7 @@ QVariant Callback::call(const QVariantList& arguments)
{
emit called(arguments);
+ qDebug() << "Callback - call result:" << m_returnValue;
return m_returnValue;
}
@@ -49,4 +52,4 @@ QVariant Callback::returnValue() const
void Callback::setReturnValue(const QVariant& returnValue)
{
m_returnValue = returnValue;
-}
+}
View
3 src/modules/webpage.js
@@ -418,6 +418,9 @@ function decorateNewPage(opts, page) {
// Calls from within the page to "phantomCallback()" arrive to this handler
definePageCallbackSetter(page, handlers, "onCallback", "_getGenericCallback");
+ // Calls arrive to this handler when the user is asked to pick a file
+ definePageCallbackSetter(page, handlers, "onFilePicker", "_getFilePickerCallback");
+
// Calls from within the page to "window.confirm(message)" arrive to this handler
// @see https://developer.mozilla.org/en/DOM/window.confirm
definePageCallbackSetter(page, handlers, "onConfirm", "_getJsConfirmCallback");
View
61 src/webpage.cpp
@@ -112,8 +112,13 @@ public slots:
QString chooseFile(QWebFrame *originatingFrame, const QString &oldFile) {
Q_UNUSED(originatingFrame);
- Q_UNUSED(oldFile);
- return m_uploadFile;
+
+ QString filePath = m_webPage->filePicker(oldFile);
+ QString choosenFile = !filePath.isNull() ? filePath : m_uploadFile;
+
+ // Return the value coming from the "filePicker" callback, IFF not null.
+ qDebug() << "CustomPage - file choosen for upload:" << choosenFile;
+ return choosenFile;
}
void javaScriptAlert(QWebFrame *originatingFrame, const QString &msg) {
@@ -227,26 +232,42 @@ class WebpageCallbacks : public QObject
WebpageCallbacks(QObject *parent = 0)
: QObject(parent)
, m_genericCallback(NULL)
+ , m_filePickerCallback(NULL)
, m_jsConfirmCallback(NULL)
, m_jsPromptCallback(NULL)
{
}
QObject *getGenericCallback() {
+ qDebug() << "WebpageCallbacks - getGenericCallback";
+
if (!m_genericCallback) {
m_genericCallback = new Callback(this);
}
return m_genericCallback;
}
+ QObject *getFilePickerCallback() {
+ qDebug() << "WebpageCallbacks - getFilePickerCallback";
+
+ if (!m_filePickerCallback) {
+ m_filePickerCallback = new Callback(this);
+ }
+ return m_filePickerCallback;
+ }
+
QObject *getJsConfirmCallback() {
+ qDebug() << "WebpageCallbacks - getJsConfirmCallback";
+
if (!m_jsConfirmCallback) {
m_jsConfirmCallback = new Callback(this);
}
return m_jsConfirmCallback;
}
QObject *getJsPromptCallback() {
+ qDebug() << "WebpageCallbacks - getJsConfirmCallback";
+
if (!m_jsPromptCallback) {
m_jsPromptCallback = new Callback(this);
}
@@ -263,6 +284,7 @@ public slots:
private:
Callback *m_genericCallback;
+ Callback *m_filePickerCallback;
Callback *m_jsConfirmCallback;
Callback *m_jsPromptCallback;
@@ -600,6 +622,25 @@ QVariant WebPage::evaluateJavaScript(const QString &code)
return evalResult;
}
+QString WebPage::filePicker(const QString &oldFile)
+{
+ qDebug() << "WebPage - filePicker" << "- old file:" << oldFile;
+
+ if (m_callbacks->m_filePickerCallback) {
+ QVariant res = m_callbacks->m_filePickerCallback->call(QVariantList() << oldFile);
+
+ if (res.canConvert<QString>()) {
+ QString filePath = res.toString();
+ qDebug() << "WebPage - filePicker" << "- new file:" << filePath;
+ // Return this value only if the file actually exists
+ if (QFile::exists(filePath)) {
+ return filePath;
+ }
+ }
+ }
+ return QString();
+}
+
bool WebPage::javaScriptConfirm(const QString &msg)
{
if (m_callbacks->m_jsConfirmCallback) {
@@ -1072,15 +1113,26 @@ QObject *WebPage::_getGenericCallback() {
return m_callbacks->getGenericCallback();
}
-QObject *WebPage::_getJsConfirmCallback() {
+QObject *WebPage::_getFilePickerCallback()
+{
+ if (!m_callbacks) {
+ m_callbacks = new WebpageCallbacks(this);
+ }
+
+ return m_callbacks->getFilePickerCallback();
+}
+
+QObject *WebPage::_getJsConfirmCallback()
+{
if (!m_callbacks) {
m_callbacks = new WebpageCallbacks(this);
}
return m_callbacks->getJsConfirmCallback();
}
-QObject *WebPage::_getJsPromptCallback() {
+QObject *WebPage::_getJsPromptCallback()
+{
if (!m_callbacks) {
m_callbacks = new WebpageCallbacks(this);
}
@@ -1409,6 +1461,7 @@ void WebPage::initCompletions()
addCompletion("onCallback");
addCompletion("onPrompt");
addCompletion("onConfirm");
+ addCompletion("onFilePicker");
addCompletion("onConsoleMessage");
addCompletion("onInitialized");
addCompletion("onLoadStarted");
View
2 src/webpage.h
@@ -252,6 +252,7 @@ public slots:
bool injectJs(const QString &jsFilePath);
void _appendScriptElement(const QString &scriptUrl);
QObject *_getGenericCallback();
+ QObject *_getFilePickerCallback();
QObject *_getJsConfirmCallback();
QObject *_getJsPromptCallback();
void uploadFile(const QString &selector, const QString &fileName);
@@ -475,6 +476,7 @@ private slots:
*/
void changeCurrentFrame(QWebFrame * const frame);
+ QString filePicker(const QString &oldFile);
bool javaScriptConfirm(const QString &msg);
bool javaScriptPrompt(const QString &msg, const QString &defaultValue, QString *result);
View
55 test/webpage-spec.js
@@ -1456,3 +1456,58 @@ describe("WebPage closing notification/alerting: closing propagation control", f
});
});
});
+
+describe("WebPage 'onFilePicker'", function() {
+ it("should be able to set the file to upload when the File Picker is invoked (i.e. clicking on a 'input[type=file]')", function() {
+ var system = require('system'),
+ fileToUpload = system.os.name === "windows" ? "C:\\Windows\\System32\\drivers\\etc\\hosts" : "/etc/hosts",
+ server = require("webserver").create(),
+ page = require("webpage").create();
+
+ // Create a webserver that returns a page with an "input type=file" element
+ server.listen(12345, function(request, response) {
+ response.statusCode = 200;
+ response.write('<html><body><input type="file" id="fileup" /></body></html>');
+ response.close();
+ });
+
+ // Register "onFilePicker" handler
+ page.onFilePicker = function(oldFile) {
+ return fileToUpload;
+ };
+
+ runs(function() {
+ page.open("http://localhost:12345", function() {
+ // Before clicking on the file selector element
+ expect(page.evaluate(function() {
+ var fileUp = document.querySelector("#fileup");
+ return fileUp.files.length;
+ })).toBe(0);
+
+ // Click on file selector element, so the "onFilePicker" is invoked
+ page.evaluate(function() {
+ var fileUp = document.querySelector("#fileup");
+ var ev = document.createEvent("MouseEvents");
+ ev.initEvent("click", true, true);
+ fileUp.dispatchEvent(ev);
+ });
+
+ // After clicking on the file selector element
+ expect(page.evaluate(function() {
+ var fileUp = document.querySelector("#fileup");
+ return fileUp.files.length;
+ })).toBe(1);
+ expect(page.evaluate(function() {
+ var fileUp = document.querySelector("#fileup");
+ return fileUp.files[0].name;
+ })).toContain("hosts");
+ });
+ });
+
+ waits(100);
+
+ runs(function() {
+ server.close();
+ });
+ });
+});

0 comments on commit eadb03a

Please sign in to comment.