From cfc3500dbf9f1dd9b966c4010fb01b21bfd5d80b Mon Sep 17 00:00:00 2001 From: Lanza Date: Mon, 11 Jan 2016 12:46:39 +0100 Subject: [PATCH] Implement HTMLDetailsElement. Fixes #9216 --- components/script/dom/create.rs | 3 +- components/script/dom/htmldetailselement.rs | 107 +++++++++++++++++ components/script/dom/macros.rs | 1 + components/script/dom/mod.rs | 1 + components/script/dom/virtualmethods.rs | 4 + .../script/dom/webidls/EventHandler.webidl | 1 + .../dom/webidls/HTMLDetailsElement.webidl | 9 ++ .../wpt/metadata/html/dom/interfaces.html.ini | 40 ------- .../html/dom/reflection-misc.html.ini | 109 ------------------ .../the-details-element/details.html.ini | 11 -- .../the-details-element/toggleEvent.html.ini | 21 ---- .../html/semantics/interfaces.html.ini | 7 -- .../wpt/mozilla/tests/mozilla/interfaces.html | 1 + 13 files changed, 126 insertions(+), 189 deletions(-) create mode 100644 components/script/dom/htmldetailselement.rs create mode 100644 components/script/dom/webidls/HTMLDetailsElement.webidl delete mode 100644 tests/wpt/metadata/html/semantics/interactive-elements/the-details-element/details.html.ini delete mode 100644 tests/wpt/metadata/html/semantics/interactive-elements/the-details-element/toggleEvent.html.ini diff --git a/components/script/dom/create.rs b/components/script/dom/create.rs index 75a08464af7..4f095b905b1 100644 --- a/components/script/dom/create.rs +++ b/components/script/dom/create.rs @@ -17,6 +17,7 @@ use dom::htmlbuttonelement::HTMLButtonElement; use dom::htmlcanvaselement::HTMLCanvasElement; use dom::htmldataelement::HTMLDataElement; use dom::htmldatalistelement::HTMLDataListElement; +use dom::htmldetailselement::HTMLDetailsElement; use dom::htmldialogelement::HTMLDialogElement; use dom::htmldirectoryelement::HTMLDirectoryElement; use dom::htmldivelement::HTMLDivElement; @@ -138,7 +139,7 @@ pub fn create_element(name: QualName, atom!("datalist") => make!(HTMLDataListElement), atom!("dd") => make!(HTMLElement), atom!("del") => make!(HTMLModElement), - atom!("details") => make!(HTMLElement), + atom!("details") => make!(HTMLDetailsElement), atom!("dfn") => make!(HTMLElement), atom!("dialog") => make!(HTMLDialogElement), atom!("dir") => make!(HTMLDirectoryElement), diff --git a/components/script/dom/htmldetailselement.rs b/components/script/dom/htmldetailselement.rs new file mode 100644 index 00000000000..947c0ee42d7 --- /dev/null +++ b/components/script/dom/htmldetailselement.rs @@ -0,0 +1,107 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use dom::attr::Attr; +use dom::bindings::codegen::Bindings::HTMLDetailsElementBinding; +use dom::bindings::codegen::Bindings::HTMLDetailsElementBinding::HTMLDetailsElementMethods; +use dom::bindings::global::GlobalRef; +use dom::bindings::inheritance::Castable; +use dom::bindings::js::Root; +use dom::bindings::refcounted::Trusted; +use dom::document::Document; +use dom::element::AttributeMutation; +use dom::eventtarget::EventTarget; +use dom::htmlelement::HTMLElement; +use dom::node::{Node, window_from_node}; +use dom::virtualmethods::VirtualMethods; +use script_thread::ScriptThreadEventCategory::DomEvent; +use script_thread::{CommonScriptMsg, Runnable}; +use std::cell::Cell; +use string_cache::Atom; +use util::str::DOMString; + +#[dom_struct] +pub struct HTMLDetailsElement { + htmlelement: HTMLElement, + toggle_counter: Cell +} + +impl HTMLDetailsElement { + fn new_inherited(localName: Atom, + prefix: Option, + document: &Document) -> HTMLDetailsElement { + HTMLDetailsElement { + htmlelement: + HTMLElement::new_inherited(localName, prefix, document), + toggle_counter: Cell::new(0) + } + } + + #[allow(unrooted_must_root)] + pub fn new(localName: Atom, + prefix: Option, + document: &Document) -> Root { + let element = HTMLDetailsElement::new_inherited(localName, prefix, document); + Node::reflect_node(box element, document, HTMLDetailsElementBinding::Wrap) + } + + pub fn check_toggle_count(&self, number: u32) -> bool { + number == self.toggle_counter.get() + } +} + +impl HTMLDetailsElementMethods for HTMLDetailsElement { + // https://html.spec.whatwg.org/multipage/#dom-details-open + make_bool_getter!(Open, "open"); + + // https://html.spec.whatwg.org/multipage/#dom-details-open + make_bool_setter!(SetOpen, "open"); +} + +impl VirtualMethods for HTMLDetailsElement { + fn super_type(&self) -> Option<&VirtualMethods> { + Some(self.upcast::() as &VirtualMethods) + } + + fn attribute_mutated(&self, attr: &Attr, mutation: AttributeMutation) { + self.super_type().unwrap().attribute_mutated(attr, mutation); + + if attr.local_name() == &atom!("open") { + let counter = self.toggle_counter.get() + 1; + self.toggle_counter.set(counter); + ToggleEventRunnable::send(&self, counter); + } + } +} + +pub struct ToggleEventRunnable { + element: Trusted, + toggle_number: u32 +} + +impl ToggleEventRunnable { + pub fn send(node: &HTMLDetailsElement, toggle_number: u32) { + let window = window_from_node(node); + let window = window.r(); + let chan = window.dom_manipulation_thread_source(); + let handler = Trusted::new(node, chan.clone()); + let dispatcher = ToggleEventRunnable { + element: handler, + toggle_number: toggle_number, + }; + let _ = chan.send(CommonScriptMsg::RunnableMsg(DomEvent, box dispatcher)); + } +} + +impl Runnable for ToggleEventRunnable { + fn handler(self: Box) { + let target = self.element.root(); + let window = window_from_node(target.upcast::()); + + if target.check_toggle_count(self.toggle_number) { + target.upcast::() + .fire_simple_event("toggle", GlobalRef::Window(window.r())); + } + } +} diff --git a/components/script/dom/macros.rs b/components/script/dom/macros.rs index 60ed65860f8..1bfa576a1d6 100644 --- a/components/script/dom/macros.rs +++ b/components/script/dom/macros.rs @@ -346,5 +346,6 @@ macro_rules! global_event_handlers( event_handler!(change, GetOnchange, SetOnchange); event_handler!(reset, GetOnreset, SetOnreset); event_handler!(submit, GetOnsubmit, SetOnsubmit); + event_handler!(toggle, GetOntoggle, SetOntoggle); ) ); diff --git a/components/script/dom/mod.rs b/components/script/dom/mod.rs index 54f7486797a..0a9a7217c53 100644 --- a/components/script/dom/mod.rs +++ b/components/script/dom/mod.rs @@ -266,6 +266,7 @@ pub mod htmlcanvaselement; pub mod htmlcollection; pub mod htmldataelement; pub mod htmldatalistelement; +pub mod htmldetailselement; pub mod htmldialogelement; pub mod htmldirectoryelement; pub mod htmldivelement; diff --git a/components/script/dom/virtualmethods.rs b/components/script/dom/virtualmethods.rs index 3540fbddf0f..2e8391671a8 100644 --- a/components/script/dom/virtualmethods.rs +++ b/components/script/dom/virtualmethods.rs @@ -17,6 +17,7 @@ use dom::htmlbaseelement::HTMLBaseElement; use dom::htmlbodyelement::HTMLBodyElement; use dom::htmlbuttonelement::HTMLButtonElement; use dom::htmlcanvaselement::HTMLCanvasElement; +use dom::htmldetailselement::HTMLDetailsElement; use dom::htmlelement::HTMLElement; use dom::htmlfieldsetelement::HTMLFieldSetElement; use dom::htmlfontelement::HTMLFontElement; @@ -145,6 +146,9 @@ pub fn vtable_for(node: &Node) -> &VirtualMethods { NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLCanvasElement)) => { node.downcast::().unwrap() as &VirtualMethods } + NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLDetailsElement)) => { + node.downcast::().unwrap() as &VirtualMethods + } NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLFieldSetElement)) => { node.downcast::().unwrap() as &VirtualMethods } diff --git a/components/script/dom/webidls/EventHandler.webidl b/components/script/dom/webidls/EventHandler.webidl index 24382756aec..91753edf9c7 100644 --- a/components/script/dom/webidls/EventHandler.webidl +++ b/components/script/dom/webidls/EventHandler.webidl @@ -33,6 +33,7 @@ interface GlobalEventHandlers { attribute EventHandler onchange; attribute EventHandler onreset; attribute EventHandler onsubmit; + attribute EventHandler ontoggle; }; [NoInterfaceObject] diff --git a/components/script/dom/webidls/HTMLDetailsElement.webidl b/components/script/dom/webidls/HTMLDetailsElement.webidl new file mode 100644 index 00000000000..062444d8312 --- /dev/null +++ b/components/script/dom/webidls/HTMLDetailsElement.webidl @@ -0,0 +1,9 @@ +/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// https://html.spec.whatwg.org/multipage/#htmldetailselement +interface HTMLDetailsElement : HTMLElement { + attribute boolean open; +}; diff --git a/tests/wpt/metadata/html/dom/interfaces.html.ini b/tests/wpt/metadata/html/dom/interfaces.html.ini index f2302f7c9c6..02806e334df 100644 --- a/tests/wpt/metadata/html/dom/interfaces.html.ini +++ b/tests/wpt/metadata/html/dom/interfaces.html.ini @@ -216,9 +216,6 @@ [Document interface: attribute ontimeupdate] expected: FAIL - [Document interface: attribute ontoggle] - expected: FAIL - [Document interface: attribute onvolumechange] expected: FAIL @@ -1776,9 +1773,6 @@ [HTMLElement interface: attribute ontimeupdate] expected: FAIL - [HTMLElement interface: attribute ontoggle] - expected: FAIL - [HTMLElement interface: attribute onvolumechange] expected: FAIL @@ -2010,9 +2004,6 @@ [HTMLElement interface: document.createElement("noscript") must inherit property "ontimeupdate" with the proper type (91)] expected: FAIL - [HTMLElement interface: document.createElement("noscript") must inherit property "ontoggle" with the proper type (92)] - expected: FAIL - [HTMLElement interface: document.createElement("noscript") must inherit property "onvolumechange" with the proper type (93)] expected: FAIL @@ -5526,30 +5517,6 @@ [ValidityState interface: document.createElement("input").validity must inherit property "valid" with the proper type (10)] expected: FAIL - [HTMLDetailsElement interface: existence and properties of interface object] - expected: FAIL - - [HTMLDetailsElement interface object length] - expected: FAIL - - [HTMLDetailsElement interface: existence and properties of interface prototype object] - expected: FAIL - - [HTMLDetailsElement interface: existence and properties of interface prototype object's "constructor" property] - expected: FAIL - - [HTMLDetailsElement interface: attribute open] - expected: FAIL - - [HTMLDetailsElement must be primary interface of document.createElement("details")] - expected: FAIL - - [Stringification of document.createElement("details")] - expected: FAIL - - [HTMLDetailsElement interface: document.createElement("details") must inherit property "open" with the proper type (0)] - expected: FAIL - [HTMLMenuElement interface: existence and properties of interface object] expected: FAIL @@ -8823,9 +8790,6 @@ [Document interface: document.implementation.createDocument(null, "", null) must inherit property "ontimeupdate" with the proper type (153)] expected: FAIL - [Document interface: document.implementation.createDocument(null, "", null) must inherit property "ontoggle" with the proper type (154)] - expected: FAIL - [Document interface: document.implementation.createDocument(null, "", null) must inherit property "onvolumechange" with the proper type (155)] expected: FAIL @@ -9042,9 +9006,6 @@ [AutocompleteErrorEvent interface object name] expected: FAIL - [HTMLDetailsElement interface object name] - expected: FAIL - [HTMLMenuElement interface object name] expected: FAIL @@ -9140,4 +9101,3 @@ [WebSocket interface: new WebSocket("ws://foo") must inherit property "extensions" with the proper type (10)] expected: FAIL - diff --git a/tests/wpt/metadata/html/dom/reflection-misc.html.ini b/tests/wpt/metadata/html/dom/reflection-misc.html.ini index 831c5f16c10..1f073b67a59 100644 --- a/tests/wpt/metadata/html/dom/reflection-misc.html.ini +++ b/tests/wpt/metadata/html/dom/reflection-misc.html.ini @@ -5529,114 +5529,6 @@ [details.tabIndex: IDL set to -2147483648 followed by getAttribute()] expected: FAIL - [details.open: typeof IDL attribute] - expected: FAIL - - [details.open: IDL get with DOM attribute unset] - expected: FAIL - - [details.open: setAttribute() to "" followed by IDL get] - expected: FAIL - - [details.open: setAttribute() to " foo " followed by IDL get] - expected: FAIL - - [details.open: setAttribute() to undefined followed by IDL get] - expected: FAIL - - [details.open: setAttribute() to null followed by IDL get] - expected: FAIL - - [details.open: setAttribute() to 7 followed by IDL get] - expected: FAIL - - [details.open: setAttribute() to 1.5 followed by IDL get] - expected: FAIL - - [details.open: setAttribute() to true followed by IDL get] - expected: FAIL - - [details.open: setAttribute() to false followed by IDL get] - expected: FAIL - - [details.open: setAttribute() to object "[object Object\]" followed by IDL get] - expected: FAIL - - [details.open: setAttribute() to NaN followed by IDL get] - expected: FAIL - - [details.open: setAttribute() to Infinity followed by IDL get] - expected: FAIL - - [details.open: setAttribute() to -Infinity followed by IDL get] - expected: FAIL - - [details.open: setAttribute() to "\\0" followed by IDL get] - expected: FAIL - - [details.open: setAttribute() to object "test-toString" followed by IDL get] - expected: FAIL - - [details.open: setAttribute() to object "test-valueOf" followed by IDL get] - expected: FAIL - - [details.open: setAttribute() to "open" followed by IDL get] - expected: FAIL - - [details.open: IDL set to "" followed by hasAttribute()] - expected: FAIL - - [details.open: IDL set to "" followed by IDL get] - expected: FAIL - - [details.open: IDL set to " foo " followed by IDL get] - expected: FAIL - - [details.open: IDL set to undefined followed by hasAttribute()] - expected: FAIL - - [details.open: IDL set to undefined followed by IDL get] - expected: FAIL - - [details.open: IDL set to null followed by hasAttribute()] - expected: FAIL - - [details.open: IDL set to null followed by IDL get] - expected: FAIL - - [details.open: IDL set to 7 followed by IDL get] - expected: FAIL - - [details.open: IDL set to 1.5 followed by IDL get] - expected: FAIL - - [details.open: IDL set to false followed by hasAttribute()] - expected: FAIL - - [details.open: IDL set to object "[object Object\]" followed by IDL get] - expected: FAIL - - [details.open: IDL set to NaN followed by hasAttribute()] - expected: FAIL - - [details.open: IDL set to NaN followed by IDL get] - expected: FAIL - - [details.open: IDL set to Infinity followed by IDL get] - expected: FAIL - - [details.open: IDL set to -Infinity followed by IDL get] - expected: FAIL - - [details.open: IDL set to "\\0" followed by IDL get] - expected: FAIL - - [details.open: IDL set to object "test-toString" followed by IDL get] - expected: FAIL - - [details.open: IDL set to object "test-valueOf" followed by IDL get] - expected: FAIL - [details.itemScope: typeof IDL attribute] expected: FAIL @@ -13106,4 +12998,3 @@ [dialog.itemId: IDL set to object "test-valueOf" followed by IDL get] expected: FAIL - diff --git a/tests/wpt/metadata/html/semantics/interactive-elements/the-details-element/details.html.ini b/tests/wpt/metadata/html/semantics/interactive-elements/the-details-element/details.html.ini deleted file mode 100644 index 280f62d750a..00000000000 --- a/tests/wpt/metadata/html/semantics/interactive-elements/the-details-element/details.html.ini +++ /dev/null @@ -1,11 +0,0 @@ -[details.html] - type: testharness - [HTMLDetailsElement should be exposed for prototyping] - expected: FAIL - - [a dynamically created details element should be instanceof HTMLDetailsElement] - expected: FAIL - - [a details element from the parser should be instanceof HTMLDetailsElement] - expected: FAIL - diff --git a/tests/wpt/metadata/html/semantics/interactive-elements/the-details-element/toggleEvent.html.ini b/tests/wpt/metadata/html/semantics/interactive-elements/the-details-element/toggleEvent.html.ini deleted file mode 100644 index 42048f12797..00000000000 --- a/tests/wpt/metadata/html/semantics/interactive-elements/the-details-element/toggleEvent.html.ini +++ /dev/null @@ -1,21 +0,0 @@ -[toggleEvent.html] - type: testharness - expected: TIMEOUT - [Adding open to 'details' should fire a toggle event at the 'details' element] - expected: NOTRUN - - [Removing open from 'details' should fire a toggle event at the 'details' element] - expected: NOTRUN - - [Adding open to 'details' (display:none) should fire a toggle event at the 'details' element] - expected: NOTRUN - - [Adding open from 'details' (no children) should fire a toggle event at the 'details' element] - expected: NOTRUN - - [Calling open twice on 'details' fires only one toggle event] - expected: FAIL - - [Adding open to 'details' (not in the document) should fire a toggle event at the 'details' element] - expected: TIMEOUT - diff --git a/tests/wpt/metadata/html/semantics/interfaces.html.ini b/tests/wpt/metadata/html/semantics/interfaces.html.ini index baf2fc4782a..76f2cd96b22 100644 --- a/tests/wpt/metadata/html/semantics/interfaces.html.ini +++ b/tests/wpt/metadata/html/semantics/interfaces.html.ini @@ -21,9 +21,6 @@ [Interfaces for xmp] expected: FAIL - [Interfaces for details] - expected: FAIL - [Interfaces for command] expected: FAIL @@ -48,9 +45,6 @@ [Interfaces for XMP] expected: FAIL - [Interfaces for DETAILS] - expected: FAIL - [Interfaces for COMMAND] expected: FAIL @@ -65,4 +59,3 @@ [Interfaces for RTC] expected: FAIL - diff --git a/tests/wpt/mozilla/tests/mozilla/interfaces.html b/tests/wpt/mozilla/tests/mozilla/interfaces.html index 9f04099f7a6..2d63e0a60b2 100644 --- a/tests/wpt/mozilla/tests/mozilla/interfaces.html +++ b/tests/wpt/mozilla/tests/mozilla/interfaces.html @@ -117,6 +117,7 @@ var interfaceNamesInGlobalScope = [ "HTMLCollection", "HTMLDataElement", "HTMLDataListElement", + "HTMLDetailsElement", "HTMLDialogElement", "HTMLDirectoryElement", "HTMLDivElement",