diff options
-rw-r--r-- | components/script/dom/element.rs | 11 | ||||
-rw-r--r-- | components/script/dom/htmlelement.rs | 62 | ||||
-rw-r--r-- | components/script/dom/node.rs | 3 | ||||
-rw-r--r-- | components/script/dom/virtualmethods.rs | 8 | ||||
-rw-r--r-- | tests/wpt/metadata/html/semantics/disabled-elements/disabledElement.html.ini | 5 | ||||
-rw-r--r-- | tests/wpt/metadata/html/semantics/selectors/pseudo-classes/focus.html.ini | 7 |
6 files changed, 80 insertions, 16 deletions
diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index a666a28e627..b586172816d 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -54,7 +54,7 @@ use dom::htmltablecellelement::{HTMLTableCellElement, HTMLTableCellElementHelper use dom::htmltablerowelement::{HTMLTableRowElement, HTMLTableRowElementHelpers}; use dom::htmltablesectionelement::{HTMLTableSectionElement, HTMLTableSectionElementHelpers}; use dom::htmltextareaelement::{HTMLTextAreaElement, RawLayoutHTMLTextAreaElementHelpers}; -use dom::node::{CLICK_IN_PROGRESS, LayoutNodeHelpers, Node, NodeHelpers, NodeTypeId}; +use dom::node::{CLICK_IN_PROGRESS, LayoutNodeHelpers, Node, NodeHelpers, NodeTypeId, SEQUENTIALLY_FOCUSABLE}; use dom::node::{document_from_node, NodeDamage}; use dom::node::{window_from_node}; use dom::nodelist::NodeList; @@ -757,9 +757,11 @@ impl<'a> FocusElementHelpers for JSRef<'a, Element> { return false; } // TODO: Check whether the element is being rendered (i.e. not hidden). - // TODO: Check the tabindex focus flag. - // https://html.spec.whatwg.org/multipage/#specially-focusable let node: JSRef<Node> = NodeCast::from_ref(self); + if node.get_flag(SEQUENTIALLY_FOCUSABLE) { + return true; + } + // https://html.spec.whatwg.org/multipage/#specially-focusable match node.type_id() { NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLAnchorElement)) | NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLInputElement)) | @@ -979,6 +981,9 @@ impl<'a> AttributeHandlers for JSRef<'a, Element> { self.attrs.borrow_mut().remove(idx); attr.r().set_owner(None); + if attr.r().namespace() == &ns!("") { + vtable_for(&NodeCast::from_ref(self)).after_remove_attr(attr.r().name()); + } let node: JSRef<Node> = NodeCast::from_ref(self); if node.is_in_doc() { diff --git a/components/script/dom/htmlelement.rs b/components/script/dom/htmlelement.rs index ce70535de74..b3ffe4b056f 100644 --- a/components/script/dom/htmlelement.rs +++ b/components/script/dom/htmlelement.rs @@ -4,6 +4,7 @@ use dom::attr::Attr; use dom::attr::AttrHelpers; +use dom::attr::AttrValue; use dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull; use dom::bindings::codegen::Bindings::HTMLElementBinding; use dom::bindings::codegen::Bindings::HTMLElementBinding::HTMLElementMethods; @@ -24,7 +25,7 @@ use dom::eventtarget::{EventTarget, EventTargetHelpers, EventTargetTypeId}; use dom::htmlinputelement::HTMLInputElement; use dom::htmlmediaelement::HTMLMediaElementTypeId; use dom::htmltablecellelement::HTMLTableCellElementTypeId; -use dom::node::{Node, NodeHelpers, NodeTypeId, document_from_node, window_from_node}; +use dom::node::{Node, NodeHelpers, NodeTypeId, document_from_node, window_from_node, SEQUENTIALLY_FOCUSABLE}; use dom::virtualmethods::VirtualMethods; use dom::window::WindowHelpers; @@ -70,6 +71,7 @@ impl HTMLElement { trait PrivateHTMLElementHelpers { fn is_body_or_frameset(self) -> bool; + fn update_sequentially_focusable_status(self); } impl<'a> PrivateHTMLElementHelpers for JSRef<'a, HTMLElement> { @@ -77,6 +79,44 @@ impl<'a> PrivateHTMLElementHelpers for JSRef<'a, HTMLElement> { let eventtarget: JSRef<EventTarget> = EventTargetCast::from_ref(self); eventtarget.is_htmlbodyelement() || eventtarget.is_htmlframesetelement() } + + fn update_sequentially_focusable_status(self) { + let element = ElementCast::from_ref(self); + let node = NodeCast::from_ref(self); + if element.has_attribute(&atom!("tabindex")) { + node.set_flag(SEQUENTIALLY_FOCUSABLE, true); + } else { + match node.type_id() { + NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLButtonElement)) | + NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLSelectElement)) | + NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLIFrameElement)) | + NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTextAreaElement)) + => node.set_flag(SEQUENTIALLY_FOCUSABLE, true), + NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLLinkElement)) | + NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLAnchorElement)) => { + if element.has_attribute(&atom!("href")) { + node.set_flag(SEQUENTIALLY_FOCUSABLE, true); + } + }, + _ => { + if let Some(attr) = element.get_attribute(&ns!(""), &atom!("draggable")) { + let attr = attr.root(); + let attr = attr.r(); + let value = attr.value(); + let is_true = match *value { + AttrValue::String(ref string) => string == "true", + _ => false, + }; + node.set_flag(SEQUENTIALLY_FOCUSABLE, is_true); + } else { + node.set_flag(SEQUENTIALLY_FOCUSABLE, false); + } + //TODO set SEQUENTIALLY_FOCUSABLE flag if editing host + //TODO set SEQUENTIALLY_FOCUSABLE flag if "sorting interface th elements" + }, + } + } + } } impl<'a> HTMLElementMethods for JSRef<'a, HTMLElement> { @@ -220,6 +260,19 @@ impl<'a> VirtualMethods for JSRef<'a, HTMLElement> { Some(element as &VirtualMethods) } + fn before_remove_attr(&self, attr: JSRef<Attr>) { + if let Some(ref s) = self.super_type() { + s.before_remove_attr(attr); + } + } + + fn after_remove_attr(&self, name: &Atom) { + if let Some(ref s) = self.super_type() { + s.after_remove_attr(name); + } + self.update_sequentially_focusable_status(); + } + fn after_set_attr(&self, attr: JSRef<Attr>) { if let Some(ref s) = self.super_type() { s.after_set_attr(attr); @@ -236,6 +289,13 @@ impl<'a> VirtualMethods for JSRef<'a, HTMLElement> { &name[2..], (**attr.value()).to_owned()); } + self.update_sequentially_focusable_status(); + } + fn bind_to_tree(&self, tree_in_doc: bool) { + if let Some(ref s) = self.super_type() { + s.bind_to_tree(tree_in_doc); + } + self.update_sequentially_focusable_status(); } } diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index ec707cd3e02..92ed3f41f6e 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -158,6 +158,9 @@ bitflags! { const CLICK_IN_PROGRESS = 0x100, #[doc = "Specifies whether this node has the focus."] const IN_FOCUS_STATE = 0x200, + #[doc = "Specifies whether this node is focusable and whether it is supposed \ + to be reachable with using sequential focus navigation."] + const SEQUENTIALLY_FOCUSABLE = 0x400, } } diff --git a/components/script/dom/virtualmethods.rs b/components/script/dom/virtualmethods.rs index a83c801831d..4effc4daf33 100644 --- a/components/script/dom/virtualmethods.rs +++ b/components/script/dom/virtualmethods.rs @@ -91,6 +91,14 @@ pub trait VirtualMethods { } } + /// Called when changing or removing attributes, after all modification + /// has taken place. + fn after_remove_attr(&self, name: &Atom) { + if let Some(ref s) = self.super_type() { + s.after_remove_attr(name); + } + } + /// Returns the right AttrValue variant for the attribute with name `name` /// on this element. fn parse_plain_attribute(&self, name: &Atom, value: DOMString) -> AttrValue { diff --git a/tests/wpt/metadata/html/semantics/disabled-elements/disabledElement.html.ini b/tests/wpt/metadata/html/semantics/disabled-elements/disabledElement.html.ini deleted file mode 100644 index cffbca16463..00000000000 --- a/tests/wpt/metadata/html/semantics/disabled-elements/disabledElement.html.ini +++ /dev/null @@ -1,5 +0,0 @@ -[disabledElement.html] - type: testharness - [A disabled <span> should be focusable] - expected: FAIL - diff --git a/tests/wpt/metadata/html/semantics/selectors/pseudo-classes/focus.html.ini b/tests/wpt/metadata/html/semantics/selectors/pseudo-classes/focus.html.ini index f3529fc646d..387c512ce75 100644 --- a/tests/wpt/metadata/html/semantics/selectors/pseudo-classes/focus.html.ini +++ b/tests/wpt/metadata/html/semantics/selectors/pseudo-classes/focus.html.ini @@ -3,12 +3,5 @@ [input3 has the attribute autofocus] expected: FAIL - [tabindex attribute makes the element focusable] - expected: FAIL - [editable elements are focusable] expected: FAIL - - [':focus' matches focussed body with tabindex] - expected: FAIL - |