Bug 1358025 - Part 2. Add SetText Transaction API. r?masayuki
Actually, input.value setter behaviour (when editor has focus) is the following.
- select all
- delete selection
- delete text node
- insert text
- create text node
- create nsIFrame since we don't support lazy construction for editable element
It is too expensive to change text. So I would like to change like the following when there is 1 text node only (normal case). If child nodes isn't 1 text node only, use original way.
- set text on existed text node
So, for this fast path, I would like to add SetText transaction API.
MozReview-Commit-ID: A7bjXtCtSoB
--- a/editor/libeditor/EditorBase.cpp
+++ b/editor/libeditor/EditorBase.cpp
@@ -17,16 +17,17 @@
#include "DeleteRangeTransaction.h" // for DeleteRangeTransaction
#include "DeleteTextTransaction.h" // for DeleteTextTransaction
#include "EditAggregateTransaction.h" // for EditAggregateTransaction
#include "EditorEventListener.h" // for EditorEventListener
#include "InsertNodeTransaction.h" // for InsertNodeTransaction
#include "InsertTextTransaction.h" // for InsertTextTransaction
#include "JoinNodeTransaction.h" // for JoinNodeTransaction
#include "PlaceholderTransaction.h" // for PlaceholderTransaction
+#include "SetTextTransaction.h" // for SetTextTransaction
#include "SplitNodeTransaction.h" // for SplitNodeTransaction
#include "StyleSheetTransactions.h" // for AddStyleSheetTransaction, etc.
#include "TextEditUtils.h" // for TextEditUtils
#include "mozInlineSpellChecker.h" // for mozInlineSpellChecker
#include "mozilla/CheckedInt.h" // for CheckedInt
#include "mozilla/EditorUtils.h" // for AutoRules, etc.
#include "mozilla/EditTransactionBase.h" // for EditTransactionBase
#include "mozilla/FlushType.h" // for FlushType::Frames
@@ -2643,27 +2644,89 @@ EditorBase::NotifyDocumentListeners(
}
default:
NS_NOTREACHED("Unknown notification");
}
return rv;
}
+nsresult
+EditorBase::SetTextImpl(const nsAString& aString, Text& aCharData)
+{
+ RefPtr<SetTextTransaction> transaction =
+ CreateTxnForSetText(aString, aCharData);
+ if (NS_WARN_IF(!transaction)) {
+ return NS_ERROR_FAILURE;
+ }
+
+ uint32_t length = aCharData.Length();
+
+ AutoRules beginRulesSniffing(this, EditAction::setText,
+ nsIEditor::eNext);
+
+ // Let listeners know what's up
+ {
+ AutoActionListenerArray listeners(mActionListeners);
+ for (auto& listener : listeners) {
+ if (length) {
+ listener->WillDeleteText(
+ static_cast<nsIDOMCharacterData*>(aCharData.AsDOMNode()), 0,
+ length);
+ }
+ if (!aString.IsEmpty()) {
+ listener->WillInsertText(
+ static_cast<nsIDOMCharacterData*>(aCharData.AsDOMNode()), 0,
+ aString);
+ }
+ }
+ }
+
+ nsresult rv = DoTransaction(transaction);
+
+ // Let listeners know what happened
+ {
+ AutoActionListenerArray listeners(mActionListeners);
+ for (auto& listener : listeners) {
+ if (length) {
+ listener->DidDeleteText(
+ static_cast<nsIDOMCharacterData*>(aCharData.AsDOMNode()), 0,
+ length, rv);
+ }
+ if (!aString.IsEmpty()) {
+ listener->DidInsertText(
+ static_cast<nsIDOMCharacterData*>(aCharData.AsDOMNode()), 0,
+ aString, rv);
+ }
+ }
+ }
+
+ return rv;
+}
+
already_AddRefed<InsertTextTransaction>
EditorBase::CreateTxnForInsertText(const nsAString& aStringToInsert,
Text& aTextNode,
int32_t aOffset)
{
RefPtr<InsertTextTransaction> transaction =
new InsertTextTransaction(aTextNode, aOffset, aStringToInsert, *this,
&mRangeUpdater);
return transaction.forget();
}
+already_AddRefed<SetTextTransaction>
+EditorBase::CreateTxnForSetText(const nsAString& aString,
+ Text& aTextNode)
+{
+ RefPtr<SetTextTransaction> transaction =
+ new SetTextTransaction(aTextNode, aString, *this, &mRangeUpdater);
+ return transaction.forget();
+}
+
nsresult
EditorBase::DeleteText(nsGenericDOMDataNode& aCharData,
uint32_t aOffset,
uint32_t aLength)
{
RefPtr<DeleteTextTransaction> transaction =
CreateTxnForDeleteText(aCharData, aOffset, aLength);
NS_ENSURE_STATE(transaction);
--- a/editor/libeditor/EditorBase.h
+++ b/editor/libeditor/EditorBase.h
@@ -67,16 +67,17 @@ enum class EditAction : int32_t
// text commands
insertText = 2000,
insertIMEText = 2001,
deleteSelection = 2002,
setTextProperty = 2003,
removeTextProperty = 2004,
outputText = 2005,
+ setText = 2006,
// html only action
insertBreak = 3000,
makeList = 3001,
indent = 3002,
outdent = 3003,
align = 3004,
makeBasicBlock = 3005,
@@ -111,16 +112,17 @@ class DeleteTextTransaction;
class EditAggregateTransaction;
class EditTransactionBase;
class ErrorResult;
class HTMLEditor;
class InsertNodeTransaction;
class InsertTextTransaction;
class JoinNodeTransaction;
class RemoveStyleSheetTransaction;
+class SetTextTransaction;
class SplitNodeTransaction;
class TextComposition;
class TextEditor;
struct EditorDOMPoint;
namespace dom {
class DataTransfer;
class Element;
@@ -199,16 +201,20 @@ public:
virtual nsresult InsertTextImpl(const nsAString& aStringToInsert,
nsCOMPtr<nsINode>* aInOutNode,
int32_t* aInOutOffset,
nsIDocument* aDoc);
nsresult InsertTextIntoTextNodeImpl(const nsAString& aStringToInsert,
Text& aTextNode, int32_t aOffset,
bool aSuppressIME = false);
+
+ nsresult SetTextImpl(const nsAString& aString,
+ Text& aTextNode);
+
NS_IMETHOD DeleteSelectionImpl(EDirection aAction,
EStripWrappers aStripWrappers);
already_AddRefed<Element> DeleteSelectionAndCreateElement(nsIAtom& aTag);
/**
* Helper routines for node/parent manipulations.
*/
@@ -349,16 +355,19 @@ protected:
/**
* Create a transaction for inserting aStringToInsert into aTextNode. Never
* returns null.
*/
already_AddRefed<mozilla::InsertTextTransaction>
CreateTxnForInsertText(const nsAString& aStringToInsert, Text& aTextNode,
int32_t aOffset);
+ already_AddRefed<SetTextTransaction>
+ CreateTxnForSetText(const nsAString& aString, Text& aTextNode);
+
/**
* Never returns null.
*/
already_AddRefed<mozilla::CompositionTransaction>
CreateTxnForComposition(const nsAString& aStringToInsert);
/**
* Create a transaction for adding a style sheet.
new file mode 100644
--- /dev/null
+++ b/editor/libeditor/SetTextTransaction.cpp
@@ -0,0 +1,109 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 sw=2 et tw=78: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "SetTextTransaction.h"
+
+#include "mozilla/DebugOnly.h" // DebugOnly
+#include "mozilla/EditorBase.h" // mEditorBase
+#include "mozilla/SelectionState.h" // RangeUpdater
+#include "mozilla/dom/Selection.h" // Selection local var
+#include "mozilla/dom/Text.h" // mTextNode
+#include "nsAString.h" // nsAString parameter
+#include "nsDebug.h" // for NS_ASSERTION, etc.
+#include "nsError.h" // for NS_OK, etc.
+#include "nsQueryObject.h" // for do_QueryObject
+
+namespace mozilla {
+
+using namespace dom;
+
+SetTextTransaction::SetTextTransaction(Text& aTextNode,
+ const nsAString& aStringToSet,
+ EditorBase& aEditorBase,
+ RangeUpdater* aRangeUpdater)
+ : mTextNode(&aTextNode)
+ , mStringToSet(aStringToSet)
+ , mEditorBase(&aEditorBase)
+ , mRangeUpdater(aRangeUpdater)
+{
+}
+
+SetTextTransaction::~SetTextTransaction()
+{
+}
+
+NS_IMPL_CYCLE_COLLECTION_INHERITED(SetTextTransaction, EditTransactionBase,
+ mEditorBase,
+ mTextNode)
+
+NS_IMPL_ADDREF_INHERITED(SetTextTransaction, EditTransactionBase)
+NS_IMPL_RELEASE_INHERITED(SetTextTransaction, EditTransactionBase)
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(SetTextTransaction)
+ if (aIID.Equals(NS_GET_IID(SetTextTransaction))) {
+ foundInterface = static_cast<nsITransaction*>(this);
+ } else
+NS_INTERFACE_MAP_END_INHERITING(EditTransactionBase)
+
+
+NS_IMETHODIMP
+SetTextTransaction::DoTransaction()
+{
+ if (NS_WARN_IF(!mEditorBase) || NS_WARN_IF(!mTextNode)) {
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+
+ nsresult rv = mTextNode->GetData(mPreviousData);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+
+ rv = mTextNode->SetData(mStringToSet);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+
+ // Only set selection to insertion point if editor gives permission
+ if (mEditorBase->GetShouldTxnSetSelection()) {
+ RefPtr<Selection> selection = mEditorBase->GetSelection();
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return NS_ERROR_NULL_POINTER;
+ }
+ DebugOnly<nsresult> rv =
+ selection->Collapse(mTextNode, mStringToSet.Length());
+ NS_ASSERTION(NS_SUCCEEDED(rv),
+ "Selection could not be collapsed after insert");
+ }
+ mRangeUpdater->SelAdjDeleteText(mTextNode, 0, mPreviousData.Length());
+ mRangeUpdater->SelAdjInsertText(*mTextNode, 0, mStringToSet);
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+SetTextTransaction::UndoTransaction()
+{
+ return mTextNode->SetData(mPreviousData);
+}
+
+NS_IMETHODIMP
+SetTextTransaction::Merge(nsITransaction* aTransaction,
+ bool* aDidMerge)
+{
+ // Set out param default value
+ *aDidMerge = false;
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+SetTextTransaction::GetTxnDescription(nsAString& aString)
+{
+ aString.AssignLiteral("SetTextTransaction: ");
+ aString += mStringToSet;
+ return NS_OK;
+}
+
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/editor/libeditor/SetTextTransaction.h
@@ -0,0 +1,80 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 sw=2 et tw=78: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_SetTextTransaction_h
+#define mozilla_SetTextTransaction_h
+
+#include "mozilla/EditTransactionBase.h" // base class
+#include "nsCycleCollectionParticipant.h" // various macros
+#include "nsID.h" // NS_DECLARE_STATIC_IID_ACCESSOR
+#include "nsISupportsImpl.h" // NS_DECL_ISUPPORTS_INHERITED
+#include "nsString.h" // nsString members
+#include "nscore.h" // NS_IMETHOD, nsAString
+
+class nsITransaction;
+
+#define NS_SETTEXTTXN_IID \
+{ 0x568bac0b, 0xa42a, 0x4150, \
+ { 0xbd, 0x90, 0x34, 0xd0, 0x2f, 0x32, 0x74, 0x2e } }
+
+namespace mozilla {
+
+class EditorBase;
+class RangeUpdater;
+
+namespace dom {
+class Text;
+} // namespace dom
+
+/**
+ * A transaction that inserts text into a content node.
+ */
+class SetTextTransaction final : public EditTransactionBase
+{
+public:
+ NS_DECLARE_STATIC_IID_ACCESSOR(NS_SETTEXTTXN_IID)
+
+ /**
+ * @param aTextNode The text content node.
+ * @param aString The new text to insert.
+ * @param aEditorBase Used to get and set the selection.
+ * @param aRangeUpdater The range updater
+ */
+ SetTextTransaction(dom::Text& aTextNode,
+ const nsAString& aString, EditorBase& aEditorBase,
+ RangeUpdater* aRangeUpdater);
+
+ NS_DECL_ISUPPORTS_INHERITED
+ NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(SetTextTransaction,
+ EditTransactionBase)
+
+ NS_DECL_EDITTRANSACTIONBASE
+
+ NS_IMETHOD Merge(nsITransaction* aTransaction, bool* aDidMerge) override;
+
+private:
+ virtual ~SetTextTransaction();
+
+ // The Text node to operate upon.
+ RefPtr<dom::Text> mTextNode;
+
+ // The text to insert into mTextNode at mOffset.
+ nsString mStringToSet;
+
+ // The previous text for undo
+ nsString mPreviousData;
+
+ // The editor, which we'll need to get the selection.
+ RefPtr<EditorBase> mEditorBase;
+
+ RangeUpdater* mRangeUpdater;
+};
+
+NS_DEFINE_STATIC_IID_ACCESSOR(SetTextTransaction, NS_SETTEXTTXN_IID)
+
+} // namespace mozilla
+
+#endif // #ifndef mozilla_SetTextTransaction_h
--- a/editor/libeditor/TextEditRules.cpp
+++ b/editor/libeditor/TextEditRules.cpp
@@ -29,18 +29,20 @@
#include "nsIDOMNode.h"
#include "nsIDOMNodeFilter.h"
#include "nsIDOMText.h"
#include "nsNameSpaceManager.h"
#include "nsINode.h"
#include "nsIPlaintextEditor.h"
#include "nsISupportsBase.h"
#include "nsLiteralString.h"
+#include "nsTextNode.h"
#include "nsUnicharUtils.h"
#include "nsIHTMLCollection.h"
+#include "nsPrintfCString.h"
namespace mozilla {
using namespace dom;
#define CANCEL_OPERATION_IF_READONLY_OR_DISABLED \
if (IsReadonly() || IsDisabled()) \
{ \
@@ -258,16 +260,20 @@ TextEditRules::WillDoAction(Selection* a
case EditAction::insertBreak:
UndefineCaretBidiLevel(aSelection);
return WillInsertBreak(aSelection, aCancel, aHandled, info->maxLength);
case EditAction::insertText:
case EditAction::insertIMEText:
UndefineCaretBidiLevel(aSelection);
return WillInsertText(info->action, aSelection, aCancel, aHandled,
info->inString, info->outString, info->maxLength);
+ case EditAction::setText:
+ UndefineCaretBidiLevel(aSelection);
+ return WillSetText(*aSelection, aCancel, aHandled, info->inString,
+ info->maxLength);
case EditAction::deleteSelection:
return WillDeleteSelection(aSelection, info->collapsedAction,
aCancel, aHandled);
case EditAction::undo:
return WillUndo(aSelection, aCancel, aHandled);
case EditAction::redo:
return WillRedo(aSelection, aCancel, aHandled);
case EditAction::setTextProperty:
@@ -303,16 +309,18 @@ TextEditRules::DidDoAction(Selection* aS
TextRulesInfo* info = static_cast<TextRulesInfo*>(aInfo);
switch (info->action) {
case EditAction::insertBreak:
return DidInsertBreak(aSelection, aResult);
case EditAction::insertText:
case EditAction::insertIMEText:
return DidInsertText(aSelection, aResult);
+ case EditAction::setText:
+ return DidSetText(*aSelection, aResult);
case EditAction::deleteSelection:
return DidDeleteSelection(aSelection, info->collapsedAction, aResult);
case EditAction::undo:
return DidUndo(aSelection, aResult);
case EditAction::redo:
return DidRedo(aSelection, aResult);
case EditAction::setTextProperty:
return DidSetTextProperty(aSelection, aResult);
@@ -762,16 +770,128 @@ TextEditRules::WillInsertText(EditAction
nsresult
TextEditRules::DidInsertText(Selection* aSelection,
nsresult aResult)
{
return DidInsert(aSelection, aResult);
}
nsresult
+TextEditRules::WillSetText(Selection& aSelection,
+ bool* aCancel,
+ bool* aHandled,
+ const nsAString* aString,
+ int32_t aMaxLength)
+{
+ MOZ_ASSERT(aCancel);
+ MOZ_ASSERT(aHandled);
+ MOZ_ASSERT(aString);
+
+ CANCEL_OPERATION_IF_READONLY_OR_DISABLED
+
+ *aHandled = false;
+ *aCancel = false;
+
+ if (NS_WARN_IF(!mTextEditor)) {
+ return NS_ERROR_FAILURE;
+ }
+ RefPtr<TextEditor> textEditor = mTextEditor;
+
+ if (!IsPlaintextEditor() || textEditor->IsIMEComposing() ||
+ aMaxLength != -1) {
+ // SetTextTransaction only supports plain text editor without IME.
+ return NS_OK;
+ }
+
+ if (IsPasswordEditor() && LookAndFeel::GetEchoPassword() &&
+ !DontEchoPassword()) {
+ // Echo password timer will implement on InsertText.
+ return NS_OK;
+ }
+
+ WillInsert(aSelection, aCancel);
+ // we want to ignore result of WillInsert()
+ *aCancel = false;
+
+ RefPtr<Element> rootElement = textEditor->GetRoot();
+ uint32_t count = rootElement->GetChildCount();
+
+ // handles only when there is only one node and it's a text node, or empty.
+
+ if (count > 1) {
+ return NS_OK;
+ }
+
+ nsAutoString tString(*aString);
+
+ if (IsPasswordEditor()) {
+ mPasswordText.Assign(tString);
+ FillBufWithPWChars(&tString, tString.Length());
+ } else if (IsSingleLineEditor()) {
+ HandleNewLines(tString, textEditor->mNewlineHandling);
+ }
+
+ if (!count) {
+ if (tString.IsEmpty()) {
+ *aHandled = true;
+ return NS_OK;
+ }
+ RefPtr<nsIDocument> doc = textEditor->GetDocument();
+ if (NS_WARN_IF(!doc)) {
+ return NS_OK;
+ }
+ RefPtr<nsTextNode> newNode = doc->CreateTextNode(tString);
+ if (NS_WARN_IF(!newNode)) {
+ return NS_OK;
+ }
+ nsresult rv = textEditor->InsertNode(*newNode, *rootElement, 0);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+ *aHandled = true;
+
+ ASSERT_PASSWORD_LENGTHS_EQUAL();
+
+ return NS_OK;
+ }
+
+ nsINode* curNode = rootElement->GetFirstChild();
+ if (NS_WARN_IF(!EditorBase::IsTextNode(curNode))) {
+ return NS_OK;
+ }
+ if (tString.IsEmpty()) {
+ nsresult rv = textEditor->DeleteNode(curNode);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+
+ *aHandled = true;
+ return NS_OK;
+ }
+
+ nsresult rv = textEditor->SetTextImpl(tString, *curNode->GetAsText());
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+
+ *aHandled = true;
+
+ ASSERT_PASSWORD_LENGTHS_EQUAL();
+
+ return NS_OK;
+}
+
+nsresult
+TextEditRules::DidSetText(Selection& aSelection,
+ nsresult aResult)
+{
+ return NS_OK;
+}
+
+nsresult
TextEditRules::WillSetTextProperty(Selection* aSelection,
bool* aCancel,
bool* aHandled)
{
if (!aSelection || !aCancel || !aHandled) {
return NS_ERROR_NULL_POINTER;
}
--- a/editor/libeditor/TextEditRules.h
+++ b/editor/libeditor/TextEditRules.h
@@ -123,16 +123,23 @@ protected:
nsAString* outString,
int32_t aMaxLength);
nsresult DidInsertText(Selection* aSelection, nsresult aResult);
nsresult WillInsertBreak(Selection* aSelection, bool* aCancel,
bool* aHandled, int32_t aMaxLength);
nsresult DidInsertBreak(Selection* aSelection, nsresult aResult);
+ nsresult WillSetText(Selection& aSelection,
+ bool* aCancel,
+ bool* aHandled,
+ const nsAString* inString,
+ int32_t aMaxLength);
+ nsresult DidSetText(Selection& aSelection, nsresult aResult);
+
void WillInsert(Selection& aSelection, bool* aCancel);
nsresult DidInsert(Selection* aSelection, nsresult aResult);
nsresult WillDeleteSelection(Selection* aSelection,
nsIEditor::EDirection aCollapsedAction,
bool* aCancel,
bool* aHandled);
nsresult DidDeleteSelection(Selection* aSelection,
--- a/editor/libeditor/TextEditor.cpp
+++ b/editor/libeditor/TextEditor.cpp
@@ -761,16 +761,74 @@ TextEditor::InsertLineBreak()
if (!cancel) {
// post-process, always called if WillInsertBreak didn't return cancel==true
rv = rules->DidDoAction(selection, &ruleInfo, rv);
}
return rv;
}
+NS_IMETHODIMP
+TextEditor::SetText(const nsAString& aString)
+{
+ if (NS_WARN_IF(!mRules)) {
+ return NS_ERROR_NOT_INITIALIZED;
+ }
+
+ // Protect the edit rules object from dying
+ nsCOMPtr<nsIEditRules> rules(mRules);
+
+ // delete placeholder txns merge.
+ AutoPlaceHolderBatch batch(this, nullptr);
+ AutoRules beginRulesSniffing(this, EditAction::setText, nsIEditor::eNext);
+
+ // pre-process
+ RefPtr<Selection> selection = GetSelection();
+ if (NS_WARN_IF(!selection)) {
+ return NS_ERROR_NULL_POINTER;
+ }
+ TextRulesInfo ruleInfo(EditAction::setText);
+ ruleInfo.inString = &aString;
+ ruleInfo.maxLength = mMaxTextLength;
+
+ bool cancel;
+ bool handled;
+ nsresult rv = rules->WillDoAction(selection, &ruleInfo, &cancel, &handled);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+ if (cancel) {
+ return NS_OK;
+ }
+ if (!handled) {
+ // We want to select trailing BR node to remove all nodes to replace all,
+ // but TextEditor::SelectEntireDocument doesn't select that BR node.
+ if (rules->DocumentIsEmpty()) {
+ // if it's empty, don't select entire doc - that would select
+ // the bogus node
+ Element* rootElement = GetRoot();
+ if (NS_WARN_IF(!rootElement)) {
+ return NS_ERROR_FAILURE;
+ }
+ rv = selection->Collapse(rootElement, 0);
+ } else {
+ rv = EditorBase::SelectEntireDocument(selection);
+ }
+ if (NS_SUCCEEDED(rv)) {
+ if (aString.IsEmpty()) {
+ rv = DeleteSelection(eNone, eStrip);
+ } else {
+ rv = InsertText(aString);
+ }
+ }
+ }
+ // post-process
+ return rules->DidDoAction(selection, &ruleInfo, rv);
+}
+
nsresult
TextEditor::BeginIMEComposition(WidgetCompositionEvent* aEvent)
{
NS_ENSURE_TRUE(!mComposition, NS_OK);
if (IsPasswordEditor()) {
NS_ENSURE_TRUE(mRules, NS_ERROR_NULL_POINTER);
// Protect the edit rules object from dying
--- a/editor/libeditor/moz.build
+++ b/editor/libeditor/moz.build
@@ -59,16 +59,17 @@ UNIFIED_SOURCES += [
'HTMLTableEditor.cpp',
'HTMLURIRefObject.cpp',
'InsertNodeTransaction.cpp',
'InsertTextTransaction.cpp',
'InternetCiter.cpp',
'JoinNodeTransaction.cpp',
'PlaceholderTransaction.cpp',
'SelectionState.cpp',
+ 'SetTextTransaction.cpp',
'SplitNodeTransaction.cpp',
'StyleSheetTransactions.cpp',
'TextEditor.cpp',
'TextEditorDataTransfer.cpp',
'TextEditorTest.cpp',
'TextEditRules.cpp',
'TextEditRulesBidi.cpp',
'TextEditUtils.cpp',
--- a/editor/nsIPlaintextEditor.idl
+++ b/editor/nsIPlaintextEditor.idl
@@ -98,15 +98,23 @@ interface nsIPlaintextEditor : nsISuppor
* If the selection is not collapsed, the selection is deleted
* and the insertion takes place at the resulting collapsed selection.
*
* @param aString the string to be inserted
*/
void insertText(in DOMString aStringToInsert);
/**
+ * Replace existed string with a string.
+ * This is fast path to replace all string when using single line control.
+ *
+ * @ param aString the string to be set
+ */
+ [noscript] void setText(in DOMString aString);
+
+ /**
* Insert a line break into the content model.
* The interpretation of a break is up to the implementation:
* it may enter a character, split a node in the tree, etc.
* This may be more efficient than calling InsertText with a newline.
*/
void insertLineBreak();
};