mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-07-28 11:49:44 +00:00
LibWeb: Add new whitespace-preserving editing command
Major browsers seem to preserve `white-space: pre/pre-wrap` styles in a `<div>` when deleting the current selection through an editing command. The idiomatic way to support this is to have a command with a "relevant CSS property" to make sure the value is recorded and restored where appropriate, however, no such command exists. Create a custom command (internal to Ladybird) that implements this behavior.
This commit is contained in:
parent
1c77b42a44
commit
a1467c22d3
Notes:
github-actions[bot]
2025-05-16 22:30:14 +00:00
Author: https://github.com/gmta
Commit: a1467c22d3
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/4779
6 changed files with 38 additions and 5 deletions
|
@ -40,6 +40,7 @@ namespace Web::Editing::CommandNames {
|
|||
__ENUMERATE_COMMAND_NAME(justifyRight, "justifyRight") \
|
||||
__ENUMERATE_COMMAND_NAME(outdent, "outdent") \
|
||||
__ENUMERATE_COMMAND_NAME(paste, "paste") \
|
||||
__ENUMERATE_COMMAND_NAME(preserveWhitespace, "preserveWhitespace") \
|
||||
__ENUMERATE_COMMAND_NAME(redo, "redo") \
|
||||
__ENUMERATE_COMMAND_NAME(removeFormat, "removeFormat") \
|
||||
__ENUMERATE_COMMAND_NAME(selectAll, "selectAll") \
|
||||
|
|
|
@ -2657,6 +2657,15 @@ static Array const commands {
|
|||
.preserves_overrides = true,
|
||||
.mapped_value = "formatOutdent"_fly_string,
|
||||
},
|
||||
// AD-HOC: This is a Ladybird-specific formatting command that is not part of the spec. It has no action and as
|
||||
// such, it's not supported in userland (yet). The relevant CSS property `white-space` is used to indicate
|
||||
// that if this style value is found during editing commands, it is recorded and restored where necessary.
|
||||
// This is used to keep things like <div style="white-space: pre">..</div> intact when a selection is
|
||||
// deleted, for example.
|
||||
CommandDefinition {
|
||||
.command = CommandNames::preserveWhitespace,
|
||||
.relevant_css_property = CSS::PropertyID::WhiteSpace,
|
||||
},
|
||||
// https://w3c.github.io/editing/docs/execCommand/#the-removeformat-command
|
||||
CommandDefinition {
|
||||
.command = CommandNames::removeFormat,
|
||||
|
|
|
@ -360,10 +360,11 @@ WebIDL::ExceptionOr<bool> Document::query_command_supported(FlyString const& com
|
|||
if (!is_html_document())
|
||||
return WebIDL::InvalidStateError::create(realm(), "queryCommandSupported is only supported on HTML documents"_string);
|
||||
|
||||
// When the queryCommandSupported(command) method on the Document interface is invoked, the
|
||||
// user agent must return true if command is supported and available within the current script
|
||||
// on the current site, and false otherwise.
|
||||
return Editing::find_command_definition(command).has_value();
|
||||
// When the queryCommandSupported(command) method on the Document interface is invoked, the user agent must return
|
||||
// true if command is supported and available within the current script on the current site, and false otherwise.
|
||||
// AD-HOC: Supported commands should have an action defined. Currently, ::preserveWhitespace does not have one.
|
||||
auto command_definition = Editing::find_command_definition(command);
|
||||
return command_definition.has_value() && command_definition->action;
|
||||
}
|
||||
|
||||
// https://w3c.github.io/editing/docs/execCommand/#querycommandvalue()
|
||||
|
|
|
@ -3333,9 +3333,10 @@ Vector<RecordedNodeValue> record_the_values_of_nodes(Vector<GC::Ref<DOM::Node>>
|
|||
// 2. For each node in node list, for each command in the list "subscript", "bold", "fontName",
|
||||
// "fontSize", "foreColor", "hiliteColor", "italic", "strikethrough", and "underline" in that
|
||||
// order:
|
||||
// AD-HOC: We include "preserveWhitespace" as well.
|
||||
Array const commands = { CommandNames::subscript, CommandNames::bold, CommandNames::fontName,
|
||||
CommandNames::fontSize, CommandNames::foreColor, CommandNames::hiliteColor, CommandNames::italic,
|
||||
CommandNames::strikethrough, CommandNames::underline };
|
||||
CommandNames::strikethrough, CommandNames::underline, CommandNames::preserveWhitespace };
|
||||
for (auto node : node_list) {
|
||||
for (auto command : commands) {
|
||||
// 1. Let ancestor equal node.
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
Before: foo<div style="white-space: pre">bar</div>
|
||||
After: foo<span style="white-space: pre;">bar</span>
|
|
@ -0,0 +1,19 @@
|
|||
<!DOCTYPE html>
|
||||
<script src="../include.js"></script>
|
||||
<div contenteditable>foo<div style="white-space: pre">bar</div></div>
|
||||
<script>
|
||||
test(() => {
|
||||
var divElm = document.querySelector('div');
|
||||
println(`Before: ${divElm.innerHTML}`);
|
||||
|
||||
// Put cursor before 'bar'
|
||||
var range = document.createRange();
|
||||
range.setStart(divElm.childNodes[1].childNodes[0], 0);
|
||||
getSelection().addRange(range);
|
||||
|
||||
// Press backspace
|
||||
document.execCommand('delete');
|
||||
|
||||
println(`After: ${divElm.innerHTML}`);
|
||||
});
|
||||
</script>
|
Loading…
Add table
Add a link
Reference in a new issue