Bug 1370513 - Fix Subsection displayed in the sidebar r?chutten draft
authorflyingrub <flyinggrub@gmail.com>
Fri, 16 Jun 2017 14:04:50 +0200
changeset 599762 6fb8a6ee6a6d4eef3c8590562b84e338499ac74a
parent 599051 6789f6766955498fe6ceb0fbf439c21f1220732b
child 634842 f6ce778f5c78e3929398513e315fc6e8547b662e
push id65594
push userbmo:flyinggrub@gmail.com
push dateFri, 23 Jun 2017 15:06:18 +0000
reviewerschutten
bugs1370513
milestone56.0a1
Bug 1370513 - Fix Subsection displayed in the sidebar r?chutten Allow to display subsection in the sidebar. The user can now select only one subsection to be displayed. Also remove unused strings. MozReview-Commit-ID: HGFyssfZhfE
toolkit/content/aboutTelemetry.css
toolkit/content/aboutTelemetry.js
toolkit/content/aboutTelemetry.xhtml
toolkit/locales/en-US/chrome/global/aboutTelemetry.dtd
toolkit/locales/en-US/chrome/global/aboutTelemetry.properties
--- a/toolkit/content/aboutTelemetry.css
+++ b/toolkit/content/aboutTelemetry.css
@@ -25,30 +25,72 @@ body {
   box-sizing: border-box;
   background-color: inherit;
   min-width: inherit;
   position: absolute;
   bottom: 0;
   left: 0;
 }
 
