[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

[tor-commits] [Git][tpo/applications/tor-browser][tor-browser-153.0esr-16.0-1] fixup! TB 31286: Implementation of bridge, proxy, and firewall settings in...



Title: GitLab

morgan pushed to branch tor-browser-153.0esr-16.0-1 at The Tor Project / Applications / Tor Browser

Commits:

  • 7bfb497b
    by Henry Wilkes at 2026-07-28T11:22:09+00:00
    fixup! TB 31286: Implementation of bridge, proxy, and firewall settings in about:preferences#connection
    
    TB 45125: Make sure observers are removed when the page in unloaded.
    
    Also remove a race condition between successive locale changes.
    

1 changed file:

Changes:

  • browser/components/torpreferences/content/bridgemoji/BridgeEmoji.js
    ... ... @@ -5,59 +5,89 @@
    5 5
        * Element to display a single bridge emoji, with a localized name.
    
    6 6
        */
    
    7 7
       class BridgeEmoji extends HTMLElement {
    
    8
    +    /**
    
    9
    +     * The instances that are active (in the DOM).
    
    10
    +     *
    
    11
    +     * @type {Set<BridgeEmoji>}
    
    12
    +     */
    
    8 13
         static #activeInstances = new Set();
    
    9
    -    static #observer(subject, topic) {
    
    10
    -      if (topic === "intl:app-locales-changed") {
    
    11
    -        BridgeEmoji.#updateEmojiLangCode();
    
    12
    -      }
    
    13
    -    }
    
    14 14
     
    
    15
    -    static #addActiveInstance(inst) {
    
    16
    -      if (this.#activeInstances.size === 0) {
    
    17
    -        Services.obs.addObserver(this.#observer, "intl:app-locales-changed");
    
    18
    -        this.#updateEmojiLangCode();
    
    19
    -      }
    
    20
    -      this.#activeInstances.add(inst);
    
    21
    -    }
    
    22
    -
    
    23
    -    static #removeActiveInstance(inst) {
    
    24
    -      this.#activeInstances.delete(inst);
    
    25
    -      if (this.#activeInstances.size === 0) {
    
    26
    -        Services.obs.removeObserver(this.#observer, "intl:app-locales-changed");
    
    27
    -      }
    
    28
    -    }
    
    15
    +    /**
    
    16
    +     * A promise that resolves with a list of emoji strings, in a specific
    
    17
    +     * order. Each BridgeEmoji instance has an `#index` in this list, which
    
    18
    +     * points to its corresponding emoji.
    
    19
    +     *
    
    20
    +     * @type {Promise<string[]>}
    
    21
    +     */
    
    22
    +    static #emojiListPromise = fetch(
    
    23
    +      "chrome://browser/content/torpreferences/bridgemoji/bridge-emojis.json"
    
    24
    +    ).then(response => response.json());
    
    29 25
     
    
    30 26
         /**
    
    31
    -     * The language code for emoji annotations.
    
    27
    +     * @typedef {{[key: string]: string}} EmojiAnnotations
    
    32 28
          *
    
    33
    -     * null if unset.
    
    29
    +     * A map from an emoji's codepoint to a locale's annotation.
    
    30
    +     */
    
    31
    +    /**
    
    32
    +     * A promise that resolves with a map from locales to their annotations.
    
    33
    +     *
    
    34
    +     * @type {Promise<{[key: string]: EmojiAnnotattions}>}
    
    35
    +     */
    
    36
    +    static #annotationsPromise = fetch(
    
    37
    +      "chrome://browser/content/torpreferences/bridgemoji/annotations.json"
    
    38
    +    ).then(response => response.json());
    
    39
    +
    
    40
    +    /**
    
    41
    +     * @typedef {object} EmojiLocaleDetails
    
    34 42
          *
    
    35
    -     * @type {string?}
    
    43
    +     * @property {string[]} [emojiList] - A list of emojis as strings, in a
    
    44
    +     *   specific order.
    
    45
    +     * @property {EmojiAnnotations} [annotations] - The annotations for the
    
    46
    +     *   locale.
    
    47
    +     * @property {string} [unknownString] - The string to use for emojis with
    
    48
    +     *   undefined annotations.
    
    36 49
          */
    
    37
    -    static #emojiLangCode = null;
    
    38 50
         /**
    
    39
    -     * A promise that resolves to two JSON structures for bridge-emojis.json and
    
    40
    -     * annotations.json, respectively.
    
    51
    +     * The cached locale details.
    
    41 52
          *
    
    42
    -     * @type {Promise}
    
    53
    +     * @type {EmojiLocaleDetails}
    
    43 54
          */
    
    44
    -    static #emojiPromise = Promise.all([
    
    45
    -      fetch(
    
    46
    -        "chrome://browser/content/torpreferences/bridgemoji/bridge-emojis.json"
    
    47
    -      ).then(response => response.json()),
    
    48
    -      fetch(
    
    49
    -        "chrome://browser/content/torpreferences/bridgemoji/annotations.json"
    
    50
    -      ).then(response => response.json()),
    
    51
    -    ]);
    
    55
    +    static #emojiLocaleDetails = {};
    
    52 56
     
    
    53
    -    static #unknownStringPromise = null;
    
    57
    +    /**
    
    58
    +     * A promise that resolves when the previous call to appLocalesChanged
    
    59
    +     * completes.
    
    60
    +     *
    
    61
    +     * @type {Promise?}
    
    62
    +     */
    
    63
    +    static #prevAppLocalesChangedCall = null;
    
    54 64
     
    
    55 65
         /**
    
    56
    -     * Update #emojiLangCode.
    
    66
    +     * Update the locale used for bridge emoji widget.
    
    57 67
          */
    
    58
    -    static async #updateEmojiLangCode() {
    
    68
    +    static async appLocalesChanged() {
    
    69
    +      // Introduce a queue to ensure calls apply in the order they are invoked,
    
    70
    +      // so the last seen locale will eventually be the applied one.
    
    71
    +      const { promise, resolve } = Promise.withResolvers();
    
    72
    +      const prevAppLocalesChangedCall = this.#prevAppLocalesChangedCall;
    
    73
    +      this.#prevAppLocalesChangedCall = promise;
    
    74
    +      try {
    
    75
    +        await prevAppLocalesChangedCall;
    
    76
    +        await this.#appLocalesChangedInternal();
    
    77
    +      } finally {
    
    78
    +        resolve();
    
    79
    +      }
    
    80
    +    }
    
    81
    +
    
    82
    +    static async #appLocalesChangedInternal() {
    
    83
    +      let [emojiAnnotations, emojiList, unknownString] = await Promise.all([
    
    84
    +        this.#annotationsPromise,
    
    85
    +        this.#emojiListPromise,
    
    86
    +        // Grab the string for the new locale.
    
    87
    +        document.l10n.formatValue("tor-bridges-emoji-unknown"),
    
    88
    +      ]);
    
    89
    +
    
    59 90
           let langCode;
    
    60
    -      const emojiAnnotations = (await BridgeEmoji.#emojiPromise)[1];
    
    61 91
           // Find the first desired locale we have annotations for.
    
    62 92
           // Add "en" as a fallback.
    
    63 93
           for (const bcp47 of [...Services.locale.appLocalesAsBCP47, "en"]) {
    
    ... ... @@ -71,14 +101,14 @@
    71 101
               break;
    
    72 102
             }
    
    73 103
           }
    
    74
    -      if (langCode !== this.#emojiLangCode) {
    
    75
    -        this.#emojiLangCode = langCode;
    
    76
    -        this.#unknownStringPromise = document.l10n.formatValue(
    
    77
    -          "tor-bridges-emoji-unknown"
    
    78
    -        );
    
    79
    -        for (const inst of this.#activeInstances) {
    
    80
    -          inst.update();
    
    81
    -        }
    
    104
    +
    
    105
    +      this.#emojiLocaleDetails = {
    
    106
    +        emojiList,
    
    107
    +        annotations: emojiAnnotations[langCode],
    
    108
    +        unknownString,
    
    109
    +      };
    
    110
    +      for (const inst of this.#activeInstances) {
    
    111
    +        inst.update();
    
    82 112
           }
    
    83 113
         }
    
    84 114
     
    
    ... ... @@ -86,22 +116,15 @@
    86 116
          * Update the bridge emoji to show their corresponding emoji with an
    
    87 117
          * annotation that matches the current locale.
    
    88 118
          */
    
    89
    -    async update() {
    
    90
    -      if (!this.#active) {
    
    91
    -        return;
    
    92
    -      }
    
    119
    +    update() {
    
    120
    +      const { emojiList, annotations, unknownString } =
    
    121
    +        BridgeEmoji.#emojiLocaleDetails;
    
    93 122
     
    
    94
    -      if (!BridgeEmoji.#emojiLangCode) {
    
    95
    -        // No lang code yet, wait until it is updated.
    
    123
    +      if (!this.#active || !emojiList || !annotations || !unknownString) {
    
    96 124
             return;
    
    97 125
           }
    
    98 126
     
    
    99 127
           const doc = this.ownerDocument;
    
    100
    -      const [unknownString, [emojiList, emojiAnnotations]] = await Promise.all([
    
    101
    -        BridgeEmoji.#unknownStringPromise,
    
    102
    -        BridgeEmoji.#emojiPromise,
    
    103
    -      ]);
    
    104
    -
    
    105 128
           const emoji = emojiList[this.#index];
    
    106 129
           let emojiName;
    
    107 130
           if (!emoji) {
    
    ... ... @@ -113,7 +136,7 @@
    113 136
               "src",
    
    114 137
               `chrome://browser/content/torpreferences/bridgemoji/svgs/${cp}.svg`
    
    115 138
             );
    
    116
    -        emojiName = emojiAnnotations[BridgeEmoji.#emojiLangCode][cp];
    
    139
    +        emojiName = annotations[cp];
    
    117 140
           }
    
    118 141
           if (!emojiName) {
    
    119 142
             doc.defaultView.console.error(`No emoji for index ${this.#index}`);
    
    ... ... @@ -157,13 +180,13 @@
    157 180
           }
    
    158 181
     
    
    159 182
           this.#active = true;
    
    160
    -      BridgeEmoji.#addActiveInstance(this);
    
    183
    +      BridgeEmoji.#activeInstances.add(this);
    
    161 184
           this.update();
    
    162 185
         }
    
    163 186
     
    
    164 187
         disconnectedCallback() {
    
    165 188
           this.#active = false;
    
    166
    -      BridgeEmoji.#removeActiveInstance(this);
    
    189
    +      BridgeEmoji.#activeInstances.delete(this);
    
    167 190
         }
    
    168 191
     
    
    169 192
         /**
    
    ... ... @@ -196,4 +219,20 @@
    196 219
       }
    
    197 220
     
    
    198 221
       customElements.define("tor-bridge-emoji", BridgeEmoji);
    
    222
    +
    
    223
    +  {
    
    224
    +    const appLocalesChanged = BridgeEmoji.appLocalesChanged.bind(BridgeEmoji);
    
    225
    +    Services.obs.addObserver(appLocalesChanged, "intl:app-locales-changed");
    
    226
    +    window.addEventListener(
    
    227
    +      "unload",
    
    228
    +      () => {
    
    229
    +        Services.obs.removeObserver(
    
    230
    +          appLocalesChanged,
    
    231
    +          "intl:app-locales-changed"
    
    232
    +        );
    
    233
    +      },
    
    234
    +      { once: true }
    
    235
    +    );
    
    236
    +    appLocalesChanged();
    
    237
    +  }
    
    199 238
     }

  • _______________________________________________
    tor-commits mailing list -- tor-commits@xxxxxxxxxxxxxxxxxxxx
    To unsubscribe send an email to tor-commits-leave@xxxxxxxxxxxxxxxxxxxx