happy-dom
Version:
Happy DOM is a JavaScript implementation of a web browser without its graphical user interface. It includes many web standards from WHATWG DOM and HTML.
127 lines (115 loc) • 3.19 kB
text/typescript
import EventTarget from '../event/EventTarget.js';
import * as PropertySymbol from '../PropertySymbol.js';
import Event from '../event/Event.js';
import BrowserWindow from '../window/BrowserWindow.js';
import TEventListener from '../event/TEventListener.js';
import MediaQueryListEvent from '../event/events/MediaQueryListEvent.js';
import IMediaQueryItem from './MediaQueryItem.js';
import MediaQueryParser from './MediaQueryParser.js';
/**
* Media Query List.
*
* Reference:
* https://developer.mozilla.org/en-US/docs/Web/API/MediaQueryList.
*/
export default class MediaQueryList extends EventTarget {
public onchange: (event: Event) => void = null;
#window: BrowserWindow;
#items: IMediaQueryItem[] | null = null;
#media: string;
#rootFontSize: string | number | null = null;
/**
* Constructor.
*
* @param options Options.
* @param options.window Owner window.
* @param options.media Media.
* @param [options.rootFontSize] Root font size.
*/
constructor(options: { window: BrowserWindow; media: string; rootFontSize?: string | number }) {
super();
this.#window = options.window;
this.#media = options.media;
this.#rootFontSize = options.rootFontSize || null;
}
/**
* Returns media.
*
* @returns Media.
*/
public get media(): string {
this.#items =
this.#items ||
MediaQueryParser.parse({
window: this.#window,
mediaQuery: this.#media,
rootFontSize: this.#rootFontSize
});
return this.#items.map((item) => item.toString()).join(', ');
}
/**
* Returns "true" if the document matches.
*
* @returns Matches.
*/
public get matches(): boolean {
this.#items =
this.#items ||
MediaQueryParser.parse({
window: this.#window,
mediaQuery: this.#media,
rootFontSize: this.#rootFontSize
});
for (const item of this.#items) {
if (!item.matches()) {
return false;
}
}
return true;
}
/**
* Adds a listener.
*
* @deprecated
* @param callback Callback.
*/
public addListener(callback: (event: Event) => void): void {
this.addEventListener('change', callback);
}
/**
* Removes listener.
*
* @deprecated
* @param callback Callback.
*/
public removeListener(callback: (event: Event) => void): void {
this.removeEventListener('change', callback);
}
/**
* @override
*/
public addEventListener(type: string, listener: TEventListener): void {
super.addEventListener(type, listener);
if (type === 'change') {
let matchesState = false;
const resizeListener = (): void => {
const matches = this.matches;
if (matches !== matchesState) {
matchesState = matches;
this.dispatchEvent(new MediaQueryListEvent('change', { matches, media: this.media }));
}
};
listener[PropertySymbol.windowResizeListener] = resizeListener;
this.#window.addEventListener('resize', resizeListener);
}
}
/**
* @override
*/
public removeEventListener(type: string, listener: TEventListener): void {
super.removeEventListener(type, listener);
if (type === 'change' && listener[PropertySymbol.windowResizeListener]) {
this.#window.removeEventListener('resize', listener[PropertySymbol.windowResizeListener]);
}
}
}