diff options
4 files changed, 58 insertions, 21 deletions
diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index ca4182164d8..57cee418838 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -36,7 +36,7 @@ use dom::documentfragment::DocumentFragment; use dom::documenttype::DocumentType; use dom::domimplementation::DOMImplementation; use dom::element::{Element, ElementCreator, AttributeHandlers}; -use dom::element::{ElementTypeId, ActivationElementHelpers}; +use dom::element::{ElementTypeId, ActivationElementHelpers, FocusElementHelpers}; use dom::event::{Event, EventBubbles, EventCancelable, EventHelpers}; use dom::eventtarget::{EventTarget, EventTargetTypeId, EventTargetHelpers}; use dom::htmlanchorelement::HTMLAnchorElement; @@ -448,7 +448,9 @@ impl<'a> DocumentHelpers<'a> for JSRef<'a, Document> { /// Request that the given element receive focus once the current transaction is complete. fn request_focus(self, elem: JSRef<Element>) { - self.possibly_focused.assign(Some(elem)) + if elem.is_focusable_area() { + self.possibly_focused.assign(Some(elem)) + } } /// Reassign the focus context to the element that last requested focus during this diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index 405ed80b95f..4625795b6c0 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -601,6 +601,53 @@ impl<'a> ElementHelpers<'a> for JSRef<'a, Element> { } } +pub trait FocusElementHelpers { + /// https://html.spec.whatwg.org/multipage/interaction.html#focusable-area + fn is_focusable_area(self) -> bool; + + /// https://html.spec.whatwg.org/multipage/scripting.html#concept-element-disabled + fn is_actually_disabled(self) -> bool; +} + +impl<'a> FocusElementHelpers for JSRef<'a, Element> { + fn is_focusable_area(self) -> bool { + if self.is_actually_disabled() { + 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/interaction.html#specially-focusable + let node: JSRef<Node> = NodeCast::from_ref(self); + match node.type_id() { + NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLAnchorElement)) | + NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLInputElement)) | + NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLSelectElement)) | + NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTextAreaElement)) => { + true + } + _ => false + } + } + + fn is_actually_disabled(self) -> bool { + let node: JSRef<Node> = NodeCast::from_ref(self); + match node.type_id() { + NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLButtonElement)) | + NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLInputElement)) | + NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLSelectElement)) | + NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTextAreaElement)) | + NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLOptionElement)) => { + node.get_disabled_state() + } + // TODO: + // an optgroup element that has a disabled attribute + // a menuitem element that has a disabled attribute + // a fieldset element that is a disabled fieldset + _ => false + } + } +} + pub trait AttributeHandlers { /// Returns the attribute with given namespace and case-sensitive local /// name, if any. diff --git a/tests/wpt/metadata/html/semantics/disabled-elements/disabledElement.html.ini b/tests/wpt/metadata/html/semantics/disabled-elements/disabledElement.html.ini index 52c221a1e49..cffbca16463 100644 --- a/tests/wpt/metadata/html/semantics/disabled-elements/disabledElement.html.ini +++ b/tests/wpt/metadata/html/semantics/disabled-elements/disabledElement.html.ini @@ -1,23 +1,5 @@ [disabledElement.html] type: testharness - [A disabled <button> should not be focusable] - expected: FAIL - - [A disabled <input> should not be focusable] - expected: FAIL - - [A disabled <select> should not be focusable] - expected: FAIL - - [A disabled <optgroup> should not be focusable] - expected: FAIL - - [A disabled <option> should not be focusable] - expected: FAIL - - [A disabled <textarea> should not be focusable] - expected: FAIL - - [A disabled <input[type=radio\]> should not be focusable] + [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 e39152a3225..25bc6b23c6a 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 @@ -2,4 +2,10 @@ type: testharness [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 |