예제 #1
0
nsresult
TextEditRules::CreateTrailingBRIfNeeded()
{
  // but only if we aren't a single line edit field
  if (IsSingleLineEditor()) {
    return NS_OK;
  }

  NS_ENSURE_STATE(mTextEditor);
  dom::Element* body = mTextEditor->GetRoot();
  NS_ENSURE_TRUE(body, NS_ERROR_NULL_POINTER);

  nsIContent* lastChild = body->GetLastChild();
  // assuming CreateBogusNodeIfNeeded() has been called first
  NS_ENSURE_TRUE(lastChild, NS_ERROR_NULL_POINTER);

  if (!lastChild->IsHTMLElement(nsGkAtoms::br)) {
    AutoTransactionsConserveSelection dontChangeMySelection(mTextEditor);
    nsCOMPtr<nsIDOMNode> domBody = do_QueryInterface(body);
    return CreateMozBR(domBody, body->Length());
  }

  // Check to see if the trailing BR is a former bogus node - this will have
  // stuck around if we previously morphed a trailing node into a bogus node.
  if (!mTextEditor->IsMozEditorBogusNode(lastChild)) {
    return NS_OK;
  }

  // Morph it back to a mozBR
  lastChild->UnsetAttr(kNameSpaceID_None, kMOZEditorBogusNodeAttrAtom, false);
  lastChild->SetAttr(kNameSpaceID_None, nsGkAtoms::type,
                     NS_LITERAL_STRING("_moz"), true);
  return NS_OK;
}
nsresult
nsTextEditRules::CreateTrailingBRIfNeeded()
{
  // but only if we aren't a single line edit field
  if (IsSingleLineEditor())
    return NS_OK;
  nsIDOMNode *body = mEditor->GetRoot();
  NS_ENSURE_TRUE(body, NS_ERROR_NULL_POINTER);
  nsCOMPtr<nsIDOMNode> lastChild;
  nsresult res = body->GetLastChild(getter_AddRefs(lastChild));
  // assuming CreateBogusNodeIfNeeded() has been called first
  NS_ENSURE_SUCCESS(res, res);  
  NS_ENSURE_TRUE(lastChild, NS_ERROR_NULL_POINTER);

  if (!nsTextEditUtils::IsBreak(lastChild))
  {
    nsAutoTxnsConserveSelection dontSpazMySelection(mEditor);
    PRUint32 rootLen;
    res = mEditor->GetLengthOfDOMNode(body, rootLen);
    NS_ENSURE_SUCCESS(res, res); 
    nsCOMPtr<nsIDOMNode> unused;
    res = CreateMozBR(body, rootLen, address_of(unused));
  }
  return res;
}
예제 #3
0
nsresult
nsTextEditRules::CreateTrailingBRIfNeeded()
{
  // but only if we aren't a single line edit field
  if (mFlags & nsIPlaintextEditor::eEditorSingleLineMask)
    return NS_OK;
  nsIDOMNode *body = mEditor->GetRoot();
  if (!body)
    return NS_ERROR_NULL_POINTER;
  nsCOMPtr<nsIDOMNode> lastChild;
  nsresult res = body->GetLastChild(getter_AddRefs(lastChild));
  // assuming CreateBogusNodeIfNeeded() has been called first
  if (NS_FAILED(res)) return res;  
  if (!lastChild) return NS_ERROR_NULL_POINTER;

  if (!nsTextEditUtils::IsBreak(lastChild))
  {
    nsAutoTxnsConserveSelection dontSpazMySelection(mEditor);
    PRUint32 rootLen;
    res = mEditor->GetLengthOfDOMNode(body, rootLen);
    if (NS_FAILED(res)) return res; 
    nsCOMPtr<nsIDOMNode> unused;
    res = CreateMozBR(body, rootLen, address_of(unused));
  }
  return res;
}
예제 #4
0
nsresult
nsTextEditRules::DidInsertBreak(nsISelection *aSelection, nsresult aResult)
{
    // we only need to execute the stuff below if we are a plaintext editor.
    // html editors have a different mechanism for putting in mozBR's
    // (because there are a bunch more places you have to worry about it in html)
    if (!IsPlaintextEditor()) {
        return NS_OK;
    }

    // if we are at the end of the document, we need to insert
    // a special mozBR following the normal br, and then set the
    // selection to stick to the mozBR.
    PRInt32 selOffset;
    nsCOMPtr<nsIDOMNode> selNode;
    nsresult res;
    res = mEditor->GetStartNodeAndOffset(aSelection, getter_AddRefs(selNode), &selOffset);
    NS_ENSURE_SUCCESS(res, res);
    // confirm we are at end of document
    if (selOffset == 0) return NS_OK;  // can't be after a br if we are at offset 0
    nsIDOMElement *rootElem = mEditor->GetRoot();

    nsCOMPtr<nsIDOMNode> root = do_QueryInterface(rootElem);
    NS_ENSURE_TRUE(root, NS_ERROR_NULL_POINTER);
    if (selNode != root) return NS_OK; // must be inside text node or somewhere other than end of root

    nsCOMPtr<nsIDOMNode> temp = mEditor->GetChildAt(selNode, selOffset);
    if (temp) return NS_OK; // can't be at end if there is a node after us.

    nsCOMPtr<nsIDOMNode> nearNode = mEditor->GetChildAt(selNode, selOffset-1);
    if (nearNode && nsTextEditUtils::IsBreak(nearNode) && !nsTextEditUtils::IsMozBR(nearNode))
    {
        nsCOMPtr<nsISelectionPrivate>selPrivate(do_QueryInterface(aSelection));
        // need to insert special moz BR. Why?  Because if we don't
        // the user will see no new line for the break.  Also, things
        // like table cells won't grow in height.
        nsCOMPtr<nsIDOMNode> brNode;
        res = CreateMozBR(selNode, selOffset, address_of(brNode));
        NS_ENSURE_SUCCESS(res, res);

        res = nsEditor::GetNodeLocation(brNode, address_of(selNode), &selOffset);
        NS_ENSURE_SUCCESS(res, res);
        selPrivate->SetInterlinePosition(PR_TRUE);
        res = aSelection->Collapse(selNode, selOffset);
        NS_ENSURE_SUCCESS(res, res);
    }
    return res;
}
예제 #5
0
nsresult
nsTextEditRules::WillInsertText(PRInt32          aAction,
                                nsISelection *aSelection,
                                PRBool          *aCancel,
                                PRBool          *aHandled,
                                const nsAString *inString,
                                nsAString *outString,
                                PRInt32          aMaxLength)
{
    if (!aSelection || !aCancel || !aHandled) {
        return NS_ERROR_NULL_POINTER;
    }

    if (inString->IsEmpty() && (aAction != kInsertTextIME))
    {
        // HACK: this is a fix for bug 19395
        // I can't outlaw all empty insertions
        // because IME transaction depend on them
        // There is more work to do to make the
        // world safe for IME.
        *aCancel = PR_TRUE;
        *aHandled = PR_FALSE;
        return NS_OK;
    }

    // initialize out param
    *aCancel = PR_FALSE;
    *aHandled = PR_TRUE;

    // handle docs with a max length
    // NOTE, this function copies inString into outString for us.
    nsresult res = TruncateInsertionIfNeeded(aSelection, inString, outString, aMaxLength);
    NS_ENSURE_SUCCESS(res, res);

    PRUint32 start = 0;
    PRUint32 end = 0;

    // handle password field docs
    if (IsPasswordEditor())
    {
        res = mEditor->GetTextSelectionOffsets(aSelection, start, end);
        NS_ASSERTION((NS_SUCCEEDED(res)), "getTextSelectionOffsets failed!");
        NS_ENSURE_SUCCESS(res, res);
    }

    // if the selection isn't collapsed, delete it.
    PRBool bCollapsed;
    res = aSelection->GetIsCollapsed(&bCollapsed);
    NS_ENSURE_SUCCESS(res, res);
    if (!bCollapsed)
    {
        res = mEditor->DeleteSelection(nsIEditor::eNone);
        NS_ENSURE_SUCCESS(res, res);
    }

    res = WillInsert(aSelection, aCancel);
    NS_ENSURE_SUCCESS(res, res);
    // initialize out param
    // we want to ignore result of WillInsert()
    *aCancel = PR_FALSE;

    // handle password field data
    // this has the side effect of changing all the characters in aOutString
    // to the replacement character
    if (IsPasswordEditor())
    {
        if (aAction == kInsertTextIME)  {
            res = RemoveIMETextFromPWBuf(start, outString);
            NS_ENSURE_SUCCESS(res, res);
        }
    }

    // People have lots of different ideas about what text fields
    // should do with multiline pastes.  See bugs 21032, 23485, 23485, 50935.
    // The six possible options are:
    // 0. paste newlines intact
    // 1. paste up to the first newline (default)
    // 2. replace newlines with spaces
    // 3. strip newlines
    // 4. replace with commas
    // 5. strip newlines and surrounding whitespace
    // So find out what we're expected to do:
    if (IsSingleLineEditor())
    {
        nsAutoString tString(*outString);

        HandleNewLines(tString, mEditor->mNewlineHandling);

        outString->Assign(tString);
    }

    if (IsPasswordEditor())
    {
        // manage the password buffer
        mPasswordText.Insert(*outString, start);

        nsCOMPtr<nsILookAndFeel> lookAndFeel = do_GetService(kLookAndFeelCID);
        if (lookAndFeel->GetEchoPassword() && !DontEchoPassword()) {
            HideLastPWInput();
            mLastStart = start;
            mLastLength = outString->Length();
            if (mTimer)
            {
                mTimer->Cancel();
            }
            else
            {
                mTimer = do_CreateInstance("@mozilla.org/timer;1", &res);
                NS_ENSURE_SUCCESS(res, res);
            }
            mTimer->InitWithCallback(this, 600, nsITimer::TYPE_ONE_SHOT);
        }
        else
        {
            res = FillBufWithPWChars(outString, outString->Length());
            NS_ENSURE_SUCCESS(res, res);
        }
    }

    // get the (collapsed) selection location
    nsCOMPtr<nsIDOMNode> selNode;
    PRInt32 selOffset;
    res = mEditor->GetStartNodeAndOffset(aSelection, getter_AddRefs(selNode), &selOffset);
    NS_ENSURE_SUCCESS(res, res);

    // don't put text in places that can't have it
    if (!mEditor->IsTextNode(selNode) && !mEditor->CanContainTag(selNode, NS_LITERAL_STRING("#text")))
        return NS_ERROR_FAILURE;

    // we need to get the doc
    nsCOMPtr<nsIDOMDocument>doc;
    res = mEditor->GetDocument(getter_AddRefs(doc));
    NS_ENSURE_SUCCESS(res, res);
    NS_ENSURE_TRUE(doc, NS_ERROR_NULL_POINTER);

    if (aAction == kInsertTextIME)
    {
        res = mEditor->InsertTextImpl(*outString, address_of(selNode), &selOffset, doc);
        NS_ENSURE_SUCCESS(res, res);
    }
    else // aAction == kInsertText
    {
        // find where we are
        nsCOMPtr<nsIDOMNode> curNode = selNode;
        PRInt32 curOffset = selOffset;

        // is our text going to be PREformatted?
        // We remember this so that we know how to handle tabs.
        PRBool isPRE;
        res = mEditor->IsPreformatted(selNode, &isPRE);
        NS_ENSURE_SUCCESS(res, res);

        // don't spaz my selection in subtransactions
        nsAutoTxnsConserveSelection dontSpazMySelection(mEditor);
        nsString tString(*outString);
        const PRUnichar *unicodeBuf = tString.get();
        nsCOMPtr<nsIDOMNode> unused;
        PRInt32 pos = 0;

        // for efficiency, break out the pre case separately.  This is because
        // it's a lot cheaper to search the input string for only newlines than
        // it is to search for both tabs and newlines.
        if (isPRE)
        {
            while (unicodeBuf && (pos != -1) && ((PRUint32)pos < tString.Length()))
            {
                PRInt32 oldPos = pos;
                PRInt32 subStrLen;
                pos = tString.FindChar(nsCRT::LF, oldPos);

                if (pos != -1)
                {
                    subStrLen = pos - oldPos;
                    // if first char is newline, then use just it
                    if (subStrLen == 0)
                        subStrLen = 1;
                }
                else
                {
                    subStrLen = tString.Length() - oldPos;
                    pos = tString.Length();
                }

                nsDependentSubstring subStr(tString, oldPos, subStrLen);

                // is it a return?
                if (subStr.EqualsLiteral(LFSTR))
                {
                    if (IsSingleLineEditor())
                    {
                        NS_ASSERTION((mEditor->mNewlineHandling == nsIPlaintextEditor::eNewlinesPasteIntact),
                                     "Newline improperly getting into single-line edit field!");
                        res = mEditor->InsertTextImpl(subStr, address_of(curNode), &curOffset, doc);
                    }
                    else
                    {
                        res = mEditor->CreateBRImpl(address_of(curNode), &curOffset, address_of(unused), nsIEditor::eNone);

                        // If the newline is the last character in the string, and the BR we
                        // just inserted is the last node in the content tree, we need to add
                        // a mozBR so that a blank line is created.

                        if (NS_SUCCEEDED(res) && curNode && pos == (PRInt32)(tString.Length() - 1))
                        {
                            nsCOMPtr<nsIDOMNode> nextChild = mEditor->GetChildAt(curNode, curOffset);

                            if (!nextChild)
                            {
                                // We must be at the end since there isn't a nextChild.
                                //
                                // curNode and curOffset should be set to the position after
                                // the BR we added above, so just create a mozBR at that position.
                                //
                                // Note that we don't update curOffset after we've created/inserted
                                // the mozBR since we never want the selection to be placed after it.

                                res = CreateMozBR(curNode, curOffset, address_of(unused));
                            }
                        }
                    }
                    pos++;
                }
                else
                {
                    res = mEditor->InsertTextImpl(subStr, address_of(curNode), &curOffset, doc);
                }
                NS_ENSURE_SUCCESS(res, res);
            }
        }
        else
        {
            char specialChars[] = {TAB, nsCRT::LF, 0};
            while (unicodeBuf && (pos != -1) && ((PRUint32)pos < tString.Length()))
            {
                PRInt32 oldPos = pos;
                PRInt32 subStrLen;
                pos = tString.FindCharInSet(specialChars, oldPos);

                if (pos != -1)
                {
                    subStrLen = pos - oldPos;
                    // if first char is newline, then use just it
                    if (subStrLen == 0)
                        subStrLen = 1;
                }
                else
                {
                    subStrLen = tString.Length() - oldPos;
                    pos = tString.Length();
                }

                nsDependentSubstring subStr(tString, oldPos, subStrLen);

                // is it a tab?
                if (subStr.EqualsLiteral("\t"))
                {
                    res = mEditor->InsertTextImpl(NS_LITERAL_STRING("    "), address_of(curNode), &curOffset, doc);
                    pos++;
                }
                // is it a return?
                else if (subStr.EqualsLiteral(LFSTR))
                {
                    res = mEditor->CreateBRImpl(address_of(curNode), &curOffset, address_of(unused), nsIEditor::eNone);
                    pos++;
                }
                else
                {
                    res = mEditor->InsertTextImpl(subStr, address_of(curNode), &curOffset, doc);
                }
                NS_ENSURE_SUCCESS(res, res);
            }
        }
        outString->Assign(tString);

        if (curNode)
        {
            aSelection->Collapse(curNode, curOffset);

            // Make the caret attach to the inserted text, unless this text ends with a LF,
            // in which case make the caret attach to the next line.
            PRBool endsWithLF = !tString.IsEmpty() && tString.get()[tString.Length() - 1] == nsCRT::LF;
            nsCOMPtr<nsISelectionPrivate>selPrivate(do_QueryInterface(aSelection));
            selPrivate->SetInterlinePosition(endsWithLF);
        }
    }
    ASSERT_PASSWORD_LENGTHS_EQUAL()
    return res;
}