1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
10 #include "nsHTMLEditUtils.h"
11 #include "nsHTMLEditor.h"
12 #include "nsHTMLEditorEventListener.h"
13 #include "nsIDOMElement.h"
14 #include "nsIDOMEvent.h"
15 #include "nsIDOMEventTarget.h"
16 #include "nsIDOMMouseEvent.h"
17 #include "nsIDOMNode.h"
18 #include "nsIDOMRange.h"
19 #include "nsIEditor.h"
20 #include "nsIHTMLEditor.h"
21 #include "nsIHTMLInlineTableEditor.h"
22 #include "nsIHTMLObjectResizer.h"
23 #include "nsISelection.h"
24 #include "nsISupportsImpl.h"
25 #include "nsLiteralString.h"
28 * nsHTMLEditorEventListener implementation
34 nsHTMLEditorEventListener::Connect(nsEditor
* aEditor
)
36 nsCOMPtr
<nsIHTMLEditor
> htmlEditor
= do_QueryObject(aEditor
);
37 nsCOMPtr
<nsIHTMLInlineTableEditor
> htmlInlineTableEditor
=
38 do_QueryObject(aEditor
);
39 NS_PRECONDITION(htmlEditor
&& htmlInlineTableEditor
,
40 "Set nsHTMLEditor or its sub class");
41 return nsEditorEventListener::Connect(aEditor
);
46 nsHTMLEditorEventListener::GetHTMLEditor()
48 // mEditor must be nsHTMLEditor or its subclass.
49 return static_cast<nsHTMLEditor
*>(mEditor
);
53 nsHTMLEditorEventListener::MouseUp(nsIDOMMouseEvent
* aMouseEvent
)
55 nsHTMLEditor
* htmlEditor
= GetHTMLEditor();
57 nsCOMPtr
<nsIDOMEventTarget
> target
;
58 nsresult rv
= aMouseEvent
->GetTarget(getter_AddRefs(target
));
59 NS_ENSURE_SUCCESS(rv
, rv
);
60 NS_ENSURE_TRUE(target
, NS_ERROR_NULL_POINTER
);
61 nsCOMPtr
<nsIDOMElement
> element
= do_QueryInterface(target
);
63 int32_t clientX
, clientY
;
64 aMouseEvent
->GetClientX(&clientX
);
65 aMouseEvent
->GetClientY(&clientY
);
66 htmlEditor
->MouseUp(clientX
, clientY
, element
);
68 return nsEditorEventListener::MouseUp(aMouseEvent
);
72 nsHTMLEditorEventListener::MouseDown(nsIDOMMouseEvent
* aMouseEvent
)
74 nsHTMLEditor
* htmlEditor
= GetHTMLEditor();
76 // Detect only "context menu" click
77 // XXX This should be easier to do!
78 // But eDOMEvents_contextmenu and NS_CONTEXTMENU is not exposed in any event
81 nsresult rv
= aMouseEvent
->GetButton(&buttonNumber
);
82 NS_ENSURE_SUCCESS(rv
, rv
);
84 bool isContextClick
= buttonNumber
== 2;
87 rv
= aMouseEvent
->GetDetail(&clickCount
);
88 NS_ENSURE_SUCCESS(rv
, rv
);
90 nsCOMPtr
<nsIDOMEventTarget
> target
;
91 rv
= aMouseEvent
->GetExplicitOriginalTarget(getter_AddRefs(target
));
92 NS_ENSURE_SUCCESS(rv
, rv
);
93 NS_ENSURE_TRUE(target
, NS_ERROR_NULL_POINTER
);
94 nsCOMPtr
<nsIDOMElement
> element
= do_QueryInterface(target
);
96 // Contenteditable should disregard mousedowns outside it
97 if (element
&& !htmlEditor
->IsDescendantOfEditorRoot(element
)) {
101 if (isContextClick
|| (buttonNumber
== 0 && clickCount
== 2)) {
102 nsCOMPtr
<nsISelection
> selection
;
103 mEditor
->GetSelection(getter_AddRefs(selection
));
104 NS_ENSURE_TRUE(selection
, NS_OK
);
106 // Get location of mouse within target node
107 nsCOMPtr
<nsIDOMNode
> parent
;
108 rv
= aMouseEvent
->GetRangeParent(getter_AddRefs(parent
));
109 NS_ENSURE_SUCCESS(rv
, rv
);
110 NS_ENSURE_TRUE(parent
, NS_ERROR_FAILURE
);
113 rv
= aMouseEvent
->GetRangeOffset(&offset
);
114 NS_ENSURE_SUCCESS(rv
, rv
);
116 // Detect if mouse point is within current selection for context click
117 bool nodeIsInSelection
= false;
118 if (isContextClick
&& !selection
->Collapsed()) {
120 rv
= selection
->GetRangeCount(&rangeCount
);
121 NS_ENSURE_SUCCESS(rv
, rv
);
123 for (int32_t i
= 0; i
< rangeCount
; i
++) {
124 nsCOMPtr
<nsIDOMRange
> range
;
126 rv
= selection
->GetRangeAt(i
, getter_AddRefs(range
));
127 if (NS_FAILED(rv
) || !range
) {
128 // Don't bail yet, iterate through them all
132 range
->IsPointInRange(parent
, offset
, &nodeIsInSelection
);
134 // Done when we find a range that we are in
135 if (nodeIsInSelection
) {
140 nsCOMPtr
<nsIDOMNode
> node
= do_QueryInterface(target
);
141 if (node
&& !nodeIsInSelection
) {
143 if (isContextClick
) {
144 // Set the selection to the point under the mouse cursor:
145 selection
->Collapse(parent
, offset
);
147 // Get enclosing link if in text so we can select the link
148 nsCOMPtr
<nsIDOMElement
> linkElement
;
149 rv
= htmlEditor
->GetElementOrParentByTagName(
150 NS_LITERAL_STRING("href"), node
,
151 getter_AddRefs(linkElement
));
152 NS_ENSURE_SUCCESS(rv
, rv
);
154 element
= linkElement
;
158 // Select entire element clicked on if NOT within an existing selection
159 // and not the entire body, or table-related elements
161 nsCOMPtr
<nsIDOMNode
> selectAllNode
=
162 htmlEditor
->FindUserSelectAllNode(element
);
165 nsCOMPtr
<nsIDOMElement
> newElement
= do_QueryInterface(selectAllNode
);
167 node
= selectAllNode
;
168 element
= newElement
;
172 if (isContextClick
&& !nsHTMLEditUtils::IsImage(node
)) {
173 selection
->Collapse(parent
, offset
);
175 htmlEditor
->SelectElement(element
);
179 // HACK !!! Context click places the caret but the context menu consumes
180 // the event; so we need to check resizing state ourselves
181 htmlEditor
->CheckSelectionStateForAnonymousButtons(selection
);
183 // Prevent bubbling if we changed selection or
184 // for all context clicks
185 if (element
|| isContextClick
) {
186 aMouseEvent
->PreventDefault();
189 } else if (!isContextClick
&& buttonNumber
== 0 && clickCount
== 1) {
190 // if the target element is an image, we have to display resizers
191 int32_t clientX
, clientY
;
192 aMouseEvent
->GetClientX(&clientX
);
193 aMouseEvent
->GetClientY(&clientY
);
194 htmlEditor
->MouseDown(clientX
, clientY
, element
, aMouseEvent
);
197 return nsEditorEventListener::MouseDown(aMouseEvent
);
201 nsHTMLEditorEventListener::MouseClick(nsIDOMMouseEvent
* aMouseEvent
)
203 nsCOMPtr
<nsIDOMEventTarget
> target
;
204 nsresult rv
= aMouseEvent
->GetTarget(getter_AddRefs(target
));
205 NS_ENSURE_SUCCESS(rv
, rv
);
206 NS_ENSURE_TRUE(target
, NS_ERROR_NULL_POINTER
);
207 nsCOMPtr
<nsIDOMElement
> element
= do_QueryInterface(target
);
209 GetHTMLEditor()->DoInlineTableEditingAction(element
);
211 return nsEditorEventListener::MouseClick(aMouseEvent
);