builtinBridgeDialog.js (4333B)
1 "use strict"; 2 3 const { TorSettings, TorBridgeSource } = ChromeUtils.importESModule( 4 "resource://gre/modules/TorSettings.sys.mjs" 5 ); 6 7 const { TorConnect, TorConnectStage, TorConnectTopics } = 8 ChromeUtils.importESModule("resource://gre/modules/TorConnect.sys.mjs"); 9 10 const gBuiltinBridgeDialog = { 11 init() { 12 this._result = window.arguments[0]; 13 14 this._radioGroup = document.getElementById( 15 "torPreferences-builtinBridge-typeSelection" 16 ); 17 18 const currentBuiltinType = 19 TorSettings.bridges.enabled && 20 TorSettings.bridges.source == TorBridgeSource.BuiltIn 21 ? TorSettings.bridges.builtin_type 22 : null; 23 24 for (const optionEl of this._radioGroup.querySelectorAll( 25 ".builtin-bridges-option" 26 )) { 27 const radio = optionEl.querySelector("radio"); 28 const type = radio.value; 29 optionEl.hidden = !TorSettings.builtinBridgeTypes.includes(type); 30 31 const descriptionEl = optionEl.querySelector( 32 ".builtin-bridges-option-description" 33 ); 34 // Set an id to be used for the aria-describedby. 35 descriptionEl.id = `builtin-bridges-description-${type}`; 36 const currentBadge = optionEl.querySelector(".bridge-status-badge"); 37 if (type === currentBuiltinType) { 38 const currentLabelEl = optionEl.querySelector( 39 ".torPreferences-current-bridge-label" 40 ); 41 currentLabelEl.id = `builtin-bridges-current-${type}`; 42 // Described by both the current badge and the full description. 43 // These will be concatenated together in the screen reader output. 44 radio.setAttribute( 45 "aria-describedby", 46 `${currentLabelEl.id} ${descriptionEl.id}` 47 ); 48 // Make visible. 49 currentBadge.classList.add("bridge-status-current-built-in"); 50 } else { 51 // No visible badge. 52 radio.setAttribute("aria-describedby", descriptionEl.id); 53 currentBadge.classList.remove("bridge-status-current-built-in"); 54 } 55 } 56 57 if (currentBuiltinType) { 58 this._radioGroup.value = currentBuiltinType; 59 } else { 60 this._radioGroup.selectedItem = null; 61 } 62 63 this._radioGroup.addEventListener("select", () => this.onSelectChange()); 64 65 const dialog = document.getElementById( 66 "torPreferences-builtinBridge-dialog" 67 ); 68 dialog.addEventListener("dialogaccept", () => { 69 this._result.accepted = true; 70 }); 71 72 // Add styling for tor-button to the dialog shadow root. 73 const styleLink = document.createElement("link"); 74 styleLink.rel = "stylesheet"; 75 styleLink.href = 76 "chrome://browser/content/torpreferences/torPreferences.css"; 77 dialog.shadowRoot.append(styleLink); 78 79 this._acceptButton = dialog.getButton("accept"); 80 81 Services.obs.addObserver(this, TorConnectTopics.StageChange); 82 83 this.onSelectChange(); 84 this.onAcceptStateChange(); 85 }, 86 87 uninit() { 88 Services.obs.removeObserver(this, TorConnectTopics.StageChange); 89 }, 90 91 onSelectChange() { 92 const value = this._radioGroup.value; 93 this._acceptButton.disabled = !value; 94 this._result.type = value; 95 }, 96 97 onAcceptStateChange() { 98 const connect = TorConnect.stageName !== TorConnectStage.Bootstrapped; 99 this._result.connect = connect; 100 this._acceptButton.setAttribute( 101 "data-l10n-id", 102 connect ? "bridge-dialog-button-connect2" : "bridge-dialog-button-accept2" 103 ); 104 this._acceptButton.classList.toggle("tor-button", connect); 105 }, 106 107 observe(subject, topic) { 108 switch (topic) { 109 case TorConnectTopics.StageChange: 110 this.onAcceptStateChange(); 111 break; 112 } 113 }, 114 }; 115 116 // Initial focus is not visible, even if opened with a keyboard. We avoid the 117 // default handler and manage the focus ourselves, which will paint the focus 118 // ring by default. 119 // NOTE: A side effect is that the focus ring will show even if the user opened 120 // with a mouse event. 121 // TODO: Remove this once bugzilla bug 1708261 is resolved. 122 document.subDialogSetDefaultFocus = () => { 123 document.getElementById("torPreferences-builtinBridge-typeSelection").focus(); 124 }; 125 126 window.addEventListener( 127 "DOMContentLoaded", 128 () => { 129 gBuiltinBridgeDialog.init(); 130 window.addEventListener( 131 "unload", 132 () => { 133 gBuiltinBridgeDialog.uninit(); 134 }, 135 { once: true } 136 ); 137 }, 138 { once: true } 139 );