about_compat_broker.js (3727B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 "use strict"; 6 7 /* global browser, onMessageFromTab */ 8 9 class AboutCompatBroker { 10 constructor(bindings) { 11 this._interventions = bindings.interventions; 12 this._shims = bindings.shims; 13 14 if (!this._interventions && !this._shims) { 15 throw new Error( 16 "No interventions or shims; about:compat broker is not needed" 17 ); 18 } 19 20 this.portsToAboutCompatTabs = this.buildPorts(); 21 this._interventions?.bindAboutCompatBroker(this); 22 this._shims?.bindAboutCompatBroker(this); 23 } 24 25 buildPorts() { 26 const ports = new Set(); 27 28 browser.runtime.onConnect.addListener(port => { 29 ports.add(port); 30 port.onDisconnect.addListener(function () { 31 ports.delete(port); 32 }); 33 }); 34 35 async function broadcast(message) { 36 for (const port of ports) { 37 port.postMessage(message); 38 } 39 } 40 41 return { broadcast }; 42 } 43 44 filterInterventions(interventions) { 45 return interventions 46 .filter(intervention => intervention.availableOnPlatform) 47 .map(intervention => { 48 const { id, active, bugs, hidden } = intervention; 49 let domain = intervention.label; 50 let bug = Object.keys(bugs)[0]; 51 return { id, active, bug, domain, hidden }; 52 }); 53 } 54 55 getInterventionById(id) { 56 for (const [type, things] of Object.entries({ 57 interventions: this._interventions?.getAvailableInterventions() || [], 58 shims: this._shims?.getAvailableShims() || [], 59 })) { 60 for (const what of things) { 61 if (what.id === id) { 62 return { type, what }; 63 } 64 } 65 } 66 return {}; 67 } 68 69 bootup() { 70 onMessageFromTab(msg => { 71 switch (msg.command || msg) { 72 case "toggle": { 73 const id = msg.id; 74 const { type, what } = this.getInterventionById(id); 75 if (!what) { 76 return Promise.reject(`No such intervention to toggle: ${id}`); 77 } 78 const active = type === "shims" ? !what.disabledReason : what.active; 79 this.portsToAboutCompatTabs 80 .broadcast({ toggling: id, active }) 81 .then(async () => { 82 switch (type) { 83 case "interventions": { 84 if (active) { 85 await this._interventions?.disableIntervention(what); 86 } else { 87 await this._interventions?.enableIntervention(what, true); 88 } 89 break; 90 } 91 case "shims": { 92 if (active) { 93 await this._shims?.disableShimForSession(id); 94 } else { 95 await this._shims?.enableShimForSession(id); 96 } 97 // no need to broadcast the "toggled" signal for shims, as 98 // they send a shimsUpdated message themselves instead 99 return; 100 } 101 } 102 this.portsToAboutCompatTabs.broadcast({ 103 toggled: id, 104 active: !active, 105 }); 106 }); 107 break; 108 } 109 case "getAllInterventions": { 110 return Promise.resolve({ 111 interventions: 112 (this._interventions?.isEnabled() && 113 this.filterInterventions( 114 this._interventions?.getAvailableInterventions() 115 )) || 116 false, 117 shims: this._shims?.getAvailableShims() || false, 118 }); 119 } 120 } 121 return undefined; 122 }); 123 } 124 }