Commit 497541bd authored by adele@apple.com's avatar adele@apple.com

WebCore:

2008-10-24  Adele Peterson  <adele@apple.com>

        Reviewed by Sam Weinig.

        WebCore part of fix for <rdar://problem/5839256> FILE CONTROL: multi-file upload.

        This change adds support for multiple file selection in an <input type="file"> control when the "multiple" attribute is used.
        This is consistent with the direction HTML5 will be going in the future.

        The initial implementation here will show "n files" as the text next to the control when multiple files are selected.  You can view
        the individual files in a tooltip for now.  Improvements to this control will come later.  

        Web developers will be able to access the FileList from the HTMLInputElement element, where they can get a base name and a size for each file.  
        These FileList Files can also be sent in an XMLHTTPRequest.

        * manual-tests/post-multi-file-upload.html: Added.
        * manual-tests/resources/multiFileResources: Added.
        * manual-tests/resources/multiFileResources/post-echo-and-notify-done.cgi: Added.
        * manual-tests/resources/multiFileResources/testFile1.html: Added.
        * manual-tests/resources/multiFileResources/testFile2.html: Added.
        * manual-tests/resources/multiFileResources/testFile3.html: Added.

        * WebCore.base.exp: Added support to export the new "chooseFilenames" method to be used in WebKit.

        * html/HTMLInputElement.cpp:
        (WebCore::HTMLInputElement::parseMappedAttribute): Add support for the multiple attribute.
        (WebCore::HTMLInputElement::value): Added comments.  The HTML5 spec says that value shouldn't apply for the file upload control,
        but we don't want to break the behavior for existing websites that may rely on this.
        (WebCore::HTMLInputElement::setValue): ditto.
        (WebCore::HTMLInputElement::setValueFromRenderer): This is no longer used for file upload controls. setFileListFromRenderer is used instead.
        (WebCore::HTMLInputElement::setFileListFromRenderer): Added. 
        * html/HTMLInputElement.h:

        * page/Chrome.cpp: (WebCore::Chrome::setToolTip): Show a tooltip with the file name list for the multi-file upload control.

        * page/DragController.cpp: (WebCore::DragController::concludeDrag): Updated to support multiple files.

        * platform/FileChooser.cpp: Add support for maintaining a list of file paths that can be retrieved by the renderer.
        (WebCore::FileChooser::FileChooser):
        (WebCore::FileChooser::create):
        (WebCore::FileChooser::clear):
        (WebCore::FileChooser::chooseFile):
        (WebCore::FileChooser::chooseFiles):
        (WebCore::FileChooser::chooseIcon):
        * platform/FileChooser.h:
        (WebCore::FileChooser::filePaths):
        (WebCore::FileChooser::allowsMultipleFiles):

        * platform/graphics/Icon.h:
        * platform/graphics/mac/IconMac.mm: (WebCore::Icon::newIconForFiles): Returns a generic icon for multiple files.
        * platform/graphics/gtk/IconGtk.cpp: (WebCore::Icon::newIconForFiles): stubbed out.
        * platform/graphics/qt/IconQt.cpp: (WebCore::Icon::newIconForFiles): ditto.
        * platform/graphics/win/IconWin.cpp: (WebCore::Icon::newIconForFiles): ditto.

        * platform/gtk/FileChooserGtk.cpp: (WebCore::FileChooser::basenameForWidth):  Updated to deal with new filenames vector.
        * platform/mac/FileChooserMac.mm: (WebCore::FileChooser::basenameForWidth): ditto.
        * platform/qt/FileChooserQt.cpp:
        (WebCore::FileChooser::openFileChooser):
        (WebCore::FileChooser::basenameForWidth):
        * platform/win/FileChooserWin.cpp: (WebCore::FileChooser::basenameForWidth):

        * platform/network/mac/FormDataStreamMac.mm: (WebCore::disassociateStreamWithResourceHandle):
        Removed unnecessary assertion.  This can get hit when connectionDidFinishLoading and cancel
        both get called for the same ResourceHandle.  This getting called twice has no negative effect.

        * rendering/RenderFileUploadControl.cpp:
        (WebCore::RenderFileUploadControl::valueChanged):  Calls setFileListFromRenderer.
        (WebCore::RenderFileUploadControl::allowsMultipleFiles):  Added.
        (WebCore::RenderFileUploadControl::updateFromElement):  Uses the new filenames call from FileChooser.
        (WebCore::RenderFileUploadControl::receiveDroppedFiles):  Updated to support multiple files.
        * rendering/RenderFileUploadControl.h:

