aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--components/script/dom/document.rs6
-rw-r--r--components/script/dom/element.rs47
-rw-r--r--tests/wpt/metadata/html/semantics/disabled-elements/disabledElement.html.ini20
-rw-r--r--tests/wpt/metadata/html/semantics/selectors/pseudo-classes/focus.html.ini6
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