tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

config.js (22137B)


      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 file,
      3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 "use strict";
      5 
      6 var Cm = Components.manager;
      7 
      8 const VKB_ENTER_KEY = 13; // User press of VKB enter key
      9 const INITIAL_PAGE_DELAY = 500; // Initial pause on program start for scroll alignment
     10 const PREFS_BUFFER_MAX = 30; // Max prefs buffer size for getPrefsBuffer()
     11 const PAGE_SCROLL_TRIGGER = 200; // Triggers additional getPrefsBuffer() on user scroll-to-bottom
     12 const FILTER_CHANGE_TRIGGER = 200; // Delay between responses to filterInput changes
     13 const INNERHTML_VALUE_DELAY = 100; // Delay before providing prefs innerHTML value
     14 
     15 var gClipboardHelper = Cc["@mozilla.org/widget/clipboardhelper;1"].getService(
     16  Ci.nsIClipboardHelper
     17 );
     18 
     19 /* ============================== NewPrefDialog ==============================
     20 *
     21 * New Preference Dialog Object and methods
     22 *
     23 * Implements User Interfaces for creation of a single(new) Preference setting
     24 *
     25 */
     26 var NewPrefDialog = {
     27  _prefsShield: null,
     28 
     29  _newPrefsDialog: null,
     30  _newPrefItem: null,
     31  _prefNameInputElt: null,
     32  _prefTypeSelectElt: null,
     33 
     34  _booleanValue: null,
     35  _booleanToggle: null,
     36  _stringValue: null,
     37  _intValue: null,
     38 
     39  _positiveButton: null,
     40 
     41  get type() {
     42    return this._prefTypeSelectElt.value;
     43  },
     44 
     45  set type(aType) {
     46    this._prefTypeSelectElt.value = aType;
     47    switch (this._prefTypeSelectElt.value) {
     48      case "boolean":
     49        this._prefTypeSelectElt.selectedIndex = 0;
     50        break;
     51      case "string":
     52        this._prefTypeSelectElt.selectedIndex = 1;
     53        break;
     54      case "int":
     55        this._prefTypeSelectElt.selectedIndex = 2;
     56        break;
     57    }
     58 
     59    this._newPrefItem.setAttribute("typestyle", aType);
     60  },
     61 
     62  // Init the NewPrefDialog
     63  init: function AC_init() {
     64    this._prefsShield = document.getElementById("prefs-shield");
     65 
     66    this._newPrefsDialog = document.getElementById("new-pref-container");
     67    this._newPrefItem = document.getElementById("new-pref-item");
     68    this._prefNameInputElt = document.getElementById("new-pref-name");
     69    this._prefTypeSelectElt = document.getElementById("new-pref-type");
     70 
     71    this._booleanValue = document.getElementById("new-pref-value-boolean");
     72    this._stringValue = document.getElementById("new-pref-value-string");
     73    this._intValue = document.getElementById("new-pref-value-int");
     74 
     75    this._positiveButton = document.getElementById("positive-button");
     76  },
     77 
     78  // Called to update positive button to display text ("Create"/"Change), and enabled/disabled status
     79  // As new pref name is initially displayed, re-focused, or modifed during user input
     80  _updatePositiveButton: function AC_updatePositiveButton(aPrefName) {
     81    document.l10n.setAttributes(
     82      this._positiveButton,
     83      "config-new-pref-create-button"
     84    );
     85    this._positiveButton.setAttribute("disabled", true);
     86    if (aPrefName == "") {
     87      return;
     88    }
     89 
     90    // If item already in list, it's being changed, else added
     91    const item = AboutConfig._list.filter(i => {
     92      return i.name == aPrefName;
     93    });
     94    if (item.length) {
     95      document.l10n.setAttributes(
     96        this._positiveButton,
     97        "config-new-pref-change-button"
     98      );
     99    } else {
    100      this._positiveButton.removeAttribute("disabled");
    101    }
    102  },
    103 
    104  // When we want to cancel/hide an existing, or show a new pref dialog
    105  toggleShowHide: function AC_toggleShowHide() {
    106    if (this._newPrefsDialog.classList.contains("show")) {
    107      this.hide();
    108    } else {
    109      this._show();
    110    }
    111  },
    112 
    113  // When we want to show the new pref dialog / shield the prefs list
    114  _show: function AC_show() {
    115    this._newPrefsDialog.classList.add("show");
    116    this._prefsShield.setAttribute("shown", true);
    117 
    118    // Initial default field values
    119    this._prefNameInputElt.value = "";
    120    this._updatePositiveButton(this._prefNameInputElt.value);
    121 
    122    this.type = "boolean";
    123    this._booleanValue.value = "false";
    124    this._stringValue.value = "";
    125    this._intValue.value = "";
    126 
    127    this._prefNameInputElt.focus();
    128 
    129    window.addEventListener("keypress", this.handleKeypress);
    130  },
    131 
    132  // When we want to cancel/hide the new pref dialog / un-shield the prefs list
    133  hide: function AC_hide() {
    134    this._newPrefsDialog.classList.remove("show");
    135    this._prefsShield.removeAttribute("shown");
    136 
    137    window.removeEventListener("keypress", this.handleKeypress);
    138  },
    139 
    140  // Watch user key input so we can provide Enter key action, commit input values
    141  handleKeypress: function AC_handleKeypress(aEvent) {
    142    // Close our VKB on new pref enter key press
    143    if (aEvent.keyCode == VKB_ENTER_KEY) {
    144      aEvent.target.blur();
    145    }
    146  },
    147 
    148  // New prefs create dialog only allows creating a non-existing preference, doesn't allow for
    149  // Changing an existing one on-the-fly, tap existing/displayed line item pref for that
    150  create: function AC_create() {
    151    if (this._positiveButton.getAttribute("disabled") == "true") {
    152      return;
    153    }
    154 
    155    switch (this.type) {
    156      case "boolean":
    157        Services.prefs.setBoolPref(
    158          this._prefNameInputElt.value,
    159          !!(this._booleanValue.value == "true")
    160        );
    161        break;
    162      case "string":
    163        Services.prefs.setCharPref(
    164          this._prefNameInputElt.value,
    165          this._stringValue.value
    166        );
    167        break;
    168      case "int":
    169        Services.prefs.setIntPref(
    170          this._prefNameInputElt.value,
    171          this._intValue.value
    172        );
    173        break;
    174    }
    175 
    176    // Ensure pref adds flushed to disk immediately
    177    Services.prefs.savePrefFile(null);
    178 
    179    this.hide();
    180  },
    181 
    182  // Display proper positive button text/state on new prefs name input focus
    183  focusName: function AC_focusName(aEvent) {
    184    this._updatePositiveButton(aEvent.target.value);
    185  },
    186 
    187  // Display proper positive button text/state as user changes new prefs name
    188  updateName: function AC_updateName(aEvent) {
    189    this._updatePositiveButton(aEvent.target.value);
    190  },
    191 
    192  // In new prefs dialog, bool prefs are <input type="text">, as they aren't yet tied to an
    193  // Actual Services.prefs.*etBoolPref()
    194  toggleBoolValue: function AC_toggleBoolValue() {
    195    this._booleanValue.value =
    196      this._booleanValue.value == "true" ? "false" : "true";
    197  },
    198 };
    199 
    200 /* ============================== AboutConfig ==============================
    201 *
    202 * Main AboutConfig object and methods
    203 *
    204 * Implements User Interfaces for maintenance of a list of Preference settings
    205 *
    206 */
    207 var AboutConfig = {
    208  contextMenuLINode: null,
    209  filterInput: null,
    210  _filterPrevInput: null,
    211  _filterChangeTimer: null,
    212  _prefsContainer: null,
    213  _loadingContainer: null,
    214  _list: null,
    215 
    216  // Init the main AboutConfig dialog
    217  init: function AC_init() {
    218    this.filterInput = document.getElementById("filter-input");
    219    this._prefsContainer = document.getElementById("prefs-container");
    220    this._loadingContainer = document.getElementById("loading-container");
    221 
    222    const list = Services.prefs.getChildList("");
    223    this._list = list.sort().map(function AC_getMapPref(aPref) {
    224      return new Pref(aPref);
    225    }, this);
    226 
    227    // Support filtering about:config via a ?filter=<string> param
    228    const match = /[?&]filter=([^&]+)/i.exec(window.location.href);
    229    if (match) {
    230      this.filterInput.value = decodeURIComponent(match[1]);
    231    }
    232 
    233    // Display the current prefs list (retains searchFilter value)
    234    this.bufferFilterInput();
    235 
    236    // Setup the prefs observers
    237    Services.prefs.addObserver("", this);
    238  },
    239 
    240  // Uninit the main AboutConfig dialog
    241  uninit: function AC_uninit() {
    242    // Remove the prefs observer
    243    Services.prefs.removeObserver("", this);
    244  },
    245 
    246  // Buffer down rapid changes in filterInput value from keyboard
    247  bufferFilterInput: function AC_bufferFilterInput() {
    248    if (this._filterChangeTimer) {
    249      clearTimeout(this._filterChangeTimer);
    250    }
    251 
    252    this._filterChangeTimer = setTimeout(() => {
    253      this._filterChangeTimer = null;
    254      // Display updated prefs list when filterInput value settles
    255      this._displayNewList();
    256    }, FILTER_CHANGE_TRIGGER);
    257  },
    258 
    259  // Update displayed list when filterInput value changes
    260  _displayNewList: function AC_displayNewList() {
    261    // This survives the search filter value past a page refresh
    262    this.filterInput.setAttribute("value", this.filterInput.value);
    263 
    264    // Don't start new filter search if same as last
    265    if (this.filterInput.value == this._filterPrevInput) {
    266      return;
    267    }
    268    this._filterPrevInput = this.filterInput.value;
    269 
    270    // Clear list item selection / context menu, prefs list, get first buffer, set scrolling on
    271    this.selected = "";
    272    this._clearPrefsContainer();
    273    this._addMorePrefsToContainer();
    274    window.onscroll = this.onScroll.bind(this);
    275 
    276    // Pause for screen to settle, then ensure at top
    277    setTimeout(() => {
    278      window.scrollTo(0, 0);
    279    }, INITIAL_PAGE_DELAY);
    280  },
    281 
    282  // Clear the displayed preferences list
    283  _clearPrefsContainer: function AC_clearPrefsContainer() {
    284    // Quick clear the prefsContainer list
    285    const empty = this._prefsContainer.cloneNode(false);
    286    this._prefsContainer.parentNode.replaceChild(empty, this._prefsContainer);
    287    this._prefsContainer = empty;
    288 
    289    // Quick clear the prefs li.HTML list
    290    this._list.forEach(function (item) {
    291      delete item.li;
    292    });
    293  },
    294 
    295  // Get a small manageable block of prefs items, and add them to the displayed list
    296  _addMorePrefsToContainer: function AC_addMorePrefsToContainer() {
    297    // Create filter regex
    298    const filterExp = this.filterInput.value
    299      ? new RegExp(this.filterInput.value, "i")
    300      : null;
    301 
    302    // Get a new block for the display list
    303    const prefsBuffer = [];
    304    for (
    305      let i = 0;
    306      i < this._list.length && prefsBuffer.length < PREFS_BUFFER_MAX;
    307      i++
    308    ) {
    309      if (!this._list[i].li && this._list[i].test(filterExp)) {
    310        prefsBuffer.push(this._list[i]);
    311      }
    312    }
    313 
    314    // Add the new block to the displayed list
    315    for (let i = 0; i < prefsBuffer.length; i++) {
    316      this._prefsContainer.appendChild(prefsBuffer[i].getOrCreateNewLINode());
    317    }
    318 
    319    // Determine if anything left to add later by scrolling
    320    let anotherPrefsBufferRemains = false;
    321    for (let i = 0; i < this._list.length; i++) {
    322      if (!this._list[i].li && this._list[i].test(filterExp)) {
    323        anotherPrefsBufferRemains = true;
    324        break;
    325      }
    326    }
    327 
    328    if (anotherPrefsBufferRemains) {
    329      // If still more could be displayed, show the throbber
    330      this._loadingContainer.style.display = "block";
    331    } else {
    332      // If no more could be displayed, hide the throbber, and stop noticing scroll events
    333      this._loadingContainer.style.display = "none";
    334      window.onscroll = null;
    335    }
    336  },
    337 
    338  // If scrolling at the bottom, maybe add some more entries
    339  onScroll: function AC_onScroll() {
    340    if (
    341      this._prefsContainer.scrollHeight -
    342        (window.pageYOffset + window.innerHeight) <
    343      PAGE_SCROLL_TRIGGER
    344    ) {
    345      if (!this._filterChangeTimer) {
    346        this._addMorePrefsToContainer();
    347      }
    348    }
    349  },
    350 
    351  // Return currently selected list item node
    352  get selected() {
    353    return document.querySelector(".pref-item.selected");
    354  },
    355 
    356  // Set list item node as selected
    357  set selected(aSelection) {
    358    const currentSelection = this.selected;
    359    if (aSelection == currentSelection) {
    360      return;
    361    }
    362 
    363    // Clear any previous selection
    364    if (currentSelection) {
    365      currentSelection.classList.remove("selected");
    366      currentSelection.removeEventListener("keypress", this.handleKeypress);
    367    }
    368 
    369    // Set any current selection
    370    if (aSelection) {
    371      aSelection.classList.add("selected");
    372      aSelection.addEventListener("keypress", this.handleKeypress);
    373    }
    374  },
    375 
    376  // Watch user key input so we can provide Enter key action, commit input values
    377  handleKeypress: function AC_handleKeypress(aEvent) {
    378    if (aEvent.keyCode == VKB_ENTER_KEY) {
    379      aEvent.target.blur();
    380    }
    381  },
    382 
    383  // Return the target list item node of an action event
    384  getLINodeForEvent: function AC_getLINodeForEvent(aEvent) {
    385    let node = aEvent.target;
    386    while (node && node.nodeName != "li") {
    387      node = node.parentNode;
    388    }
    389 
    390    return node;
    391  },
    392 
    393  // Return a pref of a list item node
    394  _getPrefForNode: function AC_getPrefForNode(aNode) {
    395    const pref = aNode.getAttribute("name");
    396 
    397    return new Pref(pref);
    398  },
    399 
    400  // When list item name or value are tapped
    401  selectOrToggleBoolPref: function AC_selectOrToggleBoolPref(aEvent) {
    402    const node = this.getLINodeForEvent(aEvent);
    403 
    404    // If not already selected, just do so
    405    if (this.selected != node) {
    406      this.selected = node;
    407      return;
    408    }
    409 
    410    // If already selected, and value is boolean, toggle it
    411    const pref = this._getPrefForNode(node);
    412    if (pref.type != Services.prefs.PREF_BOOL) {
    413      return;
    414    }
    415 
    416    this.toggleBoolPref(aEvent);
    417  },
    418 
    419  // When finalizing list input values due to blur
    420  setIntOrStringPref: function AC_setIntOrStringPref(aEvent) {
    421    const node = this.getLINodeForEvent(aEvent);
    422 
    423    // Skip if locked
    424    const pref = this._getPrefForNode(node);
    425    if (pref.locked) {
    426      return;
    427    }
    428 
    429    // Boolean inputs blur to remove focus from "button"
    430    if (pref.type == Services.prefs.PREF_BOOL) {
    431      return;
    432    }
    433 
    434    // String and Int inputs change / commit on blur
    435    pref.value = aEvent.target.value;
    436  },
    437 
    438  // When we reset a pref to it's default value (note resetting a user created pref will delete it)
    439  resetDefaultPref: function AC_resetDefaultPref(aEvent) {
    440    const node = this.getLINodeForEvent(aEvent);
    441 
    442    // If not already selected, do so
    443    if (this.selected != node) {
    444      this.selected = node;
    445    }
    446 
    447    // Reset will handle any locked condition
    448    const pref = this._getPrefForNode(node);
    449    pref.reset();
    450 
    451    // Ensure pref reset flushed to disk immediately
    452    Services.prefs.savePrefFile(null);
    453  },
    454 
    455  // When we want to toggle a bool pref
    456  toggleBoolPref: function AC_toggleBoolPref(aEvent) {
    457    const node = this.getLINodeForEvent(aEvent);
    458 
    459    // Skip if locked, or not boolean
    460    const pref = this._getPrefForNode(node);
    461    if (pref.locked) {
    462      return;
    463    }
    464 
    465    // Toggle, and blur to remove field focus
    466    pref.value = !pref.value;
    467    aEvent.target.blur();
    468  },
    469 
    470  // When Int inputs have their Up or Down arrows toggled
    471  incrOrDecrIntPref: function AC_incrOrDecrIntPref(aEvent, aInt) {
    472    const node = this.getLINodeForEvent(aEvent);
    473 
    474    // Skip if locked
    475    const pref = this._getPrefForNode(node);
    476    if (pref.locked) {
    477      return;
    478    }
    479 
    480    pref.value += aInt;
    481  },
    482 
    483  // Observe preference changes
    484  observe: function AC_observe(aSubject, aTopic, aPrefName) {
    485    const pref = new Pref(aPrefName);
    486 
    487    // Ignore uninteresting changes, and avoid "private" preferences
    488    if (aTopic != "nsPref:changed") {
    489      return;
    490    }
    491 
    492    // If pref type invalid, refresh display as user reset/removed an item from the list
    493    if (pref.type == Services.prefs.PREF_INVALID) {
    494      document.location.reload();
    495      return;
    496    }
    497 
    498    // If pref onscreen, update in place.
    499    const item = document.querySelector(
    500      '.pref-item[name="' + CSS.escape(pref.name) + '"]'
    501    );
    502    if (item) {
    503      item.setAttribute("value", pref.value);
    504      const input = item.querySelector("input");
    505      input.setAttribute("value", pref.value);
    506      input.value = pref.value;
    507 
    508      pref.default
    509        ? item.querySelector(".reset").setAttribute("disabled", "true")
    510        : item.querySelector(".reset").removeAttribute("disabled");
    511      return;
    512    }
    513 
    514    // If pref not already in list, refresh display as it's being added
    515    const anyWhere = this._list.filter(i => {
    516      return i.name == pref.name;
    517    });
    518    if (!anyWhere.length) {
    519      document.location.reload();
    520    }
    521  },
    522 
    523  // Quick context menu helpers for about:config
    524  clipboardCopy: function AC_clipboardCopy(aField) {
    525    const pref = this._getPrefForNode(this.contextMenuLINode);
    526    if (aField == "name") {
    527      gClipboardHelper.copyString(pref.name);
    528    } else {
    529      gClipboardHelper.copyString(pref.value);
    530    }
    531  },
    532 };
    533 
    534 /* ============================== Pref ==============================
    535 *
    536 * Individual Preference object / methods
    537 *
    538 * Defines a Pref object, a document list item tied to Preferences Services
    539 * And the methods by which they interact.
    540 *
    541 */
    542 function Pref(aName) {
    543  this.name = aName;
    544 }
    545 
    546 Pref.prototype = {
    547  get type() {
    548    return Services.prefs.getPrefType(this.name);
    549  },
    550 
    551  get value() {
    552    switch (this.type) {
    553      case Services.prefs.PREF_BOOL:
    554        return Services.prefs.getBoolPref(this.name);
    555      case Services.prefs.PREF_INT:
    556        return Services.prefs.getIntPref(this.name);
    557      case Services.prefs.PREF_STRING:
    558      default:
    559        return Services.prefs.getCharPref(this.name);
    560    }
    561  },
    562  set value(aPrefValue) {
    563    switch (this.type) {
    564      case Services.prefs.PREF_BOOL:
    565        Services.prefs.setBoolPref(this.name, aPrefValue);
    566        break;
    567      case Services.prefs.PREF_INT:
    568        Services.prefs.setIntPref(this.name, aPrefValue);
    569        break;
    570      case Services.prefs.PREF_STRING:
    571      default:
    572        Services.prefs.setCharPref(this.name, aPrefValue);
    573    }
    574 
    575    // Ensure pref change flushed to disk immediately
    576    Services.prefs.savePrefFile(null);
    577  },
    578 
    579  get default() {
    580    return !Services.prefs.prefHasUserValue(this.name);
    581  },
    582 
    583  get locked() {
    584    return Services.prefs.prefIsLocked(this.name);
    585  },
    586 
    587  reset: function AC_reset() {
    588    Services.prefs.clearUserPref(this.name);
    589  },
    590 
    591  test: function AC_test(aValue) {
    592    return aValue ? aValue.test(this.name) : true;
    593  },
    594 
    595  // Get existing or create new LI node for the pref
    596  getOrCreateNewLINode: function AC_getOrCreateNewLINode() {
    597    if (!this.li) {
    598      this.li = document.createElement("li");
    599 
    600      this.li.className = "pref-item";
    601      this.li.setAttribute("name", this.name);
    602 
    603      // Click callback to ensure list item selected even on no-action tap events
    604      this.li.addEventListener("click", function (aEvent) {
    605        AboutConfig.selected = AboutConfig.getLINodeForEvent(aEvent);
    606      });
    607 
    608      // Contextmenu callback to identify selected list item
    609      this.li.addEventListener("contextmenu", function (aEvent) {
    610        AboutConfig.contextMenuLINode = AboutConfig.getLINodeForEvent(aEvent);
    611      });
    612 
    613      this.li.setAttribute("contextmenu", "prefs-context-menu");
    614 
    615      const prefName = document.createElement("div");
    616      prefName.className = "pref-name";
    617      prefName.addEventListener("click", function (event) {
    618        AboutConfig.selectOrToggleBoolPref(event);
    619      });
    620      prefName.textContent = this.name;
    621 
    622      this.li.appendChild(prefName);
    623 
    624      const prefItemLine = document.createElement("div");
    625      prefItemLine.className = "pref-item-line";
    626 
    627      const prefValue = document.createElement("input");
    628      prefValue.className = "pref-value";
    629      prefValue.addEventListener("blur", function (event) {
    630        AboutConfig.setIntOrStringPref(event);
    631      });
    632      prefValue.addEventListener("click", function (event) {
    633        AboutConfig.selectOrToggleBoolPref(event);
    634      });
    635      prefValue.value = "";
    636      prefItemLine.appendChild(prefValue);
    637 
    638      const resetButton = document.createElement("div");
    639      resetButton.className = "pref-button reset";
    640      resetButton.addEventListener("click", function (event) {
    641        AboutConfig.resetDefaultPref(event);
    642      });
    643      resetButton.setAttribute("data-l10n-id", "config-pref-reset-button");
    644      prefItemLine.appendChild(resetButton);
    645 
    646      const toggleButton = document.createElement("div");
    647      toggleButton.className = "pref-button toggle";
    648      toggleButton.addEventListener("click", function (event) {
    649        AboutConfig.toggleBoolPref(event);
    650      });
    651      toggleButton.setAttribute("data-l10n-id", "config-pref-toggle-button");
    652      prefItemLine.appendChild(toggleButton);
    653 
    654      const upButton = document.createElement("div");
    655      upButton.className = "pref-button up";
    656      upButton.addEventListener("click", function (event) {
    657        AboutConfig.incrOrDecrIntPref(event, 1);
    658      });
    659      prefItemLine.appendChild(upButton);
    660 
    661      const downButton = document.createElement("div");
    662      downButton.className = "pref-button down";
    663      downButton.addEventListener("click", function (event) {
    664        AboutConfig.incrOrDecrIntPref(event, -1);
    665      });
    666      prefItemLine.appendChild(downButton);
    667 
    668      this.li.appendChild(prefItemLine);
    669 
    670      // Delay providing the list item values, until the LI is returned and added to the document
    671      setTimeout(this._valueSetup.bind(this), INNERHTML_VALUE_DELAY);
    672    }
    673 
    674    return this.li;
    675  },
    676 
    677  // Initialize list item object values
    678  _valueSetup: function AC_valueSetup() {
    679    this.li.setAttribute("type", this.type);
    680    this.li.setAttribute("value", this.value);
    681 
    682    const valDiv = this.li.querySelector(".pref-value");
    683    valDiv.value = this.value;
    684 
    685    switch (this.type) {
    686      case Services.prefs.PREF_BOOL:
    687        valDiv.setAttribute("type", "button");
    688        this.li.querySelector(".up").setAttribute("disabled", true);
    689        this.li.querySelector(".down").setAttribute("disabled", true);
    690        break;
    691      case Services.prefs.PREF_STRING:
    692        valDiv.setAttribute("type", "text");
    693        this.li.querySelector(".up").setAttribute("disabled", true);
    694        this.li.querySelector(".down").setAttribute("disabled", true);
    695        this.li.querySelector(".toggle").setAttribute("disabled", true);
    696        break;
    697      case Services.prefs.PREF_INT:
    698        valDiv.setAttribute("type", "number");
    699        this.li.querySelector(".toggle").setAttribute("disabled", true);
    700        break;
    701    }
    702 
    703    this.li.setAttribute("default", this.default);
    704    if (this.default) {
    705      this.li.querySelector(".reset").setAttribute("disabled", true);
    706    }
    707 
    708    if (this.locked) {
    709      valDiv.setAttribute("disabled", this.locked);
    710      this.li.querySelector(".pref-name").setAttribute("locked", true);
    711    }
    712  },
    713 };