Bug 539476, use the system event group for editor drop listeners, so that the default action can be prevented, r=smaug

This commit is contained in:
Neil Deakin 2010-04-18 14:27:20 -04:00
Родитель f6cd0b6d60
Коммит cfa97b3d01
2 изменённых файлов: 73 добавлений и 70 удалений

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

@ -374,16 +374,16 @@ nsEditor::InstallEventListeners()
nsCOMPtr<nsIDOMEventTarget> target(do_QueryInterface(piTarget)); nsCOMPtr<nsIDOMEventTarget> target(do_QueryInterface(piTarget));
if (target) { if (target) {
// See bug 455215, we cannot use the standard dragstart event yet // See bug 455215, we cannot use the standard dragstart event yet
rv |= target->AddEventListener(NS_LITERAL_STRING("draggesture"), rv |= elmP->AddEventListenerByType(mEventListener, NS_LITERAL_STRING("draggesture"),
mEventListener, PR_FALSE); NS_EVENT_FLAG_BUBBLE, sysGroup);
rv |= target->AddEventListener(NS_LITERAL_STRING("dragenter"), rv |= elmP->AddEventListenerByType(mEventListener, NS_LITERAL_STRING("dragenter"),
mEventListener, PR_FALSE); NS_EVENT_FLAG_BUBBLE, sysGroup);
rv |= target->AddEventListener(NS_LITERAL_STRING("dragover"), rv |= elmP->AddEventListenerByType(mEventListener, NS_LITERAL_STRING("dragover"),
mEventListener, PR_FALSE); NS_EVENT_FLAG_BUBBLE, sysGroup);
rv |= target->AddEventListener(NS_LITERAL_STRING("dragleave"), rv |= elmP->AddEventListenerByType(mEventListener, NS_LITERAL_STRING("dragleave"),
mEventListener, PR_FALSE); NS_EVENT_FLAG_BUBBLE, sysGroup);
rv |= target->AddEventListener(NS_LITERAL_STRING("drop"), rv |= elmP->AddEventListenerByType(mEventListener, NS_LITERAL_STRING("drop"),
mEventListener, PR_FALSE); NS_EVENT_FLAG_BUBBLE, sysGroup);
} }
if (NS_FAILED(rv)) if (NS_FAILED(rv))
@ -417,9 +417,17 @@ nsEditor::RemoveEventListeners()
{ {
elmP->RemoveEventListenerByType(mEventListener, elmP->RemoveEventListenerByType(mEventListener,
NS_LITERAL_STRING("keypress"), NS_LITERAL_STRING("keypress"),
NS_EVENT_FLAG_BUBBLE | NS_EVENT_FLAG_BUBBLE, sysGroup);
NS_PRIV_EVENT_UNTRUSTED_PERMITTED, elmP->RemoveEventListenerByType(mEventListener, NS_LITERAL_STRING("draggesture"),
sysGroup); NS_EVENT_FLAG_BUBBLE, sysGroup);
elmP->RemoveEventListenerByType(mEventListener, NS_LITERAL_STRING("dragenter"),
NS_EVENT_FLAG_BUBBLE, sysGroup);
elmP->RemoveEventListenerByType(mEventListener, NS_LITERAL_STRING("dragover"),
NS_EVENT_FLAG_BUBBLE, sysGroup);
elmP->RemoveEventListenerByType(mEventListener, NS_LITERAL_STRING("dragleave"),
NS_EVENT_FLAG_BUBBLE, sysGroup);
elmP->RemoveEventListenerByType(mEventListener, NS_LITERAL_STRING("drop"),
NS_EVENT_FLAG_BUBBLE, sysGroup);
} }
piTarget->RemoveEventListenerByIID(mEventListener, piTarget->RemoveEventListenerByIID(mEventListener,
@ -434,20 +442,6 @@ nsEditor::RemoveEventListeners()
piTarget->RemoveEventListenerByIID(mEventListener, piTarget->RemoveEventListenerByIID(mEventListener,
NS_GET_IID(nsIDOMCompositionListener)); NS_GET_IID(nsIDOMCompositionListener));
nsCOMPtr<nsIDOMEventTarget> target(do_QueryInterface(piTarget));
if (target) {
target->RemoveEventListener(NS_LITERAL_STRING("draggesture"),
mEventListener, PR_FALSE);
target->RemoveEventListener(NS_LITERAL_STRING("dragenter"),
mEventListener, PR_FALSE);
target->RemoveEventListener(NS_LITERAL_STRING("dragover"),
mEventListener, PR_FALSE);
target->RemoveEventListener(NS_LITERAL_STRING("dragleave"),
mEventListener, PR_FALSE);
target->RemoveEventListener(NS_LITERAL_STRING("drop"),
mEventListener, PR_FALSE);
}
} }
} }

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

