зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
581f34a57e
Коммит
39b3ec6675
|
@ -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.
|
||||
|
|
Загрузка…
Ссылка в новой задаче