Richard Pospesel pushed to branch tor-browser-102.6.0esr-12.0-1 at The Tor Project / Applications / Tor Browser

Commits:

4 changed files:

Changes:

  • browser/actors/AboutTBUpdateParent.jsm
    ... ... @@ -8,7 +8,6 @@
    8 8
     this.EXPORTED_SYMBOLS = ["AboutTBUpdateParent"];
    
    9 9
     
    
    10 10
     const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
    
    11
    -const { NetUtil } = ChromeUtils.import("resource://gre/modules/NetUtil.jsm");
    
    12 11
     const { AppConstants } = ChromeUtils.import(
    
    13 12
       "resource://gre/modules/AppConstants.jsm"
    
    14 13
     );
    
    ... ... @@ -22,9 +21,9 @@ const kRequestUpdateMessageName = "FetchUpdateData";
    22 21
      * implementation.
    
    23 22
      */
    
    24 23
     class AboutTBUpdateParent extends JSWindowActorParent {
    
    25
    -  receiveMessage(aMessage) {
    
    24
    +  async receiveMessage(aMessage) {
    
    26 25
         if (aMessage.name == kRequestUpdateMessageName) {
    
    27
    -      return this.releaseNoteInfo;
    
    26
    +      return this.getReleaseNoteInfo();
    
    28 27
         }
    
    29 28
         return undefined;
    
    30 29
       }
    
    ... ... @@ -51,7 +50,7 @@ class AboutTBUpdateParent extends JSWindowActorParent {
    51 50
       // On Mac OS, when building with --enable-tor-browser-data-outside-app-dir
    
    52 51
       // to support Gatekeeper signing, the ChangeLog.txt file is located in
    
    53 52
       // TorBrowser.app/Contents/Resources/TorBrowser/Docs/.
    
    54
    -  get releaseNoteInfo() {
    
    53
    +  async getReleaseNoteInfo() {
    
    55 54
         let info = { moreInfoURL: this.moreInfoURL };
    
    56 55
     
    
    57 56
         try {
    
    ... ... @@ -74,46 +73,72 @@ class AboutTBUpdateParent extends JSWindowActorParent {
    74 73
           f.append("Docs");
    
    75 74
           f.append("ChangeLog.txt");
    
    76 75
     
    
    77
    -      let fs = Cc["@mozilla.org/network/file-input-stream;1"].createInstance(
    
    78
    -        Ci.nsIFileInputStream
    
    79
    -      );
    
    80
    -      fs.init(f, -1, 0, 0);
    
    81
    -      let s = NetUtil.readInputStreamToString(fs, fs.available());
    
    82
    -      fs.close();
    
    83
    -
    
    84
    -      // Truncate at the first empty line.
    
    85
    -      s = s.replace(/[\r\n][\r\n][\s\S]*$/m, "");
    
    86
    -
    
    87
    -      // Split into first line (version plus releaseDate) and
    
    88
    -      // remainder (releaseNotes).
    
    89
    -      // This first match() uses multiline mode with two capture groups:
    
    90
    -      //   first line: (.*$)
    
    91
    -      //   remaining lines: ([\s\S]+)
    
    92
    -      //     [\s\S] matches all characters including end of line. This trick
    
    93
    -      //     is needed because when using JavaScript regex in multiline mode,
    
    94
    -      //     . does not match an end of line character.
    
    95
    -      let matchArray = s.match(/(.*$)\s*([\s\S]+)/m);
    
    96
    -      if (matchArray && matchArray.length == 3) {
    
    97
    -        info.releaseNotes = matchArray[2];
    
    98
    -        let line1 = matchArray[1];
    
    99
    -        // Extract the version and releaseDate. The first line looks like:
    
    100
    -        //   Tor Browser 8.5 -- May 1 2019
    
    101
    -        // The regex uses two capture groups:
    
    102
    -        //   text that does not include a hyphen: (^[^-]*)
    
    103
    -        //   remaining text: (.*$)
    
    104
    -        // In between we match optional whitespace, one or more hyphens, and
    
    105
    -        // optional whitespace by using: \s*-+\s*
    
    106
    -        matchArray = line1.match(/(^[^-]*)\s*-+\s*(.*$)/);
    
    107
    -        if (matchArray && matchArray.length == 3) {
    
    108
    -          info.version = matchArray[1];
    
    109
    -          info.releaseDate = matchArray[2];
    
    76
    +      // NOTE: We load in the entire file, but only use the first few lines
    
    77
    +      // before the first blank line.
    
    78
    +      const logLines = (await IOUtils.readUTF8(f.path))
    
    79
    +        .replace(/\n\r?\n.*/ms, "")
    
    80
    +        .split(/\n\r?/);
    
    81
    +
    
    82
    +      // Read the first line to get the version and date.
    
    83
    +      // Assume everything after the last "-" is the date.
    
    84
    +      const firstLine = logLines.shift();
    
    85
    +      const match = firstLine?.match(/(.*)-+(.*)/);
    
    86
    +      if (match) {
    
    87
    +        info.version = match[1].trim();
    
    88
    +        info.releaseDate = match[2].trim();
    
    89
    +      } else {
    
    90
    +        // No date.
    
    91
    +        info.version = firstLine?.trim();
    
    92
    +      }
    
    93
    +
    
    94
    +      // We want to read the rest of the release notes as a tree. Each entry
    
    95
    +      // will contain the text for that line.
    
    96
    +      // We choose a negative index for the top node of this tree to ensure no
    
    97
    +      // line will appear less indented.
    
    98
    +      const topEntry = { indent: -1, children: undefined };
    
    99
    +      let prevEntry = topEntry;
    
    100
    +
    
    101
    +      for (let line of logLines) {
    
    102
    +        const indent = line.match(/^ */)[0];
    
    103
    +        line = line.trim();
    
    104
    +        if (line.startsWith("*")) {
    
    105
    +          // Treat as a bullet point.
    
    106
    +          let entry = {
    
    107
    +            text: line.replace(/^\*\s/, ""),
    
    108
    +            indent: indent.length,
    
    109
    +          };
    
    110
    +          let parentEntry;
    
    111
    +          if (entry.indent > prevEntry.indent) {
    
    112
    +            // A sub-list of the previous item.
    
    113
    +            prevEntry.children = [];
    
    114
    +            parentEntry = prevEntry;
    
    115
    +          } else {
    
    116
    +            // Same list or end of sub-list.
    
    117
    +            // Search for the first parent whose indent comes before ours.
    
    118
    +            parentEntry = prevEntry.parent;
    
    119
    +            while (entry.indent <= parentEntry.indent) {
    
    120
    +              parentEntry = parentEntry.parent;
    
    121
    +            }
    
    122
    +          }
    
    123
    +          entry.parent = parentEntry;
    
    124
    +          parentEntry.children.push(entry);
    
    125
    +          prevEntry = entry;
    
    126
    +        } else if (prevEntry === topEntry) {
    
    127
    +          // Unexpected, missing bullet point on first line.
    
    128
    +          // Place as its own bullet point instead, and set as prevEntry for the
    
    129
    +          // next loop.
    
    130
    +          prevEntry = { text: line, indent: indent.length, parent: topEntry };
    
    131
    +          topEntry.children = [prevEntry];
    
    110 132
             } else {
    
    111
    -          info.version = line1; // Match failed: return entire line in version.
    
    133
    +          // Append to the previous bullet point.
    
    134
    +          prevEntry.text += ` ${line}`;
    
    112 135
             }
    
    113
    -      } else {
    
    114
    -        info.releaseNotes = s; // Only one line: use as releaseNotes.
    
    115 136
           }
    
    116
    -    } catch (e) {}
    
    137
    +
    
    138
    +      info.releaseNotes = topEntry.children;
    
    139
    +    } catch (e) {
    
    140
    +      Cu.reportError(e);
    
    141
    +    }
    
    117 142
     
    
    118 143
         return info;
    
    119 144
       }
    

  • browser/base/content/abouttbupdate/aboutTBUpdate.css
    ... ... @@ -14,61 +14,54 @@ body {
    14 14
       font-family: Helvetica, Arial, sans-serif;
    
    15 15
       color: var(--abouttor-text-color);
    
    16 16
       background-color: var(--abouttor-bg-toron-color);
    
    17
    -  background-attachment: fixed;
    
    18
    -  background-size: 100% 100%;
    
    19
    -}
    
    20
    -
    
    21
    -a {
    
    22
    -  color: var(--abouttor-text-color);
    
    23
    -}
    
    24
    -
    
    25
    -.two-column-grid {
    
    26
    -  display: inline-grid;
    
    17
    +  margin-block: 40px;
    
    18
    +  margin-inline: 50px;
    
    19
    +  display: grid;
    
    27 20
       grid-template-columns: auto auto;
    
    28
    -  grid-column-gap: 50px;
    
    29
    -  margin: 10px 0px 0px 50px;
    
    21
    +  align-items: baseline;
    
    22
    +  gap: 40px 50px;
    
    30 23
     }
    
    31 24
     
    
    32
    -.two-column-grid div {
    
    33
    -  margin-top: 40px;
    
    34
    -  align-self: baseline;  /* Align baseline of text across the row. */
    
    25
    +body > *:not([hidden]) {
    
    26
    +  display: contents;
    
    35 27
     }
    
    36 28
     
    
    37 29
     .label-column {
    
    38
    -  font-size: 14px;
    
    39
    -  font-weight: 400;
    
    30
    +  grid-column: 1;
    
    40 31
     }
    
    41 32
     
    
    42
    -/*
    
    43
    - * Use a reduced top margin to bring the row that contains the
    
    44
    - * "visit our website" link closer to the row that precedes it. This
    
    45
    - * looks better because the "visit our website" row does not have a
    
    46
    - * label in the left column.
    
    47
    - */
    
    48
    -div.more-info-row {
    
    49
    -  margin-top: 5px;
    
    50
    -  font-size: 14px;
    
    33
    +.content {
    
    34
    +  grid-column: 2;
    
    35
    +  font-family: monospace;
    
    36
    +  line-height: 1.4;
    
    37
    +}
    
    38
    +
    
    39
    +.label-column, .content {
    
    40
    +  margin: 0;
    
    41
    +  padding: 0;
    
    42
    +  font-size: 1rem;
    
    43
    +  font-weight: normal;
    
    51 44
     }
    
    52 45
     
    
    53
    -#version-content {
    
    54
    -  font-size: 50px;
    
    55
    -  font-weight: 300;
    
    46
    +a {
    
    47
    +  color: inherit;
    
    56 48
     }
    
    57 49
     
    
    58
    -body:not([havereleasedate]) .release-date-cell {
    
    59
    -  display: none;
    
    50
    +.no-line-break {
    
    51
    +  white-space: nowrap;
    
    60 52
     }
    
    61 53
     
    
    62
    -#releasedate-content {
    
    63
    -  font-size: 17px;
    
    54
    +ul {
    
    55
    +  padding-inline: 1em 0;
    
    64 56
     }
    
    65 57
     
    
    66
    -#releasenotes-label {
    
    67
    -  align-self: start;  /* Anchor "Release Notes" label at the top. */
    
    58
    +h3, h4 {
    
    59
    +  font-size: 1.1rem;
    
    60
    +  font-weight: bold;
    
    68 61
     }
    
    69 62
     
    
    70
    -#releasenotes-content {
    
    71
    -  font-family: monospace;
    
    72
    -  font-size: 15px;
    
    73
    -  white-space: pre;
    
    63
    +h3.build-system-heading {
    
    64
    +  font-size: 1.5rem;
    
    65
    +  font-weight: normal;
    
    66
    +  margin-block-start: 3em;
    
    74 67
     }

  • browser/base/content/abouttbupdate/aboutTBUpdate.js
    ... ... @@ -5,23 +5,105 @@
    5 5
     
    
    6 6
     /* eslint-env mozilla/frame-script */
    
    7 7
     
    
    8
    -// aData may contain the following string properties:
    
    9
    -//   version
    
    10
    -//   releaseDate
    
    11
    -//   moreInfoURL
    
    12
    -//   releaseNotes
    
    13
    -function onUpdate(aData) {
    
    14
    -  document.getElementById("version-content").textContent = aData.version;
    
    15
    -  if (aData.releaseDate) {
    
    16
    -    document.body.setAttribute("havereleasedate", "true");
    
    17
    -    document.getElementById("releasedate-content").textContent =
    
    18
    -      aData.releaseDate;
    
    8
    +/**
    
    9
    + * An object representing a bullet point in the release notes.
    
    10
    + *
    
    11
    + * typedef {Object} ReleaseBullet
    
    12
    + * @property {string} text - The text for this bullet point.
    
    13
    + * @property {?Array<ReleaseBullet>} children - A sub-list of bullet points.
    
    14
    + */
    
    15
    +
    
    16
    +/**
    
    17
    + * Fill an element with the given list of release bullet points.
    
    18
    + *
    
    19
    + * @param {Element} container - The element to fill with bullet points.
    
    20
    + * @param {Array<ReleaseBullet>} bulletPoints - The list of bullet points.
    
    21
    + * @param {string} [childTag="h3"] - The element tag name to use for direct
    
    22
    + *   children. Initially, the children are h3 sub-headings.
    
    23
    + */
    
    24
    +function fillReleaseNotes(container, bulletPoints, childTag = "h3") {
    
    25
    +  for (const { text, children } of bulletPoints) {
    
    26
    +    const childEl = document.createElement(childTag);
    
    27
    +    // Keep dashes like "[tor-browser]" on the same line by nowrapping the word.
    
    28
    +    for (const [index, part] of text.split(/(\S+-\S+)/).entries()) {
    
    29
    +      if (!part) {
    
    30
    +        continue;
    
    31
    +      }
    
    32
    +      const span = document.createElement("span");
    
    33
    +      span.textContent = part;
    
    34
    +      span.classList.toggle("no-line-break", index % 2);
    
    35
    +      childEl.appendChild(span);
    
    36
    +    }
    
    37
    +    container.appendChild(childEl);
    
    38
    +    if (children) {
    
    39
    +      if (childTag == "h3" && text.toLowerCase() === "build system") {
    
    40
    +        // Special case: treat the "Build System" heading's children as
    
    41
    +        // sub-headings.
    
    42
    +        childEl.classList.add("build-system-heading");
    
    43
    +        fillReleaseNotes(container, children, "h4");
    
    44
    +      } else {
    
    45
    +        const listEl = document.createElement("ul");
    
    46
    +        fillReleaseNotes(listEl, children, "li");
    
    47
    +        if (childTag == "li") {
    
    48
    +          // Insert within the "li" element.
    
    49
    +          childEl.appendChild(listEl);
    
    50
    +        } else {
    
    51
    +          container.appendChild(listEl);
    
    52
    +        }
    
    53
    +      }
    
    54
    +    }
    
    55
    +  }
    
    56
    +}
    
    57
    +
    
    58
    +/**
    
    59
    + * Set the content for the specified container, or hide it if we have no
    
    60
    + * content.
    
    61
    + *
    
    62
    + * @template C
    
    63
    + * @param {string} containerId - The id for the container.
    
    64
    + * @param {?C} content - The content for this container, or a falsey value if
    
    65
    + *   the container has no content.
    
    66
    + * @param {function(contentEl: Elemenet, content: C)} [fillContent] - A function
    
    67
    + *   to fill the ".content" contentEl with the given 'content'. If unspecified,
    
    68
    + *   the 'content' will become the contentEl's textContent.
    
    69
    + */
    
    70
    +function setContent(containerId, content, fillContent) {
    
    71
    +  const container = document.getElementById(containerId);
    
    72
    +  if (!content) {
    
    73
    +    container.hidden = true;
    
    74
    +    return;
    
    19 75
       }
    
    76
    +  const contentEl = container.querySelector(".content");
    
    77
    +  // Release notes are only in English.
    
    78
    +  contentEl.setAttribute("lang", "en-US");
    
    79
    +  contentEl.setAttribute("dir", "ltr");
    
    80
    +  if (fillContent) {
    
    81
    +    fillContent(contentEl, content);
    
    82
    +  } else {
    
    83
    +    contentEl.textContent = content;
    
    84
    +  }
    
    85
    +}
    
    86
    +
    
    87
    +/**
    
    88
    + * Callback when we receive the update details.
    
    89
    + *
    
    90
    + * @param {Object} aData - The update details.
    
    91
    + * @param {?string} aData.version - The update version.
    
    92
    + * @param {?string} aData.releaseDate - The release date.
    
    93
    + * @param {?string} aData.moreInfoURL - A URL for more info.
    
    94
    + * @param {?Array<ReleaseBullet>} aData.releaseNotes - Release notes as bullet
    
    95
    + *   points.
    
    96
    + */
    
    97
    +function onUpdate(aData) {
    
    98
    +  setContent("version-row", aData.version);
    
    99
    +  setContent("releasedate-row", aData.releaseDate);
    
    100
    +  setContent("releasenotes", aData.releaseNotes, fillReleaseNotes);
    
    101
    +
    
    20 102
       if (aData.moreInfoURL) {
    
    21 103
         document.getElementById("infolink").setAttribute("href", aData.moreInfoURL);
    
    104
    +  } else {
    
    105
    +    document.getElementById("fullinfo").hidden = true;
    
    22 106
       }
    
    23
    -  document.getElementById("releasenotes-content").textContent =
    
    24
    -    aData.releaseNotes;
    
    25 107
     }
    
    26 108
     
    
    27 109
     RPMSendQuery("FetchUpdateData").then(onUpdate);

  • browser/base/content/abouttbupdate/aboutTBUpdate.xhtml
    ... ... @@ -21,19 +21,26 @@
    21 21
               type="text/javascript"/>
    
    22 22
     </head>
    
    23 23
     <body dir="&locale.dir;">
    
    24
    -<div class="two-column-grid">
    
    25
    -  <div class="label-column">&aboutTBUpdate.version;</div>
    
    26
    -  <div id="version-content"/>
    
    27
    -
    
    28
    -  <div class="label-column release-date-cell">&aboutTBUpdate.releaseDate;</div>
    
    29
    -  <div id="releasedate-content" class="release-date-cell"/>
    
    30
    -
    
    31
    -  <div class="more-info-row"/>
    
    32
    -  <div class="more-info-row">&aboutTBUpdate.linkPrefix;<a id="infolink">&aboutTBUpdate.linkLabel;</a>&aboutTBUpdate.linkSuffix;</div>
    
    33
    -
    
    34
    -  <div id="releasenotes-label"
    
    35
    -       class="label-column">&aboutTBUpdate.releaseNotes;</div>
    
    36
    -  <div id="releasenotes-content"></div>
    
    37
    -</div>
    
    24
    +  <!-- NOTE: We don't use the <dl>, <dt> and <dd> elements to form name-value
    
    25
    +     - pairs because this semantics is relatively new, whilst firefox
    
    26
    +     - currently still maps these to the more limited "definitionlist", "term"
    
    27
    +     - and "definition" roles. -->
    
    28
    +  <div id="version-row">
    
    29
    +    <span class="label-column">&aboutTBUpdate.version;</span>
    
    30
    +    <span class="content"></span>
    
    31
    +  </div>
    
    32
    +  <div id="releasedate-row">
    
    33
    +    <span class="label-column">&aboutTBUpdate.releaseDate;</span>
    
    34
    +    <span class="content"></span>
    
    35
    +  </div>
    
    36
    +  <div id="fullinfo">
    
    37
    +    <p class="content">
    
    38
    +      &aboutTBUpdate.linkPrefix;<a id="infolink">&aboutTBUpdate.linkLabel;</a>&aboutTBUpdate.linkSuffix;
    
    39
    +    </p>
    
    40
    +  </div>
    
    41
    +  <section id="releasenotes">
    
    42
    +    <h2 class="label-column">&aboutTBUpdate.releaseNotes;</h2>
    
    43
    +    <div class="content"></div>
    
    44
    +  </section>
    
    38 45
     </body>
    
    39 46
     </html>