Fix for bug #88049: Support .selectionStart & friends for textareas

Patch by petejc@optonline.net and kin@netscape.com

  mozilla/content/html/content/src/nsHTMLInputElement.cpp
  mozilla/content/html/content/src/nsHTMLTextAreaElement.cpp
  mozilla/dom/public/idl/html/nsIDOMNSHTMLTextAreaElement.idl
  mozilla/layout/html/forms/src/nsTextControlFrame.cpp
  mozilla/layout/html/forms/src/nsTextControlFrame.h

Re-implemented selectionStart, selectionEnd, setSelectionRange() and various

utility methods in nsTextControlFrame to support multi-line text widgets.


r=jkeiser@netscape.com  sr=sfraser@netscape.com
This commit is contained in:
kin%netscape.com 2003-01-09 06:06:17 +00:00
Родитель 30a1ef9784
Коммит 872ded6605
7 изменённых файлов: 689 добавлений и 582 удалений

Просмотреть файл

@ -109,8 +109,6 @@
static NS_DEFINE_CID(kXULControllersCID, NS_XULCONTROLLERS_CID); static NS_DEFINE_CID(kXULControllersCID, NS_XULCONTROLLERS_CID);
typedef nsITextControlFrame textControlPlace;
// //
// Accessors for mBitField // Accessors for mBitField
// //
@ -2079,17 +2077,18 @@ NS_IMETHODIMP
nsHTMLInputElement::SetSelectionRange(PRInt32 aSelectionStart, nsHTMLInputElement::SetSelectionRange(PRInt32 aSelectionStart,
PRInt32 aSelectionEnd) PRInt32 aSelectionEnd)
{ {
nsresult rv = NS_ERROR_FAILURE;
nsIFormControlFrame* formControlFrame = GetFormControlFrame(PR_TRUE); nsIFormControlFrame* formControlFrame = GetFormControlFrame(PR_TRUE);
if (formControlFrame) { if (formControlFrame) {
nsCOMPtr<textControlPlace> nsITextControlFrame* textControlFrame = nsnull;
textControlFrame(do_QueryInterface(formControlFrame)); CallQueryInterface(formControlFrame, &textControlFrame);
if (textControlFrame) if (textControlFrame)
textControlFrame->SetSelectionRange(aSelectionStart, aSelectionEnd); rv = textControlFrame->SetSelectionRange(aSelectionStart, aSelectionEnd);
} }
return NS_OK; return rv;
} }
NS_IMETHODIMP NS_IMETHODIMP
@ -2104,17 +2103,18 @@ nsHTMLInputElement::GetSelectionStart(PRInt32* aSelectionStart)
NS_IMETHODIMP NS_IMETHODIMP
nsHTMLInputElement::SetSelectionStart(PRInt32 aSelectionStart) nsHTMLInputElement::SetSelectionStart(PRInt32 aSelectionStart)
{ {
nsresult rv = NS_ERROR_FAILURE;
nsIFormControlFrame* formControlFrame = GetFormControlFrame(PR_TRUE); nsIFormControlFrame* formControlFrame = GetFormControlFrame(PR_TRUE);
if (formControlFrame) { if (formControlFrame) {
nsCOMPtr<textControlPlace> nsITextControlFrame* textControlFrame = nsnull;
textControlFrame(do_QueryInterface(formControlFrame)); CallQueryInterface(formControlFrame, &textControlFrame);
if (textControlFrame) if (textControlFrame)
textControlFrame->SetSelectionStart(aSelectionStart); rv = textControlFrame->SetSelectionStart(aSelectionStart);
} }
return NS_OK; return rv;
} }
NS_IMETHODIMP NS_IMETHODIMP
@ -2130,34 +2130,36 @@ nsHTMLInputElement::GetSelectionEnd(PRInt32* aSelectionEnd)
NS_IMETHODIMP NS_IMETHODIMP
nsHTMLInputElement::SetSelectionEnd(PRInt32 aSelectionEnd) nsHTMLInputElement::SetSelectionEnd(PRInt32 aSelectionEnd)
{ {
nsresult rv = NS_ERROR_FAILURE;
nsIFormControlFrame* formControlFrame = GetFormControlFrame(PR_TRUE); nsIFormControlFrame* formControlFrame = GetFormControlFrame(PR_TRUE);
if (formControlFrame) { if (formControlFrame) {
nsCOMPtr<textControlPlace> nsITextControlFrame* textControlFrame = nsnull;
textControlFrame(do_QueryInterface(formControlFrame)); CallQueryInterface(formControlFrame, &textControlFrame);
if (textControlFrame) if (textControlFrame)
textControlFrame->SetSelectionEnd(aSelectionEnd); rv = textControlFrame->SetSelectionEnd(aSelectionEnd);
} }
return NS_OK; return rv;
} }
nsresult nsresult
nsHTMLInputElement::GetSelectionRange(PRInt32* aSelectionStart, nsHTMLInputElement::GetSelectionRange(PRInt32* aSelectionStart,
PRInt32* aSelectionEnd) PRInt32* aSelectionEnd)
{ {
nsresult rv = NS_ERROR_FAILURE;
nsIFormControlFrame* formControlFrame = GetFormControlFrame(PR_TRUE); nsIFormControlFrame* formControlFrame = GetFormControlFrame(PR_TRUE);
if (formControlFrame) { if (formControlFrame) {
nsCOMPtr<textControlPlace> nsITextControlFrame* textControlFrame = nsnull;
textControlFrame(do_QueryInterface(formControlFrame)); CallQueryInterface(formControlFrame, &textControlFrame);
if (textControlFrame) if (textControlFrame)
textControlFrame->GetSelectionRange(aSelectionStart, aSelectionEnd); rv = textControlFrame->GetSelectionRange(aSelectionStart, aSelectionEnd);
} }
return NS_OK; return rv;
} }
NS_IMETHODIMP NS_IMETHODIMP

Просмотреть файл

