Bug 1544573 - fix about:support copy/paste implementation to correctly ignore no-copy elements, r=dthayer
authorGijs Kruitbosch <gijskruitbosch@gmail.com>
Tue, 16 Apr 2019 20:33:01 +0000
changeset 469727 d0943c0f7615
parent 469726 75957624201b
child 469728 3ff550948499
push id35880
push usercbrindusan@mozilla.com
push dateWed, 17 Apr 2019 09:36:19 +0000
treeherdermozilla-central@79e6ed0b08d6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdthayer
bugs1544573
milestone68.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 1544573 - fix about:support copy/paste implementation to correctly ignore no-copy elements, r=dthayer Differential Revision: https://phabricator.services.mozilla.com/D27808
toolkit/content/aboutSupport.js
--- a/toolkit/content/aboutSupport.js
+++ b/toolkit/content/aboutSupport.js
@@ -151,17 +151,16 @@ var snapshotFormatters = {
         reportURL = null;
     } catch (e) { }
     if (!reportURL) {
       $("crashes-noConfig").style.display = "block";
       $("crashes-noConfig").classList.remove("no-copy");
       return;
     }
     $("crashes-allReports").style.display = "block";
-    $("crashes-allReports").classList.remove("no-copy");
 
     if (data.pending > 0) {
       document.l10n.setAttributes($("crashes-allReportsWithPending"), "pending-reports", { reports: data.pending });
     }
 
     let dateNow = new Date();
     $.append($("crashes-tbody"), data.submitted.map(function(crash) {
       let date = new Date(crash.date);
@@ -961,17 +960,19 @@ function copyRawDataToClipboard(button) 
 }
 
 function getLoadContext() {
   return window.docShell.QueryInterface(Ci.nsILoadContext);
 }
 
 async function copyContentsToClipboard() {
   // Get the HTML and text representations for the important part of the page.
-  let contentsDiv = $("contents");
+  let contentsDiv = $("contents").cloneNode(true);
+  // Remove the items we don't want to copy from the clone:
+  contentsDiv.querySelectorAll(".no-copy, [hidden]").forEach(n => n.remove());
   let dataHtml = contentsDiv.innerHTML;
   let dataText = createTextForElement(contentsDiv);
 
   // We can't use plain strings, we have to use nsSupportsString.
   let supportsStringClass = Cc["@mozilla.org/supports-string;1"];
   let ssHtml = supportsStringClass.createInstance(Ci.nsISupportsString);
   let ssText = supportsStringClass.createInstance(Ci.nsISupportsString);
 
@@ -1034,19 +1035,16 @@ Serializer.prototype = {
     return this._lines.length ? this._lines[this._lines.length - 1] : null;
   },
 
   set _currentLine(val) {
     return this._lines[this._lines.length - 1] = val;
   },
 
   _serializeElement(elem) {
-    if (this._ignoreElement(elem))
-      return;
-
     // table
     if (elem.localName == "table") {
       this._serializeTable(elem);
       return;
     }
 
     // all other elements
 
@@ -1057,31 +1055,29 @@ Serializer.prototype = {
         this._appendText(text);
         hasText = hasText || !!text.trim();
       } else if (child.nodeType == Node.ELEMENT_NODE) {
         this._serializeElement(child);
       }
     }
 
     // For headings, draw a "line" underneath them so they stand out.
-    if (/^h[0-9]+$/.test(elem.localName)) {
+    let isHeader = /^h[0-9]+$/.test(elem.localName);
+    if (isHeader) {
       let headerText = (this._currentLine || "").trim();
       if (headerText) {
         this._startNewLine();
         this._appendText("-".repeat(headerText.length));
       }
     }
 
-    // Add a blank line underneath block elements but only if they contain text.
-    if (hasText) {
-      let display = window.getComputedStyle(elem).getPropertyValue("display");
-      if (display == "block") {
-        this._startNewLine();
-        this._startNewLine();
-      }
+    // Add a blank line underneath elements but only if they contain text.
+    if (hasText && (isHeader || "p" == elem.localName)) {
+      this._startNewLine();
+      this._startNewLine();
     }
   },
 
   _startNewLine(lines) {
     let currLine = this._currentLine;
     if (currLine) {
       // The current line is not empty.  Trim it.
       this._currentLine = currLine.trim();
@@ -1125,23 +1121,21 @@ Serializer.prototype = {
     let trs = table.querySelectorAll("table > tr, tbody > tr");
     let startRow =
       tableHeadingElem && tableHeadingElem.localName == "tr" ? 1 : 0;
 
     if (startRow >= trs.length)
       // The table's empty.
       return;
 
-    if (hasColHeadings && !this._ignoreElement(tableHeadingElem)) {
+    if (hasColHeadings) {
       // Use column headings.  Print each tr as a multi-line chunk like:
       //   Heading 1: Column 1 value
       //   Heading 2: Column 2 value
       for (let i = startRow; i < trs.length; i++) {
-        if (this._ignoreElement(trs[i]))
-          continue;
         let children = trs[i].querySelectorAll("td");
         for (let j = 0; j < children.length; j++) {
           let text = "";
           if (colHeadings[j])
             text += colHeadings[j] + ": ";
           text += this._nodeText(children[j]).trim();
           this._appendText(text);
           this._startNewLine();
@@ -1150,18 +1144,16 @@ Serializer.prototype = {
       }
       return;
     }
 
     // Don't use column headings.  Assume the table has only two columns and
     // print each tr in a single line like:
     //   Column 1 value: Column 2 value
     for (let i = startRow; i < trs.length; i++) {
-      if (this._ignoreElement(trs[i]))
-        continue;
       let children = trs[i].querySelectorAll("th,td");
       let rowHeading = this._nodeText(children[0]).trim();
       if (children[0].classList.contains("title-column")) {
         if (!this._isHiddenSubHeading(children[0]))
           this._appendText(rowHeading);
       } else if (children.length == 1) {
         // This is a single-cell row.
         this._appendText(rowHeading);
@@ -1175,20 +1167,16 @@ Serializer.prototype = {
           this._appendText(rowHeading + ": " + this._nodeText(children[1]).trim());
         }
       }
       this._startNewLine();
     }
     this._startNewLine();
   },
 
-  _ignoreElement(elem) {
-    return elem.classList.contains("no-copy");
-  },
-
   _nodeText(node) {
     return node.textContent.replace(/\s+/g, " ");
   },
 };
 
 function openProfileDirectory() {
   // Get the profile directory.
   let currProfD = Services.dirsvc.get("ProfD", Ci.nsIFile);