mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-13 13:25:37 +00:00
Bug 1461708 - part 5: Move EditorEventListener::HandleMiddleClickPaste() to EventStateManager r=smaug
EventStateManager needs to handle middle click paste without editor. Therefore, the handler should be in EventStateManager. Differential Revision: https://phabricator.services.mozilla.com/D7852 --HG-- extra : moz-landing-system : lando
This commit is contained in:
parent
d472d6f312
commit
fd4e78f2a1
@ -35,6 +35,7 @@
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsFocusManager.h"
|
||||
#include "nsGenericHTMLElement.h"
|
||||
#include "nsIClipboard.h"
|
||||
#include "nsIContent.h"
|
||||
#include "nsIContentInlines.h"
|
||||
#include "nsIDocument.h"
|
||||
@ -5120,6 +5121,95 @@ EventStateManager::DispatchClickEvents(nsIPresShell* aPresShell,
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
EventStateManager::HandleMiddleClickPaste(nsIPresShell* aPresShell,
|
||||
WidgetMouseEvent* aMouseEvent,
|
||||
nsEventStatus* aStatus,
|
||||
TextEditor* aTextEditor)
|
||||
{
|
||||
MOZ_ASSERT(aPresShell);
|
||||
MOZ_ASSERT(aMouseEvent);
|
||||
MOZ_ASSERT(aMouseEvent->mMessage == eMouseClick &&
|
||||
aMouseEvent->button == WidgetMouseEventBase::eMiddleButton);
|
||||
MOZ_ASSERT(aStatus);
|
||||
MOZ_ASSERT(aTextEditor);
|
||||
|
||||
if (*aStatus == nsEventStatus_eConsumeNoDefault) {
|
||||
// Already consumed. Do nothing.
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
RefPtr<Selection> selection = aTextEditor->GetSelection();
|
||||
if (NS_WARN_IF(!selection)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// Move selection to the clicked point.
|
||||
nsCOMPtr<nsIContent> container;
|
||||
int32_t offset;
|
||||
nsLayoutUtils::GetContainerAndOffsetAtEvent(aPresShell, aMouseEvent,
|
||||
getter_AddRefs(container),
|
||||
&offset);
|
||||
if (container) {
|
||||
// XXX If readonly or disabled <input> or <textarea> in contenteditable
|
||||
// designMode editor is clicked, the point is in the editor.
|
||||
// However, outer HTMLEditor and Selection should handle it.
|
||||
// So, in such case, Selection::Collapse() will fail.
|
||||
DebugOnly<nsresult> rv = selection->Collapse(container, offset);
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
|
||||
"Failed to collapse Selection at middle clicked");
|
||||
}
|
||||
|
||||
int32_t clipboardType = nsIClipboard::kGlobalClipboard;
|
||||
nsresult rv = NS_OK;
|
||||
nsCOMPtr<nsIClipboard> clipboardService =
|
||||
do_GetService("@mozilla.org/widget/clipboard;1", &rv);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
bool selectionSupported;
|
||||
rv = clipboardService->SupportsSelectionClipboard(&selectionSupported);
|
||||
if (NS_SUCCEEDED(rv) && selectionSupported) {
|
||||
clipboardType = nsIClipboard::kSelectionClipboard;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the editor is still the good target to paste.
|
||||
if (aTextEditor->Destroyed() ||
|
||||
aTextEditor->IsReadonly() ||
|
||||
aTextEditor->IsDisabled()) {
|
||||
// XXX Should we consume the event when the editor is readonly and/or
|
||||
// disabled?
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// The selection may have been modified during reflow. Therefore, we
|
||||
// should adjust event target to pass IsAcceptableInputEvent().
|
||||
nsRange* range = selection->GetRangeAt(0);
|
||||
if (!range) {
|
||||
return NS_OK;
|
||||
}
|
||||
WidgetMouseEvent mouseEvent(*aMouseEvent);
|
||||
mouseEvent.mOriginalTarget = range->GetStartContainer();
|
||||
if (NS_WARN_IF(!mouseEvent.mOriginalTarget) ||
|
||||
!aTextEditor->IsAcceptableInputEvent(&mouseEvent)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// If Control key is pressed, we should paste clipboard content as
|
||||
// quotation. Otherwise, paste it as is.
|
||||
if (aMouseEvent->IsControl()) {
|
||||
DebugOnly<nsresult> rv =
|
||||
aTextEditor->PasteAsQuotationAsAction(clipboardType);
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed to paste as quotation");
|
||||
} else {
|
||||
DebugOnly<nsresult> rv =
|
||||
aTextEditor->PasteAsAction(clipboardType);
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed to paste");
|
||||
}
|
||||
*aStatus = nsEventStatus_eConsumeNoDefault;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsIFrame*
|
||||
EventStateManager::GetEventTarget()
|
||||
{
|
||||
|
@ -363,6 +363,24 @@ public:
|
||||
MIN_MULTIPLIER_VALUE_ALLOWING_OVER_ONE_PAGE_SCROLL = 1000
|
||||
};
|
||||
|
||||
/**
|
||||
* HandleMiddleClickPaste() handles middle mouse button event as pasting
|
||||
* clipboard text.
|
||||
*
|
||||
* @param aPresShell The PresShell for the ESM. This lifetime
|
||||
* should be guaranteed by the caller.
|
||||
* @param aMouseEvent The eMouseClick event which caused the
|
||||
* paste.
|
||||
* @param aStatus The event status of aMouseEvent.
|
||||
* @param aTextEditor TextEditor which may be pasted the
|
||||
* clipboard text by the middle click.
|
||||
*/
|
||||
MOZ_CAN_RUN_SCRIPT
|
||||
nsresult HandleMiddleClickPaste(nsIPresShell* aPresShell,
|
||||
WidgetMouseEvent* aMouseEvent,
|
||||
nsEventStatus* aStatus,
|
||||
TextEditor* aTextEditor);
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Prefs class capsules preference management.
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "mozilla/ContentEvents.h" // for InternalFocusEvent
|
||||
#include "mozilla/EditorBase.h" // for EditorBase, etc.
|
||||
#include "mozilla/EventListenerManager.h" // for EventListenerManager
|
||||
#include "mozilla/EventStateManager.h" // for EventStateManager
|
||||
#include "mozilla/IMEStateManager.h" // for IMEStateManager
|
||||
#include "mozilla/Preferences.h" // for Preferences
|
||||
#include "mozilla/TextEditor.h" // for TextEditor
|
||||
@ -647,18 +648,18 @@ EditorEventListener::MouseClick(MouseEvent* aMouseEvent)
|
||||
return NS_OK;
|
||||
}
|
||||
// nothing to do if editor isn't editable or clicked on out of the editor.
|
||||
RefPtr<EditorBase> editorBase(mEditorBase);
|
||||
RefPtr<TextEditor> textEditor = mEditorBase->AsTextEditor();
|
||||
WidgetMouseEvent* clickEvent =
|
||||
aMouseEvent->WidgetEventPtr()->AsMouseEvent();
|
||||
if (editorBase->IsReadonly() || editorBase->IsDisabled() ||
|
||||
!editorBase->IsAcceptableInputEvent(clickEvent)) {
|
||||
if (textEditor->IsReadonly() || textEditor->IsDisabled() ||
|
||||
!textEditor->IsAcceptableInputEvent(clickEvent)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Notifies clicking on editor to IMEStateManager even when the event was
|
||||
// consumed.
|
||||
if (EditorHasFocus()) {
|
||||
nsPresContext* presContext = GetPresContext();
|
||||
RefPtr<nsPresContext> presContext = GetPresContext();
|
||||
if (presContext) {
|
||||
IMEStateManager::OnClickInEditor(presContext, GetFocusedRootContent(),
|
||||
clickEvent);
|
||||
@ -679,64 +680,32 @@ EditorEventListener::MouseClick(MouseEvent* aMouseEvent)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (clickEvent->button == 1) {
|
||||
return HandleMiddleClickPaste(aMouseEvent);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
EditorEventListener::HandleMiddleClickPaste(MouseEvent* aMouseEvent)
|
||||
{
|
||||
MOZ_ASSERT(aMouseEvent);
|
||||
|
||||
WidgetMouseEvent* clickEvent =
|
||||
aMouseEvent->WidgetEventPtr()->AsMouseEvent();
|
||||
MOZ_ASSERT(!DetachedFromEditorOrDefaultPrevented(clickEvent));
|
||||
|
||||
if (!Preferences::GetBool("middlemouse.paste", false)) {
|
||||
// Middle click paste isn't enabled.
|
||||
if (clickEvent->button != WidgetMouseEventBase::eMiddleButton ||
|
||||
!WidgetMouseEvent::IsMiddleClickPasteEnabled()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Set the selection to the point under the mouse cursor:
|
||||
nsCOMPtr<nsINode> parent = aMouseEvent->GetRangeParent();
|
||||
int32_t offset = aMouseEvent->RangeOffset();
|
||||
|
||||
RefPtr<TextEditor> textEditor = mEditorBase->AsTextEditor();
|
||||
MOZ_ASSERT(textEditor);
|
||||
|
||||
RefPtr<Selection> selection = textEditor->GetSelection();
|
||||
if (selection) {
|
||||
selection->Collapse(parent, offset);
|
||||
nsCOMPtr<nsIPresShell> presShell = GetPresShell();
|
||||
if (NS_WARN_IF(!presShell)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult rv;
|
||||
int32_t clipboard = nsIClipboard::kGlobalClipboard;
|
||||
nsCOMPtr<nsIClipboard> clipboardService =
|
||||
do_GetService("@mozilla.org/widget/clipboard;1", &rv);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
bool selectionSupported;
|
||||
rv = clipboardService->SupportsSelectionClipboard(&selectionSupported);
|
||||
if (NS_SUCCEEDED(rv) && selectionSupported) {
|
||||
clipboard = nsIClipboard::kSelectionClipboard;
|
||||
}
|
||||
nsPresContext* presContext = GetPresContext();
|
||||
if (NS_WARN_IF(!presContext)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// If the ctrl key is pressed, we'll do paste as quotation.
|
||||
// Would've used the alt key, but the kde wmgr treats alt-middle specially.
|
||||
if (clickEvent->IsControl()) {
|
||||
textEditor->PasteAsQuotationAsAction(clipboard);
|
||||
} else {
|
||||
textEditor->PasteAsAction(clipboard);
|
||||
MOZ_ASSERT(!clickEvent->DefaultPrevented());
|
||||
nsEventStatus status = nsEventStatus_eIgnore;
|
||||
RefPtr<EventStateManager> esm = presContext->EventStateManager();
|
||||
DebugOnly<nsresult> rv =
|
||||
esm->HandleMiddleClickPaste(presShell, clickEvent, &status, textEditor);
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
|
||||
"Failed to paste for the middle button click");
|
||||
if (status == nsEventStatus_eConsumeNoDefault) {
|
||||
// Prevent the event from propagating up to be possibly handled
|
||||
// again by the containing window:
|
||||
clickEvent->StopImmediatePropagation();
|
||||
clickEvent->PreventDefault();
|
||||
}
|
||||
|
||||
// Prevent the event from propagating up to be possibly handled
|
||||
// again by the containing window:
|
||||
clickEvent->StopPropagation();
|
||||
clickEvent->PreventDefault();
|
||||
|
||||
// We processed the event, whether drop/paste succeeded or not
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -91,8 +91,6 @@ protected:
|
||||
bool EditorHasFocus();
|
||||
bool IsFileControlTextBox();
|
||||
bool ShouldHandleNativeKeyBindings(WidgetKeyboardEvent* aKeyboardEvent);
|
||||
MOZ_CAN_RUN_SCRIPT
|
||||
nsresult HandleMiddleClickPaste(dom::MouseEvent* aMouseEvent);
|
||||
|
||||
/**
|
||||
* DetachedFromEditor() returns true if editor was detached.
|
||||
|
@ -351,6 +351,11 @@ public:
|
||||
{
|
||||
return mReason == eReal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if middle click paste is enabled.
|
||||
*/
|
||||
static bool IsMiddleClickPasteEnabled();
|
||||
};
|
||||
|
||||
/******************************************************************************
|
||||
|
@ -650,6 +650,16 @@ WidgetInputEvent::AccelModifier()
|
||||
return sAccelModifier;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* mozilla::WidgetMouseEvent (MouseEvents.h)
|
||||
******************************************************************************/
|
||||
|
||||
/* static */ bool
|
||||
WidgetMouseEvent::IsMiddleClickPasteEnabled()
|
||||
{
|
||||
return Preferences::GetBool("middlemouse.paste", false);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* mozilla::WidgetWheelEvent (MouseEvents.h)
|
||||
******************************************************************************/
|
||||
|
Loading…
Reference in New Issue
Block a user