script/dom/
textcontrol.rs1use crate::clipboard_provider::EmbedderClipboardProvider;
11use crate::dom::bindings::cell::DomRefCell;
12use crate::dom::bindings::codegen::Bindings::HTMLFormElementBinding::SelectionMode;
13use crate::dom::bindings::conversions::DerivedFrom;
14use crate::dom::bindings::error::{Error, ErrorResult};
15use crate::dom::bindings::str::DOMString;
16use crate::dom::event::{EventBubbles, EventCancelable};
17use crate::dom::eventtarget::EventTarget;
18use crate::dom::node::{Node, NodeDamage, NodeTraits};
19use crate::textinput::{SelectionDirection, SelectionState, TextInput, UTF8Bytes};
20
21pub(crate) trait TextControlElement: DerivedFrom<EventTarget> + DerivedFrom<Node> {
22 fn selection_api_applies(&self) -> bool;
23 fn has_selectable_text(&self) -> bool;
24 fn set_dirty_value_flag(&self, value: bool);
25}
26
27pub(crate) struct TextControlSelection<'a, E: TextControlElement> {
28 element: &'a E,
29 textinput: &'a DomRefCell<TextInput<EmbedderClipboardProvider>>,
30}
31
32impl<'a, E: TextControlElement> TextControlSelection<'a, E> {
33 pub(crate) fn new(
34 element: &'a E,
35 textinput: &'a DomRefCell<TextInput<EmbedderClipboardProvider>>,
36 ) -> Self {
37 TextControlSelection { element, textinput }
38 }
39
40 pub(crate) fn dom_select(&self) {
42 if !self.element.has_selectable_text() {
44 return;
45 }
46
47 self.set_range(Some(0), Some(u32::MAX), None, None);
49 }
50
51 pub(crate) fn dom_start(&self) -> Option<u32> {
53 if !self.element.selection_api_applies() {
55 return None;
56 }
57
58 Some(self.start())
60 }
61
62 pub(crate) fn set_dom_start(&self, start: Option<u32>) -> ErrorResult {
64 if !self.element.selection_api_applies() {
66 return Err(Error::InvalidState);
67 }
68
69 let mut end = self.end();
71
72 if let Some(s) = start {
74 if end < s {
75 end = s;
76 }
77 }
78
79 self.set_range(start, Some(end), Some(self.direction()), None);
81 Ok(())
82 }
83
84 pub(crate) fn dom_end(&self) -> Option<u32> {
86 if !self.element.selection_api_applies() {
88 return None;
89 }
90
91 Some(self.end())
93 }
94
95 pub(crate) fn set_dom_end(&self, end: Option<u32>) -> ErrorResult {
97 if !self.element.selection_api_applies() {
99 return Err(Error::InvalidState);
100 }
101
102 self.set_range(Some(self.start()), end, Some(self.direction()), None);
104 Ok(())
105 }
106
107 pub(crate) fn dom_direction(&self) -> Option<DOMString> {
109 if !self.element.selection_api_applies() {
111 return None;
112 }
113
114 Some(DOMString::from(self.direction()))
115 }
116
117 pub(crate) fn set_dom_direction(&self, direction: Option<DOMString>) -> ErrorResult {
119 if !self.element.selection_api_applies() {
121 return Err(Error::InvalidState);
122 }
123
124 self.set_range(
126 Some(self.start()),
127 Some(self.end()),
128 direction.map(SelectionDirection::from),
129 None,
130 );
131 Ok(())
132 }
133
134 pub(crate) fn set_dom_range(
136 &self,
137 start: u32,
138 end: u32,
139 direction: Option<DOMString>,
140 ) -> ErrorResult {
141 if !self.element.selection_api_applies() {
143 return Err(Error::InvalidState);
144 }
145
146 self.set_range(
148 Some(start),
149 Some(end),
150 direction.map(SelectionDirection::from),
151 None,
152 );
153 Ok(())
154 }
155
156 pub(crate) fn set_dom_range_text(
158 &self,
159 replacement: DOMString,
160 start: Option<u32>,
161 end: Option<u32>,
162 selection_mode: SelectionMode,
163 ) -> ErrorResult {
164 if !self.element.selection_api_applies() {
166 return Err(Error::InvalidState);
167 }
168
169 self.element.set_dirty_value_flag(true);
171
172 let mut start = start.unwrap_or_else(|| self.start());
174 let mut end = end.unwrap_or_else(|| self.end());
175
176 if start > end {
178 return Err(Error::IndexSize);
179 }
180
181 let original_selection_state = self.textinput.borrow().selection_state();
184
185 let UTF8Bytes(content_length) = self.textinput.borrow().len_utf8();
186 let content_length = content_length as u32;
187
188 if start > content_length {
190 start = content_length;
191 }
192
193 if end > content_length {
195 end = content_length;
196 }
197
198 let mut selection_start = self.start();
200
201 let mut selection_end = self.end();
203
204 let new_length = replacement.len() as u32;
208
209 {
210 let mut textinput = self.textinput.borrow_mut();
211
212 textinput.set_selection_range(start, end, SelectionDirection::None);
214 textinput.replace_selection(replacement);
215 }
216
217 let new_end = start + new_length;
219
220 match selection_mode {
222 SelectionMode::Select => {
223 selection_start = start;
224 selection_end = new_end;
225 },
226
227 SelectionMode::Start => {
228 selection_start = start;
229 selection_end = start;
230 },
231
232 SelectionMode::End => {
233 selection_start = new_end;
234 selection_end = new_end;
235 },
236
237 SelectionMode::Preserve => {
238 let old_length = end - start;
240
241 let delta = (new_length as isize) - (old_length as isize);
243
244 if selection_start > end {
246 selection_start = ((selection_start as isize) + delta) as u32;
247 } else if selection_start > start {
248 selection_start = start;
249 }
250
251 if selection_end > end {
253 selection_end = ((selection_end as isize) + delta) as u32;
254 } else if selection_end > start {
255 selection_end = new_end;
256 }
257 },
258 }
259
260 self.set_range(
262 Some(selection_start),
263 Some(selection_end),
264 None,
265 Some(original_selection_state),
266 );
267 Ok(())
268 }
269
270 fn start(&self) -> u32 {
271 let UTF8Bytes(offset) = self.textinput.borrow().selection_start_offset();
272 offset as u32
273 }
274
275 fn end(&self) -> u32 {
276 let UTF8Bytes(offset) = self.textinput.borrow().selection_end_offset();
277 offset as u32
278 }
279
280 fn direction(&self) -> SelectionDirection {
281 self.textinput.borrow().selection_direction()
282 }
283
284 fn set_range(
286 &self,
287 start: Option<u32>,
288 end: Option<u32>,
289 direction: Option<SelectionDirection>,
290 original_selection_state: Option<SelectionState>,
291 ) {
292 let mut textinput = self.textinput.borrow_mut();
293 let original_selection_state =
294 original_selection_state.unwrap_or_else(|| textinput.selection_state());
295
296 let start = start.unwrap_or(0);
298
299 let end = end.unwrap_or(0);
301
302 textinput.set_selection_range(start, end, direction.unwrap_or(SelectionDirection::None));
304
305 if textinput.selection_state() != original_selection_state {
307 self.element
308 .owner_global()
309 .task_manager()
310 .user_interaction_task_source()
311 .queue_event(
312 self.element.upcast::<EventTarget>(),
313 atom!("select"),
314 EventBubbles::Bubbles,
315 EventCancelable::NotCancelable,
316 );
317 }
318
319 self.element.upcast::<Node>().dirty(NodeDamage::Other);
320 }
321}