зеркало из https://github.com/mozilla/gecko-dev.git
Bug 508479 - HTML5 Drag and Drop: Drop event on elements that are not drop targets, r=enn, sr=sicking
This commit is contained in:
Родитель
72870cbe12
Коммит
62344a3ec7
|
@ -328,7 +328,25 @@ nsContentAreaDragDrop::DragOver(nsIDOMDragEvent* inEvent)
|
|||
}
|
||||
}
|
||||
|
||||
session->SetCanDrop(dropAllowed);
|
||||
nsCOMPtr<nsIDOMNSEvent> e = do_QueryInterface(inEvent);
|
||||
NS_ENSURE_STATE(e);
|
||||
nsCOMPtr<nsIDOMEventTarget> target;
|
||||
e->GetOriginalTarget(getter_AddRefs(target));
|
||||
nsCOMPtr<nsINode> node = do_QueryInterface(target);
|
||||
if (!node) {
|
||||
nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(target);
|
||||
if (win) {
|
||||
node = do_QueryInterface(win->GetExtantDocument());
|
||||
}
|
||||
}
|
||||
PRBool isChrome =
|
||||
node ? nsContentUtils::IsChromeDoc(node->GetOwnerDoc()) : PR_FALSE;
|
||||
if (isChrome) {
|
||||
session->SetCanDrop(dropAllowed);
|
||||
} else if (dropAllowed) {
|
||||
inEvent->PreventDefault();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -459,7 +459,23 @@ nsDOMEvent::PreventDefault()
|
|||
{
|
||||
if (!(mEvent->flags & NS_EVENT_FLAG_CANT_CANCEL)) {
|
||||
mEvent->flags |= NS_EVENT_FLAG_NO_DEFAULT;
|
||||
|
||||
// Need to set an extra flag for drag events.
|
||||
if (mEvent->eventStructType == NS_DRAG_EVENT &&
|
||||
NS_IS_TRUSTED_EVENT(mEvent)) {
|
||||
nsCOMPtr<nsINode> node = do_QueryInterface(mEvent->currentTarget);
|
||||
if (!node) {
|
||||
nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(mEvent->currentTarget);
|
||||
if (win) {
|
||||
node = do_QueryInterface(win->GetExtantDocument());
|
||||
}
|
||||
}
|
||||
if (node && !nsContentUtils::IsChromeDoc(node->GetOwnerDoc())) {
|
||||
mEvent->flags |= NS_EVENT_FLAG_NO_DEFAULT_CALLED_IN_CONTENT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -46,6 +46,8 @@
|
|||
#include "nsMutationEvent.h"
|
||||
#include NEW_H
|
||||
#include "nsFixedSizeAllocator.h"
|
||||
#include "nsINode.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
|
||||
#define NS_TARGET_CHAIN_FORCE_CONTENT_DISPATCH (1 << 0)
|
||||
#define NS_TARGET_CHAIN_WANTS_WILL_HANDLE_EVENT (1 << 1)
|
||||
|
@ -444,6 +446,28 @@ nsEventDispatcher::Dispatch(nsISupports* aTarget,
|
|||
NS_ERROR_ILLEGAL_VALUE);
|
||||
NS_ASSERTION(!aTargets || !aEvent->message, "Wrong parameters!");
|
||||
|
||||
if (aEvent->flags & NS_EVENT_FLAG_ONLY_CHROME_DISPATCH) {
|
||||
nsCOMPtr<nsINode> node = do_QueryInterface(aTarget);
|
||||
if (!node) {
|
||||
nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(aTarget);
|
||||
if (win) {
|
||||
node = do_QueryInterface(win->GetExtantDocument());
|
||||
}
|
||||
}
|
||||
|
||||
NS_ENSURE_STATE(node);
|
||||
nsIDocument* doc = node->GetOwnerDoc();
|
||||
if (!nsContentUtils::IsChromeDoc(doc)) {
|
||||
nsPIDOMWindow* win = doc ? doc->GetInnerWindow() : nsnull;
|
||||
// If we can't dispatch the event to chrome, do nothing.
|
||||
NS_ENSURE_TRUE(win && win->GetChromeEventHandler(), NS_OK);
|
||||
// Set the target to be the original dispatch target,
|
||||
aEvent->target = aTarget;
|
||||
// but use chrome event handler for event target chain.
|
||||
aTarget = win->GetChromeEventHandler();
|
||||
}
|
||||
}
|
||||
|
||||
nsCOMPtr<nsPIDOMEventTarget> target = do_QueryInterface(aTarget);
|
||||
#ifdef DEBUG
|
||||
if (aDOMEvent) {
|
||||
|
|
|
@ -3042,6 +3042,13 @@ nsEventStateManager::PostHandleEvent(nsPresContext* aPresContext,
|
|||
if (!dragSession)
|
||||
break;
|
||||
|
||||
// Reset the flag.
|
||||
dragSession->SetOnlyChromeDrop(PR_FALSE);
|
||||
if (mPresContext) {
|
||||
EnsureDocument(mPresContext);
|
||||
}
|
||||
PRBool isChromeDoc = nsContentUtils::IsChromeDoc(mDocument);
|
||||
|
||||
// the initial dataTransfer is the one from the dragstart event that
|
||||
// was set on the dragSession when the drag began.
|
||||
nsCOMPtr<nsIDOMNSDataTransfer> dataTransfer;
|
||||
|
@ -3117,6 +3124,16 @@ nsEventStateManager::PostHandleEvent(nsPresContext* aPresContext,
|
|||
// inform the drag session that a drop is allowed on this node.
|
||||
dragSession->SetDragAction(action);
|
||||
dragSession->SetCanDrop(action != nsIDragService::DRAGDROP_ACTION_NONE);
|
||||
|
||||
// For now, do this only for dragover.
|
||||
//XXXsmaug dragenter needs some more work.
|
||||
if (aEvent->message == NS_DRAGDROP_OVER && !isChromeDoc) {
|
||||
// Someone has called preventDefault(), check whether is was content.
|
||||
dragSession->SetOnlyChromeDrop(
|
||||
!(aEvent->flags & NS_EVENT_FLAG_NO_DEFAULT_CALLED_IN_CONTENT));
|
||||
}
|
||||
} else if (aEvent->message == NS_DRAGDROP_OVER && !isChromeDoc) {
|
||||
dragSession->SetCanDrop(PR_FALSE);
|
||||
}
|
||||
|
||||
// now set the drop effect in the initial dataTransfer. This ensures
|
||||
|
|
|
@ -80,6 +80,7 @@ _TEST_FILES = \
|
|||
test_bug489671.html \
|
||||
test_bug493251.html \
|
||||
test_bug502818.html \
|
||||
test_bug508479.html \
|
||||
test_bug517851.html \
|
||||
$(NULL)
|
||||
|
||||
|
|
|
@ -0,0 +1,81 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>Tests for the dragstart event</title>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
|
||||
<script type="application/javascript" src="/MochiKit/packed.js"></script>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
|
||||
|
||||
<script>
|
||||
|
||||
var gGotHandlingDrop = false;
|
||||
var gGotNotHandlingDrop = false;
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
function fireEvent(target, event) {
|
||||
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
|
||||
var utils =
|
||||
window.QueryInterface(Components.interfaces.nsIInterfaceRequestor).
|
||||
getInterface(Components.interfaces.nsIDOMWindowUtils);
|
||||
utils.dispatchDOMEventViaPresShell(target, event, true);
|
||||
}
|
||||
|
||||
function fireDrop(element, dragData, effectAllowed) {
|
||||
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
|
||||
var ds = Components.classes["@mozilla.org/widget/dragservice;1"].
|
||||
getService(Components.interfaces.nsIDragService);
|
||||
|
||||
ds.startDragSession();
|
||||
|
||||
var event = document.createEvent("DragEvents");
|
||||
event.initDragEvent("dragover", true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null, null);
|
||||
fireEvent(element, event);
|
||||
|
||||
event = document.createEvent("DragEvents");
|
||||
event.initDragEvent("drop", true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null, null);
|
||||
fireEvent(element, event);
|
||||
|
||||
ds.endDragSession(false);
|
||||
ok(!ds.getCurrentSession(), "There shouldn't be a drag session anymore!");
|
||||
}
|
||||
|
||||
function runTests()
|
||||
{
|
||||
var targetHandling = document.getElementById("handling_target");
|
||||
fireDrop(targetHandling, [{"test/plain": "Hello!"}]);
|
||||
|
||||
is(gGotHandlingDrop, true, "Got drop on accepting element (1)");
|
||||
is(gGotNotHandlingDrop, false, "Didn't get drop on unaccepting element (1)");
|
||||
|
||||
// reset
|
||||
gGotHandlingDrop = false;
|
||||
gGotNotHandlingDrop = false;
|
||||
|
||||
var targetNotHandling = document.getElementById("nothandling_target");
|
||||
fireDrop(targetNotHandling, [{"test/plain": "Hello!"}]);
|
||||
|
||||
is(gGotHandlingDrop, false, "Didn't get drop on accepting element (2)");
|
||||
is(gGotNotHandlingDrop, false, "Didn't get drop on unaccepting element (2)");
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<body onload="window.setTimeout(runTests, 0);">
|
||||
|
||||
<img style="width: 100px; height: 100px;"
|
||||
src="data:image/png,%89PNG%0D%0A%1A%0A%00%00%00%0DIHDR%00%00%00%18%00%00%00%18%02%03%00%00%00%9D%19%D5k%00%00%00%04gAMA%00%00%B1%8F%0B%FCa%05%00%00%00%0CPLTE%FF%FF%FF%FF%FF%FF%F7%DC%13%00%00%00%03%80%01X%00%00%00%01tRNS%08N%3DPT%00%00%00%01bKGD%00%88%05%1DH%00%00%00%09pHYs%00%00%0B%11%00%00%0B%11%01%7Fd_%91%00%00%00%07tIME%07%D2%05%0C%14%0C%0D%D8%3F%1FQ%00%00%00%5CIDATx%9C%7D%8E%CB%09%C0%20%10D%07r%B7%20%2F%E9wV0%15h%EA%D9%12D4%BB%C1x%CC%5C%1E%0C%CC%07%C0%9C0%9Dd7()%C0A%D3%8D%E0%B8%10%1DiCHM%D0%AC%D2d%C3M%F1%B4%E7%FF%10%0BY%AC%25%93%CD%CBF%B5%B2%C0%3Alh%CD%AE%13%DF%A5%F7%E0%03byW%09A%B4%F3%E2%00%00%00%00IEND%AEB%60%82"
|
||||
id="handling_target"
|
||||
ondragenter="event.preventDefault()"
|
||||
ondragover="event.preventDefault()"
|
||||
ondrop="gGotHandlingDrop = true;">
|
||||
|
||||
<img style="width: 100px; height: 100px;"
|
||||
src="data:image/png,%89PNG%0D%0A%1A%0A%00%00%00%0DIHDR%00%00%00%18%00%00%00%18%02%03%00%00%00%9D%19%D5k%00%00%00%04gAMA%00%00%B1%8F%0B%FCa%05%00%00%00%0CPLTE%FF%FF%FF%FF%FF%FF%F7%DC%13%00%00%00%03%80%01X%00%00%00%01tRNS%08N%3DPT%00%00%00%01bKGD%00%88%05%1DH%00%00%00%09pHYs%00%00%0B%11%00%00%0B%11%01%7Fd_%91%00%00%00%07tIME%07%D2%05%0C%14%0C%0D%D8%3F%1FQ%00%00%00%5CIDATx%9C%7D%8E%CB%09%C0%20%10D%07r%B7%20%2F%E9wV0%15h%EA%D9%12D4%BB%C1x%CC%5C%1E%0C%CC%07%C0%9C0%9Dd7()%C0A%D3%8D%E0%B8%10%1DiCHM%D0%AC%D2d%C3M%F1%B4%E7%FF%10%0BY%AC%25%93%CD%CBF%B5%B2%C0%3Alh%CD%AE%13%DF%A5%F7%E0%03byW%09A%B4%F3%E2%00%00%00%00IEND%AEB%60%82"
|
||||
id="nothandling_target"
|
||||
ondrop="gGotNotHandlingDrop = true;">
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -40,7 +40,7 @@
|
|||
#include "nsDOMClassInfo.h"
|
||||
#include "nsDOMError.h"
|
||||
#include "nsIDOMNSEvent.h"
|
||||
|
||||
#include "nsIPrivateDOMEvent.h"
|
||||
#include "nsDOMWindowUtils.h"
|
||||
#include "nsGlobalWindow.h"
|
||||
#include "nsIDocument.h"
|
||||
|
@ -920,3 +920,32 @@ nsDOMWindowUtils::GetCOWForObject()
|
|||
cc->SetReturnValueWasSet(PR_TRUE);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMWindowUtils::DispatchDOMEventViaPresShell(nsIDOMNode* aTarget,
|
||||
nsIDOMEvent* aEvent,
|
||||
PRBool aTrusted,
|
||||
PRBool* aRetVal)
|
||||
{
|
||||
if (!nsContentUtils::IsCallerTrustedForRead()) {
|
||||
return NS_ERROR_DOM_SECURITY_ERR;
|
||||
}
|
||||
|
||||
nsPresContext* presContext = GetPresContext();
|
||||
NS_ENSURE_STATE(presContext);
|
||||
nsCOMPtr<nsIPresShell> shell = presContext->GetPresShell();
|
||||
NS_ENSURE_STATE(shell);
|
||||
nsCOMPtr<nsIPrivateDOMEvent> event = do_QueryInterface(aEvent);
|
||||
NS_ENSURE_STATE(event);
|
||||
event->SetTrusted(aTrusted);
|
||||
nsEvent* internalEvent = event->GetInternalNSEvent();
|
||||
NS_ENSURE_STATE(internalEvent);
|
||||
nsCOMPtr<nsIContent> content = do_QueryInterface(aTarget);
|
||||
NS_ENSURE_STATE(content);
|
||||
|
||||
nsEventStatus status = nsEventStatus_eIgnore;
|
||||
shell->HandleEventWithTarget(internalEvent, nsnull, content,
|
||||
&status);
|
||||
*aRetVal = (status != nsEventStatus_eConsumeNoDefault);
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -45,10 +45,12 @@
|
|||
* getInterface on a DOMWindow.
|
||||
*/
|
||||
|
||||
interface nsIDOMNode;
|
||||
interface nsIDOMElement;
|
||||
interface nsIDOMHTMLCanvasElement;
|
||||
interface nsIDOMEvent;
|
||||
|
||||
[scriptable, uuid(4171ea1a-3752-4bc3-8c66-1b2936ecde7a)]
|
||||
[scriptable, uuid(4775e623-d596-4364-8637-0968a5ce5e3d)]
|
||||
interface nsIDOMWindowUtils : nsISupports {
|
||||
|
||||
/**
|
||||
|
@ -403,4 +405,20 @@ interface nsIDOMWindowUtils : nsISupports {
|
|||
* Get the number of screen pixels per CSS pixel.
|
||||
*/
|
||||
readonly attribute float screenPixelsPerCSSPixel;
|
||||
|
||||
/**
|
||||
* Dispatches aEvent via the nsIPresShell object of the window's document.
|
||||
* The event is dispatched to aTarget, which should be an object
|
||||
* which implements nsIContent interface (#element, #text, etc).
|
||||
*
|
||||
* Cannot be accessed from unprivileged context (not
|
||||
* content-accessible) Will throw a DOM security error if called
|
||||
* without UniversalXPConnect privileges.
|
||||
*
|
||||
* @note Event handlers won't get aEvent as parameter, but a similar event.
|
||||
* Also, aEvent should not be reused.
|
||||
*/
|
||||
boolean dispatchDOMEventViaPresShell(in nsIDOMNode aTarget,
|
||||
in nsIDOMEvent aEvent,
|
||||
in boolean aTrusted);
|
||||
};
|
||||
|
|
|
@ -6488,6 +6488,17 @@ PresShell::HandleEventInternal(nsEvent* aEvent, nsIView *aView,
|
|||
case NS_KEY_DOWN:
|
||||
case NS_KEY_UP:
|
||||
isHandlingUserInput = PR_TRUE;
|
||||
break;
|
||||
case NS_DRAGDROP_DROP:
|
||||
nsCOMPtr<nsIDragSession> session = nsContentUtils::GetDragSession();
|
||||
if (session) {
|
||||
PRBool onlyChromeDrop = PR_FALSE;
|
||||
session->GetOnlyChromeDrop(&onlyChromeDrop);
|
||||
if (onlyChromeDrop) {
|
||||
aEvent->flags |= NS_EVENT_FLAG_ONLY_CHROME_DISPATCH;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -132,6 +132,12 @@ class nsHashKey;
|
|||
// events.
|
||||
#define NS_EVENT_FLAG_SYNTHETIC_TEST_EVENT 0x1000
|
||||
|
||||
// Use this flag if the event should be dispatched only to chrome.
|
||||
#define NS_EVENT_FLAG_ONLY_CHROME_DISPATCH 0x2000
|
||||
|
||||
// A flag for drag&drop handling.
|
||||
#define NS_EVENT_FLAG_NO_DEFAULT_CALLED_IN_CONTENT 0x4000
|
||||
|
||||
#define NS_PRIV_EVENT_UNTRUSTED_PERMITTED 0x8000
|
||||
|
||||
#define NS_EVENT_CAPTURE_MASK (~(NS_EVENT_FLAG_BUBBLE | NS_EVENT_FLAG_NO_CONTENT_DISPATCH))
|
||||
|
|
|
@ -53,7 +53,7 @@ interface nsIDOMDocument;
|
|||
interface nsIDOMNode;
|
||||
interface nsIDOMDataTransfer;
|
||||
|
||||
[scriptable, uuid(15860D52-FE2C-4DDD-AC50-9C23E24916C4)]
|
||||
[scriptable, uuid(fde41f6a-c710-46f8-a0a8-1ff76ca4ff57)]
|
||||
interface nsIDragSession : nsISupports
|
||||
{
|
||||
/**
|
||||
|
@ -61,6 +61,11 @@ interface nsIDragSession : nsISupports
|
|||
* usually the target "frame" sets this so the native system can render the correct feedback
|
||||
*/
|
||||
attribute boolean canDrop;
|
||||
|
||||
/**
|
||||
* Indicates if the drop event should be dispatched only to chrome.
|
||||
*/
|
||||
attribute boolean onlyChromeDrop;
|
||||
|
||||
/**
|
||||
* Sets the action (copy, move, link, et.c) for the current drag
|
||||
|
|
|
@ -76,7 +76,8 @@
|
|||
#define DRAGIMAGES_PREF "nglayout.enable_drag_images"
|
||||
|
||||
nsBaseDragService::nsBaseDragService()
|
||||
: mCanDrop(PR_FALSE), mDoingDrag(PR_FALSE), mHasImage(PR_FALSE), mUserCancelled(PR_FALSE),
|
||||
: mCanDrop(PR_FALSE), mOnlyChromeDrop(PR_FALSE), mDoingDrag(PR_FALSE),
|
||||
mHasImage(PR_FALSE), mUserCancelled(PR_FALSE),
|
||||
mDragAction(DRAGDROP_ACTION_NONE), mTargetSize(0,0),
|
||||
mImageX(0), mImageY(0), mScreenX(-1), mScreenY(-1), mSuppressLevel(0)
|
||||
{
|
||||
|
@ -103,6 +104,21 @@ nsBaseDragService::GetCanDrop(PRBool * aCanDrop)
|
|||
*aCanDrop = mCanDrop;
|
||||
return NS_OK;
|
||||
}
|
||||
//---------------------------------------------------------
|
||||
NS_IMETHODIMP
|
||||
nsBaseDragService::SetOnlyChromeDrop(PRBool aOnlyChrome)
|
||||
{
|
||||
mOnlyChromeDrop = aOnlyChrome;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
NS_IMETHODIMP
|
||||
nsBaseDragService::GetOnlyChromeDrop(PRBool* aOnlyChrome)
|
||||
{
|
||||
*aOnlyChrome = mOnlyChromeDrop;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
NS_IMETHODIMP
|
||||
|
@ -323,6 +339,8 @@ nsBaseDragService::StartDragSession()
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
mDoingDrag = PR_TRUE;
|
||||
// By default dispatch drop also to content.
|
||||
mOnlyChromeDrop = PR_FALSE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -128,6 +128,7 @@ protected:
|
|||
PRInt32* aScreenX, PRInt32* aScreenY);
|
||||
|
||||
PRPackedBool mCanDrop;
|
||||
PRPackedBool mOnlyChromeDrop;
|
||||
PRPackedBool mDoingDrag;
|
||||
// true if mImage should be used to set a drag image
|
||||
PRPackedBool mHasImage;
|
||||
|
|
Загрузка…
Ссылка в новой задаче