@ -41,6 +41,7 @@
#include "nsEditor.h" #include "nsEditor.h"
#include "nsIPlaintextEditor.h" #include "nsIPlaintextEditor.h"
#include "nsIDOMDOMStringList.h"
#include "nsIDOMEvent.h" #include "nsIDOMEvent.h"
#include "nsIDOMNSEvent.h" #include "nsIDOMNSEvent.h"
#include "nsIDOMDocument.h" #include "nsIDOMDocument.h"
@ -73,6 +74,7 @@
#include "nsIDOMDragEvent.h" #include "nsIDOMDragEvent.h"
#include "nsIFocusManager.h" #include "nsIFocusManager.h"
#include "nsIDOMWindow.h" #include "nsIDOMWindow.h"
#include "nsContentUtils.h"
nsEditorEventListener::nsEditorEventListener(nsEditor* aEditor) : nsEditorEventListener::nsEditorEventListener(nsEditor* aEditor) :
mEditor(aEditor), mCaretDrawn(PR_FALSE), mCommitText(PR_FALSE), mEditor(aEditor), mCaretDrawn(PR_FALSE), mCommitText(PR_FALSE),
@ -488,19 +490,14 @@ nsEditorEventListener::DragEnter(nsIDOMDragEvent* aDragEvent)
nsresult nsresult
nsEditorEventListener::DragOver(nsIDOMDragEvent* aDragEvent) nsEditorEventListener::DragOver(nsIDOMDragEvent* aDragEvent)
{ {
// XXX cache this between drag events?
nsresult rv;
nsCOMPtr<nsIDragService> dragService = do_GetService("@mozilla.org/widget/dragservice;1", &rv);
if (!dragService) return rv;
// does the drag have flavors we can accept?
nsCOMPtr<nsIDragSession> dragSession;
dragService->GetCurrentSession(getter_AddRefs(dragSession));
if (!dragSession) return NS_ERROR_FAILURE;
nsCOMPtr<nsIDOMNode> parent; nsCOMPtr<nsIDOMNode> parent;
nsCOMPtr<nsIDOMNSUIEvent> nsuiEvent = do_QueryInterface(aDragEvent); nsCOMPtr<nsIDOMNSUIEvent> nsuiEvent = do_QueryInterface(aDragEvent);
if (nsuiEvent) { if (nsuiEvent) {
PRBool defaultPrevented;
nsuiEvent->GetPreventDefault(&defaultPrevented);
if (defaultPrevented)
return NS_OK;
nsuiEvent->GetRangeParent(getter_AddRefs(parent)); nsuiEvent->GetRangeParent(getter_AddRefs(parent));
nsCOMPtr<nsIContent> dropParent = do_QueryInterface(parent); nsCOMPtr<nsIContent> dropParent = do_QueryInterface(parent);
if (!dropParent) if (!dropParent)
@ -511,18 +508,14 @@ nsEditorEventListener::DragOver(nsIDOMDragEvent* aDragEvent)
} }
PRBool canDrop = CanDrop(aDragEvent); PRBool canDrop = CanDrop(aDragEvent);
dragSession->SetCanDrop(canDrop);
if (canDrop) if (canDrop)
{ {
// We need to consume the event to prevent the browser's
// default drag listeners from being fired. (Bug 199133)
aDragEvent->PreventDefault(); // consumed aDragEvent->PreventDefault(); // consumed
if (mCaret && nsuiEvent) if (mCaret && nsuiEvent)
{ {
PRInt32 offset = 0; PRInt32 offset = 0;
rv = nsuiEvent->GetRangeOffset(&offset); nsresult rv = nsuiEvent->GetRangeOffset(&offset);
if (NS_FAILED(rv)) return rv; if (NS_FAILED(rv)) return rv;
// to avoid flicker, we could track the node and offset to see if we moved // to avoid flicker, we could track the node and offset to see if we moved
@ -586,6 +579,11 @@ nsEditorEventListener::Drop(nsIDOMDragEvent* aMouseEvent)
nsCOMPtr<nsIDOMNSUIEvent> nsuiEvent = do_QueryInterface(aMouseEvent); nsCOMPtr<nsIDOMNSUIEvent> nsuiEvent = do_QueryInterface(aMouseEvent);
if (nsuiEvent) { if (nsuiEvent) {
PRBool defaultPrevented;
nsuiEvent->GetPreventDefault(&defaultPrevented);
if (defaultPrevented)
return NS_OK;
nsCOMPtr<nsIDOMNode> parent; nsCOMPtr<nsIDOMNode> parent;
nsuiEvent->GetRangeParent(getter_AddRefs(parent)); nsuiEvent->GetRangeParent(getter_AddRefs(parent));
nsCOMPtr<nsIContent> dropParent = do_QueryInterface(parent); nsCOMPtr<nsIContent> dropParent = do_QueryInterface(parent);
@ -628,43 +626,54 @@ nsEditorEventListener::CanDrop(nsIDOMDragEvent* aEvent)
return PR_FALSE; return PR_FALSE;
} }
// XXX cache this between drag events? nsCOMPtr<nsIDOMDataTransfer> dataTransfer;
nsresult rv; aEvent->GetDataTransfer(getter_AddRefs(dataTransfer));
nsCOMPtr<nsIDragService> dragService = do_GetService("@mozilla.org/widget/dragservice;1", &rv); if (!dataTransfer)
return PR_FALSE;
// does the drag have flavors we can accept? nsCOMPtr<nsIDOMDOMStringList> types;
nsCOMPtr<nsIDragSession> dragSession; dataTransfer->GetTypes(getter_AddRefs(types));
if (dragService) if (!types)
dragService->GetCurrentSession(getter_AddRefs(dragSession)); return PR_FALSE;
if (!dragSession) return PR_FALSE;
PRBool flavorSupported = PR_FALSE; // Plaintext editors only support dropping text. Otherwise, HTML and files
dragSession->IsDataFlavorSupported(kUnicodeMime, &flavorSupported); // can be dropped as well.
PRBool typeSupported;
if (!flavorSupported) types->Contains(NS_LITERAL_STRING(kTextMime), &typeSupported);
dragSession->IsDataFlavorSupported(kMozTextInternal, &flavorSupported); if (!typeSupported) {
types->Contains(NS_LITERAL_STRING(kMozTextInternal), &typeSupported);
// if we aren't plaintext editing, we can accept more flavors if (!typeSupported && !editor->IsPlaintextEditor()) {
if (!flavorSupported && !editor->IsPlaintextEditor()) types->Contains(NS_LITERAL_STRING(kHTMLMime), &typeSupported);
{ if (!typeSupported) {
dragSession->IsDataFlavorSupported(kHTMLMime, &flavorSupported); types->Contains(NS_LITERAL_STRING(kFileMime), &typeSupported);
if (!flavorSupported) }
dragSession->IsDataFlavorSupported(kFileMime, &flavorSupported); }
#if 0
if (!flavorSupported)
dragSession->IsDataFlavorSupported(kJPEGImageMime, &flavorSupported);
#endif
} }
if (!flavorSupported) if (!typeSupported)
return PR_FALSE; return PR_FALSE;
nsCOMPtr<nsIDOMNSDataTransfer> dataTransferNS(do_QueryInterface(dataTransfer));
if (!dataTransferNS)
return PR_FALSE;
// If there is no source node, this is probably an external drag and the
// drop is allowed. The later checks rely on checking if the drag target
// is the same as the drag source.
nsCOMPtr<nsIDOMNode> sourceNode;
dataTransferNS->GetMozSourceNode(getter_AddRefs(sourceNode));
if (!sourceNode)
return PR_TRUE;
// There is a source node, so compare the source documents and this document.
// Disallow drops on the same document.
nsCOMPtr<nsIDOMDocument> domdoc; nsCOMPtr<nsIDOMDocument> domdoc;
rv = mEditor->GetDocument(getter_AddRefs(domdoc)); nsresult rv = mEditor->GetDocument(getter_AddRefs(domdoc));
if (NS_FAILED(rv)) return PR_FALSE; if (NS_FAILED(rv)) return PR_FALSE;
nsCOMPtr<nsIDOMDocument> sourceDoc; nsCOMPtr<nsIDOMDocument> sourceDoc;
rv = dragSession->GetSourceDocument(getter_AddRefs(sourceDoc)); rv = sourceNode->GetOwnerDocument(getter_AddRefs(sourceDoc));
if (NS_FAILED(rv)) return PR_FALSE; if (NS_FAILED(rv)) return PR_FALSE;
if (domdoc == sourceDoc) // source and dest are the same document; disallow drops within the selection if (domdoc == sourceDoc) // source and dest are the same document; disallow drops within the selection
{ {