aboutsummaryrefslogtreecommitdiffstats
path: root/components/script/dom/element.rs
diff options
context:
space:
mode:
Diffstat (limited to 'components/script/dom/element.rs')
-rw-r--r--components/script/dom/element.rs81
1 files changed, 77 insertions, 4 deletions
diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs
index d3b5b1946aa..ca12d6f2afd 100644
--- a/components/script/dom/element.rs
+++ b/components/script/dom/element.rs
@@ -4,16 +4,18 @@
//! Element nodes.
+use dom::activation::Activatable;
use dom::attr::{Attr, ReplacedAttr, FirstSetAttr, AttrHelpers, AttrHelpersForLayout};
use dom::attr::{AttrValue, StringAttrValue, UIntAttrValue, AtomAttrValue};
use dom::namednodemap::NamedNodeMap;
use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::AttrBinding::AttrMethods;
+use dom::bindings::codegen::Bindings::EventBinding::EventMethods;
use dom::bindings::codegen::Bindings::ElementBinding;
use dom::bindings::codegen::Bindings::ElementBinding::ElementMethods;
use dom::bindings::codegen::Bindings::NamedNodeMapBinding::NamedNodeMapMethods;
-use dom::bindings::codegen::InheritTypes::{ElementDerived, HTMLInputElementDerived};
-use dom::bindings::codegen::InheritTypes::{HTMLTableCellElementDerived, NodeCast};
+use dom::bindings::codegen::InheritTypes::{ElementDerived, HTMLInputElementDerived, HTMLTableCellElementDerived};
+use dom::bindings::codegen::InheritTypes::{HTMLInputElementCast, NodeCast, EventTargetCast, ElementCast};
use dom::bindings::js::{MutNullableJS, JS, JSRef, Temporary, TemporaryPushable};
use dom::bindings::js::{OptionalSettable, OptionalRootable, Root};
use dom::bindings::utils::{Reflectable, Reflector};
@@ -24,7 +26,8 @@ use dom::domrect::DOMRect;
use dom::domrectlist::DOMRectList;
use dom::document::{Document, DocumentHelpers, LayoutDocumentHelpers};
use dom::domtokenlist::DOMTokenList;
-use dom::eventtarget::{EventTarget, NodeTargetTypeId};
+use dom::event::Event;
+use dom::eventtarget::{EventTarget, NodeTargetTypeId, EventTargetHelpers};
use dom::htmlcollection::HTMLCollection;
use dom::htmlinputelement::{HTMLInputElement, RawLayoutHTMLInputElementHelpers};
use dom::htmlserializer::serialize;
@@ -41,7 +44,7 @@ use servo_util::namespace;
use servo_util::str::{DOMString, LengthOrPercentageOrAuto};
use std::ascii::AsciiExt;
-use std::cell::{Ref, RefMut};
+use std::cell::{Cell, Ref, RefMut};
use std::default::Default;
use std::mem;
use string_cache::{Atom, Namespace, QualName};
@@ -57,6 +60,7 @@ pub struct Element {
style_attribute: DOMRefCell<Option<style::PropertyDeclarationBlock>>,
attr_list: MutNullableJS<NamedNodeMap>,
class_list: MutNullableJS<DOMTokenList>,
+ click_in_progress: Cell<bool>,
}
impl ElementDerived for EventTarget {
@@ -175,6 +179,7 @@ impl Element {
attr_list: Default::default(),
class_list: Default::default(),
style_attribute: DOMRefCell::new(None),
+ click_in_progress: Cell::new(false),
}
}
@@ -1183,3 +1188,71 @@ impl<'a> style::TElement<'a> for JSRef<'a, Element> {
}
}
}
+
+pub trait ActivationElementHelpers<'a> {
+ fn as_maybe_activatable(&'a self) -> Option<&'a Activatable + 'a>;
+ fn click_in_progress(self) -> bool;
+ fn set_click_in_progress(self, click: bool);
+ fn nearest_activable_element(self) -> Option<JSRef<'a, Element>>;
+ fn authentic_click_activation<'b>(self, event: JSRef<'b, Event>);
+}
+
+impl<'a> ActivationElementHelpers<'a> for JSRef<'a, Element> {
+ fn as_maybe_activatable(&'a self) -> Option<&'a Activatable + 'a> {
+ let node: JSRef<Node> = NodeCast::from_ref(*self);
+ match node.type_id() {
+ ElementNodeTypeId(HTMLInputElementTypeId) => {
+ let _element: &'a JSRef<'a, HTMLInputElement> = HTMLInputElementCast::to_borrowed_ref(self).unwrap();
+ // Some(element as &'a Activatable + 'a)
+ None
+ },
+ _ => {
+ None
+ }
+ }
+ }
+
+ fn click_in_progress(self) -> bool {
+ self.click_in_progress.get()
+ }
+
+ fn set_click_in_progress(self, click: bool) {
+ self.click_in_progress.set(click)
+ }
+
+ // https://html.spec.whatwg.org/multipage/interaction.html#nearest-activatable-element
+ fn nearest_activable_element(self) -> Option<JSRef<'a, Element>> {
+ let node: JSRef<Node> = NodeCast::from_ref(self);
+ node.ancestors()
+ .filter_map(|node| ElementCast::to_ref(node))
+ .filter(|e| e.as_maybe_activatable().is_some()).next()
+ }
+
+ // https://html.spec.whatwg.org/multipage/interaction.html#run-authentic-click-activation-steps
+ fn authentic_click_activation<'b>(self, event: JSRef<'b, Event>) {
+ let target: JSRef<EventTarget> = EventTargetCast::from_ref(self);
+ // Step 2 (requires canvas support)
+ // Step 3
+ self.set_click_in_progress(true);
+ // Step 4
+ let e = self.nearest_activable_element();
+ // Step 5
+ e.map(|a| a.as_maybe_activatable().map(|el| el.pre_click_activation()));
+ // Step 6
+ target.dispatch_event_with_target(None, event).ok();
+ e.map(|el| {
+ if NodeCast::from_ref(el).is_in_doc() {
+ return; // XXXManishearth do we need this check?
+ }
+ el.as_maybe_activatable().map(|a| {
+ if event.DefaultPrevented() {
+ a.post_click_activation();
+ } else {
+ a.canceled_activation();
+ }
+ });
+ });
+ // Step 7
+ self.set_click_in_progress(false);
+ }
+}