/* 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 "TextControlElement.h" #include "mozilla/ContentEvents.h" #include "mozilla/EventDispatcher.h" #include "mozilla/IMEContentObserver.h" #include "mozilla/IMEStateManager.h" #include "mozilla/LookAndFeel.h" #include "mozilla/PresShell.h" #include "mozilla/TextControlState.h" #include "mozilla/TextEditor.h" #include "mozilla/dom/Document.h" #include "mozilla/dom/HTMLBRElement.h" #include "mozilla/dom/ShadowRoot.h" #include "nsFocusManager.h" #include "nsFrameSelection.h" #include "nsIFormControl.h" #include "nsTextControlFrame.h" #include "nsTextNode.h" using namespace mozilla::dom; namespace mozilla { static RefPtr MakeAnonElement(Document& aDoc, PseudoStyleType aPseudoType, nsAtom* aTag = nsGkAtoms::div) { MOZ_ASSERT(aPseudoType != PseudoStyleType::NotPseudo); RefPtr element = aDoc.CreateHTMLElement(aTag); element->SetPseudoElementType(aPseudoType); if (aPseudoType == PseudoStyleType::MozTextControlEditingRoot) { // Make our root node editable element->SetFlags(NODE_IS_EDITABLE); } else { // The text control's accessible takes care of the placeholder etc for us, // all our pseudo-elements other than the root should not show up in the // a11y tree. element->SetAttr(kNameSpaceID_None, nsGkAtoms::aria_hidden, u"true"_ns, false); } return element; } RefPtr MakePlaceholderOrPreview(Document& aDoc, PseudoStyleType aPseudoType, const nsAString& aValue) { RefPtr el = MakeAnonElement(aDoc, aPseudoType); RefPtr text = aDoc.CreateTextNode(aValue); el->AppendChildTo(text, false, IgnoreErrors()); return el; } void TextControlElement::GetPreviewValue(nsAString& aValue) { Element* existing = FindShadowPseudo(PseudoStyleType::MozTextControlPreview); if (!existing) { return; } auto* text = Text::FromNodeOrNull(existing->GetFirstChild()); if (NS_WARN_IF(!text)) { return; } text->GetData(aValue); } void TextControlElement::SetPreviewValue(const nsAString& aValue) { RefPtr sr = GetShadowRoot(); if (!sr) { return; } RefPtr existing = FindShadowPseudo(PseudoStyleType::MozTextControlPreview); if (aValue.IsEmpty()) { if (existing) { existing->Remove(); } return; } if (existing) { RefPtr text = Text::FromNodeOrNull(existing->GetFirstChild()); if (NS_WARN_IF(!text)) { return; } text->SetData(aValue, IgnoreErrors()); return; } // Preview goes after the root or placeholder. RefPtr prevSibling = FindShadowPseudo(PseudoStyleType::Placeholder); if (!prevSibling) { prevSibling = FindShadowPseudo(PseudoStyleType::MozTextControlEditingRoot); } if (NS_WARN_IF(!prevSibling)) { // This can happen if we get called on e.g. a datetimebox or so. return; } RefPtr preview = MakePlaceholderOrPreview( *OwnerDoc(), PseudoStyleType::MozTextControlPreview, aValue); sr->InsertChildBefore(preview, prevSibling->GetNextSibling(), /* aNotify = */ true, IgnoreErrors()); } static void ProcessPlaceholder(nsAString& aValue, bool aTextArea) { if (aTextArea) { //