script/dom/execcommand/commands/
inserthorizontalrule.rs1use js::context::JSContext;
6use script_bindings::codegen::GenericBindings::NodeBinding::NodeMethods;
7use script_bindings::codegen::GenericBindings::RangeBinding::RangeMethods;
8use script_bindings::codegen::GenericBindings::SelectionBinding::SelectionMethods;
9use script_bindings::inheritance::Castable;
10
11use crate::dom::bindings::root::DomRoot;
12use crate::dom::document::Document;
13use crate::dom::execcommand::contenteditable::selection::SelectionDeletionBlockMerging;
14use crate::dom::selection::Selection;
15use crate::dom::text::Text;
16
17pub(crate) fn execute_insert_horizontal_rule_command(
19 cx: &mut JSContext,
20 document: &Document,
21 selection: &Selection,
22) -> bool {
23 let mut active_range = selection
25 .active_range()
26 .expect("Must always have an active range");
27 let mut start_node = active_range.start_container();
28 let mut start_offset = active_range.start_offset();
29 let mut end_node = active_range.end_container();
30 let mut end_offset = active_range.end_offset();
31
32 while let Some(parent) = start_node.GetParentNode() &&
35 start_offset == 0
36 {
37 start_offset = start_node.index();
38 start_node = parent;
39 }
40
41 while let Some(parent) = end_node.GetParentNode() &&
44 end_offset == end_node.len()
45 {
46 end_offset = 1 + end_node.index();
47 end_node = parent;
48 }
49
50 if selection
52 .Collapse(cx, Some(&start_node), start_offset)
53 .is_err()
54 {
55 unreachable!("Should always be able to collapse the selection.");
56 }
57
58 if selection.Extend(cx, &end_node, end_offset).is_err() {
60 unreachable!("Should always be able to extend the selection.");
61 }
62
63 selection.delete_the_selection(
65 cx,
66 document,
67 SelectionDeletionBlockMerging::Skip,
68 Default::default(),
69 Default::default(),
70 );
71
72 active_range = selection
73 .active_range()
74 .expect("Must always have an active range");
75
76 if !active_range.start_container().is_editable_or_editing_host() {
78 return true;
79 }
80
81 if active_range.start_container().is::<Text>() && active_range.start_offset() == 0 {
85 if selection
86 .Collapse(
87 cx,
88 active_range.start_container().GetParentNode().as_deref(),
89 active_range.start_container().index(),
90 )
91 .is_err()
92 {
93 unreachable!("Should always be able to collapse the selection.");
94 }
95 active_range = selection
96 .active_range()
97 .expect("Must always have an active range");
98 }
99
100 if active_range.start_container().is::<Text>() &&
104 active_range.start_offset() == active_range.start_container().len()
105 {
106 if selection
107 .Collapse(
108 cx,
109 active_range.start_container().GetParentNode().as_deref(),
110 1 + active_range.start_container().index(),
111 )
112 .is_err()
113 {
114 unreachable!("Should always be able to collapse the selection.");
115 }
116 active_range = selection
117 .active_range()
118 .expect("Must always have an active range");
119 }
120
121 let hr = document.create_element(cx, "hr");
123
124 let hr_node = DomRoot::upcast(hr);
126 if active_range.InsertNode(cx, &hr_node).is_err() {
127 unreachable!("The image should always be insertable.");
128 }
129
130 hr_node.fix_disallowed_ancestors(cx, document);
132
133 if selection
135 .Collapse(cx, hr_node.GetParentNode().as_deref(), 1 + hr_node.index())
136 .is_err()
137 {
138 unreachable!("Should always be able to collapse the selection.");
139 }
140
141 true
143}