1use std::cell::Cell;
6
7use dom_struct::dom_struct;
8use js::context::JSContext;
9use script_bindings::reflector::{Reflector, reflect_dom_object_with_cx};
10
11use crate::dom::bindings::codegen::Bindings::NodeBinding::{GetRootNodeOptions, NodeMethods};
12use crate::dom::bindings::codegen::Bindings::RangeBinding::RangeMethods;
13use crate::dom::bindings::codegen::Bindings::SelectionBinding::SelectionMethods;
14use crate::dom::bindings::error::{Error, ErrorResult, Fallible};
15use crate::dom::bindings::inheritance::Castable;
16use crate::dom::bindings::refcounted::Trusted;
17use crate::dom::bindings::reflector::DomGlobal;
18use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom};
19use crate::dom::bindings::str::DOMString;
20use crate::dom::document::Document;
21use crate::dom::eventtarget::EventTarget;
22use crate::dom::node::{Node, NodeTraits};
23use crate::dom::range::Range;
24use crate::script_runtime::CanGc;
25
26#[derive(Clone, Copy, JSTraceable, MallocSizeOf)]
27enum Direction {
28 Forwards,
29 Backwards,
30 Directionless,
31}
32
33#[dom_struct]
34pub(crate) struct Selection {
35 reflector_: Reflector,
36 document: Dom<Document>,
37 range: MutNullableDom<Range>,
38 direction: Cell<Direction>,
39 has_scheduled_selectionchange_event: Cell<bool>,
41}
42
43impl Selection {
44 fn new_inherited(document: &Document) -> Selection {
45 Selection {
46 reflector_: Reflector::new(),
47 document: Dom::from_ref(document),
48 range: MutNullableDom::new(None),
49 direction: Cell::new(Direction::Directionless),
50 has_scheduled_selectionchange_event: Cell::new(false),
51 }
52 }
53
54 pub(crate) fn new(cx: &mut JSContext, document: &Document) -> DomRoot<Selection> {
55 reflect_dom_object_with_cx(
56 Box::new(Selection::new_inherited(document)),
57 &*document.global(),
58 cx,
59 )
60 }
61
62 fn set_range(&self, range: &Range) {
63 if let Some(existing) = self.range.get() &&
67 &*existing == range
68 {
69 return;
70 }
71 self.range.set(Some(range));
72 range.associate_selection(self);
73 self.queue_selectionchange_task();
74 }
75
76 fn clear_range(&self) {
77 if let Some(range) = self.range.get() {
80 range.disassociate_selection(self);
81 self.range.set(None);
82 self.queue_selectionchange_task();
83 }
84 }
85
86 pub(crate) fn queue_selectionchange_task(&self) {
88 self.document.clear_command_overrides();
94
95 if self.has_scheduled_selectionchange_event.get() {
97 return;
98 }
99 self.has_scheduled_selectionchange_event.set(true);
101 let this = Trusted::new(self);
103 self.document
104 .owner_global()
105 .task_manager()
106 .user_interaction_task_source() .queue(
108 task!(selectionchange_task_steps: move |cx| {
110 let this = this.root();
111 this.has_scheduled_selectionchange_event.set(false);
113 this.document.upcast::<EventTarget>().fire_event(cx, atom!("selectionchange"));
120 }),
121 );
122 }
123
124 fn is_same_root(&self, node: &Node) -> bool {
125 &*node.GetRootNode(&GetRootNodeOptions::empty()) == self.document.upcast::<Node>()
126 }
127
128 pub(crate) fn active_range(&self) -> Option<DomRoot<Range>> {
130 self.range.get()
132 }
133
134 pub(crate) fn collapse_current_range(&self, node: &Node, offset: u32) {
135 let range = self.range.get().expect("Must always have a range");
136 range.set_start(node, offset);
137 range.set_end(node, offset);
138 }
139
140 pub(crate) fn extend_current_range(&self, node: &Node, offset: u32) {
141 let range = self.range.get().expect("Must always have a range");
142 assert!(range.collapsed(), "Must only extend after collapsing");
143
144 let anchor_node = range.start_container();
145 if (*anchor_node == *node && range.start_offset() < offset) || anchor_node.is_before(node) {
146 range.set_end(node, offset);
147 self.direction.set(Direction::Forwards);
148 } else {
149 range.set_start(node, offset);
150 self.direction.set(Direction::Backwards);
151 }
152 }
153}
154
155impl SelectionMethods<crate::DomTypeHolder> for Selection {
156 fn GetAnchorNode(&self) -> Option<DomRoot<Node>> {
158 if let Some(range) = self.range.get() {
159 match self.direction.get() {
160 Direction::Forwards => Some(range.start_container()),
161 _ => Some(range.end_container()),
162 }
163 } else {
164 None
165 }
166 }
167
168 fn AnchorOffset(&self) -> u32 {
170 if let Some(range) = self.range.get() {
171 match self.direction.get() {
172 Direction::Forwards => range.start_offset(),
173 _ => range.end_offset(),
174 }
175 } else {
176 0
177 }
178 }
179
180 fn GetFocusNode(&self) -> Option<DomRoot<Node>> {
182 if let Some(range) = self.range.get() {
183 match self.direction.get() {
184 Direction::Forwards => Some(range.end_container()),
185 _ => Some(range.start_container()),
186 }
187 } else {
188 None
189 }
190 }
191
192 fn FocusOffset(&self) -> u32 {
194 if let Some(range) = self.range.get() {
195 match self.direction.get() {
196 Direction::Forwards => range.end_offset(),
197 _ => range.start_offset(),
198 }
199 } else {
200 0
201 }
202 }
203
204 fn IsCollapsed(&self) -> bool {
206 if let Some(range) = self.range.get() {
207 range.collapsed()
208 } else {
209 true
210 }
211 }
212
213 fn RangeCount(&self) -> u32 {
215 if self.range.get().is_some() { 1 } else { 0 }
216 }
217
218 fn Type(&self) -> DOMString {
220 if let Some(range) = self.range.get() {
221 if range.collapsed() {
222 DOMString::from("Caret")
223 } else {
224 DOMString::from("Range")
225 }
226 } else {
227 DOMString::from("None")
228 }
229 }
230
231 fn GetRangeAt(&self, index: u32) -> Fallible<DomRoot<Range>> {
233 if index != 0 {
234 Err(Error::IndexSize(None))
235 } else if let Some(range) = self.range.get() {
236 Ok(DomRoot::from_ref(&range))
237 } else {
238 Err(Error::IndexSize(None))
239 }
240 }
241
242 fn AddRange(&self, range: &Range) {
244 if !self.is_same_root(&range.start_container()) {
246 return;
247 }
248
249 if self.RangeCount() != 0 {
251 return;
252 }
253
254 self.set_range(range);
256 self.direction.set(Direction::Forwards);
258 }
259
260 fn RemoveRange(&self, range: &Range) -> ErrorResult {
262 if let Some(own_range) = self.range.get() &&
263 &*own_range == range
264 {
265 self.clear_range();
266 return Ok(());
267 }
268 Err(Error::NotFound(None))
269 }
270
271 fn RemoveAllRanges(&self) {
273 self.clear_range();
274 }
275
276 fn Empty(&self) {
280 self.clear_range();
281 }
282
283 fn Collapse(&self, cx: &mut JSContext, node: Option<&Node>, offset: u32) -> ErrorResult {
285 if let Some(node) = node {
286 if node.is_doctype() {
287 return Err(Error::InvalidNodeType(None));
289 }
290 if offset > node.len() {
291 return Err(Error::IndexSize(None));
293 }
294
295 if !self.is_same_root(node) {
296 return Ok(());
298 }
299
300 let range = Range::new(
302 &self.document,
303 node,
304 offset,
305 node,
306 offset,
307 CanGc::from_cx(cx),
308 );
309
310 self.set_range(&range);
312 self.direction.set(Direction::Forwards);
315 } else {
316 self.clear_range();
318 }
319 Ok(())
320 }
321
322 fn SetPosition(&self, cx: &mut JSContext, node: Option<&Node>, offset: u32) -> ErrorResult {
327 self.Collapse(cx, node, offset)
328 }
329
330 fn CollapseToStart(&self, cx: &mut JSContext) -> ErrorResult {
332 if let Some(range) = self.range.get() {
333 self.Collapse(cx, Some(&*range.start_container()), range.start_offset())
334 } else {
335 Err(Error::InvalidState(None))
336 }
337 }
338
339 fn CollapseToEnd(&self, cx: &mut JSContext) -> ErrorResult {
341 if let Some(range) = self.range.get() {
342 self.Collapse(cx, Some(&*range.end_container()), range.end_offset())
343 } else {
344 Err(Error::InvalidState(None))
345 }
346 }
347
348 fn Extend(&self, cx: &mut JSContext, node: &Node, offset: u32) -> ErrorResult {
352 if !self.is_same_root(node) {
353 return Ok(());
355 }
356 if let Some(range) = self.range.get() {
357 if node.is_doctype() {
358 return Err(Error::InvalidNodeType(None));
360 }
361
362 if offset > node.len() {
363 return Err(Error::IndexSize(None));
366 }
367
368 if !self.is_same_root(&range.start_container()) {
370 self.set_range(&Range::new(
372 &self.document,
373 node,
374 offset,
375 node,
376 offset,
377 CanGc::from_cx(cx),
378 ));
379 self.direction.set(Direction::Forwards);
380 } else {
381 let old_anchor_node = &*self.GetAnchorNode().unwrap(); let old_anchor_offset = self.AnchorOffset();
383 let is_old_anchor_before_or_equal = {
384 if old_anchor_node == node {
385 old_anchor_offset <= offset
386 } else {
387 old_anchor_node.is_before(node)
388 }
389 };
390 if is_old_anchor_before_or_equal {
391 self.set_range(&Range::new(
393 &self.document,
394 old_anchor_node,
395 old_anchor_offset,
396 node,
397 offset,
398 CanGc::from_cx(cx),
399 ));
400 self.direction.set(Direction::Forwards);
401 } else {
402 self.set_range(&Range::new(
404 &self.document,
405 node,
406 offset,
407 old_anchor_node,
408 old_anchor_offset,
409 CanGc::from_cx(cx),
410 ));
411 self.direction.set(Direction::Backwards);
412 }
413 };
414 } else {
415 return Err(Error::InvalidState(None));
417 }
418 Ok(())
419 }
420
421 fn SetBaseAndExtent(
423 &self,
424 cx: &mut JSContext,
425 anchor_node: &Node,
426 anchor_offset: u32,
427 focus_node: &Node,
428 focus_offset: u32,
429 ) -> ErrorResult {
430 if anchor_node.is_doctype() || focus_node.is_doctype() {
432 return Err(Error::InvalidNodeType(None));
434 }
435
436 if anchor_offset > anchor_node.len() || focus_offset > focus_node.len() {
437 return Err(Error::IndexSize(None));
438 }
439
440 if !self.is_same_root(anchor_node) || !self.is_same_root(focus_node) {
442 return Ok(());
443 }
444
445 let is_focus_before_anchor = {
447 if anchor_node == focus_node {
448 focus_offset < anchor_offset
449 } else {
450 focus_node.is_before(anchor_node)
451 }
452 };
453 if is_focus_before_anchor {
454 self.set_range(&Range::new(
455 &self.document,
456 focus_node,
457 focus_offset,
458 anchor_node,
459 anchor_offset,
460 CanGc::from_cx(cx),
461 ));
462 self.direction.set(Direction::Backwards);
463 } else {
464 self.set_range(&Range::new(
465 &self.document,
466 anchor_node,
467 anchor_offset,
468 focus_node,
469 focus_offset,
470 CanGc::from_cx(cx),
471 ));
472 self.direction.set(Direction::Forwards);
473 }
474 Ok(())
475 }
476
477 fn SelectAllChildren(&self, cx: &mut JSContext, node: &Node) -> ErrorResult {
479 if node.is_doctype() {
480 return Err(Error::InvalidNodeType(None));
482 }
483 if !self.is_same_root(node) {
484 return Ok(());
485 }
486
487 self.set_range(&Range::new(
491 &self.document,
492 node,
493 0,
494 node,
495 node.children_count(),
496 CanGc::from_cx(cx),
497 ));
498
499 self.direction.set(Direction::Forwards);
500 Ok(())
501 }
502
503 fn DeleteFromDocument(&self, cx: &mut JSContext) -> ErrorResult {
505 if let Some(range) = self.range.get() {
506 return range.DeleteContents(cx);
509 }
510 Ok(())
511 }
512
513 fn ContainsNode(&self, node: &Node, allow_partial_containment: bool) -> bool {
515 if !self.is_same_root(node) {
518 return false;
519 }
520 if let Some(range) = self.range.get() {
521 let start_node = &*range.start_container();
522 if !self.is_same_root(start_node) {
523 return false;
525 }
526 if allow_partial_containment {
527 if node.is_before(start_node) {
529 return false;
530 }
531 let end_node = &*range.end_container();
532 if end_node.is_before(node) {
533 return false;
534 }
535 if node == start_node {
536 return range.start_offset() < node.len();
537 }
538 if node == end_node {
539 return range.end_offset() > 0;
540 }
541 true
542 } else {
543 if node.is_before(start_node) {
544 return false;
545 }
546 let end_node = &*range.end_container();
547 if end_node.is_before(node) {
548 return false;
549 }
550 if node == start_node {
551 return range.start_offset() == 0;
552 }
553 if node == end_node {
554 return range.end_offset() == node.len();
555 }
556 true
557 }
558 } else {
559 false
561 }
562 }
563
564 fn Stringifier(&self) -> DOMString {
566 if let Some(range) = self.range.get() {
571 range.Stringifier()
572 } else {
573 DOMString::from("")
574 }
575 }
576}