/* 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 strict"; const protocol = require("resource://devtools/shared/protocol.js"); const { LongStringActor, } = require("resource://devtools/server/actors/string.js"); const { styleSheetsSpec, } = require("resource://devtools/shared/specs/style-sheets.js"); const InspectorUtils = require("InspectorUtils"); loader.lazyRequireGetter( this, "UPDATE_GENERAL", "resource://devtools/server/actors/style-sheet.js", true ); loader.lazyRequireGetter( this, "hasStyleSheetWatcherSupportForTarget", "resource://devtools/server/actors/utils/stylesheets-manager.js", true ); /** * Creates a StyleSheetsActor. StyleSheetsActor provides remote access to the * stylesheets of a document. */ var StyleSheetsActor = protocol.ActorClassWithSpec(styleSheetsSpec, { /** * The window we work with, taken from the parent actor. */ get window() { return this.parentActor.window; }, /** * The current content document of the window we work with. */ get document() { return this.window.document; }, initialize(conn, targetActor) { protocol.Actor.prototype.initialize.call(this, targetActor.conn); this.parentActor = targetActor; this._onApplicableStateChanged = this._onApplicableStateChanged.bind(this); this._onNewStyleSheetActor = this._onNewStyleSheetActor.bind(this); this._onWindowReady = this._onWindowReady.bind(this); this._transitionSheetLoaded = false; this.parentActor.on("stylesheet-added", this._onNewStyleSheetActor); this.parentActor.on("window-ready", this._onWindowReady); this.parentActor.chromeEventHandler.addEventListener( "StyleSheetApplicableStateChanged", this._onApplicableStateChanged, true ); }, getTraits() { return { traits: {}, }; }, destroy() { for (const win of this.parentActor.windows) { // This flag only exists for devtools, so we are free to clear // it when we're done. win.document.styleSheetChangeEventsEnabled = false; } this.parentActor.off("stylesheet-added", this._onNewStyleSheetActor); this.parentActor.off("window-ready", this._onWindowReady); this.parentActor.chromeEventHandler.removeEventListener( "StyleSheetApplicableStateChanged", this._onApplicableStateChanged, true ); protocol.Actor.prototype.destroy.call(this); }, /** * Event handler that is called when a the target actor emits window-ready. * * @param {Event} evt * The triggering event. */ _onWindowReady(evt) { this._addStyleSheets(evt.window); }, /** * Event handler that is called when a the target actor emits stylesheet-added. * * @param {StyleSheetActor} actor * The new style sheet actor. */ _onNewStyleSheetActor(actor) { const info = this._addingStyleSheetInfo?.get(actor.rawSheet); this._addingStyleSheetInfo?.delete(actor.rawSheet); // Forward it to the client side. this.emit( "stylesheet-added", actor, info ? info.isNew : false, info ? info.fileName : null ); }, /** * Protocol method for getting a list of StyleSheetActors representing * all the style sheets in this document. */ async getStyleSheets() { let actors = []; const windows = this.parentActor.windows; for (const win of windows) { const sheets = await this._addStyleSheets(win); actors = actors.concat(sheets); } return actors; }, /** * Check if we should be showing this stylesheet. * * @param {DOMCSSStyleSheet} sheet * Stylesheet we're interested in * * @return boolean * Whether the stylesheet should be listed. */ _shouldListSheet(sheet) { // Special case about:PreferenceStyleSheet, as it is generated on the // fly and the URI is not registered with the about: handler. // https://bugzilla.mozilla.org/show_bug.cgi?id=935803#c37 if (sheet.href?.toLowerCase() === "about:preferencestylesheet") { return false; } return true; }, /** * Event handler that is called when the state of applicable of style sheet is changed. * * For now, StyleSheetApplicableStateChanged event will be called at following timings. * - Append of stylesheet to document * - Append