diff options
Diffstat (limited to 'components/script/dom/document.rs')
-rw-r--r-- | components/script/dom/document.rs | 81 |
1 files changed, 66 insertions, 15 deletions
diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index e81800529d6..9fdff62aabb 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -39,6 +39,7 @@ use dom::domimplementation::DOMImplementation; use dom::element::{Element, ElementCreator}; use dom::event::{Event, EventBubbles, EventCancelable}; use dom::eventtarget::EventTarget; +use dom::focusevent::FocusEvent; use dom::htmlanchorelement::HTMLAnchorElement; use dom::htmlappletelement::HTMLAppletElement; use dom::htmlareaelement::HTMLAreaElement; @@ -106,8 +107,9 @@ use std::sync::Arc; use string_cache::{Atom, QualName}; use style::context::ReflowGoal; use style::restyle_hints::ElementSnapshot; -use style::stylesheets::Stylesheet; +use style::servo::Stylesheet; use time; +use url::percent_encoding::percent_decode; use url::{Host, Url}; use util::str::{DOMString, split_html_space_chars, str_join}; @@ -524,18 +526,38 @@ impl Document { /// Attempt to find a named element in this page's document. /// https://html.spec.whatwg.org/multipage/#the-indicated-part-of-the-document pub fn find_fragment_node(&self, fragid: &str) -> Option<Root<Element>> { - self.get_element_by_id(&Atom::from(fragid)).or_else(|| { - let check_anchor = |node: &HTMLAnchorElement| { - let elem = node.upcast::<Element>(); - elem.get_attribute(&ns!(), &atom!("name")) - .map_or(false, |attr| &**attr.value() == fragid) - }; - let doc_node = self.upcast::<Node>(); - doc_node.traverse_preorder() - .filter_map(Root::downcast) - .find(|node| check_anchor(&node)) - .map(Root::upcast) - }) + // Step 1 is not handled here; the fragid is already obtained by the calling function + // Step 2 + if fragid.is_empty() { + self.GetDocumentElement() + } else { + // Step 3 & 4 + String::from_utf8(percent_decode(fragid.as_bytes())).ok() + // Step 5 + .and_then(|decoded_fragid| self.get_element_by_id(&Atom::from(&*decoded_fragid))) + // Step 6 + .or_else(|| self.get_anchor_by_name(fragid)) + // Step 7 + .or_else(|| if fragid.to_lowercase() == "top" { + self.GetDocumentElement() + } else { + // Step 8 + None + }) + } + } + + fn get_anchor_by_name(&self, name: &str) -> Option<Root<Element>> { + let check_anchor = |node: &HTMLAnchorElement| { + let elem = node.upcast::<Element>(); + elem.get_attribute(&ns!(), &atom!("name")) + .map_or(false, |attr| &**attr.value() == name) + }; + let doc_node = self.upcast::<Node>(); + doc_node.traverse_preorder() + .filter_map(Root::downcast) + .find(|node| check_anchor(&node)) + .map(Root::upcast) } pub fn hit_test(&self, page_point: &Point2D<f32>) -> Option<UntrustedNodeAddress> { @@ -597,17 +619,21 @@ impl Document { /// Reassign the focus context to the element that last requested focus during this /// transaction, or none if no elements requested it. pub fn commit_focus_transaction(&self, focus_type: FocusType) { - // TODO: dispatch blur, focus, focusout, and focusin events if let Some(ref elem) = self.focused.get() { + let node = elem.upcast::<Node>(); elem.set_focus_state(false); + // FIXME: pass appropriate relatedTarget + self.fire_focus_event(FocusEventType::Blur, node, None); } self.focused.set(self.possibly_focused.get().r()); if let Some(ref elem) = self.focused.get() { elem.set_focus_state(true); - + let node = elem.upcast::<Node>(); + // FIXME: pass appropriate relatedTarget + self.fire_focus_event(FocusEventType::Focus, node, None); // Update the focus state for all elements in the focus chain. // https://html.spec.whatwg.org/multipage/#focus-chain if focus_type == FocusType::Element { @@ -1439,6 +1465,25 @@ impl Document { pub fn get_dom_complete(&self) -> u64 { self.dom_complete.get() } + + // https://html.spec.whatwg.org/multipage/#fire-a-focus-event + fn fire_focus_event(&self, focus_event_type: FocusEventType, node: &Node, relatedTarget: Option<&EventTarget>) { + let (event_name, does_bubble) = match focus_event_type { + FocusEventType::Focus => (DOMString::from("focus"), EventBubbles::DoesNotBubble), + FocusEventType::Blur => (DOMString::from("blur"), EventBubbles::DoesNotBubble), + }; + let event = FocusEvent::new(&self.window, + event_name, + does_bubble, + EventCancelable::NotCancelable, + Some(&self.window), + 0i32, + relatedTarget); + let event = event.upcast::<Event>(); + event.set_trusted(true); + let target = node.upcast(); + event.fire(target); + } } #[derive(PartialEq, HeapSizeOf)] @@ -2573,3 +2618,9 @@ pub enum FocusType { Element, // The first focus message - focus the element itself Parent, // Focusing a parent element (an iframe) } + +/// Focus events +pub enum FocusEventType { + Focus, // Element gained focus. Doesn't bubble. + Blur, // Element lost focus. Doesn't bubble. +} |