Bug 1624007 - Don't check `IsSelectionRangeContainerNotContent()` for/in `GetElementOrParentElement*()` r=m_kato

We can relax about `GetElementOrParentElement*()` because they just return
`nullptr` when selection anchor is a `Document` node.

Additionally, this patch renames the internal APIs to the names similar to
modern DOM API.

Finally, this adds automated test for
`nsIHTMLEditor.getElementOrParentByTagName()`.

Differential Revision: https://phabricator.services.mozilla.com/D70152

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Masayuki Nakano 2020-04-09 10:10:36 +00:00
Родитель 581f34a57e
Коммит 39b3ec6675
11 изменённых файлов: 621 добавлений и 179 удалений

Просмотреть файл

@ -15,8 +15,9 @@
#include "mozilla/dom/Selection.h"
#include "mozilla/dom/StaticRange.h"
#include "nsAtom.h"
#include "nscore.h"
#include "nsCOMPtr.h"
#include "nsContentUtils.h"
#include "nscore.h"
#include "nsDebug.h"
#include "nsRange.h"
#include "nsString.h"
@ -804,6 +805,15 @@ class EditorUtils final {
uint32_t aStartOffsetInString,
uint32_t aStartOffsetInText);
static nsStaticAtom* GetTagNameAtom(const nsAString& aTagName) {
if (aTagName.IsEmpty()) {
return nullptr;
}
nsAutoString lowerTagName;
nsContentUtils::ASCIIToLower(aTagName, lowerTagName);
return NS_GetStaticAtom(lowerTagName);
}
static nsStaticAtom* GetAttributeAtom(const nsAString& aAttribute) {
if (aAttribute.IsEmpty()) {
return nullptr; // Don't use nsGkAtoms::_empty for attribute.

Просмотреть файл

@ -370,7 +370,7 @@ nsresult HTMLEditor::RefreshEditingUI() {
if (IsObjectResizerEnabled() || IsInlineTableEditorEnabled()) {
// Resizing or Inline Table Editing is enabled, we need to check if the
// selection is contained in a table cell
cellElement = GetElementOrParentByTagNameAtSelection(*nsGkAtoms::td);
cellElement = GetInclusiveAncestorByTagNameAtSelection(*nsGkAtoms::td);
}
if (IsObjectResizerEnabled() && cellElement) {

Просмотреть файл

@ -71,16 +71,6 @@ using namespace widget;
const char16_t kNBSP = 160;
static already_AddRefed<nsAtom> GetLowerCaseNameAtom(
const nsAString& aTagName) {
if (aTagName.IsEmpty()) {
return nullptr;
}
nsAutoString lowerTagName;
nsContentUtils::ASCIIToLower(aTagName, lowerTagName);
return NS_Atomize(lowerTagName);
}
// Some utilities to handle overloading of "A" tag for link and named anchor.
static bool IsLinkTag(const nsAtom& aTagName) {
return &aTagName == nsGkAtoms::href;
@ -1088,10 +1078,11 @@ EditActionResult HTMLEditor::HandleTabKeyPressInTable(
}
// Find enclosing table cell from selection (cell may be selected element)
Element* cellElement = GetElementOrParentByTagNameAtSelection(*nsGkAtoms::td);
Element* cellElement =
GetInclusiveAncestorByTagNameAtSelection(*nsGkAtoms::td);
if (!cellElement) {
NS_WARNING(
"HTMLEditor::GetElementOrParentByTagNameAtSelection(*nsGkAtoms::td) "
"HTMLEditor::GetInclusiveAncestorByTagNameAtSelection(*nsGkAtoms::td) "
"returned nullptr");
// Do nothing if we didn't find a table cell.
return EditActionIgnored();
@ -2541,8 +2532,8 @@ nsresult HTMLEditor::AlignAsAction(const nsAString& aAlignType,
return EditorBase::ToGenericNSResult(result.Rv());
}
Element* HTMLEditor::GetElementOrParentByTagName(const nsAtom& aTagName,
nsINode* aNode) const {
Element* HTMLEditor::GetInclusiveAncestorByTagName(const nsStaticAtom& aTagName,
nsIContent& aContent) const {
MOZ_ASSERT(&aTagName != nsGkAtoms::_empty);
AutoEditActionDataSetter editActionData(*this, EditAction::eNotEditing);
@ -2550,55 +2541,44 @@ Element* HTMLEditor::GetElementOrParentByTagName(const nsAtom& aTagName,
return nullptr;
}
if (aNode) {
return GetElementOrParentByTagNameInternal(aTagName, *aNode);
}
if (IsSelectionRangeContainerNotContent()) {
return nullptr;
}
return GetElementOrParentByTagNameAtSelection(aTagName);
return GetInclusiveAncestorByTagNameInternal(aTagName, aContent);
}
Element* HTMLEditor::GetElementOrParentByTagNameAtSelection(
const nsAtom& aTagName) const {
Element* HTMLEditor::GetInclusiveAncestorByTagNameAtSelection(
const nsStaticAtom& aTagName) const {
MOZ_ASSERT(IsEditActionDataAvailable());
MOZ_ASSERT(!IsSelectionRangeContainerNotContent());
MOZ_ASSERT(&aTagName != nsGkAtoms::_empty);
// If no node supplied, get it from anchor node of current selection
const EditorRawDOMPoint atAnchor(SelectionRefPtr()->AnchorRef());
if (NS_WARN_IF(!atAnchor.IsSet())) {
if (NS_WARN_IF(!atAnchor.IsSet()) ||
NS_WARN_IF(!atAnchor.GetContainerAsContent())) {
return nullptr;
}
// Try to get the actual selected node
nsCOMPtr<nsINode> node;
nsIContent* content = nullptr;
if (atAnchor.GetContainer()->HasChildNodes() &&
atAnchor.GetContainerAsContent()) {
node = atAnchor.GetChild();
content = atAnchor.GetChild();
}
// Anchor node is probably a text node - just use that
if (!node) {
if (NS_WARN_IF(!atAnchor.IsSet())) {
if (!content) {
content = atAnchor.GetContainerAsContent();
if (NS_WARN_IF(!content)) {
return nullptr;
}
node = atAnchor.GetContainer();
}
return GetElementOrParentByTagNameInternal(aTagName, *node);
return GetInclusiveAncestorByTagNameInternal(aTagName, *content);
}
Element* HTMLEditor::GetElementOrParentByTagNameInternal(const nsAtom& aTagName,
nsINode& aNode) const {
Element* HTMLEditor::GetInclusiveAncestorByTagNameInternal(
const nsStaticAtom& aTagName, nsIContent& aContent) const {
MOZ_ASSERT(&aTagName != nsGkAtoms::_empty);
Element* currentElement = aNode.GetAsElementOrParentElement();
Element* currentElement = aContent.GetAsElementOrParentElement();
if (NS_WARN_IF(!currentElement)) {
// Neither aNode nor its parent is an element, so no ancestor is
MOZ_ASSERT(!aNode.GetParentNode() ||
!aNode.GetParentNode()->GetParentNode());
MOZ_ASSERT(!aContent.GetParentNode());
return nullptr;
}
@ -2645,12 +2625,35 @@ NS_IMETHODIMP HTMLEditor::GetElementOrParentByTagName(const nsAString& aTagName,
return NS_ERROR_INVALID_ARG;
}
RefPtr<nsAtom> tagName = GetLowerCaseNameAtom(aTagName);
if (NS_WARN_IF(!tagName) || NS_WARN_IF(tagName == nsGkAtoms::_empty)) {
nsStaticAtom* tagName = EditorUtils::GetTagNameAtom(aTagName);
if (NS_WARN_IF(!tagName)) {
// We don't need to support custom elements since this is an internal API.
return NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND;
}
if (NS_WARN_IF(tagName == nsGkAtoms::_empty)) {
return NS_ERROR_INVALID_ARG;
}
RefPtr<Element> parentElement = GetElementOrParentByTagName(*tagName, aNode);
if (!aNode) {
AutoEditActionDataSetter dummyEditAction(*this, EditAction::eNotEditing);
if (NS_WARN_IF(!dummyEditAction.CanHandle())) {
return NS_ERROR_NOT_AVAILABLE;
}
RefPtr<Element> parentElement =
GetInclusiveAncestorByTagNameAtSelection(*tagName);
if (!parentElement) {
return NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND;
}
parentElement.forget(aReturn);
return NS_OK;
}
if (!aNode->IsContent() || !aNode->GetAsElementOrParentElement()) {
return NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND;
}
RefPtr<Element> parentElement =
GetInclusiveAncestorByTagName(*tagName, *aNode->AsContent());
if (!parentElement) {
return NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND;
}
@ -2671,7 +2674,11 @@ NS_IMETHODIMP HTMLEditor::GetSelectedElement(const nsAString& aTagName,
}
ErrorResult error;
RefPtr<nsAtom> tagName = GetLowerCaseNameAtom(aTagName);
nsStaticAtom* tagName = EditorUtils::GetTagNameAtom(aTagName);
if (!aTagName.IsEmpty() && !tagName) {
// We don't need to support custom elements becaus of internal API.
return NS_OK;
}
RefPtr<nsINode> selectedNode = GetSelectedElement(tagName, error);
NS_WARNING_ASSERTION(!error.Failed(),
"HTMLEditor::GetSelectedElement() failed");
@ -2732,18 +2739,19 @@ already_AddRefed<Element> HTMLEditor::GetSelectedElement(const nsAtom* aTagName,
}
}
if (isLinkTag) {
if (isLinkTag && startRef.Container()->IsContent() &&
endRef.Container()->IsContent()) {
// Link node must be the same for both ends of selection.
Element* parentLinkOfStart = GetElementOrParentByTagNameInternal(
*nsGkAtoms::href, *startRef.Container());
Element* parentLinkOfStart = GetInclusiveAncestorByTagNameInternal(
*nsGkAtoms::href, *startRef.Container()->AsContent());
if (parentLinkOfStart) {
if (SelectionRefPtr()->IsCollapsed()) {
// We have just a caret in the link.
return do_AddRef(parentLinkOfStart);
}
// Link node must be the same for both ends of selection.
Element* parentLinkOfEnd = GetElementOrParentByTagNameInternal(
*nsGkAtoms::href, *endRef.Container());
Element* parentLinkOfEnd = GetInclusiveAncestorByTagNameInternal(
*nsGkAtoms::href, *endRef.Container()->AsContent());
if (parentLinkOfStart == parentLinkOfEnd) {
return do_AddRef(parentLinkOfStart);
}
@ -2917,11 +2925,12 @@ NS_IMETHODIMP HTMLEditor::CreateElementWithDefaults(const nsAString& aTagName,
*aReturn = nullptr;
RefPtr<nsAtom> tagName = GetLowerCaseNameAtom(aTagName);
nsStaticAtom* tagName = EditorUtils::GetTagNameAtom(aTagName);
if (NS_WARN_IF(!tagName)) {
return NS_ERROR_INVALID_ARG;
}
RefPtr<Element> newElement = CreateElementWithDefaults(*tagName);
RefPtr<Element> newElement =
CreateElementWithDefaults(MOZ_KnownLive(*tagName));
if (!newElement) {
NS_WARNING("HTMLEditor::CreateElementWithDefaults() failed");
return NS_ERROR_FAILURE;

Просмотреть файл

@ -581,8 +581,8 @@ class HTMLEditor final : public TextEditor,
DoInlineTableEditingAction(const Element& aUIAnonymousElement);
/**
* GetElementOrParentByTagName() looks for an element node whose name matches
* aTagName from aNode or anchor node of Selection to <body> element.
* GetInclusiveAncestorByTagName() looks for an element node whose name
* matches aTagName from aNode or anchor node of Selection to <body> element.
*
* @param aTagName The tag name which you want to look for.
* Must not be nsGkAtoms::_empty.
@ -593,14 +593,12 @@ class HTMLEditor final : public TextEditor,
* which has "href" attribute with non-empty value.
* If nsGkAtoms::anchor, the result may be <a> which
* has "name" attribute with non-empty value.
* @param aNode If non-nullptr, this starts to look for the result
* from it. Otherwise, i.e., nullptr, starts from
* anchor node of Selection.
* @param aContent Start node to look for the result.
* @return If an element which matches aTagName, returns
* an Element. Otherwise, nullptr.
*/
Element* GetElementOrParentByTagName(const nsAtom& aTagName,
nsINode* aNode) const;
Element* GetInclusiveAncestorByTagName(const nsStaticAtom& aTagName,
nsIContent& aContent) const;
/**
* Get an active editor's editing host in DOM window. If this editor isn't
@ -2890,7 +2888,7 @@ class HTMLEditor final : public TextEditor,
CollapseSelectionAfter(Element& aElement);
/**
* GetElementOrParentByTagNameAtSelection() looks for an element node whose
* GetInclusiveAncestorByTagNameAtSelection() looks for an element node whose
* name matches aTagName from anchor node of Selection to <body> element.
*
* @param aTagName The tag name which you want to look for.
@ -2905,10 +2903,11 @@ class HTMLEditor final : public TextEditor,
* @return If an element which matches aTagName, returns
* an Element. Otherwise, nullptr.
*/
Element* GetElementOrParentByTagNameAtSelection(const nsAtom& aTagName) const;
Element* GetInclusiveAncestorByTagNameAtSelection(
const nsStaticAtom& aTagName) const;
/**
* GetElementOrParentByTagNameInternal() looks for an element node whose
* GetInclusiveAncestorByTagNameInternal() looks for an element node whose
* name matches aTagName from aNode to <body> element.
*
* @param aTagName The tag name which you want to look for.
@ -2920,12 +2919,13 @@ class HTMLEditor final : public TextEditor,
* which has "href" attribute with non-empty value.
* If nsGkAtoms::anchor, the result may be <a> which
* has "name" attribute with non-empty value.
* @param aNode Start node to look for the element.
* @param aContent Start node to look for the element. This should
* not be an orphan node.
* @return If an element which matches aTagName, returns
* an Element. Otherwise, nullptr.
*/
Element* GetElementOrParentByTagNameInternal(const nsAtom& aTagName,
nsINode& aNode) const;
Element* GetInclusiveAncestorByTagNameInternal(const nsStaticAtom& aTagName,
nsIContent& aContent) const;
/**
* GetSelectedElement() returns a "selected" element node. "selected" means:
@ -2943,8 +2943,8 @@ class HTMLEditor final : public TextEditor,
* another method for avoiding breakage of comm-central apps.
*
* @param aTagName The atom of tag name in lower case. Set this to
* result of GetLowerCaseNameAtom() if you have a tag
* name with nsString.
* result of EditorUtils::GetTagNameAtom() if you have a
* tag name with nsString.
* If nullptr, this returns any element node or nullptr.
* If nsGkAtoms::href, this returns an <a> element which
* has non-empty "href" attribute or nullptr.

Просмотреть файл

@ -354,8 +354,8 @@ nsresult HTMLEditorEventListener::MouseDown(MouseEvent* aMouseEvent) {
"Selection::Collapse() failed, but ignored");
} else {
// Get enclosing link if in text so we can select the link
Element* linkElement = htmlEditor->GetElementOrParentByTagName(
*nsGkAtoms::href, originalEventTargetContent);
Element* linkElement = htmlEditor->GetInclusiveAncestorByTagName(
*nsGkAtoms::href, *originalEventTargetContent);
if (linkElement) {
element = linkElement;
}

Просмотреть файл

@ -305,12 +305,12 @@ Element* HTMLEditor::GetFirstTableRowElement(Element& aTableOrElementInTable,
ErrorResult& aRv) const {
MOZ_ASSERT(!aRv.Failed());
Element* tableElement = GetElementOrParentByTagNameInternal(
Element* tableElement = GetInclusiveAncestorByTagNameInternal(
*nsGkAtoms::table, aTableOrElementInTable);
// If the element is not in <table>, return error.
if (!tableElement) {
NS_WARNING(
"HTMLEditor::GetElementOrParentByTagNameInternal(nsGkAtoms::table) "
"HTMLEditor::GetInclusiveAncestorByTagNameInternal(nsGkAtoms::table) "
"failed");
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
@ -841,10 +841,10 @@ nsresult HTMLEditor::InsertTableRowsWithTransaction(
return NS_ERROR_FAILURE;
}
Element* parentRow =
GetElementOrParentByTagNameInternal(*nsGkAtoms::tr, *cellForRowParent);
GetInclusiveAncestorByTagNameInternal(*nsGkAtoms::tr, *cellForRowParent);
if (!parentRow) {
NS_WARNING(
"HTMLEditor::GetElementOrParentByTagNameInternal(nsGkAtoms::tr) "
"HTMLEditor::GetInclusiveAncestorByTagNameInternal(nsGkAtoms::tr) "
"failed");
return NS_ERROR_FAILURE;
}
@ -1595,11 +1595,11 @@ nsresult HTMLEditor::DeleteTableColumnWithTransaction(Element& aTableElement,
}
// When the cell is the last cell in the row, remove the row instead.
Element* parentRow =
GetElementOrParentByTagNameInternal(*nsGkAtoms::tr, *cellData.mElement);
Element* parentRow = GetInclusiveAncestorByTagNameInternal(
*nsGkAtoms::tr, *cellData.mElement);
if (!parentRow) {
NS_WARNING(
"HTMLEditor::GetElementOrParentByTagNameInternal(nsGkAtoms::tr) "
"HTMLEditor::GetInclusiveAncestorByTagNameInternal(nsGkAtoms::tr) "
"failed");
return NS_ERROR_FAILURE;
}
@ -1901,12 +1901,12 @@ nsresult HTMLEditor::DeleteTableRowWithTransaction(Element& aTableElement,
// Delete the entire row.
RefPtr<Element> parentRow =
GetElementOrParentByTagNameInternal(*nsGkAtoms::tr, *cellInDeleteRow);
GetInclusiveAncestorByTagNameInternal(*nsGkAtoms::tr, *cellInDeleteRow);
if (parentRow) {
nsresult rv = DeleteNodeWithTransaction(*parentRow);
if (NS_FAILED(rv)) {
NS_WARNING(
"HTMLEditor::GetElementOrParentByTagNameInternal(nsGkAtoms::tr) "
"HTMLEditor::GetInclusiveAncestorByTagNameInternal(nsGkAtoms::tr) "
"failed");
return rv;
}
@ -1933,17 +1933,12 @@ NS_IMETHODIMP HTMLEditor::SelectTable() {
return NS_ERROR_NOT_INITIALIZED;
}
if (IsSelectionRangeContainerNotContent()) {
NS_WARNING("Some selection containers were not content nodes");
return NS_OK; // Don't fail if we didn't find a table.
}
RefPtr<Element> table =
GetElementOrParentByTagNameAtSelection(*nsGkAtoms::table);
GetInclusiveAncestorByTagNameAtSelection(*nsGkAtoms::table);
if (!table) {
NS_WARNING(
"HTMLEditor::GetElementOrParentByTagNameAtSelection(nsGkAtoms::table) "
"failed");
"HTMLEditor::GetInclusiveAncestorByTagNameAtSelection(nsGkAtoms::table)"
" failed");
return NS_OK; // Don't fail if we didn't find a table.
}
@ -1964,16 +1959,11 @@ NS_IMETHODIMP HTMLEditor::SelectTableCell() {
return NS_ERROR_NOT_INITIALIZED;
}
if (IsSelectionRangeContainerNotContent()) {
NS_WARNING("Some selection containers were not content nodes");
// Don't fail if we didn't find a cell.
return NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND;
}
RefPtr<Element> cell = GetElementOrParentByTagNameAtSelection(*nsGkAtoms::td);
RefPtr<Element> cell =
GetInclusiveAncestorByTagNameAtSelection(*nsGkAtoms::td);
if (!cell) {
NS_WARNING(
"HTMLEditor::GetElementOrParentByTagNameAtSelection(nsGkAtoms::td) "
"HTMLEditor::GetInclusiveAncestorByTagNameAtSelection(nsGkAtoms::td) "
"failed");
// Don't fail if we didn't find a cell.
return NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND;
@ -1996,16 +1986,11 @@ NS_IMETHODIMP HTMLEditor::SelectAllTableCells() {
return NS_ERROR_NOT_INITIALIZED;
}
if (IsSelectionRangeContainerNotContent()) {
NS_WARNING("Some selection containers were not content nodes");
// Don't fail if we didn't find a cell.
return NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND;
}
RefPtr<Element> cell = GetElementOrParentByTagNameAtSelection(*nsGkAtoms::td);
RefPtr<Element> cell =
GetInclusiveAncestorByTagNameAtSelection(*nsGkAtoms::td);
if (!cell) {
NS_WARNING(
"HTMLEditor::GetElementOrParentByTagNameAtSelection(nsGkAtoms::td) "
"HTMLEditor::GetInclusiveAncestorByTagNameAtSelection(nsGkAtoms::td) "
"failed");
// Don't fail if we didn't find a cell.
return NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND;
@ -2015,10 +2000,10 @@ NS_IMETHODIMP HTMLEditor::SelectAllTableCells() {
// Get parent table
RefPtr<Element> table =
GetElementOrParentByTagNameInternal(*nsGkAtoms::table, *cell);
GetInclusiveAncestorByTagNameInternal(*nsGkAtoms::table, *cell);
if (!table) {
NS_WARNING(
"HTMLEditor::GetElementOrParentByTagNameAtSelection(nsGkAtoms::table) "
"HTMLEditor::GetInclusiveAncestorByTagNameInternal(nsGkAtoms::table) "
"failed");
return NS_ERROR_FAILURE;
}
@ -2095,16 +2080,11 @@ NS_IMETHODIMP HTMLEditor::SelectTableRow() {
return NS_ERROR_NOT_INITIALIZED;
}
if (IsSelectionRangeContainerNotContent()) {
NS_WARNING("Some selection containers were not content nodes");
// Don't fail if we didn't find a cell.
return NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND;
}
RefPtr<Element> cell = GetElementOrParentByTagNameAtSelection(*nsGkAtoms::td);
RefPtr<Element> cell =
GetInclusiveAncestorByTagNameAtSelection(*nsGkAtoms::td);
if (!cell) {
NS_WARNING(
"HTMLEditor::GetElementOrParentByTagNameAtSelection(nsGkAtoms::td) "
"HTMLEditor::GetInclusiveAncestorByTagNameAtSelection(nsGkAtoms::td) "
"failed");
// Don't fail if we didn't find a cell.
return NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND;
@ -2201,16 +2181,11 @@ NS_IMETHODIMP HTMLEditor::SelectTableColumn() {
return NS_ERROR_NOT_INITIALIZED;
}
if (IsSelectionRangeContainerNotContent()) {
NS_WARNING("Some selection containers were not content nodes");
// Don't fail if we didn't find a cell.
return NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND;
}
RefPtr<Element> cell = GetElementOrParentByTagNameAtSelection(*nsGkAtoms::td);
RefPtr<Element> cell =
GetInclusiveAncestorByTagNameAtSelection(*nsGkAtoms::td);
if (!cell) {
NS_WARNING(
"HTMLEditor::GetElementOrParentByTagNameAtSelection(nsGkAtoms::td) "
"HTMLEditor::GetInclusiveAncestorByTagNameAtSelection(nsGkAtoms::td) "
"failed");
// Don't fail if we didn't find a cell.
return NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND;
@ -3310,17 +3285,12 @@ NS_IMETHODIMP HTMLEditor::NormalizeTable(Element* aTableOrElementInTable) {
}
if (!aTableOrElementInTable) {
if (IsSelectionRangeContainerNotContent()) {
NS_WARNING("Some selection containers were not content nodes");
return NS_OK; // Don't throw error even if the element is not in <table>.
}
aTableOrElementInTable =
GetElementOrParentByTagNameAtSelection(*nsGkAtoms::table);
GetInclusiveAncestorByTagNameAtSelection(*nsGkAtoms::table);
if (!aTableOrElementInTable) {
NS_WARNING(
"HTMLEditor::GetElementOrParentByTagNameAtSelection(nsGkAtoms::table)"
" failed");
"HTMLEditor::GetInclusiveAncestorByTagNameAtSelection(nsGkAtoms::"
"table) failed");
return NS_OK; // Don't throw error even if the element is not in <table>.
}
}
@ -3337,11 +3307,11 @@ nsresult HTMLEditor::NormalizeTableInternal(Element& aTableOrElementInTable) {
if (aTableOrElementInTable.NodeInfo()->NameAtom() == nsGkAtoms::table) {
tableElement = &aTableOrElementInTable;
} else {
tableElement = GetElementOrParentByTagNameInternal(*nsGkAtoms::table,
aTableOrElementInTable);
tableElement = GetInclusiveAncestorByTagNameInternal(
*nsGkAtoms::table, aTableOrElementInTable);
if (!tableElement) {
NS_WARNING(
"HTMLEditor::GetElementOrParentByTagNameInternal(nsGkAtoms::table) "
"HTMLEditor::GetInclusiveAncestorByTagNameInternal(nsGkAtoms::table) "
"failed");
return NS_OK; // Don't throw error even if the element is not in <table>.
}
@ -3479,19 +3449,13 @@ void HTMLEditor::CellIndexes::Update(HTMLEditor& aHTMLEditor,
Selection& aSelection, ErrorResult& aRv) {
MOZ_ASSERT(!aRv.Failed());
if (aHTMLEditor.IsSelectionRangeContainerNotContent()) {
NS_WARNING("Some selection containers were not content nodes");
aRv.Throw(NS_ERROR_FAILURE);
return;
}
// Guarantee the life time of the cell element since Init() will access
// layout methods.
RefPtr<Element> cellElement =
aHTMLEditor.GetElementOrParentByTagNameAtSelection(*nsGkAtoms::td);
aHTMLEditor.GetInclusiveAncestorByTagNameAtSelection(*nsGkAtoms::td);
if (!cellElement) {
NS_WARNING(
"HTMLEditor::GetElementOrParentByTagNameAtSelection(nsGkAtoms::td) "
"HTMLEditor::GetInclusiveAncestorByTagNameAtSelection(nsGkAtoms::td) "
"failed");
aRv.Throw(NS_ERROR_FAILURE);
return;
@ -3583,16 +3547,12 @@ NS_IMETHODIMP HTMLEditor::GetTableSize(Element* aTableOrElementInTable,
Element* tableOrElementInTable = aTableOrElementInTable;
if (!tableOrElementInTable) {
if (IsSelectionRangeContainerNotContent()) {
NS_WARNING("Some selection containers were not content nodes");
return NS_ERROR_FAILURE;
}
tableOrElementInTable =
GetElementOrParentByTagNameAtSelection(*nsGkAtoms::table);
GetInclusiveAncestorByTagNameAtSelection(*nsGkAtoms::table);
if (!tableOrElementInTable) {
NS_WARNING(
"HTMLEditor::GetElementOrParentByTagNameAtSelection(nsGkAtoms::table)"
" failed");
"HTMLEditor::GetInclusiveAncestorByTagNameAtSelection(nsGkAtoms::"
"table) failed");
return NS_ERROR_FAILURE;
}
}
@ -3618,11 +3578,11 @@ void HTMLEditor::TableSize::Update(HTMLEditor& aHTMLEditor,
// <table> element. However, editor developers may not watch layout API
// changes. So, for keeping us safer, we should use RefPtr here.
RefPtr<Element> tableElement =
aHTMLEditor.GetElementOrParentByTagNameInternal(*nsGkAtoms::table,
aTableOrElementInTable);
aHTMLEditor.GetInclusiveAncestorByTagNameInternal(*nsGkAtoms::table,
aTableOrElementInTable);
if (!tableElement) {
NS_WARNING(
"HTMLEditor::GetElementOrParentByTagNameInternal(nsGkAtoms::table) "
"HTMLEditor::GetInclusiveAncestorByTagNameInternal(nsGkAtoms::table) "
"failed");
aRv.Throw(NS_ERROR_FAILURE);
return;
@ -3669,16 +3629,12 @@ NS_IMETHODIMP HTMLEditor::GetCellDataAt(
// them.
RefPtr<Element> table = aTableElement;
if (!table) {
if (IsSelectionRangeContainerNotContent()) {
NS_WARNING("Some selection containers were not content nodes");
return NS_ERROR_FAILURE;
}
// Get the selected table or the table enclosing the selection anchor.
table = GetElementOrParentByTagNameAtSelection(*nsGkAtoms::table);
table = GetInclusiveAncestorByTagNameAtSelection(*nsGkAtoms::table);
if (!table) {
NS_WARNING(
"HTMLEditor::GetElementOrParentByTagNameAtSelection(nsGkAtoms::table)"
" failed");
"HTMLEditor::GetInclusiveAncestorByTagNameAtSelection(nsGkAtoms::"
"table) failed");
return NS_ERROR_FAILURE;
}
}
@ -3762,16 +3718,12 @@ NS_IMETHODIMP HTMLEditor::GetCellAt(Element* aTableElement, int32_t aRowIndex,
Element* tableElement = aTableElement;
if (!tableElement) {
if (IsSelectionRangeContainerNotContent()) {
NS_WARNING("Some selection containers were not content nodes");
return NS_ERROR_FAILURE;
}
// Get the selected table or the table enclosing the selection anchor.
tableElement = GetElementOrParentByTagNameAtSelection(*nsGkAtoms::table);
tableElement = GetInclusiveAncestorByTagNameAtSelection(*nsGkAtoms::table);
if (!tableElement) {
NS_WARNING(
"HTMLEditor::GetElementOrParentByTagNameAtSelection(nsGkAtoms::table)"
" failed");
"HTMLEditor::GetInclusiveAncestorByTagNameAtSelection(nsGkAtoms::"
"table) failed");
return NS_ERROR_FAILURE;
}
}
@ -3882,10 +3834,10 @@ nsresult HTMLEditor::GetCellContext(Element** aTable, Element** aCell,
}
// Get containing table
table = GetElementOrParentByTagNameInternal(*nsGkAtoms::table, *cell);
table = GetInclusiveAncestorByTagNameInternal(*nsGkAtoms::table, *cell);
if (!table) {
NS_WARNING(
"HTMLEditor::GetElementOrParentByTagNameInternal(nsGkAtoms::table) "
"HTMLEditor::GetInclusiveAncestorByTagNameInternal(nsGkAtoms::table) "
"failed");
// Cell must be in a table, so fail if not found
return NS_ERROR_FAILURE;
@ -4376,10 +4328,14 @@ already_AddRefed<Element> HTMLEditor::GetSelectedOrParentTableElement(
}
}
if (NS_WARN_IF(!anchorRef.Container()->IsContent())) {
return nullptr;
}
// Then, look for a cell element (either <td> or <th>) which contains
// the anchor container.
cellElement = GetElementOrParentByTagNameInternal(*nsGkAtoms::td,
*anchorRef.Container());
cellElement = GetInclusiveAncestorByTagNameInternal(
*nsGkAtoms::td, *anchorRef.Container()->AsContent());
if (!cellElement) {
return nullptr; // Not in table.
}
@ -4404,23 +4360,19 @@ NS_IMETHODIMP HTMLEditor::GetSelectedCellsType(Element* aElement,
// (if aElement is null, this uses selection's anchor node)
RefPtr<Element> table;
if (aElement) {
table = GetElementOrParentByTagNameInternal(*nsGkAtoms::table, *aElement);
table = GetInclusiveAncestorByTagNameInternal(*nsGkAtoms::table, *aElement);
if (!table) {
NS_WARNING(
"HTMLEditor::GetElementOrParentByTagNameInternal(nsGkAtoms::table) "
"HTMLEditor::GetInclusiveAncestorByTagNameInternal(nsGkAtoms::table) "
"failed");
return NS_ERROR_FAILURE;
}
} else {
if (IsSelectionRangeContainerNotContent()) {
NS_WARNING("Some selection containers were not content nodes");
return NS_ERROR_FAILURE;
}
table = GetElementOrParentByTagNameAtSelection(*nsGkAtoms::table);
table = GetInclusiveAncestorByTagNameAtSelection(*nsGkAtoms::table);
if (!table) {
NS_WARNING(
"HTMLEditor::GetElementOrParentByTagNameAtSelection(nsGkAtoms::table)"
" failed");
"HTMLEditor::GetInclusiveAncestorByTagNameAtSelection(nsGkAtoms::"
"table) failed");
return NS_ERROR_FAILURE;
}
}

Просмотреть файл

@ -0,0 +1,19 @@
<html>
<head>
<script>
window.addEventListener('load', () => {
const element = document.createElement('t')
document.documentElement.appendChild(element)
document.documentElement.contentEditable = true
const selection = self.getSelection()
const range_1 = new Range()
range_1.setStart(element, (1715865858 % element.childNodes))
document.execCommand('enableObjectResizing', false, true)
const range_2 = new Range()
selection.addRange(range_2)
selection.addRange(range_1)
document.execCommand('bold', false, null)
})
</script>
</head>
</html>

Просмотреть файл

@ -121,4 +121,5 @@ load 1574544.html
load 1596516.html
load 1618906.html
load 1623913.html
load 1624007.html
load 1624011.html

Просмотреть файл

@ -252,6 +252,7 @@ skip-if = os == 'android'
skip-if = headless
[test_nsIEditor_insertLineBreak.html]
[test_nsIEditorMailSupport_insertAsCitedQuotation.html]
[test_nsIHTMLEditor_getElementOrParentByTagName.html]
[test_nsIHTMLEditor_getParagraphState.html]
[test_nsIHTMLEditor_getSelectedElement.html]
[test_nsIHTMLEditor_removeInlineProperty.html]

Просмотреть файл

@ -0,0 +1,449 @@
<!DOCTYPE>
<html>
<head>
<title>Test for nsIHTMLEditor.getElementOrParentByTagName()</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" href="/tests/SimpleTest/test.css">
</head>
<body>
<section>
<div id="display">
</div>
<div id="content" contenteditable></div>
</section>
<pre id="test">
</pre>
<script class="testbody" type="application/javascript">
SimpleTest.waitForExplicitFinish();
SimpleTest.waitForFocus(async function() {
let section = document.querySelector("section");
let editor = document.querySelector("[contenteditable]");
let selection = window.getSelection();
let element;
// Make sure that each test can run without previous tests for making each test
// debuggable with commenting out the unrelated tests.
try {
editor.focus();
element = SpecialPowers.unwrap(getHTMLEditor().getElementOrParentByTagName("", null));
ok(false, "nsIHTMLEditor.getElementOrParentByTagName(\"\", null) should throw an exception");
} catch {
ok(true, "nsIHTMLEditor.getElementOrParentByTagName(\"\", null) should throw an exception");
}
try {
editor.focus();
element = SpecialPowers.unwrap(getHTMLEditor().getElementOrParentByTagName(null, null));
ok(false, "nsIHTMLEditor.getElementOrParentByTagName(null, null) should throw an exception");
} catch {
ok(true, "nsIHTMLEditor.getElementOrParentByTagName(null, null) should throw an exception");
}
try {
editor.focus();
element = SpecialPowers.unwrap(getHTMLEditor().getElementOrParentByTagName(undefined, null));
ok(false, "nsIHTMLEditor.getElementOrParentByTagName(undefined, null) should throw an exception");
} catch {
ok(true, "nsIHTMLEditor.getElementOrParentByTagName(undefined, null) should throw an exception");
}
editor.focus();
element = SpecialPowers.unwrap(getHTMLEditor().getElementOrParentByTagName("undefinedtagname", null));
is(element, null,
"nsIHTMLEditor.getElementOrParentByTagName(\"undefinedtagname\", null) should return null");
editor.blur();
selection.collapse(document.getElementById("display"), 0);
element = SpecialPowers.unwrap(getHTMLEditor().getElementOrParentByTagName("section", null));
is(element, section,
"nsIHTMLEditor.getElementOrParentByTagName(\"section\", null) should return the <section> when selection is in the it (HTML editor does not have focus)");
editor.focus();
element = SpecialPowers.unwrap(getHTMLEditor().getElementOrParentByTagName("section", null));
is(element, section,
"nsIHTMLEditor.getElementOrParentByTagName(\"section\", null) should return the <section> when selection is in the it (HTML editor has focus)");
editor.focus();
selection.removeAllRanges();
element = SpecialPowers.unwrap(getHTMLEditor().getElementOrParentByTagName("section", null));
is(element, null,
"nsIHTMLEditor.getElementOrParentByTagName(\"section\", null) should return null when there is no selection");
editor.blur();
selection.collapse(document.getElementById("display"), 0);
element = SpecialPowers.unwrap(getHTMLEditor().getElementOrParentByTagName("body", null));
is(element, null,
"nsIHTMLEditor.getElementOrParentByTagName(\"body\", null) should return null when it reaches the <body>");
editor.blur();
selection.collapse(document.getElementById("display"), 0);
element = SpecialPowers.unwrap(getHTMLEditor().getElementOrParentByTagName("div", editor));
is(element, editor,
"nsIHTMLEditor.getElementOrParentByTagName(\"div\", editor) should return editor even when selection is outside of it");
editor.innerHTML = "<p>first</p><p>second</p>";
editor.focus();
selection.setBaseAndExtent(editor.firstChild.firstChild, 0, editor.firstChild.nextSibling.firstChild, 3);
element = SpecialPowers.unwrap(getHTMLEditor().getElementOrParentByTagName("p", null));
is(element, editor.firstChild,
"nsIHTMLEditor.getElementOrParentByTagName(\"p\", null) should return first <p> element when selection anchor is in it");
editor.innerHTML = "<table><tr><td>cell</td></tr></table>";
editor.focus();
selection.collapse(editor.querySelector("td").firstChild, 2);
element = SpecialPowers.unwrap(getHTMLEditor().getElementOrParentByTagName("td", null));
is(element, editor.querySelector("td"),
"nsIHTMLEditor.getElementOrParentByTagName(\"td\", null) should return the <td> when selection is collapsed in it");
editor.innerHTML = "<table><tr><td>cell</td></tr></table>";
editor.focus();
selection.collapse(editor.querySelector("td").firstChild, 2);
element = SpecialPowers.unwrap(getHTMLEditor().getElementOrParentByTagName("th", null));
is(element, null,
"nsIHTMLEditor.getElementOrParentByTagName(\"th\", null) should return null when selection is collapsed in <td>");
editor.innerHTML = "<table><tr><td>cell</td></tr></table>";
editor.focus();
selection.setBaseAndExtent(editor.querySelector("tr"), 0, editor.querySelector("tr"), 1);
element = SpecialPowers.unwrap(getHTMLEditor().getElementOrParentByTagName("td", null));
is(element, editor.querySelector("td"),
"nsIHTMLEditor.getElementOrParentByTagName(\"td\", null) should return the <td> when it's selected");
editor.innerHTML = "<table><tr><th>cell</th></tr></table>";
editor.focus();
selection.collapse(editor.querySelector("th").firstChild, 2);
element = SpecialPowers.unwrap(getHTMLEditor().getElementOrParentByTagName("td", null));
is(element, editor.querySelector("th"),
"nsIHTMLEditor.getElementOrParentByTagName(\"td\", null) should return the <th> when selection is collapsed in it");
editor.innerHTML = "<table><tr><th>cell</th></tr></table>";
editor.focus();
selection.collapse(editor.querySelector("th").firstChild, 2);
element = SpecialPowers.unwrap(getHTMLEditor().getElementOrParentByTagName("th", null));
is(element, editor.querySelector("th"),
"nsIHTMLEditor.getElementOrParentByTagName(\"th\", null) should return the <th> when selection is collapsed in it");
editor.innerHTML = "<table><tr><th>cell</th></tr></table>";
editor.focus();
selection.setBaseAndExtent(editor.querySelector("tr"), 0, editor.querySelector("tr"), 1);
element = SpecialPowers.unwrap(getHTMLEditor().getElementOrParentByTagName("td", null));
is(element, editor.querySelector("th"),
"nsIHTMLEditor.getElementOrParentByTagName(\"td\", null) should return the <th> when it's selected");
editor.innerHTML = "<table><tr><th>cell</th></tr></table>";
editor.focus();
selection.setBaseAndExtent(editor.querySelector("tr"), 0, editor.querySelector("tr"), 1);
element = SpecialPowers.unwrap(getHTMLEditor().getElementOrParentByTagName("th", null));
is(element, editor.querySelector("th"),
"nsIHTMLEditor.getElementOrParentByTagName(\"th\", null) should return the <th> when it's selected");
editor.innerHTML = "<ul><li>listitem</li></ul>";
editor.focus();
selection.collapse(editor.querySelector("li").firstChild, 4);
element = SpecialPowers.unwrap(getHTMLEditor().getElementOrParentByTagName("ul", null));
is(element, editor.querySelector("ul"),
"nsIHTMLEditor.getElementOrParentByTagName(\"ul\", null) should return the <ul> when selection is collapsed in its <li>");
editor.innerHTML = "<ul><li>listitem</li></ul>";
editor.focus();
selection.collapse(editor.querySelector("li").firstChild, 4);
element = SpecialPowers.unwrap(getHTMLEditor().getElementOrParentByTagName("list", null));
is(element, editor.querySelector("ul"),
"nsIHTMLEditor.getElementOrParentByTagName(\"list\", null) should return the <ul> when selection is collapsed in its <li>");
editor.innerHTML = "<ul><li>listitem</li></ul>";
editor.focus();
selection.collapse(editor.querySelector("li").firstChild, 4);
element = SpecialPowers.unwrap(getHTMLEditor().getElementOrParentByTagName("ol", null));
is(element, null,
"nsIHTMLEditor.getElementOrParentByTagName(\"ol\", null) should return null when selection is collapsed in <ul>");
editor.innerHTML = "<ol><li>listitem</li></ol>";
editor.focus();
selection.collapse(editor.querySelector("li").firstChild, 4);
element = SpecialPowers.unwrap(getHTMLEditor().getElementOrParentByTagName("ol", null));
is(element, editor.querySelector("ol"),
"nsIHTMLEditor.getElementOrParentByTagName(\"ol\", null) should return the <ol> when selection is collapsed in its <li>");
editor.innerHTML = "<ol><li>listitem</li></ol>";
editor.focus();
selection.collapse(editor.querySelector("li").firstChild, 4);
element = SpecialPowers.unwrap(getHTMLEditor().getElementOrParentByTagName("list", null));
is(element, editor.querySelector("ol"),
"nsIHTMLEditor.getElementOrParentByTagName(\"list\", null) should return the <ol> when selection is collapsed in its <li>");
editor.innerHTML = "<ol><li>listitem</li></ol>";
editor.focus();
selection.collapse(editor.querySelector("li").firstChild, 4);
element = SpecialPowers.unwrap(getHTMLEditor().getElementOrParentByTagName("ul", null));
is(element, null,
"nsIHTMLEditor.getElementOrParentByTagName(\"ol\", null) should return null when selection is collapsed in <ol>");
editor.innerHTML = "<dl><dt>listitem</dt></dl>";
editor.focus();
selection.collapse(editor.querySelector("dt").firstChild, 4);
element = SpecialPowers.unwrap(getHTMLEditor().getElementOrParentByTagName("dl", null));
is(element, editor.querySelector("dl"),
"nsIHTMLEditor.getElementOrParentByTagName(\"dl\", null) should return the <dl> when selection is collapsed in its <dt>");
editor.innerHTML = "<dl><dt>listitem</dt></dl>";
editor.focus();
selection.collapse(editor.querySelector("dt").firstChild, 4);
element = SpecialPowers.unwrap(getHTMLEditor().getElementOrParentByTagName("list", null));
is(element, editor.querySelector("dl"),
"nsIHTMLEditor.getElementOrParentByTagName(\"list\", null) should return the <dl> when selection is collapsed in its <dt>");
editor.innerHTML = "<dl><dd>listitem</dd></dl>";
editor.focus();
selection.collapse(editor.querySelector("dd").firstChild, 4);
element = SpecialPowers.unwrap(getHTMLEditor().getElementOrParentByTagName("dl", null));
is(element, editor.querySelector("dl"),
"nsIHTMLEditor.getElementOrParentByTagName(\"dl\", null) should return the <dl> when selection is collapsed in its <dd>");
editor.innerHTML = "<dl><dd>listitem</dd></dl>";
editor.focus();
selection.collapse(editor.querySelector("dd").firstChild, 4);
element = SpecialPowers.unwrap(getHTMLEditor().getElementOrParentByTagName("list", null));
is(element, editor.querySelector("dl"),
"nsIHTMLEditor.getElementOrParentByTagName(\"list\", null) should return the <dl> when selection is collapsed in its <dd>");
editor.innerHTML = "<ul><ol><li>listitem</li></ol></ul>";
editor.focus();
selection.collapse(editor.querySelector("li").firstChild, 4);
element = SpecialPowers.unwrap(getHTMLEditor().getElementOrParentByTagName("list", null));
is(element, editor.querySelector("ol"),
"nsIHTMLEditor.getElementOrParentByTagName(\"list\", null) should return the <ol> (sublist) when selection is collapsed in its <li>");
editor.innerHTML = "<ul><ol><li>listitem</li></ol></ul>";
editor.focus();
selection.collapse(editor.querySelector("li").firstChild, 4);
element = SpecialPowers.unwrap(getHTMLEditor().getElementOrParentByTagName("ol", null));
is(element, editor.querySelector("ol"),
"nsIHTMLEditor.getElementOrParentByTagName(\"ol\", null) should return the <ol> (sublist) when selection is collapsed in its <li>");
editor.innerHTML = "<ul><ol><li>listitem</li></ol></ul>";
editor.focus();
selection.collapse(editor.querySelector("li").firstChild, 4);
element = SpecialPowers.unwrap(getHTMLEditor().getElementOrParentByTagName("ul", null));
is(element, editor.querySelector("ul"),
"nsIHTMLEditor.getElementOrParentByTagName(\"ul\", null) should return the <ul> when selection is collapsed in its sublist's <li>");
editor.innerHTML = "<ol><ul><li>listitem</li></ul></ol>";
editor.focus();
selection.collapse(editor.querySelector("li").firstChild, 4);
element = SpecialPowers.unwrap(getHTMLEditor().getElementOrParentByTagName("list", null));
is(element, editor.querySelector("ul"),
"nsIHTMLEditor.getElementOrParentByTagName(\"list\", null) should return the <ul> (sublist) when selection is collapsed in its <li>");
editor.innerHTML = "<ol><ul><li>listitem</li></ul></ol>";
editor.focus();
selection.collapse(editor.querySelector("li").firstChild, 4);
element = SpecialPowers.unwrap(getHTMLEditor().getElementOrParentByTagName("ul", null));
is(element, editor.querySelector("ul"),
"nsIHTMLEditor.getElementOrParentByTagName(\"ul\", null) should return the <ul> (sublist) when selection is collapsed in its <li>");
editor.innerHTML = "<ol><ul><li>listitem</li></ul></ol>";
editor.focus();
selection.collapse(editor.querySelector("li").firstChild, 4);
element = SpecialPowers.unwrap(getHTMLEditor().getElementOrParentByTagName("ol", null));
is(element, editor.querySelector("ol"),
"nsIHTMLEditor.getElementOrParentByTagName(\"ol\", null) should return the <ol> when selection is collapsed in its sublist's <li>");
editor.innerHTML = "<p><a href=\"about:config\">anchor</a></p>";
editor.focus();
selection.collapse(editor.querySelector("a").firstChild, 3);
element = SpecialPowers.unwrap(getHTMLEditor().getElementOrParentByTagName("a", null));
is(element, editor.querySelector("a"),
"nsIHTMLEditor.getElementOrParentByTagName(\"a\", null) should return the <a href=\"about:config\"> when selection is collapsed in it");
editor.innerHTML = "<p><a href=\"about:config\">anchor</a></p>";
editor.focus();
selection.setBaseAndExtent(editor.firstChild, 0, editor.firstChild, 1);
element = SpecialPowers.unwrap(getHTMLEditor().getElementOrParentByTagName("a", null));
is(element, editor.querySelector("a"),
"nsIHTMLEditor.getElementOrParentByTagName(\"a\", null) should return the <a href=\"about:config\"> when it's selected");
editor.innerHTML = "<p><a href=\"about:config\">anchor</a></p>";
editor.focus();
selection.collapse(editor.querySelector("a").firstChild, 3);
element = SpecialPowers.unwrap(getHTMLEditor().getElementOrParentByTagName("href", null));
is(element, editor.querySelector("a"),
"nsIHTMLEditor.getElementOrParentByTagName(\"href\", null) should return the <a href=\"about:config\"> when selection is collapsed in it");
editor.innerHTML = "<p><a href=\"about:config\">anchor</a></p>";
editor.focus();
selection.setBaseAndExtent(editor.firstChild, 0, editor.firstChild, 1);
element = SpecialPowers.unwrap(getHTMLEditor().getElementOrParentByTagName("href", null));
is(element, editor.querySelector("a"),
"nsIHTMLEditor.getElementOrParentByTagName(\"href\", null) should return the <a href=\"about:config\"> when it's selected");
editor.innerHTML = "<p><a href=\"about:config\">anchor</a></p>";
editor.focus();
selection.collapse(editor.querySelector("a").firstChild, 3);
element = SpecialPowers.unwrap(getHTMLEditor().getElementOrParentByTagName("anchor", null));
is(element, null,
"nsIHTMLEditor.getElementOrParentByTagName(\"anchor\", null) should return null when selection is collapsed in the <a href=\"about:config\">");
editor.innerHTML = "<p><a href=\"about:config\">anchor</a></p>";
editor.focus();
selection.setBaseAndExtent(editor.firstChild, 0, editor.firstChild, 1);
element = SpecialPowers.unwrap(getHTMLEditor().getElementOrParentByTagName("anchor", null));
is(element, null,
"nsIHTMLEditor.getElementOrParentByTagName(\"anchor\", null) should return null when the <a href=\"about:config\"> is selected");
editor.innerHTML = "<p><a href=\"\">anchor</a></p>";
editor.focus();
selection.collapse(editor.querySelector("a").firstChild, 3);
element = SpecialPowers.unwrap(getHTMLEditor().getElementOrParentByTagName("a", null));
is(element, editor.querySelector("a"),
"nsIHTMLEditor.getElementOrParentByTagName(\"a\", null) should return the <a href=\"\"> when selection is collapsed in it");
editor.innerHTML = "<p><a href=\"\">anchor</a></p>";
editor.focus();
selection.setBaseAndExtent(editor.firstChild, 0, editor.firstChild, 1);
element = SpecialPowers.unwrap(getHTMLEditor().getElementOrParentByTagName("a", null));
is(element, editor.querySelector("a"),
"nsIHTMLEditor.getElementOrParentByTagName(\"a\", null) should return the <a href=\"\"> when it's selected");
editor.innerHTML = "<p><a href=\"\">anchor</a></p>";
editor.focus();
selection.collapse(editor.querySelector("a").firstChild, 3);
element = SpecialPowers.unwrap(getHTMLEditor().getElementOrParentByTagName("href", null));
is(element, editor.querySelector("a"),
"nsIHTMLEditor.getElementOrParentByTagName(\"href\", null) should return the <a href=\"\"> when selection is collapsed in it");
editor.innerHTML = "<p><a href=\"\">anchor</a></p>";
editor.focus();
selection.setBaseAndExtent(editor.firstChild, 0, editor.firstChild, 1);
element = SpecialPowers.unwrap(getHTMLEditor().getElementOrParentByTagName("href", null));
is(element, editor.querySelector("a"),
"nsIHTMLEditor.getElementOrParentByTagName(\"href\", null) should return the <a href=\"\"> when it's selected");
editor.innerHTML = "<p><a name=\"foo\">anchor</a></p>";
editor.focus();
selection.collapse(editor.querySelector("a").firstChild, 3);
element = SpecialPowers.unwrap(getHTMLEditor().getElementOrParentByTagName("a", null));
is(element, editor.querySelector("a"),
"nsIHTMLEditor.getElementOrParentByTagName(\"a\", null) should return the <a name=\"foo\"> when selection is collapsed in it");
editor.innerHTML = "<p><a name=\"foo\">anchor</a></p>";
editor.focus();
selection.setBaseAndExtent(editor.firstChild, 0, editor.firstChild, 1);
element = SpecialPowers.unwrap(getHTMLEditor().getElementOrParentByTagName("a", null));
is(element, editor.querySelector("a"),
"nsIHTMLEditor.getElementOrParentByTagName(\"a\", null) should return the <a name=\"foo\"> when it's selected");
editor.innerHTML = "<p><a name=\"foo\">anchor</a></p>";
editor.focus();
selection.collapse(editor.querySelector("a").firstChild, 3);
element = SpecialPowers.unwrap(getHTMLEditor().getElementOrParentByTagName("href", null));
is(element, null,
"nsIHTMLEditor.getElementOrParentByTagName(\"href\", null) should return null when selection is collapsed in the <a name=\"foo\">");
editor.innerHTML = "<p><a name=\"foo\">anchor</a></p>";
editor.focus();
selection.setBaseAndExtent(editor.firstChild, 0, editor.firstChild, 1);
element = SpecialPowers.unwrap(getHTMLEditor().getElementOrParentByTagName("href", null));
is(element, null,
"nsIHTMLEditor.getElementOrParentByTagName(\"href\", null) should return null when the <a name=\"foo\"> is selected");
editor.innerHTML = "<p><a name=\"foo\">anchor</a></p>";
editor.focus();
selection.collapse(editor.querySelector("a").firstChild, 3);
element = SpecialPowers.unwrap(getHTMLEditor().getElementOrParentByTagName("anchor", null));
is(element, editor.querySelector("a"),
"nsIHTMLEditor.getElementOrParentByTagName(\"anchor\", null) should return the <a name=\"foo\"> when selection is collapsed in it");
editor.innerHTML = "<p><a name=\"foo\">anchor</a></p>";
editor.focus();
selection.setBaseAndExtent(editor.firstChild, 0, editor.firstChild, 1);
element = SpecialPowers.unwrap(getHTMLEditor().getElementOrParentByTagName("anchor", null));
is(element, editor.querySelector("a"),
"nsIHTMLEditor.getElementOrParentByTagName(\"anchor\", null) should return the <a name=\"foo\"> when it's selected");
editor.innerHTML = "<p><a name=\"\">anchor</a></p>";
editor.focus();
selection.collapse(editor.querySelector("a").firstChild, 3);
element = SpecialPowers.unwrap(getHTMLEditor().getElementOrParentByTagName("a", null));
is(element, editor.querySelector("a"),
"nsIHTMLEditor.getElementOrParentByTagName(\"a\", null) should return the <a name=\"\"> when selection is collapsed in it");
editor.innerHTML = "<p><a name=\"\">anchor</a></p>";
editor.focus();
selection.setBaseAndExtent(editor.firstChild, 0, editor.firstChild, 1);
element = SpecialPowers.unwrap(getHTMLEditor().getElementOrParentByTagName("a", null));
is(element, editor.querySelector("a"),
"nsIHTMLEditor.getElementOrParentByTagName(\"a\", null) should return the <a name=\"\"> when it's selected");
editor.innerHTML = "<p><a name=\"\">anchor</a></p>";
editor.focus();
selection.collapse(editor.querySelector("a").firstChild, 3);
element = SpecialPowers.unwrap(getHTMLEditor().getElementOrParentByTagName("anchor", null));
is(element, null,
"nsIHTMLEditor.getElementOrParentByTagName(\"anchor\", null) should return null when selection is collapsed in the <a name=\"\">");
editor.innerHTML = "<p><a name=\"\">anchor</a></p>";
editor.focus();
selection.setBaseAndExtent(editor.firstChild, 0, editor.firstChild, 1);
element = SpecialPowers.unwrap(getHTMLEditor().getElementOrParentByTagName("anchor", null));
is(element, null,
"nsIHTMLEditor.getElementOrParentByTagName(\"anchor\", null) should return null when the <a name=\"\"> is selected");
editor.innerHTML = "<p><a>anchor</a></p>";
editor.focus();
selection.collapse(editor.querySelector("a").firstChild, 3);
element = SpecialPowers.unwrap(getHTMLEditor().getElementOrParentByTagName("a", null));
is(element, editor.querySelector("a"),
"nsIHTMLEditor.getElementOrParentByTagName(\"a\", null) should return the <a> when selection is collapsed in it");
editor.innerHTML = "<p><a>anchor</a></p>";
editor.focus();
selection.collapse(editor.querySelector("a").firstChild, 3);
element = SpecialPowers.unwrap(getHTMLEditor().getElementOrParentByTagName("href", null));
is(element, null,
"nsIHTMLEditor.getElementOrParentByTagName(\"href\", null) should return null when selection is collapsed in the <a>");
editor.innerHTML = "<p><a>anchor</a></p>";
editor.focus();
selection.collapse(editor.querySelector("a").firstChild, 3);
element = SpecialPowers.unwrap(getHTMLEditor().getElementOrParentByTagName("anchor", null));
is(element, null,
"nsIHTMLEditor.getElementOrParentByTagName(\"anchor\", null) should return null when selection is collapsed in the <a>");
editor.innerHTML = "<p><a>anchor</a></p>";
editor.focus();
selection.setBaseAndExtent(editor.firstChild, 0, editor.firstChild, 1);
element = SpecialPowers.unwrap(getHTMLEditor().getElementOrParentByTagName("a", null));
is(element, editor.querySelector("a"),
"nsIHTMLEditor.getElementOrParentByTagName(\"a\", null) should return the <a> when it's selected");
editor.innerHTML = "<p><a>anchor</a></p>";
editor.focus();
selection.setBaseAndExtent(editor.firstChild, 0, editor.firstChild, 1);
element = SpecialPowers.unwrap(getHTMLEditor().getElementOrParentByTagName("href", null));
is(element, null,
"nsIHTMLEditor.getElementOrParentByTagName(\"href\", null) should return null when the <a> is selected");
editor.innerHTML = "<p><a>anchor</a></p>";
editor.focus();
selection.setBaseAndExtent(editor.firstChild, 0, editor.firstChild, 1);
element = SpecialPowers.unwrap(getHTMLEditor().getElementOrParentByTagName("anchor", null));
is(element, null,
"nsIHTMLEditor.getElementOrParentByTagName(\"anchor\", null) should return the <a> is selected");
SimpleTest.finish();
});
function getHTMLEditor() {
var Ci = SpecialPowers.Ci;
var editingSession = SpecialPowers.wrap(window).docShell.editingSession;
return editingSession.getEditorForWindow(window).QueryInterface(Ci.nsIHTMLEditor);
}
</script>
</body>
</html>

Просмотреть файл

@ -262,8 +262,9 @@ interface nsIHTMLEditor : nsISupports
void removeList(in AString aListType);
/**
* GetElementOrParentByTagName() looks for an element node whose name matches
* aTagName from aNode or anchor node of Selection to <body> element.
* GetElementOrParentByTagName() returns an inclusive ancestor element whose
* name matches aTagName from aNode or anchor node of Selection to <body>
* element or null if there is no element matching with aTagName.
*
* @param aTagName The tag name which you want to look for.
* Must not be empty string.