Bug 558970 nsEditorEventListener should store its owner as nsEditor rather than nsIEditor r=smaug

This commit is contained in:
Masayuki Nakano 2010-04-19 21:20:42 +09:00
parent 44bdccd814
commit acb56f8ab0
8 changed files with 506 additions and 428 deletions

View File

@ -44,9 +44,7 @@
#include "nsIDOMHTMLDocument.h"
#include "nsIDOMHTMLElement.h"
#include "nsIDOMNSHTMLElement.h"
#include "nsIDOMEventTarget.h"
#include "nsPIDOMEventTarget.h"
#include "nsIEventListenerManager.h"
#include "nsIPrefBranch.h"
#include "nsIPrefService.h"
#include "nsUnicharUtils.h"
@ -60,12 +58,6 @@
#include "nsIDOMNamedNodeMap.h"
#include "nsIDOMNodeList.h"
#include "nsIDOMRange.h"
#include "nsIDOMEventListener.h"
#include "nsIDOMEventGroup.h"
#include "nsIDOMMouseListener.h"
#include "nsIDOMFocusListener.h"
#include "nsIDOMTextListener.h"
#include "nsIDOMCompositionListener.h"
#include "nsIDOMHTMLBRElement.h"
#include "nsIDocument.h"
#include "nsITransactionManager.h"
@ -318,7 +310,7 @@ nsEditor::CreateEventListeners()
{
NS_ENSURE_TRUE(!mEventListener, NS_ERROR_ALREADY_INITIALIZED);
mEventListener = do_QueryInterface(
static_cast<nsIDOMKeyListener*>(new nsEditorEventListener(this)));
static_cast<nsIDOMKeyListener*>(new nsEditorEventListener()));
NS_ENSURE_TRUE(mEventListener, NS_ERROR_OUT_OF_MEMORY);
return NS_OK;
}
@ -328,121 +320,18 @@ nsEditor::InstallEventListeners()
{
NS_ENSURE_TRUE(mDocWeak && mPresShellWeak && mEventListener,
NS_ERROR_NOT_INITIALIZED);
nsCOMPtr<nsPIDOMEventTarget> piTarget = GetPIDOMEventTarget();
if (!piTarget) {
RemoveEventListeners();
return NS_ERROR_FAILURE;
}
nsresult rv = NS_OK;
// register the event listeners with the listener manager
nsCOMPtr<nsIDOMEventGroup> sysGroup;
piTarget->GetSystemEventGroup(getter_AddRefs(sysGroup));
nsIEventListenerManager* elmP = piTarget->GetListenerManager(PR_TRUE);
if (sysGroup && elmP)
{
rv = elmP->AddEventListenerByType(mEventListener,
NS_LITERAL_STRING("keypress"),
NS_EVENT_FLAG_BUBBLE |
NS_PRIV_EVENT_UNTRUSTED_PERMITTED,
sysGroup);
NS_ASSERTION(NS_SUCCEEDED(rv),
"failed to register key listener in system group");
}
rv |= piTarget->AddEventListenerByIID(mEventListener,
NS_GET_IID(nsIDOMMouseListener));
if (elmP) {
// Focus event doesn't bubble so adding the listener to capturing phase.
// Make sure this works after bug 235441 gets fixed.
rv |= elmP->AddEventListenerByIID(mEventListener,
NS_GET_IID(nsIDOMFocusListener),
NS_EVENT_FLAG_CAPTURE);
}
rv |= piTarget->AddEventListenerByIID(mEventListener,
NS_GET_IID(nsIDOMTextListener));
rv |= piTarget->AddEventListenerByIID(mEventListener,
NS_GET_IID(nsIDOMCompositionListener));
nsCOMPtr<nsIDOMEventTarget> target(do_QueryInterface(piTarget));
if (target) {
// See bug 455215, we cannot use the standard dragstart event yet
rv |= elmP->AddEventListenerByType(mEventListener, NS_LITERAL_STRING("draggesture"),
NS_EVENT_FLAG_BUBBLE, sysGroup);
rv |= elmP->AddEventListenerByType(mEventListener, NS_LITERAL_STRING("dragenter"),
NS_EVENT_FLAG_BUBBLE, sysGroup);
rv |= elmP->AddEventListenerByType(mEventListener, NS_LITERAL_STRING("dragover"),
NS_EVENT_FLAG_BUBBLE, sysGroup);
rv |= elmP->AddEventListenerByType(mEventListener, NS_LITERAL_STRING("dragleave"),
NS_EVENT_FLAG_BUBBLE, sysGroup);
rv |= elmP->AddEventListenerByType(mEventListener, NS_LITERAL_STRING("drop"),
NS_EVENT_FLAG_BUBBLE, sysGroup);
}
if (NS_FAILED(rv))
{
NS_ERROR("failed to register some event listeners");
RemoveEventListeners();
}
return rv;
nsEditorEventListener* listener =
reinterpret_cast<nsEditorEventListener*>(mEventListener.get());
return listener->Connect(this);
}
void
nsEditor::RemoveEventListeners()
{
if (!mDocWeak || !mEventListener)
{
if (!mDocWeak || !mEventListener) {
return;
}
nsCOMPtr<nsPIDOMEventTarget> piTarget = GetPIDOMEventTarget();
if (piTarget)
{
// unregister the event listeners with the DOM event target
nsCOMPtr<nsIEventListenerManager> elmP =
piTarget->GetListenerManager(PR_TRUE);
nsCOMPtr<nsIDOMEventGroup> sysGroup;
piTarget->GetSystemEventGroup(getter_AddRefs(sysGroup));
if (sysGroup && elmP)
{
elmP->RemoveEventListenerByType(mEventListener,
NS_LITERAL_STRING("keypress"),
NS_EVENT_FLAG_BUBBLE, sysGroup);
elmP->RemoveEventListenerByType(mEventListener, NS_LITERAL_STRING("draggesture"),
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,
NS_GET_IID(nsIDOMMouseListener));
elmP->RemoveEventListenerByIID(mEventListener,
NS_GET_IID(nsIDOMFocusListener),
NS_EVENT_FLAG_CAPTURE);
piTarget->RemoveEventListenerByIID(mEventListener,
NS_GET_IID(nsIDOMTextListener));
piTarget->RemoveEventListenerByIID(mEventListener,
NS_GET_IID(nsIDOMCompositionListener));
}
reinterpret_cast<nsEditorEventListener*>(mEventListener.get())->Disconnect();
}
PRBool

View File

@ -344,7 +344,7 @@ protected:
// install the event listeners for the editor
nsresult InstallEventListeners();
virtual nsresult InstallEventListeners();
virtual nsresult CreateEventListeners();

View File

@ -45,6 +45,7 @@
#include "nsIDOMEvent.h"
#include "nsIDOMNSEvent.h"
#include "nsIDOMDocument.h"
#include "nsPIDOMEventTarget.h"
#include "nsIDocument.h"
#include "nsIPresShell.h"
#include "nsISelection.h"
@ -58,6 +59,8 @@
#include "nsIPrefService.h"
#include "nsILookAndFeel.h"
#include "nsFocusManager.h"
#include "nsIEventListenerManager.h"
#include "nsIDOMEventGroup.h"
// Drag & Drop, Clipboard
#include "nsIServiceManager.h"
@ -76,24 +79,173 @@
#include "nsIDOMWindow.h"
#include "nsContentUtils.h"
nsEditorEventListener::nsEditorEventListener(nsEditor* aEditor) :
mEditor(aEditor), mCaretDrawn(PR_FALSE), mCommitText(PR_FALSE),
nsEditorEventListener::nsEditorEventListener() :
mEditor(nsnull), mCaretDrawn(PR_FALSE), mCommitText(PR_FALSE),
mInTransaction(PR_FALSE)
{
}
nsEditorEventListener::~nsEditorEventListener()
{
if (mEditor) {
NS_WARNING("We're not uninstalled");
Disconnect();
}
}
nsresult
nsEditorEventListener::Connect(nsEditor* aEditor)
{
NS_ENSURE_ARG(aEditor);
NS_ENSURE_TRUE(!mEditor, NS_ERROR_NOT_AVAILABLE);
mEditor = aEditor;
nsresult rv = InstallToEditor();
if (NS_FAILED(rv)) {
Disconnect();
}
return rv;
}
nsresult
nsEditorEventListener::InstallToEditor()
{
NS_PRECONDITION(mEditor, "The caller must set mEditor");
nsCOMPtr<nsPIDOMEventTarget> piTarget = mEditor->GetPIDOMEventTarget();
NS_ENSURE_TRUE(piTarget, NS_ERROR_FAILURE);
nsresult rv;
// register the event listeners with the listener manager
nsCOMPtr<nsIDOMEventGroup> sysGroup;
piTarget->GetSystemEventGroup(getter_AddRefs(sysGroup));
NS_ENSURE_STATE(sysGroup);
nsIEventListenerManager* elmP = piTarget->GetListenerManager(PR_TRUE);
NS_ENSURE_STATE(elmP);
rv = elmP->AddEventListenerByType(static_cast<nsIDOMKeyListener*>(this),
NS_LITERAL_STRING("keypress"),
NS_EVENT_FLAG_BUBBLE |
NS_PRIV_EVENT_UNTRUSTED_PERMITTED,
sysGroup);
NS_ENSURE_SUCCESS(rv, rv);
// See bug 455215, we cannot use the standard dragstart event yet
rv = elmP->AddEventListenerByType(static_cast<nsIDOMKeyListener*>(this),
NS_LITERAL_STRING("draggesture"),
NS_EVENT_FLAG_BUBBLE, sysGroup);
NS_ENSURE_SUCCESS(rv, rv);
rv = elmP->AddEventListenerByType(static_cast<nsIDOMKeyListener*>(this),
NS_LITERAL_STRING("dragenter"),
NS_EVENT_FLAG_BUBBLE, sysGroup);
NS_ENSURE_SUCCESS(rv, rv);
rv = elmP->AddEventListenerByType(static_cast<nsIDOMKeyListener*>(this),
NS_LITERAL_STRING("dragover"),
NS_EVENT_FLAG_BUBBLE, sysGroup);
NS_ENSURE_SUCCESS(rv, rv);
rv = elmP->AddEventListenerByType(static_cast<nsIDOMKeyListener*>(this),
NS_LITERAL_STRING("dragleave"),
NS_EVENT_FLAG_BUBBLE, sysGroup);
NS_ENSURE_SUCCESS(rv, rv);
rv = elmP->AddEventListenerByType(static_cast<nsIDOMKeyListener*>(this),
NS_LITERAL_STRING("drop"),
NS_EVENT_FLAG_BUBBLE, sysGroup);
NS_ENSURE_SUCCESS(rv, rv);
rv = piTarget->AddEventListenerByIID(static_cast<nsIDOMMouseListener*>(this),
NS_GET_IID(nsIDOMMouseListener));
NS_ENSURE_SUCCESS(rv, rv);
// Focus event doesn't bubble so adding the listener to capturing phase.
// Make sure this works after bug 235441 gets fixed.
rv = elmP->AddEventListenerByIID(static_cast<nsIDOMFocusListener*>(this),
NS_GET_IID(nsIDOMFocusListener),
NS_EVENT_FLAG_CAPTURE);
NS_ENSURE_SUCCESS(rv, rv);
rv = piTarget->AddEventListenerByIID(static_cast<nsIDOMTextListener*>(this),
NS_GET_IID(nsIDOMTextListener));
NS_ENSURE_SUCCESS(rv, rv);
rv = piTarget->AddEventListenerByIID(
static_cast<nsIDOMCompositionListener*>(this),
NS_GET_IID(nsIDOMCompositionListener));
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
void
nsEditorEventListener::Disconnect()
{
if (!mEditor) {
return;
}
UninstallFromEditor();
mEditor = nsnull;
}
void
nsEditorEventListener::UninstallFromEditor()
{
nsCOMPtr<nsPIDOMEventTarget> piTarget = mEditor->GetPIDOMEventTarget();
if (!piTarget) {
return;
}
nsCOMPtr<nsIEventListenerManager> elmP =
piTarget->GetListenerManager(PR_TRUE);
if (!elmP) {
return;
}
nsCOMPtr<nsIDOMEventGroup> sysGroup;
piTarget->GetSystemEventGroup(getter_AddRefs(sysGroup));
if (!sysGroup) {
return;
}
elmP->RemoveEventListenerByType(static_cast<nsIDOMKeyListener*>(this),
NS_LITERAL_STRING("keypress"),
NS_EVENT_FLAG_BUBBLE, sysGroup);
elmP->RemoveEventListenerByType(static_cast<nsIDOMKeyListener*>(this),
NS_LITERAL_STRING("draggesture"),
NS_EVENT_FLAG_BUBBLE, sysGroup);
elmP->RemoveEventListenerByType(static_cast<nsIDOMKeyListener*>(this),
NS_LITERAL_STRING("dragenter"),
NS_EVENT_FLAG_BUBBLE, sysGroup);
elmP->RemoveEventListenerByType(static_cast<nsIDOMKeyListener*>(this),
NS_LITERAL_STRING("dragover"),
NS_EVENT_FLAG_BUBBLE, sysGroup);
elmP->RemoveEventListenerByType(static_cast<nsIDOMKeyListener*>(this),
NS_LITERAL_STRING("dragleave"),
NS_EVENT_FLAG_BUBBLE, sysGroup);
elmP->RemoveEventListenerByType(static_cast<nsIDOMKeyListener*>(this),
NS_LITERAL_STRING("drop"),
NS_EVENT_FLAG_BUBBLE, sysGroup);
piTarget->RemoveEventListenerByIID(static_cast<nsIDOMMouseListener*>(this),
NS_GET_IID(nsIDOMMouseListener));
elmP->RemoveEventListenerByIID(static_cast<nsIDOMFocusListener*>(this),
NS_GET_IID(nsIDOMFocusListener),
NS_EVENT_FLAG_CAPTURE);
piTarget->RemoveEventListenerByIID(static_cast<nsIDOMTextListener*>(this),
NS_GET_IID(nsIDOMTextListener));
piTarget->RemoveEventListenerByIID(
static_cast<nsIDOMCompositionListener*>(this),
NS_GET_IID(nsIDOMCompositionListener));
}
already_AddRefed<nsIPresShell>
nsEditorEventListener::GetPresShell()
{
NS_ENSURE_TRUE(mEditor, nsnull);
// mEditor is nsEditor or its inherited class.
// This is guaranteed by constructor.
NS_PRECONDITION(mEditor,
"The caller must check whether this is connected to an editor");
nsCOMPtr<nsIPresShell> ps;
static_cast<nsEditor*>(mEditor)->GetPresShell(getter_AddRefs(ps));
mEditor->GetPresShell(getter_AddRefs(ps));
return ps.forget();
}
@ -121,6 +273,8 @@ NS_INTERFACE_MAP_END
NS_IMETHODIMP
nsEditorEventListener::HandleEvent(nsIDOMEvent* aEvent)
{
NS_ENSURE_TRUE(mEditor, NS_ERROR_NOT_AVAILABLE);
nsCOMPtr<nsIDOMDragEvent> dragEvent = do_QueryInterface(aEvent);
if (dragEvent) {
nsAutoString eventType;
@ -146,18 +300,24 @@ nsEditorEventListener::HandleEvent(nsIDOMEvent* aEvent)
NS_IMETHODIMP
nsEditorEventListener::KeyDown(nsIDOMEvent* aKeyEvent)
{
// WARNING: If you change this method, you comment out next line.
// NS_ENSURE_TRUE(mEditor, NS_ERROR_NOT_AVAILABLE);
return NS_OK;
}
NS_IMETHODIMP
nsEditorEventListener::KeyUp(nsIDOMEvent* aKeyEvent)
{
// WARNING: If you change this method, you comment out next line.
// NS_ENSURE_TRUE(mEditor, NS_ERROR_NOT_AVAILABLE);
return NS_OK;
}
NS_IMETHODIMP
nsEditorEventListener::KeyPress(nsIDOMEvent* aKeyEvent)
{
NS_ENSURE_TRUE(mEditor, NS_ERROR_NOT_AVAILABLE);
// DOM event handling happens in two passes, the client pass and the system
// pass. We do all of our processing in the system pass, to allow client
// handlers the opportunity to cancel events and prevent typing in the editor.
@ -184,8 +344,7 @@ nsEditorEventListener::KeyPress(nsIDOMEvent* aKeyEvent)
keyEvent->GetKeyCode(&keyCode);
// if we are readonly or disabled, then do nothing.
nsEditor* editor = static_cast<nsEditor*>(mEditor);
if (editor->IsReadonly() || editor->IsDisabled())
if (mEditor->IsReadonly() || mEditor->IsDisabled())
{
// consume backspace for disabled and readonly textfields, to prevent
// back in history, which could be confusing to users
@ -195,8 +354,9 @@ nsEditorEventListener::KeyPress(nsIDOMEvent* aKeyEvent)
return NS_OK;
}
nsCOMPtr<nsIPlaintextEditor> textEditor (do_QueryInterface(mEditor));
if (!textEditor) return NS_ERROR_NO_INTERFACE;
nsCOMPtr<nsIPlaintextEditor> textEditor =
do_QueryInterface(static_cast<nsIEditor*>(mEditor));
NS_ASSERTION(textEditor, "nsEditor must have nsIPlaintextEditor");
// if there is no charCode, then it's a key that doesn't map to a character,
// so look for special keys using keyCode.
@ -254,8 +414,8 @@ nsEditorEventListener::KeyPress(nsIDOMEvent* aKeyEvent)
break;
case nsIDOMKeyEvent::DOM_VK_TAB:
if (editor->IsSingleLineEditor() || editor->IsPasswordEditor() ||
editor->IsFormWidget() || editor->IsInteractionAllowed()) {
if (mEditor->IsSingleLineEditor() || mEditor->IsPasswordEditor() ||
mEditor->IsFormWidget() || mEditor->IsInteractionAllowed()) {
return NS_OK; // let it be used for focus switching
}
@ -272,7 +432,7 @@ nsEditorEventListener::KeyPress(nsIDOMEvent* aKeyEvent)
if (isAnyModifierKeyButShift)
return NS_OK;
if (!editor->IsSingleLineEditor())
if (!mEditor->IsSingleLineEditor())
{
textEditor->HandleKeyPress(keyEvent);
aKeyEvent->PreventDefault(); // consumed
@ -292,6 +452,8 @@ nsEditorEventListener::KeyPress(nsIDOMEvent* aKeyEvent)
NS_IMETHODIMP
nsEditorEventListener::MouseClick(nsIDOMEvent* aMouseEvent)
{
NS_ENSURE_TRUE(mEditor, NS_ERROR_NOT_AVAILABLE);
nsCOMPtr<nsIDOMMouseEvent> mouseEvent = do_QueryInterface(aMouseEvent);
nsCOMPtr<nsIDOMNSEvent> nsevent = do_QueryInterface(aMouseEvent);
PRBool isTrusted = PR_FALSE;
@ -314,14 +476,9 @@ nsEditorEventListener::MouseClick(nsIDOMEvent* aMouseEvent)
return rv;
}
nsCOMPtr<nsIEditor> editor = do_QueryInterface(mEditor);
if (!editor) { return NS_OK; }
// If we got a mouse down inside the editing area, we should force the
// IME to commit before we change the cursor position
nsCOMPtr<nsIEditorIMESupport> imeEditor = do_QueryInterface(mEditor);
if (imeEditor)
imeEditor->ForceCompositionEnd();
mEditor->ForceCompositionEnd();
PRUint16 button = (PRUint16)-1;
mouseEvent->GetButton(&button);
@ -345,7 +502,7 @@ nsEditorEventListener::MouseClick(nsIDOMEvent* aMouseEvent)
return NS_ERROR_NULL_POINTER;
nsCOMPtr<nsISelection> selection;
if (NS_SUCCEEDED(editor->GetSelection(getter_AddRefs(selection))))
if (NS_SUCCEEDED(mEditor->GetSelection(getter_AddRefs(selection))))
(void)selection->Collapse(parent, offset);
// If the ctrl key is pressed, we'll do paste as quotation.
@ -355,7 +512,7 @@ nsEditorEventListener::MouseClick(nsIDOMEvent* aMouseEvent)
nsCOMPtr<nsIEditorMailSupport> mailEditor;
if (ctrlKey)
mailEditor = do_QueryInterface(mEditor);
mailEditor = do_QueryInterface(static_cast<nsIEditor*>(mEditor));
PRInt32 clipboard;
@ -368,7 +525,7 @@ nsEditorEventListener::MouseClick(nsIDOMEvent* aMouseEvent)
if (mailEditor)
mailEditor->PasteAsQuotation(clipboard);
else
editor->Paste(clipboard);
mEditor->Paste(clipboard);
// Prevent the event from propagating up to be possibly handled
// again by the containing window:
@ -386,34 +543,40 @@ nsEditorEventListener::MouseClick(nsIDOMEvent* aMouseEvent)
NS_IMETHODIMP
nsEditorEventListener::MouseDown(nsIDOMEvent* aMouseEvent)
{
nsCOMPtr<nsIEditorIMESupport> imeEditor = do_QueryInterface(mEditor);
if (!imeEditor)
return NS_OK;
imeEditor->ForceCompositionEnd();
NS_ENSURE_TRUE(mEditor, NS_ERROR_NOT_AVAILABLE);
mEditor->ForceCompositionEnd();
return NS_OK;
}
NS_IMETHODIMP
nsEditorEventListener::MouseUp(nsIDOMEvent* aMouseEvent)
{
// WARNING: If you change this method, you comment out next line.
// NS_ENSURE_TRUE(mEditor, NS_ERROR_NOT_AVAILABLE);
return NS_OK;
}
NS_IMETHODIMP
nsEditorEventListener::MouseDblClick(nsIDOMEvent* aMouseEvent)
{
// WARNING: If you change this method, you comment out next line.
// NS_ENSURE_TRUE(mEditor, NS_ERROR_NOT_AVAILABLE);
return NS_OK;
}
NS_IMETHODIMP
nsEditorEventListener::MouseOver(nsIDOMEvent* aMouseEvent)
{
// WARNING: If you change this method, you comment out next line.
// NS_ENSURE_TRUE(mEditor, NS_ERROR_NOT_AVAILABLE);
return NS_OK;
}
NS_IMETHODIMP
nsEditorEventListener::MouseOut(nsIDOMEvent* aMouseEvent)
{
// WARNING: If you change this method, you comment out next line.
// NS_ENSURE_TRUE(mEditor, NS_ERROR_NOT_AVAILABLE);
return NS_OK;
}
@ -424,6 +587,8 @@ nsEditorEventListener::MouseOut(nsIDOMEvent* aMouseEvent)
NS_IMETHODIMP
nsEditorEventListener::HandleText(nsIDOMEvent* aTextEvent)
{
NS_ENSURE_TRUE(mEditor, NS_ERROR_NOT_AVAILABLE);
nsCOMPtr<nsIPrivateTextEvent> textEvent = do_QueryInterface(aTextEvent);
if (!textEvent) {
//non-ui event passed in. bad things.
@ -436,13 +601,12 @@ nsEditorEventListener::HandleText(nsIDOMEvent* aTextEvent)
textEvent->GetText(composedText);
textRangeList = textEvent->GetInputRange();
nsEditor* editor = static_cast<nsEditor*>(mEditor);
// if we are readonly or disabled, then do nothing.
if (editor->IsReadonly() || editor->IsDisabled()) {
if (mEditor->IsReadonly() || mEditor->IsDisabled()) {
return NS_OK;
}
return editor->SetCompositionString(composedText, textRangeList);
return mEditor->SetCompositionString(composedText, textRangeList);
}
/**
@ -452,9 +616,6 @@ nsEditorEventListener::HandleText(nsIDOMEvent* aTextEvent)
nsresult
nsEditorEventListener::DragGesture(nsIDOMDragEvent* aDragEvent)
{
if ( !mEditor )
return NS_ERROR_NULL_POINTER;
// ...figure out if a drag should be started...
PRBool canDrag;
nsresult rv = mEditor->CanDrag(aDragEvent, &canDrag);
@ -574,9 +735,6 @@ nsEditorEventListener::Drop(nsIDOMDragEvent* aMouseEvent)
}
}
if (!mEditor)
return NS_ERROR_FAILURE;
nsCOMPtr<nsIDOMNSUIEvent> nsuiEvent = do_QueryInterface(aMouseEvent);
if (nsuiEvent) {
PRBool defaultPrevented;
@ -598,8 +756,7 @@ nsEditorEventListener::Drop(nsIDOMDragEvent* aMouseEvent)
if (!canDrop)
{
// was it because we're read-only?
nsEditor* editor = static_cast<nsEditor*>(mEditor);
if (editor->IsReadonly() || editor->IsDisabled())
if (mEditor->IsReadonly() || mEditor->IsDisabled())
{
// it was decided to "eat" the event as this is the "least surprise"
// since someone else handling it might be unintentional and the
@ -621,8 +778,7 @@ PRBool
nsEditorEventListener::CanDrop(nsIDOMDragEvent* aEvent)
{
// if the target doc is read-only, we can't drop
nsEditor* editor = static_cast<nsEditor*>(mEditor);
if (editor->IsReadonly() || editor->IsDisabled()) {
if (mEditor->IsReadonly() || mEditor->IsDisabled()) {
return PR_FALSE;
}
@ -642,7 +798,7 @@ nsEditorEventListener::CanDrop(nsIDOMDragEvent* aEvent)
types->Contains(NS_LITERAL_STRING(kTextMime), &typeSupported);
if (!typeSupported) {
types->Contains(NS_LITERAL_STRING(kMozTextInternal), &typeSupported);
if (!typeSupported && !editor->IsPlaintextEditor()) {
if (!typeSupported && !mEditor->IsPlaintextEditor()) {
types->Contains(NS_LITERAL_STRING(kHTMLMime), &typeSupported);
if (!typeSupported) {
types->Contains(NS_LITERAL_STRING(kFileMime), &typeSupported);
@ -730,13 +886,15 @@ nsEditorEventListener::CanDrop(nsIDOMDragEvent* aEvent)
NS_IMETHODIMP
nsEditorEventListener::HandleStartComposition(nsIDOMEvent* aCompositionEvent)
{
return static_cast<nsEditor*>(mEditor)->BeginComposition();
NS_ENSURE_TRUE(mEditor, NS_ERROR_NOT_AVAILABLE);
return mEditor->BeginComposition();
}
NS_IMETHODIMP
nsEditorEventListener::HandleEndComposition(nsIDOMEvent* aCompositionEvent)
{
return static_cast<nsEditor*>(mEditor)->EndComposition();
NS_ENSURE_TRUE(mEditor, NS_ERROR_NOT_AVAILABLE);
return mEditor->EndComposition();
}
/**
@ -746,6 +904,7 @@ nsEditorEventListener::HandleEndComposition(nsIDOMEvent* aCompositionEvent)
static already_AddRefed<nsIContent>
FindSelectionRoot(nsEditor *aEditor, nsIContent *aContent)
{
NS_PRECONDITION(aEditor, "aEditor must not be null");
nsIDocument *document = aContent->GetCurrentDoc();
if (!document) {
return nsnull;
@ -790,79 +949,77 @@ FindSelectionRoot(nsEditor *aEditor, nsIContent *aContent)
NS_IMETHODIMP
nsEditorEventListener::Focus(nsIDOMEvent* aEvent)
{
NS_ENSURE_TRUE(mEditor, NS_ERROR_NOT_AVAILABLE);
NS_ENSURE_ARG(aEvent);
nsCOMPtr<nsIDOMEventTarget> target;
aEvent->GetTarget(getter_AddRefs(target));
// turn on selection and caret
if (mEditor)
if (mEditor->IsDisabled()) {
return NS_OK;
}
nsCOMPtr<nsIContent> content = do_QueryInterface(target);
PRBool targetIsEditableDoc = PR_FALSE;
nsCOMPtr<nsIContent> editableRoot;
if (content) {
editableRoot = FindSelectionRoot(mEditor, content);
// make sure that the element is really focused in case an earlier
// listener in the chain changed the focus.
if (editableRoot) {
nsIFocusManager* fm = nsFocusManager::GetFocusManager();
NS_ENSURE_TRUE(fm, NS_OK);
nsCOMPtr<nsIDOMElement> element;
fm->GetFocusedElement(getter_AddRefs(element));
if (!SameCOMIdentity(element, target))
return NS_OK;
}
}
else {
nsCOMPtr<nsIDocument> document = do_QueryInterface(target);
targetIsEditableDoc = document && document->HasFlag(NODE_IS_EDITABLE);
}
nsCOMPtr<nsISelectionController> selCon;
mEditor->GetSelectionController(getter_AddRefs(selCon));
if (selCon && (targetIsEditableDoc || editableRoot))
{
nsEditor* editor = static_cast<nsEditor*>(mEditor);
if (!editor->IsDisabled())
{ // only enable caret and selection if the editor is not disabled
nsCOMPtr<nsIContent> content = do_QueryInterface(target);
nsCOMPtr<nsISelection> selection;
selCon->GetSelection(nsISelectionController::SELECTION_NORMAL,
getter_AddRefs(selection));
PRBool targetIsEditableDoc = PR_FALSE;
nsCOMPtr<nsIContent> editableRoot;
if (content) {
editableRoot = FindSelectionRoot(editor, content);
// make sure that the element is really focused in case an earlier
// listener in the chain changed the focus.
if (editableRoot) {
nsIFocusManager* fm = nsFocusManager::GetFocusManager();
NS_ENSURE_TRUE(fm, NS_OK);
nsCOMPtr<nsIDOMElement> element;
fm->GetFocusedElement(getter_AddRefs(element));
if (!SameCOMIdentity(element, target))
return NS_OK;
nsCOMPtr<nsIPresShell> presShell = GetPresShell();
if (presShell) {
nsRefPtr<nsCaret> caret = presShell->GetCaret();
if (caret) {
caret->SetIgnoreUserModify(PR_FALSE);
if (selection) {
caret->SetCaretDOMSelection(selection);
}
}
else {
nsCOMPtr<nsIDocument> document = do_QueryInterface(target);
targetIsEditableDoc = document && document->HasFlag(NODE_IS_EDITABLE);
}
}
nsCOMPtr<nsISelectionController> selCon;
mEditor->GetSelectionController(getter_AddRefs(selCon));
if (selCon && (targetIsEditableDoc || editableRoot))
{
nsCOMPtr<nsISelection> selection;
selCon->GetSelection(nsISelectionController::SELECTION_NORMAL,
getter_AddRefs(selection));
selCon->SetCaretReadOnly(mEditor->IsReadonly());
selCon->SetCaretEnabled(PR_TRUE);
selCon->SetDisplaySelection(nsISelectionController::SELECTION_ON);
selCon->RepaintSelection(nsISelectionController::SELECTION_NORMAL);
nsCOMPtr<nsIPresShell> presShell = GetPresShell();
if (presShell) {
nsRefPtr<nsCaret> caret = presShell->GetCaret();
if (caret) {
caret->SetIgnoreUserModify(PR_FALSE);
if (selection) {
caret->SetCaretDOMSelection(selection);
}
}
}
nsCOMPtr<nsISelectionPrivate> selectionPrivate =
do_QueryInterface(selection);
if (selectionPrivate)
{
selectionPrivate->SetAncestorLimiter(editableRoot);
}
selCon->SetCaretReadOnly(editor->IsReadonly());
selCon->SetCaretEnabled(PR_TRUE);
selCon->SetDisplaySelection(nsISelectionController::SELECTION_ON);
selCon->RepaintSelection(nsISelectionController::SELECTION_NORMAL);
nsCOMPtr<nsISelectionPrivate> selectionPrivate =
do_QueryInterface(selection);
if (selectionPrivate)
{
selectionPrivate->SetAncestorLimiter(editableRoot);
}
if (selection && !editableRoot) {
PRInt32 rangeCount;
selection->GetRangeCount(&rangeCount);
if (rangeCount == 0) {
mEditor->BeginningOfDocument();
}
}
if (selection && !editableRoot) {
PRInt32 rangeCount;
selection->GetRangeCount(&rangeCount);
if (rangeCount == 0) {
mEditor->BeginningOfDocument();
}
}
}
@ -872,6 +1029,9 @@ nsEditorEventListener::Focus(nsIDOMEvent* aEvent)
NS_IMETHODIMP
nsEditorEventListener::Blur(nsIDOMEvent* aEvent)
{
NS_ENSURE_TRUE(mEditor, NS_ERROR_NOT_AVAILABLE);
NS_ENSURE_ARG(aEvent);
// check if something else is focused. If another element is focused, then
// we should not change the selection.
nsIFocusManager* fm = nsFocusManager::GetFocusManager();
@ -882,52 +1042,43 @@ nsEditorEventListener::Blur(nsIDOMEvent* aEvent)
if (element)
return NS_OK;
NS_ENSURE_ARG(aEvent);
// turn off selection and caret
if (mEditor)
nsCOMPtr<nsISelectionController>selCon;
mEditor->GetSelectionController(getter_AddRefs(selCon));
if (selCon)
{
nsCOMPtr<nsIEditor>editor = do_QueryInterface(mEditor);
if (editor)
{
nsCOMPtr<nsISelectionController>selCon;
editor->GetSelectionController(getter_AddRefs(selCon));
if (selCon)
{
nsCOMPtr<nsISelection> selection;
selCon->GetSelection(nsISelectionController::SELECTION_NORMAL,
getter_AddRefs(selection));
nsCOMPtr<nsISelection> selection;
selCon->GetSelection(nsISelectionController::SELECTION_NORMAL,
getter_AddRefs(selection));
nsCOMPtr<nsISelectionPrivate> selectionPrivate =
do_QueryInterface(selection);
if (selectionPrivate) {
selectionPrivate->SetAncestorLimiter(nsnull);
}
nsCOMPtr<nsISelectionPrivate> selectionPrivate =
do_QueryInterface(selection);
if (selectionPrivate) {
selectionPrivate->SetAncestorLimiter(nsnull);
}
nsCOMPtr<nsIPresShell> presShell = GetPresShell();
if (presShell) {
nsRefPtr<nsCaret> caret = presShell->GetCaret();
if (caret) {
caret->SetIgnoreUserModify(PR_TRUE);
}
}
selCon->SetCaretEnabled(PR_FALSE);
nsEditor* editor = static_cast<nsEditor*>(mEditor);
if(editor->IsFormWidget() || editor->IsPasswordEditor() ||
editor->IsReadonly() || editor->IsDisabled() ||
editor->IsInputFiltered())
{
selCon->SetDisplaySelection(nsISelectionController::SELECTION_HIDDEN);//hide but do NOT turn off
}
else
{
selCon->SetDisplaySelection(nsISelectionController::SELECTION_DISABLED);
}
selCon->RepaintSelection(nsISelectionController::SELECTION_NORMAL);
nsCOMPtr<nsIPresShell> presShell = GetPresShell();
if (presShell) {
nsRefPtr<nsCaret> caret = presShell->GetCaret();
if (caret) {
caret->SetIgnoreUserModify(PR_TRUE);
}
}
selCon->SetCaretEnabled(PR_FALSE);
if(mEditor->IsFormWidget() || mEditor->IsPasswordEditor() ||
mEditor->IsReadonly() || mEditor->IsDisabled() ||
mEditor->IsInputFiltered())
{
selCon->SetDisplaySelection(nsISelectionController::SELECTION_HIDDEN);//hide but do NOT turn off
}
else
{
selCon->SetDisplaySelection(nsISelectionController::SELECTION_DISABLED);
}
selCon->RepaintSelection(nsISelectionController::SELECTION_NORMAL);
}
return NS_OK;

View File

@ -61,9 +61,13 @@ class nsEditorEventListener : public nsIDOMKeyListener,
public nsIDOMFocusListener
{
public:
nsEditorEventListener(nsEditor* aEditor);
nsEditorEventListener();
virtual ~nsEditorEventListener();
virtual nsresult Connect(nsEditor* aEditor);
void Disconnect();
NS_DECL_ISUPPORTS
NS_DECL_NSIDOMEVENTLISTENER
@ -92,6 +96,9 @@ public:
NS_IMETHOD Blur(nsIDOMEvent* aEvent);
protected:
nsresult InstallToEditor();
void UninstallFromEditor();
PRBool CanDrop(nsIDOMDragEvent* aEvent);
nsresult DragEnter(nsIDOMDragEvent* aDragEvent);
nsresult DragOver(nsIDOMDragEvent* aDragEvent);
@ -101,7 +108,7 @@ protected:
already_AddRefed<nsIPresShell> GetPresShell();
protected:
nsIEditor* mEditor; // weak
nsEditor* mEditor; // weak
nsRefPtr<nsCaret> mCaret;
PRPackedBool mCaretDrawn;
PRPackedBool mCommitText;

View File

@ -336,11 +336,21 @@ nsHTMLEditor::CreateEventListeners()
{
NS_ENSURE_TRUE(!mEventListener, NS_ERROR_ALREADY_INITIALIZED);
mEventListener = do_QueryInterface(
static_cast<nsIDOMKeyListener*>(new nsHTMLEditorEventListener(this)));
static_cast<nsIDOMKeyListener*>(new nsHTMLEditorEventListener()));
NS_ENSURE_TRUE(mEventListener, NS_ERROR_OUT_OF_MEMORY);
return NS_OK;
}
nsresult
nsHTMLEditor::InstallEventListeners()
{
NS_ENSURE_TRUE(mDocWeak && mPresShellWeak && mEventListener,
NS_ERROR_NOT_INITIALIZED);
nsHTMLEditorEventListener* listener =
reinterpret_cast<nsHTMLEditorEventListener*>(mEventListener.get());
return listener->Connect(this);
}
void
nsHTMLEditor::RemoveEventListeners()
{

View File

@ -429,6 +429,7 @@ protected:
// Create the event listeners for the editor to install
virtual nsresult CreateEventListeners();
virtual nsresult InstallEventListeners();
virtual void RemoveEventListeners();
// Return TRUE if aElement is a table-related elemet and caret was set

View File

@ -38,6 +38,7 @@
*
* ***** END LICENSE BLOCK ***** */
#include "nsHTMLEditorEventListener.h"
#include "nsHTMLEditor.h"
#include "nsString.h"
#include "nsIDOMEvent.h"
@ -53,13 +54,10 @@
#include "nsIDOMHTMLTableCellElement.h"
#include "nsIContent.h"
#include "nsIEditor.h"
#include "nsIHTMLEditor.h"
#include "nsIHTMLObjectResizer.h"
#include "nsEditProperty.h"
#include "nsTextEditUtils.h"
#include "nsHTMLEditUtils.h"
#include "nsIHTMLInlineTableEditor.h"
/*
* nsHTMLEditorEventListener implementation
@ -68,31 +66,50 @@
* moves the caret or selects an element as it does for normal click
*/
#ifdef DEBUG
nsresult
nsHTMLEditorEventListener::Connect(nsEditor* aEditor)
{
nsCOMPtr<nsIHTMLEditor> htmlEditor =
do_QueryInterface(static_cast<nsIEditor*>(aEditor));
nsCOMPtr<nsIHTMLInlineTableEditor> htmlInlineTableEditor =
do_QueryInterface(static_cast<nsIEditor*>(aEditor));
NS_PRECONDITION(htmlEditor && htmlInlineTableEditor,
"Set nsHTMLEditor or its sub class");
return nsEditorEventListener::Connect(aEditor);
}
#endif
nsHTMLEditor*
nsHTMLEditorEventListener::GetHTMLEditor()
{
// mEditor must be nsHTMLEditor or its subclass.
return static_cast<nsHTMLEditor*>(mEditor);
}
NS_IMETHODIMP
nsHTMLEditorEventListener::MouseUp(nsIDOMEvent* aMouseEvent)
{
NS_ENSURE_TRUE(mEditor, NS_ERROR_NOT_AVAILABLE);
nsCOMPtr<nsIDOMMouseEvent> mouseEvent ( do_QueryInterface(aMouseEvent) );
if (!mouseEvent) {
//non-ui event passed in. bad things.
return NS_OK;
}
// Don't do anything special if not an HTML editor
nsCOMPtr<nsIHTMLEditor> htmlEditor = do_QueryInterface(mEditor);
if (htmlEditor)
{
nsCOMPtr<nsIDOMEventTarget> target;
nsresult res = aMouseEvent->GetTarget(getter_AddRefs(target));
if (NS_FAILED(res)) return res;
if (!target) return NS_ERROR_NULL_POINTER;
nsCOMPtr<nsIDOMElement> element = do_QueryInterface(target);
nsHTMLEditor* htmlEditor = GetHTMLEditor();
nsCOMPtr<nsIHTMLObjectResizer> objectResizer = do_QueryInterface(htmlEditor);
PRInt32 clientX, clientY;
mouseEvent->GetClientX(&clientX);
mouseEvent->GetClientY(&clientY);
objectResizer->MouseUp(clientX, clientY, element);
}
nsCOMPtr<nsIDOMEventTarget> target;
nsresult res = aMouseEvent->GetTarget(getter_AddRefs(target));
if (NS_FAILED(res)) return res;
if (!target) return NS_ERROR_NULL_POINTER;
nsCOMPtr<nsIDOMElement> element = do_QueryInterface(target);
PRInt32 clientX, clientY;
mouseEvent->GetClientX(&clientX);
mouseEvent->GetClientY(&clientY);
htmlEditor->MouseUp(clientX, clientY, element);
return nsEditorEventListener::MouseUp(aMouseEvent);
}
@ -100,175 +117,172 @@ nsHTMLEditorEventListener::MouseUp(nsIDOMEvent* aMouseEvent)
NS_IMETHODIMP
nsHTMLEditorEventListener::MouseDown(nsIDOMEvent* aMouseEvent)
{
NS_ENSURE_TRUE(mEditor, NS_ERROR_NOT_AVAILABLE);
nsCOMPtr<nsIDOMMouseEvent> mouseEvent ( do_QueryInterface(aMouseEvent) );
if (!mouseEvent) {
//non-ui event passed in. bad things.
return NS_OK;
}
// Don't do anything special if not an HTML editor
nsCOMPtr<nsIHTMLEditor> htmlEditor = do_QueryInterface(mEditor);
if (htmlEditor)
{
// Detect only "context menu" click
//XXX This should be easier to do!
// But eDOMEvents_contextmenu and NS_CONTEXTMENU is not exposed in any event interface :-(
PRUint16 buttonNumber;
nsresult res = mouseEvent->GetButton(&buttonNumber);
if (NS_FAILED(res)) return res;
nsHTMLEditor* htmlEditor = GetHTMLEditor();
PRBool isContextClick;
// Detect only "context menu" click
//XXX This should be easier to do!
// But eDOMEvents_contextmenu and NS_CONTEXTMENU is not exposed in any event interface :-(
PRUint16 buttonNumber;
nsresult res = mouseEvent->GetButton(&buttonNumber);
if (NS_FAILED(res)) return res;
PRBool isContextClick;
#if defined(XP_MAC) || defined(XP_MACOSX)
// Ctrl+Click for context menu
res = mouseEvent->GetCtrlKey(&isContextClick);
if (NS_FAILED(res)) return res;
// Ctrl+Click for context menu
res = mouseEvent->GetCtrlKey(&isContextClick);
if (NS_FAILED(res)) return res;
#else
// Right mouse button for Windows, UNIX
isContextClick = buttonNumber == 2;
// Right mouse button for Windows, UNIX
isContextClick = buttonNumber == 2;
#endif
PRInt32 clickCount;
res = mouseEvent->GetDetail(&clickCount);
PRInt32 clickCount;
res = mouseEvent->GetDetail(&clickCount);
if (NS_FAILED(res)) return res;
nsCOMPtr<nsIDOMEventTarget> target;
nsCOMPtr<nsIDOMNSEvent> internalEvent = do_QueryInterface(aMouseEvent);
res = internalEvent->GetExplicitOriginalTarget(getter_AddRefs(target));
if (NS_FAILED(res)) return res;
if (!target) return NS_ERROR_NULL_POINTER;
nsCOMPtr<nsIDOMElement> element = do_QueryInterface(target);
if (isContextClick || (buttonNumber == 0 && clickCount == 2))
{
nsCOMPtr<nsISelection> selection;
mEditor->GetSelection(getter_AddRefs(selection));
if (!selection) return NS_OK;
// Get location of mouse within target node
nsCOMPtr<nsIDOMNSUIEvent> uiEvent = do_QueryInterface(aMouseEvent);
if (!uiEvent) return NS_ERROR_FAILURE;
nsCOMPtr<nsIDOMNode> parent;
PRInt32 offset = 0;
res = uiEvent->GetRangeParent(getter_AddRefs(parent));
if (NS_FAILED(res)) return res;
if (!parent) return NS_ERROR_FAILURE;
res = uiEvent->GetRangeOffset(&offset);
if (NS_FAILED(res)) return res;
nsCOMPtr<nsIDOMEventTarget> target;
nsCOMPtr<nsIDOMNSEvent> internalEvent = do_QueryInterface(aMouseEvent);
res = internalEvent->GetExplicitOriginalTarget(getter_AddRefs(target));
if (NS_FAILED(res)) return res;
if (!target) return NS_ERROR_NULL_POINTER;
nsCOMPtr<nsIDOMElement> element = do_QueryInterface(target);
if (isContextClick || (buttonNumber == 0 && clickCount == 2))
// Detect if mouse point is within current selection for context click
PRBool nodeIsInSelection = PR_FALSE;
if (isContextClick)
{
nsCOMPtr<nsISelection> selection;
mEditor->GetSelection(getter_AddRefs(selection));
if (!selection) return NS_OK;
// Get location of mouse within target node
nsCOMPtr<nsIDOMNSUIEvent> uiEvent = do_QueryInterface(aMouseEvent);
if (!uiEvent) return NS_ERROR_FAILURE;
nsCOMPtr<nsIDOMNode> parent;
PRInt32 offset = 0;
res = uiEvent->GetRangeParent(getter_AddRefs(parent));
if (NS_FAILED(res)) return res;
if (!parent) return NS_ERROR_FAILURE;
res = uiEvent->GetRangeOffset(&offset);
if (NS_FAILED(res)) return res;
// Detect if mouse point is within current selection for context click
PRBool nodeIsInSelection = PR_FALSE;
if (isContextClick)
PRBool isCollapsed;
selection->GetIsCollapsed(&isCollapsed);
if (!isCollapsed)
{
PRBool isCollapsed;
selection->GetIsCollapsed(&isCollapsed);
if (!isCollapsed)
PRInt32 rangeCount;
res = selection->GetRangeCount(&rangeCount);
if (NS_FAILED(res)) return res;
for (PRInt32 i = 0; i < rangeCount; i++)
{
PRInt32 rangeCount;
res = selection->GetRangeCount(&rangeCount);
if (NS_FAILED(res)) return res;
nsCOMPtr<nsIDOMRange> range;
for (PRInt32 i = 0; i < rangeCount; i++)
{
nsCOMPtr<nsIDOMRange> range;
res = selection->GetRangeAt(i, getter_AddRefs(range));
if (NS_FAILED(res) || !range)
continue;//don't bail yet, iterate through them all
res = selection->GetRangeAt(i, getter_AddRefs(range));
if (NS_FAILED(res) || !range)
continue;//don't bail yet, iterate through them all
nsCOMPtr<nsIDOMNSRange> nsrange(do_QueryInterface(range));
if (NS_FAILED(res) || !nsrange)
continue;//don't bail yet, iterate through them all
nsCOMPtr<nsIDOMNSRange> nsrange(do_QueryInterface(range));
if (NS_FAILED(res) || !nsrange)
continue;//don't bail yet, iterate through them all
res = nsrange->IsPointInRange(parent, offset, &nodeIsInSelection);
res = nsrange->IsPointInRange(parent, offset, &nodeIsInSelection);
// Done when we find a range that we are in
if (nodeIsInSelection)
break;
}
// Done when we find a range that we are in
if (nodeIsInSelection)
break;
}
}
nsCOMPtr<nsIDOMNode> node = do_QueryInterface(target);
if (node && !nodeIsInSelection)
}
nsCOMPtr<nsIDOMNode> node = do_QueryInterface(target);
if (node && !nodeIsInSelection)
{
if (!element)
{
if (!element)
if (isContextClick)
{
if (isContextClick)
// Set the selection to the point under the mouse cursor:
selection->Collapse(parent, offset);
}
else
{
// Get enclosing link if in text so we can select the link
nsCOMPtr<nsIDOMElement> linkElement;
res = htmlEditor->GetElementOrParentByTagName(NS_LITERAL_STRING("href"), node, getter_AddRefs(linkElement));
if (NS_FAILED(res)) return res;
if (linkElement)
element = linkElement;
}
}
// Select entire element clicked on if NOT within an existing selection
// and not the entire body, or table-related elements
if (element)
{
nsCOMPtr<nsIDOMNode> selectAllNode =
htmlEditor->FindUserSelectAllNode(element);
if (selectAllNode)
{
nsCOMPtr<nsIDOMElement> newElement = do_QueryInterface(selectAllNode);
if (newElement)
{
// Set the selection to the point under the mouse cursor:
selection->Collapse(parent, offset);
}
else
{
// Get enclosing link if in text so we can select the link
nsCOMPtr<nsIDOMElement> linkElement;
res = htmlEditor->GetElementOrParentByTagName(NS_LITERAL_STRING("href"), node, getter_AddRefs(linkElement));
if (NS_FAILED(res)) return res;
if (linkElement)
element = linkElement;
node = selectAllNode;
element = newElement;
}
}
// Select entire element clicked on if NOT within an existing selection
// and not the entire body, or table-related elements
if (element)
{
// mEditor must be nsHTMLEditor, see the constructor.
nsCOMPtr<nsIDOMNode> selectAllNode =
reinterpret_cast<nsHTMLEditor*>(mEditor)->FindUserSelectAllNode(element);
if (selectAllNode)
{
nsCOMPtr<nsIDOMElement> newElement = do_QueryInterface(selectAllNode);
if (newElement)
{
node = selectAllNode;
element = newElement;
}
}
// XXX: should we call nsHTMLEditUtils::IsTableElement here?
// that also checks for thead, tbody, tfoot
if (nsTextEditUtils::IsBody(node) ||
nsHTMLEditUtils::IsTableCellOrCaption(node) ||
nsHTMLEditUtils::IsTableRow(node) ||
nsHTMLEditUtils::IsTable(node))
{
// This will place caret just inside table cell or at start of body
selection->Collapse(parent, offset);
}
else
{
htmlEditor->SelectElement(element);
}
if (nsTextEditUtils::IsBody(node) ||
nsHTMLEditUtils::IsTableCellOrCaption(node) ||
nsHTMLEditUtils::IsTableRow(node) ||
nsHTMLEditUtils::IsTable(node))
{
// This will place caret just inside table cell or at start of body
selection->Collapse(parent, offset);
}
else
{
htmlEditor->SelectElement(element);
}
}
// HACK !!! Context click places the caret but the context menu consumes
// the event; so we need to check resizing state ourselves
htmlEditor->CheckSelectionStateForAnonymousButtons(selection);
}
// HACK !!! Context click places the caret but the context menu consumes
// the event; so we need to check resizing state ourselves
htmlEditor->CheckSelectionStateForAnonymousButtons(selection);
// Prevent bubbling if we changed selection or
// for all context clicks
if (element || isContextClick)
{
#ifndef XP_OS2
mouseEvent->PreventDefault();
#endif
return NS_OK;
}
}
else if (!isContextClick && buttonNumber == 0 && clickCount == 1)
// Prevent bubbling if we changed selection or
// for all context clicks
if (element || isContextClick)
{
// if the target element is an image, we have to display resizers
nsCOMPtr<nsIHTMLObjectResizer> objectResizer = do_QueryInterface(htmlEditor);
PRInt32 clientX, clientY;
mouseEvent->GetClientX(&clientX);
mouseEvent->GetClientY(&clientY);
objectResizer->MouseDown(clientX, clientY, element, aMouseEvent);
#ifndef XP_OS2
mouseEvent->PreventDefault();
#endif
return NS_OK;
}
}
else if (!isContextClick && buttonNumber == 0 && clickCount == 1)
{
// if the target element is an image, we have to display resizers
PRInt32 clientX, clientY;
mouseEvent->GetClientX(&clientX);
mouseEvent->GetClientY(&clientY);
htmlEditor->MouseDown(clientX, clientY, element, aMouseEvent);
}
return nsEditorEventListener::MouseDown(aMouseEvent);
}
@ -276,24 +290,21 @@ nsHTMLEditorEventListener::MouseDown(nsIDOMEvent* aMouseEvent)
NS_IMETHODIMP
nsHTMLEditorEventListener::MouseClick(nsIDOMEvent* aMouseEvent)
{
NS_ENSURE_TRUE(mEditor, NS_ERROR_NOT_AVAILABLE);
nsCOMPtr<nsIDOMMouseEvent> mouseEvent ( do_QueryInterface(aMouseEvent) );
if (!mouseEvent) {
//non-ui event passed in. bad things.
return NS_OK;
}
// Don't do anything special if not an HTML inline table editor
nsCOMPtr<nsIHTMLInlineTableEditor> inlineTableEditing = do_QueryInterface(mEditor);
if (inlineTableEditing)
{
nsCOMPtr<nsIDOMEventTarget> target;
nsresult res = aMouseEvent->GetTarget(getter_AddRefs(target));
if (NS_FAILED(res)) return res;
if (!target) return NS_ERROR_NULL_POINTER;
nsCOMPtr<nsIDOMElement> element = do_QueryInterface(target);
nsCOMPtr<nsIDOMEventTarget> target;
nsresult res = aMouseEvent->GetTarget(getter_AddRefs(target));
if (NS_FAILED(res)) return res;
if (!target) return NS_ERROR_NULL_POINTER;
nsCOMPtr<nsIDOMElement> element = do_QueryInterface(target);
inlineTableEditing->DoInlineTableEditingAction(element);
}
GetHTMLEditor()->DoInlineTableEditingAction(element);
return nsEditorEventListener::MouseClick(aMouseEvent);
}

View File

@ -41,13 +41,14 @@
#define nsHTMLEditorEventListener_h__
#include "nsEditorEventListener.h"
#include "nsHTMLEditor.h"
class nsHTMLEditor;
class nsHTMLEditorEventListener : public nsEditorEventListener
{
public:
nsHTMLEditorEventListener(nsHTMLEditor* aEditor) :
nsEditorEventListener(aEditor)
nsHTMLEditorEventListener() :
nsEditorEventListener()
{
}
@ -55,9 +56,17 @@ public:
{
}
#ifdef DEBUG
// WARNING: You must be use nsHTMLEditor or its sub class for this class.
virtual nsresult Connect(nsEditor* aEditor);
#endif
NS_IMETHOD MouseDown(nsIDOMEvent* aMouseEvent);
NS_IMETHOD MouseUp(nsIDOMEvent* aMouseEvent);
NS_IMETHOD MouseClick(nsIDOMEvent* aMouseEvent);
protected:
inline nsHTMLEditor* GetHTMLEditor();
};
#endif // nsHTMLEditorEventListener_h__