mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-01 08:42:13 +00:00
Bug 1782911 - part 4: Make HTMLEditor::MoveNodeOrChildrenWithTransaction
preserve white-space
style at moving different style node r=m_kato
Chrome and Safari preserve `white-space` with `style` attribute to keep collapsible or preserved white-spaces as-is. If an HTML element is moved, `style` attribute should be set to it. Otherwise, create `<span>` element whose `style` attribute has the declaration for `white-space` and move content into it. Differential Revision: https://phabricator.services.mozilla.com/D157413
This commit is contained in:
parent
bb2a35d9d7
commit
7e788541b1
@ -1855,10 +1855,16 @@ class HTMLEditor final : public EditorBase,
|
||||
* @param aContent Content which should be moved.
|
||||
* @param aPointToInsert The point to be inserted aContent or its
|
||||
* descendants.
|
||||
* @param aPreserveWhiteSpaceStyle
|
||||
* If yes and if it's possible to keep white-space
|
||||
* style, this method will set `style` attribute to
|
||||
* moving node or creating new <span> element.
|
||||
*/
|
||||
enum class PreserveWhiteSpaceStyle { No, Yes };
|
||||
[[nodiscard]] MOZ_CAN_RUN_SCRIPT MoveNodeResult
|
||||
MoveNodeOrChildrenWithTransaction(nsIContent& aNode,
|
||||
const EditorDOMPoint& aPointToInsert);
|
||||
MoveNodeOrChildrenWithTransaction(
|
||||
nsIContent& aContentToMove, const EditorDOMPoint& aPointToInsert,
|
||||
PreserveWhiteSpaceStyle aPreserveWhiteSpaceStyle);
|
||||
|
||||
/**
|
||||
* CanMoveNodeOrChildren() returns true if
|
||||
@ -1879,9 +1885,14 @@ class HTMLEditor final : public EditorBase,
|
||||
* moved.
|
||||
* @param aPointToInsert The point to be inserted children of aElement
|
||||
* or its descendants.
|
||||
* @param aPreserveWhiteSpaceStyle
|
||||
* If yes and if it's possible to keep white-space
|
||||
* style, this method will set `style` attribute to
|
||||
* moving node or creating new <span> element.
|
||||
*/
|
||||
[[nodiscard]] MOZ_CAN_RUN_SCRIPT MoveNodeResult MoveChildrenWithTransaction(
|
||||
Element& aElement, const EditorDOMPoint& aPointToInsert);
|
||||
Element& aElement, const EditorDOMPoint& aPointToInsert,
|
||||
PreserveWhiteSpaceStyle aPreserveWhiteSpaceStyle);
|
||||
|
||||
/**
|
||||
* CanMoveChildren() returns true if `MoveChildrenWithTransaction()` can move
|
||||
|
@ -19,18 +19,22 @@
|
||||
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/CheckedInt.h"
|
||||
#include "mozilla/ComputedStyle.h" // for ComputedStyle
|
||||
#include "mozilla/ContentIterator.h"
|
||||
#include "mozilla/EditorDOMPoint.h"
|
||||
#include "mozilla/InternalMutationEvent.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/OwningNonNull.h"
|
||||
#include "mozilla/StaticPrefs_editor.h" // for StaticPrefs::editor_*
|
||||
#include "mozilla/Unused.h"
|
||||
#include "mozilla/dom/AncestorIterator.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "mozilla/dom/HTMLBRElement.h"
|
||||
#include "mozilla/dom/Selection.h"
|
||||
#include "mozilla/mozalloc.h"
|
||||
#include "nsAString.h"
|
||||
#include "nsAtom.h"
|
||||
#include "nsComputedDOMStyle.h" // for nsComputedDOMStyle
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsDebug.h"
|
||||
#include "nsError.h"
|
||||
@ -41,6 +45,7 @@
|
||||
#include "nsRange.h"
|
||||
#include "nsString.h"
|
||||
#include "nsStringFwd.h"
|
||||
#include "nsStyleConsts.h" // for StyleWhiteSpace
|
||||
#include "nsTArray.h"
|
||||
|
||||
// NOTE: This file was split from:
|
||||
@ -4782,19 +4787,55 @@ MoveNodeResult HTMLEditor::MoveOneHardLineContentsWithTransaction(
|
||||
MoveToEndOfContainer
|
||||
aMoveToEndOfContainer /* = MoveToEndOfContainer::No */) {
|
||||
MOZ_ASSERT(IsEditActionDataAvailable());
|
||||
MOZ_ASSERT(aPointInHardLine.IsInContentNode());
|
||||
MOZ_ASSERT(aPointToInsert.IsSetAndValid());
|
||||
|
||||
if (NS_WARN_IF(aPointToInsert.IsInNativeAnonymousSubtree())) {
|
||||
return MoveNodeResult(NS_ERROR_INVALID_ARG);
|
||||
}
|
||||
|
||||
const RefPtr<Element> inclusiveAncestorBlock =
|
||||
const RefPtr<Element> destInclusiveAncestorBlock =
|
||||
aPointToInsert.IsInContentNode()
|
||||
? HTMLEditUtils::GetInclusiveAncestorElement(
|
||||
*aPointToInsert.ContainerAs<nsIContent>(),
|
||||
HTMLEditUtils::ClosestBlockElement)
|
||||
: nullptr;
|
||||
|
||||
// If we move content from or to <pre>, we don't need to preserve the
|
||||
// white-space style for compatibility with both our traditional behavior
|
||||
// and the other browsers.
|
||||
const PreserveWhiteSpaceStyle preserveWhiteSpaceStyle = [&]() {
|
||||
if (MOZ_UNLIKELY(!destInclusiveAncestorBlock)) {
|
||||
return PreserveWhiteSpaceStyle::No;
|
||||
}
|
||||
// TODO: If `white-space` is specified by non-UA stylesheet, we should
|
||||
// preserve it even if the right block is <pre> for compatibility with the
|
||||
// other browsers.
|
||||
const auto IsInclusiveDescendantOfPre = [](const nsIContent& aContent) {
|
||||
// If the content has different `white-space` style from <pre>, we
|
||||
// shouldn't treat it as a descendant of <pre> because web apps or
|
||||
// the user intent to treat the white-spaces in aContent not as `pre`.
|
||||
if (EditorUtils::GetComputedWhiteSpaceStyle(aContent).valueOr(
|
||||
StyleWhiteSpace::Normal) != StyleWhiteSpace::Pre) {
|
||||
return false;
|
||||
}
|
||||
for (const Element* element :
|
||||
aContent.InclusiveAncestorsOfType<Element>()) {
|
||||
if (element->IsHTMLElement(nsGkAtoms::pre)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
if (IsInclusiveDescendantOfPre(*destInclusiveAncestorBlock) ||
|
||||
MOZ_UNLIKELY(!aPointInHardLine.IsInContentNode()) ||
|
||||
IsInclusiveDescendantOfPre(
|
||||
*aPointInHardLine.ContainerAs<nsIContent>())) {
|
||||
return PreserveWhiteSpaceStyle::No;
|
||||
}
|
||||
return PreserveWhiteSpaceStyle::Yes;
|
||||
}();
|
||||
|
||||
EditorDOMPoint pointToInsert(aPointToInsert);
|
||||
EditorDOMPoint pointToPutCaret;
|
||||
AutoTArray<OwningNonNull<nsIContent>, 64> arrayOfContents;
|
||||
@ -4872,8 +4913,9 @@ MoveNodeResult HTMLEditor::MoveOneHardLineContentsWithTransaction(
|
||||
// If the content is a block element, move all children of it to the
|
||||
// new container, and then, remove the (probably) empty block element.
|
||||
if (HTMLEditUtils::IsBlockElement(content)) {
|
||||
moveContentsInLineResult |= MoveChildrenWithTransaction(
|
||||
MOZ_KnownLive(*content->AsElement()), pointToInsert);
|
||||
moveContentsInLineResult |=
|
||||
MoveChildrenWithTransaction(MOZ_KnownLive(*content->AsElement()),
|
||||
pointToInsert, preserveWhiteSpaceStyle);
|
||||
if (moveContentsInLineResult.isErr()) {
|
||||
NS_WARNING("HTMLEditor::MoveChildrenWithTransaction() failed");
|
||||
return moveContentsInLineResult;
|
||||
@ -4894,7 +4936,7 @@ MoveNodeResult HTMLEditor::MoveOneHardLineContentsWithTransaction(
|
||||
// MOZ_KnownLive because 'arrayOfContents' is guaranteed to
|
||||
// keep it alive.
|
||||
moveContentsInLineResult |= MoveNodeOrChildrenWithTransaction(
|
||||
MOZ_KnownLive(content), pointToInsert);
|
||||
MOZ_KnownLive(content), pointToInsert, preserveWhiteSpaceStyle);
|
||||
if (moveContentsInLineResult.isErr()) {
|
||||
NS_WARNING("HTMLEditor::MoveNodeOrChildrenWithTransaction() failed");
|
||||
return moveContentsInLineResult;
|
||||
@ -4924,7 +4966,7 @@ MoveNodeResult HTMLEditor::MoveOneHardLineContentsWithTransaction(
|
||||
// Nothing has been moved, we don't need to clean up unnecessary <br> element.
|
||||
// And also if we're not moving content into a block, we can quit right now.
|
||||
if (moveContentsInLineResult.Ignored() ||
|
||||
MOZ_UNLIKELY(!inclusiveAncestorBlock)) {
|
||||
MOZ_UNLIKELY(!destInclusiveAncestorBlock)) {
|
||||
return moveContentsInLineResult;
|
||||
}
|
||||
|
||||
@ -4937,7 +4979,8 @@ MoveNodeResult HTMLEditor::MoveOneHardLineContentsWithTransaction(
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIContent> lastLineBreakContent =
|
||||
HTMLEditUtils::GetUnnecessaryLineBreakContent(*inclusiveAncestorBlock);
|
||||
HTMLEditUtils::GetUnnecessaryLineBreakContent(
|
||||
*destInclusiveAncestorBlock);
|
||||
if (!lastLineBreakContent) {
|
||||
return moveContentsInLineResult;
|
||||
}
|
||||
@ -4990,15 +5033,120 @@ Result<bool, nsresult> HTMLEditor::CanMoveNodeOrChildren(
|
||||
}
|
||||
|
||||
MoveNodeResult HTMLEditor::MoveNodeOrChildrenWithTransaction(
|
||||
nsIContent& aContentToMove, const EditorDOMPoint& aPointToInsert) {
|
||||
nsIContent& aContentToMove, const EditorDOMPoint& aPointToInsert,
|
||||
PreserveWhiteSpaceStyle aPreserveWhiteSpaceStyle) {
|
||||
MOZ_ASSERT(IsEditActionDataAvailable());
|
||||
MOZ_ASSERT(aPointToInsert.IsSet());
|
||||
MOZ_ASSERT(aPointToInsert.IsInContentNode());
|
||||
|
||||
const auto destWhiteSpaceStyle = [&]() -> Maybe<StyleWhiteSpace> {
|
||||
if (aPreserveWhiteSpaceStyle == PreserveWhiteSpaceStyle::No ||
|
||||
!aPointToInsert.IsInContentNode()) {
|
||||
return Nothing();
|
||||
}
|
||||
auto style = EditorUtils::GetComputedWhiteSpaceStyle(
|
||||
*aPointToInsert.ContainerAs<nsIContent>());
|
||||
if (NS_WARN_IF(style.isSome() &&
|
||||
style.value() == StyleWhiteSpace::PreSpace)) {
|
||||
return Nothing();
|
||||
}
|
||||
return style;
|
||||
}();
|
||||
const auto srcWhiteSpaceStyle = [&]() -> Maybe<StyleWhiteSpace> {
|
||||
if (aPreserveWhiteSpaceStyle == PreserveWhiteSpaceStyle::No) {
|
||||
return Nothing();
|
||||
}
|
||||
auto style = EditorUtils::GetComputedWhiteSpaceStyle(aContentToMove);
|
||||
if (NS_WARN_IF(style.isSome() &&
|
||||
style.value() == StyleWhiteSpace::PreSpace)) {
|
||||
return Nothing();
|
||||
}
|
||||
return style;
|
||||
}();
|
||||
const auto GetWhiteSpaceStyleValue = [](StyleWhiteSpace aStyleWhiteSpace) {
|
||||
switch (aStyleWhiteSpace) {
|
||||
case StyleWhiteSpace::Normal:
|
||||
return u"normal"_ns;
|
||||
case StyleWhiteSpace::Pre:
|
||||
return u"pre"_ns;
|
||||
case StyleWhiteSpace::Nowrap:
|
||||
return u"nowrap"_ns;
|
||||
case StyleWhiteSpace::PreWrap:
|
||||
return u"pre-wrap"_ns;
|
||||
case StyleWhiteSpace::PreLine:
|
||||
return u"pre-line"_ns;
|
||||
case StyleWhiteSpace::BreakSpaces:
|
||||
return u"break-spaces"_ns;
|
||||
case StyleWhiteSpace::PreSpace:
|
||||
MOZ_ASSERT_UNREACHABLE("Don't handle -moz-pre-space");
|
||||
return u""_ns;
|
||||
default:
|
||||
MOZ_ASSERT_UNREACHABLE("Handle the new white-space value");
|
||||
return u""_ns;
|
||||
}
|
||||
};
|
||||
|
||||
// Check if this node can go into the destination node
|
||||
if (HTMLEditUtils::CanNodeContain(*aPointToInsert.GetContainer(),
|
||||
aContentToMove)) {
|
||||
// If it can, move it there.
|
||||
EditorDOMPoint pointToInsert(aPointToInsert);
|
||||
// Preserve white-space in the new position with using `style` attribute.
|
||||
// This is additional path from point of view of our traditional behavior.
|
||||
// Therefore, ignore errors especially if we got unexpected DOM tree.
|
||||
if (destWhiteSpaceStyle.isSome() && srcWhiteSpaceStyle.isSome() &&
|
||||
destWhiteSpaceStyle.value() != srcWhiteSpaceStyle.value()) {
|
||||
// Set `white-space` with `style` attribute if it's nsStyledElement.
|
||||
if (nsStyledElement* styledElement =
|
||||
nsStyledElement::FromNode(&aContentToMove)) {
|
||||
DebugOnly<nsresult> rvIgnored =
|
||||
CSSEditUtils::SetCSSPropertyWithTransaction(
|
||||
*this, MOZ_KnownLive(*styledElement), *nsGkAtoms::white_space,
|
||||
GetWhiteSpaceStyleValue(srcWhiteSpaceStyle.value()));
|
||||
if (NS_WARN_IF(Destroyed())) {
|
||||
return MoveNodeResult(NS_ERROR_EDITOR_DESTROYED);
|
||||
}
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rvIgnored),
|
||||
"CSSEditUtils::SetCSSPropertyWithTransaction("
|
||||
"nsGkAtoms::white_space) failed, but ignored");
|
||||
}
|
||||
// Otherwise, if the dest container can have <span> element and <span>
|
||||
// element can have the moving content node, we should insert it.
|
||||
else if (HTMLEditUtils::CanNodeContain(*aPointToInsert.GetContainer(),
|
||||
*nsGkAtoms::span) &&
|
||||
HTMLEditUtils::CanNodeContain(*nsGkAtoms::span,
|
||||
aContentToMove)) {
|
||||
RefPtr<Element> newSpanElement = CreateHTMLContent(nsGkAtoms::span);
|
||||
if (NS_WARN_IF(!newSpanElement)) {
|
||||
return MoveNodeResult(NS_ERROR_FAILURE);
|
||||
}
|
||||
nsAutoString styleAttrValue(u"white-space: "_ns);
|
||||
styleAttrValue.Append(
|
||||
GetWhiteSpaceStyleValue(srcWhiteSpaceStyle.value()));
|
||||
IgnoredErrorResult error;
|
||||
newSpanElement->SetAttr(nsGkAtoms::style, styleAttrValue, error);
|
||||
NS_WARNING_ASSERTION(!error.Failed(),
|
||||
"Element::SetAttr(nsGkAtoms::span) failed");
|
||||
if (MOZ_LIKELY(!error.Failed())) {
|
||||
CreateElementResult insertSpanElementResult =
|
||||
InsertNodeWithTransaction<Element>(*newSpanElement,
|
||||
aPointToInsert);
|
||||
if (NS_WARN_IF(insertSpanElementResult.EditorDestroyed())) {
|
||||
return MoveNodeResult(NS_ERROR_EDITOR_DESTROYED);
|
||||
}
|
||||
NS_WARNING_ASSERTION(
|
||||
insertSpanElementResult.isOk(),
|
||||
"HTMLEditor::InsertNodeWithTransaction() failed, but ignored");
|
||||
if (MOZ_LIKELY(insertSpanElementResult.isOk())) {
|
||||
// We should move the node into the new <span> to preserve the
|
||||
// style.
|
||||
pointToInsert.Set(newSpanElement, 0u);
|
||||
// We should put caret after aContentToMove after moving it so that
|
||||
// we do not need the suggested caret point here.
|
||||
insertSpanElementResult.IgnoreCaretPointSuggestion();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// If it can, move it there.
|
||||
MoveNodeResult moveNodeResult =
|
||||
MoveNodeWithTransaction(aContentToMove, pointToInsert);
|
||||
NS_WARNING_ASSERTION(moveNodeResult.isOk(),
|
||||
@ -5015,8 +5163,9 @@ MoveNodeResult HTMLEditor::MoveNodeOrChildrenWithTransaction(
|
||||
if (!aContentToMove.IsElement()) {
|
||||
return MoveNodeHandled(aPointToInsert);
|
||||
}
|
||||
MoveNodeResult moveChildrenResult = MoveChildrenWithTransaction(
|
||||
MOZ_KnownLive(*aContentToMove.AsElement()), aPointToInsert);
|
||||
MoveNodeResult moveChildrenResult =
|
||||
MoveChildrenWithTransaction(MOZ_KnownLive(*aContentToMove.AsElement()),
|
||||
aPointToInsert, aPreserveWhiteSpaceStyle);
|
||||
NS_WARNING_ASSERTION(moveChildrenResult.isOk(),
|
||||
"HTMLEditor::MoveChildrenWithTransaction() failed");
|
||||
return moveChildrenResult;
|
||||
@ -5062,7 +5211,8 @@ Result<bool, nsresult> HTMLEditor::CanMoveChildren(
|
||||
}
|
||||
|
||||
MoveNodeResult HTMLEditor::MoveChildrenWithTransaction(
|
||||
Element& aElement, const EditorDOMPoint& aPointToInsert) {
|
||||
Element& aElement, const EditorDOMPoint& aPointToInsert,
|
||||
PreserveWhiteSpaceStyle aPreserveWhiteSpaceStyle) {
|
||||
MOZ_ASSERT(aPointToInsert.IsSet());
|
||||
|
||||
if (NS_WARN_IF(&aElement == aPointToInsert.GetContainer())) {
|
||||
@ -5073,7 +5223,7 @@ MoveNodeResult HTMLEditor::MoveChildrenWithTransaction(
|
||||
while (aElement.GetFirstChild()) {
|
||||
moveChildrenResult |= MoveNodeOrChildrenWithTransaction(
|
||||
MOZ_KnownLive(*aElement.GetFirstChild()),
|
||||
moveChildrenResult.NextInsertionPoint());
|
||||
moveChildrenResult.NextInsertionPoint(), aPreserveWhiteSpaceStyle);
|
||||
if (moveChildrenResult.isErr()) {
|
||||
NS_WARNING("HTMLEditor::MoveNodeOrChildrenWithTransaction() failed");
|
||||
return moveChildrenResult;
|
||||
|
@ -456,9 +456,12 @@ EditActionResult WhiteSpaceVisibilityKeeper::
|
||||
Result<bool, nsresult> rightBlockHasContent =
|
||||
aHTMLEditor.CanMoveChildren(aRightBlockElement, aLeftBlockElement);
|
||||
#endif // #ifdef DEBUG
|
||||
// TODO: Stop using HTMLEditor::PreserveWhiteSpaceStyle::No due to no tests.
|
||||
MoveNodeResult moveNodeResult = aHTMLEditor.MoveChildrenWithTransaction(
|
||||
aRightBlockElement, EditorDOMPoint(atLeftBlockChild.GetContainer(),
|
||||
atLeftBlockChild.Offset()));
|
||||
aRightBlockElement,
|
||||
EditorDOMPoint(atLeftBlockChild.GetContainer(),
|
||||
atLeftBlockChild.Offset()),
|
||||
HTMLEditor::PreserveWhiteSpaceStyle::No);
|
||||
if (NS_WARN_IF(moveNodeResult.EditorDestroyed())) {
|
||||
return EditActionResult(NS_ERROR_EDITOR_DESTROYED);
|
||||
}
|
||||
|
@ -211,112 +211,113 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=772796
|
||||
// join-different-white-space-style-left-paragraph-and-right-line.html
|
||||
/* 39-00*/[
|
||||
"<div>test</div><span class=\"pre\">foobar\nbaz</span>",
|
||||
"<div>test<span class=\"pre\">foobar</span></div><span class=\"pre\">baz</span>", // expected
|
||||
"<div>test<span class=\"pre\" style=\"white-space: pre;\">foobar</span></div><span class=\"pre\">baz</span>", // expected
|
||||
],
|
||||
/* 40-01*/[
|
||||
"<div>test</div><span class=\"pre\"><b>foobar\nbaz</b></span>",
|
||||
"<div>test<span class=\"pre\"><b>foobar</b></span></div><span class=\"pre\"><b>baz</b></span>", // expected
|
||||
"<div>test<span class=\"pre\" style=\"white-space: pre;\"><b>foobar</b></span></div><span class=\"pre\"><b>baz</b></span>", // expected
|
||||
],
|
||||
/* 41-02*/[
|
||||
"<div>test</div><span class=\"pre\"><b>foo</b>bar\nbaz</span>",
|
||||
"<div>test<span class=\"pre\"><b>foo</b>bar</span></div><span class=\"pre\">baz</span>", // expected
|
||||
"<div>test<span class=\"pre\" style=\"white-space: pre;\"><b>foo</b>bar</span></div><span class=\"pre\">baz</span>", // expected
|
||||
],
|
||||
/* 42-03*/[
|
||||
"<div>test</div><span class=\"pre\"><b>foo</b>\nbar</span>",
|
||||
"<div>test<span class=\"pre\"><b>foo</b></span></div><span class=\"pre\">bar</span>", // expected
|
||||
"<div>test<span class=\"pre\" style=\"white-space: pre;\"><b>foo</b></span></div><span class=\"pre\">bar</span>", // expected
|
||||
],
|
||||
/* 43-04*/[
|
||||
"<div>test</div><span class=\"pre\"><b>foo\n</b>bar\nbaz</span>",
|
||||
"<div>test<span class=\"pre\"><b>foo</b></span></div><span class=\"pre\">bar\nbaz</span>", // expected
|
||||
"<div>test<span class=\"pre\" style=\"white-space: pre;\"><b>foo</b></span></div><span class=\"pre\">bar\nbaz</span>", // expected
|
||||
],
|
||||
/* 44-05*/[
|
||||
"<div>test</div><span class=\"pre\">foobar<br>baz</span>",
|
||||
"<div>test<span class=\"pre\">foobar</span><span class=\"pre\"></span></div><span class=\"pre\">baz</span>", // expected
|
||||
"<div>test<span class=\"pre\" style=\"white-space: pre;\">foobar</span></div><span class=\"pre\">baz</span>", // expected
|
||||
"<div>test<span class=\"pre\" style=\"white-space: pre;\">foobar</span><span class=\"pre\" style=\"white-space: pre;\"></span></div><span class=\"pre\">baz</span>", // current result
|
||||
],
|
||||
/* 45-06*/[
|
||||
"<div>test</div><span class=\"pre\"><b>foobar<br>baz</b></span>",
|
||||
"<div>test<span class=\"pre\"><b>foobar</b></span><span class=\"pre\"></span></div><span class=\"pre\"><b>baz</b></span>", // expected
|
||||
"<div>test<span class=\"pre\" style=\"white-space: pre;\"><b>foobar</b></span></div><span class=\"pre\"><b>baz</b></span>", // expected
|
||||
"<div>test<span class=\"pre\" style=\"white-space: pre;\"><b>foobar</b></span><span class=\"pre\" style=\"white-space: pre;\"></span></div><span class=\"pre\"><b>baz</b></span>", // current result
|
||||
],
|
||||
/* 46-07*/[
|
||||
"<div>test</div><span class=\"pre\"><div>foobar</div>baz</span>",
|
||||
"<div>test<span class=\"pre\"><div>foobar</div></span></div><span class=\"pre\">baz</span>", // expected
|
||||
"<div>test<span class=\"pre\" style=\"white-space: pre;\"><div>foobar</div></span></div><span class=\"pre\">baz</span>", // expected
|
||||
],
|
||||
/* 47-08*/[
|
||||
"<div>test</div><span class=\"pre\">foobar<div>baz</div></span>",
|
||||
"<div>test<span class=\"pre\">foobar</span></div><span class=\"pre\"><div>baz</div></span>", // expected
|
||||
"<div>test<span class=\"pre\" style=\"white-space: pre;\">foobar</span></div><span class=\"pre\"><div>baz</div></span>", // expected
|
||||
],
|
||||
/* 48-09*/[
|
||||
"<div>test</div><span class=\"pre\"><div>foobar</div>baz\nfred</span>",
|
||||
"<div>test<span class=\"pre\"><div>foobar</div></span></div><span class=\"pre\">baz\nfred</span>", // expected
|
||||
"<div>test<span class=\"pre\" style=\"white-space: pre;\"><div>foobar</div></span></div><span class=\"pre\">baz\nfred</span>", // expected
|
||||
],
|
||||
/* 49-10*/[
|
||||
"<div>test</div><span class=\"pre\">foobar<div>baz</div>\nfred</span>",
|
||||
"<div>test<span class=\"pre\">foobar</span></div><span class=\"pre\"><div>baz</div>\nfred</span>", // expected
|
||||
"<div>test<span class=\"pre\" style=\"white-space: pre;\">foobar</span></div><span class=\"pre\"><div>baz</div>\nfred</span>", // expected
|
||||
],
|
||||
/* 50-11*/[
|
||||
"<div>test</div><span class=\"pre\"><div>foo\nbar</div>baz\nfred</span>",
|
||||
"<div>testfoo\n</div><span class=\"pre\"><div>bar</div>baz\nfred</span>", // expected
|
||||
"<div>test<span style=\"white-space: pre;\">foo</span></div><span class=\"pre\"><div>bar</div>baz\nfred</span>", // expected
|
||||
],
|
||||
/* 51-12*/[
|
||||
"<div>test</div><span class=\"pre\">foo<div>bar</div>baz\nfred</span>",
|
||||
"<div>test<span class=\"pre\">foo</span></div><span class=\"pre\"><div>bar</div>baz\nfred</span>", // expected
|
||||
"<div>test<span class=\"pre\" style=\"white-space: pre;\">foo</span></div><span class=\"pre\"><div>bar</div>baz\nfred</span>", // expected
|
||||
],
|
||||
|
||||
// Some tests with <div class="pre">.
|
||||
// FYI: Those tests were ported to join-different-white-space-style-paragraphs.html
|
||||
/* 52-00*/[
|
||||
"<div>test</div><div class=\"pre\">foobar\nbaz</div>",
|
||||
"<div>testfoobar\n</div><div class=\"pre\">baz</div>", // expected
|
||||
"<div>test<span style=\"white-space: pre;\">foobar</span></div><div class=\"pre\">baz</div>", // expected
|
||||
],
|
||||
/* 53-01*/[
|
||||
"<div>test</div><div class=\"pre\"><b>foobar\nbaz</b></div>",
|
||||
"<div>test<b>foobar</b></div><div class=\"pre\"><b>baz</b></div>", // expected
|
||||
"<div>test<b>foobar\n</b></div><div class=\"pre\"><b>baz</b></div>", // current result
|
||||
"<div>test<b style=\"white-space: pre;\">foobar</b></div><div class=\"pre\"><b>baz</b></div>", // expected
|
||||
],
|
||||
/* 54-02*/[
|
||||
"<div>test</div><div class=\"pre\"><b>foo</b>bar\nbaz</div>",
|
||||
"<div>test<b>foo</b>bar\n</div><div class=\"pre\">baz</div>", // expected
|
||||
"<div>test<b style=\"white-space: pre;\">foo</b><span style=\"white-space: pre;\">bar</span></div><div class=\"pre\">baz</div>", // expected
|
||||
],
|
||||
/* 55-03*/[
|
||||
"<div>test</div><div class=\"pre\"><b>foo</b>\nbar</div>",
|
||||
"<div>test<b>foo</b>\n</div><div class=\"pre\">bar</div>", // expected
|
||||
"<div>test<b style=\"white-space: pre;\">foo</b>\n</div><div class=\"pre\">bar</div>", // expected
|
||||
"<div>test<b style=\"white-space: pre;\">foo</b><span style=\"white-space: pre;\"></span></div><div class=\"pre\">bar</div>", // current result
|
||||
],
|
||||
/* 56-04*/[
|
||||
"<div>test</div><div class=\"pre\"><b>foo\n</b>bar\nbaz</div>",
|
||||
"<div>test<b>foo</b></div><div class=\"pre\">bar\nbaz</div>", // expected
|
||||
"<div>test<b>foo\n</b></div><div class=\"pre\">bar\nbaz</div>", // current result
|
||||
"<div>test<b style=\"white-space: pre;\">foo</b></div><div class=\"pre\">bar\nbaz</div>", // expected
|
||||
],
|
||||
/* 57-05*/[
|
||||
"<div>test</div><div class=\"pre\">foobar<br>baz</div>",
|
||||
"<div>testfoobar</div><div class=\"pre\">baz</div>", // expected
|
||||
"<div>test<span style=\"white-space: pre;\">foobar</span></div><div class=\"pre\">baz</div>", // expected
|
||||
],
|
||||
/* 58-06*/[
|
||||
"<div>test</div><div class=\"pre\"><b>foobar<br>baz</b></div>",
|
||||
"<div>test<b>foobar</b></div><div class=\"pre\"><b>baz</b></div>", // expected
|
||||
"<div>test<b style=\"white-space: pre;\">foobar</b></div><div class=\"pre\"><b>baz</b></div>", // expected
|
||||
],
|
||||
/* 59-07*/[
|
||||
"<div>test</div><div class=\"pre\"><div>foobar</div>baz</div>",
|
||||
"<div>testfoobar</div><div class=\"pre\">baz</div>", // expected
|
||||
"<div>test<span style=\"white-space: pre;\">foobar</span></div><div class=\"pre\">baz</div>", // expected
|
||||
],
|
||||
/* 60-08*/[
|
||||
"<div>test</div><div class=\"pre\">foobar<div>baz</div></div>",
|
||||
"<div>testfoobar</div><div class=\"pre\"><div>baz</div></div>", // expected
|
||||
"<div>test<span style=\"white-space: pre;\">foobar</span></div><div class=\"pre\"><div>baz</div></div>", // expected
|
||||
],
|
||||
/* 61-09*/[
|
||||
"<div>test</div><div class=\"pre\"><div>foobar</div>baz\nfred</div>",
|
||||
"<div>testfoobar</div><div class=\"pre\">baz\nfred</div>", // expected
|
||||
"<div>test<span style=\"white-space: pre;\">foobar</span></div><div class=\"pre\">baz\nfred</div>", // expected
|
||||
],
|
||||
/* 62-10*/[
|
||||
"<div>test</div><div class=\"pre\">foobar<div>baz</div>\nfred</div>",
|
||||
"<div>testfoobar</div><div class=\"pre\"><div>baz</div>\nfred</div>", // expected
|
||||
"<div>test<span style=\"white-space: pre;\">foobar</span></div><div class=\"pre\"><div>baz</div>\nfred</div>", // expected
|
||||
],
|
||||
/* 63-11*/[
|
||||
"<div>test</div><div class=\"pre\"><div>foo\nbar</div>baz\nfred</div>",
|
||||
"<div>testfoo\n</div><div class=\"pre\"><div>bar</div>baz\nfred</div>", // expected
|
||||
"<div>test<span style=\"white-space: pre;\">foo</span></div><div class=\"pre\"><div>bar</div>baz\nfred</div>", // expected
|
||||
],
|
||||
/* 64-12*/[
|
||||
"<div>test</div><div class=\"pre\">foo<div>bar</div>baz\nfred</div>",
|
||||
"<div>testfoo</div><div class=\"pre\"><div>bar</div>baz\nfred</div>", // expected
|
||||
"<div>test<span style=\"white-space: pre;\">foo</span></div><div class=\"pre\"><div>bar</div>baz\nfred</div>", // expected
|
||||
],
|
||||
|
||||
// Some tests with lists. These exercise the MoveBlock "left in right".
|
||||
@ -377,9 +378,33 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=772796
|
||||
sel.collapse(theDiv, 0);
|
||||
synthesizeMouse(theDiv, 100, 2, {}); /* click behind and down */
|
||||
|
||||
function normalizeStyeAttributeValues(aElement) {
|
||||
for (const element of Array.from(
|
||||
aElement.querySelectorAll("[style]")
|
||||
)) {
|
||||
element.setAttribute(
|
||||
"style",
|
||||
element
|
||||
.getAttribute("style")
|
||||
// Random spacing differences
|
||||
.replace(/$/, ";")
|
||||
.replace(/;;$/, ";")
|
||||
// Gecko likes "transparent"
|
||||
.replace(/transparent/g, "rgba(0, 0, 0, 0)")
|
||||
// WebKit likes to look overly precise
|
||||
.replace(/, 0.496094\)/g, ", 0.5)")
|
||||
// Gecko converts anything with full alpha to "transparent" which
|
||||
// then becomes "rgba(0, 0, 0, 0)", so we have to make other
|
||||
// browsers match
|
||||
.replace(/rgba\([0-9]+, [0-9]+, [0-9]+, 0\)/g, "rgba(0, 0, 0, 0)")
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
let todoCount = 0;
|
||||
/** First round: Forward delete. **/
|
||||
synthesizeKey("KEY_Delete");
|
||||
normalizeStyeAttributeValues(theDiv);
|
||||
if (tests[i].length == 2 || theDiv.innerHTML == tests[i][1]) {
|
||||
is(theDiv.innerHTML, tests[i][1], "delete(collapsed): inner HTML for " + testName);
|
||||
} else {
|
||||
@ -398,6 +423,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=772796
|
||||
/** Second round: Backspace. **/
|
||||
synthesizeKey("KEY_ArrowRight");
|
||||
synthesizeKey("KEY_Backspace");
|
||||
normalizeStyeAttributeValues(theDiv);
|
||||
if (tests[i].length == 2 || theDiv.innerHTML == tests[i][1]) {
|
||||
is(theDiv.innerHTML, tests[i][1], "backspace: inner HTML for " + testName);
|
||||
} else {
|
||||
@ -427,6 +453,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=772796
|
||||
synthesizeKey("KEY_ArrowRight", {shiftKey: true});
|
||||
synthesizeKey("KEY_ArrowRight", {shiftKey: true});
|
||||
synthesizeKey("KEY_Delete");
|
||||
normalizeStyeAttributeValues(theDiv);
|
||||
|
||||
/* We always expect to the delete the "tf" in "testfoo". */
|
||||
function makeNonCollapsedExpectation(aExpected) {
|
||||
@ -435,12 +462,20 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=772796
|
||||
"tesoo")
|
||||
.replace("test<b>foo",
|
||||
"tes<b>oo")
|
||||
.replace("test<span class=\"pre\">foo",
|
||||
"tes<span class=\"pre\">oo")
|
||||
.replace("test<span class=\"pre\"><b>foo",
|
||||
"tes<span class=\"pre\"><b>oo")
|
||||
.replace("test<span class=\"pre\"><div>foo",
|
||||
"tes<span class=\"pre\"><div>oo");
|
||||
.replace("test<b style=\"white-space: pre;\">foo",
|
||||
"tes<b style=\"white-space: pre;\">oo")
|
||||
.replace("test<span style=\"white-space: pre;\">foo",
|
||||
"tes<span style=\"white-space: pre;\">oo")
|
||||
.replace("test<span style=\"white-space: pre;\"><b>foo",
|
||||
"tes<span style=\"white-space: pre;\"><b>oo")
|
||||
.replace("test<span style=\"white-space: pre;\"><div>foo",
|
||||
"tes<span style=\"white-space: pre;\"><div>oo")
|
||||
.replace("test<span class=\"pre\" style=\"white-space: pre;\">foo",
|
||||
"tes<span class=\"pre\" style=\"white-space: pre;\">oo")
|
||||
.replace("test<span class=\"pre\" style=\"white-space: pre;\"><b>foo",
|
||||
"tes<span class=\"pre\" style=\"white-space: pre;\"><b>oo")
|
||||
.replace("test<span class=\"pre\" style=\"white-space: pre;\"><div>foo",
|
||||
"tes<span class=\"pre\" style=\"white-space: pre;\"><div>oo");
|
||||
}
|
||||
const expected = makeNonCollapsedExpectation(tests[i][1]);
|
||||
if (tests[i].length == 2 || theDiv.innerHTML == expected) {
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user