/* 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/. */ /** * @import { ReactiveController } from "chrome://global/content/vendor/lit.all.mjs"; * @import { ThemePicker, ThemechangeEvent, ThemechangeEventDetail } from "./theme-picker.mjs"; */ const RESPONSE_EVENTS = [ "ThemePickerInitialState", "ThemePickerThemeUpdated", "ThemePickerAppearanceUpdated", "ThemePickerNativeThemeUpdated", "ThemePickerDeviceAppearanceUpdated", ]; /** * RemoteController for ThemePicker that communicates with the parent process * via JSWindowActor messages instead of directly accessing AddonManager and * Services.prefs. * * Used in unprivileged content contexts like about:editprofile where direct * access to platform APIs is not available. * * @implements {ReactiveController} */ export class ThemePickerRemoteController { host; /** * @param {ThemePicker} host */ constructor(host) { this.host = host; this.host.addController(this); for (const eventType of RESPONSE_EVENTS) { this.host.addEventListener(eventType, this); } this.host.addEventListener( "themechange", /** @param {ThemechangeEvent} e */ e => this.onThemechange(e.detail) ); window.addEventListener( "ThemePickerDeviceAppearanceUpdated", this.deviceAppearanceHandler ); } hostDisconnected() { window.removeEventListener( "ThemePickerDeviceAppearanceUpdated", this.deviceAppearanceHandler ); } deviceAppearanceHandler = e => { this.host.deviceAppearance = e.detail.deviceAppearance; }; hostConnected() { this.dispatchActorEvent("ThemePickerGetInitialState", { installSource: this.host.getAttribute("installsource") || "unknown", showInCompactLayout: this.host.layout === "compact", }); } /** * Dispatch an event to the document for the actor to handle. * * @param {string} eventType - The event type to dispatch * @param {object} detail - Event detail data */ dispatchActorEvent(eventType, detail) { this.host.dispatchEvent( new CustomEvent(eventType, { bubbles: true, composed: true, detail, }) ); } handleEvent(event) { switch (event.type) { case "ThemePickerInitialState": this.host.themes = event.detail.themes; this.host.activeThemeId = event.detail.activeThemeId; this.host.nativeTheme = event.detail.nativeTheme; this.host.appearance = event.detail.appearance; this.host.showNativeThemeOption = event.detail.showNativeThemeOption; this.host.deviceAppearance = event.detail.deviceAppearance; break; case "ThemePickerThemeUpdated": this.host.activeThemeId = event.detail.activeThemeId; break; case "ThemePickerAppearanceUpdated": this.host.appearance = event.detail.appearance; break; case "ThemePickerNativeThemeUpdated": this.host.nativeTheme = event.detail.nativeTheme; break; case "ThemePickerDeviceAppearanceUpdated": this.host.deviceAppearance = event.detail.deviceAppearance; break; } } /** * @param {ThemechangeEventDetail} detail */ onThemechange({ property, value }) { switch (property) { case "theme": this.dispatchActorEvent("ThemePickerUpdateTheme", { themeId: String(value), }); break; case "appearance": this.dispatchActorEvent("ThemePickerUpdateAppearance", { appearance: value, }); break; case "nativeTheme": this.dispatchActorEvent("ThemePickerUpdateNativeTheme", { nativeTheme: Boolean(value), }); break; } } }