@ -165,6 +165,7 @@ protected:
nsresult SetValueInternal(const nsAString& aValue, nsresult SetValueInternal(const nsAString& aValue,
nsITextControlFrame* aFrame); nsITextControlFrame* aFrame);
nsresult GetSelectionRange(PRInt32* aSelectionStart, PRInt32* aSelectionEnd);
}; };
nsresult nsresult
@ -839,64 +840,89 @@ NS_IMETHODIMP
nsHTMLTextAreaElement::GetSelectionStart(PRInt32 *aSelectionStart) nsHTMLTextAreaElement::GetSelectionStart(PRInt32 *aSelectionStart)
{ {
NS_ENSURE_ARG_POINTER(aSelectionStart); NS_ENSURE_ARG_POINTER(aSelectionStart);
nsCOMPtr<nsIFormControlFrame> formControlFrame = getter_AddRefs(GetFormControlFrame(PR_TRUE));
PRInt32 selEnd;
nsCOMPtr<nsITextControlFrame> return GetSelectionRange(aSelectionStart, &selEnd);
textControlFrame(do_QueryInterface(formControlFrame));
if (textControlFrame) {
PRInt32 selectionEnd;
return textControlFrame->GetSelectionRange(aSelectionStart, &selectionEnd);
}
return NS_OK;
} }
NS_IMETHODIMP NS_IMETHODIMP
nsHTMLTextAreaElement::SetSelectionStart(PRInt32 aSelectionStart) nsHTMLTextAreaElement::SetSelectionStart(PRInt32 aSelectionStart)
{ {
nsCOMPtr<nsIFormControlFrame> formControlFrame = getter_AddRefs(GetFormControlFrame(PR_TRUE)); nsresult rv = NS_ERROR_FAILURE;
nsIFormControlFrame* formControlFrame = GetFormControlFrame(PR_TRUE);
nsCOMPtr<nsITextControlFrame> if (formControlFrame){
textControlFrame(do_QueryInterface(formControlFrame)); nsITextControlFrame* textControlFrame = nsnull;
CallQueryInterface(formControlFrame, &textControlFrame);
if (textControlFrame) if (textControlFrame)
textControlFrame->SetSelectionStart(aSelectionStart); rv = textControlFrame->SetSelectionStart(aSelectionStart);
}
return NS_OK; return rv;
} }
NS_IMETHODIMP NS_IMETHODIMP
nsHTMLTextAreaElement::GetSelectionEnd(PRInt32 *aSelectionEnd) nsHTMLTextAreaElement::GetSelectionEnd(PRInt32 *aSelectionEnd)
{ {
NS_ENSURE_ARG_POINTER(aSelectionEnd); NS_ENSURE_ARG_POINTER(aSelectionEnd);
nsCOMPtr<nsIFormControlFrame> formControlFrame = getter_AddRefs(GetFormControlFrame(PR_TRUE));
PRInt32 selStart;
nsCOMPtr<nsITextControlFrame> return GetSelectionRange(&selStart, aSelectionEnd);
textControlFrame(do_QueryInterface(formControlFrame));
if (textControlFrame) {
PRInt32 selectionStart;
return textControlFrame->GetSelectionRange(&selectionStart, aSelectionEnd);
}
return NS_OK;
} }
NS_IMETHODIMP NS_IMETHODIMP
nsHTMLTextAreaElement::SetSelectionEnd(PRInt32 aSelectionEnd) nsHTMLTextAreaElement::SetSelectionEnd(PRInt32 aSelectionEnd)
{ {
nsCOMPtr<nsIFormControlFrame> formControlFrame = getter_AddRefs(GetFormControlFrame(PR_TRUE)); nsresult rv = NS_ERROR_FAILURE;
nsIFormControlFrame* formControlFrame = GetFormControlFrame(PR_TRUE);
nsCOMPtr<nsITextControlFrame> if (formControlFrame) {
textControlFrame(do_QueryInterface(formControlFrame)); nsITextControlFrame* textControlFrame = nsnull;
CallQueryInterface(formControlFrame, &textControlFrame);
if (textControlFrame) if (textControlFrame)
textControlFrame->SetSelectionEnd(aSelectionEnd); rv = textControlFrame->SetSelectionEnd(aSelectionEnd);
}
return NS_OK; return rv;
} }
nsresult
nsHTMLTextAreaElement::GetSelectionRange(PRInt32* aSelectionStart,
PRInt32* aSelectionEnd)
{
nsresult rv = NS_ERROR_FAILURE;
nsIFormControlFrame* formControlFrame = GetFormControlFrame(PR_TRUE);
if (formControlFrame) {
nsITextControlFrame* textControlFrame = nsnull;
CallQueryInterface(formControlFrame, &textControlFrame);
if (textControlFrame)
rv = textControlFrame->GetSelectionRange(aSelectionStart, aSelectionEnd);
}
return rv;
}
NS_IMETHODIMP
nsHTMLTextAreaElement::SetSelectionRange(PRInt32 aSelectionStart, PRInt32 aSelectionEnd)
{
nsresult rv = NS_ERROR_FAILURE;
nsIFormControlFrame* formControlFrame = GetFormControlFrame(PR_TRUE);
if (formControlFrame) {
nsITextControlFrame* textControlFrame = nsnull;
CallQueryInterface(formControlFrame, &textControlFrame);
if (textControlFrame)
rv = textControlFrame->SetSelectionRange(aSelectionStart, aSelectionEnd);
}
return rv;
}
nsresult nsresult
nsHTMLTextAreaElement::Reset() nsHTMLTextAreaElement::Reset()
{ {

Просмотреть файл

@ -51,4 +51,7 @@ interface nsIDOMNSHTMLTextAreaElement : nsISupports
readonly attribute long textLength; readonly attribute long textLength;
attribute long selectionStart; attribute long selectionStart;
attribute long selectionEnd; attribute long selectionEnd;
void setSelectionRange(in long selectionStart,
in long selectionEnd);
}; };

Просмотреть файл

