blob: 1886137fb813619275b8bb01573c88fd61470423 [file] [log] [blame]
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/qualified_name.h"
#include "third_party/blink/renderer/core/editing/commands/format_block_command.h"
#include "third_party/blink/renderer/core/editing/commands/indent_outdent_command.h"
#include "third_party/blink/renderer/core/editing/frame_selection.h"
#include "third_party/blink/renderer/core/editing/position.h"
#include "third_party/blink/renderer/core/editing/selection_template.h"
#include "third_party/blink/renderer/core/editing/testing/editing_test_base.h"
#include "third_party/blink/renderer/core/editing/testing/selection_sample.h"
#include "third_party/blink/renderer/core/editing/visible_selection.h"
#include "third_party/blink/renderer/core/html/html_head_element.h"
#include "third_party/blink/renderer/core/html_names.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
#include <memory>
namespace blink {
class ApplyBlockElementCommandTest : public EditingTestBase {};
// This is a regression test for https://crbug.com/639534
TEST_F(ApplyBlockElementCommandTest, selectionCrossingOverBody) {
GetDocument().head()->insertAdjacentHTML(
"afterbegin",
"<style> .CLASS13 { -webkit-user-modify: read-write; }</style></head>",
ASSERT_NO_EXCEPTION);
GetDocument().body()->insertAdjacentHTML(
"afterbegin",
"\n<pre><var id='va' class='CLASS13'>\nC\n</var></pre><input />",
ASSERT_NO_EXCEPTION);
GetDocument().body()->insertAdjacentText("beforebegin", "foo",
ASSERT_NO_EXCEPTION);
GetDocument().body()->setContentEditable("false", ASSERT_NO_EXCEPTION);
GetDocument().setDesignMode("on");
GetDocument().UpdateStyleAndLayout(DocumentUpdateReason::kTest);
Selection().SetSelection(
SelectionInDOMTree::Builder()
.SetBaseAndExtent(
Position(GetDocument().documentElement(), 1),
Position(GetDocument().getElementById("va")->firstChild(), 2))
.Build(),
SetSelectionOptions());
auto* command = MakeGarbageCollected<FormatBlockCommand>(
GetDocument(), html_names::kFooterTag);
command->Apply();
EXPECT_EQ(
"<head>"
"<style> .CLASS13 { -webkit-user-modify: read-write; }</style>"
"</head>foo"
"<body contenteditable=\"false\">\n"
"<pre><var id=\"va\" class=\"CLASS13\">\nC\n</var></pre><input></body>",
GetDocument().documentElement()->innerHTML());
}
// This is a regression test for https://crbug.com/660801
TEST_F(ApplyBlockElementCommandTest, visibilityChangeDuringCommand) {
GetDocument().head()->insertAdjacentHTML(
"afterbegin", "<style>li:first-child { visibility:visible; }</style>",
ASSERT_NO_EXCEPTION);
SetBodyContent("<ul style='visibility:hidden'><li>xyz</li></ul>");
GetDocument().setDesignMode("on");
UpdateAllLifecyclePhasesForTest();
Selection().SetSelection(
SelectionInDOMTree::Builder()
.Collapse(Position(GetDocument().QuerySelector("li"), 0))
.Build(),
SetSelectionOptions());
auto* command = MakeGarbageCollected<IndentOutdentCommand>(
GetDocument(), IndentOutdentCommand::kIndent);
command->Apply();
EXPECT_EQ(
"<head><style>li:first-child { visibility:visible; }</style></head>"
"<body><ul style=\"visibility:hidden\"><ul></ul><li>xyz</li></ul></body>",
GetDocument().documentElement()->innerHTML());
}
// This is a regression test for https://crbug.com/712510
TEST_F(ApplyBlockElementCommandTest, IndentHeadingIntoBlockquote) {
SetBodyContent(
"<div contenteditable=\"true\">"
"<h6><button><table></table></button></h6>"
"<object></object>"
"</div>");
Element* button = GetDocument().QuerySelector("button");
Element* object = GetDocument().QuerySelector("object");
Selection().SetSelection(SelectionInDOMTree::Builder()
.Collapse(Position(button, 0))
.Extend(Position(object, 0))
.Build(),
SetSelectionOptions());
auto* command = MakeGarbageCollected<IndentOutdentCommand>(
GetDocument(), IndentOutdentCommand::kIndent);
command->Apply();
// This only records the current behavior, which can be wrong.
EXPECT_EQ(
"<div contenteditable=\"true\">"
"<blockquote style=\"margin: 0 0 0 40px; border: none; padding: 0px;\">"
"<h6><button></button></h6>"
"<h6><button><table></table></button></h6>"
"</blockquote>"
"<h6><button></button></h6><br>"
"<object></object>"
"</div>",
GetDocument().body()->innerHTML());
}
// This is a regression test for https://crbug.com/806525
TEST_F(ApplyBlockElementCommandTest, InsertPlaceHolderAtDisconnectedPosition) {
GetDocument().setDesignMode("on");
InsertStyleElement(".input:nth-of-type(2n+1) { visibility:collapse; }");
Selection().SetSelection(
SetSelectionTextToBody(
"^<input><input class=\"input\" style=\"position:absolute\">|"),
SetSelectionOptions());
auto* command = MakeGarbageCollected<FormatBlockCommand>(GetDocument(),
html_names::kPreTag);
// Crash happens here.
EXPECT_FALSE(command->Apply());
EXPECT_EQ(
"<pre>|<input></pre><input class=\"input\" style=\"position:absolute\">",
GetSelectionTextFromBody());
}
// https://crbug.com/873084
TEST_F(ApplyBlockElementCommandTest, FormatBlockCrossingUserModifyBoundary) {
InsertStyleElement("*{-webkit-user-modify:read-write}");
Selection().SetSelection(
SetSelectionTextToBody(
"^<b style=\"-webkit-user-modify:read-only\"><button></button></b>|"),
SetSelectionOptions());
auto* command = MakeGarbageCollected<FormatBlockCommand>(GetDocument(),
html_names::kPreTag);
// Shouldn't crash here.
EXPECT_TRUE(command->Apply());
EXPECT_EQ(
"<pre>|<br></pre>"
"<b style=\"-webkit-user-modify:read-only\"><button></button></b>",
GetSelectionTextFromBody());
}
// https://crbug.com/873084
TEST_F(ApplyBlockElementCommandTest,
FormatBlockWithTableCrossingUserModifyBoundary) {
InsertStyleElement("*{-webkit-user-modify:read-write}");
Selection().SetSelection(
SetSelectionTextToBody("^<table></table>"
"<kbd "
"style=\"-webkit-user-modify:read-only\"><button><"
"/button></kbd>|"),
SetSelectionOptions());
auto* command = MakeGarbageCollected<FormatBlockCommand>(GetDocument(),
html_names::kPreTag);
// Shouldn't crash here.
EXPECT_FALSE(command->Apply());
EXPECT_EQ(
"<table>^</table>"
"<kbd style=\"-webkit-user-modify:read-only\"><button>|</button></kbd>",
GetSelectionTextFromBody());
}
// https://crbug.com/1172656
TEST_F(ApplyBlockElementCommandTest, FormatBlockWithDirectChildrenOfRoot) {
GetDocument().setDesignMode("on");
DocumentFragment* fragment = DocumentFragment::Create(GetDocument());
Element* root = GetDocument().documentElement();
fragment->ParseXML("a<div>b</div>c", root);
root->setTextContent("");
root->appendChild(fragment);
UpdateAllLifecyclePhasesForTest();
Selection().SetSelection(
SelectionInDOMTree::Builder().SelectAllChildren(*root).Build(),
SetSelectionOptions());
auto* command = MakeGarbageCollected<FormatBlockCommand>(GetDocument(),
html_names::kPreTag);
// Shouldn't crash here.
EXPECT_FALSE(command->Apply());
const SelectionInDOMTree& selection = Selection().GetSelectionInDOMTree();
EXPECT_EQ("^a<div>b</div>c|",
SelectionSample::GetSelectionText(*root, selection));
}
// This is a regression test for https://crbug.com/1180699
TEST_F(ApplyBlockElementCommandTest, OutdentEmptyBlockquote) {
Vector<std::string> selection_texts = {
"<blockquote style='padding:5px'>|</blockquote>",
"a<blockquote style='padding:5px'>|</blockquote>",
"<blockquote style='padding:5px'>|</blockquote>b",
"a<blockquote style='padding:5px'>|</blockquote>b"};
Vector<std::string> expectations = {"|", "a|<br>", "|<br>b", "a<br>|b"};
GetDocument().setDesignMode("on");
for (unsigned i = 0; i < selection_texts.size(); ++i) {
Selection().SetSelection(SetSelectionTextToBody(selection_texts[i]),
SetSelectionOptions());
auto* command = MakeGarbageCollected<IndentOutdentCommand>(
GetDocument(), IndentOutdentCommand::kOutdent);
// Shouldn't crash here.
command->Apply();
EXPECT_EQ(expectations[i], GetSelectionTextFromBody());
}
}
} // namespace blink