Merge "Fix index template null check"
diff --git a/polygerrit-ui/app/elements/shared/gr-linked-text/gr-linked-text.js b/polygerrit-ui/app/elements/shared/gr-linked-text/gr-linked-text.js
index 22e14e9..b6959b4 100644
--- a/polygerrit-ui/app/elements/shared/gr-linked-text/gr-linked-text.js
+++ b/polygerrit-ui/app/elements/shared/gr-linked-text/gr-linked-text.js
@@ -60,15 +60,15 @@
      *     commentLink patterns
      */
     _contentOrConfigChanged(content, config) {
-      var output = Polymer.dom(this.$.output);
+      const output = Polymer.dom(this.$.output);
       output.textContent = '';
-      var parser = new GrLinkTextParser(config,
+      const parser = new GrLinkTextParser(config,
           this._handleParseResult.bind(this), this.removeZeroWidthSpace);
       parser.parse(content);
 
       // Ensure that links originating from HTML commentlink configs open in a
       // new tab. @see Issue 5567
-      output.querySelectorAll('a').forEach(function(anchor) {
+      output.querySelectorAll('a').forEach(anchor => {
         anchor.setAttribute('target', '_blank');
         anchor.setAttribute('rel', 'noopener');
       });
@@ -87,9 +87,9 @@
      * @param  {DocumentFragment|undefined} fragment
      */
     _handleParseResult(text, href, fragment) {
-      var output = Polymer.dom(this.$.output);
+      const output = Polymer.dom(this.$.output);
       if (href) {
-        var a = document.createElement('a');
+        const a = document.createElement('a');
         a.href = href;
         a.textContent = text;
         a.target = '_blank';
diff --git a/polygerrit-ui/app/elements/shared/gr-linked-text/gr-linked-text_test.html b/polygerrit-ui/app/elements/shared/gr-linked-text/gr-linked-text_test.html
index baa025e..524496a 100644
--- a/polygerrit-ui/app/elements/shared/gr-linked-text/gr-linked-text_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-linked-text/gr-linked-text_test.html
@@ -37,29 +37,29 @@
 </test-fixture>
 
 <script>
-  suite('gr-linked-text tests', function() {
-    var element;
-    var sandbox;
+  suite('gr-linked-text tests', () => {
+    let element;
+    let sandbox;
 
-    setup(function() {
+    setup(() => {
       element = fixture('basic');
       sandbox = sinon.sandbox.create();
       element.config = {
         ph: {
           match: '([Bb]ug|[Ii]ssue)\\s*#?(\\d+)',
-          link: 'https://code.google.com/p/gerrit/issues/detail?id=$2'
+          link: 'https://code.google.com/p/gerrit/issues/detail?id=$2',
         },
         changeid: {
           match: '(I[0-9a-f]{8,40})',
-          link: '#/q/$1'
+          link: '#/q/$1',
         },
         changeid2: {
           match: 'Change-Id: +(I[0-9a-f]{8,40})',
-          link: '#/q/$1'
+          link: '#/q/$1',
         },
         googlesearch: {
           match: 'google:(.+)',
-          link: 'https://bing.com/search?q=$1',  // html should supercede link.
+          link: 'https://bing.com/search?q=$1', // html should supercede link.
           html: '<a href="https://google.com/search?q=$1">$1</a>',
         },
         hashedhtml: {
@@ -74,27 +74,27 @@
       };
     });
 
-    teardown(function() {
+    teardown(() => {
       sandbox.restore();
     });
 
-    test('URL pattern was parsed and linked.', function() {
-      // Reguar inline link.
-      var url = 'https://code.google.com/p/gerrit/issues/detail?id=3650';
+    test('URL pattern was parsed and linked.', () => {
+      // Regular inline link.
+      const url = 'https://code.google.com/p/gerrit/issues/detail?id=3650';
       element.content = url;
-      var linkEl = element.$.output.childNodes[0];
+      const linkEl = element.$.output.childNodes[0];
       assert.equal(linkEl.target, '_blank');
       assert.equal(linkEl.rel, 'noopener');
       assert.equal(linkEl.href, url);
       assert.equal(linkEl.textContent, url);
     });
 
-    test('Bug pattern was parsed and linked', function() {
+    test('Bug pattern was parsed and linked', () => {
       // "Issue/Bug" pattern.
       element.content = 'Issue 3650';
 
-      var linkEl = element.$.output.childNodes[0];
-      var url = 'https://code.google.com/p/gerrit/issues/detail?id=3650';
+      let linkEl = element.$.output.childNodes[0];
+      const url = 'https://code.google.com/p/gerrit/issues/detail?id=3650';
       assert.equal(linkEl.target, '_blank');
       assert.equal(linkEl.href, url);
       assert.equal(linkEl.textContent, 'Issue 3650');
@@ -107,26 +107,26 @@
       assert.equal(linkEl.textContent, 'Bug 3650');
     });
 
-    test('Change-Id pattern was parsed and linked', function() {
+    test('Change-Id pattern was parsed and linked', () => {
       // "Change-Id:" pattern.
-      var changeID = 'I11d6a37f5e9b5df0486f6c922d8836dfa780e03e';
-      var prefix = 'Change-Id: ';
+      const changeID = 'I11d6a37f5e9b5df0486f6c922d8836dfa780e03e';
+      const prefix = 'Change-Id: ';
       element.content = prefix + changeID;
 
-      var textNode = element.$.output.childNodes[0];
-      var linkEl = element.$.output.childNodes[1];
+      const textNode = element.$.output.childNodes[0];
+      const linkEl = element.$.output.childNodes[1];
       assert.equal(textNode.textContent, prefix);
-      var url = '/q/' + changeID;
+      const url = '/q/' + changeID;
       assert.equal(linkEl.target, '_blank');
       // Since url is a path, the host is added automatically.
       assert.isTrue(linkEl.href.endsWith(url));
       assert.equal(linkEl.textContent, changeID);
     });
 
-    test('Multiple matches', function() {
+    test('Multiple matches', () => {
       element.content = 'Issue 3650\nIssue 3450';
-      var linkEl1 = element.$.output.childNodes[0];
-      var linkEl2 = element.$.output.childNodes[2];
+      const linkEl1 = element.$.output.childNodes[0];
+      const linkEl2 = element.$.output.childNodes[2];
 
       assert.equal(linkEl1.target, '_blank');
       assert.equal(linkEl1.href,
@@ -139,22 +139,22 @@
       assert.equal(linkEl2.textContent, 'Issue 3450');
     });
 
-    test('Change-Id pattern parsed before bug pattern', function() {
+    test('Change-Id pattern parsed before bug pattern', () => {
       // "Change-Id:" pattern.
-      var changeID = 'I11d6a37f5e9b5df0486f6c922d8836dfa780e03e';
-      var prefix = 'Change-Id: ';
+      const changeID = 'I11d6a37f5e9b5df0486f6c922d8836dfa780e03e';
+      const prefix = 'Change-Id: ';
 
       // "Issue/Bug" pattern.
-      var bug = 'Issue 3650';
+      const bug = 'Issue 3650';
 
-      var changeUrl = '/q/' + changeID;
-      var bugUrl = 'https://code.google.com/p/gerrit/issues/detail?id=3650';
+      const changeUrl = '/q/' + changeID;
+      const bugUrl = 'https://code.google.com/p/gerrit/issues/detail?id=3650';
 
       element.content = prefix + changeID + bug;
 
-      var textNode = element.$.output.childNodes[0];
-      var changeLinkEl = element.$.output.childNodes[1];
-      var bugLinkEl = element.$.output.childNodes[2];
+      const textNode = element.$.output.childNodes[0];
+      const changeLinkEl = element.$.output.childNodes[1];
+      const bugLinkEl = element.$.output.childNodes[2];
 
       assert.equal(textNode.textContent, prefix);
 
@@ -167,41 +167,41 @@
       assert.equal(bugLinkEl.textContent, 'Issue 3650');
     });
 
-    test('html field in link config', function() {
+    test('html field in link config', () => {
       element.content = 'google:do a barrel roll';
-      var linkEl = element.$.output.childNodes[0];
+      const linkEl = element.$.output.childNodes[0];
       assert.equal(linkEl.getAttribute('href'),
           'https://google.com/search?q=do a barrel roll');
       assert.equal(linkEl.textContent, 'do a barrel roll');
     });
 
-    test('removing hash from links', function() {
+    test('removing hash from links', () => {
       element.content = 'hash:foo';
-      var linkEl = element.$.output.childNodes[0];
+      const linkEl = element.$.output.childNodes[0];
       assert.isTrue(linkEl.href.endsWith('/awesomesauce'));
       assert.equal(linkEl.textContent, 'foo');
     });
 
-    test('disabled config', function() {
+    test('disabled config', () => {
       element.content = 'foo:baz';
       assert.equal(element.$.output.innerHTML, 'foo:baz');
     });
 
-    test('R=email labels link correctly', function() {
+    test('R=email labels link correctly', () => {
       element.removeZeroWidthSpace = true;
       element.content = 'R=\u200Btest@google.com';
       assert.equal(element.$.output.textContent, 'R=test@google.com');
       assert.equal(element.$.output.innerHTML.match(/(R=<a)/g).length, 1);
     });
 
-    test('CC=email labels link correctly', function() {
+    test('CC=email labels link correctly', () => {
       element.removeZeroWidthSpace = true;
       element.content = 'CC=\u200Btest@google.com';
       assert.equal(element.$.output.textContent, 'CC=test@google.com');
       assert.equal(element.$.output.innerHTML.match(/(CC=<a)/g).length, 1);
     });
 
-    test('only {http,https,mailto} protocols are linkified', function() {
+    test('only {http,https,mailto} protocols are linkified', () => {
       element.content = 'xx mailto:test@google.com yy';
       let links = element.$.output.querySelectorAll('a');
       assert.equal(links.length, 1);
@@ -226,7 +226,7 @@
       assert.equal(links.length, 0);
     });
 
-    test('overlapping links', function() {
+    test('overlapping links', () => {
       element.config = {
         b1: {
           match: '(B:\\s*)(\\d+)',
@@ -238,7 +238,7 @@
         },
       };
       element.content = '- B: 123, 45';
-      var links = Polymer.dom(element.root).querySelectorAll('a');
+      const links = Polymer.dom(element.root).querySelectorAll('a');
 
       assert.equal(links.length, 2);
       assert.equal(element.$$('span').textContent, '- B: 123, 45');
@@ -250,31 +250,31 @@
       assert.equal(links[1].textContent, '45');
     });
 
-    test('_contentOrConfigChanged called with config', function() {
-      var contentStub = sandbox.stub(element, '_contentChanged');
-      var contentConfigStub = sandbox.stub(element, '_contentOrConfigChanged');
+    test('_contentOrConfigChanged called with config', () => {
+      const contentStub = sandbox.stub(element, '_contentChanged');
+      const contentConfigStub = sandbox.stub(element, '_contentOrConfigChanged');
       element.content = 'some text';
       assert.isTrue(contentStub.called);
       assert.isTrue(contentConfigStub.called);
     });
   });
 
-  suite('gr-linked-text with null config', function() {
-    var element;
-    var sandbox;
+  suite('gr-linked-text with null config', () => {
+    let element;
+    let sandbox;
 
-    setup(function() {
+    setup(() => {
       element = fixture('basic');
       sandbox = sinon.sandbox.create();
     });
 
-    teardown(function() {
+    teardown(() => {
       sandbox.restore();
     });
 
-    test('_contentOrConfigChanged not called without config', function() {
-      var contentStub = sandbox.stub(element, '_contentChanged');
-      var contentConfigStub = sandbox.stub(element, '_contentOrConfigChanged');
+    test('_contentOrConfigChanged not called without config', () => {
+      const contentStub = sandbox.stub(element, '_contentChanged');
+      const contentConfigStub = sandbox.stub(element, '_contentOrConfigChanged');
       element.content = 'some text';
       assert.isTrue(contentStub.called);
       assert.isFalse(contentConfigStub.called);
diff --git a/polygerrit-ui/app/elements/shared/gr-linked-text/link-text-parser.js b/polygerrit-ui/app/elements/shared/gr-linked-text/link-text-parser.js
index 8b49ca0..8526c3e 100644
--- a/polygerrit-ui/app/elements/shared/gr-linked-text/link-text-parser.js
+++ b/polygerrit-ui/app/elements/shared/gr-linked-text/link-text-parser.js
@@ -41,8 +41,8 @@
    * @param {Object|null|undefined} linkConfig Comment links as specified by the
    *     commentlinks field on a project config.
    * @param {Function} callback The callback to be fired when an intermediate
-   *     parse result is emitted. The callback is passed text and href strings if
-   *     a link is to be created, or a document fragment otherwise.
+   *     parse result is emitted. The callback is passed text and href strings
+   *     if a link is to be created, or a document fragment otherwise.
    * @param {boolean|undefined} opt_removeZeroWidthSpace If true, zero-width
    *     spaces will be removed from R=<email> and CC=<email> expressions.
    */
@@ -73,14 +73,14 @@
    */
   GrLinkTextParser.prototype.processLinks = function(text, outputArray) {
     this.sortArrayReverse(outputArray);
-    var fragment = document.createDocumentFragment();
-    var cursor = text.length;
+    const fragment = document.createDocumentFragment();
+    let cursor = text.length;
 
     // Start inserting linkified URLs from the end of the String. That way, the
     // string positions of the items don't change as we iterate through.
-    outputArray.forEach(function(item) {
-      // Add any text between the current linkified item and the item added before
-      // if it exists.
+    outputArray.forEach(item => {
+      // Add any text between the current linkified item and the item added
+      // before if it exists.
       if (item.position + item.length !== cursor) {
         fragment.insertBefore(
             document.createTextNode(
@@ -130,32 +130,32 @@
    */
   GrLinkTextParser.prototype.addItem =
       function(text, href, html, position, length, outputArray) {
-    var htmlOutput = '';
+        let htmlOutput = '';
 
-    if (href) {
-      var a = document.createElement('a');
-      a.href = href;
-      a.textContent = text;
-      a.target = '_blank';
-      a.rel = 'noopener';
-      htmlOutput = a;
-    } else if (html) {
-      var fragment = document.createDocumentFragment();
+        if (href) {
+          const a = document.createElement('a');
+          a.href = href;
+          a.textContent = text;
+          a.target = '_blank';
+          a.rel = 'noopener';
+          htmlOutput = a;
+        } else if (html) {
+          const fragment = document.createDocumentFragment();
       // Create temporary div to hold the nodes in.
-      var div = document.createElement('div');
-      div.innerHTML = html;
-      while (div.firstChild) {
-        fragment.appendChild(div.firstChild);
-      }
-      htmlOutput = fragment;
-    }
+          const div = document.createElement('div');
+          div.innerHTML = html;
+          while (div.firstChild) {
+            fragment.appendChild(div.firstChild);
+          }
+          htmlOutput = fragment;
+        }
 
-    outputArray.push({
-      html: htmlOutput,
-      position: position,
-      length: length,
-    });
-  };
+        outputArray.push({
+          html: htmlOutput,
+          position,
+          length,
+        });
+      };
 
   /**
    * Create a CommentLinkItem for a link and append it to the given output
@@ -171,9 +171,9 @@
    */
   GrLinkTextParser.prototype.addLink =
       function(text, href, position, length, outputArray) {
-    if (!text || this.hasOverlap(position, length, outputArray)) { return; }
-    this.addItem(text, href, null, position, length, outputArray);
-  };
+        if (!text || this.hasOverlap(position, length, outputArray)) { return; }
+        this.addItem(text, href, null, position, length, outputArray);
+      };
 
   /**
    * Create a CommentLinkItem specified by an HTMl string and append it to the
@@ -188,9 +188,9 @@
    */
   GrLinkTextParser.prototype.addHTML =
       function(html, position, length, outputArray) {
-    if (this.hasOverlap(position, length, outputArray)) { return; }
-    this.addItem(null, null, html, position, length, outputArray);
-  };
+        if (this.hasOverlap(position, length, outputArray)) { return; }
+        this.addItem(null, null, html, position, length, outputArray);
+      };
 
   /**
    * Does the given range overlap with anything already in the item list.
@@ -200,18 +200,18 @@
    */
   GrLinkTextParser.prototype.hasOverlap =
       function(position, length, outputArray) {
-    var endPosition = position + length;
-    for (var i = 0; i < outputArray.length; i++) {
-      var arrayItemStart = outputArray[i].position;
-      var arrayItemEnd = outputArray[i].position + outputArray[i].length;
-      if ((position >= arrayItemStart && position < arrayItemEnd) ||
+        const endPosition = position + length;
+        for (let i = 0; i < outputArray.length; i++) {
+          const arrayItemStart = outputArray[i].position;
+          const arrayItemEnd = outputArray[i].position + outputArray[i].length;
+          if ((position >= arrayItemStart && position < arrayItemEnd) ||
         (endPosition > arrayItemStart && endPosition <= arrayItemEnd) ||
         (position === arrayItemStart && position === arrayItemEnd)) {
             return true;
-      }
-    }
-    return false;
-  };
+          }
+        }
+        return false;
+      };
 
   /**
    * Parse the given source text and emit callbacks for the items that are
@@ -241,9 +241,9 @@
       text = text.replace(/^(CC|R)=\u200B/gm, '$1=');
     }
 
-    // If the href is provided then ba-linkify has recognized it as a URL. If the
-    // source text does not include a protocol, the protocol will be added by
-    // ba-linkify. Create the link if the href is provided and its protocol
+    // If the href is provided then ba-linkify has recognized it as a URL. If
+    // the source text does not include a protocol, the protocol will be added
+    // by ba-linkify. Create the link if the href is provided and its protocol
     // matches the expected pattern.
     if (href && URL_PROTOCOL_PATTERN.test(href)) {
       this.addText(text, href);
@@ -262,9 +262,10 @@
    *   object.
    */
   GrLinkTextParser.prototype.parseLinks = function(text, patterns) {
-    // The outputArray is used to store all of the matches found for all patterns.
-    var outputArray = [];
-    for (var p in patterns) {
+    // The outputArray is used to store all of the matches found for all
+    // patterns.
+    const outputArray = [];
+    for (const p in patterns) {
       if (patterns[p].enabled != null && patterns[p].enabled == false) {
         continue;
       }
@@ -279,38 +280,37 @@
         }
       }
 
-      var pattern = new RegExp(patterns[p].match, 'g');
+      const pattern = new RegExp(patterns[p].match, 'g');
 
-      var match;
-      var textToCheck = text;
-      var susbtrIndex = 0;
+      let match;
+      let textToCheck = text;
+      let susbtrIndex = 0;
 
       while ((match = pattern.exec(textToCheck)) != null) {
         textToCheck = textToCheck.substr(match.index + match[0].length);
-        var result = match[0].replace(pattern,
+        let result = match[0].replace(pattern,
             patterns[p].html || patterns[p].link);
 
+        let i;
         // Skip portion of replacement string that is equal to original.
-        for (var i = 0; i < result.length; i++) {
-          if (result[i] !== match[0][i]) {
-            break;
-          }
+        for (i = 0; i < result.length; i++) {
+          if (result[i] !== match[0][i]) { break; }
         }
         result = result.slice(i);
 
         if (patterns[p].html) {
           this.addHTML(
-            result,
-            susbtrIndex + match.index + i,
-            match[0].length - i,
-            outputArray);
+              result,
+              susbtrIndex + match.index + i,
+              match[0].length - i,
+              outputArray);
         } else if (patterns[p].link) {
           this.addLink(
-            match[0],
-            result,
-            susbtrIndex + match.index + i,
-            match[0].length - i,
-            outputArray);
+              match[0],
+              result,
+              susbtrIndex + match.index + i,
+              match[0].length - i,
+              outputArray);
         } else {
           throw Error('linkconfig entry ' + p +
               ' doesn’t contain a link or html attribute.');