Files
Emilio Cobos Álvarez c1ea090344 Bug 2033242 - Rename ownerDocGlobal to documentGlobal, and use it where appropriate in child actors and remote/. r=firefox-desktop-core-reviewers ,credential-management-reviewers,devtools-reviewers,migration-reviewers,frontend-codestyle-reviewers,ai-platform-reviewers,jdescottes,dimi,dao,Gijs,webidl,smaug
Child actors generally deal with content nodes, and those can be
adopted, in order to preserve behavior, switch to the new
.documentGlobal.

Fix + rename the use-ownerGlobal lint since now it's wrong.
.ownerDocument.defaultView is .documentGlobal, not .ownerGlobal now.

Differential Revision: https://phabricator.services.mozilla.com/D294805
2026-04-20 19:53:06 +00:00

143 lines
4.1 KiB
JavaScript

/* 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 EventEmitter = require("resource://devtools/shared/event-emitter.js");
/**
* The CustomElementWatcher can be used to be notified if a custom element definition
* is created for a node.
*
* When a custom element is defined for a monitored name, an "element-defined" event is
* fired with the following Object argument:
* - {String} name: name of the custom element defined
* - {Set} Set of impacted node actors
*/
class CustomElementWatcher extends EventEmitter {
constructor(chromeEventHandler) {
super();
this.chromeEventHandler = chromeEventHandler;
this._onCustomElementDefined = this._onCustomElementDefined.bind(this);
this.chromeEventHandler.addEventListener(
"customelementdefined",
this._onCustomElementDefined
);
/**
* Each window keeps its own custom element registry, all of them are watched
* separately. The struture of the watchedRegistries is as follows
*
* WeakMap(
* registry -> Map (
* name -> Set(NodeActors)
* )
* )
*/
this.watchedRegistries = new WeakMap();
}
destroy() {
this.watchedRegistries = null;
this.chromeEventHandler.removeEventListener(
"customelementdefined",
this._onCustomElementDefined
);
}
/**
* Watch for custom element definitions matching the name of the provided NodeActor.
*/
manageNode(nodeActor) {
if (!this._isValidNode(nodeActor)) {
return;
}
if (!this._shouldWatchDefinition(nodeActor)) {
return;
}
const registry = nodeActor.rawNode.documentGlobal.customElements;
const registryMap = this._getMapForRegistry(registry);
const name = nodeActor.rawNode.localName;
const actorsSet = this._getActorsForName(name, registryMap);
actorsSet.add(nodeActor);
}
/**
* Stop watching the provided NodeActor.
*/
unmanageNode(nodeActor) {
if (!this._isValidNode(nodeActor)) {
return;
}
try {
const win = nodeActor.rawNode.documentGlobal;
const registry = win.customElements;
const registryMap = this._getMapForRegistry(registry);
const name = nodeActor.rawNode.localName;
if (registryMap.has(name)) {
registryMap.get(name).delete(nodeActor);
}
} catch (ex) {}
}
/**
* Retrieve the map of name->nodeActors for a given CustomElementsRegistry.
* Will create the map if not created yet.
*/
_getMapForRegistry(registry) {
if (!this.watchedRegistries.has(registry)) {
this.watchedRegistries.set(registry, new Map());
}
return this.watchedRegistries.get(registry);
}
/**
* Retrieve the set of nodeActors for a given name and registry.
* Will create the set if not created yet.
*/
_getActorsForName(name, registryMap) {
if (!registryMap.has(name)) {
registryMap.set(name, new Set());
}
return registryMap.get(name);
}
_shouldWatchDefinition(nodeActor) {
const doc = nodeActor.rawNode.ownerDocument;
const namespaceURI = doc.documentElement.namespaceURI;
const name = nodeActor.rawNode.localName;
const isValidName = InspectorUtils.isCustomElementName(name, namespaceURI);
const customElements = doc.defaultView.customElements;
return isValidName && !customElements.get(name);
}
_onCustomElementDefined(event) {
const doc = event.target;
const registry = doc.defaultView.customElements;
const registryMap = this._getMapForRegistry(registry);
const name = event.detail;
const actors = this._getActorsForName(name, registryMap);
this.emit("element-defined", { name, actors });
registryMap.delete(name);
}
/**
* Some nodes (e.g. inside of <template> tags) don't have a documentElement
* and can't be watched by this helper.
*/
_isValidNode(nodeActor) {
const node = nodeActor.rawNode;
return !Cu.isDeadWrapper(node) && node.ownerDocument?.documentElement;
}
}
exports.CustomElementWatcher = CustomElementWatcher;