Bumping manifests a=b2g-bump
[gecko.git] / editor / libeditor / nsHTMLEditorEventListener.cpp
blobe05caa14c33145eeef229241de9c8cab573dc5f3
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/. */
5 #include "nsAutoPtr.h"
6 #include "nsCOMPtr.h"
7 #include "nsDebug.h"
8 #include "nsEditor.h"
9 #include "nsError.h"
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
32 #ifdef DEBUG
33 nsresult
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);
43 #endif
45 nsHTMLEditor*
46 nsHTMLEditorEventListener::GetHTMLEditor()
48 // mEditor must be nsHTMLEditor or its subclass.
49 return static_cast<nsHTMLEditor*>(mEditor);
52 nsresult
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);
71 nsresult
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
79 // interface :-(
80 int16_t buttonNumber;
81 nsresult rv = aMouseEvent->GetButton(&buttonNumber);
82 NS_ENSURE_SUCCESS(rv, rv);
84 bool isContextClick = buttonNumber == 2;
86 int32_t clickCount;
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)) {
98 return NS_OK;
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);
112 int32_t offset = 0;
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()) {
119 int32_t rangeCount;
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
129 continue;
132 range->IsPointInRange(parent, offset, &nodeIsInSelection);
134 // Done when we find a range that we are in
135 if (nodeIsInSelection) {
136 break;
140 nsCOMPtr<nsIDOMNode> node = do_QueryInterface(target);
141 if (node && !nodeIsInSelection) {
142 if (!element) {
143 if (isContextClick) {
144 // Set the selection to the point under the mouse cursor:
145 selection->Collapse(parent, offset);
146 } else {
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);
153 if (linkElement) {
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
160 if (element) {
161 nsCOMPtr<nsIDOMNode> selectAllNode =
162 htmlEditor->FindUserSelectAllNode(element);
164 if (selectAllNode) {
165 nsCOMPtr<nsIDOMElement> newElement = do_QueryInterface(selectAllNode);
166 if (newElement) {
167 node = selectAllNode;
168 element = newElement;
172 if (isContextClick && !nsHTMLEditUtils::IsImage(node)) {
173 selection->Collapse(parent, offset);
174 } else {
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();
187 return NS_OK;
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);
200 nsresult
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);