script/dom/execcommand/execcommands.rs
1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5use crate::dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods;
6use crate::dom::bindings::root::DomRoot;
7use crate::dom::bindings::str::DOMString;
8use crate::dom::document::Document;
9use crate::dom::execcommand::basecommand::BaseCommand;
10use crate::dom::execcommand::commands::delete::DeleteCommand;
11use crate::dom::selection::Selection;
12use crate::script_runtime::CanGc;
13
14impl Document {
15 /// <https://w3c.github.io/editing/docs/execCommand/#enabled>
16 fn selection_if_command_is_enabled(&self, can_gc: CanGc) -> Option<DomRoot<Selection>> {
17 // > Among commands defined in this specification, those listed in Miscellaneous commands are always enabled,
18 // > except for the cut command and the paste command.
19 // TODO
20 // > The other commands defined here are enabled if the active range is not null,
21 let selection = self.GetSelection(can_gc)?;
22 let range = selection.active_range()?;
23 // > its start node is either editable or an editing host,
24 let start = range.start_container();
25 if !start.is_editable() && !start.is_editing_host() {
26 return None;
27 }
28 // > the editing host of its start node is not an EditContext editing host,
29 // TODO
30 // > its end node is either editable or an editing host,
31 let end = range.end_container();
32 if !end.is_editable() && !end.is_editing_host() {
33 return None;
34 }
35 // > the editing host of its end node is not an EditContext editing host,
36 // TODO
37 // > and there is some editing host that is an inclusive ancestor of both its start node and its end node.
38 // TODO
39 Some(selection)
40 }
41
42 /// <https://w3c.github.io/editing/docs/execCommand/#supported>
43 fn command_if_command_is_supported(
44 &self,
45 command_id: DOMString,
46 ) -> Option<Box<dyn BaseCommand>> {
47 Some(Box::new(match &*command_id.str() {
48 "delete" => DeleteCommand {},
49 _ => return None,
50 }))
51 }
52}
53
54pub(crate) trait ExecCommandsSupport {
55 fn check_support_and_enabled(
56 &self,
57 command_id: DOMString,
58 can_gc: CanGc,
59 ) -> Option<(Box<dyn BaseCommand>, DomRoot<Selection>)>;
60 fn exec_command_for_command_id(
61 &self,
62 command_id: DOMString,
63 value: DOMString,
64 can_gc: CanGc,
65 ) -> bool;
66}
67
68impl ExecCommandsSupport for Document {
69 /// <https://w3c.github.io/editing/docs/execCommand/#querycommandenabled()>
70 fn check_support_and_enabled(
71 &self,
72 command_id: DOMString,
73 can_gc: CanGc,
74 ) -> Option<(Box<dyn BaseCommand>, DomRoot<Selection>)> {
75 // Step 2. Return true if command is both supported and enabled, false otherwise.
76 self.command_if_command_is_supported(command_id)
77 .zip(self.selection_if_command_is_enabled(can_gc))
78 }
79
80 /// <https://w3c.github.io/editing/docs/execCommand/#execcommand()>
81 fn exec_command_for_command_id(
82 &self,
83 command_id: DOMString,
84 value: DOMString,
85 can_gc: CanGc,
86 ) -> bool {
87 // Step 3. If command is not supported or not enabled, return false.
88 let Some((command, selection)) = self.check_support_and_enabled(command_id, can_gc) else {
89 return false;
90 };
91 // Step 4. If command is not in the Miscellaneous commands section:
92 // TODO
93
94 // Step 4.1. Let affected editing host be the editing host that is an inclusive ancestor
95 // of the active range's start node and end node, and is not the ancestor of any editing host
96 // that is an inclusive ancestor of the active range's start node and end node.
97 // TODO
98
99 // Step 4.2. Fire an event named "beforeinput" at affected editing host using InputEvent,
100 // with its bubbles and cancelable attributes initialized to true, and its data attribute initialized to null
101 // TODO
102
103 // Step 4.3. If the value returned by the previous step is false, return false.
104 // TODO
105
106 // Step 4.4. If command is not enabled, return false.
107 // TODO
108
109 // Step 4.5. Let affected editing host be the editing host that is an inclusive ancestor
110 // of the active range's start node and end node, and is not the ancestor of any editing host
111 // that is an inclusive ancestor of the active range's start node and end node.
112 // TODO
113
114 // Step 5. Take the action for command, passing value to the instructions as an argument.
115 let result = command.execute(&selection, value);
116 // Step 6. If the previous step returned false, return false.
117 if !result {
118 return false;
119 }
120 // Step 7. If the action modified DOM tree, then fire an event named "input" at affected editing
121 // host using InputEvent, with its isTrusted and bubbles attributes initialized to true,
122 // inputType attribute initialized to the mapped value of command, and its data attribute initialized to null.
123 // TODO
124
125 // Step 8. Return true.
126 true
127 }
128}