Bug 1802831 - Make `AutoInlineStyleSetter` align setting `text-decoration` style behavior in the CSS mode to the other browsers r=m_kato

Gecko wraps selection (and parent elements if entirely selected in them) in
new `<span>` element and set `text-decoration`.  However, the other browsers
tries to reuse selected or parent element which already has `text-decoration`
style. The other browsers' behavior is more reasonable from point of view of:
* smaller footprint
* minimizing to update the DOM tree

And aligning the behavior makes it easier to check the compatibility between
browsers and us avoid from new test failures aligning other behaviors to the
other browsers.

If there is an element specifying `text-decoration`, its `text-decoration`
declaration should be updated first.

If found element is `<i>`, `<s>` or `<strike>`, it should be replaced with new
`<span>` because these elements just represents the visual style and we should
not use such elements in the CSS mode (bug 1802736).  At this time, unless
the element has `text-decoration` rules in its `style` attribute value, we
the new `text-decoration` style should have the value represented by the
removing element (i.e., `underline` for `<i>`, `line-through` for the others).

However, if found element is `<ins>` or `<del>`, we should set its
`text-decoration` and unless it already has `text-decoration` rules, we need
to append corresponding style (`underline` for `<ins>` and `line-through` for
`<del>`) too.

When setting the values or removing a value from `text-decoration` declaration,
the value should be normalized to represent only `text-decoration-line` for
compatibility with the other browsers and keeping the implementation simpler.
And also the value should be built as the following order:
1. underline
2. overline
3. line-though

rather than updating current value with complicated code. Then, the tests can
compare with one expectation.

Depends on D163188

Differential Revision: https://phabricator.services.mozilla.com/D163429
This commit is contained in:
Masayuki Nakano 2022-12-02 22:50:56 +00:00
Родитель 6a1331f13a
Коммит be355a79de
8 изменённых файлов: 325 добавлений и 108 удалений

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

