зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
30a1ef9784
Коммит
872ded6605
|
@ -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:
|
||||||
|
|
Загрузка…
Ссылка в новой задаче