diff --git a/mozilla/editor/base/nsHTMLEditor.cpp b/mozilla/editor/base/nsHTMLEditor.cpp index 7bf479fb3bf..adb72832fd4 100644 --- a/mozilla/editor/base/nsHTMLEditor.cpp +++ b/mozilla/editor/base/nsHTMLEditor.cpp @@ -1938,13 +1938,75 @@ nsHTMLEditor::InsertImage(nsString& aURL, return res; } - // This should replace InsertLink and InsertImage once it is working +static PRBool IsLinkNode(nsIDOMNode *aNode) +{ + if (aNode) + { + nsCOMPtr anchor = do_QueryInterface(aNode); + if (anchor) + { + nsString tmpText; + if (NS_SUCCEEDED(anchor->GetHref(tmpText)) && tmpText.GetUnicode() && tmpText.Length() != 0) + return PR_TRUE; + } + } + return PR_FALSE; +} + +NS_IMETHODIMP +nsHTMLEditor::GetParentLinkElement(nsIDOMNode *aNode, nsIDOMElement** aReturn) +{ + if (!aNode || !aReturn ) + return NS_ERROR_NULL_POINTER; + + // default is null - no element found + *aReturn = nsnull; + + nsCOMPtr linkNode = aNode; + nsCOMPtr parent; + PRBool bNodeFound = PR_FALSE; + + while (PR_TRUE) + { + // Test if we have a link (an anchor with href set) + if (IsLinkNode(linkNode)) + { + bNodeFound = PR_TRUE; + break; + } + // Search up the parent chain + // We should never fail because of root test below, but lets be safe + if (!NS_SUCCEEDED(linkNode->GetParentNode(getter_AddRefs(parent))) || !parent) + break; + + // Stop searching if parent is a root (body or table cell) + PRBool isRoot; + nsAutoString parentTagName; + parent->GetNodeName(parentTagName); + if (!NS_SUCCEEDED(IsRootTag(parentTagName, isRoot)) || isRoot) + break; + linkNode = parent; + } + if (bNodeFound) + { + nsCOMPtr linkElement = do_QueryInterface(linkNode); + if (linkElement) + { + *aReturn = linkElement; + // Getters must addref + NS_ADDREF(*aReturn); + } + } + return NS_OK; +} + NS_IMETHODIMP nsHTMLEditor::GetSelectedElement(const nsString& aTagName, nsIDOMElement** aReturn) { if (!aReturn ) return NS_ERROR_NULL_POINTER; + // default is null - no element found *aReturn = nsnull; nsAutoString TagName = aTagName; @@ -1966,8 +2028,78 @@ nsHTMLEditor::GetSelectedElement(const nsString& aTagName, nsIDOMElement** aRetu nsCOMPtr selectedElement; PRBool bNodeFound = PR_FALSE; - // Don't bother to examine selection if it is collapsed - if (!isCollapsed) + if (TagName == "href") + { + // Link tag is a special case - we return the anchor node + // found for any selection that is totally within a link, + // included a collapsed selection (just a caret in a link) + nsCOMPtr anchorNode; + res = selection->GetAnchorNode(getter_AddRefs(anchorNode)); + PRInt32 anchorOffset = -1; + if (anchorNode) + selection->GetAnchorOffset(&anchorOffset); + + nsCOMPtr focusNode; + selection->GetFocusNode(getter_AddRefs(focusNode)); + PRInt32 focusOffset = -1; + if (focusNode) + selection->GetFocusOffset(&focusOffset); + + // Link node must be the same for both ends of selection + if (NS_SUCCEEDED(res) && anchorNode) + { +#ifdef DEBUG_cmanske + { + nsAutoString name; + anchorNode->GetNodeName(name); + printf("GetSelectedElement: Anchor node of selection: "); + wprintf(name.GetUnicode()); + printf(" Offset: %d\n", anchorOffset); + focusNode->GetNodeName(name); + printf("Focus node of selection: "); + wprintf(name.GetUnicode()); + printf(" Offset: %d\n", focusOffset); + } +#endif + nsCOMPtr parentLinkOfAnchor; + res = GetParentLinkElement(anchorNode, getter_AddRefs(parentLinkOfAnchor)); + if (NS_SUCCEEDED(res) && parentLinkOfAnchor) + { + if (isCollapsed) + { + // We have just a caret in the link + bNodeFound = PR_TRUE; + } else if(focusNode) + { // Link node must be the same for both ends of selection + nsCOMPtr parentLinkOfFocus; + res = GetParentLinkElement(focusNode, getter_AddRefs(parentLinkOfFocus)); + if (NS_SUCCEEDED(res) && parentLinkOfFocus == parentLinkOfAnchor) + bNodeFound = PR_TRUE; + } + + // We found a link node parent + if (bNodeFound) { + // GetParentLinkElement addref'd this, so we don't need to do it here + *aReturn = parentLinkOfAnchor; + return NS_OK; + } + } + else if (anchorOffset >= 0) // Check if link node is the only thing selected + { + nsCOMPtr anchorChild; + anchorChild = GetChildAt(anchorNode,anchorOffset); + if (anchorChild && IsLinkNode(anchorChild) && + (anchorNode == focusNode) && focusOffset == (anchorOffset+1)) + { + selectedElement = do_QueryInterface(anchorChild); + bNodeFound = PR_TRUE; + } + } + } + } + //NOTE: We will not find the link node aboveif it is the only thing selected + + if (!bNodeFound && !isCollapsed) // Don't bother to examine selection if it is collapsed { nsCOMPtr enumerator; res = selection->GetEnumerator(getter_AddRefs(enumerator)); @@ -2021,7 +2153,7 @@ nsHTMLEditor::GetSelectedElement(const nsString& aTagName, nsIDOMElement** aRetu // The "A" tag is a pain, // used for both link(href is set) and "Named Anchor" - if (TagName == "href" || (TagName == "anchor")) + if (TagName == "href" || TagName == "anchor") { // We could use GetAttribute, but might as well use anchor element directly nsCOMPtr anchor = do_QueryInterface(selectedElement); @@ -2037,44 +2169,6 @@ nsHTMLEditor::GetSelectedElement(const nsString& aTagName, nsIDOMElement** aRetu if (NS_SUCCEEDED(anchor->GetName(tmpText)) && tmpText.GetUnicode() && tmpText.Length() != 0) bNodeFound = PR_TRUE; } -#if 0 -// Not sure if this kind of logic should be here or in JavaScript - } else if (TagName == "href") - { - // Check for a single image is inside a link - // It is usually the immediate parent, but lets be sure - // by walking up the parents until we find an "A" tag - nsCOMPtr image = do_QueryInterface(selectedElement); - if (image) - { - nsCOMPtr parent; - nsCOMPtr current = do_QueryInterface(selectedElement); - PRBool notDone = PR_TRUE; - do { - res = current->GetParentNode(getter_AddRefs(parent)); - notDone = NS_SUCCEEDED(res) && parent != nsnull; - if(notDone) - { - nsString tmpText; - /*nsCOMPtr*/ - anchor = do_QueryInterface(parent); - if (anchor && NS_SUCCEEDED(anchor->GetHref(tmpText)) && tmpText.GetUnicode() && tmpText.Length() != 0) - { - - nsCOMPtr link = do_QueryInterface(parent); - if (link) - { - *aReturn =link; - // Getters must addref - NS_ADDREF(*aReturn); - } - return NS_OK; - } - } - current = parent; - } while (notDone); - } -#endif } } else if (TagName == domTagName) { // All other tag names are handled here bNodeFound = PR_TRUE; @@ -2453,7 +2547,6 @@ nsHTMLEditor::InsertLinkAroundSelection(nsIDOMElement* aAnchorElement) printf("InsertLinkAroundSelection called but there is no selection!!!\n"); res = NS_OK; } else { - // Be sure we were given an anchor element nsCOMPtr anchor = do_QueryInterface(aAnchorElement); if (anchor) diff --git a/mozilla/editor/base/nsHTMLEditor.h b/mozilla/editor/base/nsHTMLEditor.h index da7d34e3012..99f57779e91 100644 --- a/mozilla/editor/base/nsHTMLEditor.h +++ b/mozilla/editor/base/nsHTMLEditor.h @@ -152,7 +152,7 @@ public: nsString& aAlt, nsString& aAlignment); NS_IMETHOD InsertList(const nsString& aListType); - // This should replace InsertLink and InsertImage once it is working + NS_IMETHOD GetParentLinkElement(nsIDOMNode *aNode, nsIDOMElement** aReturn); NS_IMETHOD GetSelectedElement(const nsString& aTagName, nsIDOMElement** aReturn); NS_IMETHOD CreateElementWithDefaults(const nsString& aTagName, nsIDOMElement** aReturn); NS_IMETHOD InsertElement(nsIDOMElement* aElement, PRBool aDeleteSelection); diff --git a/mozilla/editor/libeditor/html/nsHTMLEditor.cpp b/mozilla/editor/libeditor/html/nsHTMLEditor.cpp index 7bf479fb3bf..adb72832fd4 100644 --- a/mozilla/editor/libeditor/html/nsHTMLEditor.cpp +++ b/mozilla/editor/libeditor/html/nsHTMLEditor.cpp @@ -1938,13 +1938,75 @@ nsHTMLEditor::InsertImage(nsString& aURL, return res; } - // This should replace InsertLink and InsertImage once it is working +static PRBool IsLinkNode(nsIDOMNode *aNode) +{ + if (aNode) + { + nsCOMPtr anchor = do_QueryInterface(aNode); + if (anchor) + { + nsString tmpText; + if (NS_SUCCEEDED(anchor->GetHref(tmpText)) && tmpText.GetUnicode() && tmpText.Length() != 0) + return PR_TRUE; + } + } + return PR_FALSE; +} + +NS_IMETHODIMP +nsHTMLEditor::GetParentLinkElement(nsIDOMNode *aNode, nsIDOMElement** aReturn) +{ + if (!aNode || !aReturn ) + return NS_ERROR_NULL_POINTER; + + // default is null - no element found + *aReturn = nsnull; + + nsCOMPtr linkNode = aNode; + nsCOMPtr parent; + PRBool bNodeFound = PR_FALSE; + + while (PR_TRUE) + { + // Test if we have a link (an anchor with href set) + if (IsLinkNode(linkNode)) + { + bNodeFound = PR_TRUE; + break; + } + // Search up the parent chain + // We should never fail because of root test below, but lets be safe + if (!NS_SUCCEEDED(linkNode->GetParentNode(getter_AddRefs(parent))) || !parent) + break; + + // Stop searching if parent is a root (body or table cell) + PRBool isRoot; + nsAutoString parentTagName; + parent->GetNodeName(parentTagName); + if (!NS_SUCCEEDED(IsRootTag(parentTagName, isRoot)) || isRoot) + break; + linkNode = parent; + } + if (bNodeFound) + { + nsCOMPtr linkElement = do_QueryInterface(linkNode); + if (linkElement) + { + *aReturn = linkElement; + // Getters must addref + NS_ADDREF(*aReturn); + } + } + return NS_OK; +} + NS_IMETHODIMP nsHTMLEditor::GetSelectedElement(const nsString& aTagName, nsIDOMElement** aReturn) { if (!aReturn ) return NS_ERROR_NULL_POINTER; + // default is null - no element found *aReturn = nsnull; nsAutoString TagName = aTagName; @@ -1966,8 +2028,78 @@ nsHTMLEditor::GetSelectedElement(const nsString& aTagName, nsIDOMElement** aRetu nsCOMPtr selectedElement; PRBool bNodeFound = PR_FALSE; - // Don't bother to examine selection if it is collapsed - if (!isCollapsed) + if (TagName == "href") + { + // Link tag is a special case - we return the anchor node + // found for any selection that is totally within a link, + // included a collapsed selection (just a caret in a link) + nsCOMPtr anchorNode; + res = selection->GetAnchorNode(getter_AddRefs(anchorNode)); + PRInt32 anchorOffset = -1; + if (anchorNode) + selection->GetAnchorOffset(&anchorOffset); + + nsCOMPtr focusNode; + selection->GetFocusNode(getter_AddRefs(focusNode)); + PRInt32 focusOffset = -1; + if (focusNode) + selection->GetFocusOffset(&focusOffset); + + // Link node must be the same for both ends of selection + if (NS_SUCCEEDED(res) && anchorNode) + { +#ifdef DEBUG_cmanske + { + nsAutoString name; + anchorNode->GetNodeName(name); + printf("GetSelectedElement: Anchor node of selection: "); + wprintf(name.GetUnicode()); + printf(" Offset: %d\n", anchorOffset); + focusNode->GetNodeName(name); + printf("Focus node of selection: "); + wprintf(name.GetUnicode()); + printf(" Offset: %d\n", focusOffset); + } +#endif + nsCOMPtr parentLinkOfAnchor; + res = GetParentLinkElement(anchorNode, getter_AddRefs(parentLinkOfAnchor)); + if (NS_SUCCEEDED(res) && parentLinkOfAnchor) + { + if (isCollapsed) + { + // We have just a caret in the link + bNodeFound = PR_TRUE; + } else if(focusNode) + { // Link node must be the same for both ends of selection + nsCOMPtr parentLinkOfFocus; + res = GetParentLinkElement(focusNode, getter_AddRefs(parentLinkOfFocus)); + if (NS_SUCCEEDED(res) && parentLinkOfFocus == parentLinkOfAnchor) + bNodeFound = PR_TRUE; + } + + // We found a link node parent + if (bNodeFound) { + // GetParentLinkElement addref'd this, so we don't need to do it here + *aReturn = parentLinkOfAnchor; + return NS_OK; + } + } + else if (anchorOffset >= 0) // Check if link node is the only thing selected + { + nsCOMPtr anchorChild; + anchorChild = GetChildAt(anchorNode,anchorOffset); + if (anchorChild && IsLinkNode(anchorChild) && + (anchorNode == focusNode) && focusOffset == (anchorOffset+1)) + { + selectedElement = do_QueryInterface(anchorChild); + bNodeFound = PR_TRUE; + } + } + } + } + //NOTE: We will not find the link node aboveif it is the only thing selected + + if (!bNodeFound && !isCollapsed) // Don't bother to examine selection if it is collapsed { nsCOMPtr enumerator; res = selection->GetEnumerator(getter_AddRefs(enumerator)); @@ -2021,7 +2153,7 @@ nsHTMLEditor::GetSelectedElement(const nsString& aTagName, nsIDOMElement** aRetu // The "A" tag is a pain, // used for both link(href is set) and "Named Anchor" - if (TagName == "href" || (TagName == "anchor")) + if (TagName == "href" || TagName == "anchor") { // We could use GetAttribute, but might as well use anchor element directly nsCOMPtr anchor = do_QueryInterface(selectedElement); @@ -2037,44 +2169,6 @@ nsHTMLEditor::GetSelectedElement(const nsString& aTagName, nsIDOMElement** aRetu if (NS_SUCCEEDED(anchor->GetName(tmpText)) && tmpText.GetUnicode() && tmpText.Length() != 0) bNodeFound = PR_TRUE; } -#if 0 -// Not sure if this kind of logic should be here or in JavaScript - } else if (TagName == "href") - { - // Check for a single image is inside a link - // It is usually the immediate parent, but lets be sure - // by walking up the parents until we find an "A" tag - nsCOMPtr image = do_QueryInterface(selectedElement); - if (image) - { - nsCOMPtr parent; - nsCOMPtr current = do_QueryInterface(selectedElement); - PRBool notDone = PR_TRUE; - do { - res = current->GetParentNode(getter_AddRefs(parent)); - notDone = NS_SUCCEEDED(res) && parent != nsnull; - if(notDone) - { - nsString tmpText; - /*nsCOMPtr*/ - anchor = do_QueryInterface(parent); - if (anchor && NS_SUCCEEDED(anchor->GetHref(tmpText)) && tmpText.GetUnicode() && tmpText.Length() != 0) - { - - nsCOMPtr link = do_QueryInterface(parent); - if (link) - { - *aReturn =link; - // Getters must addref - NS_ADDREF(*aReturn); - } - return NS_OK; - } - } - current = parent; - } while (notDone); - } -#endif } } else if (TagName == domTagName) { // All other tag names are handled here bNodeFound = PR_TRUE; @@ -2453,7 +2547,6 @@ nsHTMLEditor::InsertLinkAroundSelection(nsIDOMElement* aAnchorElement) printf("InsertLinkAroundSelection called but there is no selection!!!\n"); res = NS_OK; } else { - // Be sure we were given an anchor element nsCOMPtr anchor = do_QueryInterface(aAnchorElement); if (anchor) diff --git a/mozilla/editor/libeditor/html/nsHTMLEditor.h b/mozilla/editor/libeditor/html/nsHTMLEditor.h index da7d34e3012..99f57779e91 100644 --- a/mozilla/editor/libeditor/html/nsHTMLEditor.h +++ b/mozilla/editor/libeditor/html/nsHTMLEditor.h @@ -152,7 +152,7 @@ public: nsString& aAlt, nsString& aAlignment); NS_IMETHOD InsertList(const nsString& aListType); - // This should replace InsertLink and InsertImage once it is working + NS_IMETHOD GetParentLinkElement(nsIDOMNode *aNode, nsIDOMElement** aReturn); NS_IMETHOD GetSelectedElement(const nsString& aTagName, nsIDOMElement** aReturn); NS_IMETHOD CreateElementWithDefaults(const nsString& aTagName, nsIDOMElement** aReturn); NS_IMETHOD InsertElement(nsIDOMElement* aElement, PRBool aDeleteSelection);