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; } nsHTMLEditor* htmlEditor = GetHTMLEditor(); // 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); NS_ENSURE_SUCCESS(res, res); PRBool isContextClick = buttonNumber == 2; PRInt32 clickCount; res = mouseEvent->GetDetail(&clickCount); NS_ENSURE_SUCCESS(res, res); nsCOMPtr<nsIDOMEventTarget> target; nsCOMPtr<nsIDOMNSEvent> internalEvent = do_QueryInterface(aMouseEvent); res = internalEvent->GetExplicitOriginalTarget(getter_AddRefs(target)); NS_ENSURE_SUCCESS(res, res); NS_ENSURE_TRUE(target, NS_ERROR_NULL_POINTER); nsCOMPtr<nsIDOMElement> element = do_QueryInterface(target); if (isContextClick || (buttonNumber == 0 && clickCount == 2)) { nsCOMPtr<nsISelection> selection; mEditor->GetSelection(getter_AddRefs(selection)); NS_ENSURE_TRUE(selection, NS_OK); // Get location of mouse within target node nsCOMPtr<nsIDOMNSUIEvent> uiEvent = do_QueryInterface(aMouseEvent); NS_ENSURE_TRUE(uiEvent, NS_ERROR_FAILURE); nsCOMPtr<nsIDOMNode> parent; PRInt32 offset = 0; res = uiEvent->GetRangeParent(getter_AddRefs(parent)); NS_ENSURE_SUCCESS(res, res); NS_ENSURE_TRUE(parent, NS_ERROR_FAILURE); res = uiEvent->GetRangeOffset(&offset); NS_ENSURE_SUCCESS(res, 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) { PRInt32 rangeCount; res = selection->GetRangeCount(&rangeCount); NS_ENSURE_SUCCESS(res, res); 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 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); // Done when we find a range that we are in if (nodeIsInSelection) break; } } } nsCOMPtr<nsIDOMNode> node = do_QueryInterface(target); if (node && !nodeIsInSelection) { if (!element) { 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)); NS_ENSURE_SUCCESS(res, 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) { node = selectAllNode; element = newElement; } } if (isContextClick && !nsHTMLEditUtils::IsImage(node)) { 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); // 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) { // 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); }
nsresult nsHTMLEditorMouseListener::MouseDown(nsIDOMEvent* aMouseEvent) { 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; PRBool isContextClick; #if defined(XP_MAC) || defined(XP_MACOSX) // 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; #endif 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; // Detect if mouse point is within current selection for context click PRBool nodeIsInSelection = PR_FALSE; if (isContextClick) { 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++) { nsCOMPtr<nsIDOMRange> range; res = selection->GetRangeAt(i, getter_AddRefs(range)); if (NS_FAILED(res) || !range) continue;//dont bail yet, iterate through them all nsCOMPtr<nsIDOMNSRange> nsrange(do_QueryInterface(range)); if (NS_FAILED(res) || !nsrange) continue;//dont bail yet, iterate through them all res = nsrange->IsPointInRange(parent, offset, &nodeIsInSelection); // Done when we find a range that we are in if (nodeIsInSelection) break; } } } nsCOMPtr<nsIDOMNode> node = do_QueryInterface(target); if (node && !nodeIsInSelection) { if (!element) { 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 = mHTMLEditor->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); } } } // 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) { // 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); } } return nsTextEditorMouseListener::MouseDown(aMouseEvent); }