@ -127,42 +127,6 @@ bool ChangeStyleTransaction::ValueIncludes(const nsACString& aValueList,
return result;
}
// Removes the value aRemoveValue from the string list of white-space separated
// values aValueList
void ChangeStyleTransaction::RemoveValueFromListOfValues(
nsACString& aValues, const nsACString& aRemoveValue) {
nsAutoCString classStr(aValues);
nsAutoCString outString;
// put an extra null at the end
classStr.Append(kNullCh);
char* start = classStr.BeginWriting();
char* end = start;
while (kNullCh != *start) {
while (kNullCh != *start && nsCRT::IsAsciiSpace(*start)) {
// skip leading space
start++;
}
end = start;
while (kNullCh != *end && !nsCRT::IsAsciiSpace(*end)) {
// look for space or end
end++;
}
// end string here
*end = kNullCh;
if (start < end && !aRemoveValue.Equals(start)) {
outString.Append(start);
outString.Append(HTMLEditUtils::kSpace);
}
start = ++end;
}
aValues.Assign(outString);
}
NS_IMETHODIMP ChangeStyleTransaction::DoTransaction() {
MOZ_LOG(GetLogModule(), LogLevel::Info,
("%p ChangeStyleTransaction::%s this=%s", this, __FUNCTION__,
@ -191,19 +155,14 @@ NS_IMETHODIMP ChangeStyleTransaction::DoTransaction() {
}
mUndoValue.Assign(values);
// Does this property accept more than one value? (bug 62682)
bool multiple = AcceptsMoreThanOneValue(*mProperty);
if (mRemoveProperty) {
nsAutoCString returnString;
if (multiple) {
// Let's remove only the value we have to remove and not the others
RemoveValueFromListOfValues(values, "none"_ns);
RemoveValueFromListOfValues(values, mValue);
if (mProperty == nsGkAtoms::text_decoration) {
BuildTextDecorationValueToRemove(values, mValue, values);
if (values.IsEmpty()) {
ErrorResult error;
cssDecl->RemoveProperty(propertyNameString, returnString, error);
if (error.Failed()) {
if (MOZ_UNLIKELY(error.Failed())) {
NS_WARNING("nsICSSDeclaration::RemoveProperty() failed");
return error.StealNSResult();
}
@ -212,7 +171,7 @@ NS_IMETHODIMP ChangeStyleTransaction::DoTransaction() {
nsAutoCString priority;
cssDecl->GetPropertyPriority(propertyNameString, priority);
cssDecl->SetProperty(propertyNameString, values, priority, error);
if (error.Failed()) {
if (MOZ_UNLIKELY(error.Failed())) {
NS_WARNING("nsICSSDeclaration::SetProperty() failed");
return error.StealNSResult();
}
@ -220,7 +179,7 @@ NS_IMETHODIMP ChangeStyleTransaction::DoTransaction() {
} else {
ErrorResult error;
cssDecl->RemoveProperty(propertyNameString, returnString, error);
if (error.Failed()) {
if (MOZ_UNLIKELY(error.Failed())) {
NS_WARNING("nsICSSDeclaration::RemoveProperty() failed");
return error.StealNSResult();
}
@ -228,15 +187,14 @@ NS_IMETHODIMP ChangeStyleTransaction::DoTransaction() {
} else {
nsAutoCString priority;
cssDecl->GetPropertyPriority(propertyNameString, priority);
if (multiple) {
// Let's add the value we have to add to the others
AddValueToMultivalueProperty(values, mValue);
if (mProperty == nsGkAtoms::text_decoration) {
BuildTextDecorationValueToSet(values, mValue, values);
} else {
values.Assign(mValue);
}
ErrorResult error;
cssDecl->SetProperty(propertyNameString, values, priority, error);
if (error.Failed()) {
if (MOZ_UNLIKELY(error.Failed())) {
NS_WARNING("nsICSSDeclaration::SetProperty() failed");
return error.StealNSResult();
}
@ -281,7 +239,7 @@ nsresult ChangeStyleTransaction::SetStyle(bool aAttributeWasSet,
// An empty value means we have to remove the property
nsAutoCString returnString;
cssDecl->RemoveProperty(propertyNameString, returnString, error);
if (error.Failed()) {
if (MOZ_UNLIKELY(error.Failed())) {
NS_WARNING("nsICSSDeclaration::RemoveProperty() failed");
return error.StealNSResult();
}
@ -325,20 +283,59 @@ NS_IMETHODIMP ChangeStyleTransaction::RedoTransaction() {
return rv;
}
// True if the CSS property accepts more than one value
bool ChangeStyleTransaction::AcceptsMoreThanOneValue(nsAtom& aCSSProperty) {
return &aCSSProperty == nsGkAtoms::text_decoration;
// static
void ChangeStyleTransaction::BuildTextDecorationValueToSet(
const nsACString& aCurrentValues, const nsACString& aAddingValues,
nsACString& aOutValues) {
const bool underline = ValueIncludes(aCurrentValues, "underline"_ns) ||
ValueIncludes(aAddingValues, "underline"_ns);
const bool overline = ValueIncludes(aCurrentValues, "overline"_ns) ||
ValueIncludes(aAddingValues, "overline"_ns);
const bool lineThrough = ValueIncludes(aCurrentValues, "line-through"_ns) ||
ValueIncludes(aAddingValues, "line-through"_ns);
// FYI: Don't refer aCurrentValues which may refer same instance as
// aOutValues.
BuildTextDecorationValue(underline, overline, lineThrough, aOutValues);
}
// Adds the value aNewValue to the list of white-space separated values aValues
void ChangeStyleTransaction::AddValueToMultivalueProperty(
nsACString& aValues, const nsACString& aNewValue) {
if (aValues.IsEmpty() || aValues.LowerCaseEqualsLiteral("none")) {
aValues.Assign(aNewValue);
} else if (!ValueIncludes(aValues, aNewValue)) {
// We already have another value but not this one; add it
aValues.Append(HTMLEditUtils::kSpace);
aValues.Append(aNewValue);
// static
void ChangeStyleTransaction::BuildTextDecorationValueToRemove(
const nsACString& aCurrentValues, const nsACString& aRemovingValues,
nsACString& aOutValues) {
const bool underline = ValueIncludes(aCurrentValues, "underline"_ns) &&
!ValueIncludes(aRemovingValues, "underline"_ns);
const bool overline = ValueIncludes(aCurrentValues, "overline"_ns) &&
!ValueIncludes(aRemovingValues, "overline"_ns);
const bool lineThrough = ValueIncludes(aCurrentValues, "line-through"_ns) &&
!ValueIncludes(aRemovingValues, "line-through"_ns);
// FYI: Don't refer aCurrentValues which may refer same instance as
// aOutValues.
BuildTextDecorationValue(underline, overline, lineThrough, aOutValues);
}
void ChangeStyleTransaction::BuildTextDecorationValue(bool aUnderline,
bool aOverline,
bool aLineThrough,
nsACString& aOutValues) {
// We should build text-decoration(-line) value as same as Blink for
// compatibility. Blink sets text-decoration-line to the values in the
// following order. Blink drops `blink` and other styles like color and
// style. For keeping the code simple, let's use the lossy behavior.
aOutValues.Truncate();
if (aUnderline) {
aOutValues.AssignLiteral("underline");
}
if (aOverline) {
if (!aOutValues.IsEmpty()) {
aOutValues.Append(HTMLEditUtils::kSpace);
}
aOutValues.AppendLiteral("overline");
}
if (aLineThrough) {
if (!aOutValues.IsEmpty()) {
aOutValues.Append(HTMLEditUtils::kSpace);
}
aOutValues.AppendLiteral("line-through");
}
}

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

@ -79,31 +79,22 @@ class ChangeStyleTransaction final : public EditTransactionBase {
private:
virtual ~ChangeStyleTransaction() = default;
/*
* Adds the value aNewValue to list of white-space separated values aValues.
*
* @param aValues [IN/OUT] a list of wite-space separated values
* @param aNewValue [IN] a value this code adds to aValues if it is not
* already in
/**
* Build new text-decoration value to set/remove specific values to/from the
* rule which already has aCurrentValues.
*/
void AddValueToMultivalueProperty(nsACString& aValues,
const nsACString& aNewValue);
void BuildTextDecorationValueToSet(const nsACString& aCurrentValues,
const nsACString& aAddingValues,
nsACString& aOutValues);
void BuildTextDecorationValueToRemove(const nsACString& aCurrentValues,
const nsACString& aRemovingValues,
nsACString& aOutValues);
/**
* Returns true if the property accepts more than one value.
*
* @param aCSSProperty [IN] the CSS property
* @return true if the property accepts more than one value
* Helper method for above methods.
*/
bool AcceptsMoreThanOneValue(nsAtom& aCSSProperty);
/**
* Remove a value from a list of white-space separated values.
* @param aValues [IN] a list of white-space separated values
* @param aRemoveValue [IN] the value to remove from the list
*/
void RemoveValueFromListOfValues(nsACString& aValues,
const nsACString& aRemoveValue);
void BuildTextDecorationValue(bool aUnderline, bool aOverline,
bool aLineThrough, nsACString& aOutValues);
/**
* If the boolean is true and if the value is not the empty string,

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

@ -52,6 +52,9 @@ class MOZ_STACK_CLASS HTMLEditor::AutoInlineStyleSetter final
[[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<CaretPoint, nsresult> ApplyStyle(
HTMLEditor& aHTMLEditor, nsIContent& aContent) const;
[[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<CaretPoint, nsresult>
ApplyCSSTextDecoration(HTMLEditor& aHTMLEditor, nsIContent& aContent) const;
/**
* ElementIsGoodContainerForTheStyle() returns true if aElement is a
* good container for applying the style to a node. I.e., if this returns

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

@ -799,6 +799,15 @@ Result<CaretPoint, nsresult> HTMLEditor::AutoInlineStyleSetter::ApplyStyle(
};
if (ShouldUseCSS()) {
// We need special handlings for text-decoration.
if (IsStyleOfTextDecoration(IgnoreSElement::No)) {
Result<CaretPoint, nsresult> result =
ApplyCSSTextDecoration(aHTMLEditor, aContent);
NS_WARNING_ASSERTION(
result.isOk(),
"AutoInlineStyleSetter::ApplyCSSTextDecoration() failed");
return result;
}
RefPtr<Element> spanElement;
EditorDOMPoint pointToPutCaret;
// We only add style="" to <span>s with no attributes (bug 746515). If we
@ -875,6 +884,126 @@ Result<CaretPoint, nsresult> HTMLEditor::AutoInlineStyleSetter::ApplyStyle(
wrapWithNewElementToFormatResult.unwrap().UnwrapCaretPoint());
}
Result<CaretPoint, nsresult>
HTMLEditor::AutoInlineStyleSetter::ApplyCSSTextDecoration(
HTMLEditor& aHTMLEditor, nsIContent& aContent) const {
MOZ_ASSERT(IsStyleOfTextDecoration(IgnoreSElement::No));
EditorDOMPoint pointToPutCaret;
RefPtr<nsStyledElement> styledElement = nsStyledElement::FromNode(aContent);
nsAutoString textDecorationValue;
if (styledElement) {
nsresult rv = CSSEditUtils::GetSpecifiedProperty(
*styledElement, *nsGkAtoms::text_decoration, textDecorationValue);
if (NS_FAILED(rv)) {
NS_WARNING(
"CSSEditUtils::GetSpecifiedProperty(nsGkAtoms::text_decoration) "
"failed");
return Err(rv);
}
}
nsAutoString newTextDecorationValue;
if (&HTMLPropertyRef() == nsGkAtoms::u) {
newTextDecorationValue.AssignLiteral(u"underline");
} else if (&HTMLPropertyRef() == nsGkAtoms::s ||
&HTMLPropertyRef() == nsGkAtoms::strike) {
newTextDecorationValue.AssignLiteral(u"line-through");
} else {
MOZ_ASSERT_UNREACHABLE(
"Was new value added in "
"IsStyleOfTextDecoration(IgnoreSElement::No))?");
}
if (styledElement && IsCSSEditable(*styledElement) &&
(
// If the element has `text-decoration` by default, use it.
(styledElement->IsAnyOfHTMLElements(nsGkAtoms::u, nsGkAtoms::s,
nsGkAtoms::strike, nsGkAtoms::ins,
nsGkAtoms::del)) ||
// If the element has a text-decoration rule, use it.
!textDecorationValue.IsEmpty())) {
// However, if the element is an element to style the text-decoration,
// replace it with new <span>.
if (styledElement && styledElement->IsAnyOfHTMLElements(
nsGkAtoms::u, nsGkAtoms::s, nsGkAtoms::strike)) {
Result<CreateElementResult, nsresult> replaceResult =
aHTMLEditor.ReplaceContainerAndCloneAttributesWithTransaction(
*styledElement, *nsGkAtoms::span);
if (MOZ_UNLIKELY(replaceResult.isErr())) {
NS_WARNING(
"HTMLEditor::ReplaceContainerAndCloneAttributesWithTransaction() "
"failed");
return replaceResult.propagateErr();
}
CreateElementResult unwrappedReplaceResult = replaceResult.unwrap();
MOZ_ASSERT(unwrappedReplaceResult.GetNewNode());
unwrappedReplaceResult.MoveCaretPointTo(
pointToPutCaret, {SuggestCaret::OnlyIfHasSuggestion});
// The new <span> needs to specify the original element's text-decoration
// style unless it's specified explicitly.
if (textDecorationValue.IsEmpty()) {
if (!newTextDecorationValue.IsEmpty()) {
newTextDecorationValue.Append(HTMLEditUtils::kSpace);
}
if (styledElement->IsHTMLElement(nsGkAtoms::u)) {
newTextDecorationValue.AppendLiteral(u"underline");
} else {
newTextDecorationValue.AppendLiteral(u"line-through");
}
}
styledElement =
nsStyledElement::FromNode(unwrappedReplaceResult.GetNewNode());
if (NS_WARN_IF(!styledElement)) {
return CaretPoint(pointToPutCaret);
}
}
// If the element has default style, we need to keep it after specifying
// text-decoration.
else if (textDecorationValue.IsEmpty() &&
styledElement->IsAnyOfHTMLElements(nsGkAtoms::u, nsGkAtoms::ins)) {
if (!newTextDecorationValue.IsEmpty()) {
newTextDecorationValue.Append(HTMLEditUtils::kSpace);
}
newTextDecorationValue.AppendLiteral(u"underline");
} else if (textDecorationValue.IsEmpty() &&
styledElement->IsAnyOfHTMLElements(
nsGkAtoms::s, nsGkAtoms::strike, nsGkAtoms::del)) {
if (!newTextDecorationValue.IsEmpty()) {
newTextDecorationValue.Append(HTMLEditUtils::kSpace);
}
newTextDecorationValue.AppendLiteral(u"line-through");
}
}
// Otherwise, use new <span> element.
else {
Result<CreateElementResult, nsresult> wrapInSpanElementResult =
aHTMLEditor.InsertContainerWithTransaction(aContent, *nsGkAtoms::span);
if (MOZ_UNLIKELY(wrapInSpanElementResult.isErr())) {
NS_WARNING(
"HTMLEditor::InsertContainerWithTransaction(nsGkAtoms::span) failed");
return wrapInSpanElementResult.propagateErr();
}
CreateElementResult unwrappedWrapInSpanElementResult =
wrapInSpanElementResult.unwrap();
MOZ_ASSERT(unwrappedWrapInSpanElementResult.GetNewNode());
unwrappedWrapInSpanElementResult.MoveCaretPointTo(
pointToPutCaret, {SuggestCaret::OnlyIfHasSuggestion});
styledElement = nsStyledElement::FromNode(
unwrappedWrapInSpanElementResult.GetNewNode());
if (NS_WARN_IF(!styledElement)) {
return CaretPoint(pointToPutCaret);
}
}
nsresult rv = CSSEditUtils::SetCSSPropertyWithTransaction(
aHTMLEditor, *styledElement, *nsGkAtoms::text_decoration,
newTextDecorationValue);
if (NS_FAILED(rv)) {
NS_WARNING("CSSEditUtils::SetCSSPropertyWithTransaction() failed");
return Err(rv);
}
return CaretPoint(pointToPutCaret);
}
Result<CaretPoint, nsresult> HTMLEditor::AutoInlineStyleSetter::
ApplyStyleToNodeOrChildrenAndRemoveNestedSameStyle(
HTMLEditor& aHTMLEditor, nsIContent& aContent) const {

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

@ -1,18 +1,12 @@
[strikethrough.html?1-1000]
expected:
if (os == "android") and fission: [OK, TIMEOUT]
[[["stylewithcss","true"\],["strikethrough",""\]\] "<span>[foo</span> <span>bar\]</span>" compare innerHTML]
expected: FAIL
[[["stylewithcss","true"\],["strikethrough",""\]\] "<span>[foo</span> <span>bar\]</span>" queryCommandIndeterm("strikethrough") before]
expected: FAIL
[[["stylewithcss","false"\],["strikethrough",""\]\] "<span>[foo</span> <span>bar\]</span>" queryCommandIndeterm("strikethrough") before]
expected: FAIL
[[["stylewithcss","true"\],["strikethrough",""\]\] "<p>[foo</p><p> <span>bar</span> </p><p>baz\]</p>" compare innerHTML]
expected: FAIL
[[["stylewithcss","true"\],["strikethrough",""\]\] "<p>[foo</p><p> <span>bar</span> </p><p>baz\]</p>" queryCommandIndeterm("strikethrough") before]
expected: FAIL

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

@ -1,18 +1,12 @@
[underline.html?1-1000]
expected:
if (os == "android") and fission: [OK, TIMEOUT]
[[["stylewithcss","true"\],["underline",""\]\] "<span>[foo</span> <span>bar\]</span>" compare innerHTML]
expected: FAIL
[[["stylewithcss","true"\],["underline",""\]\] "<span>[foo</span> <span>bar\]</span>" queryCommandIndeterm("underline") before]
expected: FAIL
[[["stylewithcss","false"\],["underline",""\]\] "<span>[foo</span> <span>bar\]</span>" queryCommandIndeterm("underline") before]
expected: FAIL
[[["stylewithcss","true"\],["underline",""\]\] "<p>[foo</p><p> <span>bar</span> </p><p>baz\]</p>" compare innerHTML]
expected: FAIL
[[["stylewithcss","true"\],["underline",""\]\] "<p>[foo</p><p> <span>bar</span> </p><p>baz\]</p>" queryCommandIndeterm("underline") before]
expected: FAIL

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

@ -165,9 +165,13 @@ var browserTests = [
"{<table><tbody><tr><td><strike>foo</strike></td><td><strike>bar</strike></td><td><strike>baz</strike></td></tr></tbody></table>}",
[true,true],
{"stylewithcss":[false,true,"",false,false,""],"strikethrough":[false,false,"",false,true,""]}],
// <u> is just representing underline style. Therefore, browsers should not
// keep it. Instead, it should be replaced with new <span> and set its
// text-decoration to line-through (requested style) and underline (default
// style of <u>).
["foo<u>[bar]</u>baz",
[["stylewithcss","true"],["strikethrough",""]],
"foo<span style=\"text-decoration:line-through\"><u>[bar]</u></span>baz",
"foo<span style=\"text-decoration:underline line-through\">[bar]</span>baz",
[true,true],
{"stylewithcss":[false,false,"",false,true,""],"strikethrough":[false,false,"",false,true,""]}],
["foo<u>[bar]</u>baz",
@ -175,9 +179,11 @@ var browserTests = [
"foo<strike><u>[bar]</u></strike>baz",
[true,true],
{"stylewithcss":[false,true,"",false,false,""],"strikethrough":[false,false,"",false,true,""]}],
// The <span> which is a container of the range has text-decoration style.
// Therefore, it should be updated rather than creating new element.
["foo<span style=\"text-decoration: underline\">[bar]</span>baz",
[["stylewithcss","true"],["strikethrough",""]],
"foo<span style=\"text-decoration:line-through\"><span style=\"text-decoration:underline\">[bar]</span></span>baz",
"foo<span style=\"text-decoration:underline line-through\">[bar]</span>baz",
[true,true],
{"stylewithcss":[false,false,"",false,true,""],"strikethrough":[false,false,"",false,true,""]}],
["foo<span style=\"text-decoration: underline\">[bar]</span>baz",
@ -367,9 +373,12 @@ var browserTests = [
"<strike>foo</strike>[b<i>ar]<strike>ba</strike></i><strike>z</strike>",
[true,true],
{"stylewithcss":[false,true,"",false,false,""],"strikethrough":[false,true,"",false,false,""]}],
// Should set text-decoration of <ins> because it has underline style by
// default and it is not only representing it, thus, replacing it with <span>
// changes the meaning.
["foo<ins>[bar]</ins>baz",
[["stylewithcss","true"],["strikethrough",""]],
"foo<span style=\"text-decoration:line-through\"><ins>[bar]</ins></span>baz",
"foo<ins style=\"text-decoration:underline line-through\">[bar]</ins>baz",
[true,true],
{"stylewithcss":[false,false,"",false,true,""],"strikethrough":[false,false,"",false,true,""]}],
["foo<ins>[bar]</ins>baz",
@ -533,9 +542,13 @@ var browserTests = [
"foo<s style=\"text-decoration:overline\">b</s><span style=\"text-decoration-line:overline\"><strike>a</strike></span><s style=\"text-decoration:overline\">r</s>baz",
[true,true],
{"stylewithcss":[false,true,"",false,false,""],"strikethrough":[false,false,"",false,true,""]}],
// Should replace <u> with new <span> and set its `text-decoration` to
// line-though (for applying the requested style) and overline (which was
// specified to the <u>). Note that underline was removed by the
// text-decoration setting. Therefore, it should not appear.
["foo<u style=\"text-decoration: overline\">[bar]</u>baz",
[["stylewithcss","true"],["strikethrough",""]],
"foo<span style=\"text-decoration:line-through\"><u style=\"text-decoration:overline\">[bar]</u></span>baz",
"foo<span style=\"text-decoration:overline line-through\">[bar]</span>baz",
[true,true],
{"stylewithcss":[false,false,"",false,true,""],"strikethrough":[false,false,"",false,true,""]}],
["foo<u style=\"text-decoration: overline\">[bar]</u>baz",
@ -708,5 +721,46 @@ var browserTests = [
[["stylewithcss","false"],["strikethrough",""]],
"<s>fo</s>[o<del>b]ar</del>",
[true,true],
{"stylewithcss":[false,true,"",false,false,""],"strikethrough":[false,true,"",true,false,""]}]
{"stylewithcss":[false,true,"",false,false,""],"strikethrough":[false,true,"",true,false,""]}],
// Tests to remove only strikethrough from existing text-decoration
["abc<span style=\"text-decoration:line-through overline underline\">[def]</span>ghi",
[["stylewithcss","true"],["strikethrough",""]],
["abc<span style=\"text-decoration:underline overline\">[def]</span>ghi",
"abc<span style=\"text-decoration-line:underline overline\">[def]</span>ghi"],
[true,true],
{}],
// blink, text-decoration-color and text-decoration-style values should be
// dropped. This rule is odd because executing "underline" command causes
// the data loss, but for now, the compatibility between browsers is more
// important. Once you want/need to change the behavior of a browser, you
// should file a spec issue first.
// And these tests allows the difference between text-decoration vs.
// text-decoration-line because these tests want to check the data loss.
["abc<span style=\"text-decoration:blink overline underline\">[def]</span>ghi",
[["stylewithcss","true"],["strikethrough",""]],
["abc<span style=\"text-decoration:underline overline line-through\">[def]</span>ghi",
"abc<span style=\"text-decoration-line:underline overline line-through\">[def]</span>ghi"],
[true,true],
{}],
["abc<span style=\"text-decoration:underline blue dotted\">[def]</span>ghi",
[["stylewithcss","true"],["strikethrough",""]],
["abc<span style=\"text-decoration:underline line-through\">[def]</span>ghi",
"abc<span style=\"text-decoration-line:underline line-through\">[def]</span>ghi"],
[true,true],
{}],
["abc<span style=\"text-decoration:blink line-through underline overline\">[def]</span>ghi",
[["stylewithcss","true"],["strikethrough",""]],
["abc<span style=\"text-decoration:underline overline\">[def]</span>ghi",
"abc<span style=\"text-decoration-line:underline overline\">[def]</span>ghi"],
[true,true],
{}],
["abc<span style=\"text-decoration:underline line-through blue dotted\">[def]</span>ghi",
[["stylewithcss","true"],["strikethrough",""]],
["abc<span style=\"text-decoration:underline\">[def]</span>ghi",
"abc<span style=\"text-decoration-line:underline\">[def]</span>ghi"],
[true,true],
{}],
]

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

@ -235,9 +235,12 @@ var browserTests = [
"<p><u>foo</u>[bar]<u>baz</u></p>",
[true,true],
{"stylewithcss":[false,true,"",false,false,""],"underline":[false,true,"",false,false,""]}],
// <s> should be replaced with new <span> because it just represents line-though
// style, and should set its text-decoration to underline (requested style) and
// line-through (default style of <s>).
["foo<s>[bar]</s>baz",
[["stylewithcss","true"],["underline",""]],
"foo<span style=\"text-decoration:underline\"><s>[bar]</s></span>baz",
"foo<span style=\"text-decoration:underline line-through\">[bar]</span>baz",
[true,true],
{"stylewithcss":[false,false,"",false,true,""],"underline":[false,false,"",false,true,""]}],
["foo<s>[bar]</s>baz",
@ -245,9 +248,11 @@ var browserTests = [
"foo<u><s>[bar]</s></u>baz",
[true,true],
{"stylewithcss":[false,true,"",false,false,""],"underline":[false,false,"",false,true,""]}],
// Should update text-decoration declaration in the <span> which is a container
// of the range.
["foo<span style=\"text-decoration: line-through\">[bar]</span>baz",
[["stylewithcss","true"],["underline",""]],
"foo<span style=\"text-decoration:underline\"><span style=\"text-decoration:line-through\">[bar]</span></span>baz",
"foo<span style=\"text-decoration:underline line-through\">[bar]</span>baz",
[true,true],
{"stylewithcss":[false,false,"",false,true,""],"underline":[false,false,"",false,true,""]}],
["foo<span style=\"text-decoration: line-through\">[bar]</span>baz",
@ -315,9 +320,12 @@ var browserTests = [
"<p style=\"text-decoration:line-through\">foo<u>[bar]</u>baz</p>",
[true,true],
{"stylewithcss":[false,true,"",false,false,""],"underline":[false,false,"",false,true,""]}],
// Should replace <strike> with new <span> because <strike> is just representing
// line-through style, and set its text-decoration to underline (requested
// style) and line-though (default style of <strike>).
["foo<strike>[bar]</strike>baz",
[["stylewithcss","true"],["underline",""]],
"foo<span style=\"text-decoration:underline\"><strike>[bar]</strike></span>baz",
"foo<span style=\"text-decoration:underline line-through\">[bar]</span>baz",
[true,true],
{"stylewithcss":[false,false,"",false,true,""],"underline":[false,false,"",false,true,""]}],
["foo<strike>[bar]</strike>baz",
@ -405,9 +413,12 @@ var browserTests = [
"<ins>foo[b<i>ar]ba</i>z</ins>",
[true],
{"underline":[false,true,"",false,true,""]}],
// Should set text-decoration of <del> because it has line-through style by
// default and it is not only representing it, thus, replacing it with <span>
// changes the meaning.
["foo<del>[bar]</del>baz",
[["stylewithcss","true"],["underline",""]],
"foo<span style=\"text-decoration:underline\"><del>[bar]</del></span>baz",
"foo<del style=\"text-decoration:underline line-through\">[bar]</del>baz",
[true,true],
{"stylewithcss":[false,false,"",false,true,""],"underline":[false,false,"",false,true,""]}],
["foo<del>[bar]</del>baz",
@ -520,9 +531,13 @@ var browserTests = [
"foo<u style=\"text-decoration:line-through\">b<u>[a]</u>r</u>baz",
[true,true],
{"stylewithcss":[false,true,"",false,false,""],"underline":[false,false,"",false,true,""]}],
// Should replace <s> with new <span> and set its `text-decoration` to underline
// (for applying the requested style) and overline (which was specified to the
// <s>). Note that line-though was removed by the text-decoration setting.
// Therefore, it should not appear.
["foo<s style=\"text-decoration: overline\">[bar]</s>baz",
[["stylewithcss","true"],["underline",""]],
"foo<span style=\"text-decoration:underline\"><s style=\"text-decoration:overline\">[bar]</s></span>baz",
"foo<span style=\"text-decoration:underline overline\">[bar]</span>baz",
[true,true],
{"stylewithcss":[false,false,"",false,true,""],"underline":[false,false,"",false,true,""]}],
["foo<s style=\"text-decoration: overline\">[bar]</s>baz",
@ -704,5 +719,45 @@ var browserTests = [
[["stylewithcss","false"],["underline",""]],
"<u>fo</u>[o<ins>b]ar</ins>",
[true,true],
{"stylewithcss":[false,true,"",false,false,""],"underline":[false,true,"",true,false,""]}]
]
{"stylewithcss":[false,true,"",false,false,""],"underline":[false,true,"",true,false,""]}],
// Tests to remove only underline from existing text-decoration
["abc<span style=\"text-decoration:line-through overline underline\">[def]</span>ghi",
[["stylewithcss","true"],["underline",""]],
["abc<span style=\"text-decoration:overline line-through\">[def]</span>ghi",
"abc<span style=\"text-decoration-line:overline line-through\">[def]</span>ghi"],
[true,true],
{}],
// blink, text-decoration-color and text-decoration-style values should be
// dropped. This rule is odd because executing "underline" command causes
// the data loss, but for now, the compatibility between browsers is more
// important. Once you want/need to change the behavior of a browser, you
// should file a spec issue first.
// And these tests allows the difference between text-decoration vs.
// text-decoration-line because these tests want to check the data loss.
["abc<span style=\"text-decoration:blink line-through overline\">[def]</span>ghi",
[["stylewithcss","true"],["underline",""]],
["abc<span style=\"text-decoration:underline overline line-through\">[def]</span>ghi",
"abc<span style=\"text-decoration-line:underline overline line-through\">[def]</span>ghi"],
[true,true],
{}],
["abc<span style=\"text-decoration:line-through blue dotted\">[def]</span>ghi",
[["stylewithcss","true"],["underline",""]],
["abc<span style=\"text-decoration:underline line-through\">[def]</span>ghi",
"abc<span style=\"text-decoration-line:underline line-through\">[def]</span>ghi"],
[true,true],
{}],
["abc<span style=\"text-decoration:blink line-through underline overline\">[def]</span>ghi",
[["stylewithcss","true"],["underline",""]],
["abc<span style=\"text-decoration:overline line-through\">[def]</span>ghi",
"abc<span style=\"text-decoration-line:overline line-through\">[def]</span>ghi"],
[true,true],
{}],
["abc<span style=\"text-decoration:underline line-through blue dotted\">[def]</span>ghi",
[["stylewithcss","true"],["underline",""]],
["abc<span style=\"text-decoration:line-through\">[def]</span>ghi",
"abc<span style=\"text-decoration-line:line-through\">[def]</span>ghi"],
[true,true],
{}],
]