WebKit/mac:

2008-10-24  Adele Peterson  <adele@apple.com>

        Reviewed by Sam Weinig.

        WebKit part of fix for <rdar://problem/5839256> FILE CONTROL: multi-file upload.

        * WebCoreSupport/WebChromeClient.mm:
        (WebChromeClient::runOpenPanel):
        (-[WebOpenPanelResultListener chooseFilenames:]):
        * WebView/WebUIDelegate.h:



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@37863 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent a9835031
2008-10-24 Adele Peterson <adele@apple.com>
Reviewed by Sam Weinig.
WebCore part of fix for <rdar://problem/5839256> FILE CONTROL: multi-file upload.
This change adds support for multiple file selection in an <input type="file"> control when the "multiple" attribute is used.
This is consistent with the direction HTML5 will be going in the future.
The initial implementation here will show "n files" as the text next to the control when multiple files are selected. You can view
the individual files in a tooltip for now. Improvements to this control will come later.
Web developers will be able to access the FileList from the HTMLInputElement element, where they can get a base name and a size for each file.
These FileList Files can also be sent in an XMLHTTPRequest.
* manual-tests/post-multi-file-upload.html: Added.
* manual-tests/resources/multiFileResources: Added.
* manual-tests/resources/multiFileResources/post-echo-and-notify-done.cgi: Added.
* manual-tests/resources/multiFileResources/testFile1.html: Added.
* manual-tests/resources/multiFileResources/testFile2.html: Added.
* manual-tests/resources/multiFileResources/testFile3.html: Added.
* WebCore.base.exp: Added support to export the new "chooseFilenames" method to be used in WebKit.
* html/HTMLInputElement.cpp:
(WebCore::HTMLInputElement::parseMappedAttribute): Add support for the multiple attribute.
(WebCore::HTMLInputElement::value): Added comments. The HTML5 spec says that value shouldn't apply for the file upload control,
but we don't want to break the behavior for existing websites that may rely on this.
(WebCore::HTMLInputElement::setValue): ditto.
(WebCore::HTMLInputElement::setValueFromRenderer): This is no longer used for file upload controls. setFileListFromRenderer is used instead.
(WebCore::HTMLInputElement::setFileListFromRenderer): Added.
* html/HTMLInputElement.h:
* page/Chrome.cpp: (WebCore::Chrome::setToolTip): Show a tooltip with the file name list for the multi-file upload control.
* page/DragController.cpp: (WebCore::DragController::concludeDrag): Updated to support multiple files.
* platform/FileChooser.cpp: Add support for maintaining a list of file paths that can be retrieved by the renderer.
(WebCore::FileChooser::FileChooser):
(WebCore::FileChooser::create):
(WebCore::FileChooser::clear):
(WebCore::FileChooser::chooseFile):
(WebCore::FileChooser::chooseFiles):
(WebCore::FileChooser::chooseIcon):
* platform/FileChooser.h:
(WebCore::FileChooser::filePaths):
(WebCore::FileChooser::allowsMultipleFiles):
* platform/graphics/Icon.h:
* platform/graphics/mac/IconMac.mm: (WebCore::Icon::newIconForFiles): Returns a generic icon for multiple files.
* platform/graphics/gtk/IconGtk.cpp: (WebCore::Icon::newIconForFiles): stubbed out.
* platform/graphics/qt/IconQt.cpp: (WebCore::Icon::newIconForFiles): ditto.
* platform/graphics/win/IconWin.cpp: (WebCore::Icon::newIconForFiles): ditto.
* platform/gtk/FileChooserGtk.cpp: (WebCore::FileChooser::basenameForWidth): Updated to deal with new filenames vector.
* platform/mac/FileChooserMac.mm: (WebCore::FileChooser::basenameForWidth): ditto.
* platform/qt/FileChooserQt.cpp:
(WebCore::FileChooser::openFileChooser):
(WebCore::FileChooser::basenameForWidth):
* platform/win/FileChooserWin.cpp: (WebCore::FileChooser::basenameForWidth):
* platform/network/mac/FormDataStreamMac.mm: (WebCore::disassociateStreamWithResourceHandle):
Removed unnecessary assertion. This can get hit when connectionDidFinishLoading and cancel
both get called for the same ResourceHandle. This getting called twice has no negative effect.
* rendering/RenderFileUploadControl.cpp:
(WebCore::RenderFileUploadControl::valueChanged): Calls setFileListFromRenderer.
(WebCore::RenderFileUploadControl::allowsMultipleFiles): Added.
(WebCore::RenderFileUploadControl::updateFromElement): Uses the new filenames call from FileChooser.
(WebCore::RenderFileUploadControl::receiveDroppedFiles): Updated to support multiple files.
* rendering/RenderFileUploadControl.h:
2008-10-23 Peter Kasting <pkasting@google.com>
Reviewed by David Hyatt.
......
......@@ -139,6 +139,7 @@ __ZN7WebCore11ContextMenu22setPlatformDescriptionEP14NSMutableArray
__ZN7WebCore11EditCommand7reapplyEv
__ZN7WebCore11EditCommand7unapplyEv
__ZN7WebCore11FileChooser10chooseFileERKNS_6StringE
__ZN7WebCore11FileChooser11chooseFilesERKN3WTF6VectorINS_6StringELm0EEE
__ZN7WebCore11FileChooserD1Ev
__ZN7WebCore11FrameLoader11completeURLERKNS_6StringE
__ZN7WebCore11FrameLoader11loadArchiveEN3WTF10PassRefPtrINS_7ArchiveEEE
......@@ -874,6 +875,7 @@ __ZNK7WebCore9Selection23isContentRichlyEditableEv
__ZNK7WebCore9Selection7toRangeEv
__ZNK7WebCore9TimerBase8isActiveEv
__ZTVN7WebCore12ChromeClientE
__ZTVN7WebCore17FileChooserClientE
_filenameByFixingIllegalCharacters
_hasCaseInsensitiveSubstring
_hasCaseInsensitiveSuffix
......
......@@ -698,9 +698,10 @@ void HTMLInputElement::parseMappedAttribute(MappedAttribute *attr)
attr->name() == incrementalAttr ||
attr->name() == minAttr ||
attr->name() == maxAttr ||
attr->name() == precisionAttr) {
attr->name() == multipleAttr ||
attr->name() == precisionAttr)
setChanged();
} else
else
HTMLFormControlElementWithState::parseMappedAttribute(attr);
}
......@@ -950,6 +951,8 @@ void HTMLInputElement::copyNonAttributeProperties(const Element *source)
String HTMLInputElement::value() const
{
// The HTML5 spec (as of the 10/24/08 working draft) says that the value attribute isn't applicable to the file upload control
// but we don't want to break existing websites, who may be relying on being able to get the file name as a value.
if (inputType() == FILE) {
if (!m_fileList->isEmpty())
return m_fileList->item(0)->fileName();
......@@ -999,6 +1002,8 @@ String HTMLInputElement::valueWithDefault() const
void HTMLInputElement::setValue(const String& value)
{
// For security reasons, we don't allow setting the filename, but we do allow clearing it.
// The HTML5 spec (as of the 10/24/08 working draft) says that the value attribute isn't applicable to the file upload control
// but we don't want to break existing websites, who may be relying on this method to clear things.
if (inputType() == FILE && !value.isEmpty())
return;
......@@ -1036,21 +1041,19 @@ void HTMLInputElement::setValueFromRenderer(const String& value)
// Renderer and our event handler are responsible for constraining values.
ASSERT(value == constrainValue(value) || constrainValue(value).isEmpty());
// File upload controls will always use setFileListFromRenderer.
ASSERT (inputType() != FILE);
if (isTextField())
updatePlaceholderVisibility();
if (inputType() == FILE) {
m_fileList->clear();
m_fileList->append(File::create(value));
} else {
// Workaround for bug where trailing \n is included in the result of textContent.
// The assert macro above may also be simplified to: value == constrainValue(value)
// http://bugs.webkit.org/show_bug.cgi?id=9661
if (value == "\n")
m_value = "";
else
m_value = value;
}
// Workaround for bug where trailing \n is included in the result of textContent.
// The assert macro above may also be simplified to: value == constrainValue(value)
// http://bugs.webkit.org/show_bug.cgi?id=9661
if (value == "\n")
m_value = "";
else
m_value = value;
setValueMatchesRenderer();
......@@ -1058,6 +1061,16 @@ void HTMLInputElement::setValueFromRenderer(const String& value)
dispatchEventForType(inputEvent, true, false);
}
void HTMLInputElement::setFileListFromRenderer(const Vector<String>& paths)
{
m_fileList->clear();
int size = paths.size();
for (int i = 0; i < size; i++)
m_fileList->append(File::create(paths[i]));
setValueMatchesRenderer();
}
bool HTMLInputElement::storesValueSeparateFromAttribute() const
{
switch (inputType()) {
......
......@@ -108,6 +108,7 @@ public:
String valueWithDefault() const;
void setValueFromRenderer(const String&);
void setFileListFromRenderer(const Vector<String>&);
virtual bool saveState(String& value) const;
virtual void restoreState(const String&);
......
<html>
<head>
<script type="text/javascript">
var submittedFiles = 0;
function log(message)
{
document.getElementById('console').appendChild(document.createTextNode(message + "\n"));
}
function verifyResults()
{
if (submittedFiles == 3) {
var frame = document.getElementById('fr');
frame.parentNode.removeChild(frame);
log("Test Passed");
} else
log("Test Failed");
}
</script>
</head>
<body onload="test()">
<p>
This tests that the multi-file upload control works correctly. This test and the resources/multiFileResources must be placed on a web server so the test can be run manually.<br>
Choose "testFile1.html" "testFile2.html" and "testFile3.html" and submit the form. <br>
You should see a "Test Passed" or a "Test Failed" message after submitting the form.<br>
</p>
<form method="post" enctype="multipart/form-data" action="resources/multiFileResources/post-echo-and-notify-done.cgi" id="myForm" target="targetFrame">
<input type="file" id="target" multiple name="multiFileInput"></input>
<input type="submit" value="Submit">
</form>
<iframe name="targetFrame" id="fr"></iframe>
<pre id='console'></pre>
</body>
</html>
#!/usr/bin/perl -w
print "Content-type: text/html\n\n";
if ($ENV{'REQUEST_METHOD'} eq "POST") {
read(STDIN, $request, $ENV{'CONTENT_LENGTH'})
|| die "Could not get query\n";
print "<pre>$request</pre>";
print "<script>if (window.layoutTestController) layoutTestController.notifyDone();</script>";
} else {
print "Wrong method: " . $ENV{'REQUEST_METHOD'} . "\n";
}
<script>
parent.log('test file 1 submitted');
parent.submittedFiles++;
</script>
\ No newline at end of file
<script>
parent.log('test file 2 submitted');
parent.submittedFiles++;
</script>
\ No newline at end of file
<script>
parent.log('test file 3 submitted');
parent.submittedFiles++;
parent.verifyResults();
</script>
\ No newline at end of file
......@@ -24,6 +24,7 @@
#include "ChromeClient.h"
#include "DNS.h"
#include "Document.h"
#include "FileList.h"
#include "FloatRect.h"
#include "Frame.h"
#include "FrameTree.h"
......@@ -350,10 +351,32 @@ void Chrome::setToolTip(const HitTestResult& result)
toolTip = result.absoluteLinkURL().string();
}
// Lastly we'll consider a tooltip for element with "title" attribute
// Next we'll consider a tooltip for element with "title" attribute
if (toolTip.isEmpty())
toolTip = result.title();
// Lastly, for <input type="file"> that allow multiple files, we'll consider a tooltip for the selected filenames
if (toolTip.isEmpty()) {
if (Node* node = result.innerNonSharedNode()) {
if (node->hasTagName(inputTag)) {
HTMLInputElement* input = static_cast<HTMLInputElement*>(node);
if (input->inputType() == HTMLInputElement::FILE) {
FileList* files = input->files();
unsigned listSize = files->length();
if (files && listSize > 1) {
Vector<UChar> names;
for (size_t i = 0; i < listSize; ++i) {
append(names, files->item(i)->fileName());
if (i != listSize - 1)
names.append('\n');
}
toolTip = String::adopt(names);
}
}
}
}
}
m_client->setToolTip(toolTip);
}
......
......@@ -380,8 +380,7 @@ bool DragController::concludeDrag(DragData* dragData, DragDestinationAction acti
if (!renderer)
return false;
// Only take the first filename as <input type="file" /> can only accept one
renderer->receiveDroppedFile(filenames[0]);
renderer->receiveDroppedFiles(filenames);
return true;
}
......
......@@ -35,9 +35,9 @@ namespace WebCore {
inline FileChooser::FileChooser(FileChooserClient* client, const String& filename)
: m_client(client)
, m_filename(filename)
, m_icon(chooseIcon(filename))
{
m_filenames.append(filename);
}
PassRefPtr<FileChooser> FileChooser::create(FileChooserClient* client, const String& filename)
......@@ -51,23 +51,39 @@ FileChooser::~FileChooser()
void FileChooser::clear()
{
m_filename = String();
m_icon = chooseIcon(m_filename);
m_filenames.clear();
m_icon = 0;
}
void FileChooser::chooseFile(const String& filename)
{
if (m_filename == filename)
if (m_filenames.size() == 1 && m_filenames[0] == filename)
return;
m_filename = filename;
m_filenames.clear();
m_filenames.append(filename);
m_icon = chooseIcon(filename);
if (m_client)
m_client->valueChanged();
}
void FileChooser::chooseFiles(const Vector<String>& filenames)
{
m_filenames = filenames;
m_icon = chooseIcon(filenames);
if (m_client)
m_client->valueChanged();
}
PassRefPtr<Icon> FileChooser::chooseIcon(const String& filename)
{
return Icon::newIconForFile(filename);
}
PassRefPtr<Icon> FileChooser::chooseIcon(Vector<String> filenames)
{
if (filenames.size() == 1)
return Icon::newIconForFile(filenames[0]);
return Icon::newIconForFiles(filenames);
}
}
......@@ -31,6 +31,7 @@
#define FileChooser_h
#include "PlatformString.h"
#include <wtf/Vector.h>
namespace WebCore {
......@@ -42,6 +43,7 @@ class FileChooserClient {
public:
virtual ~FileChooserClient() { }
virtual void valueChanged() = 0;
virtual bool allowsMultipleFiles() = 0;
};
class FileChooser : public RefCounted<FileChooser> {
......@@ -59,21 +61,25 @@ public:
// the Chrome class instead.
void openFileChooser(Document*);
const String& filename() const { return m_filename; }
const Vector<String>& filenames() const { return m_filenames; }
String basenameForWidth(const Font&, int width) const;
Icon* icon() const { return m_icon.get(); }
void clear(); // for use by client; does not call valueChanged
void chooseFile(const String& filename);
void chooseFile(const String& path);
void chooseFiles(const Vector<String>& paths);
bool allowsMultipleFiles() const { return m_client ? m_client->allowsMultipleFiles() : false; }
private:
FileChooser(FileChooserClient*, const String& initialFilename);
FileChooser(FileChooserClient*, const String& initialfilename);
static PassRefPtr<Icon> chooseIcon(const String& filename);
static PassRefPtr<Icon> chooseIcon(Vector<String> filenames);
FileChooserClient* m_client;
String m_filename;
Vector<String> m_filenames;
RefPtr<Icon> m_icon;
};
......
......@@ -24,6 +24,7 @@
#include <wtf/PassRefPtr.h>
#include <wtf/RefCounted.h>
#include <wtf/Forward.h>
#include <wtf/Vector.h>
#if PLATFORM(MAC)
#include <wtf/RetainPtr.h>
......@@ -51,6 +52,8 @@ class String;
class Icon : public RefCounted<Icon> {
public:
static PassRefPtr<Icon> newIconForFile(const String& filename);
static PassRefPtr<Icon> newIconForFiles(const Vector<String>& filenames);
~Icon();
void paint(GraphicsContext*, const IntRect&);
......
......@@ -103,6 +103,12 @@ PassRefPtr<Icon> Icon::newIconForFile(const String& filename)
return icon.release();
}
PassRefPtr<Icon> Icon::newIconForFiles(const Vector<String>& filenames)
{
//FIXME: Implement this
return 0;
}
void Icon::paint(GraphicsContext* context, const IntRect& rect)
{
if (context->paintingDisabled())
......
......@@ -53,6 +53,18 @@ PassRefPtr<Icon> Icon::newIconForFile(const String& filename)
return adoptRef(new Icon(image));
}
PassRefPtr<Icon> Icon::newIconForFiles(const Vector<String>& filenames)
{
if (filenames.isEmpty())
return 0;
NSImage* image = [NSImage imageNamed:NSImageNameMultipleDocuments];
if (!image)
return 0;
return adoptRef(new Icon(image));
}
void Icon::paint(GraphicsContext* context, const IntRect& rect)
{
if (context->paintingDisabled())
......
......@@ -48,6 +48,12 @@ PassRefPtr<Icon> Icon::newIconForFile(const String& filename)
return i.release();
}
PassRefPtr<Icon> Icon::newIconForFiles(const Vector<String>& filenames)
{
//FIXME: Implement this
return 0;
}
void Icon::paint(GraphicsContext* ctx, const IntRect& rect)
{
QPixmap px = m_icon.pixmap(rect.size());
......
......@@ -50,6 +50,12 @@ PassRefPtr<Icon> Icon::newIconForFile(const String& filename)
return adoptRef(new Icon(sfi.hIcon));
}
PassRefPtr<Icon> Icon::newIconForFiles(const Vector<String>& filenames)
{
//FIXME: Implement this
return 0;
}
void Icon::paint(GraphicsContext* context, const IntRect& r)
{
if (context->paintingDisabled())
......
......@@ -84,12 +84,13 @@ String FileChooser::basenameForWidth(const Font& font, int width) const
String string = fileButtonNoFileSelectedLabel();
if (!m_filename.isEmpty()) {
gchar* systemFilename = filenameFromString(m_filename);
if (m_filenames.size() == 1) {
gchar* systemFilename = filenameFromString(m_filenames[0]);
gchar* systemBasename = g_path_get_basename(systemFilename);
g_free(systemFilename);
stringByAdoptingFileSystemRepresentation(systemBasename, string);
}
} else if (m_filenames.size() > 1)
return StringTruncator::rightTruncate(String::number(m_filenames.size()) + " files", width, font, false);
return StringTruncator::centerTruncate(string, width, font, false);
}
......
......@@ -58,10 +58,12 @@ String FileChooser::basenameForWidth(const Font& font, int width) const
return String();
String strToTruncate;
if (m_filename.isEmpty())
if (m_filenames.isEmpty())
strToTruncate = fileButtonNoFileSelectedLabel();
else if (m_filenames.size() == 1)
strToTruncate = [[NSFileManager defaultManager] displayNameAtPath:(m_filenames[0])];
else
strToTruncate = [[NSFileManager defaultManager] displayNameAtPath:m_filename];
return StringTruncator::rightTruncate(String::number(m_filenames.size()) + " files", width, font, false);
return StringTruncator::centerTruncate(strToTruncate, width, font, false);
}
......
......@@ -83,7 +83,6 @@ void disassociateStreamWithResourceHandle(NSInputStream *stream)
if (!stream)
return;
ASSERT(getStreamResourceHandleMap().contains((CFReadStreamRef)stream));
getStreamResourceHandleMap().remove((CFReadStreamRef)stream);
}
......
......@@ -42,7 +42,7 @@ void FileChooser::openFileChooser(Document* doc)
if (!fl)
return;
QString f = fl->chooseFile(m_filename);
QString f = fl->chooseFile(m_filenames[0]);
if (!f.isEmpty())
chooseFile(f);
}
......@@ -50,7 +50,7 @@ void FileChooser::openFileChooser(Document* doc)
String FileChooser::basenameForWidth(const Font& f, int width) const
{
QFontMetrics fm(f.font());
return fm.elidedText(m_filename, Qt::ElideLeft, width);
return fm.elidedText(m_filenames[0], Qt::ElideLeft, width);
}
}
......
......@@ -80,13 +80,14 @@ String FileChooser::basenameForWidth(const Font& font, int width) const
return String();
String string;
if (m_filename.isEmpty())
if (m_filenames.isEmpty())
string = fileButtonNoFileSelectedLabel();
else {
String tmpFilename = m_filename;
else if (m_filenames.size() == 1) {
String tmpFilename = m_filenames[0];
LPTSTR basename = PathFindFileName(tmpFilename.charactersWithNullTermination());
string = String(basename);
}
} else
return StringTruncator::rightTruncate(String::number(m_filenames.size()) + " files", width, font, false);
return StringTruncator::centerTruncate(string, width, font, false);
}
......
......@@ -21,6 +21,7 @@
#include "config.h"
#include "RenderFileUploadControl.h"
#include "FileList.h"
#include "FrameView.h"
#include "GraphicsContext.h"
#include "HTMLInputElement.h"
......@@ -86,7 +87,7 @@ void RenderFileUploadControl::valueChanged()
RefPtr<FileChooser> fileChooser = m_fileChooser;
HTMLInputElement* inputElement = static_cast<HTMLInputElement*>(node());
inputElement->setValueFromRenderer(fileChooser->filename());
inputElement->setFileListFromRenderer(fileChooser->filenames());
inputElement->onChange();
// only repaint if it doesn't seem we have been destroyed
......@@ -94,6 +95,12 @@ void RenderFileUploadControl::valueChanged()
repaint();
}
bool RenderFileUploadControl::allowsMultipleFiles()
{
HTMLInputElement* input = static_cast<HTMLInputElement*>(node());
return !input->getAttribute(multipleAttr).isNull();
}
void RenderFileUploadControl::click()
{
m_fileChooser->openFileChooser(node()->document());
......@@ -102,7 +109,8 @@ void RenderFileUploadControl::click()
void RenderFileUploadControl::updateFromElement()
{
HTMLInputElement* inputElement = static_cast<HTMLInputElement*>(node());
ASSERT(inputElement->inputType() == HTMLInputElement::FILE);
if (!m_button) {
m_button = new HTMLFileUploadInnerButtonElement(document(), inputElement);
m_button->setInputType("button");
......@@ -120,9 +128,11 @@ void RenderFileUploadControl::updateFromElement()
m_button->setDisabled(!theme()->isEnabled(this));
// This only supports clearing out the filename, but that's OK because for
// This only supports clearing out the files, but that's OK because for
// security reasons that's the only change the DOM is allowed to make.
if (inputElement->value().isEmpty() && !m_fileChooser->filename().isEmpty()) {
FileList* files = inputElement->files();
ASSERT(files);
if (files && files->isEmpty() && !m_fileChooser->filenames().isEmpty()) {
m_fileChooser->clear();
repaint();
}
......@@ -251,9 +261,12 @@ void RenderFileUploadControl::calcPrefWidths()
setPrefWidthsDirty(false);
}
void RenderFileUploadControl::receiveDroppedFile(const String& filename)
void RenderFileUploadControl::receiveDroppedFiles(const Vector<String>& paths)
{
m_fileChooser->chooseFile(filename);
if (allowsMultipleFiles())
m_fileChooser->chooseFiles(paths);
else
m_fileChooser->chooseFile(paths[0]);
}
String RenderFileUploadControl::buttonValue()
......
......@@ -47,10 +47,12 @@ public:
void valueChanged();
void receiveDroppedFile(const String&);
void receiveDroppedFiles(const Vector<String>&);
String buttonValue();
String fileTextValue();
bool allowsMultipleFiles();
protected:
virtual void styleDidChange(RenderStyle::Diff, const RenderStyle* oldStyle);
......
2008-10-24 Adele Peterson <adele@apple.com>
Reviewed by Sam Weinig.
WebKit part of fix for <rdar://problem/5839256> FILE CONTROL: multi-file upload.
* WebCoreSupport/WebChromeClient.mm:
(WebChromeClient::runOpenPanel):
(-[WebOpenPanelResultListener chooseFilenames:]):
* WebView/WebUIDelegate.h:
2008-10-24 Timothy Hatcher <timothy@apple.com>
Implement new InspectorClient methods to work with Settings.
......
......@@ -58,6 +58,7 @@
#import <WebCore/Widget.h>
#import <WebCore/WindowFeatures.h>
#import <wtf/PassRefPtr.h>
#import <wtf/Vector.h>
@interface NSView (WebNSViewDetails)
- (NSView *)_findLastViewInKeyViewLoop;
......@@ -546,8 +547,13 @@ void WebChromeClient::paintCustomHighlight(Node* node, const AtomicString& type,
void WebChromeClient::runOpenPanel(PassRefPtr<FileChooser> chooser)
{
BEGIN_BLOCK_OBJC_EXCEPTIONS;