/* -*- 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/. */ #ifndef HTMLEditUtils_h #define HTMLEditUtils_h /** * This header declares/defines static helper methods as members of * HTMLEditUtils. If you want to create or look for helper trivial classes for * HTMLEditor, see HTMLEditHelpers.h. */ #include "EditorBase.h" #include "EditorDOMPoint.h" #include "EditorForwards.h" #include "EditorLineBreak.h" #include "EditorUtils.h" #include "HTMLEditHelpers.h" #include "mozilla/Attributes.h" #include "mozilla/EnumSet.h" #include "mozilla/IntegerRange.h" #include "mozilla/Maybe.h" #include "mozilla/Result.h" #include "mozilla/dom/AbstractRange.h" #include "mozilla/dom/AncestorIterator.h" #include "mozilla/dom/Element.h" #include "mozilla/dom/HTMLBRElement.h" #include "mozilla/dom/Selection.h" #include "mozilla/dom/Text.h" #include "nsContentUtils.h" #include "nsCRT.h" #include "nsGkAtoms.h" #include "nsHTMLTags.h" #include "nsTArray.h" class nsAtom; class nsPresContext; namespace mozilla { enum class CollectChildrenOption { // Ignore non-editable nodes IgnoreNonEditableChildren, // Ignore invisible text nodes IgnoreInvisibleTextNodes, // Collect list children too. CollectListChildren, // Collect table children too. CollectTableChildren, }; class HTMLEditUtils final { using AbstractRange = dom::AbstractRange; using Element = dom::Element; using Selection = dom::Selection; using Text = dom::Text; public: static constexpr char16_t kNewLine = '\n'; static constexpr char16_t kCarriageReturn = '\r'; static constexpr char16_t kTab = '\t'; static constexpr char16_t kSpace = ' '; static constexpr char16_t kNBSP = 0x00A0; static constexpr char16_t kGreaterThan = '>'; /** * IsSimplyEditableNode() returns true when aNode is simply editable. * This does NOT means that aNode can be removed from current parent nor * aNode's data is editable. */ static bool IsSimplyEditableNode(const nsINode& aNode) { return aNode.IsEditable(); } /** * Return true if aNode is editable or not in a composed doc. This is useful * if the caller may modify document fragment before inserting it into a * Document. */ static bool NodeIsEditableOrNotInComposedDoc(const nsINode& aNode) { return MOZ_UNLIKELY(!aNode.IsInComposedDoc()) || aNode.IsEditable(); } /** * Return true if aElement is an editing host which is either: * - the root element * - parent is not editable * - the
element of the document */ [[nodiscard]] static bool ElementIsEditableRoot(const Element& aElement); /** * Return true if inclusive flat tree ancestor has `inert` state. */ static bool ContentIsInert(const nsIContent& aContent); /** * IsNeverContentEditableElementByUser() returns true if the element's content * is never editable by user. E.g., the content is always replaced by * native anonymous node or something. */ static bool IsNeverElementContentsEditableByUser(const nsIContent& aContent) { return aContent.IsElement() && (!HTMLEditUtils::IsContainerNode(aContent) || aContent.IsAnyOfHTMLElements( nsGkAtoms::applet, nsGkAtoms::colgroup, nsGkAtoms::frameset, nsGkAtoms::head, nsGkAtoms::html, nsGkAtoms::iframe, nsGkAtoms::meter, nsGkAtoms::progress, nsGkAtoms::select, nsGkAtoms::textarea)); } /** * IsNonEditableReplacedContent() returns true when aContent is an inclusive * descendant of a replaced element whose content shouldn't be editable by * user's operation. */ static bool IsNonEditableReplacedContent(const nsIContent& aContent) { for (Element* element : aContent.InclusiveAncestorsOfType* element as its child or its descendant. */ static bool CanElementContainParagraph(const Element& aElement) { if (HTMLEditUtils::CanNodeContain(aElement, *nsGkAtoms::p)) { return true; } // Even if the element cannot have a
element as a child, it can contain //
element as a descendant if it's one of the following elements.
if (aElement.IsAnyOfHTMLElements(nsGkAtoms::ol, nsGkAtoms::ul,
nsGkAtoms::dl, nsGkAtoms::table,
nsGkAtoms::thead, nsGkAtoms::tbody,
nsGkAtoms::tfoot, nsGkAtoms::tr)) {
return true;
}
// XXX Otherwise, Chromium checks the CSS box is a block, but we don't do it
// for now.
return false;
}
/**
* Return a point which can insert a node whose name is aTagName scanning
* from aPoint to its ancestor points.
*/
template