1use std::cell::Cell;
6
7use dom_struct::dom_struct;
8use js::context::JSContext;
9
10use crate::dom::bindings::codegen::Bindings::NodeBinding::{GetRootNodeOptions, NodeMethods};
11use crate::dom::bindings::codegen::Bindings::RangeBinding::RangeMethods;
12use crate::dom::bindings::codegen::Bindings::SelectionBinding::SelectionMethods;
13use crate::dom::bindings::error::{Error, ErrorResult, Fallible};
14use crate::dom::bindings::inheritance::Castable;
15use crate::dom::bindings::refcounted::Trusted;
16use crate::dom::bindings::reflector::{DomGlobal, Reflector, reflect_dom_object_with_cx};
17use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom};
18use crate::dom::bindings::str::DOMString;
19use crate::dom::document::Document;
20use crate::dom::eventtarget::EventTarget;
21use crate::dom::node::{Node, NodeTraits};
22use crate::dom::range::Range;
23use crate::script_runtime::CanGc;
24
25#[derive(Clone, Copy, JSTraceable, MallocSizeOf)]
26enum Direction {
27 Forwards,
28 Backwards,
29 Directionless,
30}
31
32#[dom_struct]
33pub(crate) struct Selection {
34 reflector_: Reflector,
35 document: Dom<Document>,
36 range: MutNullableDom<Range>,
37 direction: Cell<Direction>,
38 has_scheduled_selectionchange_event: Cell<bool>,
40}
41
42impl Selection {
43 fn new_inherited(document: &Document) -> Selection {
44 Selection {
45 reflector_: Reflector::new(),
46 document: Dom::from_ref(document),
47 range: MutNullableDom::new(None),
48 direction: Cell::new(Direction::Directionless),
49 has_scheduled_selectionchange_event: Cell::new(false),
50 }
51 }
52
53 pub(crate) fn new(cx: &mut JSContext, document: &Document) -> DomRoot<Selection> {
54 reflect_dom_object_with_cx(
55 Box::new(Selection::new_inherited(document)),
56 &*document.global(),
57 cx,
58 )
59 }
60
61 fn set_range(&self, range: &Range) {
62 if let Some(existing) = self.range.get() {
66 if &*existing == range {
67 return;
68 }
69 }
70 self.range.set(Some(range));
71 range.associate_selection(self);
72 self.queue_selectionchange_task();
73 }
74
75 fn clear_range(&self) {
76 if let Some(range) = self.range.get() {
79 range.disassociate_selection(self);
80 self.range.set(None);
81 self.queue_selectionchange_task();
82 }
83 }
84
85 pub(crate) fn queue_selectionchange_task(&self) {
87 self.document.clear_command_overrides();
93
94 if self.has_scheduled_selectionchange_event.get() {
96 return;
97 }
98 self.has_scheduled_selectionchange_event.set(true);
100 let this = Trusted::new(self);
102 self.document
103 .owner_global()
104 .task_manager()
105 .user_interaction_task_source() .queue(
107 task!(selectionchange_task_steps: move |cx| {
109 let this = this.root();
110 this.has_scheduled_selectionchange_event.set(false);
112 this.document.upcast::<EventTarget>().fire_event(cx, atom!("selectionchange"));
119 }),
120 );
121 }
122
123 fn is_same_root(&self, node: &Node) -> bool {
124 &*node.GetRootNode(&GetRootNodeOptions::empty()) == self.document.upcast::<Node>()
125 }
126
127 pub(crate) fn active_range(&self) -> Option<DomRoot<Range>> {
129 self.range.get()
131 }
132}
133
134impl SelectionMethods<crate::DomTypeHolder> for Selection {
135 fn GetAnchorNode(&self) -> Option<DomRoot<Node>> {
137 if let Some(range) = self.range.get() {
138 match self.direction.get() {
139 Direction::Forwards => Some(range.start_container()),
140 _ => Some(range.end_container()),
141 }
142 } else {
143 None
144 }
145 }
146
147 fn AnchorOffset(&self) -> u32 {
149 if let Some(range) = self.range.get() {
150 match self.direction.get() {
151 Direction::Forwards => range.start_offset(),
152 _ => range.end_offset(),
153 }
154 } else {
155 0
156 }
157 }
158
159 fn GetFocusNode(&self) -> Option<DomRoot<Node>> {
161 if let Some(range) = self.range.get() {
162 match self.direction.get() {
163 Direction::Forwards => Some(range.end_container()),
164 _ => Some(range.start_container()),
165 }
166 } else {
167 None
168 }
169 }
170
171 fn FocusOffset(&self) -> u32 {
173 if let Some(range) = self.range.get() {
174 match self.direction.get() {
175 Direction::Forwards => range.end_offset(),
176 _ => range.start_offset(),
177 }
178 } else {
179 0
180 }
181 }
182
183 fn IsCollapsed(&self) -> bool {
185 if let Some(range) = self.range.get() {
186 range.collapsed()
187 } else {
188 true
189 }
190 }
191
192 fn RangeCount(&self) -> u32 {
194 if self.range.get().is_some() { 1 } else { 0 }
195 }
196
197 fn Type(&self) -> DOMString {
199 if let Some(range) = self.range.get() {
200 if range.collapsed() {
201 DOMString::from("Caret")
202 } else {
203 DOMString::from("Range")
204 }
205 } else {
206 DOMString::from("None")
207 }
208 }
209
210 fn GetRangeAt(&self, index: u32) -> Fallible<DomRoot<Range>> {
212 if index != 0 {
213 Err(Error::IndexSize(None))
214 } else if let Some(range) = self.range.get() {
215 Ok(DomRoot::from_ref(&range))
216 } else {
217 Err(Error::IndexSize(None))
218 }
219 }
220
221 fn AddRange(&self, range: &Range) {
223 if !self.is_same_root(&range.start_container()) {
225 return;
226 }
227
228 if self.RangeCount() != 0 {
230 return;
231 }
232
233 self.set_range(range);
235 self.direction.set(Direction::Forwards);
237 }
238
239 fn RemoveRange(&self, range: &Range) -> ErrorResult {
241 if let Some(own_range) = self.range.get() {
242 if &*own_range == range {
243 self.clear_range();
244 return Ok(());
245 }
246 }
247 Err(Error::NotFound(None))
248 }
249
250 fn RemoveAllRanges(&self) {
252 self.clear_range();
253 }
254
255 fn Empty(&self) {
259 self.clear_range();
260 }
261
262 fn Collapse(&self, cx: &mut JSContext, node: Option<&Node>, offset: u32) -> ErrorResult {
264 if let Some(node) = node {
265 if node.is_doctype() {
266 return Err(Error::InvalidNodeType(None));
268 }
269 if offset > node.len() {
270 return Err(Error::IndexSize(None));
272 }
273
274 if !self.is_same_root(node) {
275 return Ok(());
277 }
278
279 let range = Range::new(
281 &self.document,
282 node,
283 offset,
284 node,
285 offset,
286 CanGc::from_cx(cx),
287 );
288
289 self.set_range(&range);
291 self.direction.set(Direction::Forwards);
294 } else {
295 self.clear_range();
297 }
298 Ok(())
299 }
300
301 fn SetPosition(&self, cx: &mut JSContext, node: Option<&Node>, offset: u32) -> ErrorResult {
306 self.Collapse(cx, node, offset)
307 }
308
309 fn CollapseToStart(&self, cx: &mut JSContext) -> ErrorResult {
311 if let Some(range) = self.range.get() {
312 self.Collapse(cx, Some(&*range.start_container()), range.start_offset())
313 } else {
314 Err(Error::InvalidState(None))
315 }
316 }
317
318 fn CollapseToEnd(&self, cx: &mut JSContext) -> ErrorResult {
320 if let Some(range) = self.range.get() {
321 self.Collapse(cx, Some(&*range.end_container()), range.end_offset())
322 } else {
323 Err(Error::InvalidState(None))
324 }
325 }
326
327 fn Extend(&self, cx: &mut JSContext, node: &Node, offset: u32) -> ErrorResult {
331 if !self.is_same_root(node) {
332 return Ok(());
334 }
335 if let Some(range) = self.range.get() {
336 if node.is_doctype() {
337 return Err(Error::InvalidNodeType(None));
339 }
340
341 if offset > node.len() {
342 return Err(Error::IndexSize(None));
345 }
346
347 if !self.is_same_root(&range.start_container()) {
349 self.set_range(&Range::new(
351 &self.document,
352 node,
353 offset,
354 node,
355 offset,
356 CanGc::from_cx(cx),
357 ));
358 self.direction.set(Direction::Forwards);
359 } else {
360 let old_anchor_node = &*self.GetAnchorNode().unwrap(); let old_anchor_offset = self.AnchorOffset();
362 let is_old_anchor_before_or_equal = {
363 if old_anchor_node == node {
364 old_anchor_offset <= offset
365 } else {
366 old_anchor_node.is_before(node)
367 }
368 };
369 if is_old_anchor_before_or_equal {
370 self.set_range(&Range::new(
372 &self.document,
373 old_anchor_node,
374 old_anchor_offset,
375 node,
376 offset,
377 CanGc::from_cx(cx),
378 ));
379 self.direction.set(Direction::Forwards);
380 } else {
381 self.set_range(&Range::new(
383 &self.document,
384 node,
385 offset,
386 old_anchor_node,
387 old_anchor_offset,
388 CanGc::from_cx(cx),
389 ));
390 self.direction.set(Direction::Backwards);
391 }
392 };
393 } else {
394 return Err(Error::InvalidState(None));
396 }
397 Ok(())
398 }
399
400 fn SetBaseAndExtent(
402 &self,
403 cx: &mut JSContext,
404 anchor_node: &Node,
405 anchor_offset: u32,
406 focus_node: &Node,
407 focus_offset: u32,
408 ) -> ErrorResult {
409 if anchor_node.is_doctype() || focus_node.is_doctype() {
411 return Err(Error::InvalidNodeType(None));
413 }
414
415 if anchor_offset > anchor_node.len() || focus_offset > focus_node.len() {
416 return Err(Error::IndexSize(None));
417 }
418
419 if !self.is_same_root(anchor_node) || !self.is_same_root(focus_node) {
421 return Ok(());
422 }
423
424 let is_focus_before_anchor = {
426 if anchor_node == focus_node {
427 focus_offset < anchor_offset
428 } else {
429 focus_node.is_before(anchor_node)
430 }
431 };
432 if is_focus_before_anchor {
433 self.set_range(&Range::new(
434 &self.document,
435 focus_node,
436 focus_offset,
437 anchor_node,
438 anchor_offset,
439 CanGc::from_cx(cx),
440 ));
441 self.direction.set(Direction::Backwards);
442 } else {
443 self.set_range(&Range::new(
444 &self.document,
445 anchor_node,
446 anchor_offset,
447 focus_node,
448 focus_offset,
449 CanGc::from_cx(cx),
450 ));
451 self.direction.set(Direction::Forwards);
452 }
453 Ok(())
454 }
455
456 fn SelectAllChildren(&self, cx: &mut JSContext, node: &Node) -> ErrorResult {
458 if node.is_doctype() {
459 return Err(Error::InvalidNodeType(None));
461 }
462 if !self.is_same_root(node) {
463 return Ok(());
464 }
465
466 self.set_range(&Range::new(
470 &self.document,
471 node,
472 0,
473 node,
474 node.children_count(),
475 CanGc::from_cx(cx),
476 ));
477
478 self.direction.set(Direction::Forwards);
479 Ok(())
480 }
481
482 fn DeleteFromDocument(&self, cx: &mut JSContext) -> ErrorResult {
484 if let Some(range) = self.range.get() {
485 return range.DeleteContents(cx);
488 }
489 Ok(())
490 }
491
492 fn ContainsNode(&self, node: &Node, allow_partial_containment: bool) -> bool {
494 if !self.is_same_root(node) {
497 return false;
498 }
499 if let Some(range) = self.range.get() {
500 let start_node = &*range.start_container();
501 if !self.is_same_root(start_node) {
502 return false;
504 }
505 if allow_partial_containment {
506 if node.is_before(start_node) {
508 return false;
509 }
510 let end_node = &*range.end_container();
511 if end_node.is_before(node) {
512 return false;
513 }
514 if node == start_node {
515 return range.start_offset() < node.len();
516 }
517 if node == end_node {
518 return range.end_offset() > 0;
519 }
520 true
521 } else {
522 if node.is_before(start_node) {
523 return false;
524 }
525 let end_node = &*range.end_container();
526 if end_node.is_before(node) {
527 return false;
528 }
529 if node == start_node {
530 return range.start_offset() == 0;
531 }
532 if node == end_node {
533 return range.end_offset() == node.len();
534 }
535 true
536 }
537 } else {
538 false
540 }
541 }
542
543 fn Stringifier(&self) -> DOMString {
545 if let Some(range) = self.range.get() {
550 range.Stringifier()
551 } else {
552 DOMString::from("")
553 }
554 }
555}