/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* 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/. */
class nsIContent; class nsIDocumentEncoder; class nsIOutputStream; class nsIPrincipal; class nsISelectionController; class nsITransferable;
namespace mozilla { namespace dom { class Selection;
} // namespace dom
/** * The text editor implementation. * Use to edit text document represented as a DOM tree.
*/ class TextEditor final : public EditorBase, public nsITimerCallback, public nsINamed { public: /**************************************************************************** * NOTE: DO NOT MAKE YOUR NEW METHODS PUBLIC IF they are called by other * classes under libeditor except EditorEventListener and * HTMLEditorEventListener because each public method which may fire * eEditorInput event will need to instantiate new stack class for * managing input type value of eEditorInput and cache some objects * for smarter handling. In other words, when you add new root * method to edit the DOM tree, you can make your new method public.
****************************************************************************/
/** * Note that TextEditor::Init() shouldn't cause running script synchronously. * So, `MOZ_CAN_RUN_SCRIPT_BOUNDARY` is safe here. * * @param aDocument The document which aAnonymousDivElement belongs to. * @param aAnonymousDivElement * The root editable element for this editor. * @param aSelectionController * The selection controller for independent selections * in the `<input>` or `<textarea>` element. * @param aFlags Some of nsIEditor::eEditor*Mask flags. * @param aPasswordMaskData * Set to an instance only when aFlags includes * `nsIEditor::eEditorPasswordMask`. Otherwise, must be * `nullptr`.
*/
MOZ_CAN_RUN_SCRIPT_BOUNDARY nsresult
Init(Document& aDocument, Element& aAnonymousDivElement,
nsISelectionController& aSelectionController, uint32_t aFlags,
UniquePtr<PasswordMaskData>&& aPasswordMaskData);
/** * PostCreate() should be called after Init, and is the time that the editor * tells its documentStateObservers that the document has been created. * Note that TextEditor::PostCreate() shouldn't cause running script * synchronously. So, `MOZ_CAN_RUN_SCRIPT_BOUNDARY` is safe here.
*/
MOZ_CAN_RUN_SCRIPT_BOUNDARY nsresult PostCreate();
/** * This method re-initializes the selection and caret state that are for * current editor state. When editor session is destroyed, it always reset * selection state even if this has no focus. So if destroying editor, * we have to call this method for focused editor to set selection state.
*/
MOZ_CAN_RUN_SCRIPT void ReinitializeSelection(Element& aElement);
/** * PreDestroy() is called before the editor goes away, and gives the editor a * chance to tell its documentStateObservers that the document is going away. * Note that TextEditor::PreDestroy() shouldn't cause running script * synchronously. So, `MOZ_CAN_RUN_SCRIPT_BOUNDARY` is safe here.
*/
[[nodiscard]] MOZ_CAN_RUN_SCRIPT_BOUNDARY UniquePtr<PasswordMaskData>
PreDestroy();
/** * Helper method for `AppendString()` and `AppendSubString()`. This should * be called only when `aText` is in a password field. This method masks * A part of or all of `aText` (`aStartOffsetInText` and later) should've * been copied (appended) to `aString`. `aStartOffsetInString` is where * the password was appended into `aString`.
*/ staticvoid MaskString(nsString& aString, const dom::Text& aTextNode,
uint32_t aStartOffsetInString,
uint32_t aStartOffsetInText);
// Shouldn't be used internally, but we need these using declarations for // avoiding warnings of clang. using EditorBase::CanCopy; using EditorBase::CanCut; using EditorBase::CanPaste;
// Overrides of EditorBase bool IsEmpty() const final;
/** * The maximum number of characters allowed. * default: -1 (unlimited).
*/
int32_t MaxTextLength() const { return mMaxTextLength; } void SetMaxTextLength(int32_t aLength) { mMaxTextLength = aLength; }
/** * This updates the wrap width used for initializing a document encoder within * a call of EditorBase::GetAndInitDocEncoder().
*/ void SetWrapColumn(int32_t aWrapColumn) { mWrapColumn = aWrapColumn; }
/** * 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 * @param aAllowBeforeInputEventCancelable * Whether `beforeinput` event which will be * dispatched for this can be cancelable or not. * @param aPrincipal Set subject principal if it may be called by * JS. If set to nullptr, will be treated as * called by system.
*/
MOZ_CAN_RUN_SCRIPT nsresult SetTextAsAction( const nsAString& aString,
AllowBeforeInputEventCancelable aAllowBeforeInputEventCancelable,
nsIPrincipal* aPrincipal = nullptr);
/** * ComputeTextValue() computes plaintext value of this editor. This may be * too expensive if it's in hot path. * * @param aDocumentEncoderFlags Flags of nsIDocumentEncoder. * @param aCharset Encoding of the document.
*/
nsresult ComputeTextValue(uint32_t aDocumentEncoderFlags,
nsAString& aOutputString) const {
AutoEditActionDataSetter editActionData(*this, EditAction::eNotEditing); if (NS_WARN_IF(!editActionData.CanHandle())) { return NS_ERROR_NOT_INITIALIZED;
}
nsresult rv = ComputeValueInternal(u"text/plain"_ns, aDocumentEncoderFlags,
aOutputString); if (NS_WARN_IF(NS_FAILED(rv))) { return EditorBase::ToGenericNSResult(rv);
} return NS_OK;
}
/** * The following methods are available only when the instance is a password * editor. They return whether there is unmasked range or not and range * start and length.
*/
MOZ_ALWAYS_INLINE bool IsAllMasked() const {
MOZ_ASSERT(IsPasswordEditor()); return !mPasswordMaskData || mPasswordMaskData->IsAllMasked();
}
MOZ_ALWAYS_INLINE uint32_t UnmaskedStart() const {
MOZ_ASSERT(IsPasswordEditor()); return mPasswordMaskData ? mPasswordMaskData->mUnmaskedStart : UINT32_MAX;
}
MOZ_ALWAYS_INLINE uint32_t UnmaskedLength() const {
MOZ_ASSERT(IsPasswordEditor()); return mPasswordMaskData ? mPasswordMaskData->mUnmaskedLength : 0;
}
MOZ_ALWAYS_INLINE uint32_t UnmaskedEnd() const {
MOZ_ASSERT(IsPasswordEditor()); return mPasswordMaskData ? mPasswordMaskData->UnmaskedEnd() : UINT32_MAX;
}
/** * IsMaskingPassword() returns false when the last caller of `Unmask()` * didn't want to mask again automatically. When this returns true, user * input causes masking the password even before timed-out.
*/ bool IsMaskingPassword() const {
MOZ_ASSERT(IsPasswordEditor()); return mPasswordMaskData && mPasswordMaskData->mIsMaskingPassword;
}
/** * PasswordMask() returns a character which masks each character in password * fields.
*/ static char16_t PasswordMask();
/** * If you want to prevent to echo password temporarily, use the following * methods.
*/ bool EchoingPasswordPrevented() const { return mPasswordMaskData && mPasswordMaskData->mEchoingPasswordPrevented;
} void PreventToEchoPassword() { if (mPasswordMaskData) {
mPasswordMaskData->mEchoingPasswordPrevented = true;
}
} void AllowToEchoPassword() { if (mPasswordMaskData) {
mPasswordMaskData->mEchoingPasswordPrevented = false;
}
}
protected: // May be called by friends. /**************************************************************************** * Some friend classes are allowed to call the following protected methods. * However, those methods won't prepare caches of some objects which are * necessary for them. So, if you call them from friend classes, you need * to make sure that AutoEditActionDataSetter is created.
****************************************************************************/
/** * FindBetterInsertionPoint() tries to look for better insertion point which * is typically the nearest text node and offset in it. * * @param aPoint Insertion point which the callers found. * @return Better insertion point if there is. If not returns * same point as aPoint.
*/ template <typename EditorDOMPointType>
EditorDOMPointType FindBetterInsertionPoint( const EditorDOMPointType& aPoint) const;
/** * InsertLineBreakAsSubAction() inserts a line break.
*/
[[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult InsertLineBreakAsSubAction();
/** * Replace existed string with aString. Caller must guarantee that there * is a placeholder transaction which will have the transaction. * * @ param aString The string to be set.
*/
[[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
SetTextAsSubAction(const nsAString& aString);
/** * MaybeDoAutoPasswordMasking() may mask password if we're doing auto-masking.
*/ void MaybeDoAutoPasswordMasking() { if (IsPasswordEditor() && IsMaskingPassword()) {
MaskAllCharacters();
}
}
/** * SetUnmaskRange() is available only when the instance is a password * editor. This just updates unmask range. I.e., caller needs to * guarantee to update the layout. * * @param aStart First index to show the character. * If aLength is 0, this value is ignored. * @param aLength Optional, Length to show characters. * If UINT32_MAX, it means unmasking all characters after * aStart. * If 0, it means that masking all characters. * @param aTimeout Optional, specify milliseconds to hide the unmasked * characters after this call. * If 0, it means this won't mask the characters * automatically. * If aLength is 0, this value is ignored.
*/
MOZ_CAN_RUN_SCRIPT_BOUNDARY nsresult SetUnmaskRange(
uint32_t aStart, uint32_t aLength = UINT32_MAX, uint32_t aTimeout = 0) { return SetUnmaskRangeInternal(aStart, aLength, aTimeout, false, false);
}
/** * SetUnmaskRangeAndNotify() is available only when the instance is a * password editor. This updates unmask range and notifying the text frame * to update the visible characters. * * @param aStart First index to show the character. * If UINT32_MAX, it means masking all. * @param aLength Optional, Length to show characters. * If UINT32_MAX, it means unmasking all characters after * aStart. * @param aTimeout Optional, specify milliseconds to hide the unmasked * characters after this call. * If 0, it means this won't mask the characters * automatically. * If aLength is 0, this value is ignored.
*/
MOZ_CAN_RUN_SCRIPT nsresult SetUnmaskRangeAndNotify(
uint32_t aStart, uint32_t aLength = UINT32_MAX, uint32_t aTimeout = 0) { return SetUnmaskRangeInternal(aStart, aLength, aTimeout, true, false);
}
/** * MaskAllCharacters() is an alias of SetUnmaskRange() to mask all characters. * In other words, this removes existing unmask range. * After this is called, TextEditor starts masking password automatically.
*/
MOZ_CAN_RUN_SCRIPT_BOUNDARY nsresult MaskAllCharacters() { if (!mPasswordMaskData) { return NS_OK; // Already we don't have masked range data.
} return SetUnmaskRangeInternal(UINT32_MAX, 0, 0, false, true);
}
/** * MaskAllCharactersAndNotify() is an alias of SetUnmaskRangeAndNotify() to * mask all characters and notifies the text frame. In other words, this * removes existing unmask range. * After this is called, TextEditor starts masking password automatically.
*/
MOZ_CAN_RUN_SCRIPT nsresult MaskAllCharactersAndNotify() { return SetUnmaskRangeInternal(UINT32_MAX, 0, 0, true, true);
}
/** * WillDeleteText() is called before `DeleteTextTransaction` or something * removes text in a text node. Note that this won't be called if the * instance is `HTMLEditor` since supporting it makes the code complicated * due to mutation events. * * @param aCurrentLength Current text length of the node. * @param aRemoveStartOffset Start offset of the range to be removed. * @param aRemoveLength Length of the range to be removed.
*/ void WillDeleteText(uint32_t aCurrentLength, uint32_t aRemoveStartOffset,
uint32_t aRemoveLength);
/** * DidInsertText() is called after `InsertTextTransaction` or something * inserts text into a text node. Note that this won't be called if the * instance is `HTMLEditor` since supporting it makes the code complicated * due to mutatione events. * * @param aNewLength New text length after the insertion. * @param aInsertedOffset Start offset of the inserted text. * @param aInsertedLength Length of the inserted text. * @return NS_OK or NS_ERROR_EDITOR_DESTROYED.
*/
[[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult DidInsertText(
uint32_t aNewLength, uint32_t aInsertedOffset, uint32_t aInsertedLength);
protected: // edit sub-action handler /** * MaybeTruncateInsertionStringForMaxLength() truncates aInsertionString to * `maxlength` if it was not pasted in by the user. * * @param aInsertionString [in/out] New insertion string. This is * truncated to `maxlength` if it was not pasted in * by the user. * @return If aInsertionString is truncated, it returns "as * handled", else "as ignored."
*/
Result<EditActionResult, nsresult> MaybeTruncateInsertionStringForMaxLength(
nsAString& aInsertionString);
/** * InsertLineFeedCharacterAtSelection() inserts a linefeed character at * selection.
*/
[[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<EditActionResult, nsresult>
InsertLineFeedCharacterAtSelection();
/** * Handles the newline characters according to the default system prefs * (editor.singleLine.pasteNewlines). * Each value means: * nsIEditor::eNewlinesReplaceWithSpaces (2, Firefox default): * replace newlines with spaces. * nsIEditor::eNewlinesStrip (3): * remove newlines from the string. * nsIEditor::eNewlinesReplaceWithCommas (4, Thunderbird default): * replace newlines with commas. * nsIEditor::eNewlinesStripSurroundingWhitespace (5): * collapse newlines and surrounding white-space characters and * remove them from the string. * nsIEditor::eNewlinesPasteIntact (0): * only remove the leading and trailing newlines. * nsIEditor::eNewlinesPasteToFirst (1) or any other value: * remove the first newline and all characters following it. * * @param aString the string to be modified in place.
*/ void HandleNewLinesInStringForSingleLineEditor(nsString& aString) const;
/** * HandleDeleteSelectionInternal() is a helper method of * HandleDeleteSelection(). Must be called only when the instance is * TextEditor. * NOTE: This method creates SelectionBatcher. Therefore, each caller * needs to check if the editor is still available even if this returns * NS_OK.
*/
[[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<EditActionResult, nsresult>
HandleDeleteSelectionInternal(nsIEditor::EDirection aDirectionAndAmount,
nsIEditor::EStripWrappers aStripWrappers);
/** * This method handles "delete selection" commands. * * @param aDirectionAndAmount Direction of the deletion. * @param aStripWrappers Must be nsIEditor::eNoStrip.
*/
[[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<EditActionResult, nsresult>
HandleDeleteSelection(nsIEditor::EDirection aDirectionAndAmount,
nsIEditor::EStripWrappers aStripWrappers) final;
/** * ComputeValueFromTextNodeAndBRElement() tries to compute "value" of * this editor content only with text nodes and `<br>` elements. * If this succeeds to compute the value, it's returned with aValue and * the result is marked as "handled". Otherwise, the caller needs to * compute it with another way.
*/
Result<EditActionResult, nsresult> ComputeValueFromTextNodeAndBRElement(
nsAString& aValue) const;
/** * SetTextWithoutTransaction() is optimized method to set `<input>.value` * and `<textarea>.value` to aValue without transaction. This must be * called only when it's not `HTMLEditor` and undo/redo is disabled.
*/
[[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<EditActionResult, nsresult>
SetTextWithoutTransaction(const nsAString& aValue);
/** * EnsureCaretNotAtEndOfTextNode() collapses selection at the padding `<br>` * element (i.e., container becomes the anonymous `<div>` element) if * `Selection` is at end of the text node.
*/
[[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult EnsureCaretNotAtEndOfTextNode();
protected: // Called by helper classes.
MOZ_CAN_RUN_SCRIPT void OnStartToHandleTopLevelEditSubAction(
EditSubAction aTopLevelEditSubAction,
nsIEditor::EDirection aDirectionOfTopLevelEditSubAction,
ErrorResult& aRv) final;
MOZ_CAN_RUN_SCRIPT nsresult OnEndHandlingTopLevelEditSubAction() final;
/** * HandleInlineSpellCheckAfterEdit() does spell-check after handling top level * edit subaction.
*/
nsresult HandleInlineSpellCheckAfterEdit() {
MOZ_ASSERT(IsEditActionDataAvailable()); if (!GetSpellCheckRestartPoint().IsSet()) { return NS_OK; // Maybe being initialized.
}
nsresult rv = HandleInlineSpellCheck(GetSpellCheckRestartPoint());
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed to spellcheck");
ClearSpellCheckRestartPoint(); return rv;
}
protected: // Shouldn't be used by friend classes virtual ~TextEditor();
/** * CanEchoPasswordNow() returns true if currently we can echo password. * If it's direct user input such as pasting or dropping text, this * returns false even if we may echo password.
*/ bool CanEchoPasswordNow() const;
/** * InitEditorContentAndSelection() may insert a padding `<br>` element for * if it's required in the anonymous `<div>` element or `<body>` element and * collapse selection at the end if there is no selection ranges.
*/
[[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult InitEditorContentAndSelection();
/** * Collapse `Selection` to end of the text node in the anonymous <div> * element.
*/
[[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult CollapseSelectionToEndOfTextNode();
/** * Make the given selection span the entire document.
*/
MOZ_CAN_RUN_SCRIPT nsresult SelectEntireDocument() final;
/** * See SetUnmaskRange() and SetUnmaskRangeAndNotify() for the detail. * * @param aForceStartMasking If true, forcibly starts masking. This should * be used only when `nsIEditor::Mask()` is called.
*/
MOZ_CAN_RUN_SCRIPT nsresult SetUnmaskRangeInternal(uint32_t aStart,
uint32_t aLength,
uint32_t aTimeout, bool aNotify, bool aForceStartMasking);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.