+#category-raw.selected {
+   background-color: var(--in-content-category-background-active);
+}
+
 .heading {
-  padding-inline-start: 21px;
+  padding-inline-start: 15px;
   padding-inline-end: 21px;
   color: var(--in-content-category-text);
 }
 
 .category:not(.has-data) {
   display: none;
 }
 
 .category {
   cursor: pointer;
   display: flex;
-  align-items: center;
+  flex-direction: column;
+  min-height: 42px;
+}
+
+.category-name {
+  padding: 9px 0px;
+  vertical-align: middle;
+}
+
+.category.has-subsection {
+  padding-inline-start: 0px;
+}
+
+.category.has-subsection > span {
+  padding-inline-start: 11px;
+}
+
+.category.has-subsection.selected {
+  border-inline-start: none;
+}
+
+.category-subsection {
+  padding: 9px 0px;
+  padding-inline-start: 30px;
+  display: none;
+  -moz-user-select: none;
+}
+
+.category-subsection::first-letter {
+  text-transform: uppercase;
+}
+
+.category.selected > .category-subsection {
+  display: block;
+}
+
+.category-subsection.selected {
+  padding-inline-start: 26px;
+  border-inline-start: solid 4px var(--in-content-border-highlight);
 }
 
 .category-name {
   pointer-events: none;
 }
 
 .main-content {
   width: 100%;
@@ -109,37 +151,16 @@ body {
   font-size: x-large;
   display: inline;
 }
 
 .has-data .section-name {
   cursor: pointer;
 }
 
-
-.toggle-caption {
-  font-style: italic;
-  cursor: pointer;
-}
-
-.data-section:not(.has-data) .toggle-caption,
-.data-subsection:not(.has-subdata) .toggle-caption {
-  display: none;
-}
-
-
-.empty-caption {
-  font-style: italic;
-}
-
-.has-data .empty-caption,
-.has-subdata .empty-caption {
-  display: none; /* invisible when has-data */
-}
-
 .data,
 .subdata {
   margin: 15px;
   display: none;
 }
 
 .has-data.expanded .data,
 .has-subdata.expanded .subdata {
@@ -282,17 +303,16 @@ body[dir="rtl"] .copy-node {
 #hide-raw-ping {
   float: right;
   cursor: pointer;
   font-size: 20px;
   background-color:#d8d8d8;
   padding: 5px 10px;
 }
 
-/* addon subsection style */
-.addon-caption {
+caption {
   font-size: larger;
   margin: 5px 0;
 }
 
 .process-picker {
   margin: 0 0.5em;
 }
\ No newline at end of file
--- a/toolkit/content/aboutTelemetry.js
+++ b/toolkit/content/aboutTelemetry.js
@@ -241,17 +241,17 @@ var Settings = {
   detachObservers() {
     for (let setting of this.SETTINGS) {
       Preferences.ignore(setting.pref, this.render, this);
     }
   },
 
   getStatusStringForSetting(setting) {
     let enabled = Preferences.get(setting.pref, setting.defaultPrefValue);
-    let status = bundle.GetStringFromName(enabled ? "enabled" : "disabled");
+    let status = bundle.GetStringFromName(enabled ? "telemetryEnabled" : "telemetryDisabled");
     return status;
   },
 
   /**
    * Updates the button & text at the top of the page to reflect Telemetry state.
    */
   render() {
     let homeExplanation = document.getElementById("home-explanation");
@@ -318,24 +318,24 @@ var PingPicker = {
     this.update();
   },
 
   onPingDisplayChanged() {
     this.update();
   },
 
   render() {
-    let pings = bundle.GetStringFromName("pings");
+    let pings = bundle.GetStringFromName("pingExplanationLink");
     let pingLink = "<a href=\"http://gecko.readthedocs.io/en/latest/toolkit/components/telemetry/telemetry/concepts/pings.html\">&quot;" + pings + "&quot;</a>";
     let pingName = "<span class=\"change-ping\">" + this._getSelectedPingName() + "</span>";
 
     let explanation = bundle.formatStringFromName("pingExplanation", [pingLink, pingName], 2);
     let pingExplanation = document.getElementById("ping-explanation");
     pingExplanation.innerHTML = explanation;
-    this.attachObservers();
+    GenericSubsection.deleteAllSubSections();
   },
 
   async update() {
     let viewCurrent = document.getElementById("ping-source-current").checked;
     let currentChanged = viewCurrent !== this.viewCurrentPingData;
     this.viewCurrentPingData = viewCurrent;
 
     // If we have no archived pings, disable the ping archive selection.
@@ -350,17 +350,16 @@ var PingPicker = {
         document.getElementById("archived-ping-picker").hidden = true;
         this._updateCurrentPingData();
       } else {
         document.getElementById("current-ping-picker").hidden = true;
         await this._updateArchivedPingList(archivedPingList);
         document.getElementById("archived-ping-picker").hidden = false;
       }
     }
-    this.render();
   },
 
   _updateCurrentPingData() {
     const subsession = document.getElementById("show-subsession-data").checked;
     const ping = TelemetryController.getCurrentPingData(subsession);
     if (!ping) {
       return;
     }
@@ -914,18 +913,18 @@ var StackRenderer = {
   }
 };
 
 var RawPayload = {
   /**
    * Renders the raw payload
    */
   render(aPing) {
-    setHasData("raw-payload-section", true);
-    let pre = document.getElementById("raw-payload-data-pre");
+    setHasData("raw-ping-data-section", true);
+    let pre = document.getElementById("raw-ping-data");
     pre.textContent = JSON.stringify(aPing.payload, null, 2);
   }
 };
 
 function SymbolicationRequest(aPrefix, aRenderHeader,
                               aMemoryMap, aStacks, aDurations = null) {
   this.prefix = aPrefix;
   this.renderHeader = aRenderHeader;
@@ -1378,52 +1377,69 @@ function RenderObject(aObject) {
   }
   return output + "}";
 }
 
 var GenericSubsection = {
 
   addSubSectionToSidebar(id, title) {
     let category = document.querySelector("#categories > [value=" + id + "]");
+    category.classList.add("has-subsection");
     let subCategory = document.createElement("div");
-    subCategory.setAttribute("class", "subsection");
+    subCategory.classList.add("category-subsection");
+    subCategory.setAttribute("value", id + "-" + title);
+    subCategory.addEventListener("click", (ev) => {
+      let section = ev.target;
+      showSubSection(section);
+    });
     subCategory.appendChild(document.createTextNode(title))
     category.appendChild(subCategory);
   },
 
   render(data, dataDiv, sectionID) {
     for (let [title, sectionData] of data) {
       let hasData = sectionData.size > 0;
       let s = this.renderSubsectionHeader(title, hasData, sectionID);
-      s.appendChild(this.renderSubsectionData(sectionData));
+      s.appendChild(this.renderSubsectionData(title, sectionData));
       dataDiv.appendChild(s);
     }
   },
 
   renderSubsectionHeader(title, hasData, sectionID) {
     this.addSubSectionToSidebar(sectionID, title);
     let section = document.createElement("section");
-    section.classList.add("data-subsection");
+    section.setAttribute("id", sectionID + "-" + title);
+    section.classList.add("data-subsection", "expanded");
     if (hasData) {
       section.classList.add("has-subdata");
     }
     return section;
   },
 
-  renderSubsectionData(data) {
+  renderSubsectionData(title, data) {
     // Create data container
     let dataDiv = document.createElement("div");
     dataDiv.setAttribute("class", "subsection-data subdata");
     // Instanciate the data
     let table = GenericTable.render(data);
+    let caption = document.createElement("caption");
+    caption.textContent = title;
+    table.appendChild(caption);
     dataDiv.appendChild(table);
 
     return dataDiv;
   },
 
+  deleteAllSubSections() {
+    let subsections = document.querySelectorAll(".category-subsection");
+    subsections.forEach((el) => {
+      el.parentElement.removeChild(el);
+    })
+  },
+
 }
 
 var GenericTable = {
 
   defaultHeadings: [
     bundle.GetStringFromName("keysHeader"),
     bundle.GetStringFromName("valuesHeader")
   ],
@@ -1710,29 +1726,50 @@ function setupPageHeader() {
   let subtitleElement = document.getElementById("page-subtitle");
   subtitleElement.appendChild(document.createTextNode(subtitleText));
 }
 
 /**
  * Change the section displayed
  */
 function show(selected) {
-    let current_section = document.querySelector(".active");
-    let selected_section = document.getElementById(selected.getAttribute("value"));
-    if (current_section == selected_section)
-      return;
-    current_section.classList.remove("active");
-    current_section.hidden = true;
-    selected_section.classList.add("active");
-    selected_section.hidden = false;
+  let current_button = document.querySelector(".category.selected");
+  current_button.classList.remove("selected");
+  selected.classList.add("selected");
+  // Hack because subsection text appear selected. See Bug 1375114.
+  document.getSelection().empty();
+
+  let current_section = document.querySelector(".active");
+  let selected_section = document.getElementById(selected.getAttribute("value"));
+  if (current_section == selected_section)
+    return;
+  current_section.classList.remove("active");
+  current_section.hidden = true;
+  selected_section.classList.add("active");
+  selected_section.hidden = false;
 
-    let current_button = document.querySelector("[selected=true]");
-    current_button.removeAttribute("selected");
-    selected.setAttribute("selected", "true");
-    document.getElementById("sectionTitle").textContent = selected.textContent;
+  let title = selected.querySelector(".category-name").textContent;
+  document.getElementById("sectionTitle").textContent = title;
+}
+
+function showSubSection(selected) {
+  let current_selection = document.querySelector(".category-subsection.selected");
+  if (current_selection)
+    current_selection.classList.remove("selected");
+  selected.classList.add("selected");
+
+  let section = document.getElementById(selected.getAttribute("value"));
+  section.parentElement.childNodes.forEach((element) => {
+    element.classList.remove("expanded");
+  }, this);
+  section.classList.add("expanded");
+
+  let title = selected.parentElement.querySelector(".category-name").textContent;
+  document.getElementById("sectionTitle").textContent = title + " - " + selected.textContent;
+  document.getSelection().empty(); // prevent subsection text selection
 }
 
 /**
  * Initializes load/unload, pref change and mouse-click listeners
  */
 function setupListeners() {
   Settings.attachObservers();
   PingPicker.attachObservers();
@@ -2098,40 +2135,39 @@ function renderPayloadList(ping) {
     option.appendChild(content);
     option.setAttribute("value", payloadIndex);
     listEl.appendChild(option);
   }
 }
 
 function togglePingSections(isMainPing) {
   // We always show the sections that are "common" to all pings.
-  // The raw payload section is only used for pings other than "main" and "saved-session".
-  let commonSections = new Set(["general-data-section", "environment-data-section"]);
-  let otherPingSections = new Set(["raw-payload-section"]);
+  let commonSections = new Set(["heading",
+                                "home",
+                                "general-data-section",
+                                "environment-data-section",
+                                "raw-ping-data-section"]);
 
-  let elements = document.getElementById("categories").children;
+  let elements = document.querySelectorAll(".category");
   for (let section of elements) {
-    if (commonSections.has(section.id)) {
+    if (commonSections.has(section.getAttribute("value"))) {
       continue;
     }
-
-    let showElement = isMainPing != otherPingSections.has(section.id);
-    section.hidden = !showElement;
+    section.classList.toggle("has-data", isMainPing);
   }
 }
 
 function displayPingData(ping, updatePayloadList = false) {
   gPingData = ping;
 
   // Render raw ping data.
-  let pre = document.getElementById("raw-ping-data");
-  pre.textContent = JSON.stringify(gPingData, null, 2);
-
+  RawPayload.render(ping);
 
   try {
+    PingPicker.render();
     displayRichPingData(ping, updatePayloadList);
   } catch (err) {
     console.log(err);
     PingPicker._showRawPingData();
   }
 }
 
 function displayRichPingData(ping, updatePayloadList) {
@@ -2152,17 +2188,16 @@ function displayRichPingData(ping, updat
   EnvironmentData.render(ping);
 
   // We only have special rendering code for the payloads from "main" pings.
   // For any other pings we just render the raw JSON payload.
   let isMainPing = (ping.type == "main" || ping.type == "saved-session");
   togglePingSections(isMainPing);
 
   if (!isMainPing) {
-    RawPayload.render(ping);
     return;
   }
 
   // Show telemetry log.
   TelLog.render(ping);
 
   // Show slow SQL stats
   SlowSQL.render(ping);
--- a/toolkit/content/aboutTelemetry.xhtml
+++ b/toolkit/content/aboutTelemetry.xhtml
@@ -23,17 +23,17 @@
   </head>
 
   <body id="body" dir="&locale.dir;">
 
     <div id="categories">
       <div class="heading">
         <h3>&aboutTelemetry.pageTitle;</h3>
       </div>
-      <div id="category-home" class="category has-data" selected="true" value="home">
+      <div id="category-home" class="category has-data selected" value="home">
         <span class="category-name">Home</span>
       </div>
       <div class="category" value="general-data-section">
         <span class="category-name">&aboutTelemetry.generalDataSection;</span>
       </div>
       <div class="category" value="environment-data-section">
         <span class="category-name">&aboutTelemetry.environmentDataSection;</span>
       </div>
--- a/toolkit/locales/en-US/chrome/global/aboutTelemetry.dtd
+++ b/toolkit/locales/en-US/chrome/global/aboutTelemetry.dtd
@@ -1,38 +1,26 @@
 <!-- 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/. -->
 
 <!ENTITY aboutTelemetry.pageTitle "Telemetry Data">
 
-<!ENTITY aboutTelemetry.changeDataChoices "
-  Change
-">
-
 <!ENTITY aboutTelemetry.pingDataSource "
 Ping data source:
 ">
 
 <!ENTITY aboutTelemetry.showCurrentPingData "
 Current ping data
 ">
 
 <!ENTITY aboutTelemetry.showArchivedPingData "
 Archived ping data
 ">
 
-<!ENTITY aboutTelemetry.pingDataDisplay "
-Ping data display:
-">
-
-<!ENTITY aboutTelemetry.structured "
-Structured
-">
-
 <!ENTITY aboutTelemetry.raw "
 Raw JSON
 ">
 
 <!ENTITY aboutTelemetry.showSubsessionData "
 Show subsession data
 ">
 
@@ -43,20 +31,16 @@ Choose ping:
 <!ENTITY aboutTelemetry.showNewerPing "
 &lt;&lt; Newer ping
 ">
 
 <!ENTITY aboutTelemetry.showOlderPing "
 Older ping &gt;&gt;
 ">
 
-<!ENTITY aboutTelemetry.rawPingData "
-Raw ping data…
-">
-
 <!ENTITY aboutTelemetry.archiveWeekHeader "
 Week
 ">
 
 <!ENTITY aboutTelemetry.archivePingHeader "
 Ping
 ">
 
@@ -123,24 +107,16 @@ Ping
 <!ENTITY aboutTelemetry.sessionInfoSection "
   Session Information
 ">
 
 <!ENTITY aboutTelemetry.addonHistogramsSection "
   Histograms Collected by Add-ons
 ">
 
-<!ENTITY aboutTelemetry.toggle "
-  Click to toggle section
-">
-
-<!ENTITY aboutTelemetry.emptySection "
-  (No data collected)
-">
-
 <!ENTITY aboutTelemetry.fullSqlWarning "
   NOTE: Slow SQL debugging is enabled. Full SQL strings may be displayed below but they will not be submitted to Telemetry.
 ">
 
 <!ENTITY aboutTelemetry.fetchStackSymbols "
   Fetch function names for stacks
 ">
 
@@ -150,12 +126,8 @@ Ping
 
 <!ENTITY aboutTelemetry.filterText "
   Filter (strings or /regexp/)
 ">
 
 <!ENTITY aboutTelemetry.payloadChoiceHeader "
   Payload
 ">
-
-<!ENTITY aboutTelemetry.rawPayload "
-  Raw Payload
-">
--- a/toolkit/locales/en-US/chrome/global/aboutTelemetry.properties
+++ b/toolkit/locales/en-US/chrome/global/aboutTelemetry.properties
@@ -3,36 +3,30 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 # Note to translators:
 # - %1$S will be replaced by brandFullName
 # - %2$S will be replaced with the value of the toolkit.telemetry.server_owner preference
 pageSubtitle = This page shows the information about performance, hardware, usage and customizations collected by Telemetry. This information is submitted to %1$S to help improve %2$S.
 
 # Note to translators:
-# - %1$S will be replaced by either enabled or disabled
-# - %2$S will be replaced by either enabled or disabled
+# - %1$S will be replaced by either telemetryEnabled or telemetryDisabled
+# - %2$S will be replaced by either telemetryEnabled or telemetryDisabled
 homeExplanation = Telemetry is %1$S and extended telemetry is %2$S.
 
 # Note to translators:
-# - %1$S will be replaced by a link with "pings" as text
+# - %1$S will be replaced by a link with pingExplanationLink
 # - %2$S will be replaced by the ping name
 pingExplanation = Each piece of information is sent bundled into %1$S. You are looking at the %2$S ping.
 
-pings = pings
-
-enabled = enabled
-
-disabled = disabled
+pingExplanationLink = pings
 
-generalDataTitle = General Data
+telemetryEnabled = enabled
 
-environmentDataSubsectionToggle = Click to toggle section
-
-environmentDataSubsectionEmpty = (No data collected)
+telemetryDisabled = disabled
 
 telemetryLogTitle = Telemetry Log
 
 telemetryLogHeadingId = Id
 
 telemetryLogHeadingTimestamp = Timestamp
 
 telemetryLogHeadingData = Data