/* 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/. */ /* globals window */ "use strict"; loader.lazyImporter(this, "PrivateBrowsingUtils", "resource://gre/modules/PrivateBrowsingUtils.jsm"); const { Ci } = require("chrome"); const { createClass, createFactory, DOM: dom, PropTypes } = require("devtools/client/shared/vendor/react"); const { getWorkerForms } = require("../../modules/worker"); const Services = require("Services"); const PanelHeader = createFactory(require("../panel-header")); const TargetList = createFactory(require("../target-list")); const WorkerTarget = createFactory(require("./target")); const ServiceWorkerTarget = createFactory(require("./service-worker-target")); loader.lazyImporter(this, "PrivateBrowsingUtils", "resource://gre/modules/PrivateBrowsingUtils.jsm"); loader.lazyRequireGetter(this, "DebuggerClient", "devtools/shared/client/main", true); const Strings = Services.strings.createBundle( "chrome://devtools/locale/aboutdebugging.properties"); const WorkerIcon = "chrome://devtools/skin/images/debugging-workers.svg"; const MORE_INFO_URL = "https://developer.mozilla.org/en-US/docs/Tools/about%3Adebugging"; module.exports = createClass({ displayName: "WorkersPanel", propTypes: { client: PropTypes.instanceOf(DebuggerClient).isRequired, id: PropTypes.string.isRequired }, getInitialState() { return { workers: { service: [], shared: [], other: [] } }; }, componentDidMount() { let client = this.props.client; client.addListener("workerListChanged", this.update); client.addListener("serviceWorkerRegistrationListChanged", this.update); client.addListener("processListChanged", this.update); client.addListener("registration-changed", this.update); this.update(); }, componentWillUnmount() { let client = this.props.client; client.removeListener("processListChanged", this.update); client.removeListener("serviceWorkerRegistrationListChanged", this.update); client.removeListener("workerListChanged", this.update); client.removeListener("registration-changed", this.update); }, update() { let workers = this.getInitialState().workers; getWorkerForms(this.props.client).then(forms => { forms.registrations.forEach(form => { workers.service.push({ icon: WorkerIcon, name: form.url, url: form.url, scope: form.scope, registrationActor: form.actor, active: form.active }); }); forms.workers.forEach(form => { let worker = { icon: WorkerIcon, name: form.url, url: form.url, workerActor: form.actor }; switch (form.type) { case Ci.nsIWorkerDebugger.TYPE_SERVICE: let registration = this.getRegistrationForWorker(form, workers.service); if (registration) { // XXX: Race, sometimes a ServiceWorkerRegistrationInfo doesn't // have a scriptSpec, but its associated WorkerDebugger does. if (!registration.url) { registration.name = registration.url = form.url; } registration.workerActor = form.actor; } else { // If a service worker registration could not be found, this means we are in // e10s, and registrations are not forwarded to other processes until they // reach the activated state. Augment the worker as a registration worker to // display it in aboutdebugging. worker.scope = form.scope; worker.active = false; workers.service.push(worker); } break; case Ci.nsIWorkerDebugger.TYPE_SHARED: workers.shared.push(worker); break; default: workers.other.push(worker); } }); // XXX: Filter out the service worker registrations for which we couldn't // find the scriptSpec. workers.service = workers.service.filter(reg => !!reg.url); this.setState({ workers }); }); }, getRegistrationForWorker(form, registrations) { for (let registration of registrations) { if (registration.scope === form.scope) { return registration; } } return null; }, render() { let { client, id } = this.props; let { workers } = this.state; let isWindowPrivate = PrivateBrowsingUtils.isContentWindowPrivate(window); let isPrivateBrowsingMode = PrivateBrowsingUtils.permanentPrivateBrowsing; let isServiceWorkerDisabled = !Services.prefs .getBoolPref("dom.serviceWorkers.enabled"); let errorMsg = isWindowPrivate || isPrivateBrowsingMode || isServiceWorkerDisabled ? dom.p({ className: "service-worker-disabled" }, dom.div({ className: "warning" }), Strings.GetStringFromName("configurationIsNotCompatible"), " (", dom.a({ href: MORE_INFO_URL, target: "_blank" }, Strings.GetStringFromName("moreInfo")), ")" ) : ""; return dom.div({ id: id + "-panel", className: "panel", role: "tabpanel", "aria-labelledby": id + "-header" }, PanelHeader({ id: id + "-header", name: Strings.GetStringFromName("workers") }), dom.div({ id: "workers", className: "inverted-icons" }, TargetList({ client, error: errorMsg, id: "service-workers", name: Strings.GetStringFromName("serviceWorkers"), sort: true, targetClass: ServiceWorkerTarget, targets: workers.service }), TargetList({ client, id: "shared-workers", name: Strings.GetStringFromName("sharedWorkers"), sort: true, targetClass: WorkerTarget, targets: workers.shared }), TargetList({ client, id: "other-workers", name: Strings.GetStringFromName("otherWorkers"), sort: true, targetClass: WorkerTarget, targets: workers.other }) )); } });