diff --git a/components/script/dom/mediaquerylist.rs b/components/script/dom/mediaquerylist.rs index 86f67cdd8a1..db96a4760cd 100644 --- a/components/script/dom/mediaquerylist.rs +++ b/components/script/dom/mediaquerylist.rs @@ -9,12 +9,15 @@ use dom::bindings::codegen::Bindings::EventTargetBinding::EventTargetMethods; use dom::bindings::codegen::Bindings::MediaQueryListBinding::{self, MediaQueryListMethods}; use dom::bindings::inheritance::Castable; use dom::bindings::js::{JS, Root}; +use dom::bindings::reflector::DomObject; use dom::bindings::reflector::reflect_dom_object; use dom::bindings::str::DOMString; use dom::bindings::trace::JSTraceable; use dom::bindings::weakref::{WeakRef, WeakRefVec}; use dom::document::Document; +use dom::event::Event; use dom::eventtarget::EventTarget; +use dom::mediaquerylistevent::MediaQueryListEvent; use euclid::scale_factor::ScaleFactor; use js::jsapi::JSTracer; use std::cell::Cell; @@ -136,8 +139,14 @@ impl WeakMediaQueryListVec { /// https://drafts.csswg.org/cssom-view/#evaluate-media-queries-and-report-changes pub fn evaluate_and_report_changes(&self) { for mql in self.cell.borrow().iter() { - if let MediaQueryListMatchState::Changed(_) = mql.root().unwrap().evaluate_changes() { - mql.root().unwrap().upcast::().fire_event(atom!("change")); + let mql = mql.root().unwrap(); + if let MediaQueryListMatchState::Changed(_) = mql.evaluate_changes() { + let event = MediaQueryListEvent::new(&mql.global(), + atom!("change"), + false, false, + mql.Media(), + mql.Matches()); + event.upcast::().fire(mql.upcast::()); } } } diff --git a/components/script/dom/mediaquerylistevent.rs b/components/script/dom/mediaquerylistevent.rs new file mode 100644 index 00000000000..8965ba43f79 --- /dev/null +++ b/components/script/dom/mediaquerylistevent.rs @@ -0,0 +1,82 @@ +/* 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::bindings::codegen::Bindings::EventBinding::EventMethods; +use dom::bindings::codegen::Bindings::MediaQueryListEventBinding; +use dom::bindings::codegen::Bindings::MediaQueryListEventBinding::MediaQueryListEventInit; +use dom::bindings::codegen::Bindings::MediaQueryListEventBinding::MediaQueryListEventMethods; +use dom::bindings::error::Fallible; +use dom::bindings::inheritance::Castable; +use dom::bindings::js::Root; +use dom::bindings::reflector::reflect_dom_object; +use dom::bindings::str::DOMString; +use dom::event::Event; +use dom::globalscope::GlobalScope; +use dom::window::Window; +use servo_atoms::Atom; +use std::cell::Cell; + +// https://drafts.csswg.org/cssom-view/#dom-mediaquerylistevent-mediaquerylistevent +#[dom_struct] +pub struct MediaQueryListEvent { + event: Event, + media: DOMString, + matches: Cell +} + +impl MediaQueryListEvent { + pub fn new_uninitialized(global: &GlobalScope) -> Root { + MediaQueryListEvent::new_initialized(global, + DOMString::new(), + false) + } + + pub fn new_initialized(global: &GlobalScope, + media: DOMString, + matches: bool) -> Root { + let ev = box MediaQueryListEvent { + event: Event::new_inherited(), + media: media, + matches: Cell::new(matches) + }; + reflect_dom_object(ev, global, MediaQueryListEventBinding::Wrap) + } + + pub fn new(global: &GlobalScope, type_: Atom, + bubbles: bool, cancelable: bool, + media: DOMString, matches: bool) -> Root { + let ev = MediaQueryListEvent::new_initialized(global, media, matches); + { + let event = ev.upcast::(); + event.init_event(type_, bubbles, cancelable); + } + ev + } + + pub fn Constructor(window: &Window, type_: DOMString, + init: &MediaQueryListEventInit) + -> Fallible> { + let global = window.upcast::(); + Ok(MediaQueryListEvent::new(global, Atom::from(type_), + init.parent.bubbles, init.parent.cancelable, + init.media.clone(), init.matches)) + } +} + +impl MediaQueryListEventMethods for MediaQueryListEvent { + // https://drafts.csswg.org/cssom-view/#dom-mediaquerylistevent-media + fn Media(&self) -> DOMString { + self.media.clone() + } + + // https://drafts.csswg.org/cssom-view/#dom-mediaquerylistevent-matches + fn Matches(&self) -> bool { + self.matches.get() + } + + // https://dom.spec.whatwg.org/#dom-event-istrusted + fn IsTrusted(&self) -> bool { + self.upcast::().IsTrusted() + } +} diff --git a/components/script/dom/mod.rs b/components/script/dom/mod.rs index b432b5a12e5..8c074a48ba5 100644 --- a/components/script/dom/mod.rs +++ b/components/script/dom/mod.rs @@ -371,6 +371,7 @@ pub mod location; pub mod mediaerror; pub mod medialist; pub mod mediaquerylist; +pub mod mediaquerylistevent; pub mod messageevent; pub mod mimetype; pub mod mimetypearray; diff --git a/components/script/dom/webidls/MediaQueryListEvent.webidl b/components/script/dom/webidls/MediaQueryListEvent.webidl new file mode 100644 index 00000000000..877ca17b60b --- /dev/null +++ b/components/script/dom/webidls/MediaQueryListEvent.webidl @@ -0,0 +1,15 @@ +/* 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://drafts.csswg.org/cssom-view/#dom-mediaquerylistevent-mediaquerylistevent +[Constructor(DOMString type, optional MediaQueryListEventInit eventInitDict), Exposed=(Window)] +interface MediaQueryListEvent : Event { + readonly attribute DOMString media; + readonly attribute boolean matches; +}; + +dictionary MediaQueryListEventInit : EventInit { + DOMString media = ""; + boolean matches = false; +}; diff --git a/tests/wpt/mozilla/tests/css/matchMedia.html b/tests/wpt/mozilla/tests/css/matchMedia.html index 0eeb007a49a..45a7ea268b1 100644 --- a/tests/wpt/mozilla/tests/css/matchMedia.html +++ b/tests/wpt/mozilla/tests/css/matchMedia.html @@ -126,12 +126,16 @@ window.onload = function(){ var rmListener = function(x){ + assert_true(x instanceof MediaQueryListEvent, "Check that event is instance of MediaQueryListEvent."); + resizeTest.step(function(){ assert_unreached("removeListener was not successful."); }); }; var dupListener = function(x){ + assert_true(x instanceof MediaQueryListEvent, "Check that event is instance of MediaQueryListEvent."); + duplicateListenerTest.step(function(){ assert_false(mql1.dupListenerCalled, "Check that this listener has not been called before."); mql1.dupListenerCalled = true; @@ -148,6 +152,8 @@ mql1.addListener(dupListener); mql1.addListener(function(x){ + assert_true(x instanceof MediaQueryListEvent, "Check that event is instance of MediaQueryListEvent."); + resizeTest.step(function(){ assert_equals(x, mql1, "Check that the MediaQueryList passed to the handler is the same that addListener was invoked on."); assert_true(x.matches, "(max-height: 50px) should now pass."); @@ -162,6 +168,8 @@ }); mql1.addListener(function(x){ + assert_true(x instanceof MediaQueryListEvent, "Check that event is instance of MediaQueryListEvent."); + listenerOrderTest.step(function(){ assert_true(mql1.firstListenerCalled, "Check that the listener added last is called last."); }); @@ -171,6 +179,8 @@ mql1.removeListener(rmListener); mql2.addListener(function(x){ + assert_true(x instanceof MediaQueryListEvent, "Check that event is instance of MediaQueryListEvent."); + duplicateListenerTest.done(); resizeTest.step(function(){ assert_equals(x, mql2, "Check that the MediaQueryList passed to the handler is the same that addListener was invoked on."); diff --git a/tests/wpt/mozilla/tests/mozilla/interfaces.html b/tests/wpt/mozilla/tests/mozilla/interfaces.html index 85e6335aafb..6f774fec8da 100644 --- a/tests/wpt/mozilla/tests/mozilla/interfaces.html +++ b/tests/wpt/mozilla/tests/mozilla/interfaces.html @@ -143,6 +143,7 @@ test_interfaces([ "MediaError", "MediaList", "MediaQueryList", + "MediaQueryListEvent", "MessageEvent", "MimeType", "MimeTypeArray",