@ -1141,7 +1141,8 @@ NS_IMETHODIMP nsTextControlFrame::GetAccessible(nsIAccessible** aAccessible)
} }
#endif #endif
nsTextControlFrame::nsTextControlFrame(nsIPresShell* aShell):nsStackFrame(aShell) nsTextControlFrame::nsTextControlFrame(nsIPresShell* aShell)
: nsStackFrame(aShell)
{ {
mUseEditor = PR_FALSE; mUseEditor = PR_FALSE;
mIsProcessing = PR_FALSE; mIsProcessing = PR_FALSE;
@ -2189,7 +2190,8 @@ NS_IMETHODIMP nsTextControlFrame::SetProperty(nsIPresContext* aPresContext, nsIA
else if (nsHTMLAtoms::select == aName && mSelCon) else if (nsHTMLAtoms::select == aName && mSelCon)
{ {
// select all the text // select all the text
SelectAllContents(); if (mEditor)
mEditor->SelectAll();
} }
mIsProcessing = PR_FALSE; mIsProcessing = PR_FALSE;
} }
@ -2238,178 +2240,77 @@ nsTextControlFrame::GetTextLength(PRInt32* aTextLength)
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP
nsTextControlFrame::GetFirstTextNode(nsIDOMCharacterData* *aFirstTextNode)
{
if (!mEditor)
return NS_ERROR_NOT_INITIALIZED;
nsCOMPtr<nsIDOMElement> rootElement;
mEditor->GetRootElement(getter_AddRefs(rootElement));
*aFirstTextNode = nsnull;
nsCOMPtr<nsIDOMNode> rootNode = do_QueryInterface(rootElement);
if (!rootNode) return NS_ERROR_FAILURE;
// for a text widget, the text of the document is in a single
// text node under the body. Let's make sure that's true.
nsCOMPtr<nsIDOMNodeList> childNodesList;
rootNode->GetChildNodes(getter_AddRefs(childNodesList));
if (!childNodesList)
{
NS_WARNING("rootNode has no text node list");
return NS_ERROR_FAILURE;
}
PRUint32 numChildNodes = 0;
childNodesList->GetLength(&numChildNodes);
nsCOMPtr<nsIDOMNode> firstChild;
nsresult rv = rootNode->GetFirstChild(getter_AddRefs(firstChild));
if (NS_FAILED(rv)) return rv;
if (!firstChild) return NS_ERROR_FAILURE;
nsCOMPtr<nsIDOMCharacterData> charDataNode = do_QueryInterface(firstChild, &rv);
if (NS_FAILED(rv)) return rv;
NS_ADDREF(*aFirstTextNode = charDataNode);
return NS_OK;
}
nsresult
nsTextControlFrame::SelectAllContents()
{
nsresult rv;
if (IsSingleLineTextControl())
{
rv = SetSelectionRange(0, eSelectToEnd);
}
else
{
// we have to select all
if (!mEditor)
return NS_ERROR_NOT_INITIALIZED;
NS_ASSERTION(mEditor, "Should have an editor here");
rv = mEditor->SelectAll();
}
return rv;
}
nsresult nsresult
nsTextControlFrame::SetSelectionEndPoints(PRInt32 aSelStart, PRInt32 aSelEnd) nsTextControlFrame::SetSelectionEndPoints(PRInt32 aSelStart, PRInt32 aSelEnd)
{ {
NS_ASSERTION(IsSingleLineTextControl() || IsTextArea(), "Should only call this on a single line input"); NS_ASSERTION(aSelStart <= aSelEnd, "Invalid selection offsets!");
NS_ASSERTION(mEditor, "Should have an editor here");
NS_ASSERTION(mTextSelImpl,"selection not found!");
nsCOMPtr<nsIDOMCharacterData> firstTextNode; if (aSelStart > aSelEnd)
nsresult rv = GetFirstTextNode(getter_AddRefs(firstTextNode)); return NS_ERROR_FAILURE;
if (NS_FAILED(rv) || !firstTextNode)
{ nsCOMPtr<nsIDOMNode> startNode, endNode;
// probably an empty document. not an error PRInt32 startOffset, endOffset;
return NS_OK;
// Calculate the selection start point.
nsresult rv = OffsetToDOMPoint(aSelStart, getter_AddRefs(startNode), &startOffset);
NS_ENSURE_SUCCESS(rv, rv);
if (aSelStart == aSelEnd) {
// Collapsed selection, so start and end are the same!
endNode = startNode;
endOffset = startOffset;
} }
else {
nsCOMPtr<nsIDOMNode> firstNode = do_QueryInterface(firstTextNode, &rv); // Selection isn't collapsed so we have to calculate
if (!firstNode) return rv; // the end point too.
// constrain the selection to this node rv = OffsetToDOMPoint(aSelEnd, getter_AddRefs(endNode), &endOffset);
PRUint32 nodeLengthU;
firstTextNode->GetLength(&nodeLengthU); NS_ENSURE_SUCCESS(rv, rv);
PRInt32 nodeLength = (PRInt32)nodeLengthU; }
// Create a new range to represent the new selection.
// Note that we use a new range to avoid having to do
// isIncreasing checks to avoid possible errors.
nsCOMPtr<nsIDOMRange> range;
range = do_CreateInstance(kRangeCID);
NS_ENSURE_TRUE(range, NS_ERROR_FAILURE);
rv = range->SetStart(startNode, startOffset);
NS_ENSURE_SUCCESS(rv, rv);
rv = range->SetEnd(endNode, endOffset);
NS_ENSURE_SUCCESS(rv, rv);
// Get the selection, clear it and add the new range to it!
nsCOMPtr<nsISelection> selection; nsCOMPtr<nsISelection> selection;
mTextSelImpl->GetSelection(nsISelectionController::SELECTION_NORMAL,getter_AddRefs(selection)); mTextSelImpl->GetSelection(nsISelectionController::SELECTION_NORMAL, getter_AddRefs(selection));
if (!selection) return NS_ERROR_FAILURE; NS_ENSURE_TRUE(selection, NS_ERROR_FAILURE);
// are we setting both start and end? rv = selection->RemoveAllRanges();
if (aSelStart != eIgnoreSelect && aSelEnd != eIgnoreSelect)
{
if (aSelStart == eSelectToEnd || aSelStart > nodeLength)
aSelStart = nodeLength;
if (aSelStart < 0)
aSelStart = 0;
if (aSelEnd == eSelectToEnd || aSelEnd > nodeLength) NS_ENSURE_SUCCESS(rv, rv);
aSelEnd = nodeLength;
if (aSelEnd < 0)
aSelEnd = 0;
// remove existing ranges return selection->AddRange(range);
selection->RemoveAllRanges();
nsCOMPtr<nsIDOMRange> selectionRange(do_CreateInstance(kRangeCID,&rv));
if (NS_FAILED(rv))
return rv;
selectionRange->SetStart(firstTextNode, aSelStart);
selectionRange->SetEnd(firstTextNode, aSelEnd);
selection->AddRange(selectionRange);
}
else // we're setting either start or end but not both
{
// does a range exist?
nsCOMPtr<nsIDOMRange> firstRange;
selection->GetRangeAt(0, getter_AddRefs(firstRange));
PRBool mustAdd = PR_FALSE;
PRInt32 selStart = 0, selEnd = 0;
if (firstRange)
{
firstRange->GetStartOffset(&selStart);
firstRange->GetEndOffset(&selEnd);
}
else
{
// no range. Make a new one.
firstRange = do_CreateInstance(kRangeCID,&rv);
if (NS_FAILED(rv))
return rv;
mustAdd = PR_TRUE;
}
if (aSelStart == eSelectToEnd)
selStart = nodeLength;
else if (aSelStart != eIgnoreSelect)
selStart = aSelStart;
if (aSelEnd == eSelectToEnd)
selEnd = nodeLength;
else if (aSelEnd != eIgnoreSelect)
selEnd = aSelEnd;
// swap them
if (selEnd < selStart)
{
PRInt32 temp = selStart;
selStart = selEnd;
selEnd = temp;
}
firstRange->SetStart(firstTextNode, selStart);
firstRange->SetEnd(firstTextNode, selEnd);
if (mustAdd)
selection->AddRange(firstRange);
}
return NS_OK;
} }
NS_IMETHODIMP NS_IMETHODIMP
nsTextControlFrame::SetSelectionRange(PRInt32 aSelStart, PRInt32 aSelEnd) nsTextControlFrame::SetSelectionRange(PRInt32 aSelStart, PRInt32 aSelEnd)
{ {
if (!IsSingleLineTextControl()) return NS_ERROR_NOT_IMPLEMENTED; NS_ENSURE_TRUE(mEditor, NS_ERROR_NOT_INITIALIZED);
// make sure we have an editor
if (!mEditor)
return NS_ERROR_NOT_INITIALIZED;
if (aSelStart > aSelEnd) {
// Simulate what we'd see SetSelectionStart() was called, followed
// by a SetSelectionEnd().
aSelStart = aSelEnd;
}
return SetSelectionEndPoints(aSelStart, aSelEnd); return SetSelectionEndPoints(aSelStart, aSelEnd);
} }
@ -2417,122 +2318,266 @@ nsTextControlFrame::SetSelectionRange(PRInt32 aSelStart, PRInt32 aSelEnd)
NS_IMETHODIMP NS_IMETHODIMP
nsTextControlFrame::SetSelectionStart(PRInt32 aSelectionStart) nsTextControlFrame::SetSelectionStart(PRInt32 aSelectionStart)
{ {
if (!IsSingleLineTextControl() && !IsTextArea()) return NS_ERROR_NOT_IMPLEMENTED; NS_ENSURE_TRUE(mEditor, NS_ERROR_NOT_INITIALIZED);
// make sure we have an editor PRInt32 selStart = 0, selEnd = 0;
if (!mEditor)
return NS_ERROR_NOT_INITIALIZED; nsresult rv = GetSelectionRange(&selStart, &selEnd);
NS_ENSURE_SUCCESS(rv, rv);
if (aSelectionStart > selEnd) {
// Collapse to the new start point.
selEnd = aSelectionStart;
}
selStart = aSelectionStart;
return SetSelectionEndPoints(aSelectionStart, eIgnoreSelect); return SetSelectionEndPoints(selStart, selEnd);
} }
NS_IMETHODIMP NS_IMETHODIMP
nsTextControlFrame::SetSelectionEnd(PRInt32 aSelectionEnd) nsTextControlFrame::SetSelectionEnd(PRInt32 aSelectionEnd)
{ {
if (!IsSingleLineTextControl() && !IsTextArea()) return NS_ERROR_NOT_IMPLEMENTED; NS_ENSURE_TRUE(mEditor, NS_ERROR_NOT_INITIALIZED);
// make sure we have an editor
if (!mEditor)
return NS_ERROR_NOT_INITIALIZED;
return SetSelectionEndPoints(eIgnoreSelect, aSelectionEnd); PRInt32 selStart = 0, selEnd = 0;
nsresult rv = GetSelectionRange(&selStart, &selEnd);
NS_ENSURE_SUCCESS(rv, rv);
if (aSelectionEnd < selStart) {
// Collapse to the new end point.
selStart = aSelectionEnd;
}
selEnd = aSelectionEnd;
return SetSelectionEndPoints(selStart, selEnd);
} }
nsresult
nsTextControlFrame::DOMPointToOffset(nsIDOMNode* aNode,
PRInt32 aNodeOffset,
PRInt32* aResult)
{
NS_ENSURE_ARG_POINTER(aNode && aResult);
*aResult = 0;
nsCOMPtr<nsIDOMElement> rootElement;
mEditor->GetRootElement(getter_AddRefs(rootElement));
nsCOMPtr<nsIDOMNode> rootNode(do_QueryInterface(rootElement));
NS_ENSURE_TRUE(rootNode, NS_ERROR_FAILURE);
nsCOMPtr<nsIDOMNodeList> nodeList;
nsresult rv = rootNode->GetChildNodes(getter_AddRefs(nodeList));
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_TRUE(nodeList, NS_ERROR_FAILURE);
PRUint32 length = 0;
rv = nodeList->GetLength(&length);
NS_ENSURE_SUCCESS(rv, rv);
if (!length || aNodeOffset < 0)
return NS_OK;
PRInt32 i, textOffset = 0;
for (i = 0; i < length; i++) {
if (rootNode == aNode && i == aNodeOffset) {
*aResult = textOffset;
return NS_OK;
}
nsCOMPtr<nsIDOMNode> item;
rv = nodeList->Item(i, getter_AddRefs(item));
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_TRUE(item, NS_ERROR_FAILURE);
nsCOMPtr<nsIDOMText> domText(do_QueryInterface(item));
if (domText) {
PRUint32 textLength = 0;
rv = domText->GetLength(&textLength);
NS_ENSURE_SUCCESS(rv, rv);
if (item == aNode) {
NS_ASSERTION((aNodeOffset >= 0 && aNodeOffset <= textLength),
"Invalid aNodeOffset!");
*aResult = textOffset + aNodeOffset;
return NS_OK;
}
textOffset += textLength;
}
else {
// Must be a BR node, count it as a newline.
++textOffset;
}
}
NS_ASSERTION((aNode == rootNode && aNodeOffset == length),
"Invalide node offset!");
*aResult = textOffset;
return NS_OK;
}
nsresult
nsTextControlFrame::OffsetToDOMPoint(PRInt32 aOffset,
nsIDOMNode** aResult,
PRInt32* aPosition)
{
NS_ENSURE_ARG_POINTER(aResult && aPosition);
*aResult = nsnull;
*aPosition = 0;
nsCOMPtr<nsIDOMElement> rootElement;
mEditor->GetRootElement(getter_AddRefs(rootElement));
nsCOMPtr<nsIDOMNode> rootNode(do_QueryInterface(rootElement));
NS_ENSURE_TRUE(rootNode, NS_ERROR_FAILURE);
nsCOMPtr<nsIDOMNodeList> nodeList;
nsresult rv = rootNode->GetChildNodes(getter_AddRefs(nodeList));
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_TRUE(nodeList, NS_ERROR_FAILURE);
PRUint32 length = 0;
rv = nodeList->GetLength(&length);
NS_ENSURE_SUCCESS(rv, rv);
if (!length || aOffset < 0) {
*aPosition = 0;
*aResult = rootNode;
NS_ADDREF(*aResult);
return NS_OK;
}
PRInt32 textOffset = 0;
PRUint32 lastIndex = length - 1;
for (PRUint32 i=0; i<length; i++) {
nsCOMPtr<nsIDOMNode> item;
rv = nodeList->Item(i, getter_AddRefs(item));
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_TRUE(item, NS_ERROR_FAILURE);
nsCOMPtr<nsIDOMText> domText(do_QueryInterface(item));
if (domText) {
PRUint32 textLength = 0;
rv = domText->GetLength(&textLength);
NS_ENSURE_SUCCESS(rv, rv);
// Check if aOffset falls within this range.
if (aOffset >= textOffset && aOffset <= textOffset+(PRInt32)textLength) {
*aPosition = aOffset - textOffset;
*aResult = item;
NS_ADDREF(*aResult);
return NS_OK;
}
textOffset += textLength;
// If there aren't any more siblings after this text node,
// return the point at the end of this text node!
if (i == lastIndex) {
*aPosition = textLength;
*aResult = item;
NS_ADDREF(*aResult);
return NS_OK;
}
}
else {
// Must be a BR node, count it as a newline.
if (aOffset == textOffset || i == lastIndex) {
// We've found the correct position, or aOffset takes us
// beyond the last child under rootNode, just return the point
// under rootNode that is in front of this br.
*aPosition = i;
*aResult = rootNode;
NS_ADDREF(*aResult);
return NS_OK;
}
++textOffset;
}
}
NS_ASSERTION(0, "We should never get here!");
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP NS_IMETHODIMP
nsTextControlFrame::GetSelectionRange(PRInt32* aSelectionStart, PRInt32* aSelectionEnd) nsTextControlFrame::GetSelectionRange(PRInt32* aSelectionStart, PRInt32* aSelectionEnd)
{ {
NS_ENSURE_ARG_POINTER((aSelectionStart && aSelectionEnd)); // make sure we have an editor
NS_ENSURE_TRUE(mEditor, NS_ERROR_NOT_INITIALIZED);
// make sure we have an editor *aSelectionStart = 0;
if (!mEditor) *aSelectionEnd = 0;
return NS_ERROR_NOT_INITIALIZED;
*aSelectionStart = 0; nsCOMPtr<nsISelection> selection;
*aSelectionEnd = 0; nsresult rv = mTextSelImpl->GetSelection(nsISelectionController::SELECTION_NORMAL, getter_AddRefs(selection));
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_TRUE(selection, NS_ERROR_FAILURE);
nsCOMPtr<nsISelection> selection; PRInt32 numRanges = 0;
mTextSelImpl->GetSelection(nsISelectionController::SELECTION_NORMAL,getter_AddRefs(selection)); selection->GetRangeCount(&numRanges);
if (!selection) return NS_ERROR_FAILURE;
// we should have only zero or one range if (numRanges < 1)
PRInt32 numRanges = 0;
selection->GetRangeCount(&numRanges);
if (numRanges > 1)
{
NS_ASSERTION(0, "Found more than on range in GetSelectionRange");
}
if (numRanges != 0)
{
nsCOMPtr<nsIDOMRange> firstRange;
selection->GetRangeAt(0, getter_AddRefs(firstRange));
if (!firstRange)
return NS_ERROR_FAILURE;
if (IsSingleLineTextControl() || IsTextArea())
{
firstRange->GetStartOffset(aSelectionStart);
firstRange->GetEndOffset(aSelectionEnd);
}
else//multiline
{
//mContent = parent. iterate over each child.
//when text nodes are reached add text length.
//if you find range-startoffset,startnode then mark aSelecitonStart
nsresult rv = NS_ERROR_FAILURE;
nsCOMPtr<nsIDOMNode> contentNode;
nsCOMPtr<nsIDOMNode> curNode;
contentNode = do_QueryInterface(mContent);
if (!contentNode || NS_FAILED(rv = contentNode->GetFirstChild(getter_AddRefs(curNode))) || !curNode)
return rv;
nsCOMPtr<nsIDOMNode> startParent;
nsCOMPtr<nsIDOMNode> endParent;
PRInt32 startOffset;
PRInt32 endOffset;
firstRange->GetStartContainer(getter_AddRefs(startParent));
firstRange->GetStartOffset(&startOffset);
firstRange->GetEndContainer(getter_AddRefs(endParent));
firstRange->GetEndOffset(&endOffset);
PRInt32 currentTextOffset = 0;
while(curNode)
{
nsCOMPtr<nsIDOMText> domText;
domText = do_QueryInterface(curNode);
if (contentNode == startParent)
{
if (domText)
*aSelectionStart = currentTextOffset + startOffset;
else
*aSelectionStart = currentTextOffset;
}
if (curNode == endParent)
{
if (domText)
*aSelectionEnd = currentTextOffset + endOffset;
else
*aSelectionEnd = currentTextOffset;
break;
}
if (domText)
{
PRUint32 length;
if (NS_SUCCEEDED(domText->GetLength(&length)))
currentTextOffset += length;
}
else
++currentTextOffset;
}
if (!curNode) //something went very wrong...
{
*aSelectionEnd = *aSelectionStart;//couldnt find the end
}
}
}
return NS_OK; return NS_OK;
// We only operate on the first range in the selection!
nsCOMPtr<nsIDOMRange> firstRange;
rv = selection->GetRangeAt(0, getter_AddRefs(firstRange));
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_TRUE(firstRange, NS_ERROR_FAILURE);
nsCOMPtr<nsIDOMNode> startNode, endNode;
PRInt32 startOffset = 0, endOffset = 0;
// Get the start point of the range.
rv = firstRange->GetStartContainer(getter_AddRefs(startNode));
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_TRUE(startNode, NS_ERROR_FAILURE);
rv = firstRange->GetStartOffset(&startOffset);
NS_ENSURE_SUCCESS(rv, rv);
// Get the end point of the range.
rv = firstRange->GetEndContainer(getter_AddRefs(endNode));
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_TRUE(endNode, NS_ERROR_FAILURE);
rv = firstRange->GetEndOffset(&endOffset);
NS_ENSURE_SUCCESS(rv, rv);
// Convert the start point to a selection offset.
rv = DOMPointToOffset(startNode, startOffset, aSelectionStart);
NS_ENSURE_SUCCESS(rv, rv);
// Convert the end point to a selection offset.
return DOMPointToOffset(endNode, endOffset, aSelectionEnd);
} }
@ -3120,5 +3165,3 @@ nsTextControlFrame::HandleEvent(nsIPresContext* aPresContext,
return nsStackFrame::HandleEvent(aPresContext, aEvent, aEventStatus); return nsStackFrame::HandleEvent(aPresContext, aEvent, aEventStatus);
} }

Просмотреть файл

@ -212,6 +212,8 @@ public: //for methods who access nsTextControlFrame directly
void SetValueChanged(PRBool aValueChanged); void SetValueChanged(PRBool aValueChanged);
/** Called when the frame is focused, to remember the value for onChange. */ /** Called when the frame is focused, to remember the value for onChange. */
nsresult InitFocusedValue(); nsresult InitFocusedValue();
nsresult DOMPointToOffset(nsIDOMNode* aNode, PRInt32 aNodeOffset, PRInt32 *aResult);
nsresult OffsetToDOMPoint(PRInt32 aOffset, nsIDOMNode** aResult, PRInt32* aPosition);
protected: protected:
@ -289,13 +291,6 @@ protected:
private: private:
//helper methods //helper methods
enum {
eIgnoreSelect = -2,
eSelectToEnd = -1
};
NS_IMETHODIMP GetFirstTextNode(nsIDOMCharacterData* *aFirstTextNode);
nsresult SelectAllContents();
nsresult SetSelectionEndPoints(PRInt32 aSelStart, PRInt32 aSelEnd); nsresult SetSelectionEndPoints(PRInt32 aSelStart, PRInt32 aSelEnd);
private: private:

Просмотреть файл

@ -1141,7 +1141,8 @@ NS_IMETHODIMP nsTextControlFrame::GetAccessible(nsIAccessible** aAccessible)
} }
#endif #endif
nsTextControlFrame::nsTextControlFrame(nsIPresShell* aShell):nsStackFrame(aShell) nsTextControlFrame::nsTextControlFrame(nsIPresShell* aShell)
: nsStackFrame(aShell)
{ {
mUseEditor = PR_FALSE; mUseEditor = PR_FALSE;
mIsProcessing = PR_FALSE; mIsProcessing = PR_FALSE;
@ -2189,7 +2190,8 @@ NS_IMETHODIMP nsTextControlFrame::SetProperty(nsIPresContext* aPresContext, nsIA
else if (nsHTMLAtoms::select == aName && mSelCon) else if (nsHTMLAtoms::select == aName && mSelCon)
{ {
// select all the text // select all the text
SelectAllContents(); if (mEditor)
mEditor->SelectAll();
} }
mIsProcessing = PR_FALSE; mIsProcessing = PR_FALSE;
} }
@ -2238,178 +2240,77 @@ nsTextControlFrame::GetTextLength(PRInt32* aTextLength)
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP
nsTextControlFrame::GetFirstTextNode(nsIDOMCharacterData* *aFirstTextNode)
{
if (!mEditor)
return NS_ERROR_NOT_INITIALIZED;
nsCOMPtr<nsIDOMElement> rootElement;
mEditor->GetRootElement(getter_AddRefs(rootElement));
*aFirstTextNode = nsnull;
nsCOMPtr<nsIDOMNode> rootNode = do_QueryInterface(rootElement);
if (!rootNode) return NS_ERROR_FAILURE;
// for a text widget, the text of the document is in a single
// text node under the body. Let's make sure that's true.
nsCOMPtr<nsIDOMNodeList> childNodesList;
rootNode->GetChildNodes(getter_AddRefs(childNodesList));
if (!childNodesList)
{
NS_WARNING("rootNode has no text node list");
return NS_ERROR_FAILURE;
}
PRUint32 numChildNodes = 0;
childNodesList->GetLength(&numChildNodes);
nsCOMPtr<nsIDOMNode> firstChild;
nsresult rv = rootNode->GetFirstChild(getter_AddRefs(firstChild));
if (NS_FAILED(rv)) return rv;
if (!firstChild) return NS_ERROR_FAILURE;
nsCOMPtr<nsIDOMCharacterData> charDataNode = do_QueryInterface(firstChild, &rv);
if (NS_FAILED(rv)) return rv;
NS_ADDREF(*aFirstTextNode = charDataNode);
return NS_OK;
}
nsresult
nsTextControlFrame::SelectAllContents()
{
nsresult rv;
if (IsSingleLineTextControl())
{
rv = SetSelectionRange(0, eSelectToEnd);
}
else
{
// we have to select all
if (!mEditor)
return NS_ERROR_NOT_INITIALIZED;
NS_ASSERTION(mEditor, "Should have an editor here");
rv = mEditor->SelectAll();
}
return rv;
}
nsresult nsresult
nsTextControlFrame::SetSelectionEndPoints(PRInt32 aSelStart, PRInt32 aSelEnd) nsTextControlFrame::SetSelectionEndPoints(PRInt32 aSelStart, PRInt32 aSelEnd)
{ {
NS_ASSERTION(IsSingleLineTextControl() || IsTextArea(), "Should only call this on a single line input"); NS_ASSERTION(aSelStart <= aSelEnd, "Invalid selection offsets!");
NS_ASSERTION(mEditor, "Should have an editor here");
NS_ASSERTION(mTextSelImpl,"selection not found!");
nsCOMPtr<nsIDOMCharacterData> firstTextNode; if (aSelStart > aSelEnd)
nsresult rv = GetFirstTextNode(getter_AddRefs(firstTextNode)); return NS_ERROR_FAILURE;
if (NS_FAILED(rv) || !firstTextNode)
{ nsCOMPtr<nsIDOMNode> startNode, endNode;
// probably an empty document. not an error PRInt32 startOffset, endOffset;
return NS_OK;
// Calculate the selection start point.
nsresult rv = OffsetToDOMPoint(aSelStart, getter_AddRefs(startNode), &startOffset);
NS_ENSURE_SUCCESS(rv, rv);
if (aSelStart == aSelEnd) {
// Collapsed selection, so start and end are the same!
endNode = startNode;
endOffset = startOffset;
} }
else {
nsCOMPtr<nsIDOMNode> firstNode = do_QueryInterface(firstTextNode, &rv); // Selection isn't collapsed so we have to calculate
if (!firstNode) return rv; // the end point too.
// constrain the selection to this node rv = OffsetToDOMPoint(aSelEnd, getter_AddRefs(endNode), &endOffset);
PRUint32 nodeLengthU;
firstTextNode->GetLength(&nodeLengthU); NS_ENSURE_SUCCESS(rv, rv);
PRInt32 nodeLength = (PRInt32)nodeLengthU; }
// Create a new range to represent the new selection.
// Note that we use a new range to avoid having to do
// isIncreasing checks to avoid possible errors.
nsCOMPtr<nsIDOMRange> range;
range = do_CreateInstance(kRangeCID);
NS_ENSURE_TRUE(range, NS_ERROR_FAILURE);
rv = range->SetStart(startNode, startOffset);
NS_ENSURE_SUCCESS(rv, rv);
rv = range->SetEnd(endNode, endOffset);
NS_ENSURE_SUCCESS(rv, rv);
// Get the selection, clear it and add the new range to it!
nsCOMPtr<nsISelection> selection; nsCOMPtr<nsISelection> selection;
mTextSelImpl->GetSelection(nsISelectionController::SELECTION_NORMAL,getter_AddRefs(selection)); mTextSelImpl->GetSelection(nsISelectionController::SELECTION_NORMAL, getter_AddRefs(selection));
if (!selection) return NS_ERROR_FAILURE; NS_ENSURE_TRUE(selection, NS_ERROR_FAILURE);
// are we setting both start and end? rv = selection->RemoveAllRanges();
if (aSelStart != eIgnoreSelect && aSelEnd != eIgnoreSelect)
{
if (aSelStart == eSelectToEnd || aSelStart > nodeLength)
aSelStart = nodeLength;
if (aSelStart < 0)
aSelStart = 0;
if (aSelEnd == eSelectToEnd || aSelEnd > nodeLength) NS_ENSURE_SUCCESS(rv, rv);
aSelEnd = nodeLength;
if (aSelEnd < 0)
aSelEnd = 0;
// remove existing ranges return selection->AddRange(range);
selection->RemoveAllRanges();
nsCOMPtr<nsIDOMRange> selectionRange(do_CreateInstance(kRangeCID,&rv));
if (NS_FAILED(rv))
return rv;
selectionRange->SetStart(firstTextNode, aSelStart);
selectionRange->SetEnd(firstTextNode, aSelEnd);
selection->AddRange(selectionRange);
}
else // we're setting either start or end but not both
{
// does a range exist?
nsCOMPtr<nsIDOMRange> firstRange;
selection->GetRangeAt(0, getter_AddRefs(firstRange));
PRBool mustAdd = PR_FALSE;
PRInt32 selStart = 0, selEnd = 0;
if (firstRange)
{
firstRange->GetStartOffset(&selStart);
firstRange->GetEndOffset(&selEnd);
}
else
{
// no range. Make a new one.
firstRange = do_CreateInstance(kRangeCID,&rv);
if (NS_FAILED(rv))
return rv;
mustAdd = PR_TRUE;
}
if (aSelStart == eSelectToEnd)
selStart = nodeLength;
else if (aSelStart != eIgnoreSelect)
selStart = aSelStart;
if (aSelEnd == eSelectToEnd)
selEnd = nodeLength;
else if (aSelEnd != eIgnoreSelect)
selEnd = aSelEnd;
// swap them
if (selEnd < selStart)
{
PRInt32 temp = selStart;
selStart = selEnd;
selEnd = temp;
}
firstRange->SetStart(firstTextNode, selStart);
firstRange->SetEnd(firstTextNode, selEnd);
if (mustAdd)
selection->AddRange(firstRange);
}
return NS_OK;
} }
NS_IMETHODIMP NS_IMETHODIMP
nsTextControlFrame::SetSelectionRange(PRInt32 aSelStart, PRInt32 aSelEnd) nsTextControlFrame::SetSelectionRange(PRInt32 aSelStart, PRInt32 aSelEnd)
{ {
if (!IsSingleLineTextControl()) return NS_ERROR_NOT_IMPLEMENTED; NS_ENSURE_TRUE(mEditor, NS_ERROR_NOT_INITIALIZED);
// make sure we have an editor
if (!mEditor)
return NS_ERROR_NOT_INITIALIZED;
if (aSelStart > aSelEnd) {
// Simulate what we'd see SetSelectionStart() was called, followed
// by a SetSelectionEnd().
aSelStart = aSelEnd;
}
return SetSelectionEndPoints(aSelStart, aSelEnd); return SetSelectionEndPoints(aSelStart, aSelEnd);
} }
@ -2417,122 +2318,266 @@ nsTextControlFrame::SetSelectionRange(PRInt32 aSelStart, PRInt32 aSelEnd)
NS_IMETHODIMP NS_IMETHODIMP
nsTextControlFrame::SetSelectionStart(PRInt32 aSelectionStart) nsTextControlFrame::SetSelectionStart(PRInt32 aSelectionStart)
{ {
if (!IsSingleLineTextControl() && !IsTextArea()) return NS_ERROR_NOT_IMPLEMENTED; NS_ENSURE_TRUE(mEditor, NS_ERROR_NOT_INITIALIZED);
// make sure we have an editor PRInt32 selStart = 0, selEnd = 0;
if (!mEditor)
return NS_ERROR_NOT_INITIALIZED; nsresult rv = GetSelectionRange(&selStart, &selEnd);
NS_ENSURE_SUCCESS(rv, rv);
if (aSelectionStart > selEnd) {
// Collapse to the new start point.
selEnd = aSelectionStart;
}
selStart = aSelectionStart;
return SetSelectionEndPoints(aSelectionStart, eIgnoreSelect); return SetSelectionEndPoints(selStart, selEnd);
} }
NS_IMETHODIMP NS_IMETHODIMP
nsTextControlFrame::SetSelectionEnd(PRInt32 aSelectionEnd) nsTextControlFrame::SetSelectionEnd(PRInt32 aSelectionEnd)
{ {
if (!IsSingleLineTextControl() && !IsTextArea()) return NS_ERROR_NOT_IMPLEMENTED; NS_ENSURE_TRUE(mEditor, NS_ERROR_NOT_INITIALIZED);
// make sure we have an editor
if (!mEditor)
return NS_ERROR_NOT_INITIALIZED;
return SetSelectionEndPoints(eIgnoreSelect, aSelectionEnd); PRInt32 selStart = 0, selEnd = 0;
nsresult rv = GetSelectionRange(&selStart, &selEnd);
NS_ENSURE_SUCCESS(rv, rv);
if (aSelectionEnd < selStart) {
// Collapse to the new end point.
selStart = aSelectionEnd;
}
selEnd = aSelectionEnd;
return SetSelectionEndPoints(selStart, selEnd);
} }
nsresult
nsTextControlFrame::DOMPointToOffset(nsIDOMNode* aNode,
PRInt32 aNodeOffset,
PRInt32* aResult)
{
NS_ENSURE_ARG_POINTER(aNode && aResult);
*aResult = 0;
nsCOMPtr<nsIDOMElement> rootElement;
mEditor->GetRootElement(getter_AddRefs(rootElement));
nsCOMPtr<nsIDOMNode> rootNode(do_QueryInterface(rootElement));
NS_ENSURE_TRUE(rootNode, NS_ERROR_FAILURE);
nsCOMPtr<nsIDOMNodeList> nodeList;
nsresult rv = rootNode->GetChildNodes(getter_AddRefs(nodeList));
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_TRUE(nodeList, NS_ERROR_FAILURE);
PRUint32 length = 0;
rv = nodeList->GetLength(&length);
NS_ENSURE_SUCCESS(rv, rv);
if (!length || aNodeOffset < 0)
return NS_OK;
PRInt32 i, textOffset = 0;
for (i = 0; i < length; i++) {
if (rootNode == aNode && i == aNodeOffset) {
*aResult = textOffset;
return NS_OK;
}
nsCOMPtr<nsIDOMNode> item;
rv = nodeList->Item(i, getter_AddRefs(item));
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_TRUE(item, NS_ERROR_FAILURE);
nsCOMPtr<nsIDOMText> domText(do_QueryInterface(item));
if (domText) {
PRUint32 textLength = 0;
rv = domText->GetLength(&textLength);
NS_ENSURE_SUCCESS(rv, rv);
if (item == aNode) {
NS_ASSERTION((aNodeOffset >= 0 && aNodeOffset <= textLength),
"Invalid aNodeOffset!");
*aResult = textOffset + aNodeOffset;
return NS_OK;
}
textOffset += textLength;
}
else {
// Must be a BR node, count it as a newline.
++textOffset;
}
}
NS_ASSERTION((aNode == rootNode && aNodeOffset == length),
"Invalide node offset!");
*aResult = textOffset;
return NS_OK;
}
nsresult
nsTextControlFrame::OffsetToDOMPoint(PRInt32 aOffset,
nsIDOMNode** aResult,
PRInt32* aPosition)
{
NS_ENSURE_ARG_POINTER(aResult && aPosition);
*aResult = nsnull;
*aPosition = 0;
nsCOMPtr<nsIDOMElement> rootElement;
mEditor->GetRootElement(getter_AddRefs(rootElement));
nsCOMPtr<nsIDOMNode> rootNode(do_QueryInterface(rootElement));
NS_ENSURE_TRUE(rootNode, NS_ERROR_FAILURE);
nsCOMPtr<nsIDOMNodeList> nodeList;
nsresult rv = rootNode->GetChildNodes(getter_AddRefs(nodeList));
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_TRUE(nodeList, NS_ERROR_FAILURE);
PRUint32 length = 0;
rv = nodeList->GetLength(&length);
NS_ENSURE_SUCCESS(rv, rv);
if (!length || aOffset < 0) {
*aPosition = 0;
*aResult = rootNode;
NS_ADDREF(*aResult);
return NS_OK;
}
PRInt32 textOffset = 0;
PRUint32 lastIndex = length - 1;
for (PRUint32 i=0; i<length; i++) {
nsCOMPtr<nsIDOMNode> item;
rv = nodeList->Item(i, getter_AddRefs(item));
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_TRUE(item, NS_ERROR_FAILURE);
nsCOMPtr<nsIDOMText> domText(do_QueryInterface(item));
if (domText) {
PRUint32 textLength = 0;
rv = domText->GetLength(&textLength);
NS_ENSURE_SUCCESS(rv, rv);
// Check if aOffset falls within this range.
if (aOffset >= textOffset && aOffset <= textOffset+(PRInt32)textLength) {
*aPosition = aOffset - textOffset;
*aResult = item;
NS_ADDREF(*aResult);
return NS_OK;
}
textOffset += textLength;
// If there aren't any more siblings after this text node,
// return the point at the end of this text node!
if (i == lastIndex) {
*aPosition = textLength;
*aResult = item;
NS_ADDREF(*aResult);
return NS_OK;
}
}
else {
// Must be a BR node, count it as a newline.
if (aOffset == textOffset || i == lastIndex) {
// We've found the correct position, or aOffset takes us
// beyond the last child under rootNode, just return the point
// under rootNode that is in front of this br.
*aPosition = i;
*aResult = rootNode;
NS_ADDREF(*aResult);
return NS_OK;
}
++textOffset;
}
}
NS_ASSERTION(0, "We should never get here!");
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP NS_IMETHODIMP
nsTextControlFrame::GetSelectionRange(PRInt32* aSelectionStart, PRInt32* aSelectionEnd) nsTextControlFrame::GetSelectionRange(PRInt32* aSelectionStart, PRInt32* aSelectionEnd)
{ {
NS_ENSURE_ARG_POINTER((aSelectionStart && aSelectionEnd)); // make sure we have an editor
NS_ENSURE_TRUE(mEditor, NS_ERROR_NOT_INITIALIZED);
// make sure we have an editor *aSelectionStart = 0;
if (!mEditor) *aSelectionEnd = 0;
return NS_ERROR_NOT_INITIALIZED;
*aSelectionStart = 0; nsCOMPtr<nsISelection> selection;
*aSelectionEnd = 0; nsresult rv = mTextSelImpl->GetSelection(nsISelectionController::SELECTION_NORMAL, getter_AddRefs(selection));
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_TRUE(selection, NS_ERROR_FAILURE);
nsCOMPtr<nsISelection> selection; PRInt32 numRanges = 0;
mTextSelImpl->GetSelection(nsISelectionController::SELECTION_NORMAL,getter_AddRefs(selection)); selection->GetRangeCount(&numRanges);
if (!selection) return NS_ERROR_FAILURE;
// we should have only zero or one range if (numRanges < 1)
PRInt32 numRanges = 0;
selection->GetRangeCount(&numRanges);
if (numRanges > 1)
{
NS_ASSERTION(0, "Found more than on range in GetSelectionRange");
}
if (numRanges != 0)
{
nsCOMPtr<nsIDOMRange> firstRange;
selection->GetRangeAt(0, getter_AddRefs(firstRange));
if (!firstRange)
return NS_ERROR_FAILURE;
if (IsSingleLineTextControl() || IsTextArea())
{
firstRange->GetStartOffset(aSelectionStart);
firstRange->GetEndOffset(aSelectionEnd);
}
else//multiline
{
//mContent = parent. iterate over each child.
//when text nodes are reached add text length.
//if you find range-startoffset,startnode then mark aSelecitonStart
nsresult rv = NS_ERROR_FAILURE;
nsCOMPtr<nsIDOMNode> contentNode;
nsCOMPtr<nsIDOMNode> curNode;
contentNode = do_QueryInterface(mContent);
if (!contentNode || NS_FAILED(rv = contentNode->GetFirstChild(getter_AddRefs(curNode))) || !curNode)
return rv;
nsCOMPtr<nsIDOMNode> startParent;
nsCOMPtr<nsIDOMNode> endParent;
PRInt32 startOffset;
PRInt32 endOffset;
firstRange->GetStartContainer(getter_AddRefs(startParent));
firstRange->GetStartOffset(&startOffset);
firstRange->GetEndContainer(getter_AddRefs(endParent));
firstRange->GetEndOffset(&endOffset);
PRInt32 currentTextOffset = 0;
while(curNode)
{
nsCOMPtr<nsIDOMText> domText;
domText = do_QueryInterface(curNode);
if (contentNode == startParent)
{
if (domText)
*aSelectionStart = currentTextOffset + startOffset;
else
*aSelectionStart = currentTextOffset;
}
if (curNode == endParent)
{
if (domText)
*aSelectionEnd = currentTextOffset + endOffset;
else
*aSelectionEnd = currentTextOffset;
break;
}
if (domText)
{
PRUint32 length;
if (NS_SUCCEEDED(domText->GetLength(&length)))
currentTextOffset += length;
}
else
++currentTextOffset;
}
if (!curNode) //something went very wrong...
{
*aSelectionEnd = *aSelectionStart;//couldnt find the end
}
}
}
return NS_OK; return NS_OK;
// We only operate on the first range in the selection!
nsCOMPtr<nsIDOMRange> firstRange;
rv = selection->GetRangeAt(0, getter_AddRefs(firstRange));
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_TRUE(firstRange, NS_ERROR_FAILURE);
nsCOMPtr<nsIDOMNode> startNode, endNode;
PRInt32 startOffset = 0, endOffset = 0;
// Get the start point of the range.
rv = firstRange->GetStartContainer(getter_AddRefs(startNode));
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_TRUE(startNode, NS_ERROR_FAILURE);
rv = firstRange->GetStartOffset(&startOffset);
NS_ENSURE_SUCCESS(rv, rv);
// Get the end point of the range.
rv = firstRange->GetEndContainer(getter_AddRefs(endNode));
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_TRUE(endNode, NS_ERROR_FAILURE);
rv = firstRange->GetEndOffset(&endOffset);
NS_ENSURE_SUCCESS(rv, rv);
// Convert the start point to a selection offset.
rv = DOMPointToOffset(startNode, startOffset, aSelectionStart);
NS_ENSURE_SUCCESS(rv, rv);
// Convert the end point to a selection offset.
return DOMPointToOffset(endNode, endOffset, aSelectionEnd);
} }
@ -3120,5 +3165,3 @@ nsTextControlFrame::HandleEvent(nsIPresContext* aPresContext,
return nsStackFrame::HandleEvent(aPresContext, aEvent, aEventStatus); return nsStackFrame::HandleEvent(aPresContext, aEvent, aEventStatus);
} }

Просмотреть файл

@ -212,6 +212,8 @@ public: //for methods who access nsTextControlFrame directly
void SetValueChanged(PRBool aValueChanged); void SetValueChanged(PRBool aValueChanged);
/** Called when the frame is focused, to remember the value for onChange. */ /** Called when the frame is focused, to remember the value for onChange. */
nsresult InitFocusedValue(); nsresult InitFocusedValue();
nsresult DOMPointToOffset(nsIDOMNode* aNode, PRInt32 aNodeOffset, PRInt32 *aResult);
nsresult OffsetToDOMPoint(PRInt32 aOffset, nsIDOMNode** aResult, PRInt32* aPosition);
protected: protected:
@ -289,13 +291,6 @@ protected:
private: private:
//helper methods //helper methods
enum {
eIgnoreSelect = -2,
eSelectToEnd = -1
};
NS_IMETHODIMP GetFirstTextNode(nsIDOMCharacterData* *aFirstTextNode);
nsresult SelectAllContents();
nsresult SetSelectionEndPoints(PRInt32 aSelStart, PRInt32 aSelEnd); nsresult SetSelectionEndPoints(PRInt32 aSelStart, PRInt32 aSelEnd);
private: private: