forked from mirrors/gecko-dev
		
	Automatic changes by ESLint, except for manual corrections for .xml files. Differential Revision: https://phabricator.services.mozilla.com/D4439 --HG-- extra : moz-landing-system : lando
		
			
				
	
	
		
			339 lines
		
	
	
	
		
			11 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			339 lines
		
	
	
	
		
			11 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
/* -*- indent-tabs-mode: nil; js-indent-level: 4 -*- */
 | 
						|
/* 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/. */
 | 
						|
 | 
						|
/* import-globals-from ../../../toolkit/content/preferencesBindings.js */
 | 
						|
 | 
						|
ChromeUtils.import("resource://gre/modules/Services.jsm");
 | 
						|
 | 
						|
Preferences.addAll([
 | 
						|
  { id: "intl.accept_languages", type: "wstring" },
 | 
						|
  { id: "pref.browser.language.disable_button.up", type: "bool" },
 | 
						|
  { id: "pref.browser.language.disable_button.down", type: "bool" },
 | 
						|
  { id: "pref.browser.language.disable_button.remove", type: "bool" },
 | 
						|
  { id: "privacy.spoof_english", type: "int" },
 | 
						|
]);
 | 
						|
 | 
						|
var gLanguagesDialog = {
 | 
						|
 | 
						|
  _availableLanguagesList: [],
 | 
						|
  _acceptLanguages: { },
 | 
						|
 | 
						|
  _selectedItemID: null,
 | 
						|
 | 
						|
  onLoad() {
 | 
						|
    Preferences.get("intl.accept_languages").on("change",
 | 
						|
      () => this._readAcceptLanguages().catch(Cu.reportError));
 | 
						|
 | 
						|
    if (!this._availableLanguagesList.length) {
 | 
						|
      document.mozSubdialogReady = this._loadAvailableLanguages();
 | 
						|
    }
 | 
						|
  },
 | 
						|
 | 
						|
  get _activeLanguages() {
 | 
						|
    return document.getElementById("activeLanguages");
 | 
						|
  },
 | 
						|
 | 
						|
  get _availableLanguages() {
 | 
						|
    return document.getElementById("availableLanguages");
 | 
						|
  },
 | 
						|
 | 
						|
  async _loadAvailableLanguages() {
 | 
						|
    // This is a parser for: resource://gre/res/language.properties
 | 
						|
    // The file is formatted like so:
 | 
						|
    // ab[-cd].accept=true|false
 | 
						|
    //  ab = language
 | 
						|
    //  cd = region
 | 
						|
    var bundleAccepted    = document.getElementById("bundleAccepted");
 | 
						|
 | 
						|
    function LocaleInfo(aLocaleName, aLocaleCode, aIsVisible) {
 | 
						|
      this.name = aLocaleName;
 | 
						|
      this.code = aLocaleCode;
 | 
						|
      this.isVisible = aIsVisible;
 | 
						|
    }
 | 
						|
 | 
						|
    // 1) Read the available languages out of language.properties
 | 
						|
 | 
						|
    let localeCodes = [];
 | 
						|
    let localeValues = [];
 | 
						|
    for (let currString of bundleAccepted.strings) {
 | 
						|
      var property = currString.key.split("."); // ab[-cd].accept
 | 
						|
      if (property[1] == "accept") {
 | 
						|
        localeCodes.push(property[0]);
 | 
						|
        localeValues.push(currString.value);
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    let localeNames = Services.intl.getLocaleDisplayNames(undefined, localeCodes);
 | 
						|
 | 
						|
    for (let i in localeCodes) {
 | 
						|
      let isVisible = localeValues[i] == "true" &&
 | 
						|
        (!(localeCodes[i] in this._acceptLanguages) || !this._acceptLanguages[localeCodes[i]]);
 | 
						|
 | 
						|
      let li = new LocaleInfo(localeNames[i], localeCodes[i], isVisible);
 | 
						|
      this._availableLanguagesList.push(li);
 | 
						|
    }
 | 
						|
 | 
						|
    await this._buildAvailableLanguageList();
 | 
						|
    await this._readAcceptLanguages();
 | 
						|
  },
 | 
						|
 | 
						|
  async _buildAvailableLanguageList() {
 | 
						|
    var availableLanguagesPopup = document.getElementById("availableLanguagesPopup");
 | 
						|
    while (availableLanguagesPopup.hasChildNodes())
 | 
						|
      availableLanguagesPopup.firstChild.remove();
 | 
						|
 | 
						|
    let frag = document.createDocumentFragment();
 | 
						|
 | 
						|
    // Load the UI with the data
 | 
						|
    for (var i = 0; i < this._availableLanguagesList.length; ++i) {
 | 
						|
      let locale = this._availableLanguagesList[i];
 | 
						|
      let localeCode = locale.code;
 | 
						|
      if (locale.isVisible &&
 | 
						|
          (!(localeCode in this._acceptLanguages) || !this._acceptLanguages[localeCode])) {
 | 
						|
        var menuitem = document.createXULElement("menuitem");
 | 
						|
        menuitem.id = localeCode;
 | 
						|
        document.l10n.setAttributes(menuitem, "languages-code-format", {
 | 
						|
          locale: locale.name,
 | 
						|
          code: localeCode,
 | 
						|
        });
 | 
						|
        frag.appendChild(menuitem);
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    await document.l10n.translateFragment(frag);
 | 
						|
 | 
						|
    // Sort the list of languages by name
 | 
						|
    let comp = new Services.intl.Collator(undefined, {
 | 
						|
      usage: "sort",
 | 
						|
    });
 | 
						|
 | 
						|
    let items = Array.from(frag.children);
 | 
						|
 | 
						|
    items.sort((a, b) => {
 | 
						|
      return comp.compare(a.getAttribute("label"), b.getAttribute("label"));
 | 
						|
    });
 | 
						|
 | 
						|
    // Re-append items in the correct order:
 | 
						|
    items.forEach(item => frag.appendChild(item));
 | 
						|
 | 
						|
    availableLanguagesPopup.appendChild(frag);
 | 
						|
 | 
						|
    this._availableLanguages.setAttribute("label", this._availableLanguages.getAttribute("placeholder"));
 | 
						|
  },
 | 
						|
 | 
						|
  async _readAcceptLanguages() {
 | 
						|
    while (this._activeLanguages.hasChildNodes())
 | 
						|
      this._activeLanguages.firstChild.remove();
 | 
						|
 | 
						|
    var selectedIndex = 0;
 | 
						|
    var preference = Preferences.get("intl.accept_languages");
 | 
						|
    if (preference.value == "")
 | 
						|
      return;
 | 
						|
    var languages = preference.value.toLowerCase().split(/\s*,\s*/);
 | 
						|
    for (var i = 0; i < languages.length; ++i) {
 | 
						|
      var listitem = document.createXULElement("richlistitem");
 | 
						|
      var label = document.createXULElement("label");
 | 
						|
      listitem.appendChild(label);
 | 
						|
      listitem.id = languages[i];
 | 
						|
      if (languages[i] == this._selectedItemID)
 | 
						|
        selectedIndex = i;
 | 
						|
      this._activeLanguages.appendChild(listitem);
 | 
						|
      var localeName = this._getLocaleName(languages[i]);
 | 
						|
      document.l10n.setAttributes(label, "languages-active-code-format", {
 | 
						|
        locale: localeName,
 | 
						|
        code: languages[i],
 | 
						|
      });
 | 
						|
 | 
						|
      // Hash this language as an "Active" language so we don't
 | 
						|
      // show it in the list that can be added.
 | 
						|
      this._acceptLanguages[languages[i]] = true;
 | 
						|
    }
 | 
						|
 | 
						|
    // We're forcing an early localization here because otherwise
 | 
						|
    // the initial sizing of the dialog will happen before it and
 | 
						|
    // result in overflow.
 | 
						|
    await document.l10n.translateFragment(this._activeLanguages);
 | 
						|
 | 
						|
    if (this._activeLanguages.childNodes.length > 0) {
 | 
						|
      this._activeLanguages.ensureIndexIsVisible(selectedIndex);
 | 
						|
      this._activeLanguages.selectedIndex = selectedIndex;
 | 
						|
    }
 | 
						|
 | 
						|
    // Update states of accept-language list and buttons according to
 | 
						|
    // privacy.resistFingerprinting and privacy.spoof_english.
 | 
						|
    this.readSpoofEnglish();
 | 
						|
  },
 | 
						|
 | 
						|
  onAvailableLanguageSelect() {
 | 
						|
    var availableLanguages = this._availableLanguages;
 | 
						|
    var addButton = document.getElementById("addButton");
 | 
						|
    addButton.disabled = availableLanguages.disabled ||
 | 
						|
                         availableLanguages.selectedIndex < 0;
 | 
						|
 | 
						|
    this._availableLanguages.removeAttribute("accesskey");
 | 
						|
  },
 | 
						|
 | 
						|
  addLanguage() {
 | 
						|
    var selectedID = this._availableLanguages.selectedItem.id;
 | 
						|
    var preference = Preferences.get("intl.accept_languages");
 | 
						|
    var arrayOfPrefs = preference.value.toLowerCase().split(/\s*,\s*/);
 | 
						|
    for (var i = 0; i < arrayOfPrefs.length; ++i ) {
 | 
						|
      if (arrayOfPrefs[i] == selectedID)
 | 
						|
        return;
 | 
						|
    }
 | 
						|
 | 
						|
    this._selectedItemID = selectedID;
 | 
						|
 | 
						|
    if (preference.value == "")
 | 
						|
      preference.value = selectedID;
 | 
						|
    else {
 | 
						|
      arrayOfPrefs.unshift(selectedID);
 | 
						|
      preference.value = arrayOfPrefs.join(",");
 | 
						|
    }
 | 
						|
 | 
						|
    this._acceptLanguages[selectedID] = true;
 | 
						|
    this._availableLanguages.selectedItem = null;
 | 
						|
 | 
						|
    // Rebuild the available list with the added item removed...
 | 
						|
    this._buildAvailableLanguageList().catch(Cu.reportError);
 | 
						|
  },
 | 
						|
 | 
						|
  removeLanguage() {
 | 
						|
    // Build the new preference value string.
 | 
						|
    var languagesArray = [];
 | 
						|
    for (var i = 0; i < this._activeLanguages.childNodes.length; ++i) {
 | 
						|
      var item = this._activeLanguages.childNodes[i];
 | 
						|
      if (!item.selected)
 | 
						|
        languagesArray.push(item.id);
 | 
						|
      else
 | 
						|
        this._acceptLanguages[item.id] = false;
 | 
						|
    }
 | 
						|
    var string = languagesArray.join(",");
 | 
						|
 | 
						|
    // Get the item to select after the remove operation completes.
 | 
						|
    var selection = this._activeLanguages.selectedItems;
 | 
						|
    var lastSelected = selection[selection.length - 1];
 | 
						|
    var selectItem = lastSelected.nextSibling || lastSelected.previousSibling;
 | 
						|
    selectItem = selectItem ? selectItem.id : null;
 | 
						|
 | 
						|
    this._selectedItemID = selectItem;
 | 
						|
 | 
						|
    // Update the preference and force a UI rebuild
 | 
						|
    var preference = Preferences.get("intl.accept_languages");
 | 
						|
    preference.value = string;
 | 
						|
 | 
						|
    this._buildAvailableLanguageList().catch(Cu.reportError);
 | 
						|
  },
 | 
						|
 | 
						|
  _getLocaleName(localeCode) {
 | 
						|
    if (!this._availableLanguagesList.length)
 | 
						|
      this._loadAvailableLanguages();
 | 
						|
    for (var i = 0; i < this._availableLanguagesList.length; ++i) {
 | 
						|
      if (localeCode == this._availableLanguagesList[i].code)
 | 
						|
        return this._availableLanguagesList[i].name;
 | 
						|
    }
 | 
						|
    return "";
 | 
						|
  },
 | 
						|
 | 
						|
  moveUp() {
 | 
						|
    var selectedItem = this._activeLanguages.selectedItems[0];
 | 
						|
    var previousItem = selectedItem.previousSibling;
 | 
						|
 | 
						|
    var string = "";
 | 
						|
    for (var i = 0; i < this._activeLanguages.childNodes.length; ++i) {
 | 
						|
      var item = this._activeLanguages.childNodes[i];
 | 
						|
      string += (i == 0 ? "" : ",");
 | 
						|
      if (item.id == previousItem.id)
 | 
						|
        string += selectedItem.id;
 | 
						|
      else if (item.id == selectedItem.id)
 | 
						|
        string += previousItem.id;
 | 
						|
      else
 | 
						|
        string += item.id;
 | 
						|
    }
 | 
						|
 | 
						|
    this._selectedItemID = selectedItem.id;
 | 
						|
 | 
						|
    // Update the preference and force a UI rebuild
 | 
						|
    var preference = Preferences.get("intl.accept_languages");
 | 
						|
    preference.value = string;
 | 
						|
  },
 | 
						|
 | 
						|
  moveDown() {
 | 
						|
    var selectedItem = this._activeLanguages.selectedItems[0];
 | 
						|
    var nextItem = selectedItem.nextSibling;
 | 
						|
 | 
						|
    var string = "";
 | 
						|
    for (var i = 0; i < this._activeLanguages.childNodes.length; ++i) {
 | 
						|
      var item = this._activeLanguages.childNodes[i];
 | 
						|
      string += (i == 0 ? "" : ",");
 | 
						|
      if (item.id == nextItem.id)
 | 
						|
        string += selectedItem.id;
 | 
						|
      else if (item.id == selectedItem.id)
 | 
						|
        string += nextItem.id;
 | 
						|
      else
 | 
						|
        string += item.id;
 | 
						|
    }
 | 
						|
 | 
						|
    this._selectedItemID = selectedItem.id;
 | 
						|
 | 
						|
    // Update the preference and force a UI rebuild
 | 
						|
    var preference = Preferences.get("intl.accept_languages");
 | 
						|
    preference.value = string;
 | 
						|
  },
 | 
						|
 | 
						|
  onLanguageSelect() {
 | 
						|
    var upButton = document.getElementById("up");
 | 
						|
    var downButton = document.getElementById("down");
 | 
						|
    var removeButton = document.getElementById("remove");
 | 
						|
    switch (this._activeLanguages.selectedCount) {
 | 
						|
    case 0:
 | 
						|
      upButton.disabled = downButton.disabled = removeButton.disabled = true;
 | 
						|
      break;
 | 
						|
    case 1:
 | 
						|
      upButton.disabled = this._activeLanguages.selectedIndex == 0;
 | 
						|
      downButton.disabled = this._activeLanguages.selectedIndex == this._activeLanguages.childNodes.length - 1;
 | 
						|
      removeButton.disabled = false;
 | 
						|
      break;
 | 
						|
    default:
 | 
						|
      upButton.disabled = true;
 | 
						|
      downButton.disabled = true;
 | 
						|
      removeButton.disabled = false;
 | 
						|
    }
 | 
						|
  },
 | 
						|
 | 
						|
  readSpoofEnglish() {
 | 
						|
    var checkbox = document.getElementById("spoofEnglish");
 | 
						|
    var resistFingerprinting = Services.prefs.getBoolPref("privacy.resistFingerprinting");
 | 
						|
    if (!resistFingerprinting) {
 | 
						|
      checkbox.hidden = true;
 | 
						|
      return false;
 | 
						|
    }
 | 
						|
 | 
						|
    var spoofEnglish = Preferences.get("privacy.spoof_english").value;
 | 
						|
    var activeLanguages = this._activeLanguages;
 | 
						|
    var availableLanguages = this._availableLanguages;
 | 
						|
    checkbox.hidden = false;
 | 
						|
    switch (spoofEnglish) {
 | 
						|
    case 1: // don't spoof intl.accept_languages
 | 
						|
      activeLanguages.disabled = false;
 | 
						|
      activeLanguages.selectItem(activeLanguages.firstChild);
 | 
						|
      availableLanguages.disabled = false;
 | 
						|
      this.onAvailableLanguageSelect();
 | 
						|
      return false;
 | 
						|
    case 2: // spoof intl.accept_languages
 | 
						|
      activeLanguages.clearSelection();
 | 
						|
      activeLanguages.disabled = true;
 | 
						|
      availableLanguages.disabled = true;
 | 
						|
      this.onAvailableLanguageSelect();
 | 
						|
      return true;
 | 
						|
    default: // will prompt for spoofing intl.accept_languages if resisting fingerprinting
 | 
						|
      return false;
 | 
						|
    }
 | 
						|
  },
 | 
						|
 | 
						|
  writeSpoofEnglish() {
 | 
						|
    return document.getElementById("spoofEnglish").checked ? 2 : 1;
 | 
						|
  },
 | 
						|
};
 |