Bug 1522168 - Part 1 - Lazify the creation of table row elements. r=mconley
authorPaolo Amadini <paolo.mozmail@amadzone.org>
Thu, 24 Jan 2019 18:33:57 +0000
changeset 515345 aa0e9d1e6bd25a60710d5cb13732cd87fdda4f2c
parent 515344 f6659c725cba4ea07980ddc67019792d04df69bf
child 515346 efd1576b3550da5015ce229c7bf927908bf0b632
push id1953
push userffxbld-merge
push dateMon, 11 Mar 2019 12:10:20 +0000
treeherdermozilla-release@9c35dcbaa899 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmconley
bugs1522168
milestone66.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1522168 - Part 1 - Lazify the creation of table row elements. r=mconley Differential Revision: https://phabricator.services.mozilla.com/D17504
browser/components/aboutconfig/content/aboutconfig.js
--- a/browser/components/aboutconfig/content/aboutconfig.js
+++ b/browser/components/aboutconfig/content/aboutconfig.js
@@ -33,22 +33,18 @@ let gPrefInEdit = null;
  * Lowercase substring that should be contained in the preference name.
  */
 let gFilterString = null;
 
 class PrefRow {
   constructor(name) {
     this.name = name;
     this.value = true;
+    this.editing = false;
     this.refreshValue();
-
-    this.editing = false;
-    this.element = document.createElement("tr");
-    this._setupElement();
-    gElementToPrefMap.set(this.element, this);
   }
 
   refreshValue() {
     this.hasDefaultValue = prefHasDefaultValue(this.name);
     this.hasUserValue = Services.prefs.prefHasUserValue(this.name);
     this.isLocked = Services.prefs.prefIsLocked(this.name);
 
     // If this preference has been deleted, we keep its last known value.
@@ -83,20 +79,30 @@ class PrefRow {
   get exists() {
     return this.hasDefaultValue || this.hasUserValue;
   }
 
   get matchesFilter() {
     return !gFilterString || this.name.toLowerCase().includes(gFilterString);
   }
 
-  _setupElement() {
-    this.element.textContent = "";
+  /**
+   * Returns a reference to the table row element to be added to the document,
+   * constructing and initializing it the first time this method is called.
+   */
+  getElement() {
+    if (this._element) {
+      return this._element;
+    }
+
+    this._element = document.createElement("tr");
+    gElementToPrefMap.set(this._element, this);
+
     let nameCell = document.createElement("th");
-    this.element.append(
+    this._element.append(
       nameCell,
       this.valueCell = document.createElement("td"),
       this.editCell = document.createElement("td"),
       this.resetCell = document.createElement("td")
     );
     this.editCell.appendChild(
       this.editButton = document.createElement("button")
     );
@@ -109,22 +115,29 @@ class PrefRow {
     // Add <wbr> behind dots to prevent line breaking in random mid-word places.
     let parts = this.name.split(".");
     for (let i = 0; i < parts.length - 1; i++) {
       nameCell.append(parts[i] + ".", document.createElement("wbr"));
     }
     nameCell.append(parts[parts.length - 1]);
 
     this.refreshElement();
+
+    return this._element;
   }
 
   refreshElement() {
-    this.element.classList.toggle("has-user-value", !!this.hasUserValue);
-    this.element.classList.toggle("locked", !!this.isLocked);
-    this.element.classList.toggle("deleted", !this.exists);
+    if (!this._element) {
+      // No need to update if this preference was never added to the table.
+      return;
+    }
+
+    this._element.classList.toggle("has-user-value", !!this.hasUserValue);
+    this._element.classList.toggle("locked", !!this.isLocked);
+    this._element.classList.toggle("deleted", !this.exists);
     if (this.exists && !this.editing) {
       // We need to place the text inside a "span" element to ensure that the
       // text copied to the clipboard includes all whitespace.
       let span = document.createElement("span");
       span.textContent = this.value;
       // We additionally need to wrap this with another "span" element to convey
       // the state to screen readers without affecting the visual presentation.
       span.setAttribute("aria-hidden", "true");
@@ -262,17 +275,17 @@ let gPrefObserver = {
       if (!pref.editing) {
         pref.refreshElement();
       }
       return;
     }
 
     let newPref = new PrefRow(data);
     if (newPref.matchesFilter) {
-      document.getElementById("prefs").appendChild(newPref.element);
+      document.getElementById("prefs").appendChild(newPref.getElement());
     }
   },
 };
 
 if (!Preferences.get("browser.aboutConfig.showWarning")) {
   // When showing the filtered preferences directly, remove the warning elements
   // immediately to prevent flickering, but wait to filter the preferences until
   // the value of the textbox has been restored from previous sessions.
@@ -369,17 +382,17 @@ function filterPrefs() {
   if (searchName && !gExistingPrefs.has(searchName)) {
     prefArray.push(new PrefRow(searchName));
   }
 
   let prefsElement = document.getElementById("prefs");
   prefsElement.textContent = "";
   let fragment = document.createDocumentFragment();
   for (let pref of prefArray) {
-    fragment.appendChild(pref.element);
+    fragment.appendChild(pref.getElement());
   }
   prefsElement.appendChild(fragment);
 
   // We only start observing preference changes after the first search is done,
   // so that newly added preferences won't appear while the page is still empty.
   if (!gPrefObserverRegistered) {
     gPrefObserverRegistered = true;
     Services.prefs.addObserver("", gPrefObserver);