Bug 50660 - Drag and drop for file upload form control r=jst,enndeakin

This commit is contained in:
Michael Ventnor 2011-06-01 16:06:38 +10:00
Родитель d1ba1be886
Коммит 4d6f07caf9
4 изменённых файлов: 129 добавлений и 5 удалений

Просмотреть файл

@ -1372,6 +1372,31 @@ nsHTMLInputElement::SetFiles(const nsCOMArray<nsIDOMFile>& aFiles,
mFiles.Clear();
mFiles.AppendObjects(aFiles);
AfterSetFiles(aSetValueChanged);
}
void
nsHTMLInputElement::SetFiles(nsIDOMFileList* aFiles,
bool aSetValueChanged)
{
mFiles.Clear();
if (aFiles) {
PRUint32 listLength;
aFiles->GetLength(&listLength);
for (PRUint32 i = 0; i < listLength; i++) {
nsCOMPtr<nsIDOMFile> file;
aFiles->Item(i, getter_AddRefs(file));
mFiles.AppendObject(file);
}
}
AfterSetFiles(aSetValueChanged);
}
void
nsHTMLInputElement::AfterSetFiles(bool aSetValueChanged)
{
// No need to flush here, if there's no frame at this point we
// don't need to force creation of one just to tell it about this
// new value. We just want the display to update as needed.

Просмотреть файл

@ -145,11 +145,11 @@ public:
{
return nsGenericHTMLElement::GetEditor(aEditor);
}
// Forward nsIDOMHTMLElement
NS_FORWARD_NSIDOMHTMLELEMENT_NOFOCUSCLICK(nsGenericHTMLFormElement::)
NS_IMETHOD Focus();
NS_IMETHOD Click();
// Forward nsIDOMHTMLElement
NS_FORWARD_NSIDOMHTMLELEMENT_NOFOCUSCLICK(nsGenericHTMLFormElement::)
NS_IMETHOD Focus();
NS_IMETHOD Click();
NS_IMETHOD SetUserInput(const nsAString& aInput);
@ -218,6 +218,7 @@ public:
void GetDisplayFileName(nsAString& aFileName) const;
const nsCOMArray<nsIDOMFile>& GetFiles() const;
void SetFiles(const nsCOMArray<nsIDOMFile>& aFiles, bool aSetValueChanged);
void SetFiles(nsIDOMFileList* aFiles, bool aSetValueChanged);
void SetCheckedChangedInternal(PRBool aCheckedChanged);
PRBool GetCheckedChanged() const {
@ -457,6 +458,11 @@ protected:
*/
nsresult UpdateFileList();
/**
* Called after calling one of the SetFiles() functions.
*/
void AfterSetFiles(bool aSetValueChanged);
/**
* Determine whether the editor needs to be initialized explicitly for
* a particular event.

Просмотреть файл

@ -93,6 +93,9 @@
#include "nsDOMFile.h"
#include "nsEventStates.h"
#include "nsIDOMDOMStringList.h"
#include "nsIDOMDragEvent.h"
namespace dom = mozilla::dom;
#define SYNC_TEXT 0x1
@ -136,6 +139,15 @@ nsFileControlFrame::DestroyFrom(nsIFrame* aDestructRoot)
mTextFrame = nsnull;
ENSURE_TRUE(mContent);
// Remove the drag events
nsCOMPtr<nsIDOMEventTarget> dragTarget = do_QueryInterface(mContent);
if (dragTarget) {
dragTarget->RemoveEventListener(NS_LITERAL_STRING("drop"),
mMouseListener, PR_FALSE);
dragTarget->RemoveEventListener(NS_LITERAL_STRING("dragover"),
mMouseListener, PR_FALSE);
}
// remove mMouseListener as a mouse event listener (bug 40533, bug 355931)
NS_NAMED_LITERAL_STRING(click, "click");
@ -258,6 +270,14 @@ nsFileControlFrame::CreateAnonymousContent(nsTArray<ContentInfo>& aElements)
if (!aElements.AppendElement(mTextContent))
return NS_ERROR_OUT_OF_MEMORY;
// Register the whole frame as an event listener of drag events
nsCOMPtr<nsIDOMEventTarget> dragTarget = do_QueryInterface(mContent);
NS_ENSURE_STATE(dragTarget);
dragTarget->AddEventListener(NS_LITERAL_STRING("drop"),
mMouseListener, PR_FALSE);
dragTarget->AddEventListener(NS_LITERAL_STRING("dragover"),
mMouseListener, PR_FALSE);
NS_NAMED_LITERAL_STRING(click, "click");
nsCOMPtr<nsIDOMEventGroup> systemGroup;
mContent->GetSystemEventGroup(getter_AddRefs(systemGroup));
@ -498,6 +518,74 @@ nsFileControlFrame::BrowseMouseListener::MouseClick(nsIDOMEvent* aMouseEvent)
return input ? input->FireAsyncClickHandler() : NS_OK;
}
/**
* This is called when we receive any registered events on the control.
* We've only registered for drop, dragover and click events, and click events
* already call MouseClick() for us. Here, we handle file drops.
*/
NS_IMETHODIMP
nsFileControlFrame::BrowseMouseListener::HandleEvent(nsIDOMEvent* aEvent)
{
NS_ASSERTION(mFrame, "We should have been unregistered");
nsCOMPtr<nsIDOMNSUIEvent> uiEvent = do_QueryInterface(aEvent);
NS_ENSURE_STATE(uiEvent);
PRBool defaultPrevented = PR_FALSE;
uiEvent->GetPreventDefault(&defaultPrevented);
if (defaultPrevented) {
return NS_OK;
}
nsCOMPtr<nsIDOMDragEvent> dragEvent = do_QueryInterface(aEvent);
if (!dragEvent || !IsValidDropData(dragEvent)) {
return NS_OK;
}
nsAutoString eventType;
aEvent->GetType(eventType);
if (eventType.EqualsLiteral("dragover")) {
// Prevent default if we can accept this drag data
aEvent->PreventDefault();
return NS_OK;
}
if (eventType.EqualsLiteral("drop")) {
aEvent->StopPropagation();
aEvent->PreventDefault();
nsIContent* content = mFrame->GetContent();
NS_ASSERTION(content, "The frame has no content???");
nsHTMLInputElement* inputElement = nsHTMLInputElement::FromContent(content);
NS_ASSERTION(inputElement, "No input element for this file upload control frame!");
nsCOMPtr<nsIDOMDataTransfer> dataTransfer;
dragEvent->GetDataTransfer(getter_AddRefs(dataTransfer));
nsCOMPtr<nsIDOMFileList> fileList;
dataTransfer->GetFiles(getter_AddRefs(fileList));
inputElement->SetFiles(fileList, true);
}
return NS_OK;
}
/* static */ PRBool
nsFileControlFrame::BrowseMouseListener::IsValidDropData(nsIDOMDragEvent* aEvent)
{
nsCOMPtr<nsIDOMDataTransfer> dataTransfer;
aEvent->GetDataTransfer(getter_AddRefs(dataTransfer));
NS_ENSURE_TRUE(dataTransfer, PR_FALSE);
nsCOMPtr<nsIDOMDOMStringList> types;
dataTransfer->GetTypes(getter_AddRefs(types));
NS_ENSURE_TRUE(types, PR_FALSE);
// We only support dropping files onto a file upload control
PRBool typeSupported;
types->Contains(NS_LITERAL_STRING("Files"), &typeSupported);
return typeSupported;
}
nscoord
nsFileControlFrame::GetMinWidth(nsRenderingContext *aRenderingContext)
{

Просмотреть файл

@ -48,6 +48,8 @@
#include "nsTextControlFrame.h"
typedef nsTextControlFrame nsNewFrame;
class nsIDOMDragEvent;
class nsFileControlFrame : public nsBlockFrame,
public nsIFormControlFrame,
public nsIAnonymousContentCreator
@ -169,6 +171,9 @@ protected:
public:
BrowseMouseListener(nsFileControlFrame* aFrame) : MouseListener(aFrame) {};
NS_IMETHOD MouseClick(nsIDOMEvent* aMouseEvent);
NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent);
static PRBool IsValidDropData(nsIDOMDragEvent* aEvent);
};
virtual PRBool IsFrameOfType(PRUint32 aFlags) const