Don't allow disabled fields to be focused

This commit is contained in:
Matt Brubeck 2015-04-07 17:27:58 -07:00
parent 35fb516662
commit 4e63a5063e
4 changed files with 58 additions and 21 deletions

View file

@ -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

View file

@ -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.