/* 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 https://mozilla.org/MPL/2.0/. */ use std::cell::Cell; use std::rc::Rc; use dom_struct::dom_struct; use style::media_queries::MediaList; use style_traits::ToCss; use crate::dom::bindings::codegen::Bindings::EventListenerBinding::EventListener; use crate::dom::bindings::codegen::Bindings::EventTargetBinding::{ AddEventListenerOptions, EventListenerOptions, }; use crate::dom::bindings::codegen::Bindings::MediaQueryListBinding::MediaQueryListMethods; use crate::dom::bindings::inheritance::Castable; use crate::dom::bindings::reflector::reflect_dom_object; use crate::dom::bindings::root::{Dom, DomRoot}; use crate::dom::bindings::str::DOMString; use crate::dom::document::Document; use crate::dom::eventtarget::EventTarget; pub enum MediaQueryListMatchState { Same(bool), Changed(bool), } #[dom_struct] pub struct MediaQueryList { eventtarget: EventTarget, document: Dom, #[no_trace] media_query_list: MediaList, last_match_state: Cell>, } impl MediaQueryList { fn new_inherited(document: &Document, media_query_list: MediaList) -> MediaQueryList { MediaQueryList { eventtarget: EventTarget::new_inherited(), document: Dom::from_ref(document), media_query_list, last_match_state: Cell::new(None), } } pub fn new(document: &Document, media_query_list: MediaList) -> DomRoot { reflect_dom_object( Box::new(MediaQueryList::new_inherited(document, media_query_list)), document.window(), ) } } impl MediaQueryList { pub fn evaluate_changes(&self) -> MediaQueryListMatchState { let matches = self.evaluate(); let result = if let Some(old_matches) = self.last_match_state.get() { if old_matches == matches { MediaQueryListMatchState::Same(matches) } else { MediaQueryListMatchState::Changed(matches) } } else { MediaQueryListMatchState::Changed(matches) }; self.last_match_state.set(Some(matches)); result } pub fn evaluate(&self) -> bool { let quirks_mode = self.document.quirks_mode(); self.document .with_device(move |device| self.media_query_list.evaluate(device, quirks_mode)) } } impl MediaQueryListMethods for MediaQueryList { // https://drafts.csswg.org/cssom-view/#dom-mediaquerylist-media fn Media(&self) -> DOMString { self.media_query_list.to_css_string().into() } // https://drafts.csswg.org/cssom-view/#dom-mediaquerylist-matches fn Matches(&self) -> bool { match self.last_match_state.get() { None => self.evaluate(), Some(state) => state, } } // https://drafts.csswg.org/cssom-view/#dom-mediaquerylist-addlistener fn AddListener(&self, listener: Option>) { self.upcast::().add_event_listener( DOMString::from_string("change".to_owned()), listener, AddEventListenerOptions { parent: EventListenerOptions { capture: false }, once: false, }, ); } // https://drafts.csswg.org/cssom-view/#dom-mediaquerylist-removelistener fn RemoveListener(&self, listener: Option>) { self.upcast::().remove_event_listener( DOMString::from_string("change".to_owned()), listener, EventListenerOptions { capture: false }, ); } // https://drafts.csswg.org/cssom-view/#dom-mediaquerylist-onchange event_handler!(change, GetOnchange, SetOnchange); }