зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1627175 - part 2: Move `EditorBase::IsModifiableNode()`, `EditorBase::IsEditable()`, `EditorBase::IsTextElementOrText()` and `EditorBase::IsPaddingBRElementForEmptyEditor()` to `EditorUtils` r=m_kato
Due to the include hell, `EditorBase.h` cannot include `EditorUtils.h`. Therefore we need these 3 methods once. Additionally, `IsModifiableNode()` is really odd method and looks like that it's used for the following 2 purposes: 1. Simply can be editable. 2. Can be removed from parent. For the former case, we should sort out it with `EditorUtils::IsEditableContent()`, but for now, this patch moves it to `HTMLEditUtils::IsSimplyEditable()`. On the other hand, for the latter case, we obviously has a bug. Therefore, this patch creates `HTMLEditUtils::IsRemovableFromParentNode()` and make it check whether the removing node is also editable. Unfortunately, `EditorUtils::IsEditableContent()` needs to take editor type. But it's most callers are in `HTMLEditor` and most of remains are in common methods of `EditorBase`. I guess we could remove this ugly argument in the future. Depends on D70874 Differential Revision: https://phabricator.services.mozilla.com/D70875 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
72d50388f6
Коммит
4cc133b568
|
@ -4,6 +4,8 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
#include "DeleteNodeTransaction.h"
|
#include "DeleteNodeTransaction.h"
|
||||||
|
|
||||||
|
#include "HTMLEditUtils.h"
|
||||||
#include "mozilla/EditorBase.h"
|
#include "mozilla/EditorBase.h"
|
||||||
#include "mozilla/SelectionState.h" // RangeUpdater
|
#include "mozilla/SelectionState.h" // RangeUpdater
|
||||||
#include "nsDebug.h"
|
#include "nsDebug.h"
|
||||||
|
@ -40,10 +42,11 @@ NS_INTERFACE_MAP_END_INHERITING(EditTransactionBase)
|
||||||
|
|
||||||
bool DeleteNodeTransaction::CanDoIt() const {
|
bool DeleteNodeTransaction::CanDoIt() const {
|
||||||
if (NS_WARN_IF(!mContentToDelete) || NS_WARN_IF(!mEditorBase) ||
|
if (NS_WARN_IF(!mContentToDelete) || NS_WARN_IF(!mEditorBase) ||
|
||||||
!mParentNode || !mEditorBase->IsModifiableNode(*mParentNode)) {
|
!mParentNode) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return mEditorBase->IsTextEditor() ||
|
||||||
|
HTMLEditUtils::IsSimplyEditableNode(*mParentNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP DeleteNodeTransaction::DoTransaction() {
|
NS_IMETHODIMP DeleteNodeTransaction::DoTransaction() {
|
||||||
|
@ -51,7 +54,7 @@ NS_IMETHODIMP DeleteNodeTransaction::DoTransaction() {
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mEditorBase->AsHTMLEditor() && mContentToDelete->IsText()) {
|
if (mEditorBase->IsTextEditor() && mContentToDelete->IsText()) {
|
||||||
uint32_t length = mContentToDelete->AsText()->TextLength();
|
uint32_t length = mContentToDelete->AsText()->TextLength();
|
||||||
if (length > 0) {
|
if (length > 0) {
|
||||||
mEditorBase->AsTextEditor()->WillDeleteText(length, 0, length);
|
mEditorBase->AsTextEditor()->WillDeleteText(length, 0, length);
|
||||||
|
@ -93,7 +96,7 @@ DeleteNodeTransaction::UndoTransaction() {
|
||||||
NS_WARNING("nsINode::InsertBefore() failed");
|
NS_WARNING("nsINode::InsertBefore() failed");
|
||||||
return error.StealNSResult();
|
return error.StealNSResult();
|
||||||
}
|
}
|
||||||
if (!editorBase->AsHTMLEditor() && contentToDelete->IsText()) {
|
if (editorBase->IsTextEditor() && contentToDelete->IsText()) {
|
||||||
uint32_t length = contentToDelete->AsText()->TextLength();
|
uint32_t length = contentToDelete->AsText()->TextLength();
|
||||||
if (length > 0) {
|
if (length > 0) {
|
||||||
nsresult rv = MOZ_KnownLive(editorBase->AsTextEditor())
|
nsresult rv = MOZ_KnownLive(editorBase->AsTextEditor())
|
||||||
|
@ -113,7 +116,7 @@ NS_IMETHODIMP DeleteNodeTransaction::RedoTransaction() {
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mEditorBase->AsHTMLEditor() && mContentToDelete->IsText()) {
|
if (mEditorBase->IsTextEditor() && mContentToDelete->IsText()) {
|
||||||
uint32_t length = mContentToDelete->AsText()->TextLength();
|
uint32_t length = mContentToDelete->AsText()->TextLength();
|
||||||
if (length > 0) {
|
if (length > 0) {
|
||||||
mEditorBase->AsTextEditor()->WillDeleteText(length, 0, length);
|
mEditorBase->AsTextEditor()->WillDeleteText(length, 0, length);
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
#include "DeleteTextTransaction.h"
|
#include "DeleteTextTransaction.h"
|
||||||
|
|
||||||
|
#include "HTMLEditUtils.h"
|
||||||
#include "mozilla/Assertions.h"
|
#include "mozilla/Assertions.h"
|
||||||
#include "mozilla/EditorBase.h"
|
#include "mozilla/EditorBase.h"
|
||||||
#include "mozilla/EditorDOMPoint.h"
|
#include "mozilla/EditorDOMPoint.h"
|
||||||
|
@ -94,7 +95,8 @@ bool DeleteTextTransaction::CanDoIt() const {
|
||||||
if (NS_WARN_IF(!mTextNode) || NS_WARN_IF(!mEditorBase)) {
|
if (NS_WARN_IF(!mTextNode) || NS_WARN_IF(!mEditorBase)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return mEditorBase->IsModifiableNode(*mTextNode);
|
return mEditorBase->IsTextEditor() ||
|
||||||
|
HTMLEditUtils::IsSimplyEditableNode(*mTextNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP DeleteTextTransaction::DoTransaction() {
|
NS_IMETHODIMP DeleteTextTransaction::DoTransaction() {
|
||||||
|
|
|
@ -639,11 +639,13 @@ bool EditorBase::IsSelectionEditable() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mIsHTMLEditorClass) {
|
if (IsTextEditor()) {
|
||||||
// XXX we just check that the anchor node is editable at the moment
|
// XXX we just check that the anchor node is editable at the moment
|
||||||
// we should check that all nodes in the selection are editable
|
// we should check that all nodes in the selection are editable
|
||||||
nsCOMPtr<nsINode> anchorNode = SelectionRefPtr()->GetAnchorNode();
|
nsCOMPtr<nsINode> anchorNode = SelectionRefPtr()->GetAnchorNode();
|
||||||
return anchorNode && IsEditable(anchorNode);
|
return anchorNode && anchorNode->IsContent() &&
|
||||||
|
EditorUtils::IsEditableContent(*anchorNode->AsContent(),
|
||||||
|
GetEditorType());
|
||||||
}
|
}
|
||||||
|
|
||||||
nsINode* anchorNode = SelectionRefPtr()->GetAnchorNode();
|
nsINode* anchorNode = SelectionRefPtr()->GetAnchorNode();
|
||||||
|
@ -1788,7 +1790,7 @@ nsresult EditorBase::JoinNodesWithTransaction(nsINode& aLeftNode,
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP EditorBase::DeleteNode(nsINode* aNode) {
|
NS_IMETHODIMP EditorBase::DeleteNode(nsINode* aNode) {
|
||||||
if (NS_WARN_IF(!aNode)) {
|
if (NS_WARN_IF(!aNode) || NS_WARN_IF(!aNode->IsContent())) {
|
||||||
return NS_ERROR_INVALID_ARG;
|
return NS_ERROR_INVALID_ARG;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1800,15 +1802,14 @@ NS_IMETHODIMP EditorBase::DeleteNode(nsINode* aNode) {
|
||||||
return EditorBase::ToGenericNSResult(rv);
|
return EditorBase::ToGenericNSResult(rv);
|
||||||
}
|
}
|
||||||
|
|
||||||
rv = DeleteNodeWithTransaction(*aNode);
|
rv = DeleteNodeWithTransaction(MOZ_KnownLive(*aNode->AsContent()));
|
||||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
|
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
|
||||||
"EditorBase::DeleteNodeWithTransaction() failed");
|
"EditorBase::DeleteNodeWithTransaction() failed");
|
||||||
return EditorBase::ToGenericNSResult(rv);
|
return EditorBase::ToGenericNSResult(rv);
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult EditorBase::DeleteNodeWithTransaction(nsINode& aNode) {
|
nsresult EditorBase::DeleteNodeWithTransaction(nsIContent& aContent) {
|
||||||
MOZ_ASSERT(IsEditActionDataAvailable());
|
MOZ_ASSERT(IsEditActionDataAvailable());
|
||||||
MOZ_ASSERT(aNode.IsContent());
|
|
||||||
|
|
||||||
IgnoredErrorResult ignoredError;
|
IgnoredErrorResult ignoredError;
|
||||||
AutoEditSubActionNotifier startToHandleEditSubAction(
|
AutoEditSubActionNotifier startToHandleEditSubAction(
|
||||||
|
@ -1821,13 +1822,13 @@ nsresult EditorBase::DeleteNodeWithTransaction(nsINode& aNode) {
|
||||||
"TextEditor::OnStartToHandleTopLevelEditSubAction() failed, but ignored");
|
"TextEditor::OnStartToHandleTopLevelEditSubAction() failed, but ignored");
|
||||||
|
|
||||||
if (AsHTMLEditor()) {
|
if (AsHTMLEditor()) {
|
||||||
TopLevelEditSubActionDataRef().WillDeleteContent(*this, *aNode.AsContent());
|
TopLevelEditSubActionDataRef().WillDeleteContent(*this, aContent);
|
||||||
}
|
}
|
||||||
|
|
||||||
// FYI: DeleteNodeTransaction grabs aNode while it's alive. So, it's safe
|
// FYI: DeleteNodeTransaction grabs aContent while it's alive. So, it's safe
|
||||||
// to refer aNode even after calling DoTransaction().
|
// to refer aContent even after calling DoTransaction().
|
||||||
RefPtr<DeleteNodeTransaction> deleteNodeTransaction =
|
RefPtr<DeleteNodeTransaction> deleteNodeTransaction =
|
||||||
DeleteNodeTransaction::MaybeCreate(*this, *aNode.AsContent());
|
DeleteNodeTransaction::MaybeCreate(*this, aContent);
|
||||||
NS_WARNING_ASSERTION(deleteNodeTransaction,
|
NS_WARNING_ASSERTION(deleteNodeTransaction,
|
||||||
"DeleteNodeTransaction::MaybeCreate() failed");
|
"DeleteNodeTransaction::MaybeCreate() failed");
|
||||||
nsresult rv;
|
nsresult rv;
|
||||||
|
@ -1838,7 +1839,7 @@ nsresult EditorBase::DeleteNodeWithTransaction(nsINode& aNode) {
|
||||||
|
|
||||||
if (mTextServicesDocument && NS_SUCCEEDED(rv)) {
|
if (mTextServicesDocument && NS_SUCCEEDED(rv)) {
|
||||||
RefPtr<TextServicesDocument> textServicesDocument = mTextServicesDocument;
|
RefPtr<TextServicesDocument> textServicesDocument = mTextServicesDocument;
|
||||||
textServicesDocument->DidDeleteNode(&aNode);
|
textServicesDocument->DidDeleteNode(&aContent);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
rv = NS_ERROR_FAILURE;
|
rv = NS_ERROR_FAILURE;
|
||||||
|
@ -1847,7 +1848,7 @@ nsresult EditorBase::DeleteNodeWithTransaction(nsINode& aNode) {
|
||||||
if (!mActionListeners.IsEmpty()) {
|
if (!mActionListeners.IsEmpty()) {
|
||||||
AutoActionListenerArray listeners(mActionListeners);
|
AutoActionListenerArray listeners(mActionListeners);
|
||||||
for (auto& listener : listeners) {
|
for (auto& listener : listeners) {
|
||||||
DebugOnly<nsresult> rvIgnored = listener->DidDeleteNode(&aNode, rv);
|
DebugOnly<nsresult> rvIgnored = listener->DidDeleteNode(&aContent, rv);
|
||||||
NS_WARNING_ASSERTION(
|
NS_WARNING_ASSERTION(
|
||||||
NS_SUCCEEDED(rvIgnored),
|
NS_SUCCEEDED(rvIgnored),
|
||||||
"nsIEditActionListener::DidDeleteNode() failed, but ignored");
|
"nsIEditActionListener::DidDeleteNode() failed, but ignored");
|
||||||
|
@ -3095,12 +3096,13 @@ nsresult EditorBase::InsertTextIntoTextNodeWithTransaction(
|
||||||
nsINode* EditorBase::GetFirstEditableNode(nsINode* aRoot) {
|
nsINode* EditorBase::GetFirstEditableNode(nsINode* aRoot) {
|
||||||
MOZ_ASSERT(aRoot);
|
MOZ_ASSERT(aRoot);
|
||||||
|
|
||||||
nsIContent* node = GetLeftmostChild(aRoot);
|
EditorType editorType = GetEditorType();
|
||||||
if (node && !IsEditable(node)) {
|
nsIContent* content = GetLeftmostChild(aRoot);
|
||||||
node = GetNextEditableNode(*node);
|
if (content && !EditorUtils::IsEditableContent(*content, editorType)) {
|
||||||
|
content = GetNextEditableNode(*content);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (node != aRoot) ? node : nullptr;
|
return (content != aRoot) ? content : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult EditorBase::NotifyDocumentListeners(
|
nsresult EditorBase::NotifyDocumentListeners(
|
||||||
|
@ -3796,19 +3798,20 @@ nsIContent* EditorBase::GetPreviousNodeInternal(const EditorRawDOMPoint& aPoint,
|
||||||
|
|
||||||
// unless there isn't one, in which case we are at the end of the node
|
// unless there isn't one, in which case we are at the end of the node
|
||||||
// and want the deep-right child.
|
// and want the deep-right child.
|
||||||
nsIContent* rightMostNode =
|
nsIContent* rightMostContent =
|
||||||
GetRightmostChild(aPoint.GetContainer(), aNoBlockCrossing);
|
GetRightmostChild(aPoint.GetContainer(), aNoBlockCrossing);
|
||||||
if (!rightMostNode) {
|
if (!rightMostContent) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((!aFindEditableNode || IsEditable(rightMostNode)) &&
|
if ((!aFindEditableNode ||
|
||||||
(aFindAnyDataNode || IsElementOrText(*rightMostNode))) {
|
EditorUtils::IsEditableContent(*rightMostContent, GetEditorType())) &&
|
||||||
return rightMostNode;
|
(aFindAnyDataNode || EditorUtils::IsElementOrText(*rightMostContent))) {
|
||||||
|
return rightMostContent;
|
||||||
}
|
}
|
||||||
|
|
||||||
// restart the search from the non-editable node we just found
|
// restart the search from the non-editable node we just found
|
||||||
return GetPreviousNodeInternal(*rightMostNode, aFindEditableNode,
|
return GetPreviousNodeInternal(*rightMostContent, aFindEditableNode,
|
||||||
aFindAnyDataNode, aNoBlockCrossing);
|
aFindAnyDataNode, aNoBlockCrossing);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3848,23 +3851,24 @@ nsIContent* EditorBase::GetNextNodeInternal(const EditorRawDOMPoint& aPoint,
|
||||||
return point.GetChild();
|
return point.GetChild();
|
||||||
}
|
}
|
||||||
|
|
||||||
nsIContent* leftMostNode =
|
nsIContent* leftMostContent =
|
||||||
GetLeftmostChild(point.GetChild(), aNoBlockCrossing);
|
GetLeftmostChild(point.GetChild(), aNoBlockCrossing);
|
||||||
if (!leftMostNode) {
|
if (!leftMostContent) {
|
||||||
return point.GetChild();
|
return point.GetChild();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IsDescendantOfEditorRoot(leftMostNode)) {
|
if (!IsDescendantOfEditorRoot(leftMostContent)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((!aFindEditableNode || IsEditable(leftMostNode)) &&
|
if ((!aFindEditableNode ||
|
||||||
(aFindAnyDataNode || IsElementOrText(*leftMostNode))) {
|
EditorUtils::IsEditableContent(*leftMostContent, GetEditorType())) &&
|
||||||
return leftMostNode;
|
(aFindAnyDataNode || EditorUtils::IsElementOrText(*leftMostContent))) {
|
||||||
|
return leftMostContent;
|
||||||
}
|
}
|
||||||
|
|
||||||
// restart the search from the non-editable node we just found
|
// restart the search from the non-editable node we just found
|
||||||
return GetNextNodeInternal(*leftMostNode, aFindEditableNode,
|
return GetNextNodeInternal(*leftMostContent, aFindEditableNode,
|
||||||
aFindAnyDataNode, aNoBlockCrossing);
|
aFindAnyDataNode, aNoBlockCrossing);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3941,15 +3945,16 @@ nsIContent* EditorBase::FindNode(nsINode* aCurrentNode, bool aGoForward,
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsCOMPtr<nsIContent> candidate =
|
nsIContent* candidate =
|
||||||
FindNextLeafNode(aCurrentNode, aGoForward, bNoBlockCrossing);
|
FindNextLeafNode(aCurrentNode, aGoForward, bNoBlockCrossing);
|
||||||
|
|
||||||
if (!candidate) {
|
if (!candidate) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((!aEditableNode || IsEditable(candidate)) &&
|
if ((!aEditableNode ||
|
||||||
(aFindAnyDataNode || IsElementOrText(*candidate))) {
|
EditorUtils::IsEditableContent(*candidate, GetEditorType())) &&
|
||||||
|
(aFindAnyDataNode || EditorUtils::IsElementOrText(*candidate))) {
|
||||||
return candidate;
|
return candidate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4084,9 +4089,10 @@ bool EditorBase::IsContainer(nsINode* aNode) const {
|
||||||
uint32_t EditorBase::CountEditableChildren(nsINode* aNode) {
|
uint32_t EditorBase::CountEditableChildren(nsINode* aNode) {
|
||||||
MOZ_ASSERT(aNode);
|
MOZ_ASSERT(aNode);
|
||||||
uint32_t count = 0;
|
uint32_t count = 0;
|
||||||
|
EditorType editorType = GetEditorType();
|
||||||
for (nsIContent* child = aNode->GetFirstChild(); child;
|
for (nsIContent* child = aNode->GetFirstChild(); child;
|
||||||
child = child->GetNextSibling()) {
|
child = child->GetNextSibling()) {
|
||||||
if (IsEditable(child)) {
|
if (EditorUtils::IsEditableContent(*child, editorType)) {
|
||||||
++count;
|
++count;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4342,6 +4348,7 @@ EditorDOMPoint EditorBase::JoinNodesDeepWithTransaction(
|
||||||
nsCOMPtr<nsINode> parentNode = aRightNode.GetParentNode();
|
nsCOMPtr<nsINode> parentNode = aRightNode.GetParentNode();
|
||||||
|
|
||||||
EditorDOMPoint ret;
|
EditorDOMPoint ret;
|
||||||
|
EditorType editorType = GetEditorType();
|
||||||
while (leftNodeToJoin && rightNodeToJoin && parentNode &&
|
while (leftNodeToJoin && rightNodeToJoin && parentNode &&
|
||||||
AreNodesSameType(*leftNodeToJoin, *rightNodeToJoin)) {
|
AreNodesSameType(*leftNodeToJoin, *rightNodeToJoin)) {
|
||||||
uint32_t length = leftNodeToJoin->Length();
|
uint32_t length = leftNodeToJoin->Length();
|
||||||
|
@ -4370,14 +4377,16 @@ EditorDOMPoint EditorBase::JoinNodesDeepWithTransaction(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Skip over non-editable nodes
|
// Skip over non-editable nodes
|
||||||
while (leftNodeToJoin && !IsEditable(leftNodeToJoin)) {
|
while (leftNodeToJoin &&
|
||||||
|
!EditorUtils::IsEditableContent(*leftNodeToJoin, editorType)) {
|
||||||
leftNodeToJoin = leftNodeToJoin->GetPreviousSibling();
|
leftNodeToJoin = leftNodeToJoin->GetPreviousSibling();
|
||||||
}
|
}
|
||||||
if (!leftNodeToJoin) {
|
if (!leftNodeToJoin) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (rightNodeToJoin && !IsEditable(rightNodeToJoin)) {
|
while (rightNodeToJoin &&
|
||||||
|
!EditorUtils::IsEditableContent(*rightNodeToJoin, editorType)) {
|
||||||
rightNodeToJoin = rightNodeToJoin->GetNextSibling();
|
rightNodeToJoin = rightNodeToJoin->GetNextSibling();
|
||||||
}
|
}
|
||||||
if (!rightNodeToJoin) {
|
if (!rightNodeToJoin) {
|
||||||
|
@ -4440,11 +4449,14 @@ nsresult EditorBase::MaybeCreatePaddingBRElementForEmptyEditor() {
|
||||||
// Now we've got the body element. Iterate over the body element's children,
|
// Now we've got the body element. Iterate over the body element's children,
|
||||||
// looking for editable content. If no editable content is found, insert the
|
// looking for editable content. If no editable content is found, insert the
|
||||||
// padding <br> element.
|
// padding <br> element.
|
||||||
bool isRootEditable = IsEditable(rootElement);
|
EditorType editorType = GetEditorType();
|
||||||
|
bool isRootEditable =
|
||||||
|
EditorUtils::IsEditableContent(*rootElement, editorType);
|
||||||
for (nsIContent* rootChild = rootElement->GetFirstChild(); rootChild;
|
for (nsIContent* rootChild = rootElement->GetFirstChild(); rootChild;
|
||||||
rootChild = rootChild->GetNextSibling()) {
|
rootChild = rootChild->GetNextSibling()) {
|
||||||
if (EditorBase::IsPaddingBRElementForEmptyEditor(*rootChild) ||
|
if (EditorUtils::IsPaddingBRElementForEmptyEditor(*rootChild) ||
|
||||||
!isRootEditable || IsEditable(rootChild) ||
|
!isRootEditable ||
|
||||||
|
EditorUtils::IsEditableContent(*rootChild, editorType) ||
|
||||||
HTMLEditUtils::IsBlockElement(*rootChild)) {
|
HTMLEditUtils::IsBlockElement(*rootChild)) {
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
@ -4452,7 +4464,7 @@ nsresult EditorBase::MaybeCreatePaddingBRElementForEmptyEditor() {
|
||||||
|
|
||||||
// Skip adding the padding <br> element for empty editor if body
|
// Skip adding the padding <br> element for empty editor if body
|
||||||
// is read-only.
|
// is read-only.
|
||||||
if (!IsModifiableNode(*rootElement)) {
|
if (IsHTMLEditor() && !HTMLEditUtils::IsSimplyEditableNode(*rootElement)) {
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5380,10 +5392,6 @@ nsresult EditorBase::SetTextDirectionTo(TextDirection aTextDirection) {
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EditorBase::IsModifiableNode(const nsINode& aNode) const {
|
|
||||||
return !AsHTMLEditor() || aNode.IsEditable();
|
|
||||||
}
|
|
||||||
|
|
||||||
nsIContent* EditorBase::GetFocusedContent() const {
|
nsIContent* EditorBase::GetFocusedContent() const {
|
||||||
EventTarget* piTarget = GetDOMEventTarget();
|
EventTarget* piTarget = GetDOMEventTarget();
|
||||||
if (!piTarget) {
|
if (!piTarget) {
|
||||||
|
@ -6017,7 +6025,7 @@ EditorBase::AutoEditActionDataSetter::AutoEditActionDataSetter(
|
||||||
|
|
||||||
mEditAction = aEditAction;
|
mEditAction = aEditAction;
|
||||||
mDirectionOfTopLevelEditSubAction = eNone;
|
mDirectionOfTopLevelEditSubAction = eNone;
|
||||||
if (mEditorBase.mIsHTMLEditorClass) {
|
if (mEditorBase.IsHTMLEditor()) {
|
||||||
mTopLevelEditSubActionData.mSelectedRange =
|
mTopLevelEditSubActionData.mSelectedRange =
|
||||||
mEditorBase.AsHTMLEditor()
|
mEditorBase.AsHTMLEditor()
|
||||||
->GetSelectedRangeItemForTopLevelEditSubAction();
|
->GetSelectedRangeItemForTopLevelEditSubAction();
|
||||||
|
|
|
@ -154,6 +154,8 @@ class EditorBase : public nsIEditor,
|
||||||
typedef dom::Selection Selection;
|
typedef dom::Selection Selection;
|
||||||
typedef dom::Text Text;
|
typedef dom::Text Text;
|
||||||
|
|
||||||
|
enum class EditorType { Text, HTML };
|
||||||
|
|
||||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||||
NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(EditorBase, nsIEditor)
|
NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(EditorBase, nsIEditor)
|
||||||
|
|
||||||
|
@ -169,6 +171,9 @@ class EditorBase : public nsIEditor,
|
||||||
*/
|
*/
|
||||||
EditorBase();
|
EditorBase();
|
||||||
|
|
||||||
|
bool IsTextEditor() const { return !mIsHTMLEditorClass; }
|
||||||
|
bool IsHTMLEditor() const { return mIsHTMLEditorClass; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Init is to tell the implementation of nsIEditor to begin its services
|
* Init is to tell the implementation of nsIEditor to begin its services
|
||||||
* @param aDoc The dom document interface being observed
|
* @param aDoc The dom document interface being observed
|
||||||
|
@ -214,7 +219,7 @@ class EditorBase : public nsIEditor,
|
||||||
// @return true, iff at least one of NS_EVENT_BITS_MUTATION_* is set.
|
// @return true, iff at least one of NS_EVENT_BITS_MUTATION_* is set.
|
||||||
bool MaybeHasMutationEventListeners(
|
bool MaybeHasMutationEventListeners(
|
||||||
uint32_t aMutationEventType = 0xFFFFFFFF) const {
|
uint32_t aMutationEventType = 0xFFFFFFFF) const {
|
||||||
if (!mIsHTMLEditorClass) {
|
if (IsTextEditor()) {
|
||||||
// DOM mutation event listeners cannot catch the changes of
|
// DOM mutation event listeners cannot catch the changes of
|
||||||
// <input type="text"> nor <textarea>.
|
// <input type="text"> nor <textarea>.
|
||||||
return false;
|
return false;
|
||||||
|
@ -1410,11 +1415,11 @@ class EditorBase : public nsIEditor,
|
||||||
SetTextNodeWithoutTransaction(const nsAString& aString, Text& aTextNode);
|
SetTextNodeWithoutTransaction(const nsAString& aString, Text& aTextNode);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DeleteNodeWithTransaction() removes aNode from the DOM tree.
|
* DeleteNodeWithTransaction() removes aContent from the DOM tree.
|
||||||
*
|
*
|
||||||
* @param aNode The node which will be removed form the DOM tree.
|
* @param aContent The node which will be removed form the DOM tree.
|
||||||
*/
|
*/
|
||||||
MOZ_CAN_RUN_SCRIPT nsresult DeleteNodeWithTransaction(nsINode& aNode);
|
MOZ_CAN_RUN_SCRIPT nsresult DeleteNodeWithTransaction(nsIContent& aContent);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* InsertNodeWithTransaction() inserts aContentToInsert before the child
|
* InsertNodeWithTransaction() inserts aContentToInsert before the child
|
||||||
|
@ -2097,54 +2102,6 @@ class EditorBase : public nsIEditor,
|
||||||
*/
|
*/
|
||||||
virtual bool IsContainer(nsINode* aNode) const;
|
virtual bool IsContainer(nsINode* aNode) const;
|
||||||
|
|
||||||
/**
|
|
||||||
* returns true if aNode is an editable node.
|
|
||||||
*/
|
|
||||||
bool IsEditable(nsINode* aNode) const {
|
|
||||||
if (NS_WARN_IF(!aNode)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!aNode->IsContent() || !IsModifiableNode(*aNode) ||
|
|
||||||
EditorBase::IsPaddingBRElementForEmptyEditor(*aNode)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (aNode->NodeType()) {
|
|
||||||
case nsINode::ELEMENT_NODE:
|
|
||||||
// In HTML editors, if we're dealing with an element, then ask it
|
|
||||||
// whether it's editable.
|
|
||||||
return mIsHTMLEditorClass ? aNode->IsEditable() : true;
|
|
||||||
case nsINode::TEXT_NODE:
|
|
||||||
// Text nodes are considered to be editable by both typed of editors.
|
|
||||||
return true;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if aNode is a usual element node (not padding <br> element
|
|
||||||
* for empty editor) or a text node. In other words, returns true if aNode
|
|
||||||
* is a usual element node or visible data node.
|
|
||||||
*/
|
|
||||||
bool IsElementOrText(const nsINode& aNode) const {
|
|
||||||
if (aNode.IsText()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return aNode.IsElement() &&
|
|
||||||
!EditorBase::IsPaddingBRElementForEmptyEditor(aNode);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if aNode is a <br> element and it's marked as padding for
|
|
||||||
* empty editor.
|
|
||||||
*/
|
|
||||||
static bool IsPaddingBRElementForEmptyEditor(const nsINode& aNode) {
|
|
||||||
const dom::HTMLBRElement* brElement = dom::HTMLBRElement::FromNode(&aNode);
|
|
||||||
return brElement && brElement->IsPaddingForEmptyEditor();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if aNode is a <br> element and it's marked as padding for
|
* Returns true if aNode is a <br> element and it's marked as padding for
|
||||||
* empty last line.
|
* empty last line.
|
||||||
|
@ -2181,11 +2138,6 @@ class EditorBase : public nsIEditor,
|
||||||
return aNode->NodeType() == nsINode::TEXT_NODE;
|
return aNode->NodeType() == nsINode::TEXT_NODE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* IsModifiableNode() checks whether the node is editable or not.
|
|
||||||
*/
|
|
||||||
bool IsModifiableNode(const nsINode& aNode) const;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GetNodeAtRangeOffsetPoint() returns the node at this position in a range,
|
* GetNodeAtRangeOffsetPoint() returns the node at this position in a range,
|
||||||
* assuming that the container is the node itself if it's a text node, or
|
* assuming that the container is the node itself if it's a text node, or
|
||||||
|
@ -2369,6 +2321,10 @@ class EditorBase : public nsIEditor,
|
||||||
*/
|
*/
|
||||||
virtual ~EditorBase();
|
virtual ~EditorBase();
|
||||||
|
|
||||||
|
MOZ_ALWAYS_INLINE EditorType GetEditorType() const {
|
||||||
|
return mIsHTMLEditorClass ? EditorType::HTML : EditorType::Text;
|
||||||
|
}
|
||||||
|
|
||||||
int32_t WrapWidth() const { return mWrapColumn; }
|
int32_t WrapWidth() const { return mWrapColumn; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include "mozilla/EditorDOMPoint.h"
|
#include "mozilla/EditorDOMPoint.h"
|
||||||
#include "mozilla/GuardObjects.h"
|
#include "mozilla/GuardObjects.h"
|
||||||
#include "mozilla/RangeBoundary.h"
|
#include "mozilla/RangeBoundary.h"
|
||||||
|
#include "mozilla/dom/HTMLBRElement.h"
|
||||||
#include "mozilla/dom/Selection.h"
|
#include "mozilla/dom/Selection.h"
|
||||||
#include "mozilla/dom/StaticRange.h"
|
#include "mozilla/dom/StaticRange.h"
|
||||||
#include "nsAtom.h"
|
#include "nsAtom.h"
|
||||||
|
@ -783,6 +784,8 @@ class MOZ_RAII DOMSubtreeIterator final : public DOMIterator {
|
||||||
|
|
||||||
class EditorUtils final {
|
class EditorUtils final {
|
||||||
public:
|
public:
|
||||||
|
using EditorType = EditorBase::EditorType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* IsDescendantOf() checks if aNode is a child or a descendant of aParent.
|
* IsDescendantOf() checks if aNode is a child or a descendant of aParent.
|
||||||
* aOutPoint is set to the child of aParent.
|
* aOutPoint is set to the child of aParent.
|
||||||
|
@ -794,6 +797,53 @@ class EditorUtils final {
|
||||||
static bool IsDescendantOf(const nsINode& aNode, const nsINode& aParent,
|
static bool IsDescendantOf(const nsINode& aNode, const nsINode& aParent,
|
||||||
EditorDOMPoint* aOutPoint);
|
EditorDOMPoint* aOutPoint);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if aContent is a <br> element and it's marked as padding for
|
||||||
|
* empty editor.
|
||||||
|
*/
|
||||||
|
static bool IsPaddingBRElementForEmptyEditor(const nsIContent& aContent) {
|
||||||
|
const dom::HTMLBRElement* brElement =
|
||||||
|
dom::HTMLBRElement::FromNode(&aContent);
|
||||||
|
return brElement && brElement->IsPaddingForEmptyEditor();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IsEditableContent() returns true if aContent's data or children is ediable
|
||||||
|
* for the given editor type. Be aware, returning true does NOT mean the
|
||||||
|
* node can be removed from its parent node, and returning false does NOT
|
||||||
|
* mean the node cannot be removed from the parent node.
|
||||||
|
* XXX May be the anonymous nodes in TextEditor not editable? If it's not
|
||||||
|
* so, we can get rid of aEditorType.
|
||||||
|
*/
|
||||||
|
static bool IsEditableContent(const nsIContent& aContent,
|
||||||
|
EditorType aEditorType) {
|
||||||
|
if ((aEditorType == EditorType::HTML && !aContent.IsEditable()) ||
|
||||||
|
EditorUtils::IsPaddingBRElementForEmptyEditor(aContent)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// In HTML editors, if we're dealing with an element, then ask it
|
||||||
|
// whether it's editable.
|
||||||
|
if (aContent.IsElement()) {
|
||||||
|
return aEditorType == EditorType::HTML ? aContent.IsEditable() : true;
|
||||||
|
}
|
||||||
|
// Text nodes are considered to be editable by both typed of editors.
|
||||||
|
return aContent.IsText();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if aContent is a usual element node (not padding <br> element
|
||||||
|
* for empty editor) or a text node. In other words, returns true if
|
||||||
|
* aContent is a usual element node or visible data node.
|
||||||
|
*/
|
||||||
|
static bool IsElementOrText(const nsIContent& aContent) {
|
||||||
|
if (aContent.IsText()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return aContent.IsElement() &&
|
||||||
|
!EditorUtils::IsPaddingBRElementForEmptyEditor(aContent);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper method for `AppendString()` and `AppendSubString()`. This should
|
* Helper method for `AppendString()` and `AppendSubString()`. This should
|
||||||
* be called only when `aText` is in a password field. This method masks
|
* be called only when `aText` is in a password field. This method masks
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
#include "HTMLEditor.h"
|
#include "HTMLEditor.h"
|
||||||
|
|
||||||
|
#include "HTMLEditUtils.h"
|
||||||
#include "mozilla/Attributes.h"
|
#include "mozilla/Attributes.h"
|
||||||
#include "mozilla/PresShell.h"
|
#include "mozilla/PresShell.h"
|
||||||
#include "mozilla/PresShellInlines.h"
|
#include "mozilla/PresShellInlines.h"
|
||||||
|
@ -436,7 +437,8 @@ nsresult HTMLEditor::RefreshEditingUI() {
|
||||||
nsIContent* hostContent = GetActiveEditingHost();
|
nsIContent* hostContent = GetActiveEditingHost();
|
||||||
|
|
||||||
if (IsObjectResizerEnabled() && focusElement &&
|
if (IsObjectResizerEnabled() && focusElement &&
|
||||||
IsModifiableNode(*focusElement) && focusElement != hostContent) {
|
HTMLEditUtils::IsSimplyEditableNode(*focusElement) &&
|
||||||
|
focusElement != hostContent) {
|
||||||
if (nsGkAtoms::img == focusTagAtom) {
|
if (nsGkAtoms::img == focusTagAtom) {
|
||||||
mResizedObjectIsAnImage = true;
|
mResizedObjectIsAnImage = true;
|
||||||
}
|
}
|
||||||
|
@ -456,7 +458,8 @@ nsresult HTMLEditor::RefreshEditingUI() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsAbsolutePositionEditorEnabled() && absPosElement &&
|
if (IsAbsolutePositionEditorEnabled() && absPosElement &&
|
||||||
IsModifiableNode(*absPosElement) && absPosElement != hostContent) {
|
HTMLEditUtils::IsSimplyEditableNode(*absPosElement) &&
|
||||||
|
absPosElement != hostContent) {
|
||||||
if (mAbsolutelyPositionedObject) {
|
if (mAbsolutelyPositionedObject) {
|
||||||
nsresult rv = RefreshGrabberInternal();
|
nsresult rv = RefreshGrabberInternal();
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
|
@ -472,8 +475,10 @@ nsresult HTMLEditor::RefreshEditingUI() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// XXX Shouldn't we check whether the `<table>` element is editable or not?
|
||||||
if (IsInlineTableEditorEnabled() && cellElement &&
|
if (IsInlineTableEditorEnabled() && cellElement &&
|
||||||
IsModifiableNode(*cellElement) && cellElement != hostContent) {
|
HTMLEditUtils::IsSimplyEditableNode(*cellElement) &&
|
||||||
|
cellElement != hostContent) {
|
||||||
if (mInlineEditedCell) {
|
if (mInlineEditedCell) {
|
||||||
nsresult rv = RefreshInlineTableEditingUIInternal();
|
nsresult rv = RefreshInlineTableEditingUIInternal();
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
|
|
|
@ -688,7 +688,7 @@ EditActionResult HTMLEditor::CanHandleHTMLEditSubAction() const {
|
||||||
return EditActionResult(NS_ERROR_FAILURE);
|
return EditActionResult(NS_ERROR_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IsModifiableNode(*selStartNode)) {
|
if (!HTMLEditUtils::IsSimplyEditableNode(*selStartNode)) {
|
||||||
return EditActionCanceled();
|
return EditActionCanceled();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -701,21 +701,22 @@ EditActionResult HTMLEditor::CanHandleHTMLEditSubAction() const {
|
||||||
return EditActionIgnored();
|
return EditActionIgnored();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IsModifiableNode(*selEndNode)) {
|
if (!HTMLEditUtils::IsSimplyEditableNode(*selEndNode)) {
|
||||||
return EditActionCanceled();
|
return EditActionCanceled();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// XXX What does it mean the common ancestor is editable? I have no idea.
|
||||||
|
// It should be in same (active) editing host, and even if it's editable,
|
||||||
|
// there may be non-editable contents in the range.
|
||||||
nsINode* commonAncestor = range->GetClosestCommonInclusiveAncestor();
|
nsINode* commonAncestor = range->GetClosestCommonInclusiveAncestor();
|
||||||
if (!commonAncestor) {
|
if (!commonAncestor) {
|
||||||
NS_WARNING(
|
NS_WARNING(
|
||||||
"AbstractRange::GetClosestCommonInclusiveAncestor() returned nullptr");
|
"AbstractRange::GetClosestCommonInclusiveAncestor() returned nullptr");
|
||||||
return EditActionResult(NS_ERROR_FAILURE);
|
return EditActionResult(NS_ERROR_FAILURE);
|
||||||
}
|
}
|
||||||
if (!IsModifiableNode(*commonAncestor)) {
|
return HTMLEditUtils::IsSimplyEditableNode(*commonAncestor)
|
||||||
return EditActionCanceled();
|
? EditActionIgnored()
|
||||||
}
|
: EditActionCanceled();
|
||||||
|
|
||||||
return EditActionIgnored();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ListElementSelectionState::ListElementSelectionState(HTMLEditor& aHTMLEditor,
|
ListElementSelectionState::ListElementSelectionState(HTMLEditor& aHTMLEditor,
|
||||||
|
@ -1255,7 +1256,7 @@ nsresult ParagraphStateAtSelection::CollectEditableFormatNodesInSelection(
|
||||||
OwningNonNull<nsIContent> content = aArrayOfContents[i];
|
OwningNonNull<nsIContent> content = aArrayOfContents[i];
|
||||||
|
|
||||||
// Remove all non-editable nodes. Leave them be.
|
// Remove all non-editable nodes. Leave them be.
|
||||||
if (!aHTMLEditor.IsEditable(content)) {
|
if (!EditorUtils::IsEditableContent(content, EditorType::HTML)) {
|
||||||
aArrayOfContents.RemoveElementAt(i);
|
aArrayOfContents.RemoveElementAt(i);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -1823,7 +1824,8 @@ EditActionResult HTMLEditor::InsertParagraphSeparatorAsSubAction() {
|
||||||
MOZ_ASSERT(atStartOfSelection.IsSetAndValid());
|
MOZ_ASSERT(atStartOfSelection.IsSetAndValid());
|
||||||
|
|
||||||
// Do nothing if the node is read-only
|
// Do nothing if the node is read-only
|
||||||
if (!IsModifiableNode(*atStartOfSelection.GetContainer())) {
|
if (!HTMLEditUtils::IsSimplyEditableNode(
|
||||||
|
*atStartOfSelection.GetContainer())) {
|
||||||
return EditActionCanceled();
|
return EditActionCanceled();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3481,13 +3483,18 @@ nsresult HTMLEditor::DeleteUnnecessaryNodesAndCollapseSelection(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (NS_WARN_IF(!atCaret.IsInContentNode()) ||
|
||||||
|
NS_WARN_IF(!selectionEndPoint.IsInContentNode())) {
|
||||||
|
return NS_ERROR_EDITOR_UNEXPECTED_DOM_TREE;
|
||||||
|
}
|
||||||
|
|
||||||
// We might have left only collapsed whitespace in the start/end nodes
|
// We might have left only collapsed whitespace in the start/end nodes
|
||||||
{
|
{
|
||||||
AutoTrackDOMPoint startTracker(RangeUpdaterRef(), &atCaret);
|
AutoTrackDOMPoint startTracker(RangeUpdaterRef(), &atCaret);
|
||||||
AutoTrackDOMPoint endTracker(RangeUpdaterRef(), &selectionEndPoint);
|
AutoTrackDOMPoint endTracker(RangeUpdaterRef(), &selectionEndPoint);
|
||||||
|
|
||||||
nsresult rv = DeleteNodeIfInvisibleAndEditableTextNode(
|
nsresult rv = DeleteNodeIfInvisibleAndEditableTextNode(
|
||||||
MOZ_KnownLive(*atCaret.GetContainer()));
|
MOZ_KnownLive(*atCaret.ContainerAsContent()));
|
||||||
if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
|
if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
|
||||||
return NS_ERROR_EDITOR_DESTROYED;
|
return NS_ERROR_EDITOR_DESTROYED;
|
||||||
}
|
}
|
||||||
|
@ -3495,7 +3502,7 @@ nsresult HTMLEditor::DeleteUnnecessaryNodesAndCollapseSelection(
|
||||||
"HTMLEditor::DeleteNodeIfInvisibleAndEditableTextNode("
|
"HTMLEditor::DeleteNodeIfInvisibleAndEditableTextNode("
|
||||||
") failed to remove start node, but ignored");
|
") failed to remove start node, but ignored");
|
||||||
rv = DeleteNodeIfInvisibleAndEditableTextNode(
|
rv = DeleteNodeIfInvisibleAndEditableTextNode(
|
||||||
MOZ_KnownLive(*selectionEndPoint.GetContainer()));
|
MOZ_KnownLive(*selectionEndPoint.ContainerAsContent()));
|
||||||
if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
|
if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
|
||||||
return NS_ERROR_EDITOR_DESTROYED;
|
return NS_ERROR_EDITOR_DESTROYED;
|
||||||
}
|
}
|
||||||
|
@ -3512,19 +3519,20 @@ nsresult HTMLEditor::DeleteUnnecessaryNodesAndCollapseSelection(
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult HTMLEditor::DeleteNodeIfInvisibleAndEditableTextNode(nsINode& aNode) {
|
nsresult HTMLEditor::DeleteNodeIfInvisibleAndEditableTextNode(
|
||||||
|
nsIContent& aContent) {
|
||||||
MOZ_ASSERT(IsEditActionDataAvailable());
|
MOZ_ASSERT(IsEditActionDataAvailable());
|
||||||
|
|
||||||
Text* text = aNode.GetAsText();
|
Text* text = aContent.GetAsText();
|
||||||
if (!text) {
|
if (!text) {
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsVisibleTextNode(*text) || !IsModifiableNode(*text)) {
|
if (IsVisibleTextNode(*text) || !HTMLEditUtils::IsSimplyEditableNode(*text)) {
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult rv = DeleteNodeWithTransaction(aNode);
|
nsresult rv = DeleteNodeWithTransaction(aContent);
|
||||||
if (NS_WARN_IF(Destroyed())) {
|
if (NS_WARN_IF(Destroyed())) {
|
||||||
return NS_ERROR_EDITOR_DESTROYED;
|
return NS_ERROR_EDITOR_DESTROYED;
|
||||||
}
|
}
|
||||||
|
@ -4177,7 +4185,7 @@ nsresult HTMLEditor::DeleteElementsExceptTableRelatedElements(nsINode& aNode) {
|
||||||
MOZ_ASSERT(IsEditActionDataAvailable());
|
MOZ_ASSERT(IsEditActionDataAvailable());
|
||||||
|
|
||||||
if (!HTMLEditUtils::IsTableElementButNotTable(&aNode)) {
|
if (!HTMLEditUtils::IsTableElementButNotTable(&aNode)) {
|
||||||
nsresult rv = DeleteNodeWithTransaction(aNode);
|
nsresult rv = DeleteNodeWithTransaction(MOZ_KnownLive(*aNode.AsContent()));
|
||||||
if (NS_WARN_IF(Destroyed())) {
|
if (NS_WARN_IF(Destroyed())) {
|
||||||
return NS_ERROR_EDITOR_DESTROYED;
|
return NS_ERROR_EDITOR_DESTROYED;
|
||||||
}
|
}
|
||||||
|
@ -4545,7 +4553,7 @@ EditActionResult HTMLEditor::ChangeSelectedHardLinesToList(
|
||||||
// If current node is a `<br>` element, delete it and forget previous
|
// If current node is a `<br>` element, delete it and forget previous
|
||||||
// list item element.
|
// list item element.
|
||||||
// If current node is an empty inline node, just delete it.
|
// If current node is an empty inline node, just delete it.
|
||||||
if (IsEditable(content) &&
|
if (EditorUtils::IsEditableContent(content, EditorType::HTML) &&
|
||||||
(content->IsHTMLElement(nsGkAtoms::br) || IsEmptyInlineNode(content))) {
|
(content->IsHTMLElement(nsGkAtoms::br) || IsEmptyInlineNode(content))) {
|
||||||
nsresult rv = DeleteNodeWithTransaction(*content);
|
nsresult rv = DeleteNodeWithTransaction(*content);
|
||||||
if (NS_WARN_IF(Destroyed())) {
|
if (NS_WARN_IF(Destroyed())) {
|
||||||
|
@ -4929,7 +4937,7 @@ nsresult HTMLEditor::RemoveListAtSelectionAsSubAction() {
|
||||||
// CollectNonEditableNodes::No.
|
// CollectNonEditableNodes::No.
|
||||||
for (int32_t i = arrayOfContents.Length() - 1; i >= 0; i--) {
|
for (int32_t i = arrayOfContents.Length() - 1; i >= 0; i--) {
|
||||||
OwningNonNull<nsIContent>& content = arrayOfContents[i];
|
OwningNonNull<nsIContent>& content = arrayOfContents[i];
|
||||||
if (!IsEditable(content)) {
|
if (!EditorUtils::IsEditableContent(content, EditorType::HTML)) {
|
||||||
arrayOfContents.RemoveElementAt(i);
|
arrayOfContents.RemoveElementAt(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5498,7 +5506,7 @@ nsresult HTMLEditor::HandleCSSIndentAtSelectionInternal() {
|
||||||
|
|
||||||
// Ignore all non-editable nodes. Leave them be.
|
// Ignore all non-editable nodes. Leave them be.
|
||||||
// XXX We ignore non-editable nodes here, but not so in the above block.
|
// XXX We ignore non-editable nodes here, but not so in the above block.
|
||||||
if (!IsEditable(content)) {
|
if (!EditorUtils::IsEditableContent(content, EditorType::HTML)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5706,7 +5714,7 @@ nsresult HTMLEditor::HandleHTMLIndentAtSelectionInternal() {
|
||||||
|
|
||||||
// Ignore all non-editable nodes. Leave them be.
|
// Ignore all non-editable nodes. Leave them be.
|
||||||
// XXX We ignore non-editable nodes here, but not so in the above block.
|
// XXX We ignore non-editable nodes here, but not so in the above block.
|
||||||
if (!IsEditable(content)) {
|
if (!EditorUtils::IsEditableContent(content, EditorType::HTML)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6908,7 +6916,7 @@ nsresult HTMLEditor::AlignNodesAndDescendants(
|
||||||
++indexOfTransitionList;
|
++indexOfTransitionList;
|
||||||
|
|
||||||
// Ignore all non-editable nodes. Leave them be.
|
// Ignore all non-editable nodes. Leave them be.
|
||||||
if (!IsEditable(content)) {
|
if (!EditorUtils::IsEditableContent(content, EditorType::HTML)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7350,7 +7358,7 @@ size_t HTMLEditor::CollectChildren(
|
||||||
aIndexToInsertChildren + numberOfFoundChildren, aCollectListChildren,
|
aIndexToInsertChildren + numberOfFoundChildren, aCollectListChildren,
|
||||||
aCollectTableChildren, aCollectNonEditableNodes);
|
aCollectTableChildren, aCollectNonEditableNodes);
|
||||||
} else if (aCollectNonEditableNodes == CollectNonEditableNodes::Yes ||
|
} else if (aCollectNonEditableNodes == CollectNonEditableNodes::Yes ||
|
||||||
IsEditable(content)) {
|
EditorUtils::IsEditableContent(*content, EditorType::HTML)) {
|
||||||
aOutArrayOfContents.InsertElementAt(
|
aOutArrayOfContents.InsertElementAt(
|
||||||
aIndexToInsertChildren + numberOfFoundChildren++, *content);
|
aIndexToInsertChildren + numberOfFoundChildren++, *content);
|
||||||
}
|
}
|
||||||
|
@ -8155,7 +8163,8 @@ nsresult HTMLEditor::CollectEditTargetNodes(
|
||||||
}
|
}
|
||||||
if (aCollectNonEditableNodes == CollectNonEditableNodes::No) {
|
if (aCollectNonEditableNodes == CollectNonEditableNodes::No) {
|
||||||
for (size_t i = aOutArrayOfContents.Length(); i > 0; --i) {
|
for (size_t i = aOutArrayOfContents.Length(); i > 0; --i) {
|
||||||
if (!IsEditable(aOutArrayOfContents[i - 1])) {
|
if (!EditorUtils::IsEditableContent(aOutArrayOfContents[i - 1],
|
||||||
|
EditorType::HTML)) {
|
||||||
aOutArrayOfContents.RemoveElementAt(i - 1);
|
aOutArrayOfContents.RemoveElementAt(i - 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9303,7 +9312,7 @@ nsresult HTMLEditor::RemoveBlockContainerElements(
|
||||||
}
|
}
|
||||||
firstContent = lastContent = curBlock = nullptr;
|
firstContent = lastContent = curBlock = nullptr;
|
||||||
}
|
}
|
||||||
if (!IsEditable(content)) {
|
if (!EditorUtils::IsEditableContent(content, EditorType::HTML)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// Remove current block
|
// Remove current block
|
||||||
|
@ -9337,7 +9346,7 @@ nsresult HTMLEditor::RemoveBlockContainerElements(
|
||||||
}
|
}
|
||||||
firstContent = lastContent = curBlock = nullptr;
|
firstContent = lastContent = curBlock = nullptr;
|
||||||
}
|
}
|
||||||
if (!IsEditable(content)) {
|
if (!EditorUtils::IsEditableContent(content, EditorType::HTML)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// Recursion time
|
// Recursion time
|
||||||
|
@ -9376,7 +9385,7 @@ nsresult HTMLEditor::RemoveBlockContainerElements(
|
||||||
}
|
}
|
||||||
curBlock = GetBlockNodeParent(content);
|
curBlock = GetBlockNodeParent(content);
|
||||||
if (!curBlock || !HTMLEditUtils::IsFormatNode(curBlock) ||
|
if (!curBlock || !HTMLEditUtils::IsFormatNode(curBlock) ||
|
||||||
!IsEditable(curBlock)) {
|
!EditorUtils::IsEditableContent(*curBlock, EditorType::HTML)) {
|
||||||
// Not a block kind that we care about.
|
// Not a block kind that we care about.
|
||||||
curBlock = nullptr;
|
curBlock = nullptr;
|
||||||
} else {
|
} else {
|
||||||
|
@ -9439,7 +9448,8 @@ nsresult HTMLEditor::CreateOrChangeBlockContainerElement(
|
||||||
|
|
||||||
// Is it already the right kind of block, or an uneditable block?
|
// Is it already the right kind of block, or an uneditable block?
|
||||||
if (content->IsHTMLElement(&aBlockTag) ||
|
if (content->IsHTMLElement(&aBlockTag) ||
|
||||||
(!IsEditable(content) && HTMLEditUtils::IsBlockElement(content))) {
|
(!EditorUtils::IsEditableContent(content, EditorType::HTML) &&
|
||||||
|
HTMLEditUtils::IsBlockElement(content))) {
|
||||||
// Forget any previous block used for previous inline nodes
|
// Forget any previous block used for previous inline nodes
|
||||||
curBlock = nullptr;
|
curBlock = nullptr;
|
||||||
// Do nothing to this block
|
// Do nothing to this block
|
||||||
|
@ -9605,7 +9615,8 @@ nsresult HTMLEditor::CreateOrChangeBlockContainerElement(
|
||||||
// added here if that should change
|
// added here if that should change
|
||||||
//
|
//
|
||||||
// If content is a non editable, drop it if we are going to <pre>.
|
// If content is a non editable, drop it if we are going to <pre>.
|
||||||
if (&aBlockTag == nsGkAtoms::pre && !IsEditable(content)) {
|
if (&aBlockTag == nsGkAtoms::pre &&
|
||||||
|
!EditorUtils::IsEditableContent(content, EditorType::HTML)) {
|
||||||
// Do nothing to this block
|
// Do nothing to this block
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -9999,7 +10010,7 @@ nsresult HTMLEditor::InsertBRElementToEmptyListItemsAndTableCellsInRange(
|
||||||
MOZ_ASSERT(Element::FromNode(&aNode));
|
MOZ_ASSERT(Element::FromNode(&aNode));
|
||||||
MOZ_ASSERT(aSelf);
|
MOZ_ASSERT(aSelf);
|
||||||
Element* element = aNode.AsElement();
|
Element* element = aNode.AsElement();
|
||||||
if (!static_cast<HTMLEditor*>(aSelf)->IsEditable(element) ||
|
if (!EditorUtils::IsEditableContent(*element, EditorType::HTML) ||
|
||||||
(!HTMLEditUtils::IsListItem(element) &&
|
(!HTMLEditUtils::IsListItem(element) &&
|
||||||
!HTMLEditUtils::IsTableCellOrCaption(*element))) {
|
!HTMLEditUtils::IsTableCellOrCaption(*element))) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -10175,14 +10186,15 @@ nsresult HTMLEditor::AdjustCaretPositionAndEnsurePaddingBRElement(
|
||||||
MOZ_ASSERT(SelectionRefPtr()->IsCollapsed());
|
MOZ_ASSERT(SelectionRefPtr()->IsCollapsed());
|
||||||
|
|
||||||
EditorDOMPoint point(EditorBase::GetStartPoint(*SelectionRefPtr()));
|
EditorDOMPoint point(EditorBase::GetStartPoint(*SelectionRefPtr()));
|
||||||
if (NS_WARN_IF(!point.IsSet())) {
|
if (NS_WARN_IF(!point.IsInContentNode())) {
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If selection start is not editable, climb up the tree until editable one.
|
// If selection start is not editable, climb up the tree until editable one.
|
||||||
while (!IsEditable(point.GetContainer())) {
|
while (!EditorUtils::IsEditableContent(*point.ContainerAsContent(),
|
||||||
|
EditorType::HTML)) {
|
||||||
point.Set(point.GetContainer());
|
point.Set(point.GetContainer());
|
||||||
if (NS_WARN_IF(!point.IsSet())) {
|
if (NS_WARN_IF(!point.IsInContentNode())) {
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10190,7 +10202,9 @@ nsresult HTMLEditor::AdjustCaretPositionAndEnsurePaddingBRElement(
|
||||||
// If caret is in empty block element, we need to insert a `<br>` element
|
// If caret is in empty block element, we need to insert a `<br>` element
|
||||||
// because the block should have one-line height.
|
// because the block should have one-line height.
|
||||||
if (RefPtr<Element> blockElement = GetBlock(*point.GetContainer())) {
|
if (RefPtr<Element> blockElement = GetBlock(*point.GetContainer())) {
|
||||||
if (IsEditable(blockElement) && IsEmptyNode(*blockElement, false, false) &&
|
if (blockElement &&
|
||||||
|
EditorUtils::IsEditableContent(*blockElement, EditorType::HTML) &&
|
||||||
|
IsEmptyNode(*blockElement, false, false) &&
|
||||||
CanContainTag(*point.GetContainer(), *nsGkAtoms::br)) {
|
CanContainTag(*point.GetContainer(), *nsGkAtoms::br)) {
|
||||||
Element* bodyOrDocumentElement = GetRoot();
|
Element* bodyOrDocumentElement = GetRoot();
|
||||||
if (NS_WARN_IF(!bodyOrDocumentElement)) {
|
if (NS_WARN_IF(!bodyOrDocumentElement)) {
|
||||||
|
@ -10501,7 +10515,8 @@ nsresult HTMLEditor::RemoveEmptyNodesIn(nsRange& aRange) {
|
||||||
|
|
||||||
// now delete the empty nodes
|
// now delete the empty nodes
|
||||||
for (OwningNonNull<nsIContent>& emptyContent : arrayOfEmptyContents) {
|
for (OwningNonNull<nsIContent>& emptyContent : arrayOfEmptyContents) {
|
||||||
if (IsModifiableNode(emptyContent)) {
|
// XXX Shouldn't we check whether it's removable from its parent??
|
||||||
|
if (HTMLEditUtils::IsSimplyEditableNode(emptyContent)) {
|
||||||
// MOZ_KnownLive because 'arrayOfEmptyContents' is guaranteed to keep it
|
// MOZ_KnownLive because 'arrayOfEmptyContents' is guaranteed to keep it
|
||||||
// alive.
|
// alive.
|
||||||
rv = DeleteNodeWithTransaction(MOZ_KnownLive(emptyContent));
|
rv = DeleteNodeWithTransaction(MOZ_KnownLive(emptyContent));
|
||||||
|
@ -11380,7 +11395,7 @@ nsresult HTMLEditor::MoveSelectedContentsToDivElementToMakeItAbsolutePosition(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ignore all non-editable nodes. Leave them be.
|
// Ignore all non-editable nodes. Leave them be.
|
||||||
if (!IsEditable(content)) {
|
if (!EditorUtils::IsEditableContent(content, EditorType::HTML)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,11 +14,31 @@ class nsAtom;
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
|
|
||||||
|
enum class EditAction;
|
||||||
|
|
||||||
class HTMLEditUtils final {
|
class HTMLEditUtils final {
|
||||||
using Element = dom::Element;
|
using Element = dom::Element;
|
||||||
using Selection = dom::Selection;
|
using Selection = dom::Selection;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
/**
|
||||||
|
* IsSimplyEditableNode() returns true when aNode is simply editable.
|
||||||
|
* This does NOT means that aNode can be removed from current parent nor
|
||||||
|
* aNode's data is editable.
|
||||||
|
*/
|
||||||
|
static bool IsSimplyEditableNode(const nsINode& aNode) {
|
||||||
|
return aNode.IsEditable();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IsRemovableFromParentNode() returns true when aContent is editable, has a
|
||||||
|
* parent node and the parent node is also editable.
|
||||||
|
*/
|
||||||
|
static bool IsRemovableFromParentNode(const nsIContent& aContent) {
|
||||||
|
return aContent.IsEditable() && aContent.GetParentNode() &&
|
||||||
|
aContent.GetParentNode()->IsEditable();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* IsBlockElement() returns true if aContent is an element and it should
|
* IsBlockElement() returns true if aContent is an element and it should
|
||||||
* be treated as a block. (This does not refer style information.)
|
* be treated as a block. (This does not refer style information.)
|
||||||
|
|
|
@ -1841,7 +1841,9 @@ EditorDOMPoint HTMLEditor::InsertNodeIntoProperAncestorWithTransaction(
|
||||||
return EditorDOMPoint();
|
return EditorDOMPoint();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IsEditable(pointToInsert.GetContainer())) {
|
if (!pointToInsert.IsInContentNode() ||
|
||||||
|
!EditorUtils::IsEditableContent(*pointToInsert.ContainerAsContent(),
|
||||||
|
EditorType::HTML)) {
|
||||||
// There's no suitable place to put the node in this editing host. Maybe
|
// There's no suitable place to put the node in this editing host. Maybe
|
||||||
// someone is trying to put block content in a span. So just put it
|
// someone is trying to put block content in a span. So just put it
|
||||||
// where we were originally asked.
|
// where we were originally asked.
|
||||||
|
@ -3365,18 +3367,15 @@ nsresult HTMLEditor::DeleteSelectionWithTransaction(
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult HTMLEditor::DeleteNodeWithTransaction(nsINode& aNode) {
|
nsresult HTMLEditor::DeleteNodeWithTransaction(nsIContent& aContent) {
|
||||||
if (NS_WARN_IF(!aNode.IsContent())) {
|
|
||||||
return NS_ERROR_INVALID_ARG;
|
|
||||||
}
|
|
||||||
// Do nothing if the node is read-only.
|
// Do nothing if the node is read-only.
|
||||||
// XXX This is not a override method of EditorBase's method. This might
|
// XXX This is not a override method of EditorBase's method. This might
|
||||||
// cause not called accidentally. We need to investigate this issue.
|
// cause not called accidentally. We need to investigate this issue.
|
||||||
if (NS_WARN_IF(!IsModifiableNode(*aNode.AsContent()) &&
|
if (NS_WARN_IF(!HTMLEditUtils::IsSimplyEditableNode(aContent) &&
|
||||||
!EditorBase::IsPaddingBRElementForEmptyEditor(aNode))) {
|
!EditorUtils::IsPaddingBRElementForEmptyEditor(aContent))) {
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
nsresult rv = EditorBase::DeleteNodeWithTransaction(aNode);
|
nsresult rv = EditorBase::DeleteNodeWithTransaction(aContent);
|
||||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
|
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
|
||||||
"EditorBase::DeleteNodeWithTransaction() failed");
|
"EditorBase::DeleteNodeWithTransaction() failed");
|
||||||
return rv;
|
return rv;
|
||||||
|
@ -3396,7 +3395,7 @@ nsresult HTMLEditor::DeleteAllChildrenWithTransaction(Element& aElement) {
|
||||||
!ignoredError.Failed(),
|
!ignoredError.Failed(),
|
||||||
"OnStartToHandleTopLevelEditSubAction() failed, but ignored");
|
"OnStartToHandleTopLevelEditSubAction() failed, but ignored");
|
||||||
|
|
||||||
while (nsCOMPtr<nsINode> child = aElement.GetLastChild()) {
|
while (nsCOMPtr<nsIContent> child = aElement.GetLastChild()) {
|
||||||
nsresult rv = DeleteNodeWithTransaction(*child);
|
nsresult rv = DeleteNodeWithTransaction(*child);
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
NS_WARNING("HTMLEditor::DeleteNodeWithTransaction() failed");
|
NS_WARNING("HTMLEditor::DeleteNodeWithTransaction() failed");
|
||||||
|
@ -3510,7 +3509,7 @@ nsresult HTMLEditor::DeleteParentBlocksWithTransactionIfEmpty(
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP HTMLEditor::DeleteNode(nsINode* aNode) {
|
NS_IMETHODIMP HTMLEditor::DeleteNode(nsINode* aNode) {
|
||||||
if (NS_WARN_IF(!aNode)) {
|
if (NS_WARN_IF(!aNode) || NS_WARN_IF(!aNode->IsContent())) {
|
||||||
return NS_ERROR_INVALID_ARG;
|
return NS_ERROR_INVALID_ARG;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3522,7 +3521,7 @@ NS_IMETHODIMP HTMLEditor::DeleteNode(nsINode* aNode) {
|
||||||
return EditorBase::ToGenericNSResult(rv);
|
return EditorBase::ToGenericNSResult(rv);
|
||||||
}
|
}
|
||||||
|
|
||||||
rv = DeleteNodeWithTransaction(*aNode);
|
rv = DeleteNodeWithTransaction(MOZ_KnownLive(*aNode->AsContent()));
|
||||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
|
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
|
||||||
"HTMLEditor::DeleteNodeWithTransaction() failed");
|
"HTMLEditor::DeleteNodeWithTransaction() failed");
|
||||||
return rv;
|
return rv;
|
||||||
|
@ -3531,7 +3530,7 @@ NS_IMETHODIMP HTMLEditor::DeleteNode(nsINode* aNode) {
|
||||||
nsresult HTMLEditor::DeleteTextWithTransaction(Text& aTextNode,
|
nsresult HTMLEditor::DeleteTextWithTransaction(Text& aTextNode,
|
||||||
uint32_t aOffset,
|
uint32_t aOffset,
|
||||||
uint32_t aLength) {
|
uint32_t aLength) {
|
||||||
if (NS_WARN_IF(!IsModifiableNode(aTextNode))) {
|
if (NS_WARN_IF(!HTMLEditUtils::IsSimplyEditableNode(aTextNode))) {
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3551,7 +3550,8 @@ nsresult HTMLEditor::InsertTextWithTransaction(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do nothing if the node is read-only
|
// Do nothing if the node is read-only
|
||||||
if (NS_WARN_IF(!IsModifiableNode(*aPointToInsert.GetContainer()))) {
|
if (NS_WARN_IF(!HTMLEditUtils::IsSimplyEditableNode(
|
||||||
|
*aPointToInsert.GetContainer()))) {
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3694,7 +3694,7 @@ void HTMLEditor::DoContentInserted(nsIContent* aChild,
|
||||||
}
|
}
|
||||||
// We don't need to handle our own modifications
|
// We don't need to handle our own modifications
|
||||||
else if (!GetTopLevelEditSubAction() && container->IsEditable()) {
|
else if (!GetTopLevelEditSubAction() && container->IsEditable()) {
|
||||||
if (EditorBase::IsPaddingBRElementForEmptyEditor(*aChild)) {
|
if (EditorUtils::IsPaddingBRElementForEmptyEditor(*aChild)) {
|
||||||
// Ignore insertion of the padding <br> element.
|
// Ignore insertion of the padding <br> element.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -3747,7 +3747,7 @@ MOZ_CAN_RUN_SCRIPT_BOUNDARY void HTMLEditor::ContentRemoved(
|
||||||
// We don't need to handle our own modifications
|
// We don't need to handle our own modifications
|
||||||
} else if (!GetTopLevelEditSubAction() &&
|
} else if (!GetTopLevelEditSubAction() &&
|
||||||
aChild->GetParentNode()->IsEditable()) {
|
aChild->GetParentNode()->IsEditable()) {
|
||||||
if (aChild && EditorBase::IsPaddingBRElementForEmptyEditor(*aChild)) {
|
if (aChild && EditorUtils::IsPaddingBRElementForEmptyEditor(*aChild)) {
|
||||||
// Ignore removal of the padding <br> element for empty editor.
|
// Ignore removal of the padding <br> element for empty editor.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -3958,10 +3958,11 @@ nsresult HTMLEditor::CollapseAdjacentTextNodes(nsRange& aInRange) {
|
||||||
}
|
}
|
||||||
AutoTArray<OwningNonNull<Text>, 8> textNodes;
|
AutoTArray<OwningNonNull<Text>, 8> textNodes;
|
||||||
subtreeIter.AppendNodesToArray(
|
subtreeIter.AppendNodesToArray(
|
||||||
+[](nsINode& aNode, void* aSelf) -> bool {
|
+[](nsINode& aNode, void*) -> bool {
|
||||||
return static_cast<HTMLEditor*>(aSelf)->IsEditable(&aNode);
|
return EditorUtils::IsEditableContent(*aNode.AsText(),
|
||||||
|
EditorType::HTML);
|
||||||
},
|
},
|
||||||
textNodes, this);
|
textNodes);
|
||||||
|
|
||||||
// now that I have a list of text nodes, collapse adjacent text nodes
|
// now that I have a list of text nodes, collapse adjacent text nodes
|
||||||
// NOTE: assumption that JoinNodes keeps the righthand node
|
// NOTE: assumption that JoinNodes keeps the righthand node
|
||||||
|
@ -4108,24 +4109,28 @@ nsIContent* HTMLEditor::GetPriorHTMLSibling(nsINode* aNode,
|
||||||
SkipWhitespace aSkipWS) const {
|
SkipWhitespace aSkipWS) const {
|
||||||
MOZ_ASSERT(aNode);
|
MOZ_ASSERT(aNode);
|
||||||
|
|
||||||
nsIContent* node = aNode->GetPreviousSibling();
|
nsIContent* content = aNode->GetPreviousSibling();
|
||||||
while (node && (!IsEditable(node) || SkippableWhitespace(node, aSkipWS))) {
|
while (content &&
|
||||||
node = node->GetPreviousSibling();
|
(!EditorUtils::IsEditableContent(*content, EditorType::HTML) ||
|
||||||
|
SkippableWhitespace(content, aSkipWS))) {
|
||||||
|
content = content->GetPreviousSibling();
|
||||||
}
|
}
|
||||||
|
|
||||||
return node;
|
return content;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsIContent* HTMLEditor::GetNextHTMLSibling(nsINode* aNode,
|
nsIContent* HTMLEditor::GetNextHTMLSibling(nsINode* aNode,
|
||||||
SkipWhitespace aSkipWS) const {
|
SkipWhitespace aSkipWS) const {
|
||||||
MOZ_ASSERT(aNode);
|
MOZ_ASSERT(aNode);
|
||||||
|
|
||||||
nsIContent* node = aNode->GetNextSibling();
|
nsIContent* content = aNode->GetNextSibling();
|
||||||
while (node && (!IsEditable(node) || SkippableWhitespace(node, aSkipWS))) {
|
while (content &&
|
||||||
node = node->GetNextSibling();
|
(!EditorUtils::IsEditableContent(*content, EditorType::HTML) ||
|
||||||
|
SkippableWhitespace(content, aSkipWS))) {
|
||||||
|
content = content->GetNextSibling();
|
||||||
}
|
}
|
||||||
|
|
||||||
return node;
|
return content;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsIContent* HTMLEditor::GetPreviousHTMLElementOrTextInternal(
|
nsIContent* HTMLEditor::GetPreviousHTMLElementOrTextInternal(
|
||||||
|
@ -4225,28 +4230,25 @@ bool HTMLEditor::IsLastEditableChild(nsINode* aNode) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
nsIContent* HTMLEditor::GetFirstEditableChild(nsINode& aNode) const {
|
nsIContent* HTMLEditor::GetFirstEditableChild(nsINode& aNode) const {
|
||||||
nsCOMPtr<nsIContent> child = aNode.GetFirstChild();
|
nsIContent* child = aNode.GetFirstChild();
|
||||||
|
while (child && !EditorUtils::IsEditableContent(*child, EditorType::HTML)) {
|
||||||
while (child && !IsEditable(child)) {
|
|
||||||
child = child->GetNextSibling();
|
child = child->GetNextSibling();
|
||||||
}
|
}
|
||||||
|
|
||||||
return child;
|
return child;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsIContent* HTMLEditor::GetLastEditableChild(nsINode& aNode) const {
|
nsIContent* HTMLEditor::GetLastEditableChild(nsINode& aNode) const {
|
||||||
nsCOMPtr<nsIContent> child = aNode.GetLastChild();
|
nsIContent* child = aNode.GetLastChild();
|
||||||
|
while (child && !EditorUtils::IsEditableContent(*child, EditorType::HTML)) {
|
||||||
while (child && !IsEditable(child)) {
|
|
||||||
child = child->GetPreviousSibling();
|
child = child->GetPreviousSibling();
|
||||||
}
|
}
|
||||||
|
|
||||||
return child;
|
return child;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsIContent* HTMLEditor::GetFirstEditableLeaf(nsINode& aNode) const {
|
nsIContent* HTMLEditor::GetFirstEditableLeaf(nsINode& aNode) const {
|
||||||
nsCOMPtr<nsIContent> child = GetLeftmostChild(&aNode);
|
nsIContent* child = GetLeftmostChild(&aNode);
|
||||||
while (child && (!IsEditable(child) || child->HasChildren())) {
|
while (child && (!EditorUtils::IsEditableContent(*child, EditorType::HTML) ||
|
||||||
|
child->HasChildren())) {
|
||||||
child = GetNextEditableHTMLNode(*child);
|
child = GetNextEditableHTMLNode(*child);
|
||||||
|
|
||||||
// Only accept nodes that are descendants of aNode
|
// Only accept nodes that are descendants of aNode
|
||||||
|
@ -4260,7 +4262,8 @@ nsIContent* HTMLEditor::GetFirstEditableLeaf(nsINode& aNode) const {
|
||||||
|
|
||||||
nsIContent* HTMLEditor::GetLastEditableLeaf(nsINode& aNode) const {
|
nsIContent* HTMLEditor::GetLastEditableLeaf(nsINode& aNode) const {
|
||||||
nsCOMPtr<nsIContent> child = GetRightmostChild(&aNode, false);
|
nsCOMPtr<nsIContent> child = GetRightmostChild(&aNode, false);
|
||||||
while (child && (!IsEditable(child) || child->HasChildren())) {
|
while (child && (!EditorUtils::IsEditableContent(*child, EditorType::HTML) ||
|
||||||
|
child->HasChildren())) {
|
||||||
child = GetPreviousEditableHTMLNode(*child);
|
child = GetPreviousEditableHTMLNode(*child);
|
||||||
|
|
||||||
// Only accept nodes that are descendants of aNode
|
// Only accept nodes that are descendants of aNode
|
||||||
|
@ -4370,7 +4373,7 @@ bool HTMLEditor::IsEmptyNodeImpl(nsINode& aNode, bool aSingleBRDoesntCount,
|
||||||
for (nsCOMPtr<nsIContent> child = aNode.GetFirstChild(); child;
|
for (nsCOMPtr<nsIContent> child = aNode.GetFirstChild(); child;
|
||||||
child = child->GetNextSibling()) {
|
child = child->GetNextSibling()) {
|
||||||
// Is the child editable and non-empty? if so, return false
|
// Is the child editable and non-empty? if so, return false
|
||||||
if (EditorBase::IsEditable(child)) {
|
if (EditorUtils::IsEditableContent(*child, EditorType::HTML)) {
|
||||||
if (Text* text = child->GetAsText()) {
|
if (Text* text = child->GetAsText()) {
|
||||||
// break out if we find we aren't empty
|
// break out if we find we aren't empty
|
||||||
if (!(aSafeToAskFrames ? !IsInVisibleTextFrames(*text)
|
if (!(aSafeToAskFrames ? !IsInVisibleTextFrames(*text)
|
||||||
|
@ -4690,7 +4693,8 @@ nsresult HTMLEditor::SetCSSBackgroundColorWithTransaction(
|
||||||
if (NS_WARN_IF(!node)) {
|
if (NS_WARN_IF(!node)) {
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
if (node->IsContent() && IsEditable(node)) {
|
if (node->IsContent() && EditorUtils::IsEditableContent(
|
||||||
|
*node->AsContent(), EditorType::HTML)) {
|
||||||
arrayOfContents.AppendElement(*node->AsContent());
|
arrayOfContents.AppendElement(*node->AsContent());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4702,7 +4706,8 @@ nsresult HTMLEditor::SetCSSBackgroundColorWithTransaction(
|
||||||
// If start node is a text node, set background color of its parent
|
// If start node is a text node, set background color of its parent
|
||||||
// block.
|
// block.
|
||||||
if (startOfRange.IsInTextNode() &&
|
if (startOfRange.IsInTextNode() &&
|
||||||
IsEditable(startOfRange.GetContainer())) {
|
EditorUtils::IsEditableContent(*startOfRange.ContainerAsText(),
|
||||||
|
EditorType::HTML)) {
|
||||||
RefPtr<Element> blockParent =
|
RefPtr<Element> blockParent =
|
||||||
GetBlockNodeParent(startOfRange.GetContainer());
|
GetBlockNodeParent(startOfRange.GetContainer());
|
||||||
if (blockParent && handledBlockParent != blockParent) {
|
if (blockParent && handledBlockParent != blockParent) {
|
||||||
|
@ -4731,7 +4736,9 @@ nsresult HTMLEditor::SetCSSBackgroundColorWithTransaction(
|
||||||
|
|
||||||
// Finally, if end node is a text node, set background color of its
|
// Finally, if end node is a text node, set background color of its
|
||||||
// parent block.
|
// parent block.
|
||||||
if (endOfRange.IsInTextNode() && IsEditable(endOfRange.GetContainer())) {
|
if (endOfRange.IsInTextNode() &&
|
||||||
|
EditorUtils::IsEditableContent(*endOfRange.ContainerAsText(),
|
||||||
|
EditorType::HTML)) {
|
||||||
RefPtr<Element> blockParent =
|
RefPtr<Element> blockParent =
|
||||||
GetBlockNodeParent(endOfRange.GetContainer());
|
GetBlockNodeParent(endOfRange.GetContainer());
|
||||||
if (blockParent && handledBlockParent != blockParent) {
|
if (blockParent && handledBlockParent != blockParent) {
|
||||||
|
@ -4801,7 +4808,7 @@ nsresult HTMLEditor::CopyLastEditableChildStylesWithTransaction(
|
||||||
|
|
||||||
// First, clear out aNewBlock. Contract is that we want only the styles
|
// First, clear out aNewBlock. Contract is that we want only the styles
|
||||||
// from aPreviousBlock.
|
// from aPreviousBlock.
|
||||||
for (nsCOMPtr<nsINode> child = newBlock->GetFirstChild(); child;
|
for (nsCOMPtr<nsIContent> child = newBlock->GetFirstChild(); child;
|
||||||
child = newBlock->GetFirstChild()) {
|
child = newBlock->GetFirstChild()) {
|
||||||
nsresult rv = DeleteNodeWithTransaction(*child);
|
nsresult rv = DeleteNodeWithTransaction(*child);
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include "mozilla/Attributes.h"
|
#include "mozilla/Attributes.h"
|
||||||
#include "mozilla/ComposerCommandsUpdater.h"
|
#include "mozilla/ComposerCommandsUpdater.h"
|
||||||
#include "mozilla/CSSEditUtils.h"
|
#include "mozilla/CSSEditUtils.h"
|
||||||
|
#include "mozilla/EditorUtils.h"
|
||||||
#include "mozilla/ManualNAC.h"
|
#include "mozilla/ManualNAC.h"
|
||||||
#include "mozilla/StyleSheet.h"
|
#include "mozilla/StyleSheet.h"
|
||||||
#include "mozilla/TextEditor.h"
|
#include "mozilla/TextEditor.h"
|
||||||
|
@ -685,13 +686,13 @@ class HTMLEditor final : public TextEditor,
|
||||||
EDirection aAction, EStripWrappers aStripWrappers) override;
|
EDirection aAction, EStripWrappers aStripWrappers) override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DeleteNodeWithTransaction() removes aNode from the DOM tree if it's
|
* DeleteNodeWithTransaction() removes aContent from the DOM tree if it's
|
||||||
* modifiable. Note that this is not an override of same method of
|
* modifiable. Note that this is not an override of same method of
|
||||||
* EditorBase.
|
* EditorBase.
|
||||||
*
|
*
|
||||||
* @param aNode The node to be removed from the DOM tree.
|
* @param aContent The node to be removed from the DOM tree.
|
||||||
*/
|
*/
|
||||||
MOZ_CAN_RUN_SCRIPT nsresult DeleteNodeWithTransaction(nsINode& aNode);
|
MOZ_CAN_RUN_SCRIPT nsresult DeleteNodeWithTransaction(nsIContent& aContent);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DeleteTextWithTransaction() removes text in the range from aTextNode if
|
* DeleteTextWithTransaction() removes text in the range from aTextNode if
|
||||||
|
@ -759,7 +760,6 @@ class HTMLEditor final : public TextEditor,
|
||||||
RemoveBlockContainerWithTransaction(Element& aElement);
|
RemoveBlockContainerWithTransaction(Element& aElement);
|
||||||
|
|
||||||
virtual Element* GetEditorRoot() const override;
|
virtual Element* GetEditorRoot() const override;
|
||||||
using EditorBase::IsEditable;
|
|
||||||
MOZ_CAN_RUN_SCRIPT virtual nsresult RemoveAttributeOrEquivalent(
|
MOZ_CAN_RUN_SCRIPT virtual nsresult RemoveAttributeOrEquivalent(
|
||||||
Element* aElement, nsAtom* aAttribute,
|
Element* aElement, nsAtom* aAttribute,
|
||||||
bool aSuppressTransaction) override;
|
bool aSuppressTransaction) override;
|
||||||
|
@ -1685,8 +1685,8 @@ class HTMLEditor final : public TextEditor,
|
||||||
}
|
}
|
||||||
|
|
||||||
bool brElementHasFound = false;
|
bool brElementHasFound = false;
|
||||||
for (auto& content : aArrayOfContents) {
|
for (OwningNonNull<nsIContent>& content : aArrayOfContents) {
|
||||||
if (!IsEditable(content)) {
|
if (!EditorUtils::IsEditableContent(content, EditorType::HTML)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (content->IsHTMLElement(nsGkAtoms::br)) {
|
if (content->IsHTMLElement(nsGkAtoms::br)) {
|
||||||
|
@ -2015,11 +2015,11 @@ class HTMLEditor final : public TextEditor,
|
||||||
SelectAllOfCurrentList aSelectAllOfCurrentList);
|
SelectAllOfCurrentList aSelectAllOfCurrentList);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If aNode is a text node that contains only collapsed whitespace or empty
|
* If aContent is a text node that contains only collapsed whitespace or empty
|
||||||
* and editable.
|
* and editable.
|
||||||
*/
|
*/
|
||||||
[[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
|
[[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
|
||||||
DeleteNodeIfInvisibleAndEditableTextNode(nsINode& aNode);
|
DeleteNodeIfInvisibleAndEditableTextNode(nsIContent& aContent);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If aPoint follows invisible `<br>` element, returns the invisible `<br>`
|
* If aPoint follows invisible `<br>` element, returns the invisible `<br>`
|
||||||
|
@ -4675,6 +4675,8 @@ class MOZ_STACK_CLASS ParagraphStateAtSelection final {
|
||||||
bool IsMixed() const { return mIsMixed; }
|
bool IsMixed() const { return mIsMixed; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
using EditorType = EditorBase::EditorType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* AppendDescendantFormatNodesAndFirstInlineNode() appends descendant
|
* AppendDescendantFormatNodesAndFirstInlineNode() appends descendant
|
||||||
* format blocks and first inline child node in aNonFormatBlockElement to
|
* format blocks and first inline child node in aNonFormatBlockElement to
|
||||||
|
@ -4708,13 +4710,13 @@ class MOZ_STACK_CLASS ParagraphStateAtSelection final {
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|
||||||
mozilla::HTMLEditor* nsIEditor::AsHTMLEditor() {
|
mozilla::HTMLEditor* nsIEditor::AsHTMLEditor() {
|
||||||
return static_cast<mozilla::EditorBase*>(this)->mIsHTMLEditorClass
|
return static_cast<mozilla::EditorBase*>(this)->IsHTMLEditor()
|
||||||
? static_cast<mozilla::HTMLEditor*>(this)
|
? static_cast<mozilla::HTMLEditor*>(this)
|
||||||
: nullptr;
|
: nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
const mozilla::HTMLEditor* nsIEditor::AsHTMLEditor() const {
|
const mozilla::HTMLEditor* nsIEditor::AsHTMLEditor() const {
|
||||||
return static_cast<const mozilla::EditorBase*>(this)->mIsHTMLEditorClass
|
return static_cast<const mozilla::EditorBase*>(this)->IsHTMLEditor()
|
||||||
? static_cast<const mozilla::HTMLEditor*>(this)
|
? static_cast<const mozilla::HTMLEditor*>(this)
|
||||||
: nullptr;
|
: nullptr;
|
||||||
}
|
}
|
||||||
|
|
|
@ -262,7 +262,8 @@ nsresult HTMLEditor::SetInlinePropertyInternal(
|
||||||
if (NS_WARN_IF(!node)) {
|
if (NS_WARN_IF(!node)) {
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
if (node->IsContent() && IsEditable(node)) {
|
if (node->IsContent() && EditorUtils::IsEditableContent(
|
||||||
|
*node->AsContent(), EditorType::HTML)) {
|
||||||
arrayOfContents.AppendElement(*node->AsContent());
|
arrayOfContents.AppendElement(*node->AsContent());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -270,7 +271,8 @@ nsresult HTMLEditor::SetInlinePropertyInternal(
|
||||||
|
|
||||||
// If start node is a text node, apply new style to a part of it.
|
// If start node is a text node, apply new style to a part of it.
|
||||||
if (startOfRange.IsInTextNode() &&
|
if (startOfRange.IsInTextNode() &&
|
||||||
IsEditable(startOfRange.GetContainer())) {
|
EditorUtils::IsEditableContent(*startOfRange.ContainerAsText(),
|
||||||
|
EditorType::HTML)) {
|
||||||
nsresult rv = SetInlinePropertyOnTextNode(
|
nsresult rv = SetInlinePropertyOnTextNode(
|
||||||
MOZ_KnownLive(*startOfRange.GetContainerAsText()),
|
MOZ_KnownLive(*startOfRange.GetContainerAsText()),
|
||||||
startOfRange.Offset(), startOfRange.GetContainer()->Length(),
|
startOfRange.Offset(), startOfRange.GetContainer()->Length(),
|
||||||
|
@ -297,7 +299,9 @@ nsresult HTMLEditor::SetInlinePropertyInternal(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finally, if end node is a text node, apply new style to a part ot it.
|
// Finally, if end node is a text node, apply new style to a part ot it.
|
||||||
if (endOfRange.IsInTextNode() && IsEditable(endOfRange.GetContainer())) {
|
if (endOfRange.IsInTextNode() &&
|
||||||
|
EditorUtils::IsEditableContent(*endOfRange.GetContainerAsText(),
|
||||||
|
EditorType::HTML)) {
|
||||||
nsresult rv = SetInlinePropertyOnTextNode(
|
nsresult rv = SetInlinePropertyOnTextNode(
|
||||||
MOZ_KnownLive(*endOfRange.GetContainerAsText()), 0,
|
MOZ_KnownLive(*endOfRange.GetContainerAsText()), 0,
|
||||||
endOfRange.Offset(), aProperty, aAttribute, aAttributeValue);
|
endOfRange.Offset(), aProperty, aAttribute, aAttributeValue);
|
||||||
|
@ -497,7 +501,8 @@ nsresult HTMLEditor::SetInlinePropertyOnNodeImpl(nsIContent& aContent,
|
||||||
// Populate the list.
|
// Populate the list.
|
||||||
for (nsCOMPtr<nsIContent> child = aContent.GetFirstChild(); child;
|
for (nsCOMPtr<nsIContent> child = aContent.GetFirstChild(); child;
|
||||||
child = child->GetNextSibling()) {
|
child = child->GetNextSibling()) {
|
||||||
if (IsEditable(child) && !IsEmptyTextNode(*child)) {
|
if (EditorUtils::IsEditableContent(*child, EditorType::HTML) &&
|
||||||
|
!IsEmptyTextNode(*child)) {
|
||||||
arrayOfNodes.AppendElement(*child);
|
arrayOfNodes.AppendElement(*child);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -649,7 +654,7 @@ nsresult HTMLEditor::SetInlinePropertyOnNode(nsIContent& aNode,
|
||||||
for (nsIContent* content = previousSibling ? previousSibling->GetNextSibling()
|
for (nsIContent* content = previousSibling ? previousSibling->GetNextSibling()
|
||||||
: parent->GetFirstChild();
|
: parent->GetFirstChild();
|
||||||
content && content != nextSibling; content = content->GetNextSibling()) {
|
content && content != nextSibling; content = content->GetNextSibling()) {
|
||||||
if (IsEditable(content)) {
|
if (EditorUtils::IsEditableContent(*content, EditorType::HTML)) {
|
||||||
nodesToSet.AppendElement(*content);
|
nodesToSet.AppendElement(*content);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -751,7 +756,8 @@ SplitNodeResult HTMLEditor::SplitAncestorStyledInlineElementsAt(
|
||||||
for (nsIContent* content :
|
for (nsIContent* content :
|
||||||
InclusiveAncestorsOfType<nsIContent>(*aPointToSplit.GetContainer())) {
|
InclusiveAncestorsOfType<nsIContent>(*aPointToSplit.GetContainer())) {
|
||||||
if (HTMLEditUtils::IsBlockElement(*content) || !content->GetParent() ||
|
if (HTMLEditUtils::IsBlockElement(*content) || !content->GetParent() ||
|
||||||
!IsEditable(content->GetParent())) {
|
!EditorUtils::IsEditableContent(*content->GetParent(),
|
||||||
|
EditorType::HTML)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
arrayOfParents.AppendElement(*content);
|
arrayOfParents.AppendElement(*content);
|
||||||
|
@ -787,7 +793,7 @@ SplitNodeResult HTMLEditor::SplitAncestorStyledInlineElementsAt(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// If aProperty is nullptr, we need to split any style.
|
// If aProperty is nullptr, we need to split any style.
|
||||||
else if (!IsEditable(content) ||
|
else if (!EditorUtils::IsEditableContent(content, EditorType::HTML) ||
|
||||||
!HTMLEditUtils::IsRemovableInlineStyleElement(
|
!HTMLEditUtils::IsRemovableInlineStyleElement(
|
||||||
*content->AsElement())) {
|
*content->AsElement())) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -1009,7 +1015,7 @@ nsresult HTMLEditor::RemoveStyleInside(Element& aElement, nsAtom* aProperty,
|
||||||
}
|
}
|
||||||
// XXX Why do we check if aElement is editable only when aProperty is
|
// XXX Why do we check if aElement is editable only when aProperty is
|
||||||
// nullptr?
|
// nullptr?
|
||||||
else if (IsEditable(&aElement)) {
|
else if (EditorUtils::IsEditableContent(aElement, EditorType::HTML)) {
|
||||||
// or removing all styles and the element is a presentation element.
|
// or removing all styles and the element is a presentation element.
|
||||||
removeHTMLStyle = HTMLEditUtils::IsRemovableInlineStyleElement(aElement);
|
removeHTMLStyle = HTMLEditUtils::IsRemovableInlineStyleElement(aElement);
|
||||||
}
|
}
|
||||||
|
@ -1231,7 +1237,8 @@ nsresult HTMLEditor::PromoteInlineRange(nsRange& aRange) {
|
||||||
for (nsIContent* content :
|
for (nsIContent* content :
|
||||||
InclusiveAncestorsOfType<nsIContent>(*aRange.GetStartContainer())) {
|
InclusiveAncestorsOfType<nsIContent>(*aRange.GetStartContainer())) {
|
||||||
MOZ_ASSERT(newRangeStart.GetContainer() == content);
|
MOZ_ASSERT(newRangeStart.GetContainer() == content);
|
||||||
if (content->IsHTMLElement(nsGkAtoms::body) || !IsEditable(content) ||
|
if (content->IsHTMLElement(nsGkAtoms::body) ||
|
||||||
|
!EditorUtils::IsEditableContent(*content, EditorType::HTML) ||
|
||||||
!IsStartOfContainerOrBeforeFirstEditableChild(newRangeStart)) {
|
!IsStartOfContainerOrBeforeFirstEditableChild(newRangeStart)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1248,7 +1255,8 @@ nsresult HTMLEditor::PromoteInlineRange(nsRange& aRange) {
|
||||||
for (nsIContent* content :
|
for (nsIContent* content :
|
||||||
InclusiveAncestorsOfType<nsIContent>(*aRange.GetEndContainer())) {
|
InclusiveAncestorsOfType<nsIContent>(*aRange.GetEndContainer())) {
|
||||||
MOZ_ASSERT(newRangeEnd.GetContainer() == content);
|
MOZ_ASSERT(newRangeEnd.GetContainer() == content);
|
||||||
if (content->IsHTMLElement(nsGkAtoms::body) || !IsEditable(content) ||
|
if (content->IsHTMLElement(nsGkAtoms::body) ||
|
||||||
|
!EditorUtils::IsEditableContent(*content, EditorType::HTML) ||
|
||||||
!IsEndOfContainerOrEqualsOrAfterLastEditableChild(newRangeEnd)) {
|
!IsEndOfContainerOrEqualsOrAfterLastEditableChild(newRangeEnd)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1399,8 +1407,9 @@ nsresult HTMLEditor::GetInlinePropertyBase(nsAtom& aHTMLProperty,
|
||||||
}
|
}
|
||||||
|
|
||||||
// just ignore any non-editable nodes
|
// just ignore any non-editable nodes
|
||||||
if (content->GetAsText() &&
|
if (content->IsText() &&
|
||||||
(!IsEditable(content) || IsEmptyTextNode(*content))) {
|
(!EditorUtils::IsEditableContent(*content, EditorType::HTML) ||
|
||||||
|
IsEmptyTextNode(*content))) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (content->GetAsText()) {
|
if (content->GetAsText()) {
|
||||||
|
@ -1837,18 +1846,21 @@ nsresult HTMLEditor::RemoveInlinePropertyInternal(
|
||||||
AutoTArray<OwningNonNull<nsIContent>, 64> arrayOfContents;
|
AutoTArray<OwningNonNull<nsIContent>, 64> arrayOfContents;
|
||||||
if (startOfRange.GetContainer() == endOfRange.GetContainer() &&
|
if (startOfRange.GetContainer() == endOfRange.GetContainer() &&
|
||||||
startOfRange.IsInTextNode()) {
|
startOfRange.IsInTextNode()) {
|
||||||
if (!IsEditable(startOfRange.GetContainer())) {
|
if (!EditorUtils::IsEditableContent(*startOfRange.ContainerAsText(),
|
||||||
|
EditorType::HTML)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
arrayOfContents.AppendElement(*startOfRange.GetContainerAsText());
|
arrayOfContents.AppendElement(*startOfRange.ContainerAsText());
|
||||||
} else if (startOfRange.IsInTextNode() && endOfRange.IsInTextNode() &&
|
} else if (startOfRange.IsInTextNode() && endOfRange.IsInTextNode() &&
|
||||||
startOfRange.GetContainer()->GetNextSibling() ==
|
startOfRange.GetContainer()->GetNextSibling() ==
|
||||||
endOfRange.GetContainer()) {
|
endOfRange.GetContainer()) {
|
||||||
if (IsEditable(startOfRange.GetContainer())) {
|
if (EditorUtils::IsEditableContent(*startOfRange.ContainerAsText(),
|
||||||
arrayOfContents.AppendElement(*startOfRange.GetContainerAsText());
|
EditorType::HTML)) {
|
||||||
|
arrayOfContents.AppendElement(*startOfRange.ContainerAsText());
|
||||||
}
|
}
|
||||||
if (IsEditable(endOfRange.GetContainer())) {
|
if (EditorUtils::IsEditableContent(*endOfRange.ContainerAsText(),
|
||||||
arrayOfContents.AppendElement(*endOfRange.GetContainerAsText());
|
EditorType::HTML)) {
|
||||||
|
arrayOfContents.AppendElement(*endOfRange.ContainerAsText());
|
||||||
}
|
}
|
||||||
if (arrayOfContents.IsEmpty()) {
|
if (arrayOfContents.IsEmpty()) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -1857,8 +1869,9 @@ nsresult HTMLEditor::RemoveInlinePropertyInternal(
|
||||||
// Append first node if it's a text node but selected not entirely.
|
// Append first node if it's a text node but selected not entirely.
|
||||||
if (startOfRange.IsInTextNode() &&
|
if (startOfRange.IsInTextNode() &&
|
||||||
!startOfRange.IsStartOfContainer() &&
|
!startOfRange.IsStartOfContainer() &&
|
||||||
IsEditable(startOfRange.GetContainer())) {
|
EditorUtils::IsEditableContent(*startOfRange.ContainerAsText(),
|
||||||
arrayOfContents.AppendElement(*startOfRange.GetContainerAsText());
|
EditorType::HTML)) {
|
||||||
|
arrayOfContents.AppendElement(*startOfRange.ContainerAsText());
|
||||||
}
|
}
|
||||||
// Append all entirely selected nodes.
|
// Append all entirely selected nodes.
|
||||||
ContentSubtreeIterator subtreeIter;
|
ContentSubtreeIterator subtreeIter;
|
||||||
|
@ -1868,7 +1881,9 @@ nsresult HTMLEditor::RemoveInlinePropertyInternal(
|
||||||
if (NS_WARN_IF(!node)) {
|
if (NS_WARN_IF(!node)) {
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
if (node->IsContent() && IsEditable(node)) {
|
if (node->IsContent() &&
|
||||||
|
EditorUtils::IsEditableContent(*node->AsContent(),
|
||||||
|
EditorType::HTML)) {
|
||||||
arrayOfContents.AppendElement(*node->AsContent());
|
arrayOfContents.AppendElement(*node->AsContent());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1876,8 +1891,9 @@ nsresult HTMLEditor::RemoveInlinePropertyInternal(
|
||||||
// Append last node if it's a text node but selected not entirely.
|
// Append last node if it's a text node but selected not entirely.
|
||||||
if (startOfRange.GetContainer() != endOfRange.GetContainer() &&
|
if (startOfRange.GetContainer() != endOfRange.GetContainer() &&
|
||||||
endOfRange.IsInTextNode() && !endOfRange.IsEndOfContainer() &&
|
endOfRange.IsInTextNode() && !endOfRange.IsEndOfContainer() &&
|
||||||
IsEditable(endOfRange.GetContainer())) {
|
EditorUtils::IsEditableContent(*endOfRange.ContainerAsText(),
|
||||||
arrayOfContents.AppendElement(*endOfRange.GetContainerAsText());
|
EditorType::HTML)) {
|
||||||
|
arrayOfContents.AppendElement(*endOfRange.ContainerAsText());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2156,25 +2172,25 @@ nsresult HTMLEditor::RelativeFontChange(FontSize aDir) {
|
||||||
// Iterate range and build up array
|
// Iterate range and build up array
|
||||||
ContentSubtreeIterator subtreeIter;
|
ContentSubtreeIterator subtreeIter;
|
||||||
if (NS_SUCCEEDED(subtreeIter.Init(range))) {
|
if (NS_SUCCEEDED(subtreeIter.Init(range))) {
|
||||||
nsTArray<OwningNonNull<nsIContent>> arrayOfNodes;
|
nsTArray<OwningNonNull<nsIContent>> arrayOfContents;
|
||||||
for (; !subtreeIter.IsDone(); subtreeIter.Next()) {
|
for (; !subtreeIter.IsDone(); subtreeIter.Next()) {
|
||||||
if (NS_WARN_IF(!subtreeIter.GetCurrentNode()->IsContent())) {
|
if (NS_WARN_IF(!subtreeIter.GetCurrentNode()->IsContent())) {
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
OwningNonNull<nsIContent> node =
|
OwningNonNull<nsIContent> content =
|
||||||
*subtreeIter.GetCurrentNode()->AsContent();
|
*subtreeIter.GetCurrentNode()->AsContent();
|
||||||
|
|
||||||
if (IsEditable(node)) {
|
if (EditorUtils::IsEditableContent(content, EditorType::HTML)) {
|
||||||
arrayOfNodes.AppendElement(node);
|
arrayOfContents.AppendElement(content);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now that we have the list, do the font size change on each node
|
// Now that we have the list, do the font size change on each node
|
||||||
for (auto& node : arrayOfNodes) {
|
for (OwningNonNull<nsIContent>& content : arrayOfContents) {
|
||||||
// MOZ_KnownLive because 'arrayOfNodes' is guaranteed to keep it
|
// MOZ_KnownLive because 'arrayOfContents' is guaranteed to keep it
|
||||||
// alive.
|
// alive.
|
||||||
nsresult rv = RelativeFontChangeOnNode(
|
nsresult rv = RelativeFontChangeOnNode(
|
||||||
aDir == FontSize::incr ? +1 : -1, MOZ_KnownLive(node));
|
aDir == FontSize::incr ? +1 : -1, MOZ_KnownLive(content));
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
NS_WARNING("HTMLEditor::RelativeFontChangeOnNode() failed");
|
NS_WARNING("HTMLEditor::RelativeFontChangeOnNode() failed");
|
||||||
return rv;
|
return rv;
|
||||||
|
@ -2184,18 +2200,21 @@ nsresult HTMLEditor::RelativeFontChange(FontSize aDir) {
|
||||||
// Now check the start and end parents of the range to see if they need
|
// Now check the start and end parents of the range to see if they need
|
||||||
// to be separately handled (they do if they are text nodes, due to how
|
// to be separately handled (they do if they are text nodes, due to how
|
||||||
// the subtree iterator works - it will not have reported them).
|
// the subtree iterator works - it will not have reported them).
|
||||||
if (IsTextNode(startNode) && IsEditable(startNode)) {
|
if (IsTextNode(startNode) &&
|
||||||
|
EditorUtils::IsEditableContent(*startNode->AsText(),
|
||||||
|
EditorType::HTML)) {
|
||||||
nsresult rv = RelativeFontChangeOnTextNode(
|
nsresult rv = RelativeFontChangeOnTextNode(
|
||||||
aDir, MOZ_KnownLive(*startNode->GetAsText()), range->StartOffset(),
|
aDir, MOZ_KnownLive(*startNode->AsText()), range->StartOffset(),
|
||||||
startNode->Length());
|
startNode->Length());
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
NS_WARNING("HTMLEditor::RelativeFontChangeOnTextNode() failed");
|
NS_WARNING("HTMLEditor::RelativeFontChangeOnTextNode() failed");
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (IsTextNode(endNode) && IsEditable(endNode)) {
|
if (IsTextNode(endNode) && EditorUtils::IsEditableContent(
|
||||||
|
*endNode->AsText(), EditorType::HTML)) {
|
||||||
nsresult rv = RelativeFontChangeOnTextNode(
|
nsresult rv = RelativeFontChangeOnTextNode(
|
||||||
aDir, MOZ_KnownLive(*endNode->GetAsText()), 0, range->EndOffset());
|
aDir, MOZ_KnownLive(*endNode->AsText()), 0, range->EndOffset());
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
NS_WARNING("HTMLEditor::RelativeFontChangeOnTextNode() failed");
|
NS_WARNING("HTMLEditor::RelativeFontChangeOnTextNode() failed");
|
||||||
return rv;
|
return rv;
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
#include "JoinNodeTransaction.h"
|
#include "JoinNodeTransaction.h"
|
||||||
|
|
||||||
|
#include "HTMLEditUtils.h"
|
||||||
#include "mozilla/EditorBase.h" // for EditorBase
|
#include "mozilla/EditorBase.h" // for EditorBase
|
||||||
#include "mozilla/dom/Text.h"
|
#include "mozilla/dom/Text.h"
|
||||||
#include "nsAString.h"
|
#include "nsAString.h"
|
||||||
|
@ -49,7 +50,8 @@ bool JoinNodeTransaction::CanDoIt() const {
|
||||||
NS_WARN_IF(!mEditorBase) || !mLeftContent->GetParentNode()) {
|
NS_WARN_IF(!mEditorBase) || !mLeftContent->GetParentNode()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return mEditorBase->IsModifiableNode(*mLeftContent->GetParentNode());
|
return mEditorBase->IsTextEditor() ||
|
||||||
|
HTMLEditUtils::IsRemovableFromParentNode(*mLeftContent);
|
||||||
}
|
}
|
||||||
|
|
||||||
// After DoTransaction() and RedoTransaction(), the left node is removed from
|
// After DoTransaction() and RedoTransaction(), the left node is removed from
|
||||||
|
|
|
@ -755,7 +755,7 @@ nsresult TextEditor::DeleteSelectionAsSubAction(EDirection aDirectionAndAmount,
|
||||||
if (atNewStartOfSelection.IsInTextNode() &&
|
if (atNewStartOfSelection.IsInTextNode() &&
|
||||||
!atNewStartOfSelection.GetContainer()->Length()) {
|
!atNewStartOfSelection.GetContainer()->Length()) {
|
||||||
nsresult rv = DeleteNodeWithTransaction(
|
nsresult rv = DeleteNodeWithTransaction(
|
||||||
MOZ_KnownLive(*atNewStartOfSelection.GetContainer()));
|
MOZ_KnownLive(*atNewStartOfSelection.ContainerAsText()));
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
NS_WARNING("EditorBase::DeleteNodeWithTransaction() failed");
|
NS_WARNING("EditorBase::DeleteNodeWithTransaction() failed");
|
||||||
return rv;
|
return rv;
|
||||||
|
@ -1487,9 +1487,11 @@ NS_IMETHODIMP TextEditor::GetTextLength(int32_t* aCount) {
|
||||||
DebugOnly<nsresult> rvIgnored = postOrderIter.Init(rootElement);
|
DebugOnly<nsresult> rvIgnored = postOrderIter.Init(rootElement);
|
||||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rvIgnored),
|
NS_WARNING_ASSERTION(NS_SUCCEEDED(rvIgnored),
|
||||||
"PostContentIterator::Init() failed, but ignored");
|
"PostContentIterator::Init() failed, but ignored");
|
||||||
|
EditorType editorType = GetEditorType();
|
||||||
for (; !postOrderIter.IsDone(); postOrderIter.Next()) {
|
for (; !postOrderIter.IsDone(); postOrderIter.Next()) {
|
||||||
nsINode* currentNode = postOrderIter.GetCurrentNode();
|
nsINode* currentNode = postOrderIter.GetCurrentNode();
|
||||||
if (IsTextNode(currentNode) && IsEditable(currentNode)) {
|
if (IsTextNode(currentNode) &&
|
||||||
|
EditorUtils::IsEditableContent(*currentNode->AsText(), editorType)) {
|
||||||
totalLength += currentNode->Length();
|
totalLength += currentNode->Length();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1566,7 +1568,7 @@ nsresult TextEditor::UndoAsAction(uint32_t aCount, nsIPrincipal* aPrincipal) {
|
||||||
// performance hit here.
|
// performance hit here.
|
||||||
nsIContent* leftMostChild = GetLeftmostChild(mRootElement);
|
nsIContent* leftMostChild = GetLeftmostChild(mRootElement);
|
||||||
if (leftMostChild &&
|
if (leftMostChild &&
|
||||||
EditorBase::IsPaddingBRElementForEmptyEditor(*leftMostChild)) {
|
EditorUtils::IsPaddingBRElementForEmptyEditor(*leftMostChild)) {
|
||||||
mPaddingBRElementForEmptyEditor =
|
mPaddingBRElementForEmptyEditor =
|
||||||
static_cast<HTMLBRElement*>(leftMostChild);
|
static_cast<HTMLBRElement*>(leftMostChild);
|
||||||
} else {
|
} else {
|
||||||
|
@ -1649,7 +1651,7 @@ nsresult TextEditor::RedoAsAction(uint32_t aCount, nsIPrincipal* aPrincipal) {
|
||||||
Element* brElement =
|
Element* brElement =
|
||||||
nodeList->Length() == 1 ? nodeList->Item(0) : nullptr;
|
nodeList->Length() == 1 ? nodeList->Item(0) : nullptr;
|
||||||
if (brElement &&
|
if (brElement &&
|
||||||
EditorBase::IsPaddingBRElementForEmptyEditor(*brElement)) {
|
EditorUtils::IsPaddingBRElementForEmptyEditor(*brElement)) {
|
||||||
mPaddingBRElementForEmptyEditor =
|
mPaddingBRElementForEmptyEditor =
|
||||||
static_cast<HTMLBRElement*>(brElement);
|
static_cast<HTMLBRElement*>(brElement);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -669,14 +669,14 @@ nsIContent* WSRunScanner::GetEditableBlockParentOrTopmotEditableInlineContent(
|
||||||
if (NS_WARN_IF(!aContent)) {
|
if (NS_WARN_IF(!aContent)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
NS_ASSERTION(mHTMLEditor->IsEditable(aContent),
|
NS_ASSERTION(EditorUtils::IsEditableContent(*aContent, EditorType::HTML),
|
||||||
"Given content is not editable");
|
"Given content is not editable");
|
||||||
// XXX What should we do if scan range crosses block boundary? Currently,
|
// XXX What should we do if scan range crosses block boundary? Currently,
|
||||||
// it's not collapsed only when inserting composition string so that
|
// it's not collapsed only when inserting composition string so that
|
||||||
// it's possible but shouldn't occur actually.
|
// it's possible but shouldn't occur actually.
|
||||||
nsIContent* editableBlockParentOrTopmotEditableInlineContent = nullptr;
|
nsIContent* editableBlockParentOrTopmotEditableInlineContent = nullptr;
|
||||||
for (nsIContent* content : InclusiveAncestorsOfType<nsIContent>(*aContent)) {
|
for (nsIContent* content : InclusiveAncestorsOfType<nsIContent>(*aContent)) {
|
||||||
if (!mHTMLEditor->IsEditable(content)) {
|
if (!EditorUtils::IsEditableContent(*content, EditorType::HTML)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
editableBlockParentOrTopmotEditableInlineContent = content;
|
editableBlockParentOrTopmotEditableInlineContent = content;
|
||||||
|
|
|
@ -412,6 +412,8 @@ class MOZ_STACK_CLASS WSRunScanner {
|
||||||
Element* GetEditingHost() const { return mEditingHost; }
|
Element* GetEditingHost() const { return mEditingHost; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
using EditorType = EditorBase::EditorType;
|
||||||
|
|
||||||
// WSFragment represents a single run of ws (all leadingws, or all normalws,
|
// WSFragment represents a single run of ws (all leadingws, or all normalws,
|
||||||
// or all trailingws, or all leading+trailingws). Note that this single run
|
// or all trailingws, or all leading+trailingws). Note that this single run
|
||||||
// may still span multiple nodes.
|
// may still span multiple nodes.
|
||||||
|
|
Загрузка…
Ссылка в новой задаче