Merge "ES6ify /gr-cursor-manager/*"
diff --git a/gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/TestAccount.java b/gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/TestAccount.java
index 5117328..3ab4a88 100644
--- a/gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/TestAccount.java
+++ b/gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/TestAccount.java
@@ -16,12 +16,15 @@
 
 import static java.util.stream.Collectors.toList;
 
+import com.google.common.net.InetAddresses;
 import com.google.gerrit.reviewdb.client.Account;
 import com.google.gerrit.server.mail.Address;
 import com.jcraft.jsch.KeyPair;
 import java.io.ByteArrayOutputStream;
+import java.net.InetSocketAddress;
 import java.util.Arrays;
 import java.util.List;
+import org.apache.http.client.utils.URIBuilder;
 import org.eclipse.jgit.lib.PersonIdent;
 
 public class TestAccount {
@@ -77,12 +80,13 @@
   }
 
   public String getHttpUrl(GerritServer server) {
-    return String.format(
-        "http://%s:%s@%s:%d",
-        username,
-        httpPassword,
-        server.getHttpAddress().getAddress().getHostAddress(),
-        server.getHttpAddress().getPort());
+    InetSocketAddress addr = server.getHttpAddress();
+    return new URIBuilder()
+        .setScheme("http")
+        .setUserInfo(username, httpPassword)
+        .setHost(InetAddresses.toUriString(addr.getAddress()))
+        .setPort(addr.getPort())
+        .toString();
   }
 
   public Account.Id getId() {
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/revision/RobotCommentsIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/revision/RobotCommentsIT.java
index e525e96..c440d90 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/revision/RobotCommentsIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/revision/RobotCommentsIT.java
@@ -85,7 +85,7 @@
 
   @Test
   public void retrievingRobotCommentsBeforeAddingAnyDoesNotRaiseAnException() throws Exception {
-    assume().that(notesMigration.enabled()).isTrue();
+    assume().that(notesMigration.readChanges()).isTrue();
 
     Map<String, List<RobotCommentInfo>> robotComments =
         gApi.changes().id(changeId).current().robotComments();
@@ -96,7 +96,7 @@
 
   @Test
   public void addedRobotCommentsCanBeRetrieved() throws Exception {
-    assume().that(notesMigration.enabled()).isTrue();
+    assume().that(notesMigration.readChanges()).isTrue();
 
     RobotCommentInput in = createRobotCommentInput();
     addRobotComment(changeId, in);
@@ -110,7 +110,7 @@
 
   @Test
   public void addedRobotCommentsCanBeRetrievedByChange() throws Exception {
-    assume().that(notesMigration.enabled()).isTrue();
+    assume().that(notesMigration.readChanges()).isTrue();
 
     RobotCommentInput in = createRobotCommentInput();
     addRobotComment(changeId, in);
@@ -133,7 +133,7 @@
 
   @Test
   public void robotCommentsCanBeRetrievedAsList() throws Exception {
-    assume().that(notesMigration.enabled()).isTrue();
+    assume().that(notesMigration.readChanges()).isTrue();
 
     RobotCommentInput robotCommentInput = createRobotCommentInput();
     addRobotComment(changeId, robotCommentInput);
@@ -148,7 +148,7 @@
 
   @Test
   public void specificRobotCommentCanBeRetrieved() throws Exception {
-    assume().that(notesMigration.enabled()).isTrue();
+    assume().that(notesMigration.readChanges()).isTrue();
 
     RobotCommentInput robotCommentInput = createRobotCommentInput();
     addRobotComment(changeId, robotCommentInput);
@@ -163,7 +163,7 @@
 
   @Test
   public void robotCommentWithoutOptionalFieldsCanBeAdded() throws Exception {
-    assume().that(notesMigration.enabled()).isTrue();
+    assume().that(notesMigration.readChanges()).isTrue();
 
     RobotCommentInput in = createRobotCommentInputWithMandatoryFields();
     addRobotComment(changeId, in);
@@ -176,7 +176,7 @@
 
   @Test
   public void hugeRobotCommentIsRejected() throws Exception {
-    assume().that(notesMigration.enabled()).isTrue();
+    assume().that(notesMigration.readChanges()).isTrue();
 
     int defaultSizeLimit = 1024 * 1024;
     int sizeOfRest = 451;
@@ -189,7 +189,7 @@
 
   @Test
   public void reasonablyLargeRobotCommentIsAccepted() throws Exception {
-    assume().that(notesMigration.enabled()).isTrue();
+    assume().that(notesMigration.readChanges()).isTrue();
 
     int defaultSizeLimit = 1024 * 1024;
     int sizeOfRest = 451;
@@ -204,7 +204,7 @@
   @Test
   @GerritConfig(name = "change.robotCommentSizeLimit", value = "10k")
   public void maximumAllowedSizeOfRobotCommentCanBeAdjusted() throws Exception {
-    assume().that(notesMigration.enabled()).isTrue();
+    assume().that(notesMigration.readChanges()).isTrue();
 
     int sizeLimit = 10 * 1024;
     fixReplacementInfo.replacement = getStringFor(sizeLimit);
@@ -217,7 +217,7 @@
   @Test
   @GerritConfig(name = "change.robotCommentSizeLimit", value = "0")
   public void zeroForMaximumAllowedSizeOfRobotCommentRemovesRestriction() throws Exception {
-    assume().that(notesMigration.enabled()).isTrue();
+    assume().that(notesMigration.readChanges()).isTrue();
 
     int defaultSizeLimit = 1024 * 1024;
     fixReplacementInfo.replacement = getStringFor(defaultSizeLimit);
@@ -232,7 +232,7 @@
   @GerritConfig(name = "change.robotCommentSizeLimit", value = "-1")
   public void negativeValueForMaximumAllowedSizeOfRobotCommentRemovesRestriction()
       throws Exception {
-    assume().that(notesMigration.enabled()).isTrue();
+    assume().that(notesMigration.readChanges()).isTrue();
 
     int defaultSizeLimit = 1024 * 1024;
     fixReplacementInfo.replacement = getStringFor(defaultSizeLimit);
@@ -245,7 +245,7 @@
 
   @Test
   public void addedFixSuggestionCanBeRetrieved() throws Exception {
-    assume().that(notesMigration.enabled()).isTrue();
+    assume().that(notesMigration.readChanges()).isTrue();
 
     addRobotComment(changeId, withFixRobotCommentInput);
     List<RobotCommentInfo> robotCommentInfos = getRobotComments();
@@ -255,7 +255,7 @@
 
   @Test
   public void fixIdIsGeneratedForFixSuggestion() throws Exception {
-    assume().that(notesMigration.enabled()).isTrue();
+    assume().that(notesMigration.readChanges()).isTrue();
 
     addRobotComment(changeId, withFixRobotCommentInput);
     List<RobotCommentInfo> robotCommentInfos = getRobotComments();
@@ -270,7 +270,7 @@
 
   @Test
   public void descriptionOfFixSuggestionIsAcceptedAsIs() throws Exception {
-    assume().that(notesMigration.enabled()).isTrue();
+    assume().that(notesMigration.readChanges()).isTrue();
 
     addRobotComment(changeId, withFixRobotCommentInput);
     List<RobotCommentInfo> robotCommentInfos = getRobotComments();
@@ -284,7 +284,7 @@
 
   @Test
   public void descriptionOfFixSuggestionIsMandatory() throws Exception {
-    assume().that(notesMigration.enabled()).isTrue();
+    assume().that(notesMigration.readChanges()).isTrue();
 
     fixSuggestionInfo.description = null;
 
@@ -298,7 +298,7 @@
 
   @Test
   public void addedFixReplacementCanBeRetrieved() throws Exception {
-    assume().that(notesMigration.enabled()).isTrue();
+    assume().that(notesMigration.readChanges()).isTrue();
 
     addRobotComment(changeId, withFixRobotCommentInput);
     List<RobotCommentInfo> robotCommentInfos = getRobotComments();
@@ -312,7 +312,7 @@
 
   @Test
   public void fixReplacementsAreMandatory() throws Exception {
-    assume().that(notesMigration.enabled()).isTrue();
+    assume().that(notesMigration.readChanges()).isTrue();
 
     fixSuggestionInfo.replacements = Collections.emptyList();
 
@@ -327,7 +327,7 @@
 
   @Test
   public void pathOfFixReplacementIsAcceptedAsIs() throws Exception {
-    assume().that(notesMigration.enabled()).isTrue();
+    assume().that(notesMigration.readChanges()).isTrue();
 
     addRobotComment(changeId, withFixRobotCommentInput);
 
@@ -343,7 +343,7 @@
 
   @Test
   public void pathOfFixReplacementIsMandatory() throws Exception {
-    assume().that(notesMigration.enabled()).isTrue();
+    assume().that(notesMigration.readChanges()).isTrue();
 
     fixReplacementInfo.path = null;
 
@@ -357,7 +357,7 @@
 
   @Test
   public void rangeOfFixReplacementIsAcceptedAsIs() throws Exception {
-    assume().that(notesMigration.enabled()).isTrue();
+    assume().that(notesMigration.readChanges()).isTrue();
 
     addRobotComment(changeId, withFixRobotCommentInput);
 
@@ -373,7 +373,7 @@
 
   @Test
   public void rangeOfFixReplacementIsMandatory() throws Exception {
-    assume().that(notesMigration.enabled()).isTrue();
+    assume().that(notesMigration.readChanges()).isTrue();
 
     fixReplacementInfo.range = null;
 
@@ -387,7 +387,7 @@
 
   @Test
   public void rangeOfFixReplacementNeedsToBeValid() throws Exception {
-    assume().that(notesMigration.enabled()).isTrue();
+    assume().that(notesMigration.readChanges()).isTrue();
 
     fixReplacementInfo.range = createRange(13, 9, 5, 10);
     exception.expect(BadRequestException.class);
@@ -398,7 +398,7 @@
   @Test
   public void rangesOfFixReplacementsOfSameFixSuggestionForSameFileMayNotOverlap()
       throws Exception {
-    assume().that(notesMigration.enabled()).isTrue();
+    assume().that(notesMigration.readChanges()).isTrue();
 
     FixReplacementInfo fixReplacementInfo1 = new FixReplacementInfo();
     fixReplacementInfo1.path = FILE_NAME;
@@ -422,7 +422,7 @@
   @Test
   public void rangesOfFixReplacementsOfSameFixSuggestionForDifferentFileMayOverlap()
       throws Exception {
-    assume().that(notesMigration.enabled()).isTrue();
+    assume().that(notesMigration.readChanges()).isTrue();
 
     FixReplacementInfo fixReplacementInfo1 = new FixReplacementInfo();
     fixReplacementInfo1.path = FILE_NAME;
@@ -447,7 +447,7 @@
   @Test
   public void rangesOfFixReplacementsOfDifferentFixSuggestionsForSameFileMayOverlap()
       throws Exception {
-    assume().that(notesMigration.enabled()).isTrue();
+    assume().that(notesMigration.readChanges()).isTrue();
 
     FixReplacementInfo fixReplacementInfo1 = new FixReplacementInfo();
     fixReplacementInfo1.path = FILE_NAME;
@@ -472,7 +472,7 @@
 
   @Test
   public void fixReplacementsDoNotNeedToBeOrderedAccordingToRange() throws Exception {
-    assume().that(notesMigration.enabled()).isTrue();
+    assume().that(notesMigration.readChanges()).isTrue();
 
     FixReplacementInfo fixReplacementInfo1 = new FixReplacementInfo();
     fixReplacementInfo1.path = FILE_NAME;
@@ -501,7 +501,7 @@
 
   @Test
   public void replacementStringOfFixReplacementIsAcceptedAsIs() throws Exception {
-    assume().that(notesMigration.enabled()).isTrue();
+    assume().that(notesMigration.readChanges()).isTrue();
 
     addRobotComment(changeId, withFixRobotCommentInput);
 
@@ -517,7 +517,7 @@
 
   @Test
   public void replacementStringOfFixReplacementIsMandatory() throws Exception {
-    assume().that(notesMigration.enabled()).isTrue();
+    assume().that(notesMigration.readChanges()).isTrue();
 
     fixReplacementInfo.replacement = null;
 
@@ -532,7 +532,7 @@
 
   @Test
   public void fixWithinALineCanBeApplied() throws Exception {
-    assume().that(notesMigration.enabled()).isTrue();
+    assume().that(notesMigration.readChanges()).isTrue();
 
     fixReplacementInfo.path = FILE_NAME;
     fixReplacementInfo.replacement = "Modified content";
@@ -557,7 +557,7 @@
 
   @Test
   public void fixSpanningMultipleLinesCanBeApplied() throws Exception {
-    assume().that(notesMigration.enabled()).isTrue();
+    assume().that(notesMigration.readChanges()).isTrue();
 
     fixReplacementInfo.path = FILE_NAME;
     fixReplacementInfo.replacement = "Modified content\n5";
@@ -581,7 +581,7 @@
 
   @Test
   public void fixWithTwoCloseReplacementsOnSameFileCanBeApplied() throws Exception {
-    assume().that(notesMigration.enabled()).isTrue();
+    assume().that(notesMigration.readChanges()).isTrue();
 
     FixReplacementInfo fixReplacementInfo1 = new FixReplacementInfo();
     fixReplacementInfo1.path = FILE_NAME;
@@ -615,7 +615,7 @@
 
   @Test
   public void twoFixesOnSameFileCanBeApplied() throws Exception {
-    assume().that(notesMigration.enabled()).isTrue();
+    assume().that(notesMigration.readChanges()).isTrue();
 
     FixReplacementInfo fixReplacementInfo1 = new FixReplacementInfo();
     fixReplacementInfo1.path = FILE_NAME;
@@ -650,7 +650,7 @@
 
   @Test
   public void twoConflictingFixesOnSameFileCannotBeApplied() throws Exception {
-    assume().that(notesMigration.enabled()).isTrue();
+    assume().that(notesMigration.readChanges()).isTrue();
 
     FixReplacementInfo fixReplacementInfo1 = new FixReplacementInfo();
     fixReplacementInfo1.path = FILE_NAME;
@@ -679,7 +679,7 @@
 
   @Test
   public void twoFixesOfSameRobotCommentCanBeApplied() throws Exception {
-    assume().that(notesMigration.enabled()).isTrue();
+    assume().that(notesMigration.readChanges()).isTrue();
 
     FixReplacementInfo fixReplacementInfo1 = new FixReplacementInfo();
     fixReplacementInfo1.path = FILE_NAME;
@@ -714,7 +714,7 @@
 
   @Test
   public void fixReferringToDifferentFileThanRobotCommentCanBeApplied() throws Exception {
-    assume().that(notesMigration.enabled()).isTrue();
+    assume().that(notesMigration.readChanges()).isTrue();
 
     fixReplacementInfo.path = FILE_NAME2;
     fixReplacementInfo.range = createRange(2, 0, 3, 0);
@@ -736,7 +736,7 @@
 
   @Test
   public void fixInvolvingTwoFilesCanBeApplied() throws Exception {
-    assume().that(notesMigration.enabled()).isTrue();
+    assume().that(notesMigration.readChanges()).isTrue();
 
     FixReplacementInfo fixReplacementInfo1 = new FixReplacementInfo();
     fixReplacementInfo1.path = FILE_NAME;
@@ -775,7 +775,7 @@
 
   @Test
   public void fixReferringToNonExistentFileCannotBeApplied() throws Exception {
-    assume().that(notesMigration.enabled()).isTrue();
+    assume().that(notesMigration.readChanges()).isTrue();
 
     fixReplacementInfo.path = "a_non_existent_file.txt";
     fixReplacementInfo.range = createRange(1, 0, 2, 0);
@@ -792,7 +792,7 @@
 
   @Test
   public void fixOnPreviousPatchSetWithoutChangeEditCannotBeApplied() throws Exception {
-    assume().that(notesMigration.enabled()).isTrue();
+    assume().that(notesMigration.readChanges()).isTrue();
 
     fixReplacementInfo.path = FILE_NAME;
     fixReplacementInfo.replacement = "Modified content";
@@ -815,7 +815,7 @@
 
   @Test
   public void fixOnPreviousPatchSetWithExistingChangeEditCanBeApplied() throws Exception {
-    assume().that(notesMigration.enabled()).isTrue();
+    assume().that(notesMigration.readChanges()).isTrue();
 
     // Create an empty change edit.
     gApi.changes().id(changeId).edit().create();
@@ -849,7 +849,7 @@
   @Test
   public void fixOnCurrentPatchSetWithChangeEditOnPreviousPatchSetCannotBeApplied()
       throws Exception {
-    assume().that(notesMigration.enabled()).isTrue();
+    assume().that(notesMigration.readChanges()).isTrue();
 
     // Create an empty change edit.
     gApi.changes().id(changeId).edit().create();
@@ -874,7 +874,7 @@
 
   @Test
   public void fixDoesNotModifyCommitMessageOfChangeEdit() throws Exception {
-    assume().that(notesMigration.enabled()).isTrue();
+    assume().that(notesMigration.readChanges()).isTrue();
 
     String changeEditCommitMessage = "This is the commit message of the change edit.\n";
     gApi.changes().id(changeId).edit().modifyCommitMessage(changeEditCommitMessage);
@@ -897,7 +897,7 @@
 
   @Test
   public void applyingFixTwiceIsIdempotent() throws Exception {
-    assume().that(notesMigration.enabled()).isTrue();
+    assume().that(notesMigration.readChanges()).isTrue();
 
     fixReplacementInfo.path = FILE_NAME;
     fixReplacementInfo.replacement = "Modified content";
@@ -922,7 +922,7 @@
 
   @Test
   public void nonExistentFixCannotBeApplied() throws Exception {
-    assume().that(notesMigration.enabled()).isTrue();
+    assume().that(notesMigration.readChanges()).isTrue();
 
     fixReplacementInfo.path = FILE_NAME;
     fixReplacementInfo.replacement = "Modified content";
@@ -941,7 +941,7 @@
 
   @Test
   public void applyingFixReturnsEditInfoForCreatedChangeEdit() throws Exception {
-    assume().that(notesMigration.enabled()).isTrue();
+    assume().that(notesMigration.readChanges()).isTrue();
 
     fixReplacementInfo.path = FILE_NAME;
     fixReplacementInfo.replacement = "Modified content";
@@ -964,7 +964,7 @@
 
   @Test
   public void applyingFixOnTopOfChangeEditReturnsEditInfoForUpdatedChangeEdit() throws Exception {
-    assume().that(notesMigration.enabled()).isTrue();
+    assume().that(notesMigration.readChanges()).isTrue();
 
     gApi.changes().id(changeId).edit().create();
 
@@ -989,7 +989,7 @@
 
   @Test
   public void createdChangeEditIsBasedOnCurrentPatchSet() throws Exception {
-    assume().that(notesMigration.enabled()).isTrue();
+    assume().that(notesMigration.readChanges()).isTrue();
     String currentRevision = gApi.changes().id(changeId).get().currentRevision;
 
     fixReplacementInfo.path = FILE_NAME;
@@ -1009,7 +1009,7 @@
 
   @Test
   public void robotCommentsNotSupportedWithoutNoteDb() throws Exception {
-    assume().that(notesMigration.enabled()).isFalse();
+    assume().that(notesMigration.readChanges()).isFalse();
 
     RobotCommentInput in = createRobotCommentInput();
     ReviewInput reviewInput = new ReviewInput();
@@ -1025,7 +1025,7 @@
 
   @Test
   public void queryChangesWithUnresolvedCommentCount() throws Exception {
-    assume().that(notesMigration.enabled()).isTrue();
+    assume().that(notesMigration.readChanges()).isTrue();
 
     PushOneCommit.Result r1 = createChange();
     PushOneCommit.Result r2 =
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/notedb/NoteDbPrimaryIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/notedb/NoteDbPrimaryIT.java
index 2b29054..3ed172f 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/notedb/NoteDbPrimaryIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/notedb/NoteDbPrimaryIT.java
@@ -63,6 +63,7 @@
 import com.google.gerrit.server.notedb.PrimaryStorageMigrator;
 import com.google.gerrit.server.notedb.TestChangeRebuilderWrapper;
 import com.google.gerrit.server.project.ChangeControl;
+import com.google.gerrit.server.update.RetryHelper;
 import com.google.gerrit.testutil.ConfigSuite;
 import com.google.gerrit.testutil.NoteDbMode;
 import com.google.gerrit.testutil.TestTimeUtil;
@@ -102,6 +103,7 @@
   @Inject private ChangeControl.GenericFactory changeControlFactory;
   @Inject private ChangeUpdate.Factory updateFactory;
   @Inject private InternalUser.Factory internalUserFactory;
+  @Inject private RetryHelper retryHelper;
 
   private PrimaryStorageMigrator migrator;
 
@@ -126,7 +128,7 @@
         queryProvider,
         updateFactory,
         internalUserFactory,
-        batchUpdateFactory);
+        retryHelper);
   }
 
   @After
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/IoUtil.java b/gerrit-common/src/main/java/com/google/gerrit/common/IoUtil.java
index 1ac42d1..624bcea 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/IoUtil.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/IoUtil.java
@@ -56,6 +56,10 @@
   }
 
   public static void loadJARs(Collection<Path> jars) {
+    if (jars.isEmpty()) {
+      return;
+    }
+
     ClassLoader cl = IoUtil.class.getClassLoader();
     if (!(cl instanceof URLClassLoader)) {
       throw noAddURL("Not loaded by URLClassLoader", null);
diff --git a/gerrit-plugin-api/BUILD b/gerrit-plugin-api/BUILD
index ebc5619..2e768ee 100644
--- a/gerrit-plugin-api/BUILD
+++ b/gerrit-plugin-api/BUILD
@@ -19,6 +19,7 @@
     "//gerrit-extension-api:api",
     "//gerrit-gwtexpui:server",
     "//gerrit-reviewdb:server",
+    "//gerrit-server/src/main/prolog:common",
     "//lib/commons:lang",
     "//lib/commons:lang3",
     "//lib/dropwizard:dropwizard-core",
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/CommentsUtil.java b/gerrit-server/src/main/java/com/google/gerrit/server/CommentsUtil.java
index 249ec7e..c51e33a 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/CommentsUtil.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/CommentsUtil.java
@@ -40,6 +40,7 @@
 import com.google.gerrit.reviewdb.client.RefNames;
 import com.google.gerrit.reviewdb.client.RobotComment;
 import com.google.gerrit.reviewdb.server.ReviewDb;
+import com.google.gerrit.reviewdb.server.ReviewDbUtil;
 import com.google.gerrit.server.config.AllUsersName;
 import com.google.gerrit.server.config.GerritServerId;
 import com.google.gerrit.server.git.GitRepositoryManager;
@@ -49,6 +50,7 @@
 import com.google.gerrit.server.notedb.NotesMigration;
 import com.google.gerrit.server.patch.PatchListCache;
 import com.google.gerrit.server.patch.PatchListNotAvailableException;
+import com.google.gerrit.server.update.BatchUpdateReviewDb;
 import com.google.gerrit.server.update.ChangeContext;
 import com.google.gwtorm.server.OrmException;
 import com.google.gwtorm.server.ResultSet;
@@ -410,6 +412,12 @@
     if (PrimaryStorage.of(update.getChange()).equals(PrimaryStorage.REVIEW_DB)) {
       PatchLineComment.Key key =
           new PatchLineComment.Key(new Patch.Key(psId, commentKey.filename), commentKey.uuid);
+
+      if (db instanceof BatchUpdateReviewDb) {
+        db = ((BatchUpdateReviewDb) db).unsafeGetDelegate();
+      }
+      db = ReviewDbUtil.unwrapDb(db);
+
       PatchLineComment patchLineComment = db.patchComments().get(key);
 
       if (!patchLineComment.getStatus().equals(PUBLISHED)) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountByEmailCacheImpl.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountByEmailCacheImpl.java
index 0120aed..9eec82d 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountByEmailCacheImpl.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountByEmailCacheImpl.java
@@ -18,12 +18,9 @@
 
 import com.google.common.cache.CacheLoader;
 import com.google.common.cache.LoadingCache;
-import com.google.common.collect.Streams;
 import com.google.gerrit.reviewdb.client.Account;
-import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.account.externalids.ExternalIds;
 import com.google.gerrit.server.cache.CacheModule;
-import com.google.gwtorm.server.SchemaFactory;
 import com.google.inject.Inject;
 import com.google.inject.Module;
 import com.google.inject.Provider;
@@ -78,25 +75,22 @@
   }
 
   static class Loader extends CacheLoader<String, Set<Account.Id>> {
-    private final SchemaFactory<ReviewDb> schema;
-
     // This must be a provider to prevent a cyclic dependency within Google-internal glue code.
     private final Provider<ExternalIds> externalIds;
 
     @Inject
-    Loader(SchemaFactory<ReviewDb> schema, Provider<ExternalIds> externalIds) {
-      this.schema = schema;
+    Loader(Provider<ExternalIds> externalIds) {
       this.externalIds = externalIds;
     }
 
     @Override
     public Set<Account.Id> load(String email) throws Exception {
-      try (ReviewDb db = schema.open()) {
-        return Streams.concat(
-                Streams.stream(db.accounts().byPreferredEmail(email)).map(a -> a.getId()),
-                externalIds.get().byEmail(email).stream().map(e -> e.accountId()))
-            .collect(toImmutableSet());
-      }
+      return externalIds
+          .get()
+          .byEmail(email)
+          .stream()
+          .map(e -> e.accountId())
+          .collect(toImmutableSet());
     }
   }
 }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/AbandonUtil.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/AbandonUtil.java
index 7645685..02ad66e 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/AbandonUtil.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/AbandonUtil.java
@@ -39,7 +39,6 @@
 public class AbandonUtil {
   private static final Logger log = LoggerFactory.getLogger(AbandonUtil.class);
 
-  private final BatchUpdate.Factory updateFactory;
   private final ChangeCleanupConfig cfg;
   private final ChangeQueryProcessor queryProcessor;
   private final ChangeQueryBuilder queryBuilder;
@@ -48,13 +47,11 @@
 
   @Inject
   AbandonUtil(
-      BatchUpdate.Factory updateFactory,
       ChangeCleanupConfig cfg,
       InternalUser.Factory internalUserFactory,
       ChangeQueryProcessor queryProcessor,
       ChangeQueryBuilder queryBuilder,
       Abandon abandon) {
-    this.updateFactory = updateFactory;
     this.cfg = cfg;
     this.queryProcessor = queryProcessor;
     this.queryBuilder = queryBuilder;
@@ -62,7 +59,7 @@
     internalUser = internalUserFactory.create();
   }
 
-  public void abandonInactiveOpenChanges() {
+  public void abandonInactiveOpenChanges(BatchUpdate.Factory updateFactory) {
     if (cfg.getAbandonAfter() <= 0) {
       return;
     }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeCleanupRunner.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeCleanupRunner.java
index 4299188..eb7d099 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeCleanupRunner.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeCleanupRunner.java
@@ -17,10 +17,13 @@
 import static com.google.gerrit.server.config.ScheduleConfig.MISSING_CONFIG;
 
 import com.google.gerrit.extensions.events.LifecycleListener;
+import com.google.gerrit.extensions.restapi.RestApiException;
 import com.google.gerrit.lifecycle.LifecycleModule;
 import com.google.gerrit.server.config.ChangeCleanupConfig;
 import com.google.gerrit.server.config.ScheduleConfig;
 import com.google.gerrit.server.git.WorkQueue;
+import com.google.gerrit.server.update.RetryHelper;
+import com.google.gerrit.server.update.UpdateException;
 import com.google.gerrit.server.util.ManualRequestContext;
 import com.google.gerrit.server.util.OneOffRequestContext;
 import com.google.gwtorm.server.OrmException;
@@ -81,19 +84,29 @@
 
   private final OneOffRequestContext oneOffRequestContext;
   private final AbandonUtil abandonUtil;
+  private final RetryHelper retryHelper;
 
   @Inject
-  ChangeCleanupRunner(OneOffRequestContext oneOffRequestContext, AbandonUtil abandonUtil) {
+  ChangeCleanupRunner(
+      OneOffRequestContext oneOffRequestContext, AbandonUtil abandonUtil, RetryHelper retryHelper) {
     this.oneOffRequestContext = oneOffRequestContext;
     this.abandonUtil = abandonUtil;
+    this.retryHelper = retryHelper;
   }
 
   @Override
   public void run() {
     log.info("Running change cleanups.");
     try (ManualRequestContext ctx = oneOffRequestContext.open()) {
-      abandonUtil.abandonInactiveOpenChanges();
-    } catch (OrmException e) {
+      // abandonInactiveOpenChanges skips failures instead of throwing, so retrying will never
+      // actually happen. For the purposes of this class that is fine: they'll get tried again the
+      // next time the scheduled task is run.
+      retryHelper.execute(
+          updateFactory -> {
+            abandonUtil.abandonInactiveOpenChanges(updateFactory);
+            return null;
+          });
+    } catch (RestApiException | UpdateException | OrmException e) {
       log.error("Failed to cleanup changes.", e);
     }
   }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/CherryPick.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/CherryPick.java
index 18ed4de..1a1f8cc 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/CherryPick.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/CherryPick.java
@@ -96,8 +96,8 @@
 
     try {
       Change.Id cherryPickedChangeId =
-          // TODO(dborowitz): Pass updateFactory here.
           cherryPickChange.cherryPick(
+              updateFactory,
               revision.getChange(),
               revision.getPatchSet(),
               input.message,
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/CherryPickChange.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/CherryPickChange.java
index ac092b5..a540298 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/CherryPickChange.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/CherryPickChange.java
@@ -80,7 +80,6 @@
   private final MergeUtil.Factory mergeUtilFactory;
   private final ChangeMessagesUtil changeMessagesUtil;
   private final PatchSetUtil psUtil;
-  private final BatchUpdate.Factory batchUpdateFactory;
 
   @Inject
   CherryPickChange(
@@ -94,8 +93,7 @@
       PatchSetInserter.Factory patchSetInserterFactory,
       MergeUtil.Factory mergeUtilFactory,
       ChangeMessagesUtil changeMessagesUtil,
-      PatchSetUtil psUtil,
-      BatchUpdate.Factory batchUpdateFactory) {
+      PatchSetUtil psUtil) {
     this.db = db;
     this.seq = seq;
     this.queryProvider = queryProvider;
@@ -107,14 +105,20 @@
     this.mergeUtilFactory = mergeUtilFactory;
     this.changeMessagesUtil = changeMessagesUtil;
     this.psUtil = psUtil;
-    this.batchUpdateFactory = batchUpdateFactory;
   }
 
   public Change.Id cherryPick(
-      Change change, PatchSet patch, String message, String ref, RefControl refControl, int parent)
+      BatchUpdate.Factory batchUpdateFactory,
+      Change change,
+      PatchSet patch,
+      String message,
+      String ref,
+      RefControl refControl,
+      int parent)
       throws OrmException, IOException, InvalidChangeOperationException, IntegrationException,
           UpdateException, RestApiException {
     return cherryPick(
+        batchUpdateFactory,
         change.getId(),
         patch.getId(),
         change.getDest(),
@@ -128,6 +132,7 @@
   }
 
   public Change.Id cherryPick(
+      BatchUpdate.Factory batchUpdateFactory,
       @Nullable Change.Id sourceChangeId,
       @Nullable PatchSet.Id sourcePatchId,
       @Nullable Branch.NameKey sourceBranch,
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/CherryPickCommit.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/CherryPickCommit.java
index cf99d37..4c027dd 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/CherryPickCommit.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/CherryPickCommit.java
@@ -22,7 +22,6 @@
 import com.google.gerrit.extensions.restapi.BadRequestException;
 import com.google.gerrit.extensions.restapi.ResourceConflictException;
 import com.google.gerrit.extensions.restapi.RestApiException;
-import com.google.gerrit.extensions.restapi.RestModifyView;
 import com.google.gerrit.reviewdb.client.Change;
 import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.reviewdb.client.RefNames;
@@ -31,6 +30,9 @@
 import com.google.gerrit.server.project.InvalidChangeOperationException;
 import com.google.gerrit.server.project.ProjectControl;
 import com.google.gerrit.server.project.RefControl;
+import com.google.gerrit.server.update.BatchUpdate;
+import com.google.gerrit.server.update.RetryHelper;
+import com.google.gerrit.server.update.RetryingRestModifyView;
 import com.google.gerrit.server.update.UpdateException;
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
@@ -39,19 +41,23 @@
 import org.eclipse.jgit.revwalk.RevCommit;
 
 @Singleton
-public class CherryPickCommit implements RestModifyView<CommitResource, CherryPickInput> {
+public class CherryPickCommit
+    extends RetryingRestModifyView<CommitResource, CherryPickInput, ChangeInfo> {
 
   private final CherryPickChange cherryPickChange;
   private final ChangeJson.Factory json;
 
   @Inject
-  CherryPickCommit(CherryPickChange cherryPickChange, ChangeJson.Factory json) {
+  CherryPickCommit(
+      RetryHelper retryHelper, CherryPickChange cherryPickChange, ChangeJson.Factory json) {
+    super(retryHelper);
     this.cherryPickChange = cherryPickChange;
     this.json = json;
   }
 
   @Override
-  public ChangeInfo apply(CommitResource rsrc, CherryPickInput input)
+  public ChangeInfo applyImpl(
+      BatchUpdate.Factory updateFactory, CommitResource rsrc, CherryPickInput input)
       throws OrmException, IOException, UpdateException, RestApiException {
     String message = Strings.nullToEmpty(input.message).trim();
     String destination = Strings.nullToEmpty(input.destination).trim();
@@ -78,6 +84,7 @@
     try {
       Change.Id cherryPickedChangeId =
           cherryPickChange.cherryPick(
+              updateFactory,
               null,
               null,
               null,
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/ConsistencyChecker.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/ConsistencyChecker.java
index 49d7bae..e1ccff9 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/ConsistencyChecker.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/ConsistencyChecker.java
@@ -22,6 +22,7 @@
 
 import com.google.auto.value.AutoValue;
 import com.google.common.collect.Collections2;
+import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.MultimapBuilder;
 import com.google.common.collect.SetMultimap;
@@ -53,6 +54,7 @@
 import com.google.gerrit.server.update.BatchUpdateOp;
 import com.google.gerrit.server.update.ChangeContext;
 import com.google.gerrit.server.update.RepoContext;
+import com.google.gerrit.server.update.RetryHelper;
 import com.google.gerrit.server.update.UpdateException;
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
@@ -101,7 +103,6 @@
     public abstract List<ProblemInfo> problems();
   }
 
-  private final BatchUpdate.Factory updateFactory;
   private final ChangeControl.GenericFactory changeControlFactory;
   private final ChangeNotes.Factory notesFactory;
   private final DynamicItem<AccountPatchReviewStore> accountPatchReviewStore;
@@ -112,7 +113,9 @@
   private final Provider<CurrentUser> user;
   private final Provider<PersonIdent> serverIdent;
   private final Provider<ReviewDb> db;
+  private final RetryHelper retryHelper;
 
+  private BatchUpdate.Factory updateFactory;
   private FixInput fix;
   private ChangeControl ctl;
   private Repository repo;
@@ -129,7 +132,6 @@
   @Inject
   ConsistencyChecker(
       @GerritPersonIdent Provider<PersonIdent> serverIdent,
-      BatchUpdate.Factory updateFactory,
       ChangeControl.GenericFactory changeControlFactory,
       ChangeNotes.Factory notesFactory,
       DynamicItem<AccountPatchReviewStore> accountPatchReviewStore,
@@ -138,7 +140,8 @@
       PatchSetInserter.Factory patchSetInserterFactory,
       PatchSetUtil psUtil,
       Provider<CurrentUser> user,
-      Provider<ReviewDb> db) {
+      Provider<ReviewDb> db,
+      RetryHelper retryHelper) {
     this.accountPatchReviewStore = accountPatchReviewStore;
     this.changeControlFactory = changeControlFactory;
     this.db = db;
@@ -147,13 +150,14 @@
     this.patchSetInserterFactory = patchSetInserterFactory;
     this.psUtil = psUtil;
     this.repoManager = repoManager;
+    this.retryHelper = retryHelper;
     this.serverIdent = serverIdent;
-    this.updateFactory = updateFactory;
     this.user = user;
     reset();
   }
 
   private void reset() {
+    updateFactory = null;
     ctl = null;
     repo = null;
     rw = null;
@@ -167,23 +171,38 @@
   public Result check(ChangeControl cc, @Nullable FixInput f) {
     checkNotNull(cc);
     try {
-      reset();
-      ctl = cc;
-      fix = f;
-      checkImpl();
-      return result();
-    } finally {
-      if (rw != null) {
-        rw.getObjectReader().close();
-        rw.close();
-        oi.close();
-      }
-      if (repo != null) {
-        repo.close();
-      }
+      return retryHelper.execute(
+          buf -> {
+            try {
+              reset();
+              this.updateFactory = buf;
+              ctl = cc;
+              fix = f;
+              checkImpl();
+              return result();
+            } finally {
+              if (rw != null) {
+                rw.getObjectReader().close();
+                rw.close();
+                oi.close();
+              }
+              if (repo != null) {
+                repo.close();
+              }
+            }
+          });
+    } catch (RestApiException e) {
+      return logAndReturnOneProblem(e, cc, "Error checking change: " + e.getMessage());
+    } catch (UpdateException e) {
+      return logAndReturnOneProblem(e, cc, "Error checking change");
     }
   }
 
+  private Result logAndReturnOneProblem(Exception e, ChangeControl cc, String problem) {
+    log.warn("Error checking change " + cc.getId(), e);
+    return Result.create(cc, ImmutableList.of(problem(problem)));
+  }
+
   private void checkImpl() {
     checkOwner();
     checkCurrentPatchSetEntity();
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/DeleteComment.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/DeleteComment.java
index d358184..17665b0 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/DeleteComment.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/DeleteComment.java
@@ -21,7 +21,6 @@
 import com.google.gerrit.extensions.restapi.ResourceConflictException;
 import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
 import com.google.gerrit.extensions.restapi.RestApiException;
-import com.google.gerrit.extensions.restapi.RestModifyView;
 import com.google.gerrit.reviewdb.client.Comment;
 import com.google.gerrit.reviewdb.client.PatchSet;
 import com.google.gerrit.reviewdb.server.ReviewDb;
@@ -34,6 +33,8 @@
 import com.google.gerrit.server.update.BatchUpdate;
 import com.google.gerrit.server.update.BatchUpdateOp;
 import com.google.gerrit.server.update.ChangeContext;
+import com.google.gerrit.server.update.RetryHelper;
+import com.google.gerrit.server.update.RetryingRestModifyView;
 import com.google.gerrit.server.update.UpdateException;
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
@@ -45,12 +46,12 @@
 import org.eclipse.jgit.errors.ConfigInvalidException;
 
 @Singleton
-public class DeleteComment implements RestModifyView<CommentResource, DeleteCommentInput> {
+public class DeleteComment
+    extends RetryingRestModifyView<CommentResource, DeleteCommentInput, CommentInfo> {
 
   private final Provider<CurrentUser> userProvider;
   private final Provider<ReviewDb> dbProvider;
   private final PermissionBackend permissionBackend;
-  private final BatchUpdate.Factory batchUpdateFactory;
   private final CommentsUtil commentsUtil;
   private final Provider<CommentJson> commentJson;
   private final ChangeNotes.Factory notesFactory;
@@ -60,21 +61,22 @@
       Provider<CurrentUser> userProvider,
       Provider<ReviewDb> dbProvider,
       PermissionBackend permissionBackend,
-      BatchUpdate.Factory batchUpdateFactory,
+      RetryHelper retryHelper,
       CommentsUtil commentsUtil,
       Provider<CommentJson> commentJson,
       ChangeNotes.Factory notesFactory) {
+    super(retryHelper);
     this.userProvider = userProvider;
     this.dbProvider = dbProvider;
     this.permissionBackend = permissionBackend;
-    this.batchUpdateFactory = batchUpdateFactory;
     this.commentsUtil = commentsUtil;
     this.commentJson = commentJson;
     this.notesFactory = notesFactory;
   }
 
   @Override
-  public CommentInfo apply(CommentResource rsrc, DeleteCommentInput input)
+  public CommentInfo applyImpl(
+      BatchUpdate.Factory batchUpdateFactory, CommentResource rsrc, DeleteCommentInput input)
       throws RestApiException, IOException, ConfigInvalidException, OrmException,
           PermissionBackendException, UpdateException {
     CurrentUser user = userProvider.get();
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/PublishChangeEdit.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/PublishChangeEdit.java
index 3acb93b..658b87b 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/PublishChangeEdit.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/PublishChangeEdit.java
@@ -25,10 +25,12 @@
 import com.google.gerrit.extensions.restapi.ResourceConflictException;
 import com.google.gerrit.extensions.restapi.Response;
 import com.google.gerrit.extensions.restapi.RestApiException;
-import com.google.gerrit.extensions.restapi.RestModifyView;
 import com.google.gerrit.extensions.restapi.RestView;
 import com.google.gerrit.server.edit.ChangeEdit;
 import com.google.gerrit.server.edit.ChangeEditUtil;
+import com.google.gerrit.server.update.BatchUpdate;
+import com.google.gerrit.server.update.RetryHelper;
+import com.google.gerrit.server.update.RetryingRestModifyView;
 import com.google.gerrit.server.update.UpdateException;
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
@@ -69,19 +71,22 @@
   }
 
   @Singleton
-  public static class Publish implements RestModifyView<ChangeResource, PublishChangeEditInput> {
+  public static class Publish
+      extends RetryingRestModifyView<ChangeResource, PublishChangeEditInput, Response<?>> {
 
     private final ChangeEditUtil editUtil;
     private final NotifyUtil notifyUtil;
 
     @Inject
-    Publish(ChangeEditUtil editUtil, NotifyUtil notifyUtil) {
+    Publish(RetryHelper retryHelper, ChangeEditUtil editUtil, NotifyUtil notifyUtil) {
+      super(retryHelper);
       this.editUtil = editUtil;
       this.notifyUtil = notifyUtil;
     }
 
     @Override
-    public Response<?> apply(ChangeResource rsrc, PublishChangeEditInput in)
+    protected Response<?> applyImpl(
+        BatchUpdate.Factory updateFactory, ChangeResource rsrc, PublishChangeEditInput in)
         throws IOException, OrmException, RestApiException, UpdateException {
       Capable r = rsrc.getControl().getProjectControl().canPushToAtLeastOneRef();
       if (r != Capable.OK) {
@@ -97,7 +102,11 @@
         in = new PublishChangeEditInput();
       }
       editUtil.publish(
-          rsrc.getControl(), edit.get(), in.notify, notifyUtil.resolveAccounts(in.notifyDetails));
+          updateFactory,
+          rsrc.getControl(),
+          edit.get(),
+          in.notify,
+          notifyUtil.resolveAccounts(in.notifyDetails));
       return Response.none();
     }
   }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/edit/ChangeEditUtil.java b/gerrit-server/src/main/java/com/google/gerrit/server/edit/ChangeEditUtil.java
index 1e11968..9160932 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/edit/ChangeEditUtil.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/edit/ChangeEditUtil.java
@@ -75,7 +75,6 @@
   private final Provider<ReviewDb> db;
   private final Provider<CurrentUser> user;
   private final ChangeKindCache changeKindCache;
-  private final BatchUpdate.Factory updateFactory;
   private final PatchSetUtil psUtil;
 
   @Inject
@@ -87,7 +86,6 @@
       Provider<ReviewDb> db,
       Provider<CurrentUser> user,
       ChangeKindCache changeKindCache,
-      BatchUpdate.Factory updateFactory,
       PatchSetUtil psUtil) {
     this.gitManager = gitManager;
     this.patchSetInserterFactory = patchSetInserterFactory;
@@ -96,7 +94,6 @@
     this.db = db;
     this.user = user;
     this.changeKindCache = changeKindCache;
-    this.updateFactory = updateFactory;
     this.psUtil = psUtil;
   }
 
@@ -158,6 +155,7 @@
   /**
    * Promote change edit to patch set, by squashing the edit into its parent.
    *
+   * @param updateFactory factory for creating updates.
    * @param ctl the {@code ChangeControl} of the change to which the change edit belongs
    * @param edit change edit to publish
    * @param notify Notify handling that defines to whom email notifications should be sent after the
@@ -169,6 +167,7 @@
    * @throws RestApiException
    */
   public void publish(
+      BatchUpdate.Factory updateFactory,
       ChangeControl ctl,
       final ChangeEdit edit,
       NotifyHandling notify,
@@ -226,17 +225,6 @@
               }
             });
         bu.execute();
-      } catch (UpdateException e) {
-        if (e.getCause() instanceof IOException
-            && e.getMessage()
-                .equals(
-                    String.format(
-                        "%s: Failed to delete ref %s: %s",
-                        IOException.class.getName(),
-                        edit.getRefName(),
-                        RefUpdate.Result.LOCK_FAILURE.name()))) {
-          throw new ResourceConflictException("edit ref was updated");
-        }
       }
 
       indexer.index(db.get(), inserter.getChange());
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/strategy/SubmitStrategy.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/strategy/SubmitStrategy.java
index f9b9add..e9ed294 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/strategy/SubmitStrategy.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/strategy/SubmitStrategy.java
@@ -103,7 +103,6 @@
 
     final AccountCache accountCache;
     final ApprovalsUtil approvalsUtil;
-    final BatchUpdate.Factory batchUpdateFactory;
     final ChangeControl.GenericFactory changeControlFactory;
     final ChangeMerged changeMerged;
     final ChangeMessagesUtil cmUtil;
@@ -143,7 +142,6 @@
     Arguments(
         AccountCache accountCache,
         ApprovalsUtil approvalsUtil,
-        BatchUpdate.Factory batchUpdateFactory,
         ChangeControl.GenericFactory changeControlFactory,
         ChangeMerged changeMerged,
         ChangeMessagesUtil cmUtil,
@@ -176,7 +174,6 @@
         @Assisted boolean dryrun) {
       this.accountCache = accountCache;
       this.approvalsUtil = approvalsUtil;
-      this.batchUpdateFactory = batchUpdateFactory;
       this.changeControlFactory = changeControlFactory;
       this.changeMerged = changeMerged;
       this.mergedSenderFactory = mergedSenderFactory;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/receive/MailProcessor.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/receive/MailProcessor.java
index 862da9f..0c2cf04 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/mail/receive/MailProcessor.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/mail/receive/MailProcessor.java
@@ -50,6 +50,7 @@
 import com.google.gerrit.server.update.BatchUpdateOp;
 import com.google.gerrit.server.update.ChangeContext;
 import com.google.gerrit.server.update.Context;
+import com.google.gerrit.server.update.RetryHelper;
 import com.google.gerrit.server.update.UpdateException;
 import com.google.gerrit.server.util.ManualRequestContext;
 import com.google.gerrit.server.util.OneOffRequestContext;
@@ -72,7 +73,7 @@
   private static final Logger log = LoggerFactory.getLogger(MailProcessor.class);
 
   private final AccountByEmailCache accountByEmailCache;
-  private final BatchUpdate.Factory buf;
+  private final RetryHelper retryHelper;
   private final ChangeMessagesUtil changeMessagesUtil;
   private final CommentsUtil commentsUtil;
   private final OneOffRequestContext oneOffRequestContext;
@@ -89,7 +90,7 @@
   @Inject
   public MailProcessor(
       AccountByEmailCache accountByEmailCache,
-      BatchUpdate.Factory buf,
+      RetryHelper retryHelper,
       ChangeMessagesUtil changeMessagesUtil,
       CommentsUtil commentsUtil,
       OneOffRequestContext oneOffRequestContext,
@@ -103,7 +104,7 @@
       AccountCache accountCache,
       @CanonicalWebUrl Provider<String> canonicalUrl) {
     this.accountByEmailCache = accountByEmailCache;
-    this.buf = buf;
+    this.retryHelper = retryHelper;
     this.changeMessagesUtil = changeMessagesUtil;
     this.commentsUtil = commentsUtil;
     this.oneOffRequestContext = oneOffRequestContext;
@@ -122,9 +123,17 @@
    * Parse comments from MailMessage and persist them on the change.
    *
    * @param message MailMessage to process.
-   * @throws OrmException
    */
-  public void process(MailMessage message) throws OrmException {
+  public void process(MailMessage message) throws RestApiException, UpdateException {
+    retryHelper.execute(
+        buf -> {
+          processImpl(buf, message);
+          return null;
+        });
+  }
+
+  private void processImpl(BatchUpdate.Factory buf, MailMessage message)
+      throws OrmException, UpdateException, RestApiException {
     for (DynamicMap.Entry<MailFilter> filter : mailFilters) {
       if (!filter.getProvider().get().shouldProcessMessage(message)) {
         log.warn(
@@ -200,11 +209,7 @@
       Op o = new Op(new PatchSet.Id(cd.getId(), metadata.patchSet), parsedComments, message.id());
       BatchUpdate batchUpdate = buf.create(cd.db(), project, ctx.getUser(), TimeUtil.nowTs());
       batchUpdate.addOp(cd.getId(), o);
-      try {
-        batchUpdate.execute();
-      } catch (UpdateException | RestApiException e) {
-        throw new OrmException(e);
-      }
+      batchUpdate.execute();
     }
   }
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/receive/MailReceiver.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/receive/MailReceiver.java
index 5068985..7c05478 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/mail/receive/MailReceiver.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/mail/receive/MailReceiver.java
@@ -16,10 +16,11 @@
 
 import com.google.common.annotations.VisibleForTesting;
 import com.google.gerrit.extensions.events.LifecycleListener;
+import com.google.gerrit.extensions.restapi.RestApiException;
 import com.google.gerrit.lifecycle.LifecycleModule;
 import com.google.gerrit.server.git.WorkQueue;
 import com.google.gerrit.server.mail.EmailSettings;
-import com.google.gwtorm.server.OrmException;
+import com.google.gerrit.server.update.UpdateException;
 import com.google.inject.Inject;
 import java.util.Collections;
 import java.util.HashSet;
@@ -132,7 +133,7 @@
                       try {
                         mailProcessor.process(m);
                         requestDeletion(m.id());
-                      } catch (OrmException e) {
+                      } catch (RestApiException | UpdateException e) {
                         log.error("Mail: Can't process message " + m.id() + " . Won't delete.", e);
                       }
                     });
@@ -141,7 +142,7 @@
         try {
           mailProcessor.process(m);
           requestDeletion(m.id());
-        } catch (OrmException e) {
+        } catch (RestApiException | UpdateException e) {
           log.error("Mail: Can't process messages. Won't delete.", e);
         }
       }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/PrimaryStorageMigrator.java b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/PrimaryStorageMigrator.java
index 3f0db77..8503f0a 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/PrimaryStorageMigrator.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/PrimaryStorageMigrator.java
@@ -52,6 +52,7 @@
 import com.google.gerrit.server.update.BatchUpdate;
 import com.google.gerrit.server.update.BatchUpdateOp;
 import com.google.gerrit.server.update.ChangeContext;
+import com.google.gerrit.server.update.RetryHelper;
 import com.google.gerrit.server.update.UpdateException;
 import com.google.gwtorm.server.AtomicUpdate;
 import com.google.gwtorm.server.OrmException;
@@ -82,7 +83,6 @@
   private static final Logger log = LoggerFactory.getLogger(PrimaryStorageMigrator.class);
 
   private final AllUsersName allUsers;
-  private final BatchUpdate.Factory batchUpdateFactory;
   private final ChangeControl.GenericFactory changeControlFactory;
   private final ChangeRebuilder rebuilder;
   private final ChangeUpdate.Factory updateFactory;
@@ -90,6 +90,7 @@
   private final InternalUser.Factory internalUserFactory;
   private final Provider<InternalChangeQuery> queryProvider;
   private final Provider<ReviewDb> db;
+  private final RetryHelper retryHelper;
 
   private final long skewMs;
   private final long timeoutMs;
@@ -106,7 +107,7 @@
       Provider<InternalChangeQuery> queryProvider,
       ChangeUpdate.Factory updateFactory,
       InternalUser.Factory internalUserFactory,
-      BatchUpdate.Factory batchUpdateFactory) {
+      RetryHelper retryHelper) {
     this(
         cfg,
         db,
@@ -118,7 +119,7 @@
         queryProvider,
         updateFactory,
         internalUserFactory,
-        batchUpdateFactory);
+        retryHelper);
   }
 
   @VisibleForTesting
@@ -133,7 +134,7 @@
       Provider<InternalChangeQuery> queryProvider,
       ChangeUpdate.Factory updateFactory,
       InternalUser.Factory internalUserFactory,
-      BatchUpdate.Factory batchUpdateFactory) {
+      RetryHelper retryHelper) {
     this.db = db;
     this.repoManager = repoManager;
     this.allUsers = allUsers;
@@ -143,7 +144,7 @@
     this.queryProvider = queryProvider;
     this.updateFactory = updateFactory;
     this.internalUserFactory = internalUserFactory;
-    this.batchUpdateFactory = batchUpdateFactory;
+    this.retryHelper = retryHelper;
     skewMs = NoteDbChangeState.getReadOnlySkew(cfg);
 
     String s = "notedb";
@@ -451,19 +452,27 @@
   private void releaseReadOnlyLeaseInNoteDb(Project.NameKey project, Change.Id id)
       throws OrmException {
     // Use a BatchUpdate since ReviewDb is primary at this point, so it needs to reflect the update.
-    try (BatchUpdate bu =
-        batchUpdateFactory.create(
-            db.get(), project, internalUserFactory.create(), TimeUtil.nowTs())) {
-      bu.addOp(
-          id,
-          new BatchUpdateOp() {
-            @Override
-            public boolean updateChange(ChangeContext ctx) {
-              ctx.getUpdate(ctx.getChange().currentPatchSetId()).setReadOnlyUntil(new Timestamp(0));
-              return true;
+    // (In practice retrying won't happen, since we aren't using fused updates at this point.)
+    try {
+      retryHelper.execute(
+          updateFactory -> {
+            try (BatchUpdate bu =
+                updateFactory.create(
+                    db.get(), project, internalUserFactory.create(), TimeUtil.nowTs())) {
+              bu.addOp(
+                  id,
+                  new BatchUpdateOp() {
+                    @Override
+                    public boolean updateChange(ChangeContext ctx) {
+                      ctx.getUpdate(ctx.getChange().currentPatchSetId())
+                          .setReadOnlyUntil(new Timestamp(0));
+                      return true;
+                    }
+                  });
+              bu.execute();
+              return null;
             }
           });
-      bu.execute();
     } catch (RestApiException | UpdateException e) {
       throw new OrmException(e);
     }
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/query/change/AbstractQueryChangesTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/query/change/AbstractQueryChangesTest.java
index ac421f0..34536ab 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/query/change/AbstractQueryChangesTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/query/change/AbstractQueryChangesTest.java
@@ -70,6 +70,8 @@
 import com.google.gerrit.server.account.AccountCache;
 import com.google.gerrit.server.account.AccountManager;
 import com.google.gerrit.server.account.AuthRequest;
+import com.google.gerrit.server.account.externalids.ExternalId;
+import com.google.gerrit.server.account.externalids.ExternalIdsUpdate;
 import com.google.gerrit.server.change.ChangeInserter;
 import com.google.gerrit.server.change.ChangeTriplet;
 import com.google.gerrit.server.change.PatchSetInserter;
@@ -166,6 +168,7 @@
   @Inject protected ThreadLocalRequestContext requestContext;
   @Inject protected ProjectCache projectCache;
   @Inject protected MetaDataUpdate.Server metaDataUpdateFactory;
+  @Inject protected ExternalIdsUpdate.Server externalIdsUpdate;
 
   // Only for use in setting up/tearing down injector; other users should use schemaFactory.
   @Inject private InMemoryDatabase inMemoryDatabase;
@@ -198,7 +201,9 @@
 
     userId = accountManager.authenticate(AuthRequest.forUser("user")).getAccountId();
     Account userAccount = db.accounts().get(userId);
-    userAccount.setPreferredEmail("user@example.com");
+    String email = "user@example.com";
+    externalIdsUpdate.create().insert(ExternalId.createEmail(userId, email));
+    userAccount.setPreferredEmail(email);
     db.accounts().update(ImmutableList.of(userAccount));
     user = userFactory.create(userId);
     requestContext.setContext(newRequestContext(userAccount.getId()));
diff --git a/lib/prolog/BUILD b/lib/prolog/BUILD
index 875f135..f6b4c5f 100644
--- a/lib/prolog/BUILD
+++ b/lib/prolog/BUILD
@@ -6,6 +6,13 @@
 )
 
 java_library(
+    name = "runtime-neverlink",
+    data = ["//lib:LICENSE-prologcafe"],
+    visibility = ["//visibility:public"],
+    exports = ["@prolog_runtime//jar:neverlink"],
+)
+
+java_library(
     name = "compiler",
     data = ["//lib:LICENSE-prologcafe"],
     visibility = ["//visibility:public"],
diff --git a/lib/prolog/prolog.bzl b/lib/prolog/prolog.bzl
index cae85ad..43a8bab 100644
--- a/lib/prolog/prolog.bzl
+++ b/lib/prolog/prolog.bzl
@@ -12,14 +12,12 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-load("//tools/bzl:genrule2.bzl", "genrule2")
-
 def prolog_cafe_library(
     name,
     srcs,
     deps = [],
     **kwargs):
-  genrule2(
+  native.genrule(
     name = name + '__pl2j',
     cmd = '$(location //lib/prolog:compiler_bin) ' +
       '$$(dirname $@) $@ ' +
@@ -31,6 +29,6 @@
   native.java_library(
     name = name,
     srcs = [':' + name + '__pl2j'],
-    deps = ['//lib/prolog:runtime'] + deps,
+    deps = ['//lib/prolog:runtime-neverlink'] + deps,
     **kwargs
   )
diff --git a/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata-it_test.html b/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata-it_test.html
index 1c5dd59..ae45da4 100644
--- a/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata-it_test.html
+++ b/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata-it_test.html
@@ -40,76 +40,76 @@
 </test-fixture>
 
 <script>
-  suite('gr-change-metadata integration tests', function() {
-    var sandbox;
-    var element;
+  suite('gr-change-metadata integration tests', () => {
+    let sandbox;
+    let element;
 
-    var sectionSelectors = [
+    const sectionSelectors = [
       'section.assignee',
       'section.labelStatus',
       'section.strategy',
       'section.topic',
     ];
 
-    var getStyle = function(selector, name) {
+    const getStyle = function(selector, name) {
       return window.getComputedStyle(
           Polymer.dom(element.root).querySelector(selector))[name];
     };
 
-    setup(function() {
+    setup(() => {
       sandbox = sinon.sandbox.create();
       stub('gr-change-metadata', {
-        _computeShowLabelStatus: function() { return true; },
-        _computeShowReviewersByState: function() { return true; },
-        ready: function() {
+        _computeShowLabelStatus() { return true; },
+        _computeShowReviewersByState() { return true; },
+        ready() {
           this.change = {labels: []};
           this.serverConfig = {};
         },
       });
     });
 
-    teardown(function() {
+    teardown(() => {
       Gerrit._pluginsPending = -1;
       Gerrit._allPluginsPromise = undefined;
       sandbox.restore();
     });
 
-    suite('by default', function() {
-      setup(function(done) {
+    suite('by default', () => {
+      setup(done => {
         element = fixture('element');
         flush(done);
       });
 
-      sectionSelectors.forEach(function(sectionSelector) {
-        test(sectionSelector + ' does not have display: none', function() {
+      for (const sectionSelector of sectionSelectors) {
+        test(sectionSelector + ' does not have display: none', () => {
           assert.notEqual(getStyle(sectionSelector, 'display'), 'none');
         });
-      });
+      }
     });
 
-    suite('with plugin style', function() {
-      setup(function(done) {
-        var pluginHost = fixture('plugin-host');
+    suite('with plugin style', () => {
+      setup(done => {
+        const pluginHost = fixture('plugin-host');
         pluginHost.config = {
           js_resource_paths: [],
           html_resource_paths: [
             new URL('test/plugin.html', window.location.href).toString(),
-          ]
+          ],
         };
         element = fixture('element');
-        var importSpy = sandbox.spy(element.$.externalStyle, '_import');
-        Gerrit.awaitPluginsLoaded().then(function() {
-          Promise.all(importSpy.returnValues).then(function() {
+        const importSpy = sandbox.spy(element.$.externalStyle, '_import');
+        Gerrit.awaitPluginsLoaded().then(() => {
+          Promise.all(importSpy.returnValues).then(() => {
             flush(done);
           });
         });
       });
 
-      sectionSelectors.forEach(function(sectionSelector) {
-        test(sectionSelector + ' may have display: none', function() {
+      for (const sectionSelector of sectionSelectors) {
+        test(sectionSelector + ' may have display: none', () => {
           assert.equal(getStyle(sectionSelector, 'display'), 'none');
         });
-      });
+      }
     });
   });
 </script>
diff --git a/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata.js b/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata.js
index 4527104..62fe5ed 100644
--- a/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata.js
+++ b/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata.js
@@ -14,7 +14,7 @@
 (function() {
   'use strict';
 
-  var SubmitTypeLabel = {
+  const SubmitTypeLabel = {
     FAST_FORWARD_ONLY: 'Fast Forward Only',
     MERGE_IF_NECESSARY: 'Merge if Necessary',
     REBASE_IF_NECESSARY: 'Rebase if Necessary',
@@ -61,15 +61,15 @@
       '_assigneeChanged(_assignee.*)',
     ],
 
-    _changeChanged: function(change) {
+    _changeChanged(change) {
       this._assignee = change.assignee ? [change.assignee] : [];
     },
 
-    _assigneeChanged: function(assigneeRecord) {
+    _assigneeChanged(assigneeRecord) {
       if (!this.change) { return; }
-      var assignee = assigneeRecord.base;
+      const assignee = assigneeRecord.base;
       if (assignee.length) {
-        var acct = assignee[0];
+        const acct = assignee[0];
         if (this.change.assignee &&
             acct._account_id === this.change.assignee._account_id) { return; }
         this.set(['change', 'assignee'], acct);
@@ -81,7 +81,7 @@
       }
     },
 
-    _computeHideStrategy: function(change) {
+    _computeHideStrategy(change) {
       return !this.changeIsOpen(change.status);
     },
 
@@ -89,7 +89,7 @@
      * This is a whitelist of web link types that provide direct links to
      * the commit in the url property.
      */
-    _isCommitWebLink: function(link) {
+    _isCommitWebLink(link) {
       return link.name === 'gitiles' || link.name === 'gitweb';
     },
 
@@ -99,34 +99,34 @@
      * an existential check can be used to hide or show the webLinks
      * section.
      */
-    _computeWebLinks: function(commitInfo) {
-      if (!commitInfo || !commitInfo.web_links) { return null }
+    _computeWebLinks(commitInfo) {
+      if (!commitInfo || !commitInfo.web_links) { return null; }
       // We are already displaying these types of links elsewhere,
       // don't include in the metadata links section.
-      var webLinks = commitInfo.web_links.filter(
-          function(l) {return !this._isCommitWebLink(l); }.bind(this));
+      const webLinks = commitInfo.web_links.filter(
+          l => {return !this._isCommitWebLink(l); });
 
       return webLinks.length ? webLinks : null;
     },
 
-    _computeStrategy: function(change) {
+    _computeStrategy(change) {
       return SubmitTypeLabel[change.submit_type];
     },
 
-    _computeLabelNames: function(labels) {
+    _computeLabelNames(labels) {
       return Object.keys(labels).sort();
     },
 
-    _computeLabelValues: function(labelName, _labels) {
-      var result = [];
-      var labels = _labels.base;
-      var t = labels[labelName];
+    _computeLabelValues(labelName, _labels) {
+      const result = [];
+      const labels = _labels.base;
+      const t = labels[labelName];
       if (!t) { return result; }
-      var approvals = t.all || [];
-      approvals.forEach(function(label) {
+      const approvals = t.all || [];
+      for (const label of approvals) {
         if (label.value && label.value != labels[labelName].default_value) {
-          var labelClassName;
-          var labelValPrefix = '';
+          let labelClassName;
+          let labelValPrefix = '';
           if (label.value > 0) {
             labelValPrefix = '+';
             labelClassName = 'approved';
@@ -139,35 +139,35 @@
             account: label,
           });
         }
-      });
+      }
       return result;
     },
 
-    _computeValueTooltip: function(score, labelName) {
-      var values = this.change.labels[labelName].values;
+    _computeValueTooltip(score, labelName) {
+      const values = this.change.labels[labelName].values;
       return values[score];
     },
 
-    _handleTopicChanged: function(e, topic) {
+    _handleTopicChanged(e, topic) {
       if (!topic.length) { topic = null; }
       this.$.restAPI.setChangeTopic(this.change._number, topic);
     },
 
-    _computeTopicReadOnly: function(mutable, change) {
+    _computeTopicReadOnly(mutable, change) {
       return !mutable || !change.actions.topic || !change.actions.topic.enabled;
     },
 
-    _computeAssigneeReadOnly: function(mutable, change) {
+    _computeAssigneeReadOnly(mutable, change) {
       return !mutable ||
           !change.actions.assignee ||
           !change.actions.assignee.enabled;
     },
 
-    _computeTopicPlaceholder: function(_topicReadOnly) {
+    _computeTopicPlaceholder(_topicReadOnly) {
       return _topicReadOnly ? 'No Topic' : 'Click to add topic';
     },
 
-    _computeShowReviewersByState: function(serverConfig) {
+    _computeShowReviewersByState(serverConfig) {
       return !!serverConfig.note_db_enabled;
     },
 
@@ -181,9 +181,9 @@
      * @param {boolean} mutable this.mutable describes whether the
      *     change-metadata section is modifiable by the current user.
      */
-    _computeCanDeleteVote: function(reviewer, mutable) {
+    _computeCanDeleteVote(reviewer, mutable) {
       if (!mutable) { return false; }
-      for (var i = 0; i < this.change.removable_reviewers.length; i++) {
+      for (let i = 0; i < this.change.removable_reviewers.length; i++) {
         if (this.change.removable_reviewers[i]._account_id ===
             reviewer._account_id) {
           return true;
@@ -192,20 +192,20 @@
       return false;
     },
 
-    _onDeleteVote: function(e) {
+    _onDeleteVote(e) {
       e.preventDefault();
-      var target = Polymer.dom(e).rootTarget;
-      var labelName = target.labelName;
-      var accountID = parseInt(target.getAttribute('data-account-id'), 10);
+      const target = Polymer.dom(e).rootTarget;
+      const labelName = target.labelName;
+      const accountID = parseInt(target.getAttribute('data-account-id'), 10);
       this._xhrPromise =
           this.$.restAPI.deleteVote(this.change.id, accountID, labelName)
-          .then(function(response) {
+          .then(response => {
             if (!response.ok) { return response; }
-            var label = this.change.labels[labelName];
-            var labels = label.all || [];
-            for (var i = 0; i < labels.length; i++) {
+            const label = this.change.labels[labelName];
+            const labels = label.all || [];
+            for (let i = 0; i < labels.length; i++) {
               if (labels[i]._account_id === accountID) {
-                for (var key in label) {
+                for (const key in label) {
                   if (label.hasOwnProperty(key) &&
                       label[key]._account_id === accountID) {
                     // Remove special label field, keeping change label values
@@ -217,19 +217,20 @@
                 break;
               }
             }
-          }.bind(this));
+          });
     },
 
-    _computeShowLabelStatus: function(change) {
-      var isNewChange = change.status === this.ChangeStatus.NEW;
-      var hasLabels = Object.keys(change.labels).length > 0;
+    _computeShowLabelStatus(change) {
+      const isNewChange = change.status === this.ChangeStatus.NEW;
+      const hasLabels = Object.keys(change.labels).length > 0;
       return isNewChange && hasLabels;
     },
 
-    _computeMissingLabels: function(labels) {
-      var missingLabels = [];
-      for (var label in labels) {
-        var obj = labels[label];
+    _computeMissingLabels(labels) {
+      const missingLabels = [];
+      for (const label in labels) {
+        if (!labels.hasOwnProperty(label)) { continue; }
+        const obj = labels[label];
         if (!obj.optional && !obj.approved) {
           missingLabels.push(label);
         }
@@ -237,26 +238,26 @@
       return missingLabels;
     },
 
-    _computeMissingLabelsHeader: function(labels) {
+    _computeMissingLabelsHeader(labels) {
       return 'Needs label' +
           (this._computeMissingLabels(labels).length > 1 ? 's' : '') + ':';
     },
 
-    _showMissingLabels: function(labels) {
+    _showMissingLabels(labels) {
       return !!this._computeMissingLabels(labels).length;
     },
 
-    _showMissingRequirements: function(labels, workInProgress) {
+    _showMissingRequirements(labels, workInProgress) {
       return workInProgress || this._showMissingLabels(labels);
     },
 
-    _computeProjectURL: function(project) {
+    _computeProjectURL(project) {
       return this.getBaseUrl() + '/q/project:' +
         this.encodeURL(project, false);
     },
 
-    _computeBranchURL: function(project, branch) {
-      var status;
+    _computeBranchURL(project, branch) {
+      let status;
       if (this.change.status == this.ChangeStatus.NEW) {
         status = 'open';
       } else {
@@ -268,13 +269,13 @@
               ' status:' + this.encodeURL(status, false);
     },
 
-    _computeTopicURL: function(topic) {
+    _computeTopicURL(topic) {
       return this.getBaseUrl() + '/q/topic:' +
           this.encodeURL('"' + topic + '"', false) +
             '+(status:open OR status:merged)';
     },
 
-    _handleTopicRemoved: function() {
+    _handleTopicRemoved() {
       this.set(['change', 'topic'], '');
       this.$.restAPI.setChangeTopic(this.change._number, null);
     },
diff --git a/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata_test.html b/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata_test.html
index 2840c1f..5003a68 100644
--- a/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata_test.html
+++ b/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata_test.html
@@ -33,25 +33,25 @@
 </test-fixture>
 
 <script>
-  suite('gr-change-metadata tests', function() {
-    var element;
-    var sandbox;
+  suite('gr-change-metadata tests', () => {
+    let element;
+    let sandbox;
 
-    setup(function() {
+    setup(() => {
       sandbox = sinon.sandbox.create();
       stub('gr-rest-api-interface', {
-        getConfig: function() { return Promise.resolve({}); },
-        getLoggedIn: function() { return Promise.resolve(false); },
+        getConfig() { return Promise.resolve({}); },
+        getLoggedIn() { return Promise.resolve(false); },
       });
 
       element = fixture('basic');
     });
 
-    teardown(function() {
+    teardown(() => {
       sandbox.restore();
     });
 
-    test('computed fields', function() {
+    test('computed fields', () => {
       assert.isFalse(element._computeHideStrategy({status: 'NEW'}));
       assert.isFalse(element._computeHideStrategy({status: 'DRAFT'}));
       assert.isTrue(element._computeHideStrategy({status: 'MERGED'}));
@@ -60,22 +60,22 @@
           'Cherry Pick');
     });
 
-    test('show strategy for open change', function() {
+    test('show strategy for open change', () => {
       element.change = {status: 'NEW', submit_type: 'CHERRY_PICK', labels: {}};
       flushAsynchronousOperations();
-      var strategy = element.$$('.strategy');
+      const strategy = element.$$('.strategy');
       assert.ok(strategy);
       assert.isFalse(strategy.hasAttribute('hidden'));
       assert.equal(strategy.children[1].innerHTML, 'Cherry Pick');
     });
 
-    test('hide strategy for closed change', function() {
+    test('hide strategy for closed change', () => {
       element.change = {status: 'MERGED', labels: {}};
       flushAsynchronousOperations();
       assert.isTrue(element.$$('.strategy').hasAttribute('hidden'));
     });
 
-    test('show CC section when NoteDb enabled', function() {
+    test('show CC section when NoteDb enabled', () => {
       function hasCc() {
         return element._showReviewersByState;
       }
@@ -87,9 +87,9 @@
       assert.isTrue(hasCc());
     });
 
-    test('computes submit status', function() {
-      var showMissingLabels = false;
-      sandbox.stub(element, '_showMissingLabels', function() {
+    test('computes submit status', () => {
+      let showMissingLabels = false;
+      sandbox.stub(element, '_showMissingLabels', () => {
         return showMissingLabels;
       });
       assert.isFalse(element._showMissingRequirements(null, false));
@@ -98,8 +98,8 @@
       assert.isTrue(element._showMissingRequirements(null, false));
     });
 
-    test('show missing labels', function() {
-      var labels = {};
+    test('show missing labels', () => {
+      let labels = {};
       assert.isFalse(element._showMissingLabels(labels));
       labels = {test: {}};
       assert.isTrue(element._showMissingLabels(labels));
@@ -116,25 +116,25 @@
           ['test', 'test2']);
     });
 
-    test('weblinks hidden when no weblinks', function() {
+    test('weblinks hidden when no weblinks', () => {
       element.commitInfo = {};
       flushAsynchronousOperations();
-      var webLinks = element.$.webLinks;
+      const webLinks = element.$.webLinks;
       assert.isTrue(webLinks.hasAttribute('hidden'));
     });
 
-    test('weblinks hidden when only gitiles weblink', function() {
+    test('weblinks hidden when only gitiles weblink', () => {
       element.commitInfo = {web_links: [{name: 'gitiles', url: '#'}]};
       flushAsynchronousOperations();
-      var webLinks = element.$.webLinks;
+      const webLinks = element.$.webLinks;
       assert.isTrue(webLinks.hasAttribute('hidden'));
       assert.equal(element._computeWebLinks(element.commitInfo), null);
     });
 
-    test('weblinks are visible when other weblinks', function() {
+    test('weblinks are visible when other weblinks', () => {
       element.commitInfo = {web_links: [{name: 'test', url: '#'}]};
       flushAsynchronousOperations();
-      var webLinks = element.$.webLinks;
+      const webLinks = element.$.webLinks;
       assert.isFalse(webLinks.hasAttribute('hidden'));
       assert.equal(element._computeWebLinks(element.commitInfo).length, 1);
       // With two non-gitiles weblinks, there are two returned.
@@ -143,18 +143,18 @@
       assert.equal(element._computeWebLinks(element.commitInfo).length, 2);
     });
 
-    test('weblinks are visible when gitiles and other weblinks', function() {
+    test('weblinks are visible when gitiles and other weblinks', () => {
       element.commitInfo = {
         web_links: [{name: 'test', url: '#'}, {name: 'gitiles', url: '#'}]};
       flushAsynchronousOperations();
-      var webLinks = element.$.webLinks;
+      const webLinks = element.$.webLinks;
       assert.isFalse(webLinks.hasAttribute('hidden'));
       // Only the non-gitiles weblink is returned.
       assert.equal(element._computeWebLinks(element.commitInfo).length, 1);
     });
 
-    test('determines whether to show "Ready to Submit" label', function() {
-      var showMissingSpy = sandbox.spy(element, '_showMissingRequirements');
+    test('determines whether to show "Ready to Submit" label', () => {
+      const showMissingSpy = sandbox.spy(element, '_showMissingRequirements');
       element.change = {status: 'NEW', submit_type: 'CHERRY_PICK', labels: {
         test: {
           all: [{_account_id: 1, name: 'bojack', value: 1}],
@@ -166,9 +166,9 @@
       assert.isTrue(showMissingSpy.called);
     });
 
-    suite('Topic removal', function() {
-      var change;
-      setup(function() {
+    suite('Topic removal', () => {
+      let change;
+      setup(() => {
         change = {
           _number: 'the number',
           actions: {
@@ -189,8 +189,8 @@
         };
       });
 
-      test('_computeTopicReadOnly', function() {
-        var mutable = false;
+      test('_computeTopicReadOnly', () => {
+        let mutable = false;
         assert.isTrue(element._computeTopicReadOnly(mutable, change));
         mutable = true;
         assert.isTrue(element._computeTopicReadOnly(mutable, change));
@@ -200,26 +200,26 @@
         assert.isTrue(element._computeTopicReadOnly(mutable, change));
       });
 
-      test('topic read only hides delete button', function() {
+      test('topic read only hides delete button', () => {
         element.mutable = false;
         element.change = change;
         flushAsynchronousOperations();
-        var button = element.$$('gr-linked-chip').$$('gr-button');
+        const button = element.$$('gr-linked-chip').$$('gr-button');
         assert.isTrue(button.hasAttribute('hidden'));
       });
 
-      test('topic not read only does not hide delete button', function() {
+      test('topic not read only does not hide delete button', () => {
         element.mutable = true;
         change.actions.topic.enabled = true;
         element.change = change;
         flushAsynchronousOperations();
-        var button = element.$$('gr-linked-chip').$$('gr-button');
+        const button = element.$$('gr-linked-chip').$$('gr-button');
         assert.isFalse(button.hasAttribute('hidden'));
       });
     });
 
-    suite('remove reviewer votes', function() {
-      setup(function() {
+    suite('remove reviewer votes', () => {
+      setup(() => {
         sandbox.stub(element, '_computeValueTooltip').returns('');
         sandbox.stub(element, '_computeTopicReadOnly').returns(true);
         element.change = {
@@ -240,30 +240,39 @@
         };
       });
 
-      test('_computeCanDeleteVote hides delete button', function() {
+      test('_computeCanDeleteVote hides delete button', () => {
         flushAsynchronousOperations();
-        var button = element.$$('gr-account-chip').$$('gr-button');
+        const button = element.$$('gr-account-chip').$$('gr-button');
         assert.isTrue(button.hasAttribute('hidden'));
         element.mutable = true;
         assert.isTrue(button.hasAttribute('hidden'));
       });
 
-      test('_computeCanDeleteVote shows delete button', function() {
+      test('_computeCanDeleteVote shows delete button', () => {
         element.change.removable_reviewers = [
           {
             _account_id: 1,
             name: 'bojack',
-          }
+          },
         ];
         element.mutable = true;
         flushAsynchronousOperations();
-        var button = element.$$('gr-account-chip').$$('gr-button');
+        const button = element.$$('gr-account-chip').$$('gr-button');
         assert.isFalse(button.hasAttribute('hidden'));
       });
 
-      test('deletes votes', function(done) {
+      test('deletes votes', done => {
         sandbox.stub(element.$.restAPI, 'deleteVote')
-            .returns(Promise.resolve({'ok': true}));
+            .returns(Promise.resolve({ok: true}));
+        const spliceStub = sandbox.stub(element, 'splice', (path, index,
+            length) => {
+          assert.deepEqual(path, ['change.labels', 'test', 'all']);
+          assert.equal(index, 0);
+          assert.equal(length, 1);
+          assert.notOk(element.change.labels.test.recommended);
+          spliceStub.restore();
+          done();
+        });
         element.change.removable_reviewers = [
           {
             _account_id: 1,
@@ -273,70 +282,60 @@
         element.change.labels.test.recommended = {_account_id: 1};
         element.mutable = true;
         flushAsynchronousOperations();
-        var button = element.$$('gr-account-chip').$$('gr-button');
+        const button = element.$$('gr-account-chip').$$('gr-button');
         MockInteractions.tap(button);
-        flushAsynchronousOperations();
-        var spliceStub = sinon.stub(element, 'splice',
-            function(path, index, length) {
-          assert.deepEqual(path, ['change.labels', 'test', 'all']);
-          assert.equal(index, 0);
-          assert.equal(length, 1);
-          assert.notOk(element.change.labels.test.recommended);
-          spliceStub.restore();
-          done();
-        });
       });
 
-      test('changing topic calls setChangeTopic', function() {
-        var topicStub = sandbox.stub(element.$.restAPI, 'setChangeTopic',
-            function() {});
+      test('changing topic calls setChangeTopic', () => {
+        const topicStub = sandbox.stub(element.$.restAPI, 'setChangeTopic',
+            () => {});
         element._handleTopicChanged({}, 'the new topic');
         assert.isTrue(topicStub.calledWith('the number', 'the new topic'));
       });
 
-      test('topic href has quotes', function() {
-        var hrefArr = element._computeTopicURL('test')
+      test('topic href has quotes', () => {
+        const hrefArr = element._computeTopicURL('test')
             .split('%2522'); // Double-escaped quote.
         assert.equal(hrefArr[1], 'test');
       });
 
-      test('clicking x on topic chip removes topic', function() {
-        var topicStub = sandbox.stub(element.$.restAPI, 'setChangeTopic');
+      test('clicking x on topic chip removes topic', () => {
+        const topicStub = sandbox.stub(element.$.restAPI, 'setChangeTopic');
         flushAsynchronousOperations();
-        var remove = element.$$('gr-linked-chip').$.remove;
+        const remove = element.$$('gr-linked-chip').$.remove;
         MockInteractions.tap(remove);
         assert.equal(element.change.topic, '');
         assert.isTrue(topicStub.called);
       });
 
-      suite('assignee field', function() {
-        var dummyAccount = {
+      suite('assignee field', () => {
+        const dummyAccount = {
           _account_id: 1,
           name: 'bojack',
         };
-        var change = {
+        const change = {
           actions: {
             assignee: {enabled: false},
           },
           assignee: dummyAccount,
         };
-        var deleteStub;
-        var setStub;
+        let deleteStub;
+        let setStub;
 
-        setup(function() {
+        setup(() => {
           deleteStub = sandbox.stub(element.$.restAPI, 'deleteAssignee');
           setStub = sandbox.stub(element.$.restAPI, 'setAssignee');
         });
 
-        test('changing change recomputes _assignee', function() {
+        test('changing change recomputes _assignee', () => {
           assert.isFalse(!!element._assignee.length);
-          var change = element.change;
+          const change = element.change;
           change.assignee = dummyAccount;
           element._changeChanged(change);
           assert.deepEqual(element._assignee[0], dummyAccount);
         });
 
-        test('modifying _assignee calls API', function() {
+        test('modifying _assignee calls API', () => {
           assert.isFalse(!!element._assignee.length);
           element.set('_assignee', [dummyAccount]);
           assert.isTrue(setStub.calledOnce);
@@ -350,8 +349,8 @@
           assert.isTrue(deleteStub.calledOnce);
         });
 
-        test('_computeAssigneeReadOnly', function() {
-          var mutable = false;
+        test('_computeAssigneeReadOnly', () => {
+          let mutable = false;
           assert.isTrue(element._computeAssigneeReadOnly(mutable, change));
           mutable = true;
           assert.isTrue(element._computeAssigneeReadOnly(mutable, change));
diff --git a/polygerrit-ui/app/elements/change/gr-change-metadata/test/plugin.html b/polygerrit-ui/app/elements/change/gr-change-metadata/test/plugin.html
index 1cd3138..d0ed4a1 100644
--- a/polygerrit-ui/app/elements/change/gr-change-metadata/test/plugin.html
+++ b/polygerrit-ui/app/elements/change/gr-change-metadata/test/plugin.html
@@ -1,6 +1,6 @@
 <dom-module id="my-plugin">
   <script>
-    Gerrit.install(function(plugin) {
+    Gerrit.install(plugin => {
       plugin.registerStyleModule('change-metadata', 'my-plugin-style');
     });
   </script>
diff --git a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.html b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.html
index 392b7ae..2be6ffe 100644
--- a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.html
+++ b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.html
@@ -118,7 +118,7 @@
         font-family: var(--monospace-font-family);
         margin-right: 1em;
         margin-bottom: 1em;
-        max-width: 72ch;
+        max-width: var(--commit-message-max-width, 72ch);;
       }
       .commitMessage gr-linked-text {
         overflow: auto;
@@ -230,7 +230,11 @@
         margin-left: 1em;
         padding-top: var(--related-change-btn-top-padding, 0);
       }
-
+      @media screen and (min-width: 80em) {
+        .commitMessage {
+          max-width: var(--commit-message-max-width, 100ch);
+        }
+      }
       /* NOTE: If you update this breakpoint, also update the
       BREAKPOINT_RELATED_MED in the JS */
       @media screen and (max-width: 60em) {
diff --git a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.js b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.js
index 06db65f..e6607ff 100644
--- a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.js
+++ b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.js
@@ -14,20 +14,20 @@
 (function() {
   'use strict';
 
-  var CHANGE_ID_ERROR = {
+  const CHANGE_ID_ERROR = {
     MISMATCH: 'mismatch',
     MISSING: 'missing',
   };
-  var CHANGE_ID_REGEX_PATTERN = /^Change-Id\:\s(I[0-9a-f]{8,40})/gm;
-  var COMMENT_SAVE = 'Saving... Try again after all comments are saved.';
+  const CHANGE_ID_REGEX_PATTERN = /^Change-Id\:\s(I[0-9a-f]{8,40})/gm;
+  const COMMENT_SAVE = 'Saving... Try again after all comments are saved.';
 
-  var MIN_LINES_FOR_COMMIT_COLLAPSE = 30;
-  var DEFAULT_NUM_FILES_SHOWN = 200;
+  const MIN_LINES_FOR_COMMIT_COLLAPSE = 30;
+  const DEFAULT_NUM_FILES_SHOWN = 200;
 
   // Maximum length for patch set descriptions.
-  var PATCH_DESC_MAX_LENGTH = 500;
-  var REVIEWERS_REGEX = /^R=/gm;
-  var MIN_CHECK_INTERVAL_SECS = 0;
+  const PATCH_DESC_MAX_LENGTH = 500;
+  const REVIEWERS_REGEX = /^R=/gm;
+  const MIN_CHECK_INTERVAL_SECS = 0;
 
   // These are the same as the breakpoint set in CSS. Make sure both are changed
   // together.
@@ -72,7 +72,7 @@
       viewState: {
         type: Object,
         notify: true,
-        value: function() { return {}; },
+        value() { return {}; },
       },
       backPage: String,
       hasParent: Boolean,
@@ -82,7 +82,7 @@
       },
       keyEventTarget: {
         type: Object,
-        value: function() { return document.body; },
+        value() { return document.body; },
       },
       _diffPrefs: Object,
       _numFilesShown: {
@@ -107,7 +107,7 @@
       _changeNum: String,
       _diffDrafts: {
         type: Object,
-        value: function() { return {}; },
+        value() { return {}; },
       },
       _editingCommitMessage: {
         type: Boolean,
@@ -205,15 +205,15 @@
       ',': '_handleCommaKey',
     },
 
-    attached: function() {
-      this._getLoggedIn().then(function(loggedIn) {
+    attached() {
+      this._getLoggedIn().then(loggedIn => {
         this._loggedIn = loggedIn;
         if (loggedIn) {
-          this.$.restAPI.getAccount().then(function(acct) {
+          this.$.restAPI.getAccount().then(acct => {
             this._account = acct;
-          }.bind(this));
+          });
         }
-      }.bind(this));
+      });
 
       this._numFilesShown = this.viewState.numFilesShown ?
           this.viewState.numFilesShown : DEFAULT_NUM_FILES_SHOWN;
@@ -229,7 +229,7 @@
       this.listen(document, 'visibilitychange', '_handleVisibilityChange');
     },
 
-    detached: function() {
+    detached() {
       this.unlisten(window, 'scroll', '_handleScroll');
       this.unlisten(document, 'visibilitychange', '_handleVisibilityChange');
 
@@ -238,51 +238,51 @@
       }
     },
 
-    _computePrefsButtonHidden: function(prefs, loggedIn) {
+    _computePrefsButtonHidden(prefs, loggedIn) {
       return !loggedIn || !prefs;
     },
 
-    _handleEditCommitMessage: function(e) {
+    _handleEditCommitMessage(e) {
       this._editingCommitMessage = true;
       this.$.commitMessageEditor.focusTextarea();
     },
 
-    _handleCommitMessageSave: function(e) {
-      var message = e.detail.content;
+    _handleCommitMessageSave(e) {
+      const message = e.detail.content;
 
       this.$.jsAPI.handleCommitMessage(this._change, message);
 
       this.$.commitMessageEditor.disabled = true;
-      this._saveCommitMessage(message).then(function(resp) {
+      this._saveCommitMessage(message).then(resp => {
         this.$.commitMessageEditor.disabled = false;
         if (!resp.ok) { return; }
 
         this._latestCommitMessage = this._prepareCommitMsgForLinkify(message);
         this._editingCommitMessage = false;
         this._reloadWindow();
-      }.bind(this)).catch(function(err) {
+      }).catch(err => {
         this.$.commitMessageEditor.disabled = false;
-      }.bind(this));
+      });
     },
 
-    _reloadWindow: function() {
+    _reloadWindow() {
       window.location.reload();
     },
 
-    _handleCommitMessageCancel: function(e) {
+    _handleCommitMessageCancel(e) {
       this._editingCommitMessage = false;
     },
 
-    _saveCommitMessage: function(message) {
+    _saveCommitMessage(message) {
       return this.$.restAPI.saveChangeCommitMessageEdit(
-          this._changeNum, message).then(function(resp) {
+          this._changeNum, message).then(resp => {
             if (!resp.ok) { return resp; }
 
             return this.$.restAPI.publishChangeEdit(this._changeNum);
-          }.bind(this));
+          });
     },
 
-    _computeHideEditCommitMessage: function(loggedIn, editing, change) {
+    _computeHideEditCommitMessage(loggedIn, editing, change) {
       if (!loggedIn || editing || change.status === this.ChangeStatus.MERGED) {
         return true;
       }
@@ -290,29 +290,28 @@
       return false;
     },
 
-    _handlePrefsTap: function(e) {
+    _handlePrefsTap(e) {
       e.preventDefault();
       this.$.fileList.openDiffPrefs();
     },
 
-    _handleCommentSave: function(e) {
+    _handleCommentSave(e) {
       if (!e.target.comment.__draft) { return; }
 
-      var draft = e.target.comment;
+      const draft = e.target.comment;
       draft.patch_set = draft.patch_set || this._patchRange.patchNum;
 
       // The use of path-based notification helpers (set, push) can’t be used
       // because the paths could contain dots in them. A new object must be
       // created to satisfy Polymer’s dirty checking.
       // https://github.com/Polymer/polymer/issues/3127
-      // TODO(andybons): Polyfill for Object.assign in IE.
-      var diffDrafts = Object.assign({}, this._diffDrafts);
+      const diffDrafts = Object.assign({}, this._diffDrafts);
       if (!diffDrafts[draft.path]) {
         diffDrafts[draft.path] = [draft];
         this._diffDrafts = diffDrafts;
         return;
       }
-      for (var i = 0; i < this._diffDrafts[draft.path].length; i++) {
+      for (let i = 0; i < this._diffDrafts[draft.path].length; i++) {
         if (this._diffDrafts[draft.path][i].id === draft.id) {
           diffDrafts[draft.path][i] = draft;
           this._diffDrafts = diffDrafts;
@@ -320,7 +319,7 @@
         }
       }
       diffDrafts[draft.path].push(draft);
-      diffDrafts[draft.path].sort(function(c1, c2) {
+      diffDrafts[draft.path].sort((c1, c2) => {
         // No line number means that it’s a file comment. Sort it above the
         // others.
         return (c1.line || -1) - (c2.line || -1);
@@ -328,15 +327,15 @@
       this._diffDrafts = diffDrafts;
     },
 
-    _handleCommentDiscard: function(e) {
+    _handleCommentDiscard(e) {
       if (!e.target.comment.__draft) { return; }
 
-      var draft = e.target.comment;
+      const draft = e.target.comment;
       if (!this._diffDrafts[draft.path]) {
         return;
       }
-      var index = -1;
-      for (var i = 0; i < this._diffDrafts[draft.path].length; i++) {
+      let index = -1;
+      for (let i = 0; i < this._diffDrafts[draft.path].length; i++) {
         if (this._diffDrafts[draft.path][i].id === draft.id) {
           index = i;
           break;
@@ -354,8 +353,7 @@
       // because the paths could contain dots in them. A new object must be
       // created to satisfy Polymer’s dirty checking.
       // https://github.com/Polymer/polymer/issues/3127
-      // TODO(andybons): Polyfill for Object.assign in IE.
-      var diffDrafts = Object.assign({}, this._diffDrafts);
+      const diffDrafts = Object.assign({}, this._diffDrafts);
       diffDrafts[draft.path].splice(index, 1);
       if (diffDrafts[draft.path].length === 0) {
         delete diffDrafts[draft.path];
@@ -363,32 +361,32 @@
       this._diffDrafts = diffDrafts;
     },
 
-    _handlePatchChange: function(e) {
+    _handlePatchChange(e) {
       this._changePatchNum(parseInt(e.target.value, 10), true);
     },
 
-    _handleReplyTap: function(e) {
+    _handleReplyTap(e) {
       e.preventDefault();
       this._openReplyDialog();
     },
 
-    _handleDownloadTap: function(e) {
+    _handleDownloadTap(e) {
       e.preventDefault();
-      this.$.downloadOverlay.open().then(function() {
+      this.$.downloadOverlay.open().then(() => {
         this.$.downloadOverlay
             .setFocusStops(this.$.downloadDialog.getFocusStops());
         this.$.downloadDialog.focus();
-      }.bind(this));
+      });
     },
 
-    _handleDownloadDialogClose: function(e) {
+    _handleDownloadDialogClose(e) {
       this.$.downloadOverlay.close();
     },
 
-    _handleMessageReply: function(e) {
-      var msg = e.detail.message.message;
-      var quoteStr = msg.split('\n').map(
-          function(line) { return '> ' + line; }).join('\n') + '\n\n';
+    _handleMessageReply(e) {
+      const msg = e.detail.message.message;
+      const quoteStr = msg.split('\n').map(
+          line => { return '> ' + line; }).join('\n') + '\n\n';
 
       if (quoteStr !== this.$.replyDialog.quote) {
         this.$.replyDialog.draft = quoteStr;
@@ -397,33 +395,33 @@
       this._openReplyDialog();
     },
 
-    _handleReplyOverlayOpen: function(e) {
+    _handleReplyOverlayOpen(e) {
       this.$.replyDialog.focus();
     },
 
-    _handleReplySent: function(e) {
+    _handleReplySent(e) {
       this.$.replyOverlay.close();
       this._reload();
     },
 
-    _handleReplyCancel: function(e) {
+    _handleReplyCancel(e) {
       this.$.replyOverlay.close();
     },
 
-    _handleReplyAutogrow: function(e) {
+    _handleReplyAutogrow(e) {
       this.$.replyOverlay.refit();
     },
 
-    _handleShowReplyDialog: function(e) {
-      var target = this.$.replyDialog.FocusTarget.REVIEWERS;
+    _handleShowReplyDialog(e) {
+      let target = this.$.replyDialog.FocusTarget.REVIEWERS;
       if (e.detail.value && e.detail.value.ccsOnly) {
         target = this.$.replyDialog.FocusTarget.CCS;
       }
       this._openReplyDialog(target);
     },
 
-    _handleScroll: function() {
-      this.debounce('scroll', function() {
+    _handleScroll() {
+      this.debounce('scroll', () => {
         history.replaceState(
             {
               scrollTop: document.body.scrollTop,
@@ -433,13 +431,13 @@
       }, 150);
     },
 
-    _paramsChanged: function(value) {
+    _paramsChanged(value) {
       if (value.view !== this.tagName.toLowerCase()) {
         this._initialLoadComplete = false;
         return;
       }
 
-      var patchChanged = this._patchRange &&
+      const patchChanged = this._patchRange &&
           (value.patchNum !== undefined && value.basePatchNum !== undefined) &&
           (this._patchRange.patchNum !== value.patchNum ||
           this._patchRange.basePatchNum !== value.basePatchNum);
@@ -448,7 +446,7 @@
         this._initialLoadComplete = false;
       }
 
-      var patchRange = {
+      const patchRange = {
         patchNum: value.patchNum,
         basePatchNum: value.basePatchNum || 'PARENT',
       };
@@ -458,12 +456,12 @@
           patchRange.patchNum = this.computeLatestPatchNum(this._allPatchSets);
         }
         this._patchRange = patchRange;
-        this._reloadPatchNumDependentResources().then(function() {
+        this._reloadPatchNumDependentResources().then(() => {
           this.$.jsAPI.handleEvent(this.$.jsAPI.EventType.SHOW_CHANGE, {
             change: this._change,
             patchNum: patchRange.patchNum,
           });
-        }.bind(this));
+        });
         return;
       }
 
@@ -471,19 +469,19 @@
       this._patchRange = patchRange;
       this.$.relatedChanges.clear();
 
-      this._reload().then(function() {
+      this._reload().then(() => {
         this._performPostLoadTasks();
-      }.bind(this));
+      });
     },
 
-    _performPostLoadTasks: function() {
+    _performPostLoadTasks() {
       // Allow the message list and related changes to render before scrolling.
       // Related changes are loaded here (after everything else) because they
       // take the longest and are secondary information. Because the element may
       // alter the total height of the page, the call to potentially scroll to
       // a linked message is performed after related changes is fully loaded.
-      this.$.relatedChanges.reload().then(function() {
-        this.async(function() {
+      this.$.relatedChanges.reload().then(() => {
+        this.async(() => {
           if (history.state && history.state.scrollTop) {
             document.documentElement.scrollTop =
                 document.body.scrollTop = history.state.scrollTop;
@@ -491,7 +489,7 @@
             this._maybeScrollToMessage();
           }
         }, 1);
-      }.bind(this));
+      });
 
       this._maybeShowReplyDialog();
 
@@ -505,10 +503,10 @@
       this._initialLoadComplete = true;
     },
 
-    _paramsAndChangeChanged: function(value) {
+    _paramsAndChangeChanged(value) {
       // If the change number or patch range is different, then reset the
       // selected file index.
-      var patchRangeState = this.viewState.patchRange;
+      const patchRangeState = this.viewState.patchRange;
       if (this.viewState.changeNum !== this._changeNum ||
           patchRangeState.basePatchNum !== this._patchRange.basePatchNum ||
           patchRangeState.patchNum !== this._patchRange.patchNum) {
@@ -516,28 +514,28 @@
       }
     },
 
-    _numFilesShownChanged: function(numFilesShown) {
+    _numFilesShownChanged(numFilesShown) {
       this.viewState.numFilesShown = numFilesShown;
     },
 
-    _maybeScrollToMessage: function() {
-      var msgPrefix = '#message-';
-      var hash = window.location.hash;
-      if (hash.indexOf(msgPrefix) === 0) {
+    _maybeScrollToMessage() {
+      const msgPrefix = '#message-';
+      const hash = window.location.hash;
+      if (hash.startsWith(msgPrefix) === 0) {
         this.$.messageList.scrollToMessage(hash.substr(msgPrefix.length));
       }
     },
 
-    _getLocationSearch: function() {
+    _getLocationSearch() {
       // Not inlining to make it easier to test.
       return window.location.search;
     },
 
-    _getUrlParameter: function(param) {
-      var pageURL = this._getLocationSearch().substring(1);
-      var vars = pageURL.split('&');
-      for (var i = 0; i < vars.length; i++) {
-        var name = vars[i].split('=');
+    _getUrlParameter(param) {
+      const pageURL = this._getLocationSearch().substring(1);
+      const vars = pageURL.split('&');
+      for (let i = 0; i < vars.length; i++) {
+        const name = vars[i].split('=');
         if (name[0] == param) {
           return name[0];
         }
@@ -545,36 +543,36 @@
       return null;
     },
 
-    _maybeShowRevertDialog: function() {
+    _maybeShowRevertDialog() {
       Gerrit.awaitPluginsLoaded()
-        .then(this._getLoggedIn.bind(this))
-        .then(function(loggedIn) {
-          if (!loggedIn || this._change.status !== this.ChangeStatus.MERGED) {
+          .then(this._getLoggedIn.bind(this))
+          .then(loggedIn => {
+            if (!loggedIn || this._change.status !== this.ChangeStatus.MERGED) {
             // Do not display dialog if not logged-in or the change is not
             // merged.
-            return;
-          }
-          if (!!this._getUrlParameter('revert')) {
-            this.$.actions.showRevertDialog();
-          }
-        }.bind(this));
+              return;
+            }
+            if (this._getUrlParameter('revert')) {
+              this.$.actions.showRevertDialog();
+            }
+          });
     },
 
-    _maybeShowReplyDialog: function() {
-      this._getLoggedIn().then(function(loggedIn) {
+    _maybeShowReplyDialog() {
+      this._getLoggedIn().then(loggedIn => {
         if (!loggedIn) { return; }
 
         if (this.viewState.showReplyDialog) {
           this._openReplyDialog();
           // TODO(kaspern@): Find a better signal for when to call center.
-          this.async(function() { this.$.replyOverlay.center(); }, 100);
-          this.async(function() { this.$.replyOverlay.center(); }, 1000);
+          this.async(() => { this.$.replyOverlay.center(); }, 100);
+          this.async(() => { this.$.replyOverlay.center(); }, 1000);
           this.set('viewState.showReplyDialog', false);
         }
-      }.bind(this));
+      });
     },
 
-    _resetFileListViewState: function() {
+    _resetFileListViewState() {
       this.set('viewState.selectedFileIndex', 0);
       if (!!this.viewState.changeNum &&
           this.viewState.changeNum !== this._changeNum) {
@@ -587,7 +585,7 @@
       this.set('viewState.patchRange', this._patchRange);
     },
 
-    _changeChanged: function(change) {
+    _changeChanged(change) {
       if (!change || !this._patchRange || !this._allPatchSets) { return; }
       this.set('_patchRange.basePatchNum',
           this._patchRange.basePatchNum || 'PARENT');
@@ -597,8 +595,8 @@
 
       this._updateSelected();
 
-      var title = change.subject + ' (' + change.change_id.substr(0, 9) + ')';
-      this.fire('title-change', {title: title});
+      const title = change.subject + ' (' + change.change_id.substr(0, 9) + ')';
+      this.fire('title-change', {title});
     },
 
     /**
@@ -608,9 +606,9 @@
      *     always include the patch range, even if the requested patchNum is
      *     known to be the latest.
      */
-    _changePatchNum: function(patchNum, opt_forceParams) {
+    _changePatchNum(patchNum, opt_forceParams) {
       if (!opt_forceParams) {
-        var currentPatchNum;
+        let currentPatchNum;
         if (this._change.current_revision) {
           currentPatchNum =
               this._change.revisions[this._change.current_revision]._number;
@@ -623,19 +621,19 @@
           return;
         }
       }
-      var patchExpr = this._patchRange.basePatchNum === 'PARENT' ? patchNum :
+      const patchExpr = this._patchRange.basePatchNum === 'PARENT' ? patchNum :
           this._patchRange.basePatchNum + '..' + patchNum;
       page.show(this.changePath(this._changeNum) + '/' + patchExpr);
     },
 
-    _computeChangePermalink: function(changeNum) {
+    _computeChangePermalink(changeNum) {
       return this.getBaseUrl() + '/' + changeNum;
     },
 
-    _computeChangeStatus: function(change, patchNum) {
-      var statusString;
+    _computeChangeStatus(change, patchNum) {
+      let statusString;
       if (change.status === this.ChangeStatus.NEW) {
-        var rev = this.getRevisionByPatchNum(change.revisions, patchNum);
+        const rev = this.getRevisionByPatchNum(change.revisions, patchNum);
         if (rev && rev.draft === true) {
           statusString = 'Draft';
         }
@@ -645,12 +643,12 @@
       return statusString || '';
     },
 
-    _computeShowCommitInfo: function(changeStatus, current_revision) {
+    _computeShowCommitInfo(changeStatus, current_revision) {
       return changeStatus === 'Merged' && current_revision;
     },
 
-    _computeMergedCommitInfo: function(current_revision, revisions) {
-      var rev = revisions[current_revision];
+    _computeMergedCommitInfo(current_revision, revisions) {
+      const rev = revisions[current_revision];
       if (!rev || !rev.commit) { return {}; }
       // CommitInfo.commit is optional. Set commit in all cases to avoid error
       // in <gr-commit-info>. @see Issue 5337
@@ -658,11 +656,11 @@
       return rev.commit;
     },
 
-    _computeChangeIdClass: function(displayChangeId) {
+    _computeChangeIdClass(displayChangeId) {
       return displayChangeId === CHANGE_ID_ERROR.MISMATCH ? 'warning' : '';
     },
 
-    _computeTitleAttributeWarning: function(displayChangeId) {
+    _computeTitleAttributeWarning(displayChangeId) {
       if (displayChangeId === CHANGE_ID_ERROR.MISMATCH) {
         return 'Change-Id mismatch';
       } else if (displayChangeId === CHANGE_ID_ERROR.MISSING) {
@@ -670,12 +668,12 @@
       }
     },
 
-    _computeChangeIdCommitMessageError: function(commitMessage, change) {
+    _computeChangeIdCommitMessageError(commitMessage, change) {
       if (!commitMessage) { return CHANGE_ID_ERROR.MISSING; }
 
       // Find the last match in the commit message:
-      var changeId;
-      var changeIdArr;
+      let changeId;
+      let changeIdArr;
 
       while (changeIdArr = CHANGE_ID_REGEX_PATTERN.exec(commitMessage)) {
         changeId = changeIdArr[1];
@@ -695,7 +693,7 @@
       return CHANGE_ID_ERROR.MISSING;
     },
 
-    _computePatchInfoClass: function(patchNum, allPatchSets) {
+    _computePatchInfoClass(patchNum, allPatchSets) {
       if (parseInt(patchNum, 10) ===
           this.computeLatestPatchNum(allPatchSets)) {
         return '';
@@ -710,24 +708,24 @@
      * @param {Number|String} basePatchNum Base patch number from file list
      * @return {Boolean}
      */
-    _computePatchSetDisabled: function(patchNum, basePatchNum) {
+    _computePatchSetDisabled(patchNum, basePatchNum) {
       basePatchNum = basePatchNum === 'PARENT' ? 0 : basePatchNum;
       return parseInt(patchNum, 10) <= parseInt(basePatchNum, 10);
     },
 
-    _computeLabelNames: function(labels) {
+    _computeLabelNames(labels) {
       return Object.keys(labels).sort();
     },
 
-    _computeLabelValues: function(labelName, labels) {
-      var result = [];
-      var t = labels[labelName];
+    _computeLabelValues(labelName, labels) {
+      const result = [];
+      const t = labels[labelName];
       if (!t) { return result; }
-      var approvals = t.all || [];
-      approvals.forEach(function(label) {
+      const approvals = t.all || [];
+      for (label of approvals) {
         if (label.value && label.value != labels[labelName].default_value) {
-          var labelClassName;
-          var labelValPrefix = '';
+          let labelClassName;
+          let labelValPrefix = '';
           if (label.value > 0) {
             labelValPrefix = '+';
             labelClassName = 'approved';
@@ -740,33 +738,33 @@
             account: label,
           });
         }
-      });
+      }
       return result;
     },
 
-    _computeReplyButtonLabel: function(changeRecord, canStartReview) {
+    _computeReplyButtonLabel(changeRecord, canStartReview) {
       if (canStartReview) {
         return 'Start review';
       }
 
-      var drafts = (changeRecord && changeRecord.base) || {};
-      var draftCount = Object.keys(drafts).reduce(function(count, file) {
+      const drafts = (changeRecord && changeRecord.base) || {};
+      const draftCount = Object.keys(drafts).reduce((count, file) => {
         return count + drafts[file].length;
       }, 0);
 
-      var label = 'Reply';
+      let label = 'Reply';
       if (draftCount > 0) {
         label += ' (' + draftCount + ')';
       }
       return label;
     },
 
-    _handleAKey: function(e) {
+    _handleAKey(e) {
       if (this.shouldSuppressKeyboardShortcut(e) ||
           this.modifierPressed(e)) {
         return;
       }
-      this._getLoggedIn().then(function(isLoggedIn) {
+      this._getLoggedIn().then(isLoggedIn => {
         if (!isLoggedIn) {
           this.fire('show-auth-required');
           return;
@@ -774,10 +772,10 @@
 
         e.preventDefault();
         this._openReplyDialog();
-      }.bind(this));
+      });
     },
 
-    _handleDKey: function(e) {
+    _handleDKey(e) {
       if (this.shouldSuppressKeyboardShortcut(e) ||
           this.modifierPressed(e)) { return; }
 
@@ -785,13 +783,13 @@
       this.$.downloadOverlay.open();
     },
 
-    _handleCapitalRKey: function(e) {
+    _handleCapitalRKey(e) {
       if (this.shouldSuppressKeyboardShortcut(e)) { return; }
       e.preventDefault();
       page.show('/c/' + this._change._number);
     },
 
-    _handleSKey: function(e) {
+    _handleSKey(e) {
       if (this.shouldSuppressKeyboardShortcut(e) ||
           this.modifierPressed(e)) { return; }
 
@@ -799,14 +797,14 @@
       this.$.changeStar.toggleStar();
     },
 
-    _handleUKey: function(e) {
+    _handleUKey(e) {
       if (this.shouldSuppressKeyboardShortcut(e)) { return; }
 
       e.preventDefault();
       this._determinePageBack();
     },
 
-    _handleXKey: function(e) {
+    _handleXKey(e) {
       if (this.shouldSuppressKeyboardShortcut(e) ||
           this.modifierPressed(e)) { return; }
 
@@ -814,7 +812,7 @@
       this.$.messageList.handleExpandCollapse(true);
     },
 
-    _handleZKey: function(e) {
+    _handleZKey(e) {
       if (this.shouldSuppressKeyboardShortcut(e) ||
           this.modifierPressed(e)) { return; }
 
@@ -822,7 +820,7 @@
       this.$.messageList.handleExpandCollapse(false);
     },
 
-    _handleCommaKey: function(e) {
+    _handleCommaKey(e) {
       if (this.shouldSuppressKeyboardShortcut(e) ||
           this.modifierPressed(e)) { return; }
 
@@ -830,20 +828,18 @@
       this.$.fileList.openDiffPrefs();
     },
 
-    _determinePageBack: function() {
+    _determinePageBack() {
       // Default backPage to '/' if user came to change view page
       // via an email link, etc.
       page.show(this.backPage || '/');
     },
 
-    _handleLabelRemoved: function(splices, path) {
-      for (var i = 0; i < splices.length; i++) {
-        var splice = splices[i];
-        for (var j = 0; j < splice.removed.length; j++) {
-          var removed = splice.removed[j];
-          var changePath = path.split('.');
-          var labelPath = changePath.splice(0, changePath.length - 2);
-          var labelDict = this.get(labelPath);
+    _handleLabelRemoved(splices, path) {
+      for (let splice of splices) {
+        for (let removed of splice.removed) {
+          const changePath = path.split('.');
+          const labelPath = changePath.splice(0, changePath.length - 2);
+          const labelDict = this.get(labelPath);
           if (labelDict.approved &&
               labelDict.approved._account_id === removed._account_id) {
             this._reload();
@@ -853,7 +849,7 @@
       }
     },
 
-    _labelsChanged: function(changeRecord) {
+    _labelsChanged(changeRecord) {
       if (!changeRecord) { return; }
       if (changeRecord.value.indexSplices) {
         this._handleLabelRemoved(changeRecord.value.indexSplices,
@@ -864,53 +860,53 @@
       });
     },
 
-    _openReplyDialog: function(opt_section) {
+    _openReplyDialog(opt_section) {
       if (this.$.restAPI.hasPendingDiffDrafts()) {
         this.dispatchEvent(new CustomEvent('show-alert',
             {detail: {message: COMMENT_SAVE}, bubbles: true}));
         return;
       }
-      this.$.replyOverlay.open().then(function() {
+      this.$.replyOverlay.open().then(() => {
         this.$.replyOverlay.setFocusStops(this.$.replyDialog.getFocusStops());
         this.$.replyDialog.open(opt_section);
         Polymer.dom.flush();
         this.$.replyOverlay.center();
-      }.bind(this));
+      });
     },
 
-    _handleReloadChange: function(e) {
-      return this._reload().then(function() {
+    _handleReloadChange(e) {
+      return this._reload().then(() => {
         // If the change was rebased, we need to reload the page with the
         // latest patch.
         if (e.detail.action === 'rebase') {
           page.show(this.changePath(this._changeNum));
         }
-      }.bind(this));
+      });
     },
 
-    _handleGetChangeDetailError: function(response) {
-      this.fire('page-error', {response: response});
+    _handleGetChangeDetailError(response) {
+      this.fire('page-error', {response});
     },
 
-    _getDiffDrafts: function() {
+    _getDiffDrafts() {
       return this.$.restAPI.getDiffDrafts(this._changeNum).then(
-          function(drafts) {
+          drafts => {
             return this._diffDrafts = drafts;
-          }.bind(this));
+          });
     },
 
-    _getLoggedIn: function() {
+    _getLoggedIn() {
       return this.$.restAPI.getLoggedIn();
     },
 
-    _getProjectConfig: function() {
+    _getProjectConfig() {
       return this.$.restAPI.getProjectConfig(this._change.project).then(
-          function(config) {
+          config => {
             this._projectConfig = config;
-          }.bind(this));
+          });
     },
 
-    _updateRebaseAction: function(revisionActions) {
+    _updateRebaseAction(revisionActions) {
       if (revisionActions && revisionActions.rebase) {
         revisionActions.rebase.rebaseOnCurrent =
             !!revisionActions.rebase.enabled;
@@ -919,73 +915,73 @@
       return revisionActions;
     },
 
-    _prepareCommitMsgForLinkify: function(msg) {
+    _prepareCommitMsgForLinkify(msg) {
       // TODO(wyatta) switch linkify sequence, see issue 5526.
       // This is a zero-with space. It is added to prevent the linkify library
       // from including R= as part of the email address.
       return msg.replace(REVIEWERS_REGEX, 'R=\u200B');
     },
 
-    _getChangeDetail: function() {
+    _getChangeDetail() {
       return this.$.restAPI.getChangeDetail(this._changeNum,
           this._handleGetChangeDetailError.bind(this)).then(
-              function(change) {
+          change => {
                 // Issue 4190: Coalesce missing topics to null.
-                if (!change.topic) { change.topic = null; }
-                if (!change.reviewer_updates) {
-                  change.reviewer_updates = null;
-                }
-                var latestRevisionSha = this._getLatestRevisionSHA(change);
-                var currentRevision = change.revisions[latestRevisionSha];
-                if (currentRevision.commit && currentRevision.commit.message) {
-                  this._latestCommitMessage = this._prepareCommitMsgForLinkify(
-                      currentRevision.commit.message);
-                } else {
-                  this._latestCommitMessage = null;
-                }
-                var lineHeight = getComputedStyle(this).lineHeight;
-                this._lineHeight = lineHeight.slice(0, lineHeight.length - 2);
+            if (!change.topic) { change.topic = null; }
+            if (!change.reviewer_updates) {
+              change.reviewer_updates = null;
+            }
+            const latestRevisionSha = this._getLatestRevisionSHA(change);
+            const currentRevision = change.revisions[latestRevisionSha];
+            if (currentRevision.commit && currentRevision.commit.message) {
+              this._latestCommitMessage = this._prepareCommitMsgForLinkify(
+                  currentRevision.commit.message);
+            } else {
+              this._latestCommitMessage = null;
+            }
+            const lineHeight = getComputedStyle(this).lineHeight;
+            this._lineHeight = lineHeight.slice(0, lineHeight.length - 2);
 
-                this._change = change;
-                if (!this._patchRange || !this._patchRange.patchNum ||
+            this._change = change;
+            if (!this._patchRange || !this._patchRange.patchNum ||
                     this._patchRange.patchNum === currentRevision._number) {
                   // CommitInfo.commit is optional, and may need patching.
-                  if (!currentRevision.commit.commit) {
-                    currentRevision.commit.commit = latestRevisionSha;
-                  }
-                  this._commitInfo = currentRevision.commit;
-                  this._currentRevisionActions =
+              if (!currentRevision.commit.commit) {
+                currentRevision.commit.commit = latestRevisionSha;
+              }
+              this._commitInfo = currentRevision.commit;
+              this._currentRevisionActions =
                       this._updateRebaseAction(currentRevision.actions);
                   // TODO: Fetch and process files.
-                }
-              }.bind(this));
+            }
+          });
     },
 
-    _getComments: function() {
+    _getComments() {
       return this.$.restAPI.getDiffComments(this._changeNum).then(
-          function(comments) {
+          comments => {
             this._comments = comments;
-          }.bind(this));
+          });
     },
 
-    _getLatestCommitMessage: function() {
+    _getLatestCommitMessage() {
       return this.$.restAPI.getChangeCommitInfo(this._changeNum,
           this.computeLatestPatchNum(this._allPatchSets)).then(
-              function(commitInfo) {
-                this._latestCommitMessage =
+          commitInfo => {
+            this._latestCommitMessage =
                     this._prepareCommitMsgForLinkify(commitInfo.message);
-              }.bind(this));
+          });
     },
 
-    _getLatestRevisionSHA: function(change) {
+    _getLatestRevisionSHA(change) {
       if (change.current_revision) {
         return change.current_revision;
       }
       // current_revision may not be present in the case where the latest rev is
       // a draft and the user doesn’t have permission to view that rev.
-      var latestRev = null;
-      var latestPatchNum = -1;
-      for (var rev in change.revisions) {
+      let latestRev = null;
+      let latestPatchNum = -1;
+      for (const rev in change.revisions) {
         if (!change.revisions.hasOwnProperty(rev)) { continue; }
 
         if (change.revisions[rev]._number > latestPatchNum) {
@@ -996,54 +992,54 @@
       return latestRev;
     },
 
-    _getCommitInfo: function() {
+    _getCommitInfo() {
       return this.$.restAPI.getChangeCommitInfo(
           this._changeNum, this._patchRange.patchNum).then(
-              function(commitInfo) {
-                this._commitInfo = commitInfo;
-              }.bind(this));
+          commitInfo => {
+            this._commitInfo = commitInfo;
+          });
     },
 
-    _reloadDiffDrafts: function() {
+    _reloadDiffDrafts() {
       this._diffDrafts = {};
-      this._getDiffDrafts().then(function() {
+      this._getDiffDrafts().then(() => {
         if (this.$.replyOverlay.opened) {
-          this.async(function() { this.$.replyOverlay.center(); }, 1);
+          this.async(() => { this.$.replyOverlay.center(); }, 1);
         }
-      }.bind(this));
+      });
     },
 
-    _reload: function() {
+    _reload() {
       this._loading = true;
       this._relatedChangesCollapsed = true;
 
-      this._getLoggedIn().then(function(loggedIn) {
+      this._getLoggedIn().then(loggedIn => {
         if (!loggedIn) { return; }
 
         this._reloadDiffDrafts();
-      }.bind(this));
+      });
 
-      var detailCompletes = this._getChangeDetail().then(function() {
+      const detailCompletes = this._getChangeDetail().then(() => {
         this._loading = false;
         this._getProjectConfig();
-      }.bind(this));
+      });
       this._getComments();
 
       if (this._patchRange.patchNum) {
         return Promise.all([
           this._reloadPatchNumDependentResources(),
           detailCompletes,
-        ]).then(function() {
+        ]).then(() => {
           return this.$.actions.reload();
-        }.bind(this));
+        });
       } else {
         // The patch number is reliant on the change detail request.
-        return detailCompletes.then(function() {
+        return detailCompletes.then(() => {
           this.$.fileList.reload();
           if (!this._latestCommitMessage) {
             this._getLatestCommitMessage();
           }
-        }.bind(this));
+        });
       }
     },
 
@@ -1051,34 +1047,35 @@
      * Kicks off requests for resources that rely on the patch range
      * (`this._patchRange`) being defined.
      */
-    _reloadPatchNumDependentResources: function() {
+    _reloadPatchNumDependentResources() {
       return Promise.all([
         this._getCommitInfo(),
         this.$.fileList.reload(),
       ]);
     },
 
-    _updateSelected: function() {
+    _updateSelected() {
       this._selectedPatchSet = this._patchRange.patchNum;
     },
 
-    _computePatchSetDescription: function(change, patchNum) {
-      var rev = this.getRevisionByPatchNum(change.revisions, patchNum);
+    _computePatchSetDescription(change, patchNum) {
+      const rev = this.getRevisionByPatchNum(change.revisions, patchNum);
       return (rev && rev.description) ?
           rev.description.substring(0, PATCH_DESC_MAX_LENGTH) : '';
     },
 
-    _computePatchSetCommentsString: function(allComments, patchNum) {
-      var numComments = 0;
-      var numUnresolved = 0;
-      for (var file in allComments) {
-        var comments = allComments[file];
-        numComments += this.$.fileList.getCommentsForPath(
-            allComments, patchNum, file).length;
-        numUnresolved += this.$.fileList.computeUnresolvedNum(
-            allComments, {}, patchNum, file);
+    _computePatchSetCommentsString(allComments, patchNum) {
+      let numComments = 0;
+      let numUnresolved = 0;
+      for (const file in allComments) {
+        if(allComments.hasOwnProperty(file)) {
+          numComments += this.$.fileList.getCommentsForPath(
+              allComments, patchNum, file).length;
+          numUnresolved += this.$.fileList.computeUnresolvedNum(
+              allComments, {}, patchNum, file);
+        }
       }
-      var commentsStr = '';
+      let commentsStr = '';
       if (numComments > 0) {
         commentsStr = '(' + numComments + ' comments';
         if (numUnresolved > 0) {
@@ -1089,22 +1086,22 @@
       return commentsStr;
     },
 
-    _computeDescriptionPlaceholder: function(readOnly) {
+    _computeDescriptionPlaceholder(readOnly) {
       return (readOnly ? 'No' : 'Add a') + ' patch set description';
     },
 
-    _handleDescriptionChanged: function(e) {
-      var desc = e.detail.trim();
-      var rev = this.getRevisionByPatchNum(this._change.revisions,
+    _handleDescriptionChanged(e) {
+      const desc = e.detail.trim();
+      const rev = this.getRevisionByPatchNum(this._change.revisions,
           this._selectedPatchSet);
-      var sha = this._getPatchsetHash(this._change.revisions, rev);
+      const sha = this._getPatchsetHash(this._change.revisions, rev);
       this.$.restAPI.setDescription(this._changeNum,
           this._selectedPatchSet, desc)
-          .then(function(res) {
+          .then(res => {
             if (res.ok) {
               this.set(['_change', 'revisions', sha, 'description'], desc);
             }
-          }.bind(this));
+          });
     },
 
 
@@ -1113,8 +1110,8 @@
      * @param {Object} patchSet A revision already fetched from {revisions}
      * @return {string} the SHA hash corresponding to the revision.
      */
-    _getPatchsetHash: function(revisions, patchSet) {
-      for (var rev in revisions) {
+    _getPatchsetHash(revisions, patchSet) {
+      for (const rev in revisions) {
         if (revisions.hasOwnProperty(rev) &&
             revisions[rev] === patchSet) {
           return rev;
@@ -1122,70 +1119,70 @@
       }
     },
 
-    _computeCanStartReview: function(loggedIn, change, account) {
+    _computeCanStartReview(loggedIn, change, account) {
       return !!(loggedIn && change.work_in_progress &&
           change.owner._account_id === account._account_id);
     },
 
-    _computeDescriptionReadOnly: function(loggedIn, change, account) {
+    _computeDescriptionReadOnly(loggedIn, change, account) {
       return !(loggedIn && (account._account_id === change.owner._account_id));
     },
 
-    _computeReplyDisabled: function() { return false; },
+    _computeReplyDisabled() { return false; },
 
-    _computeChangePermalinkAriaLabel: function(changeNum) {
+    _computeChangePermalinkAriaLabel(changeNum) {
       return 'Change ' + changeNum;
     },
 
-    _computeCommitClass: function(collapsed, commitMessage) {
+    _computeCommitClass(collapsed, commitMessage) {
       if (this._computeCommitToggleHidden(commitMessage)) { return ''; }
       return collapsed ? 'collapsed' : '';
     },
 
-    _computeRelatedChangesClass: function(collapsed, loading) {
+    _computeRelatedChangesClass(collapsed, loading) {
       if (!loading && !this.customStyle['--relation-chain-max-height']) {
         this._updateRelatedChangeMaxHeight();
       }
       return collapsed ? 'collapsed' : '';
     },
 
-    _computeCollapseText: function(collapsed) {
+    _computeCollapseText(collapsed) {
       // Symbols are up and down triangles.
       return collapsed ? '\u25bc Show more' : '\u25b2 Show less';
     },
 
-    _toggleCommitCollapsed: function() {
+    _toggleCommitCollapsed() {
       this._commitCollapsed = !this._commitCollapsed;
       if (this._commitCollapsed) {
         window.scrollTo(0, 0);
       }
     },
 
-    _toggleRelatedChangesCollapsed: function() {
+    _toggleRelatedChangesCollapsed() {
       this._relatedChangesCollapsed = !this._relatedChangesCollapsed;
       if (this._relatedChangesCollapsed) {
         window.scrollTo(0, 0);
       }
     },
 
-    _computeCommitToggleHidden: function(commitMessage) {
+    _computeCommitToggleHidden(commitMessage) {
       if (!commitMessage) { return true; }
       return commitMessage.split('\n').length < MIN_LINES_FOR_COMMIT_COLLAPSE;
     },
 
-    _getOffsetHeight: function(element) {
+    _getOffsetHeight(element) {
       return element.offsetHeight;
     },
 
-    _getScrollHeight: function(element) {
+    _getScrollHeight(element) {
       return element.scrollHeight;
     },
 
     /**
      * Get the line height of an element to the nearest integer.
      */
-    _getLineHeight: function(element) {
-      var lineHeightStr = getComputedStyle(element).lineHeight;
+    _getLineHeight(element) {
+      const lineHeightStr = getComputedStyle(element).lineHeight;
       return Math.round(lineHeightStr.slice(0, lineHeightStr.length - 2));
     },
 
@@ -1242,16 +1239,19 @@
             remainder + 'px';
         }
       }
+      if (this.$.relatedChanges.hidden) {
+        this.customStyle['--commit-message-max-width'] = 'none';
+      }
       this.customStyle['--relation-chain-max-height'] = newHeight + 'px';
       this.updateStyles();
     },
 
-    _computeRelatedChangesToggleHidden: function() {
+    _computeRelatedChangesToggleHidden() {
       return this._getScrollHeight(this.$.relatedChanges) <=
           this._getOffsetHeight(this.$.relatedChanges);
     },
 
-    _startUpdateCheckTimer: function() {
+    _startUpdateCheckTimer() {
       if (!this.serverConfig ||
           !this.serverConfig.change ||
           this.serverConfig.change.update_delay === undefined ||
@@ -1259,9 +1259,9 @@
         return;
       }
 
-      this._updateCheckTimerHandle = this.async(function() {
+      this._updateCheckTimerHandle = this.async(() => {
         this.fetchIsLatestKnown(this._change, this.$.restAPI)
-            .then(function(latest) {
+            .then(latest => {
               if (latest) {
                 this._startUpdateCheckTimer();
               } else {
@@ -1278,16 +1278,16 @@
                   }.bind(this),
                 });
               }
-            }.bind(this));
+            });
       }, this.serverConfig.change.update_delay * 1000);
     },
 
-    _cancelUpdateCheckTimer: function() {
+    _cancelUpdateCheckTimer() {
       this.cancelAsync(this._updateCheckTimerHandle);
       this._updateCheckTimerHandle = null;
     },
 
-    _handleVisibilityChange: function() {
+    _handleVisibilityChange() {
       if (document.hidden && this._updateCheckTimerHandle) {
         this._cancelUpdateCheckTimer();
       } else if (!this._updateCheckTimerHandle) {
@@ -1295,7 +1295,7 @@
       }
     },
 
-    _computeHeaderClass: function(change) {
+    _computeHeaderClass(change) {
       return change.work_in_progress ? 'header wip' : 'header';
     },
   });
diff --git a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_test.html b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_test.html
index f1ce0e4..eebde09 100644
--- a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_test.html
+++ b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_test.html
@@ -34,75 +34,75 @@
 </test-fixture>
 
 <script>
-  suite('gr-change-view tests', function() {
-    var element;
-    var sandbox;
-    var showStub;
-    var TEST_SCROLL_TOP_PX = 100;
+  suite('gr-change-view tests', () => {
+    let element;
+    let sandbox;
+    let showStub;
+    const TEST_SCROLL_TOP_PX = 100;
 
-    setup(function() {
+    setup(() => {
       sandbox = sinon.sandbox.create();
       showStub = sandbox.stub(page, 'show');
       stub('gr-rest-api-interface', {
-        getConfig: function() { return Promise.resolve({}); },
-        getAccount: function() { return Promise.resolve(null); },
+        getConfig() { return Promise.resolve({}); },
+        getAccount() { return Promise.resolve(null); },
       });
       element = fixture('basic');
     });
 
-    teardown(function(done) {
-      flush(function() {
+    teardown(done => {
+      flush(() => {
         sandbox.restore();
         done();
       });
     });
 
-    suite('keyboard shortcuts', function() {
-      test('S should toggle the CL star', function() {
-        var starStub = sandbox.stub(element.$.changeStar, 'toggleStar');
+    suite('keyboard shortcuts', () => {
+      test('S should toggle the CL star', () => {
+        const starStub = sandbox.stub(element.$.changeStar, 'toggleStar');
         MockInteractions.pressAndReleaseKeyOn(element, 83, null, 's');
         assert(starStub.called);
       });
 
-      test('U should navigate to / if no backPage set', function() {
+      test('U should navigate to / if no backPage set', () => {
         MockInteractions.pressAndReleaseKeyOn(element, 85, null, 'u');
         assert(showStub.lastCall.calledWithExactly('/'));
       });
 
-      test('U should navigate to backPage if set', function() {
+      test('U should navigate to backPage if set', () => {
         element.backPage = '/dashboard/self';
         MockInteractions.pressAndReleaseKeyOn(element, 85, null, 'u');
         assert(showStub.lastCall.calledWithExactly('/dashboard/self'));
       });
 
-      test('A fires an error event when not logged in', function(done) {
+      test('A fires an error event when not logged in', done => {
         sandbox.stub(element, '_getLoggedIn').returns(Promise.resolve(false));
-        var loggedInErrorSpy = sandbox.spy();
+        const loggedInErrorSpy = sandbox.spy();
         element.addEventListener('show-auth-required', loggedInErrorSpy);
         MockInteractions.pressAndReleaseKeyOn(element, 65, null, 'a');
-        flush(function() {
+        flush(() => {
           assert.isFalse(element.$.replyOverlay.opened);
           assert.isTrue(loggedInErrorSpy.called);
           done();
         });
       });
 
-      test('shift A does not open reply overlay', function(done) {
+      test('shift A does not open reply overlay', done => {
         sandbox.stub(element, '_getLoggedIn').returns(Promise.resolve(true));
         MockInteractions.pressAndReleaseKeyOn(element, 65, 'shift', 'a');
-        flush(function() {
+        flush(() => {
           assert.isFalse(element.$.replyOverlay.opened);
           done();
         });
       });
 
-      test('A toggles overlay when logged in', function(done) {
+      test('A toggles overlay when logged in', done => {
         sandbox.stub(element, '_getLoggedIn').returns(Promise.resolve(true));
         sandbox.stub(element.$.replyDialog, 'fetchIsLatestKnown')
             .returns(Promise.resolve(true));
         element._change = {labels: {}};
         MockInteractions.pressAndReleaseKeyOn(element, 65, null, 'a');
-        flush(function() {
+        flush(() => {
           assert.isTrue(element.$.replyOverlay.opened);
           element.$.replyOverlay.close();
           assert.isFalse(element.$.replyOverlay.opened);
@@ -110,65 +110,64 @@
         });
       });
 
-      test('X should expand all messages', function() {
-        var handleExpand =
+      test('X should expand all messages', () => {
+        const handleExpand =
             sandbox.stub(element.$.messageList, 'handleExpandCollapse');
         MockInteractions.pressAndReleaseKeyOn(element, 88, null, 'x');
         assert(handleExpand.calledWith(true));
       });
 
-      test('Z should collapse all messages', function() {
-         var handleExpand =
+      test('Z should collapse all messages', () => {
+        const handleExpand =
             sandbox.stub(element.$.messageList, 'handleExpandCollapse');
         MockInteractions.pressAndReleaseKeyOn(element, 90, null, 'z');
         assert(handleExpand.calledWith(false));
       });
 
       test('shift + R should fetch and navigate to the latest patch set',
-          function(done) {
-        element._changeNum = '42';
-        element._patchRange = {
-          basePatchNum: 'PARENT',
-          patchNum: 1,
-        };
-        element._change = {
-          change_id: 'Iad9dc96274af6946f3632be53b106ef80f7ba6ca',
-          _number: 42,
-          revisions: {
-            rev1: {_number: 1},
-          },
-          current_revision: 'rev1',
-          status: 'NEW',
-          labels: {},
-          actions: {},
-        };
+          done => {
+            element._changeNum = '42';
+            element._patchRange = {
+              basePatchNum: 'PARENT',
+              patchNum: 1,
+            };
+            element._change = {
+              change_id: 'Iad9dc96274af6946f3632be53b106ef80f7ba6ca',
+              _number: 42,
+              revisions: {
+                rev1: {_number: 1},
+              },
+              current_revision: 'rev1',
+              status: 'NEW',
+              labels: {},
+              actions: {},
+            };
 
-        sandbox.stub(element.$.actions, 'reload');
+            sandbox.stub(element.$.actions, 'reload');
 
-        showStub.restore();
-        showStub = sandbox.stub(page, 'show', function(arg) {
-          assert.equal(arg, '/c/42');
-          done();
-        });
+            showStub.restore();
+            showStub = sandbox.stub(page, 'show', arg => {
+              assert.equal(arg, '/c/42');
+              done();
+            });
 
-        MockInteractions.pressAndReleaseKeyOn(element, 82, 'shift', 'r');
-      });
+            MockInteractions.pressAndReleaseKeyOn(element, 82, 'shift', 'r');
+          });
 
-      test('d should open download overlay', function() {
-        var stub = sandbox.stub(element.$.downloadOverlay, 'open');
+      test('d should open download overlay', () => {
+        const stub = sandbox.stub(element.$.downloadOverlay, 'open');
         MockInteractions.pressAndReleaseKeyOn(element, 68, null, 'd');
         assert.isTrue(stub.called);
       });
 
-      test(', should open diff preferences', function() {
-        var stub = sandbox.stub(element.$.fileList.$.diffPreferences, 'open');
+      test(', should open diff preferences', () => {
+        const stub = sandbox.stub(element.$.fileList.$.diffPreferences, 'open');
         MockInteractions.pressAndReleaseKeyOn(element, 188, null, ',');
         assert.isTrue(stub.called);
       });
     });
 
-    test('Diff preferences hidden when no prefs or logged out',
-        function() {
+    test('Diff preferences hidden when no prefs or logged out', () => {
       element._loggedIn = false;
       flushAsynchronousOperations();
       assert.isTrue(element.$.diffPrefsContainer.hidden);
@@ -178,7 +177,7 @@
       assert.isTrue(element.$.diffPrefsContainer.hidden);
 
       element._loggedIn = false;
-      element._diffPrefs = {'font_size': '12'};
+      element._diffPrefs = {font_size: '12'};
       flushAsynchronousOperations();
       assert.isTrue(element.$.diffPrefsContainer.hidden);
 
@@ -187,11 +186,11 @@
       assert.isFalse(element.$.diffPrefsContainer.hidden);
     });
 
-    test('prefsButton opens gr-diff-preferences', function() {
-      var handlePrefsTapSpy = sandbox.spy(element, '_handlePrefsTap');
-      var overlayOpenStub = sandbox.stub(element.$.fileList,
+    test('prefsButton opens gr-diff-preferences', () => {
+      const handlePrefsTapSpy = sandbox.spy(element, '_handlePrefsTap');
+      const overlayOpenStub = sandbox.stub(element.$.fileList,
           'openDiffPrefs');
-      var prefsButton = Polymer.dom(element.root).querySelectorAll(
+      const prefsButton = Polymer.dom(element.root).querySelectorAll(
           '.prefsButton')[0];
 
       MockInteractions.tap(prefsButton);
@@ -200,7 +199,7 @@
       assert.isTrue(overlayOpenStub.called);
     });
 
-    test('_computeDescriptionReadOnly', function() {
+    test('_computeDescriptionReadOnly', () => {
       assert.equal(element._computeDescriptionReadOnly(false,
           {owner: {_account_id: 1}}, {_account_id: 1}), true);
       assert.equal(element._computeDescriptionReadOnly(true,
@@ -209,16 +208,16 @@
           {owner: {_account_id: 1}}, {_account_id: 1}), false);
     });
 
-    test('_computeDescriptionPlaceholder', function() {
+    test('_computeDescriptionPlaceholder', () => {
       assert.equal(element._computeDescriptionPlaceholder(true),
           'No patch set description');
       assert.equal(element._computeDescriptionPlaceholder(false),
           'Add a patch set description');
     });
 
-    test('_computePatchSetDisabled', function() {
-      var basePatchNum = 'PARENT';
-      var patchNum = 1;
+    test('_computePatchSetDisabled', () => {
+      let basePatchNum = 'PARENT';
+      let patchNum = 1;
       assert.equal(element._computePatchSetDisabled(patchNum, basePatchNum),
           false);
       basePatchNum = 1;
@@ -229,24 +228,24 @@
           false);
     });
 
-    test('_prepareCommitMsgForLinkify', function() {
-      var commitMessage = 'R=test@google.com';
-      var result = element._prepareCommitMsgForLinkify(commitMessage);
+    test('_prepareCommitMsgForLinkify', () => {
+      let commitMessage = 'R=test@google.com';
+      let result = element._prepareCommitMsgForLinkify(commitMessage);
       assert.equal(result, 'R=\u200Btest@google.com');
 
       commitMessage = 'R=test@google.com\nR=test@google.com';
-      var result = element._prepareCommitMsgForLinkify(commitMessage);
+      result = element._prepareCommitMsgForLinkify(commitMessage);
       assert.equal(result, 'R=\u200Btest@google.com\nR=\u200Btest@google.com');
     }),
 
-    test('_computePatchSetCommentsString', function() {
+    test('_computePatchSetCommentsString', () => {
       // Test string with unresolved comments.
       comments = {
-        'foo': 'foo comments',
-        'bar': 'bar comments',
-        'xyz': 'xyz comments',
+        foo: 'foo comments',
+        bar: 'bar comments',
+        xyz: 'xyz comments',
       };
-      sandbox.stub(element.$.fileList, 'getCommentsForPath', function(c, p, f) {
+      sandbox.stub(element.$.fileList, 'getCommentsForPath', (c, p, f) => {
         if (f == 'foo') {
           return ['comment1', 'comment2'];
         } else if (f == 'bar') {
@@ -255,8 +254,7 @@
           return [];
         }
       });
-      sandbox.stub(
-          element.$.fileList, 'computeUnresolvedNum', function (c, d, p, f) {
+      sandbox.stub(element.$.fileList, 'computeUnresolvedNum', (c, d, p, f) => {
         if (f == 'foo') {
           return 0;
         } else if (f == 'bar') {
@@ -269,17 +267,17 @@
           '(3 comments, 1 unresolved)');
 
       // Test string with no unresolved comments.
-      delete comments['bar']
+      delete comments['bar'];
       assert.equal(element._computePatchSetCommentsString(comments, 1),
           '(2 comments)');
 
       // Test string with no comments.
-      delete comments['foo']
+      delete comments['foo'];
       assert.equal(element._computePatchSetCommentsString(comments, 1), '');
     });
 
-    test('_handleDescriptionChanged', function() {
-      var putDescStub = sandbox.stub(element.$.restAPI, 'setDescription')
+    test('_handleDescriptionChanged', () => {
+      const putDescStub = sandbox.stub(element.$.restAPI, 'setDescription')
           .returns(Promise.resolve({ok: true}));
       sandbox.stub(element, '_computeDescriptionReadOnly');
 
@@ -304,7 +302,7 @@
       element._loggedIn = true;
 
       flushAsynchronousOperations();
-      var label = element.$.descriptionLabel;
+      const label = element.$.descriptionLabel;
       assert.equal(label.value, 'test');
       label.editing = true;
       label._inputText = 'test2';
@@ -314,19 +312,19 @@
       assert.equal(putDescStub.args[0][2], 'test2');
     });
 
-    test('_updateRebaseAction', function() {
-      var currentRevisionActions = {
+    test('_updateRebaseAction', () => {
+      const currentRevisionActions = {
         cherrypick: {
           enabled: true,
           label: 'Cherry Pick',
           method: 'POST',
-          title: 'cherrypick'
+          title: 'cherrypick',
         },
         rebase: {
           enabled: true,
           label: 'Rebase',
           method: 'POST',
-          title: 'Rebase onto tip of branch or parent change'
+          title: 'Rebase onto tip of branch or parent change',
         },
       };
 
@@ -334,7 +332,7 @@
       // When rebase is enabled initially, rebaseOnCurrent should be set to
       // true.
       assert.equal(element._updateRebaseAction(currentRevisionActions),
-        currentRevisionActions);
+          currentRevisionActions);
 
       assert.isTrue(currentRevisionActions.rebase.enabled);
       assert.isTrue(currentRevisionActions.rebase.rebaseOnCurrent);
@@ -344,14 +342,14 @@
       // When rebase is not enabled initially, rebaseOnCurrent should be set to
       // false.
       assert.equal(element._updateRebaseAction(currentRevisionActions),
-        currentRevisionActions);
+          currentRevisionActions);
 
       assert.isTrue(currentRevisionActions.rebase.enabled);
       assert.isFalse(currentRevisionActions.rebase.rebaseOnCurrent);
     });
 
-    test('_reload is called when an approved label is removed', function() {
-      var vote = {_account_id: 1, name: 'bojack', value: 1};
+    test('_reload is called when an approved label is removed', () => {
+      const vote = {_account_id: 1, name: 'bojack', value: 1};
       element._changeNum = '42';
       element._patchRange = {
         basePatchNum: 'PARENT',
@@ -377,7 +375,7 @@
         },
       };
       flushAsynchronousOperations();
-      var reloadStub = sandbox.stub(element, '_reload');
+      const reloadStub = sandbox.stub(element, '_reload');
       element.splice('_change.labels.test.all', 0, 1);
       assert.isFalse(reloadStub.called);
       element._change.labels.test.all.push(vote);
@@ -389,13 +387,13 @@
       assert.isTrue(reloadStub.calledOnce);
     });
 
-    test('reply button has updated count when there are drafts', function() {
-      var getLabel = element._computeReplyButtonLabel;
+    test('reply button has updated count when there are drafts', () => {
+      const getLabel = element._computeReplyButtonLabel;
 
       assert.equal(getLabel(null, false), 'Reply');
       assert.equal(getLabel(null, true), 'Start review');
 
-      var changeRecord = {base: null};
+      const changeRecord = {base: null};
       assert.equal(getLabel(changeRecord, false), 'Reply');
 
       changeRecord.base = {};
@@ -408,18 +406,18 @@
       assert.equal(getLabel(changeRecord, false), 'Reply (3)');
     });
 
-    test('start review button when owner of WIP change', function() {
+    test('start review button when owner of WIP change', () => {
       assert.equal(
           element._computeReplyButtonLabel(null, true),
           'Start review');
     });
 
-    test('comment events properly update diff drafts', function() {
+    test('comment events properly update diff drafts', () => {
       element._patchRange = {
         basePatchNum: 'PARENT',
         patchNum: 2,
       };
-      var draft = {
+      const draft = {
         __draft: true,
         id: 'id1',
         path: '/foo/bar.txt',
@@ -433,7 +431,7 @@
       element._handleCommentSave({target: {comment: draft}});
       draft.patch_set = 2;
       assert.deepEqual(element._diffDrafts, {'/foo/bar.txt': [draft]});
-      var draft2 = {
+      const draft2 = {
         __draft: true,
         id: 'id2',
         path: '/foo/bar.txt',
@@ -450,7 +448,7 @@
       assert.deepEqual(element._diffDrafts, {});
     });
 
-    test('change num change', function() {
+    test('change num change', () => {
       element._changeNum = null;
       element._patchRange = {
         basePatchNum: 'PARENT',
@@ -486,7 +484,7 @@
       assert.equal(element._numFilesShown, 200);
     });
 
-    test('patch num change', function(done) {
+    test('patch num change', done => {
       element._changeNum = '42';
       element._patchRange = {
         basePatchNum: 'PARENT',
@@ -507,19 +505,19 @@
       element.viewState.diffMode = 'UNIFIED';
       flushAsynchronousOperations();
 
-      var selectEl = element.$$('.patchInfo-header select');
+      const selectEl = element.$$('.patchInfo-header select');
       assert.ok(selectEl);
-      var optionEls = Polymer.dom(element.root).querySelectorAll(
+      const optionEls = Polymer.dom(element.root).querySelectorAll(
           '.patchInfo-header option');
       assert.equal(optionEls.length, 4);
-      var select = element.$$('.patchInfo-header #patchSetSelect').bindValue;
+      const select = element.$$('.patchInfo-header #patchSetSelect').bindValue;
       assert.notEqual(select, 1);
       assert.equal(select, 2);
       assert.notEqual(select, 3);
       assert.equal(optionEls[3].value, 13);
 
-      var numEvents = 0;
-      selectEl.addEventListener('change', function(e) {
+      let numEvents = 0;
+      selectEl.addEventListener('change', e => {
         assert.equal(element.viewState.diffMode, 'UNIFIED');
         numEvents++;
         if (numEvents == 1) {
@@ -537,7 +535,7 @@
       element.fire('change', {}, {node: selectEl});
     });
 
-    test('patch num change with missing current_revision', function(done) {
+    test('patch num change with missing current_revision', done => {
       element._changeNum = '42';
       element._patchRange = {
         basePatchNum: 'PARENT',
@@ -555,21 +553,21 @@
         labels: {},
       };
       flushAsynchronousOperations();
-      var selectEl = element.$$('.patchInfo-header select');
+      const selectEl = element.$$('.patchInfo-header select');
       assert.ok(selectEl);
-      var optionEls = Polymer.dom(element.root).querySelectorAll(
+      const optionEls = Polymer.dom(element.root).querySelectorAll(
           '.patchInfo-header option');
       assert.equal(optionEls.length, 4);
       assert.notEqual(
-        element.$$('.patchInfo-header #patchSetSelect').bindValue, 1);
+          element.$$('.patchInfo-header #patchSetSelect').bindValue, 1);
       assert.equal(
-        element.$$('.patchInfo-header #patchSetSelect').bindValue, 2);
+          element.$$('.patchInfo-header #patchSetSelect').bindValue, 2);
       assert.notEqual(
-        element.$$('.patchInfo-header #patchSetSelect').bindValue, 3);
+          element.$$('.patchInfo-header #patchSetSelect').bindValue, 3);
       assert.equal(optionEls[3].value, 13);
 
-      var numEvents = 0;
-      selectEl.addEventListener('change', function(e) {
+      let numEvents = 0;
+      selectEl.addEventListener('change', e => {
         numEvents++;
         if (numEvents == 1) {
           assert(showStub.lastCall.calledWithExactly('/c/42/1'),
@@ -586,15 +584,15 @@
       element.fire('change', {}, {node: selectEl});
     });
 
-    test('don’t reload entire page when patchRange changes', function() {
-      var reloadStub = sandbox.stub(element, '_reload',
-          function() { return Promise.resolve(); });
-      var reloadPatchDependentStub = sandbox.stub(element,
+    test('don’t reload entire page when patchRange changes', () => {
+      const reloadStub = sandbox.stub(element, '_reload',
+          () => { return Promise.resolve(); });
+      const reloadPatchDependentStub = sandbox.stub(element,
           '_reloadPatchNumDependentResources',
-          function() { return Promise.resolve(); });
-      var relatedClearSpy = sandbox.spy(element.$.relatedChanges, 'clear');
+          () => { return Promise.resolve(); });
+      const relatedClearSpy = sandbox.spy(element.$.relatedChanges, 'clear');
 
-      var value = {
+      const value = {
         view: 'gr-change-view',
         patchNum: '1',
       };
@@ -612,11 +610,11 @@
       assert.isTrue(relatedClearSpy.calledOnce);
     });
 
-    test('reload entire page when patchRange doesnt change', function() {
-      var reloadStub = sandbox.stub(element, '_reload',
-          function() { return Promise.resolve(); });
+    test('reload entire page when patchRange doesnt change', () => {
+      const reloadStub = sandbox.stub(element, '_reload',
+          () => { return Promise.resolve(); });
 
-      var value = {
+      const value = {
         view: 'gr-change-view',
       };
       element._paramsChanged(value);
@@ -626,7 +624,7 @@
       assert.isTrue(reloadStub.calledTwice);
     });
 
-    test('include base patch when not parent', function() {
+    test('include base patch when not parent', () => {
       element._changeNum = '42';
       element._patchRange = {
         basePatchNum: '2',
@@ -654,33 +652,32 @@
     });
 
     test('related changes are updated and new patch selected after rebase',
-        function(done) {
-      element._changeNum = '42';
-      sandbox.stub(element, 'computeLatestPatchNum', function() {
-        return 1;
-      });
-      sandbox.stub(element, '_reload',
-          function() { return Promise.resolve(); });
-      var e = {detail: {action: 'rebase'}};
-      element._handleReloadChange(e).then(function() {
-        assert.isTrue(showStub.lastCall.calledWithExactly('/c/42'));
-        done();
-      });
-    });
+        done => {
+          element._changeNum = '42';
+          sandbox.stub(element, 'computeLatestPatchNum', () => {
+            return 1;
+          });
+          sandbox.stub(element, '_reload',
+              () => { return Promise.resolve(); });
+          const e = {detail: {action: 'rebase'}};
+          element._handleReloadChange(e).then(() => {
+            assert.isTrue(showStub.lastCall.calledWithExactly('/c/42'));
+            done();
+          });
+        });
 
-    test('related changes are not updated after other action', function(done) {
-      sandbox.stub(element, '_reload',
-          function() { return Promise.resolve(); });
+    test('related changes are not updated after other action', done => {
+      sandbox.stub(element, '_reload', () => { return Promise.resolve(); });
       sandbox.stub(element, '_updateSelected');
       sandbox.stub(element.$.relatedChanges, 'reload');
-      var e = {detail: {action: 'abandon'}};
-      element._handleReloadChange(e).then(function() {
+      const e = {detail: {action: 'abandon'}};
+      element._handleReloadChange(e).then(() => {
         assert.isFalse(showStub.called);
         done();
       });
     });
 
-    test('change status new', function() {
+    test('change status new', () => {
       element._changeNum = '1';
       element._patchRange = {
         basePatchNum: 'PARENT',
@@ -695,11 +692,11 @@
         status: 'NEW',
         labels: {},
       };
-      var status = element._computeChangeStatus(element._change, '1');
+      const status = element._computeChangeStatus(element._change, '1');
       assert.equal(status, '');
     });
 
-    test('change status draft', function() {
+    test('change status draft', () => {
       element._changeNum = '1';
       element._patchRange = {
         basePatchNum: 'PARENT',
@@ -714,11 +711,11 @@
         status: 'DRAFT',
         labels: {},
       };
-      var status = element._computeChangeStatus(element._change, '1');
+      const status = element._computeChangeStatus(element._change, '1');
       assert.equal(status, 'Draft');
     });
 
-    test('change status merged', function() {
+    test('change status merged', () => {
       element._changeNum = '1';
       element._patchRange = {
         basePatchNum: 'PARENT',
@@ -733,11 +730,11 @@
         status: element.ChangeStatus.MERGED,
         labels: {},
       };
-      var status = element._computeChangeStatus(element._change, '1');
+      const status = element._computeChangeStatus(element._change, '1');
       assert.equal(status, 'Merged');
     });
 
-    test('revision status draft', function() {
+    test('revision status draft', () => {
       element._changeNum = '1';
       element._patchRange = {
         basePatchNum: 'PARENT',
@@ -756,12 +753,12 @@
         status: 'NEW',
         labels: {},
       };
-      var status = element._computeChangeStatus(element._change, '2');
+      const status = element._computeChangeStatus(element._change, '2');
       assert.equal(status, 'Draft');
     });
 
-    test('_computeMergedCommitInfo', function() {
-      var dummyRevs = {
+    test('_computeMergedCommitInfo', () => {
+      const dummyRevs = {
         1: {commit: {commit: 1}},
         2: {commit: {}},
       };
@@ -770,13 +767,13 @@
           dummyRevs[1].commit);
 
       // Regression test for issue 5337.
-      var commit = element._computeMergedCommitInfo(2, dummyRevs);
+      const commit = element._computeMergedCommitInfo(2, dummyRevs);
       assert.notDeepEqual(commit, dummyRevs[2]);
       assert.deepEqual(commit, {commit: 2});
     });
 
-    test('get latest revision', function() {
-      var change = {
+    test('get latest revision', () => {
+      let change = {
         revisions: {
           rev1: {_number: 1},
           rev3: {_number: 3},
@@ -792,8 +789,8 @@
       assert.equal(element._getLatestRevisionSHA(change), 'rev1');
     });
 
-    test('show commit message edit button', function() {
-      var _change = {
+    test('show commit message edit button', () => {
+      const _change = {
         status: element.ChangeStatus.MERGED,
       };
       assert.isTrue(element._computeHideEditCommitMessage(false, false, {}));
@@ -804,80 +801,80 @@
           _change));
     });
 
-    test('_computeChangeIdCommitMessageError', function() {
-      var commitMessage =
+    test('_computeChangeIdCommitMessageError', () => {
+      let commitMessage =
         'Change-Id: I4ce18b2395bca69d7a9aa48bf4554faa56282483';
-      var change = {change_id: 'I4ce18b2395bca69d7a9aa48bf4554faa56282483'};
+      let change = {change_id: 'I4ce18b2395bca69d7a9aa48bf4554faa56282483'};
       assert.equal(
-        element._computeChangeIdCommitMessageError(commitMessage, change),
-        null);
+          element._computeChangeIdCommitMessageError(commitMessage, change),
+          null);
 
       change = {change_id: 'I4ce18b2395bca69d7a9aa48bf4554faa56282484'};
       assert.equal(
-        element._computeChangeIdCommitMessageError(commitMessage, change),
-        'mismatch');
+          element._computeChangeIdCommitMessageError(commitMessage, change),
+          'mismatch');
 
       commitMessage = 'This is the greatest change.';
       assert.equal(
-        element._computeChangeIdCommitMessageError(commitMessage, change),
-        'missing');
+          element._computeChangeIdCommitMessageError(commitMessage, change),
+          'missing');
     });
 
-    test('multiple change Ids in commit message picks last', function() {
-      var commitMessage = [
-       'Change-Id: I4ce18b2395bca69d7a9aa48bf4554faa56282484',
-       'Change-Id: I4ce18b2395bca69d7a9aa48bf4554faa56282483',
+    test('multiple change Ids in commit message picks last', () => {
+      const commitMessage = [
+        'Change-Id: I4ce18b2395bca69d7a9aa48bf4554faa56282484',
+        'Change-Id: I4ce18b2395bca69d7a9aa48bf4554faa56282483',
       ].join('\n');
-      var change = {change_id: 'I4ce18b2395bca69d7a9aa48bf4554faa56282483'};
+      let change = {change_id: 'I4ce18b2395bca69d7a9aa48bf4554faa56282483'};
       assert.equal(
-        element._computeChangeIdCommitMessageError(commitMessage, change),
-        null);
+          element._computeChangeIdCommitMessageError(commitMessage, change),
+          null);
       change = {change_id: 'I4ce18b2395bca69d7a9aa48bf4554faa56282484'};
       assert.equal(
-        element._computeChangeIdCommitMessageError(commitMessage, change),
-        'mismatch');
+          element._computeChangeIdCommitMessageError(commitMessage, change),
+          'mismatch');
     });
 
-    test('does not count change Id that starts mid line', function() {
-      var commitMessage = [
-       'Change-Id: I4ce18b2395bca69d7a9aa48bf4554faa56282484',
-       'Change-Id: I4ce18b2395bca69d7a9aa48bf4554faa56282483',
+    test('does not count change Id that starts mid line', () => {
+      const commitMessage = [
+        'Change-Id: I4ce18b2395bca69d7a9aa48bf4554faa56282484',
+        'Change-Id: I4ce18b2395bca69d7a9aa48bf4554faa56282483',
       ].join(' and ');
-      var change = {change_id: 'I4ce18b2395bca69d7a9aa48bf4554faa56282484'};
+      let change = {change_id: 'I4ce18b2395bca69d7a9aa48bf4554faa56282484'};
       assert.equal(
-        element._computeChangeIdCommitMessageError(commitMessage, change),
-        null);
+          element._computeChangeIdCommitMessageError(commitMessage, change),
+          null);
       change = {change_id: 'I4ce18b2395bca69d7a9aa48bf4554faa56282483'};
       assert.equal(
-        element._computeChangeIdCommitMessageError(commitMessage, change),
-        'mismatch');
+          element._computeChangeIdCommitMessageError(commitMessage, change),
+          'mismatch');
     });
 
-    test('_computeTitleAttributeWarning', function() {
-      var changeIdCommitMessageError = 'missing';
+    test('_computeTitleAttributeWarning', () => {
+      let changeIdCommitMessageError = 'missing';
       assert.equal(
           element._computeTitleAttributeWarning(changeIdCommitMessageError),
           'No Change-Id in commit message');
 
-      var changeIdCommitMessageError = 'mismatch';
+      changeIdCommitMessageError = 'mismatch';
       assert.equal(
           element._computeTitleAttributeWarning(changeIdCommitMessageError),
           'Change-Id mismatch');
     });
 
-    test('_computeChangeIdClass', function() {
-      var changeIdCommitMessageError = 'missing';
+    test('_computeChangeIdClass', () => {
+      let changeIdCommitMessageError = 'missing';
       assert.equal(
-        element._computeChangeIdClass(changeIdCommitMessageError), '');
+          element._computeChangeIdClass(changeIdCommitMessageError), '');
 
-      var changeIdCommitMessageError = 'mismatch';
+      changeIdCommitMessageError = 'mismatch';
       assert.equal(
-        element._computeChangeIdClass(changeIdCommitMessageError), 'warning');
+          element._computeChangeIdClass(changeIdCommitMessageError), 'warning');
     });
 
-    test('topic is coalesced to null', function(done) {
+    test('topic is coalesced to null', done => {
       sandbox.stub(element, '_changeChanged');
-      sandbox.stub(element.$.restAPI, 'getChangeDetail', function() {
+      sandbox.stub(element.$.restAPI, 'getChangeDetail', () => {
         return Promise.resolve({
           id: '123456789',
           labels: {},
@@ -886,15 +883,15 @@
         });
       });
 
-      element._getChangeDetail().then(function() {
+      element._getChangeDetail().then(() => {
         assert.isNull(element._change.topic);
         done();
       });
     });
 
-    test('commit sha is populated from getChangeDetail', function(done) {
+    test('commit sha is populated from getChangeDetail', done => {
       sandbox.stub(element, '_changeChanged');
-      sandbox.stub(element.$.restAPI, 'getChangeDetail', function() {
+      sandbox.stub(element.$.restAPI, 'getChangeDetail', () => {
         return Promise.resolve({
           id: '123456789',
           labels: {},
@@ -903,17 +900,17 @@
         });
       });
 
-      element._getChangeDetail().then(function() {
+      element._getChangeDetail().then(() => {
         assert.equal('foo', element._commitInfo.commit);
         done();
       });
     });
 
-    test('reply dialog focus can be controlled', function() {
-      var FocusTarget = element.$.replyDialog.FocusTarget;
-      var openStub = sandbox.stub(element, '_openReplyDialog');
+    test('reply dialog focus can be controlled', () => {
+      const FocusTarget = element.$.replyDialog.FocusTarget;
+      const openStub = sandbox.stub(element, '_openReplyDialog');
 
-      var e = {detail: {}};
+      const e = {detail: {}};
       element._handleShowReplyDialog(e);
       assert(openStub.lastCall.calledWithExactly(FocusTarget.REVIEWERS),
           '_openReplyDialog should have been passed REVIEWERS');
@@ -924,8 +921,8 @@
           '_openReplyDialog should have been passed CCS');
     });
 
-    test('class is applied to file list on old patch set', function() {
-      var allPatchSets = [{num: 1}, {num: 2}, {num: 4}];
+    test('class is applied to file list on old patch set', () => {
+      const allPatchSets = [{num: 1}, {num: 2}, {num: 4}];
       assert.equal(element._computePatchInfoClass('1', allPatchSets),
           'patchInfo--oldPatchSet');
       assert.equal(element._computePatchInfoClass('2', allPatchSets),
@@ -933,8 +930,8 @@
       assert.equal(element._computePatchInfoClass('4', allPatchSets), '');
     });
 
-    test('getUrlParameter functionality', function() {
-      var locationStub = sandbox.stub(element, '_getLocationSearch');
+    test('getUrlParameter functionality', () => {
+      const locationStub = sandbox.stub(element, '_getLocationSearch');
 
       locationStub.returns('?test');
       assert.equal(element._getUrlParameter('test'), 'test');
@@ -946,14 +943,13 @@
       assert.isNull(element._getUrlParameter('test'));
       locationStub.returns('?test2');
       assert.isNull(element._getUrlParameter('test'));
-
     });
 
-    test('revert dialog opened with revert param', function(done) {
-      sandbox.stub(element.$.restAPI, 'getLoggedIn', function() {
+    test('revert dialog opened with revert param', done => {
+      sandbox.stub(element.$.restAPI, 'getLoggedIn', () => {
         return Promise.resolve(true);
       });
-      sandbox.stub(Gerrit, 'awaitPluginsLoaded', function() {
+      sandbox.stub(Gerrit, 'awaitPluginsLoaded', () => {
         return Promise.resolve();
       });
 
@@ -972,37 +968,36 @@
         actions: {},
       };
 
-      var urlParamStub = sandbox.stub(element, '_getUrlParameter',
-          function(param) {
+      sandbox.stub(element, '_getUrlParameter',
+          param => {
             assert.equal(param, 'revert');
             return param;
           });
 
-      var revertDialogStub = sandbox.stub(element.$.actions, 'showRevertDialog',
+      sandbox.stub(element.$.actions, 'showRevertDialog',
           done);
 
       element._maybeShowRevertDialog();
       assert.isTrue(Gerrit.awaitPluginsLoaded.called);
     });
 
-    suite('scroll related tests', function() {
-      test('document scrolling calls function to set scroll height',
-          function(done) {
-            var originalHeight = document.body.scrollHeight;
-            var scrollStub = sandbox.stub(element, '_handleScroll',
-                function() {
-                  assert.isTrue(scrollStub.called);
-                  document.body.style.height =
-                      originalHeight + 'px';
-                  scrollStub.restore();
-                  done();
-                });
-            document.body.style.height = '10000px';
-            document.body.scrollTop = TEST_SCROLL_TOP_PX;
-            element._handleScroll();
-          });
+    suite('scroll related tests', () => {
+      test('document scrolling calls function to set scroll height', done => {
+        const originalHeight = document.body.scrollHeight;
+        const scrollStub = sandbox.stub(element, '_handleScroll',
+            () => {
+              assert.isTrue(scrollStub.called);
+              document.body.style.height =
+                  originalHeight + 'px';
+              scrollStub.restore();
+              done();
+            });
+        document.body.style.height = '10000px';
+        document.body.scrollTop = TEST_SCROLL_TOP_PX;
+        element._handleScroll();
+      });
 
-      test('history is loaded correctly', function() {
+      test('history is loaded correctly', () => {
         history.replaceState(
             {
               scrollTop: 100,
@@ -1010,14 +1005,13 @@
             },
             location.pathname);
 
-        var reloadStub = sandbox.stub(element, '_reload',
-            function() {
-              // When element is reloaded, ensure that the history
-              // state has the scrollTop set earlier. This will then
-              // be reset.
-              assert.isTrue(history.state.scrollTop == 100);
-              return Promise.resolve({});
-            });
+        sandbox.stub(element, '_reload', () => {
+          // When element is reloaded, ensure that the history
+          // state has the scrollTop set earlier. This will then
+          // be reset.
+          assert.isTrue(history.state.scrollTop == 100);
+          return Promise.resolve({});
+        });
 
         // simulate reloading component, which is done when route
         // changes to match a regex of change view type.
@@ -1025,45 +1019,45 @@
       });
     });
 
-    suite('reply dialog tests', function() {
-      setup(function() {
+    suite('reply dialog tests', () => {
+      setup(() => {
         sandbox.stub(element.$.replyDialog, '_draftChanged');
         sandbox.stub(element.$.replyDialog, 'fetchIsLatestKnown',
-            function() { return Promise.resolve(true); });
+            () => { return Promise.resolve(true); });
         element._change = {labels: {}};
       });
 
-      test('reply from comment adds quote text', function() {
-        var e = {detail: {message: {message: 'quote text'}}};
+      test('reply from comment adds quote text', () => {
+        const e = {detail: {message: {message: 'quote text'}}};
         element._handleMessageReply(e);
         assert.equal(element.$.replyDialog.draft, '> quote text\n\n');
         assert.equal(element.$.replyDialog.quote, '> quote text\n\n');
       });
 
-      test('reply from comment replaces quote text', function() {
+      test('reply from comment replaces quote text', () => {
         element.$.replyDialog.draft = '> old quote text\n\n some draft text';
         element.$.replyDialog.quote = '> old quote text\n\n';
-        var e = {detail: {message: {message: 'quote text'}}};
+        const e = {detail: {message: {message: 'quote text'}}};
         element._handleMessageReply(e);
         assert.equal(element.$.replyDialog.draft, '> quote text\n\n');
         assert.equal(element.$.replyDialog.quote, '> quote text\n\n');
       });
 
-      test('reply from same comment preserves quote text', function() {
+      test('reply from same comment preserves quote text', () => {
         element.$.replyDialog.draft = '> quote text\n\n some draft text';
         element.$.replyDialog.quote = '> quote text\n\n';
-        var e = {detail: {message: {message: 'quote text'}}};
+        const e = {detail: {message: {message: 'quote text'}}};
         element._handleMessageReply(e);
         assert.equal(element.$.replyDialog.draft,
             '> quote text\n\n some draft text');
         assert.equal(element.$.replyDialog.quote, '> quote text\n\n');
       });
 
-      test('reply from top of page contains previous draft', function() {
-        var div = document.createElement('div');
+      test('reply from top of page contains previous draft', () => {
+        const div = document.createElement('div');
         element.$.replyDialog.draft = '> quote text\n\n some draft text';
         element.$.replyDialog.quote = '> quote text\n\n';
-        var e = {target: div, preventDefault: sandbox.spy()};
+        const e = {target: div, preventDefault: sandbox.spy()};
         element._handleReplyTap(e);
         assert.equal(element.$.replyDialog.draft,
             '> quote text\n\n some draft text');
@@ -1071,29 +1065,29 @@
       });
     });
 
-    test('reply button is disabled until server config is loaded', function() {
+    test('reply button is disabled until server config is loaded', () => {
       assert.isTrue(element._replyDisabled);
       element.serverConfig = {};
       assert.isFalse(element._replyDisabled);
     });
 
-    suite('commit message expand/collapse', function() {
-      setup(function() {
+    suite('commit message expand/collapse', () => {
+      setup(() => {
         sandbox.stub(element, 'fetchIsLatestKnown',
-            function() { return Promise.resolve(false); });
+            () => { return Promise.resolve(false); });
       });
 
-      test('commitCollapseToggle hidden for short commit message', function() {
+      test('commitCollapseToggle hidden for short commit message', () => {
         element._latestCommitMessage = '';
         assert.isTrue(element.$.commitCollapseToggle.hasAttribute('hidden'));
       });
 
-      test('commitCollapseToggle shown for long commit message', function() {
+      test('commitCollapseToggle shown for long commit message', () => {
         element._latestCommitMessage = _.times(31, String).join('\n');
         assert.isFalse(element.$.commitCollapseToggle.hasAttribute('hidden'));
       });
 
-      test('commitCollapseToggle functions', function() {
+      test('commitCollapseToggle functions', () => {
         element._latestCommitMessage = _.times(31, String).join('\n');
         assert.isTrue(element._commitCollapsed);
         assert.isTrue(
@@ -1105,37 +1099,36 @@
       });
     });
 
-    suite('related changes expand/collapse', function() {
-      var updateHeightSpy;
-      setup(function() {
+    suite('related changes expand/collapse', () => {
+      let updateHeightSpy;
+      setup(() => {
         updateHeightSpy = sandbox.spy(element, '_updateRelatedChangeMaxHeight');
       });
 
       test('relatedChangesToggle shown height greater than changeInfo height',
-          function() {
-        assert.isTrue(element.$.relatedChangesToggle.hasAttribute('hidden'));
-        sandbox.stub(element, '_getOffsetHeight', () => 50);
-        sandbox.stub(element, '_getScrollHeight', () => 60);
-        sandbox.stub(window, 'matchMedia', () => ({matches: true}));
-        element._relatedChangesLoading = false;
-        assert.isFalse(element.$.relatedChangesToggle.hasAttribute('hidden'));
-        assert.equal(updateHeightSpy.callCount, 1);
-      });
+          () => {
+            assert.isTrue(element.$.relatedChangesToggle.hasAttribute('hidden'));
+            sandbox.stub(element, '_getOffsetHeight', () => 50);
+            sandbox.stub(element, '_getScrollHeight', () => 60);
+            sandbox.stub(window, 'matchMedia', () => ({matches: true}));
+            element._relatedChangesLoading = false;
+            assert.isFalse(element.$.relatedChangesToggle.hasAttribute('hidden'));
+            assert.equal(updateHeightSpy.callCount, 1);
+          });
 
       test('relatedChangesToggle hidden height less than changeInfo height',
-            function() {
-        assert.isTrue(element.$.relatedChangesToggle.hasAttribute('hidden'));
-        sandbox.stub(element, '_getOffsetHeight', () => 50);
-        sandbox.stub(element, '_getScrollHeight', () => 40);
-        sandbox.stub(window, 'matchMedia', () => ({matches: true}));
-        element._relatedChangesLoading = false;
-        assert.isTrue(element.$.relatedChangesToggle.hasAttribute('hidden'));
-        assert.equal(updateHeightSpy.callCount, 1);
-      });
+          () => {
+            assert.isTrue(element.$.relatedChangesToggle.hasAttribute('hidden'));
+            sandbox.stub(element, '_getOffsetHeight', () => 50);
+            sandbox.stub(element, '_getScrollHeight', () => 40);
+            sandbox.stub(window, 'matchMedia', () => ({matches: true}));
+            element._relatedChangesLoading = false;
+            assert.isTrue(element.$.relatedChangesToggle.hasAttribute('hidden'));
+            assert.equal(updateHeightSpy.callCount, 1);
+          });
 
-      test('relatedChangesToggle functions', function() {
+      test('relatedChangesToggle functions', () => {
         sandbox.stub(element, '_getOffsetHeight', () => 50);
-        sandbox.stub(element, '_getScrollHeight', () => 60);
         sandbox.stub(window, 'matchMedia', () => ({matches: false}));
         element._relatedChangesLoading = false;
         assert.isTrue(element._relatedChangesCollapsed);
@@ -1147,7 +1140,7 @@
             element.$.relatedChanges.classList.contains('collapsed'));
       });
 
-      test('_updateRelatedChangeMaxHeight without commit toggle', function() {
+      test('_updateRelatedChangeMaxHeight without commit toggle', () => {
         sandbox.stub(element, '_getOffsetHeight', () => 50);
         sandbox.stub(element, '_getLineHeight', () => 12);
         sandbox.stub(window, 'matchMedia', () => ({matches: false}));
@@ -1163,7 +1156,7 @@
             undefined);
       });
 
-      test('_updateRelatedChangeMaxHeight with commit toggle', function() {
+      test('_updateRelatedChangeMaxHeight with commit toggle', () => {
         element._latestCommitMessage = _.times(31, String).join('\n');
         sandbox.stub(element, '_getOffsetHeight', () => 50);
         sandbox.stub(element, '_getLineHeight', () => 12);
@@ -1190,7 +1183,7 @@
             '400px');
       });
 
-       test('_updateRelatedChangeMaxHeight in medium screen mode', () => {
+      test('_updateRelatedChangeMaxHeight in medium screen mode', () => {
         element._latestCommitMessage = _.times(31, String).join('\n');
         sandbox.stub(element, '_getOffsetHeight', () => 50);
         sandbox.stub(element, '_getLineHeight', () => 12);
@@ -1208,17 +1201,17 @@
       });
 
 
-      suite('update checks', function() {
-        setup(function() {
+      suite('update checks', () => {
+        setup(() => {
           sandbox.spy(element, '_startUpdateCheckTimer');
-          sandbox.stub(element, 'async', function(f) {
+          sandbox.stub(element, 'async', f => {
             // Only fire the async callback one time.
             if (element.async.callCount > 1) { return; }
             f.call(element);
           });
         });
 
-        test('_startUpdateCheckTimer negative delay', function() {
+        test('_startUpdateCheckTimer negative delay', () => {
           sandbox.stub(element, 'fetchIsLatestKnown');
 
           element.serverConfig = {change: {update_delay: -1}};
@@ -1227,9 +1220,9 @@
           assert.isFalse(element.fetchIsLatestKnown.called);
         });
 
-        test('_startUpdateCheckTimer up-to-date', function() {
+        test('_startUpdateCheckTimer up-to-date', () => {
           sandbox.stub(element, 'fetchIsLatestKnown',
-              function() { return Promise.resolve(true); });
+              () => { return Promise.resolve(true); });
 
           element.serverConfig = {change: {update_delay: 12345}};
 
@@ -1238,21 +1231,20 @@
           assert.equal(element.async.lastCall.args[1], 12345 * 1000);
         });
 
-        test('_startUpdateCheckTimer out-of-date shows an alert',
-            function(done) {
+        test('_startUpdateCheckTimer out-of-date shows an alert', done => {
           sandbox.stub(element, 'fetchIsLatestKnown',
-              function() { return Promise.resolve(false); });
-          element.addEventListener('show-alert', function() {
+              () => { return Promise.resolve(false); });
+          element.addEventListener('show-alert', () => {
             done();
           });
           element.serverConfig = {change: {update_delay: 12345}};
         });
       });
 
-      test('canStartReview computation', function() {
-        var account1 = {_account_id: 1};
-        var account2 = {_account_id: 2};
-        var change = {
+      test('canStartReview computation', () => {
+        const account1 = {_account_id: 1};
+        const account2 = {_account_id: 2};
+        const change = {
           owner: {_account_id: 1},
         };
         assert.isFalse(element._computeCanStartReview(true, change, account1));
@@ -1264,7 +1256,7 @@
         assert.isFalse(element._computeCanStartReview(true, change, account2));
       });
 
-      test('header class computation', function() {
+      test('header class computation', () => {
         assert.equal(element._computeHeaderClass({}), 'header');
         assert.equal(element._computeHeaderClass({work_in_progress: true}),
             'header wip');
diff --git a/polygerrit-ui/app/elements/change/gr-comment-list/gr-comment-list.js b/polygerrit-ui/app/elements/change/gr-comment-list/gr-comment-list.js
index 98a2508..ab2ad11 100644
--- a/polygerrit-ui/app/elements/change/gr-comment-list/gr-comment-list.js
+++ b/polygerrit-ui/app/elements/change/gr-comment-list/gr-comment-list.js
@@ -14,8 +14,8 @@
 (function() {
   'use strict';
 
-  var COMMIT_MESSAGE_PATH = '/COMMIT_MSG';
-  var MERGE_LIST_PATH = '/MERGE_LIST';
+  const COMMIT_MESSAGE_PATH = '/COMMIT_MSG';
+  const MERGE_LIST_PATH = '/MERGE_LIST';
 
   Polymer({
     is: 'gr-comment-list',
@@ -32,17 +32,16 @@
       projectConfig: Object,
     },
 
-    _computeFilesFromComments: function(comments) {
-      var arr = Object.keys(comments || {});
+    _computeFilesFromComments(comments) {
+      const arr = Object.keys(comments || {});
       return arr.sort(this.specialFilePathCompare);
     },
 
-    _computeFileDiffURL: function(file, changeNum, patchNum) {
-      return this.getBaseUrl() + '/c/' + changeNum +
-        '/' + patchNum + '/' + file;
+    _computeFileDiffURL(file, changeNum, patchNum) {
+      return `${this.getBaseUrl()}/c/${changeNum}/${patchNum}/${file}`;
     },
 
-    _computeFileDisplayName: function(path) {
+    _computeFileDisplayName(path) {
       if (path === COMMIT_MESSAGE_PATH) {
         return 'Commit message';
       } else if (path === MERGE_LIST_PATH) {
@@ -51,12 +50,12 @@
       return path;
     },
 
-    _isOnParent: function(comment) {
+    _isOnParent(comment) {
       return comment.side === 'PARENT';
     },
 
-    _computeDiffLineURL: function(file, changeNum, patchNum, comment) {
-      var diffURL = this._computeFileDiffURL(file, changeNum, patchNum);
+    _computeDiffLineURL(file, changeNum, patchNum, comment) {
+      let diffURL = this._computeFileDiffURL(file, changeNum, patchNum);
       if (comment.line) {
         diffURL += '#';
         if (this._isOnParent(comment)) { diffURL += 'b'; }
@@ -65,18 +64,18 @@
       return diffURL;
     },
 
-    _computeCommentsForFile: function(comments, file) {
+    _computeCommentsForFile(comments, file) {
       // Changes are not picked up by the dom-repeat due to the array instance
       // identity not changing even when it has elements added/removed from it.
       return (comments[file] || []).slice();
     },
 
-    _computePatchDisplayName: function(comment) {
+    _computePatchDisplayName(comment) {
       if (this._isOnParent(comment)) {
         return 'Base, ';
       }
       if (comment.patch_set != this.patchNum) {
-        return 'PS' + comment.patch_set + ', ';
+        return `PS${comment.patch_set}, `;
       }
       return '';
     },
diff --git a/polygerrit-ui/app/elements/change/gr-comment-list/gr-comment-list_test.html b/polygerrit-ui/app/elements/change/gr-comment-list/gr-comment-list_test.html
index e27bad0..5275f48 100644
--- a/polygerrit-ui/app/elements/change/gr-comment-list/gr-comment-list_test.html
+++ b/polygerrit-ui/app/elements/change/gr-comment-list/gr-comment-list_test.html
@@ -31,41 +31,42 @@
 </test-fixture>
 
 <script>
-  suite('gr-comment-list tests', function() {
-    var element;
+  suite('gr-comment-list tests', () => {
+    let element;
 
-    setup(function() {
+    setup(() => {
       element = fixture('basic');
     });
 
-    test('_computeFilesFromComments w/ special file path sorting', function() {
-      var comments = {
+    test('_computeFilesFromComments w/ special file path sorting', () => {
+      const comments = {
         'file_b.html': [],
         'file_c.css': [],
         'file_a.js': [],
         'test.cc': [],
         'test.h': [],
       };
-      var expected = [
+      const expected = [
         'file_a.js',
         'file_b.html',
         'file_c.css',
         'test.h',
-        'test.cc'
+        'test.cc',
       ];
-      var actual = element._computeFilesFromComments(comments);
+      const actual = element._computeFilesFromComments(comments);
       assert.deepEqual(actual, expected);
 
       assert.deepEqual(element._computeFilesFromComments(null), []);
     });
 
-    test('_computeFileDiffURL', function() {
-      var expected = '/c/<change>/<patch>/<file>';
-      var actual = element._computeFileDiffURL('<file>', '<change>', '<patch>');
+    test('_computeFileDiffURL', () => {
+      const expected = '/c/<change>/<patch>/<file>';
+      const actual =
+          element._computeFileDiffURL('<file>', '<change>', '<patch>');
       assert.equal(actual, expected);
     });
 
-    test('_computeFileDisplayName', function() {
+    test('_computeFileDisplayName', () => {
       assert.equal(element._computeFileDisplayName('/COMMIT_MSG'),
           'Commit message');
       assert.equal(element._computeFileDisplayName('/MERGE_LIST'),
@@ -74,10 +75,10 @@
           '/foo/bar/baz');
     });
 
-    test('_computeDiffLineURL', function() {
-      var comment = {line: 123, side: 'REVISION', patch_set: 10};
-      var expected = '/c/<change>/<patch>/<file>#123';
-      var actual = element._computeDiffLineURL('<file>', '<change>', '<patch>',
+    test('_computeDiffLineURL', () => {
+      const comment = {line: 123, side: 'REVISION', patch_set: 10};
+      let expected = '/c/<change>/<patch>/<file>#123';
+      let actual = element._computeDiffLineURL('<file>', '<change>', '<patch>',
           comment);
       assert.equal(actual, expected);
 
@@ -89,8 +90,8 @@
           comment);
     });
 
-    test('_computePatchDisplayName', function() {
-      var comment = {line: 123, side: 'REVISION', patch_set: 10};
+    test('_computePatchDisplayName', () => {
+      const comment = {line: 123, side: 'REVISION', patch_set: 10};
 
       element.patchNum = 10;
       assert.equal(element._computePatchDisplayName(comment), '');
diff --git a/polygerrit-ui/app/elements/change/gr-commit-info/gr-commit-info.js b/polygerrit-ui/app/elements/change/gr-commit-info/gr-commit-info.js
index 5aa8601..c55e8c7 100644
--- a/polygerrit-ui/app/elements/change/gr-commit-info/gr-commit-info.js
+++ b/polygerrit-ui/app/elements/change/gr-commit-info/gr-commit-info.js
@@ -31,13 +31,13 @@
       },
     },
 
-    _isWebLink: function(link) {
+    _isWebLink(link) {
       // This is a whitelist of web link types that provide direct links to
       // the commit in the url property.
       return link.name === 'gitiles' || link.name === 'gitweb';
     },
 
-    _computeShowWebLink: function(change, commitInfo, serverConfig) {
+    _computeShowWebLink(change, commitInfo, serverConfig) {
       if (serverConfig.gitweb && serverConfig.gitweb.url &&
           serverConfig.gitweb.type && serverConfig.gitweb.type.revision) {
         return true;
@@ -47,8 +47,8 @@
         return false;
       }
 
-      for (var i = 0; i < commitInfo.web_links.length; i++) {
-        if (this._isWebLink(commitInfo.web_links[i])) {
+      for (const link of commitInfo.web_links) {
+        if (this._isWebLink(link)) {
           return true;
         }
       }
@@ -56,7 +56,7 @@
       return false;
     },
 
-    _computeWebLink: function(change, commitInfo, serverConfig) {
+    _computeWebLink(change, commitInfo, serverConfig) {
       if (!this._computeShowWebLink(change, commitInfo, serverConfig)) {
         return;
       }
@@ -69,10 +69,10 @@
                 .replace('${commit}', commitInfo.commit);
       }
 
-      var webLink = null;
-      for (var i = 0; i < commitInfo.web_links.length; i++) {
-        if (this._isWebLink(commitInfo.web_links[i])) {
-          webLink = commitInfo.web_links[i].url;
+      let webLink = null;
+      for (const link of commitInfo.web_links) {
+        if (this._isWebLink(link)) {
+          webLink = link.url;
           break;
         }
       }
@@ -88,7 +88,7 @@
       return webLink;
     },
 
-    _computeShortHash: function(commitInfo) {
+    _computeShortHash(commitInfo) {
       if (!commitInfo || !commitInfo.commit) {
         return;
       }
diff --git a/polygerrit-ui/app/elements/change/gr-commit-info/gr-commit-info_test.html b/polygerrit-ui/app/elements/change/gr-commit-info/gr-commit-info_test.html
index c8faff5..fc45f2a 100644
--- a/polygerrit-ui/app/elements/change/gr-commit-info/gr-commit-info_test.html
+++ b/polygerrit-ui/app/elements/change/gr-commit-info/gr-commit-info_test.html
@@ -33,14 +33,14 @@
 </test-fixture>
 
 <script>
-  suite('gr-commit-info tests', function() {
-    var element;
+  suite('gr-commit-info tests', () => {
+    let element;
 
-    setup(function() {
+    setup(() => {
       element = fixture('basic');
     });
 
-    test('no web link when unavailable', function() {
+    test('no web link when unavailable', () => {
       element.commitInfo = {};
       element.serverConfig = {};
       element.change = {labels: []};
@@ -49,7 +49,7 @@
           element.commitInfo, element.serverConfig));
     });
 
-    test('use web link when available', function() {
+    test('use web link when available', () => {
       element.commitInfo = {web_links: [{name: 'gitweb', url: 'link-url'}]};
       element.serverConfig = {};
 
@@ -59,9 +59,9 @@
           element.serverConfig), '../../link-url');
     });
 
-    test('does not relativize web links that begin with scheme', function() {
+    test('does not relativize web links that begin with scheme', () => {
       element.commitInfo = {
-        web_links: [{name: 'gitweb', url: 'https://link-url'}]
+        web_links: [{name: 'gitweb', url: 'https://link-url'}],
       };
       element.serverConfig = {};
 
@@ -71,7 +71,7 @@
           element.serverConfig), 'https://link-url');
     });
 
-    test('use gitweb when available', function() {
+    test('use gitweb when available', () => {
       element.commitInfo = {commit: 'commit-sha'};
       element.serverConfig = {gitweb: {
         url: 'url-base/',
@@ -80,7 +80,7 @@
       element.change = {
         project: 'project-name',
         labels: [],
-        current_revision: element.commitInfo.commit
+        current_revision: element.commitInfo.commit,
       };
 
       assert.isOk(element._computeShowWebLink(element.change,
@@ -90,10 +90,10 @@
           element.serverConfig), 'url-base/xx project-name xx commit-sha xx');
     });
 
-    test('prefer gitweb when both are available', function() {
+    test('prefer gitweb when both are available', () => {
       element.commitInfo = {
         commit: 'commit-sha',
-        web_links: [{url: 'link-url'}]
+        web_links: [{url: 'link-url'}],
       };
       element.serverConfig = {gitweb: {
         url: 'url-base/',
@@ -102,20 +102,20 @@
       element.change = {
         project: 'project-name',
         labels: [],
-        current_revision: element.commitInfo.commit
+        current_revision: element.commitInfo.commit,
       };
 
       assert.isOk(element._computeShowWebLink(element.change,
           element.commitInfo, element.serverConfig));
 
-      var link = element._computeWebLink(element.change, element.commitInfo,
+      const link = element._computeWebLink(element.change, element.commitInfo,
           element.serverConfig);
 
       assert.equal(link, 'url-base/xx project-name xx commit-sha xx');
       assert.notEqual(link, '../../link-url');
     });
 
-    test('ignore web links that are neither gitweb nor gitiles', function() {
+    test('ignore web links that are neither gitweb nor gitiles', () => {
       element.commitInfo = {
         commit: 'commit-sha',
         web_links: [
@@ -126,7 +126,7 @@
           {
             name: 'gitiles',
             url: 'https://link-url',
-          }
+          },
         ],
       };
       element.serverConfig = {};
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-abandon-dialog/gr-confirm-abandon-dialog.js b/polygerrit-ui/app/elements/change/gr-confirm-abandon-dialog/gr-confirm-abandon-dialog.js
index e47f14f..074e39e 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-abandon-dialog/gr-confirm-abandon-dialog.js
+++ b/polygerrit-ui/app/elements/change/gr-confirm-abandon-dialog/gr-confirm-abandon-dialog.js
@@ -33,16 +33,16 @@
       message: String,
     },
 
-    resetFocus: function() {
+    resetFocus() {
       this.$.messageInput.textarea.focus();
     },
 
-    _handleConfirmTap: function(e) {
+    _handleConfirmTap(e) {
       e.preventDefault();
       this.fire('confirm', {reason: this.message}, {bubbles: false});
     },
 
-    _handleCancelTap: function(e) {
+    _handleCancelTap(e) {
       e.preventDefault();
       this.fire('cancel', null, {bubbles: false});
     },
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-dialog/gr-confirm-cherrypick-dialog.js b/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-dialog/gr-confirm-cherrypick-dialog.js
index 716e29c..48a3f76 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-dialog/gr-confirm-cherrypick-dialog.js
+++ b/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-dialog/gr-confirm-cherrypick-dialog.js
@@ -41,8 +41,8 @@
       '_computeMessage(changeStatus, commitNum, commitMessage)',
     ],
 
-    _computeMessage: function(changeStatus, commitNum, commitMessage) {
-      var newMessage = commitMessage;
+    _computeMessage(changeStatus, commitNum, commitMessage) {
+      let newMessage = commitMessage;
 
       if (changeStatus === 'MERGED') {
         newMessage += '(cherry picked from commit ' + commitNum + ')';
@@ -50,12 +50,12 @@
       this.message = newMessage;
     },
 
-    _handleConfirmTap: function(e) {
+    _handleConfirmTap(e) {
       e.preventDefault();
       this.fire('confirm', null, {bubbles: false});
     },
 
-    _handleCancelTap: function(e) {
+    _handleCancelTap(e) {
       e.preventDefault();
       this.fire('cancel', null, {bubbles: false});
     },
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-dialog/gr-confirm-cherrypick-dialog_test.html b/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-dialog/gr-confirm-cherrypick-dialog_test.html
index 3c1cf2b..2d6defd 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-dialog/gr-confirm-cherrypick-dialog_test.html
+++ b/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-dialog/gr-confirm-cherrypick-dialog_test.html
@@ -33,42 +33,41 @@
 </test-fixture>
 
 <script>
-  suite('gr-confirm-cherrypick-dialog tests', function() {
-    var element;
+  suite('gr-confirm-cherrypick-dialog tests', () => {
+    let element;
 
-    setup(function() {
+    setup(() => {
       element = fixture('basic');
     });
 
-    test('with merged change', function() {
+    test('with merged change', () => {
       element.changeStatus = 'MERGED';
       element.commitMessage = 'message\n';
       element.commitNum = '123';
       element.branch = 'master';
       flushAsynchronousOperations();
-      var expectedMessage = 'message\n(cherry picked from commit 123)';
+      const expectedMessage = 'message\n(cherry picked from commit 123)';
       assert.equal(element.message, expectedMessage);
     });
 
-    test('with unmerged change', function() {
+    test('with unmerged change', () => {
       element.changeStatus = 'OPEN';
       element.commitMessage = 'message\n';
       element.commitNum = '123';
       element.branch = 'master';
       flushAsynchronousOperations();
-      var expectedMessage = 'message\n';
+      const expectedMessage = 'message\n';
       assert.equal(element.message, expectedMessage);
     });
 
-    test('with updated commit message', function() {
+    test('with updated commit message', () => {
       element.changeStatus = 'OPEN';
       element.commitMessage = 'message\n';
       element.commitNum = '123';
       element.branch = 'master';
-      var myNewMessage = 'updated commit message';
+      const myNewMessage = 'updated commit message';
       element.message = myNewMessage;
       flushAsynchronousOperations();
-      var expectedMessage = 'message\n';
       assert.equal(element.message, myNewMessage);
     });
   });
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-rebase-dialog/gr-confirm-rebase-dialog.js b/polygerrit-ui/app/elements/change/gr-confirm-rebase-dialog/gr-confirm-rebase-dialog.js
index 4ecb31f..6cb7a9b 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-rebase-dialog/gr-confirm-rebase-dialog.js
+++ b/polygerrit-ui/app/elements/change/gr-confirm-rebase-dialog/gr-confirm-rebase-dialog.js
@@ -40,29 +40,29 @@
       '_updateSelectedOption(rebaseOnCurrent, hasParent)',
     ],
 
-    _displayParentOption: function(rebaseOnCurrent, hasParent) {
+    _displayParentOption(rebaseOnCurrent, hasParent) {
       return hasParent && rebaseOnCurrent;
     },
 
-    _displayParentUpToDateMsg: function(rebaseOnCurrent, hasParent) {
+    _displayParentUpToDateMsg(rebaseOnCurrent, hasParent) {
       return hasParent && !rebaseOnCurrent;
     },
 
-    _displayTipOption: function(rebaseOnCurrent, hasParent) {
+    _displayTipOption(rebaseOnCurrent, hasParent) {
       return !(!rebaseOnCurrent && !hasParent);
     },
 
-    _handleConfirmTap: function(e) {
+    _handleConfirmTap(e) {
       e.preventDefault();
       this.fire('confirm', null, {bubbles: false});
     },
 
-    _handleCancelTap: function(e) {
+    _handleCancelTap(e) {
       e.preventDefault();
       this.fire('cancel', null, {bubbles: false});
     },
 
-    _handleRebaseOnOther: function(e) {
+    _handleRebaseOnOther(e) {
       this.$.parentInput.focus();
     },
 
@@ -73,15 +73,15 @@
      * rebased on top of the target branch. Leaving out the base implies that it
      * should be rebased on top of its current parent.
      */
-    _handleRebaseOnTip: function(e) {
+    _handleRebaseOnTip(e) {
       this.base = '';
     },
 
-    _handleRebaseOnParent: function(e) {
+    _handleRebaseOnParent(e) {
       this.base = null;
     },
 
-    _handleEnterChangeNumberTap: function(e) {
+    _handleEnterChangeNumberTap(e) {
       this.$.rebaseOnOtherInput.checked = true;
     },
 
@@ -89,7 +89,7 @@
      * Sets the default radio button based on the state of the app and
      * the corresponding value to be submitted.
      */
-    _updateSelectedOption: function(rebaseOnCurrent, hasParent) {
+    _updateSelectedOption(rebaseOnCurrent, hasParent) {
       if (this._displayParentOption(rebaseOnCurrent, hasParent)) {
         this.$.rebaseOnParentInput.checked = true;
         this._handleRebaseOnParent();
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-rebase-dialog/gr-confirm-rebase-dialog_test.html b/polygerrit-ui/app/elements/change/gr-confirm-rebase-dialog/gr-confirm-rebase-dialog_test.html
index 37eb812..bb9651b 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-rebase-dialog/gr-confirm-rebase-dialog_test.html
+++ b/polygerrit-ui/app/elements/change/gr-confirm-rebase-dialog/gr-confirm-rebase-dialog_test.html
@@ -33,14 +33,14 @@
 </test-fixture>
 
 <script>
-  suite('gr-confirm-rebase-dialog tests', function() {
-    var element;
+  suite('gr-confirm-rebase-dialog tests', () => {
+    let element;
 
-    setup(function() {
+    setup(() => {
       element = fixture('basic');
     });
 
-    test('controls with parent and rebase on current available', function() {
+    test('controls with parent and rebase on current available', () => {
       element.rebaseOnCurrent = true;
       element.hasParent = true;
       flushAsynchronousOperations();
@@ -51,7 +51,7 @@
       assert.isTrue(element.$.tipUpToDateMsg.hasAttribute('hidden'));
     });
 
-    test('controls with parent rebase on current not available', function() {
+    test('controls with parent rebase on current not available', () => {
       element.rebaseOnCurrent = false;
       element.hasParent = true;
       flushAsynchronousOperations();
@@ -62,7 +62,7 @@
       assert.isTrue(element.$.tipUpToDateMsg.hasAttribute('hidden'));
     });
 
-    test('controls without parent and rebase on current available', function() {
+    test('controls without parent and rebase on current available', () => {
       element.rebaseOnCurrent = true;
       element.hasParent = false;
       flushAsynchronousOperations();
@@ -73,7 +73,7 @@
       assert.isTrue(element.$.tipUpToDateMsg.hasAttribute('hidden'));
     });
 
-    test('controls without parent rebase on current not available', function() {
+    test('controls without parent rebase on current not available', () => {
       element.rebaseOnCurrent = false;
       element.hasParent = false;
       flushAsynchronousOperations();
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-revert-dialog/gr-confirm-revert-dialog.js b/polygerrit-ui/app/elements/change/gr-confirm-revert-dialog/gr-confirm-revert-dialog.js
index 8f621f0..4a1bbb8 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-revert-dialog/gr-confirm-revert-dialog.js
+++ b/polygerrit-ui/app/elements/change/gr-confirm-revert-dialog/gr-confirm-revert-dialog.js
@@ -33,27 +33,26 @@
       message: String,
     },
 
-    populateRevertMessage: function(message, commitHash) {
+    populateRevertMessage(message, commitHash) {
       // Figure out what the revert title should be.
-      var originalTitle = message.split('\n')[0];
-      var revertTitle = 'Revert "' + originalTitle + '"';
+      const originalTitle = message.split('\n')[0];
+      const revertTitle = `Revert "${originalTitle}"`;
       if (!commitHash) {
         alert('Unable to find the commit hash of this change.');
         return;
       }
-      var revertCommitText = 'This reverts commit ' + commitHash + '.';
+      const revertCommitText = `This reverts commit ${commitHash}.`;
 
-      this.message = revertTitle + '\n\n' +
-                     revertCommitText + '\n\n' +
-                     'Reason for revert: <INSERT REASONING HERE>\n';
+      this.message = `${revertTitle}\n\n${revertCommitText}\n\n` +
+          `Reason for revert: <INSERT REASONING HERE>\n`;
     },
 
-    _handleConfirmTap: function(e) {
+    _handleConfirmTap(e) {
       e.preventDefault();
       this.fire('confirm', null, {bubbles: false});
     },
 
-    _handleCancelTap: function(e) {
+    _handleCancelTap(e) {
       e.preventDefault();
       this.fire('cancel', null, {bubbles: false});
     },
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-revert-dialog/gr-confirm-revert-dialog_test.html b/polygerrit-ui/app/elements/change/gr-confirm-revert-dialog/gr-confirm-revert-dialog_test.html
index d5c459b..78b0dfc 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-revert-dialog/gr-confirm-revert-dialog_test.html
+++ b/polygerrit-ui/app/elements/change/gr-confirm-revert-dialog/gr-confirm-revert-dialog_test.html
@@ -33,62 +33,62 @@
 </test-fixture>
 
 <script>
-  suite('gr-confirm-revert-dialog tests', function() {
-    var element;
+  suite('gr-confirm-revert-dialog tests', () => {
+    let element;
 
-    setup(function() {
+    setup(() => {
       element = fixture('basic');
     });
 
-    test('no match', function() {
+    test('no match', () => {
       assert.isNotOk(element.message);
-      var alertStub = sinon.stub(window, 'alert');
+      const alertStub = sinon.stub(window, 'alert');
       element.populateRevertMessage('not a commitHash in sight', undefined);
       assert.isTrue(alertStub.calledOnce);
       alertStub.restore();
     });
 
-    test('single line', function() {
+    test('single line', () => {
       assert.isNotOk(element.message);
       element.populateRevertMessage(
           'one line commit\n\nChange-Id: abcdefg\n',
           'abcd123');
-      var expected = 'Revert "one line commit"\n\n' +
-                     'This reverts commit abcd123.\n\n' +
-                     'Reason for revert: <INSERT REASONING HERE>\n';
+      const expected = 'Revert "one line commit"\n\n' +
+          'This reverts commit abcd123.\n\n' +
+          'Reason for revert: <INSERT REASONING HERE>\n';
       assert.equal(element.message, expected);
     });
 
-    test('multi line', function() {
+    test('multi line', () => {
       assert.isNotOk(element.message);
       element.populateRevertMessage(
           'many lines\ncommit\n\nmessage\n\nChange-Id: abcdefg\n',
           'abcd123');
-      var expected = 'Revert "many lines"\n\n' +
-                     'This reverts commit abcd123.\n\n' +
-                     'Reason for revert: <INSERT REASONING HERE>\n';
+      const expected = 'Revert "many lines"\n\n' +
+          'This reverts commit abcd123.\n\n' +
+          'Reason for revert: <INSERT REASONING HERE>\n';
       assert.equal(element.message, expected);
     });
 
-    test('issue above change id', function() {
+    test('issue above change id', () => {
       assert.isNotOk(element.message);
       element.populateRevertMessage(
           'much lines\nvery\n\ncommit\n\nBug: Issue 42\nChange-Id: abcdefg\n',
           'abcd123');
-      var expected = 'Revert "much lines"\n\n' +
-                     'This reverts commit abcd123.\n\n' +
-                     'Reason for revert: <INSERT REASONING HERE>\n';
+      const expected = 'Revert "much lines"\n\n' +
+          'This reverts commit abcd123.\n\n' +
+          'Reason for revert: <INSERT REASONING HERE>\n';
       assert.equal(element.message, expected);
     });
 
-    test('revert a revert', function() {
+    test('revert a revert', () => {
       assert.isNotOk(element.message);
       element.populateRevertMessage(
           'Revert "one line commit"\n\nChange-Id: abcdefg\n',
           'abcd123');
-      var expected = 'Revert "Revert "one line commit""\n\n' +
-                     'This reverts commit abcd123.\n\n' +
-                     'Reason for revert: <INSERT REASONING HERE>\n';
+      const expected = 'Revert "Revert "one line commit""\n\n' +
+          'This reverts commit abcd123.\n\n' +
+          'Reason for revert: <INSERT REASONING HERE>\n';
       assert.equal(element.message, expected);
     });
   });
diff --git a/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog.js b/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog.js
index f843ee8..b26802d 100644
--- a/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog.js
+++ b/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog.js
@@ -35,7 +35,7 @@
 
       _schemes: {
         type: Array,
-        value: function() { return []; },
+        value() { return []; },
         computed: '_computeSchemes(change, patchNum)',
         observer: '_schemesChanged',
       },
@@ -50,7 +50,7 @@
       Gerrit.RESTClientBehavior,
     ],
 
-    focus: function() {
+    focus() {
       if (this._schemes.length) {
         this.$$('.copyToClipboard').focus();
       } else {
@@ -58,59 +58,60 @@
       }
     },
 
-    getFocusStops: function() {
-      var links = this.$$('#archives').querySelectorAll('a');
+    getFocusStops() {
+      const links = this.$$('#archives').querySelectorAll('a');
       return {
         start: this.$.closeButton,
         end: links[links.length - 1],
       };
     },
 
-    _loggedInChanged: function(loggedIn) {
+    _loggedInChanged(loggedIn) {
       if (!loggedIn) { return; }
-      this.$.restAPI.getPreferences().then(function(prefs) {
+      this.$.restAPI.getPreferences().then(prefs => {
         if (prefs.download_scheme) {
           // Note (issue 5180): normalize the download scheme with lower-case.
           this._selectedScheme = prefs.download_scheme.toLowerCase();
         }
-      }.bind(this));
+      });
     },
 
-    _computeDownloadCommands: function(change, patchNum, _selectedScheme) {
-      var commandObj;
-      for (var rev in change.revisions) {
+    _computeDownloadCommands(change, patchNum, _selectedScheme) {
+      let commandObj;
+      for (const rev in change.revisions) {
         if (change.revisions[rev]._number === patchNum &&
             change.revisions[rev].fetch.hasOwnProperty(_selectedScheme)) {
           commandObj = change.revisions[rev].fetch[_selectedScheme].commands;
           break;
         }
       }
-      var commands = [];
-      for (var title in commandObj) {
+      const commands = [];
+      for (const title in commandObj) {
+        if (!commandObj.hasOwnProperty(title)) { continue; }
         commands.push({
-          title: title,
+          title,
           command: commandObj[title],
         });
       }
       return commands;
     },
 
-    _computeZipDownloadLink: function(change, patchNum) {
+    _computeZipDownloadLink(change, patchNum) {
       return this._computeDownloadLink(change, patchNum, true);
     },
 
-    _computeZipDownloadFilename: function(change, patchNum) {
+    _computeZipDownloadFilename(change, patchNum) {
       return this._computeDownloadFilename(change, patchNum, true);
     },
 
-    _computeDownloadLink: function(change, patchNum, zip) {
+    _computeDownloadLink(change, patchNum, zip) {
       return this.changeBaseURL(change._number, patchNum) + '/patch?' +
           (zip ? 'zip' : 'download');
     },
 
-    _computeDownloadFilename: function(change, patchNum, zip) {
-      var shortRev;
-      for (var rev in change.revisions) {
+    _computeDownloadFilename(change, patchNum, zip) {
+      let shortRev;
+      for (const rev in change.revisions) {
         if (change.revisions[rev]._number === patchNum) {
           shortRev = rev.substr(0, 7);
           break;
@@ -119,15 +120,15 @@
       return shortRev + '.diff.' + (zip ? 'zip' : 'base64');
     },
 
-    _computeArchiveDownloadLink: function(change, patchNum, format) {
+    _computeArchiveDownloadLink(change, patchNum, format) {
       return this.changeBaseURL(change._number, patchNum) +
           '/archive?format=' + format;
     },
 
-    _computeSchemes: function(change, patchNum) {
-      for (var rev in change.revisions) {
+    _computeSchemes(change, patchNum) {
+      for (const rev in change.revisions) {
         if (change.revisions[rev]._number === patchNum) {
-          var fetch = change.revisions[rev].fetch;
+          const fetch = change.revisions[rev].fetch;
           if (fetch) {
             return Object.keys(fetch).sort();
           }
@@ -137,47 +138,47 @@
       return [];
     },
 
-    _computePatchSetQuantity: function(revisions) {
+    _computePatchSetQuantity(revisions) {
       if (!revisions) { return 0; }
       return Object.keys(revisions).length;
     },
 
-    _computeSchemeSelected: function(scheme, selectedScheme) {
+    _computeSchemeSelected(scheme, selectedScheme) {
       return scheme === selectedScheme;
     },
 
-    _handleSchemeTap: function(e) {
+    _handleSchemeTap(e) {
       e.preventDefault();
-      var el = Polymer.dom(e).rootTarget;
+      const el = Polymer.dom(e).rootTarget;
       this._selectedScheme = el.getAttribute('data-scheme');
       if (this.loggedIn) {
         this.$.restAPI.savePreferences({download_scheme: this._selectedScheme});
       }
     },
 
-    _handleInputTap: function(e) {
+    _handleInputTap(e) {
       e.preventDefault();
       Polymer.dom(e).rootTarget.select();
     },
 
-    _handleCloseTap: function(e) {
+    _handleCloseTap(e) {
       e.preventDefault();
       this.fire('close', null, {bubbles: false});
     },
 
-    _schemesChanged: function(schemes) {
+    _schemesChanged(schemes) {
       if (schemes.length === 0) { return; }
-      if (schemes.indexOf(this._selectedScheme) === -1) {
+      if (!schemes.includes(this._selectedScheme)) {
         this._selectedScheme = schemes.sort()[0];
       }
     },
 
-    _copyToClipboard: function(e) {
+    _copyToClipboard(e) {
       e.target.parentElement.querySelector('.copyCommand').select();
       document.execCommand('copy');
       getSelection().removeAllRanges();
       e.target.textContent = 'done';
-      setTimeout(function() { e.target.textContent = 'copy'; }, 1000);
+      setTimeout(() => { e.target.textContent = 'copy'; }, 1000);
     },
   });
 })();
diff --git a/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog_test.html b/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog_test.html
index 0635d6d..4a8d2d9 100644
--- a/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog_test.html
+++ b/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog_test.html
@@ -48,8 +48,8 @@
           fetch: {
             repo: {
               commands: {
-                repo: 'repo download test-project 5/1'
-              }
+                repo: 'repo download test-project 5/1',
+              },
             },
             ssh: {
               commands: {
@@ -69,8 +69,8 @@
                 'Pull':
                   'git pull ' +
                   'ssh://andybons@localhost:29418/test-project ' +
-                  'refs/changes/05/5/1'
-              }
+                  'refs/changes/05/5/1',
+              },
             },
             http: {
               commands: {
@@ -90,12 +90,12 @@
                 'Pull':
                   'git pull ' +
                   'http://andybons@localhost:8080/a/test-project ' +
-                  'refs/changes/05/5/1'
-              }
-            }
-          }
-        }
-      }
+                  'refs/changes/05/5/1',
+              },
+            },
+          },
+        },
+      },
     };
   }
 
@@ -106,74 +106,74 @@
         '34685798fe548b6d17d1e8e5edc43a26d055cc72': {
           _number: 1,
           fetch: {},
-        }
-      }
+        },
+      },
     };
   }
 
-  suite('gr-download-dialog tests with no fetch options', function() {
-    var element;
+  suite('gr-download-dialog tests with no fetch options', () => {
+    let element;
 
-    setup(function() {
+    setup(() => {
       element = fixture('basic');
       element.change = getChangeObjectNoFetch();
       element.patchNum = 1;
       element.config = {
         schemes: {
           'anonymous http': {},
-          http: {},
-          repo: {},
-          ssh: {},
+          'http': {},
+          'repo': {},
+          'ssh': {},
         },
         archives: ['tgz', 'tar', 'tbz2', 'txz'],
       };
     });
 
-    test('focuses on first download link if no copy links', function() {
+    test('focuses on first download link if no copy links', () => {
       flushAsynchronousOperations();
-      var focusStub = sinon.stub(element.$.download, 'focus');
+      const focusStub = sinon.stub(element.$.download, 'focus');
       element.focus();
       assert.isTrue(focusStub.called);
       focusStub.restore();
     });
   });
 
-  suite('gr-download-dialog tests', function() {
-    var element;
+  suite('gr-download-dialog tests', () => {
+    let element;
 
-    setup(function() {
+    setup(() => {
       element = fixture('basic');
       element.change = getChangeObject();
       element.patchNum = 1;
       element.config = {
         schemes: {
           'anonymous http': {},
-          http: {},
-          repo: {},
-          ssh: {},
+          'http': {},
+          'repo': {},
+          'ssh': {},
         },
         archives: ['tgz', 'tar', 'tbz2', 'txz'],
       };
     });
 
-    test('focuses on first copy link', function() {
+    test('focuses on first copy link', () => {
       flushAsynchronousOperations();
-      var focusStub = sinon.stub(element.$$('.copyToClipboard'), 'focus');
+      const focusStub = sinon.stub(element.$$('.copyToClipboard'), 'focus');
       element.focus();
       flushAsynchronousOperations();
       assert.isTrue(focusStub.called);
       focusStub.restore();
     });
 
-    test('copy to clipboard', function() {
+    test('copy to clipboard', () => {
       flushAsynchronousOperations();
-      var clipboardSpy = sinon.spy(element, '_copyToClipboard');
-      var copyBtn = element.$$('.copyToClipboard');
+      const clipboardSpy = sinon.spy(element, '_copyToClipboard');
+      const copyBtn = element.$$('.copyToClipboard');
       MockInteractions.tap(copyBtn);
       assert.isTrue(clipboardSpy.called);
     });
 
-    test('element visibility', function() {
+    test('element visibility', () => {
       assert.isFalse(element.$$('ul').hasAttribute('hidden'));
       assert.isFalse(element.$$('main').hasAttribute('hidden'));
       assert.isFalse(element.$$('.archivesContainer').hasAttribute('hidden'));
@@ -182,40 +182,40 @@
       assert.isTrue(element.$$('.archivesContainer').hasAttribute('hidden'));
     });
 
-    test('computed fields', function() {
+    test('computed fields', () => {
       assert.equal(element._computeArchiveDownloadLink(
           {_number: 123}, 2, 'tgz'),
           '/changes/123/revisions/2/archive?format=tgz');
     });
 
-    test('close event', function(done) {
-      element.addEventListener('close', function() {
+    test('close event', done => {
+      element.addEventListener('close', () => {
         done();
       });
       MockInteractions.tap(element.$$('.closeButtonContainer gr-button'));
     });
 
-    test('tab selection', function() {
+    test('tab selection', () => {
       flushAsynchronousOperations();
-      var el = element.$$('[data-scheme="http"]').parentElement;
+      let el = element.$$('[data-scheme="http"]').parentElement;
       assert.isTrue(el.hasAttribute('selected'));
-      ['repo', 'ssh'].forEach(function(scheme) {
-        var el = element.$$('[data-scheme="' + scheme + '"]').parentElement;
+      for (const scheme of ['repo', 'ssh']) {
+        const el = element.$$('[data-scheme="' + scheme + '"]').parentElement;
         assert.isFalse(el.hasAttribute('selected'));
-      });
+      }
 
       MockInteractions.tap(element.$$('[data-scheme="ssh"]'));
       el = element.$$('[data-scheme="ssh"]').parentElement;
       assert.isTrue(el.hasAttribute('selected'));
-      ['http', 'repo'].forEach(function(scheme) {
-        var el = element.$$('[data-scheme="' + scheme + '"]').parentElement;
+      for (const scheme of ['http', 'repo']) {
+        const el = element.$$('[data-scheme="' + scheme + '"]').parentElement;
         assert.isFalse(el.hasAttribute('selected'));
-      });
+      }
     });
 
-    test('loads scheme from preferences w/o initial login', function(done) {
+    test('loads scheme from preferences w/o initial login', done => {
       stub('gr-rest-api-interface', {
-        getPreferences: function() {
+        getPreferences() {
           return Promise.resolve({download_scheme: 'repo'});
         },
       });
@@ -223,19 +223,19 @@
       element.loggedIn = true;
 
       assert.isTrue(element.$.restAPI.getPreferences.called);
-      element.$.restAPI.getPreferences.lastCall.returnValue.then(function() {
+      element.$.restAPI.getPreferences.lastCall.returnValue.then(() => {
         assert.equal(element._selectedScheme, 'repo');
         done();
       });
     });
   });
 
-  suite('gr-download-dialog tests', function() {
-    var element;
+  suite('gr-download-dialog tests', () => {
+    let element;
 
-    setup(function() {
+    setup(() => {
       stub('gr-rest-api-interface', {
-        getPreferences: function() {
+        getPreferences() {
           return Promise.resolve({download_scheme: 'repo'});
         },
       });
@@ -246,28 +246,28 @@
       element.config = {
         schemes: {
           'anonymous http': {},
-          http: {},
-          repo: {},
-          ssh: {},
+          'http': {},
+          'repo': {},
+          'ssh': {},
         },
         archives: ['tgz', 'tar', 'tbz2', 'txz'],
       };
     });
 
-    test('loads scheme from preferences', function(done) {
-      element.$.restAPI.getPreferences.lastCall.returnValue.then(function() {
+    test('loads scheme from preferences', done => {
+      element.$.restAPI.getPreferences.lastCall.returnValue.then(() => {
         assert.equal(element._selectedScheme, 'repo');
         done();
       });
     });
 
-    test('saves scheme to preferences', function() {
-      var savePrefsStub = sinon.stub(element.$.restAPI, 'savePreferences',
-          function() { return Promise.resolve(); });
+    test('saves scheme to preferences', () => {
+      const savePrefsStub = sinon.stub(element.$.restAPI, 'savePreferences',
+          () => { return Promise.resolve(); });
 
       Polymer.dom.flush();
 
-      var firstSchemeButton = element.$$('li gr-button[data-scheme]');
+      const firstSchemeButton = element.$$('li gr-button[data-scheme]');
 
       MockInteractions.tap(firstSchemeButton);
 
@@ -277,9 +277,9 @@
     });
   });
 
-  test('normalize scheme from preferences', function(done) {
+  test('normalize scheme from preferences', done => {
     stub('gr-rest-api-interface', {
-      getPreferences: function() {
+      getPreferences() {
         return Promise.resolve({download_scheme: 'REPO'});
       },
     });
@@ -287,10 +287,10 @@
     element.change = getChangeObject();
     element.patchNum = 1;
     element.config = {
-      schemes: {'anonymous http': {}, http: {}, repo: {}, ssh: {}},
+      schemes: {'anonymous http': {}, 'http': {}, 'repo': {}, 'ssh': {}},
       archives: ['tgz', 'tar', 'tbz2', 'txz'],
     };
-    element.$.restAPI.getPreferences.lastCall.returnValue.then(function() {
+    element.$.restAPI.getPreferences.lastCall.returnValue.then(() => {
       assert.equal(element._selectedScheme, 'repo');
       done();
     });
diff --git a/polygerrit-ui/app/elements/change/gr-message/gr-message.js b/polygerrit-ui/app/elements/change/gr-message/gr-message.js
index 5467af9..919ef6b 100644
--- a/polygerrit-ui/app/elements/change/gr-message/gr-message.js
+++ b/polygerrit-ui/app/elements/change/gr-message/gr-message.js
@@ -30,7 +30,7 @@
      */
 
     listeners: {
-      'tap': '_handleTap',
+      tap: '_handleTap',
     },
 
     properties: {
@@ -86,16 +86,16 @@
       '_updateExpandedClass(message.expanded)',
     ],
 
-    ready: function() {
-      this.$.restAPI.getConfig().then(function(config) {
+    ready() {
+      this.$.restAPI.getConfig().then(config => {
         this.config = config;
-      }.bind(this));
-      this.$.restAPI.getLoggedIn().then(function(loggedIn) {
+      });
+      this.$.restAPI.getLoggedIn().then(loggedIn => {
         this._loggedIn = loggedIn;
-      }.bind(this));
+      });
     },
 
-    _updateExpandedClass: function(expanded) {
+    _updateExpandedClass(expanded) {
       if (expanded) {
         this.classList.add('expanded');
       } else {
@@ -103,25 +103,25 @@
       }
     },
 
-    _computeAuthor: function(message) {
+    _computeAuthor(message) {
       return message.author || message.updated_by;
     },
 
-    _computeShowAvatar: function(author, config) {
+    _computeShowAvatar(author, config) {
       return !!(author && config && config.plugin && config.plugin.has_avatars);
     },
 
-    _computeShowOnBehalfOf: function(message) {
-      var author = message.author || message.updated_by;
+    _computeShowOnBehalfOf(message) {
+      const author = message.author || message.updated_by;
       return !!(author && message.real_author &&
           author._account_id != message.real_author._account_id);
     },
 
-    _computeShowReplyButton: function(message, loggedIn) {
+    _computeShowReplyButton(message, loggedIn) {
       return !!message.message && loggedIn;
     },
 
-    _computeExpanded: function(expanded) {
+    _computeExpanded(expanded) {
       return expanded;
     },
 
@@ -130,54 +130,54 @@
      * should be true or not, then _expanded is set to true if there are
      * inline comments (otherwise false).
      */
-    _commentsChanged: function(value) {
+    _commentsChanged(value) {
       if (this.message && this.message.expanded === undefined) {
         this.set('message.expanded', Object.keys(value || {}).length > 0);
       }
     },
 
-    _handleTap: function(e) {
+    _handleTap(e) {
       if (this.message.expanded) { return; }
       e.stopPropagation();
       this.set('message.expanded', true);
     },
 
-    _handleAuthorTap: function(e) {
+    _handleAuthorTap(e) {
       if (!this.message.expanded) { return; }
       e.stopPropagation();
       this.set('message.expanded', false);
     },
 
-    _computeIsAutomated: function(message) {
+    _computeIsAutomated(message) {
       return !!(message.reviewer ||
-          (message.tag && message.tag.indexOf('autogenerated') === 0));
+          (message.tag && message.tag.startsWith('autogenerated')));
     },
 
-    _computeIsHidden: function(hideAutomated, isAutomated) {
+    _computeIsHidden(hideAutomated, isAutomated) {
       return hideAutomated && isAutomated;
     },
 
-    _computeIsReviewerUpdate: function(event) {
+    _computeIsReviewerUpdate(event) {
       return event.type === 'REVIEWER_UPDATE';
     },
 
-    _computeClass: function(expanded, showAvatar) {
-      var classes = [];
+    _computeClass(expanded, showAvatar) {
+      const classes = [];
       classes.push(expanded ? 'expanded' : 'collapsed');
       classes.push(showAvatar ? 'showAvatar' : 'hideAvatar');
       return classes.join(' ');
     },
 
-    _computeMessageHash: function(message) {
+    _computeMessageHash(message) {
       return '#message-' + message.id;
     },
 
-    _handleLinkTap: function(e) {
+    _handleLinkTap(e) {
       e.preventDefault();
 
       this.fire('scroll-to', {message: this.message}, {bubbles: false});
 
-      var hash = this._computeMessageHash(this.message);
+      const hash = this._computeMessageHash(this.message);
       // Don't add the hash to the window history if it's already there.
       // Otherwise you mess up expected back button behavior.
       if (window.location.hash == hash) { return; }
@@ -186,7 +186,7 @@
       page.show(window.location.pathname + hash, null, false);
     },
 
-    _handleReplyTap: function(e) {
+    _handleReplyTap(e) {
       e.preventDefault();
       this.fire('reply', {message: this.message});
     },
diff --git a/polygerrit-ui/app/elements/change/gr-message/gr-message_test.html b/polygerrit-ui/app/elements/change/gr-message/gr-message_test.html
index 72c09d9..5f8b312 100644
--- a/polygerrit-ui/app/elements/change/gr-message/gr-message_test.html
+++ b/polygerrit-ui/app/elements/change/gr-message/gr-message_test.html
@@ -33,30 +33,30 @@
 </test-fixture>
 
 <script>
-  suite('gr-message tests', function() {
-    var element;
+  suite('gr-message tests', () => {
+    let element;
 
-    setup(function() {
+    setup(() => {
       stub('gr-rest-api-interface', {
-        getLoggedIn: function() { return Promise.resolve(false); },
+        getLoggedIn() { return Promise.resolve(false); },
       });
       element = fixture('basic');
     });
 
-    test('reply event', function(done) {
+    test('reply event', done => {
       element.message = {
-        'id': '47c43261_55aa2c41',
-        'author': {
-          '_account_id': 1115495,
-          'name': 'Andrew Bonventre',
-          'email': 'andybons@chromium.org',
+        id: '47c43261_55aa2c41',
+        author: {
+          _account_id: 1115495,
+          name: 'Andrew Bonventre',
+          email: 'andybons@chromium.org',
         },
-        'date': '2016-01-12 20:24:49.448000000',
-        'message': 'Uploaded patch set 1.',
-        '_revision_number': 1
+        date: '2016-01-12 20:24:49.448000000',
+        message: 'Uploaded patch set 1.',
+        _revision_number: 1,
       };
 
-      element.addEventListener('reply', function(e) {
+      element.addEventListener('reply', e => {
         assert.deepEqual(e.detail.message, element.message);
         done();
       });
@@ -64,38 +64,38 @@
       MockInteractions.tap(element.$$('.replyContainer gr-button'));
     });
 
-    test('reviewer update', function() {
-      var author = {
+    test('reviewer update', () => {
+      const author = {
         _account_id: 1115495,
         name: 'Andrew Bonventre',
         email: 'andybons@chromium.org',
       };
-      var reviewer = {
+      const reviewer = {
         _account_id: 123456,
         name: 'Foo Bar',
         email: 'barbar@chromium.org',
       };
       element.message = {
         id: 0xDEADBEEF,
-        author: author,
-        reviewer: reviewer,
+        author,
+        reviewer,
         date: '2016-01-12 20:24:49.448000000',
         type: 'REVIEWER_UPDATE',
         updates: [
           {
             message: 'Added to CC:',
             reviewers: [reviewer],
-          }
+          },
         ],
       };
       flushAsynchronousOperations();
-      var content = element.$$('.contentContainer');
+      const content = element.$$('.contentContainer');
       assert.isOk(content);
       assert.strictEqual(element.$$('gr-account-chip').account, reviewer);
       assert.equal(author.name, element.$$('.author > .name').textContent);
     });
 
-    test('autogenerated prefix hiding', function() {
+    test('autogenerated prefix hiding', () => {
       element.message = {
         tag: 'autogenerated:gerrit:test',
         updated: '2016-01-12 20:24:49.448000000',
@@ -109,7 +109,7 @@
       assert.isTrue(element.hidden);
     });
 
-    test('reviewer message treated as autogenerated', function() {
+    test('reviewer message treated as autogenerated', () => {
       element.message = {
         tag: 'autogenerated:gerrit:test',
         updated: '2016-01-12 20:24:49.448000000',
@@ -124,7 +124,7 @@
       assert.isTrue(element.hidden);
     });
 
-    test('tag that is not autogenerated prefix does not hide', function() {
+    test('tag that is not autogenerated prefix does not hide', () => {
       element.message = {
         tag: 'something',
         updated: '2016-01-12 20:24:49.448000000',
@@ -138,16 +138,16 @@
       assert.isFalse(element.hidden);
     });
 
-    test('reply button hidden unless logged in', function() {
-      var message = {
-        'message': 'Uploaded patch set 1.',
+    test('reply button hidden unless logged in', () => {
+      const message = {
+        message: 'Uploaded patch set 1.',
       };
       assert.isFalse(element._computeShowReplyButton(message, false));
       assert.isTrue(element._computeShowReplyButton(message, true));
     });
 
-    test('_computeShowOnBehalfOf', function() {
-      var message = {
+    test('_computeShowOnBehalfOf', () => {
+      const message = {
         message: '...',
       };
       assert.isNotOk(element._computeShowOnBehalfOf(message));
diff --git a/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list.js b/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list.js
index 8501b20..fe35c7f 100644
--- a/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list.js
+++ b/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list.js
@@ -41,23 +41,23 @@
       },
       _relatedResponse: {
         type: Object,
-        value: function() { return {changes: []}; },
+        value() { return {changes: []}; },
       },
       _submittedTogether: {
         type: Array,
-        value: function() { return []; },
+        value() { return []; },
       },
       _conflicts: {
         type: Array,
-        value: function() { return []; },
+        value() { return []; },
       },
       _cherryPicks: {
         type: Array,
-        value: function() { return []; },
+        value() { return []; },
       },
       _sameTopic: {
         type: Array,
-        value: function() { return []; },
+        value() { return []; },
       },
     },
 
@@ -71,53 +71,52 @@
           '_conflicts, _cherryPicks, _sameTopic)',
     ],
 
-    clear: function() {
+    clear() {
       this.loading = true;
       this.hidden = true;
     },
 
-    reload: function() {
+    reload() {
       if (!this.change || !this.patchNum) {
         return Promise.resolve();
       }
       this.loading = true;
-      var promises = [
-        this._getRelatedChanges().then(function(response) {
+      const promises = [
+        this._getRelatedChanges().then(response => {
           this._relatedResponse = response;
 
           this.hasParent = this._calculateHasParent(this.change.change_id,
               response.changes);
-
-        }.bind(this)),
-        this._getSubmittedTogether().then(function(response) {
+        }),
+        this._getSubmittedTogether().then(response => {
           this._submittedTogether = response;
-        }.bind(this)),
-        this._getCherryPicks().then(function(response) {
+        }),
+        this._getCherryPicks().then(response => {
           this._cherryPicks = response;
-        }.bind(this)),
+        }),
       ];
 
       // Get conflicts if change is open and is mergeable.
       if (this.changeIsOpen(this.change.status) && this.change.mergeable) {
-        promises.push(this._getConflicts().then(function(response) {
+        promises.push(this._getConflicts().then(response => {
           this._conflicts = response;
-        }.bind(this)));
+        }));
       }
 
-      promises.push(this._getServerConfig().then(function(config) {
+      promises.push(this._getServerConfig().then(config => {
         if (this.change.topic && !config.change.submit_whole_topic) {
-          return this._getChangesWithSameTopic().then(function(response) {
+          return this._getChangesWithSameTopic().then(response => {
             this._sameTopic = response;
-          }.bind(this));
+          });
         } else {
           this._sameTopic = [];
         }
         return this._sameTopic;
-      }.bind(this)));
+      }));
 
-      return Promise.all(promises).then(function() {
+      return Promise.all(promises).then(() => {
         this.loading = false;
-      }.bind(this));
+      });
     },
 
     /**
@@ -128,62 +127,62 @@
      * @param  {Array} relatedChanges
      * @return {Boolean}
      */
-    _calculateHasParent: function(currentChangeId, relatedChanges) {
+    _calculateHasParent(currentChangeId, relatedChanges) {
       return relatedChanges.length > 0 &&
           relatedChanges[relatedChanges.length - 1].change_id !==
           currentChangeId;
     },
 
-    _getRelatedChanges: function() {
+    _getRelatedChanges() {
       return this.$.restAPI.getRelatedChanges(this.change._number,
           this.patchNum);
     },
 
-    _getSubmittedTogether: function() {
+    _getSubmittedTogether() {
       return this.$.restAPI.getChangesSubmittedTogether(this.change._number);
     },
 
-    _getServerConfig: function() {
+    _getServerConfig() {
       return this.$.restAPI.getConfig();
     },
 
-    _getConflicts: function() {
+    _getConflicts() {
       return this.$.restAPI.getChangeConflicts(this.change._number);
     },
 
-    _getCherryPicks: function() {
+    _getCherryPicks() {
       return this.$.restAPI.getChangeCherryPicks(this.change.project,
           this.change.change_id, this.change._number);
     },
 
-    _getChangesWithSameTopic: function() {
+    _getChangesWithSameTopic() {
       return this.$.restAPI.getChangesWithSameTopic(this.change.topic);
     },
 
-    _computeChangeURL: function(changeNum, patchNum) {
-      var urlStr = this.getBaseUrl() + '/c/' + changeNum;
+    _computeChangeURL(changeNum, patchNum) {
+      let urlStr = this.getBaseUrl() + '/c/' + changeNum;
       if (patchNum != null) {
         urlStr += '/' + patchNum;
       }
       return urlStr;
     },
 
-    _computeChangeContainerClass: function(currentChange, relatedChange) {
-      var classes = ['changeContainer'];
+    _computeChangeContainerClass(currentChange, relatedChange) {
+      const classes = ['changeContainer'];
       if (relatedChange.change_id === currentChange.change_id) {
         classes.push('thisChange');
       }
       return classes.join(' ');
     },
 
-    _computeLinkClass: function(change) {
+    _computeLinkClass(change) {
       if (change.status == this.ChangeStatus.ABANDONED) {
         return 'strikethrough';
       }
     },
 
-    _computeChangeStatusClass: function(change) {
-      var classes = ['status'];
+    _computeChangeStatusClass(change) {
+      const classes = ['status'];
       if (change._revision_number != change._current_revision_number) {
         classes.push('notCurrent');
       } else if (this._isIndirectAncestor(change)) {
@@ -196,7 +195,7 @@
       return classes.join(' ');
     },
 
-    _computeChangeStatus: function(change) {
+    _computeChangeStatus(change) {
       switch (change.status) {
         case this.ChangeStatus.MERGED:
           return 'Merged';
@@ -215,16 +214,16 @@
       return '';
     },
 
-    _resultsChanged: function(related, submittedTogether, conflicts,
+    _resultsChanged(related, submittedTogether, conflicts,
         cherryPicks, sameTopic) {
-      var results = [
+      const results = [
         related,
         submittedTogether,
         conflicts,
         cherryPicks,
         sameTopic,
       ];
-      for (var i = 0; i < results.length; i++) {
+      for (let i = 0; i < results.length; i++) {
         if (results[i].length > 0) {
           this.hidden = false;
           this.fire('update', null, {bubbles: false});
@@ -234,23 +233,23 @@
       this.hidden = true;
     },
 
-    _isIndirectAncestor: function(change) {
-      return this._connectedRevisions.indexOf(change.commit.commit) == -1;
+    _isIndirectAncestor(change) {
+      return !this._connectedRevisions.includes(change.commit.commit);
     },
 
-    _computeConnectedRevisions: function(change, patchNum, relatedChanges) {
-      var connected = [];
-      var changeRevision;
-      for (var rev in change.revisions) {
+    _computeConnectedRevisions(change, patchNum, relatedChanges) {
+      const connected = [];
+      let changeRevision;
+      for (const rev in change.revisions) {
         if (change.revisions[rev]._number == patchNum) {
           changeRevision = rev;
         }
       }
-      var commits = relatedChanges.map(function(c) { return c.commit; });
-      var pos = commits.length - 1;
+      const commits = relatedChanges.map(c => { return c.commit; });
+      let pos = commits.length - 1;
 
       while (pos >= 0) {
-        var commit = commits[pos].commit;
+        const commit = commits[pos].commit;
         connected.push(commit);
         if (commit == changeRevision) {
           break;
@@ -258,8 +257,8 @@
         pos--;
       }
       while (pos >= 0) {
-        for (var i = 0; i < commits[pos].parents.length; i++) {
-          if (connected.indexOf(commits[pos].parents[i].commit) != -1) {
+        for (let i = 0; i < commits[pos].parents.length; i++) {
+          if (connected.includes(commits[pos].parents[i].commit)) {
             connected.push(commits[pos].commit);
             break;
           }
diff --git a/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list_test.html b/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list_test.html
index 171f758..4a25405 100644
--- a/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list_test.html
+++ b/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list_test.html
@@ -33,21 +33,21 @@
 </test-fixture>
 
 <script>
-  suite('gr-related-changes-list tests', function() {
-    var element;
-    var sandbox;
+  suite('gr-related-changes-list tests', () => {
+    let element;
+    let sandbox;
 
-    setup(function() {
+    setup(() => {
       element = fixture('basic');
       sandbox = sinon.sandbox.create();
     });
 
-    teardown(function() {
+    teardown(() => {
       sandbox.restore();
     });
 
-    test('connected revisions', function() {
-      var change = {
+    test('connected revisions', () => {
+      const change = {
         revisions: {
           'e3c6d60783bfdec9ebae7dcfec4662360433449e': {
             _number: 1,
@@ -72,8 +72,8 @@
           },
         },
       };
-      var patchNum = 7;
-      var relatedChanges = [
+      let patchNum = 7;
+      let relatedChanges = [
         {
           commit: {
             commit: '2cebeedfb1e80f4b872d0a13ade529e70652c0c8',
@@ -136,7 +136,7 @@
         },
       ];
 
-      var connectedChanges =
+      let connectedChanges =
           element._computeConnectedRevisions(change, patchNum, relatedChanges);
       assert.deepEqual(connectedChanges, [
         '613bc4f81741a559c6667ac08d71dcc3348f73ce',
@@ -222,9 +222,9 @@
       ]);
     });
 
-    test('_computeChangeContainerClass', function() {
-      var change1 = {change_id: 123};
-      var change2 = {change_id: 456};
+    test('_computeChangeContainerClass', () => {
+      const change1 = {change_id: 123};
+      const change2 = {change_id: 456};
 
       assert.notEqual(element._computeChangeContainerClass(
           change1, change1).indexOf('thisChange'), -1);
@@ -232,26 +232,25 @@
           change1, change2).indexOf('thisChange'), -1);
     });
 
-    suite('get conflicts tests', function() {
-      var element;
-      var conflictsStub;
+    suite('get conflicts tests', () => {
+      let element;
+      let conflictsStub;
 
-      setup(function() {
+      setup(() => {
         element = fixture('basic');
 
-        sandbox.stub(element, '_getRelatedChanges',
-            function() {
-              return Promise.resolve({changes: []});
-            });
+        sandbox.stub(element, '_getRelatedChanges', () => {
+          return Promise.resolve({changes: []});
+        });
         sandbox.stub(element, '_getSubmittedTogether',
-            function() { return Promise.resolve(); });
+            () => { return Promise.resolve(); });
         sandbox.stub(element, '_getCherryPicks',
-            function() { return Promise.resolve(); });
+            () => { return Promise.resolve(); });
         conflictsStub = sandbox.stub(element, '_getConflicts',
-            function() { return Promise.resolve(['test data']); });
+            () => { return Promise.resolve(['test data']); });
       });
 
-      test('request conflicts if open and mergeable', function() {
+      test('request conflicts if open and mergeable', () => {
         element.patchNum = 7;
         element.change = {
           change_id: 123,
@@ -262,7 +261,7 @@
         assert.isTrue(conflictsStub.called);
       });
 
-      test('does not request conflicts if closed and mergeable', function() {
+      test('does not request conflicts if closed and mergeable', () => {
         element.patchNum = 7;
         element.change = {
           change_id: 123,
@@ -273,7 +272,7 @@
         assert.isFalse(conflictsStub.called);
       });
 
-      test('does not request conflicts if open and not mergeable', function() {
+      test('does not request conflicts if open and not mergeable', () => {
         element.patchNum = 7;
         element.change = {
           change_id: 123,
@@ -284,7 +283,7 @@
         assert.isFalse(conflictsStub.called);
       });
 
-      test('doesnt request conflicts if closed and not mergeable', function() {
+      test('doesnt request conflicts if closed and not mergeable', () => {
         element.patchNum = 7;
         element.change = {
           change_id: 123,
@@ -296,9 +295,9 @@
       });
     });
 
-    test('_calculateHasParent', function() {
-      var changeId = 123;
-      var relatedChanges = [];
+    test('_calculateHasParent', () => {
+      const changeId = 123;
+      const relatedChanges = [];
 
       assert.equal(element._calculateHasParent(changeId, relatedChanges),
           false);
@@ -310,10 +309,9 @@
       relatedChanges.push({change_id: 234});
       assert.equal(element._calculateHasParent(changeId, relatedChanges),
           true);
-
     });
 
-    test('clear hides', function() {
+    test('clear hides', () => {
       element.loading = false;
       element.hidden = false;
       element.clear();
@@ -321,8 +319,8 @@
       assert.isTrue(element.hidden);
     });
 
-    test('update fires', function() {
-      var updateHandler = sandbox.stub();
+    test('update fires', () => {
+      const updateHandler = sandbox.stub();
       element.addEventListener('update', updateHandler);
 
       element._resultsChanged([], [], [], [], []);
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-comment-thread-group/gr-diff-comment-thread-group.js b/polygerrit-ui/app/elements/diff/gr-diff-comment-thread-group/gr-diff-comment-thread-group.js
index df75d52..7899fc7 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-comment-thread-group/gr-diff-comment-thread-group.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-comment-thread-group/gr-diff-comment-thread-group.js
@@ -21,7 +21,7 @@
       changeNum: String,
       comments: {
         type: Array,
-        value: function() { return []; },
+        value() { return []; },
       },
       patchForNewThreads: String,
       projectConfig: Object,
@@ -32,7 +32,7 @@
       },
       _threads: {
         type: Array,
-        value: function() { return []; },
+        value() { return []; },
       },
     },
 
@@ -40,16 +40,16 @@
       '_commentsChanged(comments.*)',
     ],
 
-    addNewThread: function(locationRange) {
+    addNewThread(locationRange) {
       this.push('_threads', {
         comments: [],
-        locationRange: locationRange,
+        locationRange,
         patchNum: this.patchForNewThreads,
       });
     },
 
-    removeThread: function(locationRange) {
-      for (var i = 0; i < this._threads.length; i++) {
+    removeThread(locationRange) {
+      for (let i = 0; i < this._threads.length; i++) {
         if (this._threads[i].locationRange === locationRange) {
           this.splice('_threads', i, 1);
           return;
@@ -57,10 +57,10 @@
       }
     },
 
-    getThreadForRange: function(rangeToCheck) {
-      var threads = [].filter.call(
+    getThreadForRange(rangeToCheck) {
+      const threads = [].filter.call(
           Polymer.dom(this.root).querySelectorAll('gr-diff-comment-thread'),
-          function(thread) {
+          thread => {
             return thread.locationRange === rangeToCheck;
           });
       if (threads.length === 1) {
@@ -68,13 +68,13 @@
       }
     },
 
-    _commentsChanged: function() {
+    _commentsChanged() {
       this._threads = this._getThreadGroups(this.comments);
     },
 
-    _sortByDate: function(threadGroups) {
+    _sortByDate(threadGroups) {
       if (!threadGroups.length) { return; }
-      return threadGroups.sort(function(a, b) {
+      return threadGroups.sort((a, b) => {
         // If a comment is a draft, it doesn't have a start_datetime yet.
         // Assume it is newer than the comment it is being compared to.
         if (!a.start_datetime) {
@@ -88,7 +88,7 @@
       });
     },
 
-    _calculateLocationRange: function(range, comment) {
+    _calculateLocationRange(range, comment) {
       return 'range-' + range.start_line + '-' +
           range.start_character + '-' +
           range.end_line + '-' +
@@ -102,15 +102,15 @@
      * This is needed for switching between side-by-side and unified views when
      * there are unsaved drafts.
      */
-    _getPatchNum: function(comment) {
+    _getPatchNum(comment) {
       return comment.patchNum || this.patchForNewThreads;
     },
 
-    _getThreadGroups: function(comments) {
-      var threadGroups = {};
+    _getThreadGroups(comments) {
+      const threadGroups = {};
 
-      comments.forEach(function(comment) {
-        var locationRange;
+      for (const comment of comments) {
+        let locationRange;
         if (!comment.range) {
           locationRange = 'line-' + comment.__commentSide;
         } else {
@@ -123,18 +123,18 @@
           threadGroups[locationRange] = {
             start_datetime: comment.updated,
             comments: [comment],
-            locationRange: locationRange,
+            locationRange,
             commentSide: comment.__commentSide,
             patchNum: this._getPatchNum(comment),
           };
         }
-      }.bind(this));
+      }
 
-      var threadGroupArr = [];
-      var threadGroupKeys = Object.keys(threadGroups);
-      threadGroupKeys.forEach(function(threadGroupKey) {
+      const threadGroupArr = [];
+      const threadGroupKeys = Object.keys(threadGroups);
+      for (const threadGroupKey of threadGroupKeys) {
         threadGroupArr.push(threadGroups[threadGroupKey]);
-      });
+      }
 
       return this._sortByDate(threadGroupArr);
     },
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-comment-thread-group/gr-diff-comment-thread-group_test.html b/polygerrit-ui/app/elements/diff/gr-diff-comment-thread-group/gr-diff-comment-thread-group_test.html
index 53a8e81..056b74f 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-comment-thread-group/gr-diff-comment-thread-group_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-comment-thread-group/gr-diff-comment-thread-group_test.html
@@ -34,25 +34,25 @@
 </test-fixture>
 
 <script>
-  suite('gr-diff-comment-thread-group tests', function() {
-    var element;
-    var sandbox;
+  suite('gr-diff-comment-thread-group tests', () => {
+    let element;
+    let sandbox;
 
-    setup(function() {
+    setup(() => {
       sandbox = sinon.sandbox.create();
       stub('gr-rest-api-interface', {
-        getLoggedIn: function() { return Promise.resolve(false); },
+        getLoggedIn() { return Promise.resolve(false); },
       });
       element = fixture('basic');
     });
 
-    teardown(function() {
+    teardown(() => {
       sandbox.restore();
     });
 
-    test('_getThreadGroups', function() {
+    test('_getThreadGroups', () => {
       element.patchForNewThreads = 3;
-      var comments = [
+      const comments = [
         {
           id: 'sallys_confession',
           message: 'i like you, jack',
@@ -66,23 +66,23 @@
         },
       ];
 
-      var expectedThreadGroups = [
+      let expectedThreadGroups = [
         {
           start_datetime: '2015-12-23 15:00:20.396000000',
           commentSide: 'left',
           comments: [{
-              id: 'sallys_confession',
-              message: 'i like you, jack',
-              updated: '2015-12-23 15:00:20.396000000',
-              __commentSide: 'left',
-            }, {
-              id: 'jacks_reply',
-              message: 'i like you, too',
-              updated: '2015-12-24 15:00:20.396000000',
-              __commentSide: 'left',
-            }],
+            id: 'sallys_confession',
+            message: 'i like you, jack',
+            updated: '2015-12-23 15:00:20.396000000',
+            __commentSide: 'left',
+          }, {
+            id: 'jacks_reply',
+            message: 'i like you, too',
+            updated: '2015-12-24 15:00:20.396000000',
+            __commentSide: 'left',
+          }],
           locationRange: 'line-left',
-          patchNum: 3
+          patchNum: 3,
         },
       ];
 
@@ -91,33 +91,33 @@
 
       // Patch num should get inherited from comment rather
       comments.push({
-          id: 'betsys_confession',
-          message: 'i like you, jack',
-          updated: '2015-12-24 15:00:10.396000000',
-          range: {
-            start_line: 1,
-            start_character: 1,
-            end_line: 1,
-            end_character: 2,
-          },
-          __commentSide: 'left',
-        });
+        id: 'betsys_confession',
+        message: 'i like you, jack',
+        updated: '2015-12-24 15:00:10.396000000',
+        range: {
+          start_line: 1,
+          start_character: 1,
+          end_line: 1,
+          end_character: 2,
+        },
+        __commentSide: 'left',
+      });
 
       expectedThreadGroups = [
         {
           start_datetime: '2015-12-23 15:00:20.396000000',
           commentSide: 'left',
           comments: [{
-              id: 'sallys_confession',
-              message: 'i like you, jack',
-              updated: '2015-12-23 15:00:20.396000000',
-              __commentSide: 'left',
-            }, {
-              id: 'jacks_reply',
-              message: 'i like you, too',
-              updated: '2015-12-24 15:00:20.396000000',
-              __commentSide: 'left',
-            }],
+            id: 'sallys_confession',
+            message: 'i like you, jack',
+            updated: '2015-12-23 15:00:20.396000000',
+            __commentSide: 'left',
+          }, {
+            id: 'jacks_reply',
+            message: 'i like you, too',
+            updated: '2015-12-24 15:00:20.396000000',
+            __commentSide: 'left',
+          }],
           patchNum: 3,
           locationRange: 'line-left',
         },
@@ -145,8 +145,8 @@
           expectedThreadGroups);
     });
 
-    test('_sortByDate', function() {
-      var threadGroups = [
+    test('_sortByDate', () => {
+      let threadGroups = [
         {
           start_datetime: '2015-12-23 15:00:20.396000000',
           comments: [],
@@ -159,12 +159,12 @@
         },
       ];
 
-      var expectedResult = [
+      let expectedResult = [
         {
           start_datetime: '2015-12-22 15:00:10.396000000',
           comments: [],
           locationRange: 'range-1-1-1-2',
-        },{
+        }, {
           start_datetime: '2015-12-23 15:00:20.396000000',
           comments: [],
           locationRange: 'line',
@@ -175,7 +175,7 @@
 
       // When a comment doesn't have a date, the one without the date should be
       // last.
-      var threadGroups = [
+      threadGroups = [
         {
           start_datetime: '2015-12-23 15:00:20.396000000',
           comments: [],
@@ -187,7 +187,7 @@
         },
       ];
 
-      var expectedResult = [
+      expectedResult = [
         {
           start_datetime: '2015-12-23 15:00:20.396000000',
           comments: [],
@@ -198,22 +198,25 @@
           locationRange: 'range-1-1-1-2',
         },
       ];
+
+      assert.deepEqual(element._sortByDate(threadGroups), expectedResult);
     });
 
-    test('_calculateLocationRange', function() {
-      var comment = {__commentSide: 'left'};
-      var range = {
+    test('_calculateLocationRange', () => {
+      const comment = {__commentSide: 'left'};
+      const range = {
         start_line: 1,
         start_character: 2,
         end_line: 3,
         end_character: 4,
       };
       assert.equal(
-        element._calculateLocationRange(range, comment), 'range-1-2-3-4-left');
+          element._calculateLocationRange(range, comment),
+          'range-1-2-3-4-left');
     });
 
-    test('thread groups are updated when comments change', function() {
-      var commentsChangedStub = sandbox.stub(element, '_commentsChanged');
+    test('thread groups are updated when comments change', () => {
+      const commentsChangedStub = sandbox.stub(element, '_commentsChanged');
       element.comments = [];
       element.comments.push({
         id: 'sallys_confession',
@@ -223,16 +226,16 @@
       assert(commentsChangedStub.called);
     });
 
-    test('addNewThread', function() {
-      var locationRange = 'range-1-2-3-4';
+    test('addNewThread', () => {
+      const locationRange = 'range-1-2-3-4';
       element._threads = [{locationRange: 'line'}];
       element.addNewThread(locationRange);
       assert(element._threads.length, 2);
     });
 
-    test('_getPatchNum', function() {
+    test('_getPatchNum', () => {
       element.patchForNewThreads = 3;
-      var comment = {
+      const comment = {
         id: 'sallys_confession',
         message: 'i like you, jack',
         updated: '2015-12-23 15:00:20.396000000',
@@ -242,11 +245,11 @@
       assert.equal(element._getPatchNum(comment), 4);
     });
 
-    test('removeThread', function() {
-      var locationRange = 'range-1-2-3-4';
+    test('removeThread', () => {
+      const locationRange = 'range-1-2-3-4';
       element._threads = [
         {locationRange: 'range-1-2-3-4', comments: []},
-        {locationRange: 'line', comments: []}
+        {locationRange: 'line', comments: []},
       ];
       flushAsynchronousOperations();
       element.removeThread(locationRange);
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-comment-thread/gr-diff-comment-thread.js b/polygerrit-ui/app/elements/diff/gr-diff-comment-thread/gr-diff-comment-thread.js
index be88e476..20b89c2 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-comment-thread/gr-diff-comment-thread.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-comment-thread/gr-diff-comment-thread.js
@@ -14,8 +14,8 @@
 (function() {
   'use strict';
 
-  var UNRESOLVED_EXPAND_COUNT = 5;
-  var NEWLINE_PATTERN = /\n/g;
+  const UNRESOLVED_EXPAND_COUNT = 5;
+  const NEWLINE_PATTERN = /\n/g;
 
   Polymer({
     is: 'gr-diff-comment-thread',
@@ -30,12 +30,12 @@
       changeNum: String,
       comments: {
         type: Array,
-        value: function() { return []; },
+        value() { return []; },
       },
       locationRange: String,
       keyEventTarget: {
         type: Object,
-        value: function() { return document.body; },
+        value() { return document.body; },
       },
       commentSide: String,
       patchNum: String,
@@ -71,17 +71,17 @@
       'e shift+e': '_handleEKey',
     },
 
-    attached: function() {
-      this._getLoggedIn().then(function(loggedIn) {
+    attached() {
+      this._getLoggedIn().then(loggedIn => {
         this._showActions = loggedIn;
-      }.bind(this));
+      });
       this._setInitialExpandedState();
     },
 
-    addOrEditDraft: function(opt_lineNum, opt_range) {
-      var lastComment = this.comments[this.comments.length - 1] || {};
+    addOrEditDraft(opt_lineNum, opt_range) {
+      const lastComment = this.comments[this.comments.length - 1] || {};
       if (lastComment.__draft) {
-        var commentEl = this._commentElWithDraftID(
+        const commentEl = this._commentElWithDraftID(
             lastComment.id || lastComment.__draftID);
         commentEl.editing = true;
 
@@ -89,25 +89,25 @@
         // actions are available.
         commentEl.collapsed = false;
       } else {
-        var range = opt_range ? opt_range :
+        const range = opt_range ? opt_range :
             lastComment ? lastComment.range : undefined;
-        var unresolved = lastComment ? lastComment.unresolved : undefined;
+        const unresolved = lastComment ? lastComment.unresolved : undefined;
         this.addDraft(opt_lineNum, range, unresolved);
       }
     },
 
-    addDraft: function(opt_lineNum, opt_range, opt_unresolved) {
-      var draft = this._newDraft(opt_lineNum, opt_range);
+    addDraft(opt_lineNum, opt_range, opt_unresolved) {
+      const draft = this._newDraft(opt_lineNum, opt_range);
       draft.__editing = true;
       draft.unresolved = opt_unresolved === false ? opt_unresolved : true;
       this.push('comments', draft);
     },
 
-    _getLoggedIn: function() {
+    _getLoggedIn() {
       return this.$.restAPI.getLoggedIn();
     },
 
-    _commentsChanged: function(changeRecord) {
+    _commentsChanged(changeRecord) {
       this._orderedComments = this._sortedComments(this.comments);
       if (this._orderedComments.length) {
         this._lastComment = this._getLastComment();
@@ -115,15 +115,15 @@
       }
     },
 
-    _hideActions: function(_showActions, _lastComment) {
+    _hideActions(_showActions, _lastComment) {
       return !_showActions || !_lastComment || !!_lastComment.__draft;
     },
 
-    _getLastComment: function() {
+    _getLastComment() {
       return this._orderedComments[this._orderedComments.length - 1] || {};
     },
 
-    _handleEKey: function(e) {
+    _handleEKey(e) {
       if (this.shouldSuppressKeyboardShortcut(e)) { return; }
 
       // Don’t preventDefault in this case because it will render the event
@@ -136,12 +136,12 @@
       }
     },
 
-    _expandCollapseComments: function(actionIsCollapse) {
-      var comments =
+    _expandCollapseComments(actionIsCollapse) {
+      const comments =
           Polymer.dom(this.root).querySelectorAll('gr-diff-comment');
-      comments.forEach(function(comment) {
+      for (const comment of comments) {
         comment.collapsed = actionIsCollapse;
-      });
+      }
     },
 
     /**
@@ -149,33 +149,32 @@
      * {UNRESOLVED_EXPAND_COUNT} comments expanded by default if the
      * thread is unresolved.
      */
-    _setInitialExpandedState: function() {
-      var comment;
+    _setInitialExpandedState() {
+      let comment;
       if (this._orderedComments) {
-        for (var i = 0; i < this._orderedComments.length; i++) {
+        for (let i = 0; i < this._orderedComments.length; i++) {
           comment = this._orderedComments[i];
           comment.collapsed =
               this._orderedComments.length - i - 1 >= UNRESOLVED_EXPAND_COUNT ||
               !this._unresolved;
         }
       }
-
     },
 
-    _sortedComments: function(comments) {
-      return comments.slice().sort(function(c1, c2) {
-        var c1Date = c1.__date || util.parseDate(c1.updated);
-        var c2Date = c2.__date || util.parseDate(c2.updated);
-        var dateCompare = c1Date - c2Date;
+    _sortedComments(comments) {
+      return comments.slice().sort((c1, c2) => {
+        const c1Date = c1.__date || util.parseDate(c1.updated);
+        const c2Date = c2.__date || util.parseDate(c2.updated);
+        const dateCompare = c1Date - c2Date;
         if (!c1.id || !c1.id.localeCompare) { return 0; }
         // If same date, fall back to sorting by id.
         return dateCompare ? dateCompare : c1.id.localeCompare(c2.id);
       });
     },
 
-    _createReplyComment: function(parent, content, opt_isEditing,
+    _createReplyComment(parent, content, opt_isEditing,
         opt_unresolved) {
-      var reply = this._newReply(
+      const reply = this._newReply(
           this._orderedComments[this._orderedComments.length - 1].id,
           parent.line,
           content,
@@ -184,7 +183,7 @@
 
       // If there is currently a comment in an editing state, add an attribute
       // so that the gr-diff-comment knows not to populate the draft text.
-      for (var i = 0; i < this.comments.length; i++) {
+      for (let i = 0; i < this.comments.length; i++) {
         if (this.comments[i].__editing) {
           reply.__otherEditing = true;
           break;
@@ -199,62 +198,62 @@
 
       if (!opt_isEditing) {
         // Allow the reply to render in the dom-repeat.
-        this.async(function() {
-          var commentEl = this._commentElWithDraftID(reply.__draftID);
+        this.async(() => {
+          const commentEl = this._commentElWithDraftID(reply.__draftID);
           commentEl.save();
         }, 1);
       }
     },
 
-    _processCommentReply: function(opt_quote) {
-      var comment = this._lastComment;
-      var quoteStr;
+    _processCommentReply(opt_quote) {
+      const comment = this._lastComment;
+      let quoteStr;
       if (opt_quote) {
-        var msg = comment.message;
+        const msg = comment.message;
         quoteStr = '> ' + msg.replace(NEWLINE_PATTERN, '\n> ') + '\n\n';
       }
       this._createReplyComment(comment, quoteStr, true, comment.unresolved);
     },
 
-    _handleCommentReply: function(e) {
+    _handleCommentReply(e) {
       this._processCommentReply();
     },
 
-    _handleCommentQuote: function(e) {
+    _handleCommentQuote(e) {
       this._processCommentReply(true);
     },
 
-    _handleCommentAck: function(e) {
-      var comment = this._lastComment;
+    _handleCommentAck(e) {
+      const comment = this._lastComment;
       this._createReplyComment(comment, 'Ack', false, false);
     },
 
-    _handleCommentDone: function(e) {
-      var comment = this._lastComment;
+    _handleCommentDone(e) {
+      const comment = this._lastComment;
       this._createReplyComment(comment, 'Done', false, false);
     },
 
-    _handleCommentFix: function(e) {
-      var comment = e.detail.comment;
-      var msg = comment.message;
-      var quoteStr = '> ' + msg.replace(NEWLINE_PATTERN, '\n> ') + '\n\n';
-      var response = quoteStr + 'Please Fix';
+    _handleCommentFix(e) {
+      const comment = e.detail.comment;
+      const msg = comment.message;
+      const quoteStr = '> ' + msg.replace(NEWLINE_PATTERN, '\n> ') + '\n\n';
+      const response = quoteStr + 'Please Fix';
       this._createReplyComment(comment, response, false, true);
     },
 
-    _commentElWithDraftID: function(id) {
-      var els = Polymer.dom(this.root).querySelectorAll('gr-diff-comment');
-      for (var i = 0; i < els.length; i++) {
-        if (els[i].comment.id === id || els[i].comment.__draftID === id) {
-          return els[i];
+    _commentElWithDraftID(id) {
+      const els = Polymer.dom(this.root).querySelectorAll('gr-diff-comment');
+      for (const el of els) {
+        if (el.comment.id === id || el.comment.__draftID === id) {
+          return el;
         }
       }
       return null;
     },
 
-    _newReply: function(inReplyTo, opt_lineNum, opt_message, opt_unresolved,
-          opt_range) {
-      var d = this._newDraft(opt_lineNum);
+    _newReply(inReplyTo, opt_lineNum, opt_message, opt_unresolved,
+        opt_range) {
+      const d = this._newDraft(opt_lineNum);
       d.in_reply_to = inReplyTo;
       d.range = opt_range;
       if (opt_message != null) {
@@ -266,8 +265,8 @@
       return d;
     },
 
-    _newDraft: function(opt_lineNum, opt_range) {
-      var d = {
+    _newDraft(opt_lineNum, opt_range) {
+      const d = {
         __draft: true,
         __draftID: Math.random().toString(36),
         __date: new Date(),
@@ -290,15 +289,15 @@
       return d;
     },
 
-    _getSide: function(isOnParent) {
+    _getSide(isOnParent) {
       if (isOnParent) { return 'PARENT'; }
       return 'REVISION';
     },
 
-    _handleCommentDiscard: function(e) {
-      var diffCommentEl = Polymer.dom(e).rootTarget;
-      var comment = diffCommentEl.comment;
-      var idx = this._indexOf(comment, this.comments);
+    _handleCommentDiscard(e) {
+      const diffCommentEl = Polymer.dom(e).rootTarget;
+      const comment = diffCommentEl.comment;
+      const idx = this._indexOf(comment, this.comments);
       if (idx == -1) {
         throw Error('Cannot find comment ' +
             JSON.stringify(diffCommentEl.comment));
@@ -310,23 +309,23 @@
 
       // Check to see if there are any other open comments getting edited and
       // set the local storage value to its message value.
-      for (var i = 0; i < this.comments.length; i++) {
-        if (this.comments[i].__editing) {
-          var commentLocation = {
+      for (const changeComment of this.comments) {
+        if (changeComment.__editing) {
+          const commentLocation = {
             changeNum: this.changeNum,
             patchNum: this.patchNum,
-            path: this.comments[i].path,
-            line: this.comments[i].line,
+            path: changeComment.path,
+            line: changeComment.line,
           };
           return this.$.storage.setDraftComment(commentLocation,
-              this.comments[i].message);
+              changeComment.message);
         }
       }
     },
 
-    _handleCommentUpdate: function(e) {
-      var comment = e.detail.comment;
-      var index = this._indexOf(comment, this.comments);
+    _handleCommentUpdate(e) {
+      const comment = e.detail.comment;
+      const index = this._indexOf(comment, this.comments);
       if (index === -1) {
         // This should never happen: comment belongs to another thread.
         console.warn('Comment update for another comment thread.');
@@ -335,9 +334,9 @@
       this.set(['comments', index], comment);
     },
 
-    _indexOf: function(comment, arr) {
-      for (var i = 0; i < arr.length; i++) {
-        var c = arr[i];
+    _indexOf(comment, arr) {
+      for (let i = 0; i < arr.length; i++) {
+        const c = arr[i];
         if ((c.__draftID != null && c.__draftID == comment.__draftID) ||
             (c.id != null && c.id == comment.id)) {
           return i;
@@ -346,7 +345,7 @@
       return -1;
     },
 
-    _computeHostClass: function(unresolved) {
+    _computeHostClass(unresolved) {
       return unresolved ? 'unresolved' : '';
     },
   });
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-comment-thread/gr-diff-comment-thread_test.html b/polygerrit-ui/app/elements/diff/gr-diff-comment-thread/gr-diff-comment-thread_test.html
index 546308e..85beca6 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-comment-thread/gr-diff-comment-thread_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-comment-thread/gr-diff-comment-thread_test.html
@@ -40,25 +40,25 @@
 </test-fixture>
 
 <script>
-  suite('gr-diff-comment-thread tests', function() {
-    var element;
-    var sandbox;
+  suite('gr-diff-comment-thread tests', () => {
+    let element;
+    let sandbox;
 
-    setup(function() {
+    setup(() => {
       sandbox = sinon.sandbox.create();
       stub('gr-rest-api-interface', {
-        getLoggedIn: function() { return Promise.resolve(false); },
+        getLoggedIn() { return Promise.resolve(false); },
       });
       sandbox = sinon.sandbox.create();
       element = fixture('basic');
     });
 
-    teardown(function() {
+    teardown(() => {
       sandbox.restore();
     });
 
-    test('comments are sorted correctly', function() {
-      var comments = [
+    test('comments are sorted correctly', () => {
+      const comments = [
         {
           id: 'jacks_reply',
           message: 'i like you, too',
@@ -86,9 +86,9 @@
           id: 'sallys_mission',
           message: 'i have to find santa',
           updated: '2015-12-24 15:00:20.396000000',
-        }
+        },
       ];
-      var results = element._sortedComments(comments);
+      const results = element._sortedComments(comments);
       assert.deepEqual(results, [
         {
           id: 'sally_to_dr_finklestein',
@@ -117,11 +117,11 @@
           message: 'i like you, too',
           in_reply_to: 'sallys_confession',
           updated: '2015-12-25 15:00:20.396000000',
-        }
+        },
       ]);
     });
 
-    test('addOrEditDraft w/ edit draft', function() {
+    test('addOrEditDraft w/ edit draft', () => {
       element.comments = [{
         id: 'jacks_reply',
         message: 'i like you, too',
@@ -129,9 +129,9 @@
         updated: '2015-12-25 15:00:20.396000000',
         __draft: true,
       }];
-      var commentElStub = sandbox.stub(element, '_commentElWithDraftID',
-          function() { return {}; });
-      var addDraftStub = sandbox.stub(element, 'addDraft');
+      const commentElStub = sandbox.stub(element, '_commentElWithDraftID',
+          () => { return {}; });
+      const addDraftStub = sandbox.stub(element, 'addDraft');
 
       element.addOrEditDraft(123);
 
@@ -139,11 +139,11 @@
       assert.isFalse(addDraftStub.called);
     });
 
-    test('addOrEditDraft w/o edit draft', function() {
+    test('addOrEditDraft w/o edit draft', () => {
       element.comments = [];
-      var commentElStub = sandbox.stub(element, '_commentElWithDraftID',
-          function() { return {}; });
-      var addDraftStub = sandbox.stub(element, 'addDraft');
+      const commentElStub = sandbox.stub(element, '_commentElWithDraftID',
+          () => { return {}; });
+      const addDraftStub = sandbox.stub(element, 'addDraft');
 
       element.addOrEditDraft(123);
 
@@ -151,40 +151,41 @@
       assert.isTrue(addDraftStub.called);
     });
 
-    test('_hideActions', function() {
-      var showActions = true;
-      var lastComment = {};
+    test('_hideActions', () => {
+      let showActions = true;
+      const lastComment = {};
       assert.equal(element._hideActions(showActions, lastComment), false);
       showActions = false;
       assert.equal(element._hideActions(showActions, lastComment), true);
-      var showActions = true;
+      showActions = true;
       lastComment.__draft = true;
       assert.equal(element._hideActions(showActions, lastComment), true);
     });
   });
 
-  suite('comment action tests', function() {
-    var element;
+  suite('comment action tests', () => {
+    let element;
 
-    setup(function() {
+    setup(() => {
       stub('gr-rest-api-interface', {
-        getLoggedIn: function() { return Promise.resolve(false); },
-        saveDiffDraft: function() {
+        getLoggedIn() { return Promise.resolve(false); },
+        saveDiffDraft() {
           return Promise.resolve({
             ok: true,
-            text: function() { return Promise.resolve(')]}\'\n' +
-                JSON.stringify({
-                  id: '7afa4931_de3d65bd',
-                  path: '/path/to/file.txt',
-                  line: 5,
-                  in_reply_to: 'baf0414d_60047215',
-                  updated: '2015-12-21 02:01:10.850000000',
-                  message: 'Done',
-                }));
+            text() {
+              return Promise.resolve(')]}\'\n' +
+                  JSON.stringify({
+                    id: '7afa4931_de3d65bd',
+                    path: '/path/to/file.txt',
+                    line: 5,
+                    in_reply_to: 'baf0414d_60047215',
+                    updated: '2015-12-21 02:01:10.850000000',
+                    message: 'Done',
+                  }));
             },
           });
         },
-        deleteDiffDraft: function() { return Promise.resolve({ok: true}); },
+        deleteDiffDraft() { return Promise.resolve({ok: true}); },
       });
       element = fixture('withComment');
       element.comments = [{
@@ -200,15 +201,15 @@
       flushAsynchronousOperations();
     });
 
-    test('reply', function(done) {
-      var commentEl = element.$$('gr-diff-comment');
+    test('reply', done => {
+      const commentEl = element.$$('gr-diff-comment');
       assert.ok(commentEl);
 
-      var replyBtn = element.$.replyBtn;
+      const replyBtn = element.$.replyBtn;
       MockInteractions.tap(replyBtn);
       flushAsynchronousOperations();
 
-      var drafts = element._orderedComments.filter(function(c) {
+      const drafts = element._orderedComments.filter(c => {
         return c.__draft == true;
       });
       assert.equal(drafts.length, 1);
@@ -217,16 +218,16 @@
       done();
     });
 
-    test('quote reply', function(done) {
-      var commentEl = element.$$('gr-diff-comment');
+    test('quote reply', done => {
+      const commentEl = element.$$('gr-diff-comment');
       assert.ok(commentEl);
 
-      var quoteBtn = element.$.quoteBtn;
+      const quoteBtn = element.$.quoteBtn;
       MockInteractions.tap(quoteBtn);
       flushAsynchronousOperations();
 
-      var drafts = element._orderedComments.filter(function(c) {
-          return c.__draft == true;
+      const drafts = element._orderedComments.filter(c => {
+        return c.__draft == true;
       });
       assert.equal(drafts.length, 1);
       assert.equal(drafts[0].message, '> is this a crossover episode!?\n\n');
@@ -234,7 +235,7 @@
       done();
     });
 
-    test('quote reply multiline', function(done) {
+    test('quote reply multiline', done => {
       element.comments = [{
         author: {
           name: 'Mr. Peanutbutter',
@@ -247,14 +248,14 @@
       }];
       flushAsynchronousOperations();
 
-      var commentEl = element.$$('gr-diff-comment');
+      const commentEl = element.$$('gr-diff-comment');
       assert.ok(commentEl);
 
-      var quoteBtn = element.$.quoteBtn;
+      const quoteBtn = element.$.quoteBtn;
       MockInteractions.tap(quoteBtn);
       flushAsynchronousOperations();
 
-      var drafts = element._orderedComments.filter(function(c) {
+      const drafts = element._orderedComments.filter(c => {
         return c.__draft == true;
       });
       assert.equal(drafts.length, 1);
@@ -264,17 +265,17 @@
       done();
     });
 
-    test('ack', function(done) {
+    test('ack', done => {
       element.changeNum = '42';
       element.patchNum = '1';
 
-      var commentEl = element.$$('gr-diff-comment');
+      const commentEl = element.$$('gr-diff-comment');
       assert.ok(commentEl);
 
-      var ackBtn = element.$.ackBtn;
+      const ackBtn = element.$.ackBtn;
       MockInteractions.tap(ackBtn);
-      flush(function() {
-        var drafts = element.comments.filter(function(c) {
+      flush(() => {
+        const drafts = element.comments.filter(c => {
           return c.__draft == true;
         });
         assert.equal(drafts.length, 1);
@@ -285,16 +286,16 @@
       });
     });
 
-    test('done', function(done) {
+    test('done', done => {
       element.changeNum = '42';
       element.patchNum = '1';
-      var commentEl = element.$$('gr-diff-comment');
+      const commentEl = element.$$('gr-diff-comment');
       assert.ok(commentEl);
 
-      var doneBtn = element.$.doneBtn;
+      const doneBtn = element.$.doneBtn;
       MockInteractions.tap(doneBtn);
-      flush(function() {
-        var drafts = element.comments.filter(function(c) {
+      flush(() => {
+        const drafts = element.comments.filter(c => {
           return c.__draft == true;
         });
         assert.equal(drafts.length, 1);
@@ -305,13 +306,13 @@
       });
     });
 
-    test('please fix', function(done) {
+    test('please fix', done => {
       element.changeNum = '42';
       element.patchNum = '1';
-      var commentEl = element.$$('gr-diff-comment');
+      const commentEl = element.$$('gr-diff-comment');
       assert.ok(commentEl);
-      commentEl.addEventListener('create-fix-comment', function() {
-        var drafts = element._orderedComments.filter(function(c) {
+      commentEl.addEventListener('create-fix-comment', () => {
+        const drafts = element._orderedComments.filter(c => {
           return c.__draft == true;
         });
         assert.equal(drafts.length, 1);
@@ -325,21 +326,21 @@
           {bubbles: false});
     });
 
-    test('discard', function(done) {
+    test('discard', done => {
       element.changeNum = '42';
       element.patchNum = '1';
       element.push('comments', element._newReply(
-        element.comments[0].id,
-        element.comments[0].line,
-        element.comments[0].path,
-        'it’s pronouced jiff, not giff'));
+          element.comments[0].id,
+          element.comments[0].line,
+          element.comments[0].path,
+          'it’s pronouced jiff, not giff'));
       flushAsynchronousOperations();
 
-      var draftEl =
+      const draftEl =
           Polymer.dom(element.root).querySelectorAll('gr-diff-comment')[1];
       assert.ok(draftEl);
-      draftEl.addEventListener('comment-discard', function() {
-        var drafts = element.comments.filter(function(c) {
+      draftEl.addEventListener('comment-discard', () => {
+        const drafts = element.comments.filter(c => {
           return c.__draft == true;
         });
         assert.equal(drafts.length, 0);
@@ -348,9 +349,7 @@
       draftEl.fire('comment-discard', null, {bubbles: false});
     });
 
-    test('first editing comment does not add __otherEditing attribute',
-        function() {
-      var commentEl = element.$$('gr-diff-comment');
+    test('first editing comment does not add __otherEditing attribute', () => {
       element.comments = [{
         author: {
           name: 'Mr. Peanutbutter',
@@ -363,19 +362,19 @@
         __draft: true,
       }];
 
-      var replyBtn = element.$.replyBtn;
+      const replyBtn = element.$.replyBtn;
       MockInteractions.tap(replyBtn);
       flushAsynchronousOperations();
 
-      var editing = element._orderedComments.filter(function(c) {
+      const editing = element._orderedComments.filter(c => {
         return c.__editing == true;
       });
       assert.equal(editing.length, 1);
       assert.equal(!!editing[0].__otherEditing, false);
     });
 
-    test('When not editing other comments, local storage not set after discard',
-        function(done) {
+    test('When not editing other comments, local storage not set' +
+        ' after discard', done => {
       element.changeNum = '42';
       element.patchNum = '1';
       element.comments = [{
@@ -413,13 +412,13 @@
         updated: '2015-12-08 19:48:33.843000000',
         __draft: true,
       }];
-      var storageStub = sinon.stub(element.$.storage, 'setDraftComment');
+      const storageStub = sinon.stub(element.$.storage, 'setDraftComment');
       flushAsynchronousOperations();
 
-      var draftEl =
-          Polymer.dom(element.root).querySelectorAll('gr-diff-comment')[1];
+      const draftEl =
+      Polymer.dom(element.root).querySelectorAll('gr-diff-comment')[1];
       assert.ok(draftEl);
-      draftEl.addEventListener('comment-discard', function() {
+      draftEl.addEventListener('comment-discard', () => {
         assert.isFalse(storageStub.called);
         storageStub.restore();
         done();
@@ -427,9 +426,9 @@
       draftEl.fire('comment-discard', null, {bubbles: false});
     });
 
-    test('comment-update', function() {
-      var commentEl = element.$$('gr-diff-comment');
-      var updatedComment = {
+    test('comment-update', () => {
+      const commentEl = element.$$('gr-diff-comment');
+      const updatedComment = {
         id: element.comments[0].id,
         foo: 'bar',
       };
@@ -437,88 +436,81 @@
       assert.strictEqual(element.comments[0], updatedComment);
     });
 
-    suite('jack and sally comment data test consolidation', function() {
-      var getComments = function() {
-        return Polymer.dom(element.root).querySelectorAll('gr-diff-comment');
-      };
-
-      setup(function() {
+    suite('jack and sally comment data test consolidation', () => {
+      setup(() => {
         element.comments = [
-        {
-          id: 'jacks_reply',
-          message: 'i like you, too',
-          in_reply_to: 'sallys_confession',
-          updated: '2015-12-25 15:00:20.396000000',
-          unresolved: false,
-        }, {
-          id: 'sallys_confession',
-          in_reply_to: 'nonexistent_comment',
-          message: 'i like you, jack',
-          updated: '2015-12-24 15:00:20.396000000',
-        }, {
-          id: 'sally_to_dr_finklestein',
-          in_reply_to: 'nonexistent_comment',
-          message: 'i’m running away',
-          updated: '2015-10-31 09:00:20.396000000',
-        }, {
-          id: 'sallys_defiance',
-          message: 'i will poison you so i can get away',
-          updated: '2015-10-31 15:00:20.396000000',
-        }];
+          {
+            id: 'jacks_reply',
+            message: 'i like you, too',
+            in_reply_to: 'sallys_confession',
+            updated: '2015-12-25 15:00:20.396000000',
+            unresolved: false,
+          }, {
+            id: 'sallys_confession',
+            in_reply_to: 'nonexistent_comment',
+            message: 'i like you, jack',
+            updated: '2015-12-24 15:00:20.396000000',
+          }, {
+            id: 'sally_to_dr_finklestein',
+            in_reply_to: 'nonexistent_comment',
+            message: 'i’m running away',
+            updated: '2015-10-31 09:00:20.396000000',
+          }, {
+            id: 'sallys_defiance',
+            message: 'i will poison you so i can get away',
+            updated: '2015-10-31 15:00:20.396000000',
+          }];
       });
 
-      test('orphan replies', function() {
+      test('orphan replies', () => {
         assert.equal(4, element._orderedComments.length);
       });
 
-      test('keyboard shortcuts', function() {
-        var expandCollapseStub = sinon.stub(element, '_expandCollapseComments');
+      test('keyboard shortcuts', () => {
+        const expandCollapseStub =
+            sinon.stub(element, '_expandCollapseComments');
         MockInteractions.pressAndReleaseKeyOn(element, 69, null, 'e');
         assert.isTrue(expandCollapseStub.lastCall.calledWith(false));
 
         MockInteractions.pressAndReleaseKeyOn(element, 69, 'shift', 'e');
         assert.isTrue(expandCollapseStub.lastCall.calledWith(true));
-        expandCollapseStub.restore();
       });
 
-      test('comment in_reply_to is either null or most recent comment id',
-          function() {
+      test('comment in_reply_to is either null or most recent comment', () => {
         element._createReplyComment(element.comments[3], 'dummy', true);
         flushAsynchronousOperations();
         assert.equal(element._orderedComments.length, 5);
         assert.equal(element._orderedComments[4].in_reply_to, 'jacks_reply');
       });
 
-      test('resolvable comments', function() {
+      test('resolvable comments', () => {
         assert.isFalse(element._unresolved);
         element._createReplyComment(element.comments[3], 'dummy', true, true);
         flushAsynchronousOperations();
         assert.isTrue(element._unresolved);
       });
 
-      test('_setInitialExpandedState', function() {
+      test('_setInitialExpandedState', () => {
         element._unresolved = true;
         element._setInitialExpandedState();
-        var comments = getComments();
-        for (var i = 0; i < element.comments.length; i++) {
+        for (let i = 0; i < element.comments.length; i++) {
           assert.isFalse(element.comments[i].collapsed);
         }
         element._unresolved = false;
         element._setInitialExpandedState();
-        var comments = getComments();
-        for (var i = 0; i < element.comments.length; i++) {
+        for (let i = 0; i < element.comments.length; i++) {
           assert.isTrue(element.comments[i].collapsed);
         }
       });
     });
 
-    test('_computeHostClass', function() {
+    test('_computeHostClass', () => {
       assert.equal(element._computeHostClass(true), 'unresolved');
       assert.equal(element._computeHostClass(false), '');
     });
 
-    test('addDraft sets unresolved state correctly', function() {
-      var unresolved = true;
+    test('addDraft sets unresolved state correctly', () => {
+      let unresolved = true;
       element.comments = [];
       element.addDraft(null, null, unresolved);
       assert.equal(element.comments[0].unresolved, true);
@@ -533,15 +525,15 @@
       assert.equal(element.comments[0].unresolved, true);
     });
 
-    test('_newDraft', function() {
+    test('_newDraft', () => {
       element.commentSide = 'left';
       element.patchNum = 3;
-      var draft = element._newDraft();
+      const draft = element._newDraft();
       assert.equal(draft.__commentSide, 'left');
       assert.equal(draft.patchNum, 3);
     });
 
-    test('new comment gets created', function() {
+    test('new comment gets created', () => {
       element.comments = [];
       element.addOrEditDraft(1);
       assert.equal(element.comments.length, 1);
@@ -552,7 +544,7 @@
       assert.equal(element.comments.length, 2);
     });
 
-    test('unresolved label', function() {
+    test('unresolved label', () => {
       element._unresolved = false;
       assert.isTrue(element.$.unresolvedLabel.hasAttribute('hidden'));
       element._unresolved = true;
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-comment/gr-diff-comment.js b/polygerrit-ui/app/elements/diff/gr-diff-comment/gr-diff-comment.js
index 0791193..ea6347f 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-comment/gr-diff-comment.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-comment/gr-diff-comment.js
@@ -173,6 +173,9 @@
     },
 
     _eraseDraftComment: function() {
+      // Prevents a race condition in which removing the draft comment occurs
+      // prior to it being saved.
+      this.cancelDebouncer('store');
       this.$.storage.eraseDraftComment({
         changeNum: this.changeNum,
         patchNum: this._getPatchNum(),
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-comment/gr-diff-comment_test.html b/polygerrit-ui/app/elements/diff/gr-diff-comment/gr-diff-comment_test.html
index 919a64f..bcac6b3 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-comment/gr-diff-comment_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-comment/gr-diff-comment_test.html
@@ -476,6 +476,7 @@
 
     test('draft saving/editing', function(done) {
       var fireStub = sinon.stub(element, 'fire');
+      let cancelDebounce = sandbox.stub(element, 'cancelDebouncer');
 
       element.draft = true;
       MockInteractions.tap(element.$$('.edit'));
@@ -507,6 +508,7 @@
       element._xhrPromise.then(function(draft) {
         assert(fireStub.calledWith('comment-save'),
                'comment-save should be sent');
+        assert(cancelDebounce.calledWith('store'));
         assert.deepEqual(fireStub.lastCall.args[1], {
           comment: {
             __commentSide: 'right',
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-preferences/gr-diff-preferences.js b/polygerrit-ui/app/elements/diff/gr-diff-preferences/gr-diff-preferences.js
index e29f8ef..20833d0 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-preferences/gr-diff-preferences.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-preferences/gr-diff-preferences.js
@@ -41,20 +41,19 @@
       '_localPrefsChanged(localPrefs.*)',
     ],
 
-    getFocusStops: function() {
+    getFocusStops() {
       return {
         start: this.$.contextSelect,
         end: this.$.cancelButton,
       };
     },
 
-    resetFocus: function() {
+    resetFocus() {
       this.$.contextSelect.focus();
     },
 
-    _prefsChanged: function(changeRecord) {
-      var prefs = changeRecord.base;
-      // TODO(andybons): This is not supported in IE. Implement a polyfill.
+    _prefsChanged(changeRecord) {
+      const prefs = changeRecord.base;
       // NOTE: Object.assign is NOT automatically a deep copy. If prefs adds
       // an object as a value, it must be marked enumerable.
       this._newPrefs = Object.assign({}, prefs);
@@ -65,71 +64,70 @@
       this.$.syntaxHighlightInput.checked = prefs.syntax_highlighting;
     },
 
-    _localPrefsChanged: function(changeRecord) {
-      var localPrefs = changeRecord.base || {};
-      // TODO(viktard): This is not supported in IE. Implement a polyfill.
+    _localPrefsChanged(changeRecord) {
+      const localPrefs = changeRecord.base || {};
       this._newLocalPrefs = Object.assign({}, localPrefs);
     },
 
-    _handleContextSelectChange: function(e) {
-      var selectEl = Polymer.dom(e).rootTarget;
+    _handleContextSelectChange(e) {
+      const selectEl = Polymer.dom(e).rootTarget;
       this.set('_newPrefs.context', parseInt(selectEl.value, 10));
     },
 
-    _handleShowTabsTap: function(e) {
+    _handleShowTabsTap(e) {
       this.set('_newPrefs.show_tabs', Polymer.dom(e).rootTarget.checked);
     },
 
-    _handleShowTrailingWhitespaceTap: function(e) {
+    _handleShowTrailingWhitespaceTap(e) {
       this.set('_newPrefs.show_whitespace_errors',
           Polymer.dom(e).rootTarget.checked);
     },
 
-    _handleSyntaxHighlightTap: function(e) {
+    _handleSyntaxHighlightTap(e) {
       this.set('_newPrefs.syntax_highlighting',
           Polymer.dom(e).rootTarget.checked);
     },
 
-    _handlelineWrappingTap: function(e) {
+    _handlelineWrappingTap(e) {
       this.set('_newPrefs.line_wrapping', Polymer.dom(e).rootTarget.checked);
     },
 
-    _handleSave: function(e) {
+    _handleSave(e) {
       e.stopPropagation();
       this.prefs = this._newPrefs;
       this.localPrefs = this._newLocalPrefs;
-      var el = Polymer.dom(e).rootTarget;
+      const el = Polymer.dom(e).rootTarget;
       el.disabled = true;
       this.$.storage.savePreferences(this._localPrefs);
-      this._saveDiffPreferences().then(function(response) {
+      this._saveDiffPreferences().then(response => {
         el.disabled = false;
         if (!response.ok) { return response; }
 
         this.$.prefsOverlay.close();
-      }.bind(this)).catch(function(err) {
+      }).catch(err => {
         el.disabled = false;
-      }.bind(this));
+      });
     },
 
-    _handleCancel: function(e) {
+    _handleCancel(e) {
       e.stopPropagation();
       this.$.prefsOverlay.close();
     },
 
-    _handlePrefsTap: function(e) {
+    _handlePrefsTap(e) {
       e.preventDefault();
       this._openPrefs();
     },
 
-    open: function() {
-      this.$.prefsOverlay.open().then(function() {
-        var focusStops = this.getFocusStops();
+    open() {
+      this.$.prefsOverlay.open().then(() => {
+        const focusStops = this.getFocusStops();
         this.$.prefsOverlay.setFocusStops(focusStops);
         this.resetFocus();
-      }.bind(this));
+      });
     },
 
-    _saveDiffPreferences: function() {
+    _saveDiffPreferences() {
       return this.$.restAPI.saveDiffPreferences(this.prefs);
     },
   });
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-preferences/gr-diff-preferences_test.html b/polygerrit-ui/app/elements/diff/gr-diff-preferences/gr-diff-preferences_test.html
index b163c71..d201edf 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-preferences/gr-diff-preferences_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-preferences/gr-diff-preferences_test.html
@@ -33,20 +33,20 @@
 </test-fixture>
 
 <script>
-  suite('gr-diff-preferences tests', function() {
-    var element;
-    var sandbox;
+  suite('gr-diff-preferences tests', () => {
+    let element;
+    let sandbox;
 
-    setup(function() {
+    setup(() => {
       sandbox = sinon.sandbox.create();
       element = fixture('basic');
     });
 
-    teardown(function() {
+    teardown(() => {
       sandbox.restore();
     });
 
-    test('model changes', function() {
+    test('model changes', () => {
       element.prefs = {
         context: 10,
         font_size: 12,
@@ -78,7 +78,7 @@
       assert.isFalse(element._newPrefs.syntax_highlighting);
     });
 
-    test('clicking fit to screen hides line length input', function() {
+    test('clicking fit to screen hides line length input', () => {
       element.prefs = {line_wrapping: false};
 
       assert.isFalse(element.$.columnsPref.hidden);
@@ -90,31 +90,31 @@
       assert.isFalse(element.$.columnsPref.hidden);
     });
 
-    test('clicking save button calls _handleSave function', function() {
-      var savePrefs = sinon.stub(element, '_handleSave');
+    test('clicking save button calls _handleSave function', () => {
+      const savePrefs = sinon.stub(element, '_handleSave');
       MockInteractions.tap(element.$.saveButton);
       flushAsynchronousOperations();
       assert(savePrefs.calledOnce);
       savePrefs.restore();
     });
 
-    test('save button', function() {
+    test('save button', () => {
       element.prefs = {
         font_size: '11',
       };
       element._newPrefs = {
         font_size: '12',
       };
-      var saveStub = sandbox.stub(element.$.restAPI, 'saveDiffPreferences',
-          function() { return Promise.resolve(); });
+      const saveStub = sandbox.stub(element.$.restAPI, 'saveDiffPreferences',
+          () => { return Promise.resolve(); });
 
       MockInteractions.tap(element.$$('gr-button[primary]'));
       assert.deepEqual(element.prefs, element._newPrefs);
       assert.deepEqual(saveStub.lastCall.args[0], element._newPrefs);
     });
 
-    test('cancel button', function() {
-      var closeStub = sandbox.stub(element.$.prefsOverlay, 'close');
+    test('cancel button', () => {
+      const closeStub = sandbox.stub(element.$.prefsOverlay, 'close');
       MockInteractions.tap(element.$$('gr-button:not([primary])'));
       assert.isTrue(closeStub.called);
     });
diff --git a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.html b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.html
index 848de56..dbbe14c 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.html
@@ -23,6 +23,8 @@
 <link rel="import" href="../gr-diff-selection/gr-diff-selection.html">
 <link rel="import" href="../gr-syntax-themes/gr-theme-default.html">
 
+<script src="../../../scripts/hiddenscroll.js"></script>
+
 <dom-module id="gr-diff">
   <template>
     <style>
@@ -31,7 +33,6 @@
         --dark-remove-highlight-color: rgba(255, 0, 0, 0.15);
         --light-add-highlight-color: #efe;
         --dark-add-highlight-color: rgba(0, 255, 0, 0.15);
-
       }
       :host.no-left .sideBySide ::content .left,
       :host.no-left .sideBySide ::content .left + td,
@@ -47,6 +48,9 @@
         overflow-x: auto;
         will-change: transform;
       }
+      .diffContainer.hiddenscroll {
+        padding-bottom: .8em;
+      }
       table {
         border-collapse: collapse;
         border-right: 1px solid #ddd;
diff --git a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.js b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.js
index ba402f2..09f9e83 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.js
@@ -114,7 +114,6 @@
       this._getLoggedIn().then(function(loggedIn) {
         this._loggedIn = loggedIn;
       }.bind(this));
-
     },
 
     ready: function() {
@@ -203,6 +202,9 @@
         default:
           throw Error('Invalid view mode: ', viewMode);
       }
+      if (Gerrit.hiddenscroll) {
+        classes.push('hiddenscroll');
+      }
       if (loggedIn) {
         classes.push('canComment');
       }
diff --git a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff_test.html b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff_test.html
index f765b26..a85615e 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff_test.html
@@ -712,6 +712,12 @@
           assert.equal(element.getCursorStops().length, 50);
         });
       });
+
+      test('adds .hiddenscroll', function() {
+        Gerrit.hiddenscroll = true;
+        element.displayLine = true;
+        assert.include(element.$$('.diffContainer').className, 'hiddenscroll');
+      });
     });
 
     suite('logged in', function() {
diff --git a/polygerrit-ui/app/elements/diff/gr-patch-range-select/gr-patch-range-select.js b/polygerrit-ui/app/elements/diff/gr-patch-range-select/gr-patch-range-select.js
index 58d29bd..e9437bd 100644
--- a/polygerrit-ui/app/elements/diff/gr-patch-range-select/gr-patch-range-select.js
+++ b/polygerrit-ui/app/elements/diff/gr-patch-range-select/gr-patch-range-select.js
@@ -15,7 +15,7 @@
   'use strict';
 
   // Maximum length for patch set descriptions.
-  var PATCH_DESC_MAX_LENGTH = 500;
+  const PATCH_DESC_MAX_LENGTH = 500;
 
   Polymer({
     is: 'gr-patch-range-select',
@@ -36,15 +36,15 @@
 
     behaviors: [Gerrit.PatchSetBehavior],
 
-    _updateSelected: function() {
+    _updateSelected() {
       this._rightSelected = this.patchRange.patchNum;
       this._leftSelected = this.patchRange.basePatchNum;
     },
 
-    _handlePatchChange: function(e) {
-      var leftPatch = this._leftSelected;
-      var rightPatch = this._rightSelected;
-      var rangeStr = rightPatch;
+    _handlePatchChange(e) {
+      const leftPatch = this._leftSelected;
+      const rightPatch = this._rightSelected;
+      let rangeStr = rightPatch;
       if (leftPatch != 'PARENT') {
         rangeStr = leftPatch + '..' + rangeStr;
       }
@@ -52,11 +52,11 @@
       e.target.blur();
     },
 
-    _computeLeftDisabled: function(patchNum, patchRange) {
+    _computeLeftDisabled(patchNum, patchRange) {
       return parseInt(patchNum, 10) >= parseInt(patchRange.patchNum, 10);
     },
 
-    _computeRightDisabled: function(patchNum, patchRange) {
+    _computeRightDisabled(patchNum, patchRange) {
       if (patchRange.basePatchNum == 'PARENT') { return false; }
       return parseInt(patchNum, 10) <= parseInt(patchRange.basePatchNum, 10);
     },
@@ -66,16 +66,16 @@
     // are loaded, the correct value will get selected.  I attempted to
     // debounce these, but because they are detecting two different
     // events, sometimes the timing was off and one ended up missing.
-    _synchronizeSelectionRight: function() {
+    _synchronizeSelectionRight() {
       this.$.rightPatchSelect.value = this._rightSelected;
     },
 
-    _synchronizeSelectionLeft: function() {
+    _synchronizeSelectionLeft() {
       this.$.leftPatchSelect.value = this._leftSelected;
     },
 
-    _computePatchSetDescription: function(revisions, patchNum) {
-      var rev = this.getRevisionByPatchNum(revisions, patchNum);
+    _computePatchSetDescription(revisions, patchNum) {
+      const rev = this.getRevisionByPatchNum(revisions, patchNum);
       return (rev && rev.description) ?
           rev.description.substring(0, PATCH_DESC_MAX_LENGTH) : '';
     },
diff --git a/polygerrit-ui/app/elements/diff/gr-patch-range-select/gr-patch-range-select_test.html b/polygerrit-ui/app/elements/diff/gr-patch-range-select/gr-patch-range-select_test.html
index 00d73bf..0195eac 100644
--- a/polygerrit-ui/app/elements/diff/gr-patch-range-select/gr-patch-range-select_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-patch-range-select/gr-patch-range-select_test.html
@@ -34,24 +34,24 @@
 </test-fixture>
 
 <script>
-  suite('gr-patch-range-select tests', function() {
-    var element;
+  suite('gr-patch-range-select tests', () => {
+    let element;
 
-    setup(function() {
+    setup(() => {
       element = fixture('basic');
     });
 
-    test('enabled/disabled options', function() {
-      var patchRange = {
+    test('enabled/disabled options', () => {
+      const patchRange = {
         basePatchNum: 'PARENT',
         patchNum: '3',
       };
-      ['1', '2', '3'].forEach(function(patchNum) {
+      for (const patchNum of ['1', '2', '3']) {
         assert.isFalse(element._computeRightDisabled(patchNum, patchRange));
-      });
-      ['PARENT', '1', '2'].forEach(function(patchNum) {
+      }
+      for (const patchNum of ['PARENT', '1', '2']) {
         assert.isFalse(element._computeLeftDisabled(patchNum, patchRange));
-      });
+      }
       assert.isTrue(element._computeLeftDisabled('3', patchRange));
 
       patchRange.basePatchNum = '2';
@@ -61,11 +61,11 @@
       assert.isFalse(element._computeRightDisabled('3', patchRange));
     });
 
-    test('navigation', function(done) {
-      var showStub = sinon.stub(page, 'show');
-      var leftSelectEl = element.$.leftPatchSelect;
-      var rightSelectEl = element.$.rightPatchSelect;
-      var blurSpy = sinon.spy(leftSelectEl, 'blur');
+    test('navigation', done => {
+      const showStub = sinon.stub(page, 'show');
+      const leftSelectEl = element.$.leftPatchSelect;
+      const rightSelectEl = element.$.rightPatchSelect;
+      const blurSpy = sinon.spy(leftSelectEl, 'blur');
       element.changeNum = '42';
       element.path = 'path/to/file.txt';
       element.availablePatches = ['1', '2', '3'];
@@ -75,8 +75,8 @@
       };
       flushAsynchronousOperations();
 
-      var numEvents = 0;
-      leftSelectEl.addEventListener('change', function(e) {
+      let numEvents = 0;
+      leftSelectEl.addEventListener('change', e => {
         numEvents++;
         if (numEvents == 1) {
           assert(showStub.lastCall.calledWithExactly(
@@ -98,23 +98,23 @@
       element.fire('change', {}, {node: leftSelectEl});
     });
 
-    test('filesWeblinks', function() {
+    test('filesWeblinks', () => {
       element.filesWeblinks = {
         meta_a: [
           {
             name: 'foo',
             url: 'f.oo',
-          }
+          },
         ],
         meta_b: [
           {
             name: 'bar',
             url: 'ba.r',
-          }
+          },
         ],
       };
       flushAsynchronousOperations();
-      var domApi = Polymer.dom(element.root);
+      const domApi = Polymer.dom(element.root);
       assert.equal(
           domApi.querySelector('a[href="f.oo"]').textContent, 'foo');
       assert.equal(
diff --git a/polygerrit-ui/app/elements/diff/gr-syntax-lib-loader/gr-syntax-lib-loader.js b/polygerrit-ui/app/elements/diff/gr-syntax-lib-loader/gr-syntax-lib-loader.js
index 520f24d..75b00e8 100644
--- a/polygerrit-ui/app/elements/diff/gr-syntax-lib-loader/gr-syntax-lib-loader.js
+++ b/polygerrit-ui/app/elements/diff/gr-syntax-lib-loader/gr-syntax-lib-loader.js
@@ -14,8 +14,8 @@
 (function() {
   'use strict';
 
-  var HLJS_PATH = 'bower_components/highlightjs/highlight.min.js';
-  var LIB_ROOT_PATTERN = /(.+\/)elements\/gr-app\.html/;
+  const HLJS_PATH = 'bower_components/highlightjs/highlight.min.js';
+  const LIB_ROOT_PATTERN = /(.+\/)elements\/gr-app\.html/;
 
   Polymer({
     is: 'gr-syntax-lib-loader',
@@ -30,11 +30,11 @@
           loading: false,
           callbacks: [],
         },
-      }
+      },
     },
 
-    get: function() {
-      return new Promise(function(resolve) {
+    get() {
+      return new Promise(resolve => {
         // If the lib is totally loaded, resolve immediately.
         if (this._state.loaded) {
           resolve(this._getHighlightLib());
@@ -48,27 +48,29 @@
         }
 
         this._state.callbacks.push(resolve);
-      }.bind(this));
+      });
     },
 
-    _onLibLoaded: function() {
-      var lib = this._getHighlightLib();
+    _onLibLoaded() {
+      const lib = this._getHighlightLib();
       this._state.loaded = true;
       this._state.loading = false;
-      this._state.callbacks.forEach(function(cb) { cb(lib); });
+      for (const cb of this._state.callbacks) {
+        cb(lib);
+      }
       this._state.callbacks = [];
     },
 
-    _getHighlightLib: function() {
+    _getHighlightLib() {
       return window.hljs;
     },
 
-    _configureHighlightLib: function() {
+    _configureHighlightLib() {
       this._getHighlightLib().configure(
           {classPrefix: 'gr-diff gr-syntax gr-syntax-'});
     },
 
-    _getLibRoot: function() {
+    _getLibRoot() {
       if (this._cachedLibRoot) { return this._cachedLibRoot; }
 
       return this._cachedLibRoot = document.head
@@ -78,16 +80,16 @@
     },
     _cachedLibRoot: null,
 
-    _loadHLJS: function() {
-      return new Promise(function(resolve) {
-        var script = document.createElement('script');
+    _loadHLJS() {
+      return new Promise(resolve => {
+        const script = document.createElement('script');
         script.src = this._getLibRoot() + HLJS_PATH;
         script.onload = function() {
           this._configureHighlightLib();
           resolve();
         }.bind(this);
         Polymer.dom(document.head).appendChild(script);
-      }.bind(this));
+      });
     },
   });
 })();
diff --git a/polygerrit-ui/app/elements/diff/gr-syntax-lib-loader/gr-syntax-lib-loader_test.html b/polygerrit-ui/app/elements/diff/gr-syntax-lib-loader/gr-syntax-lib-loader_test.html
index 985fc6d..0a916d0 100644
--- a/polygerrit-ui/app/elements/diff/gr-syntax-lib-loader/gr-syntax-lib-loader_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-syntax-lib-loader/gr-syntax-lib-loader_test.html
@@ -32,26 +32,24 @@
 </test-fixture>
 
 <script>
-  suite('gr-syntax-lib-loader tests', function() {
-    var element;
-    var resolveLoad;
-    var loadStub;
+  suite('gr-syntax-lib-loader tests', () => {
+    let element;
+    let resolveLoad;
+    let loadStub;
 
-    setup(function() {
+    setup(() => {
       element = fixture('basic');
 
-      loadStub = sinon.stub(element, '_loadHLJS', function() {
-        return new Promise(function(resolve) {
-          resolveLoad = resolve;
-        });
-      });
+      loadStub = sinon.stub(element, '_loadHLJS', () =>
+        new Promise(resolve => resolveLoad = resolve)
+      );
 
       // Assert preconditions:
       assert.isFalse(element._state.loaded);
       assert.isFalse(element._state.loading);
     });
 
-    teardown(function() {
+    teardown(() => {
       if (window.hljs) {
         delete window.hljs;
       }
@@ -63,8 +61,8 @@
       element._state.callbacks = [];
     });
 
-    test('only load once', function(done) {
-      var firstCallHandler = sinon.stub();
+    test('only load once', done => {
+      const firstCallHandler = sinon.stub();
       element.get().then(firstCallHandler);
 
       // It should now be in the loading state.
@@ -73,7 +71,7 @@
       assert.isFalse(element._state.loaded);
       assert.isFalse(firstCallHandler.called);
 
-      var secondCallHandler = sinon.stub();
+      const secondCallHandler = sinon.stub();
       element.get().then(secondCallHandler);
 
       // No change in state.
@@ -84,7 +82,7 @@
 
       // Now load the library.
       resolveLoad();
-      flush(function() {
+      flush(() => {
         // The state should be loaded and both handlers called.
         assert.isFalse(element._state.loading);
         assert.isTrue(element._state.loaded);
diff --git a/polygerrit-ui/app/elements/plugins/gr-external-style/gr-external-style.js b/polygerrit-ui/app/elements/plugins/gr-external-style/gr-external-style.js
index 162921a..5e3749d 100644
--- a/polygerrit-ui/app/elements/plugins/gr-external-style/gr-external-style.js
+++ b/polygerrit-ui/app/elements/plugins/gr-external-style/gr-external-style.js
@@ -21,39 +21,39 @@
       name: String,
     },
 
-    _import: function(url) {
-      return new Promise(function(resolve, reject) {
+    _import(url) {
+      return new Promise((resolve, reject) => {
         this.importHref(url, resolve, reject);
-      }.bind(this));
+      });
     },
 
-    _applyStyle: function(name) {
-      var s = document.createElement('style', 'custom-style');
+    _applyStyle(name) {
+      const s = document.createElement('style', 'custom-style');
       s.setAttribute('include', name);
       Polymer.dom(this.root).appendChild(s);
     },
 
-    ready: function() {
-      Gerrit.awaitPluginsLoaded().then(function() {
-        var sharedStyles = Gerrit._styleModules[this.name];
+    ready() {
+      Gerrit.awaitPluginsLoaded().then(() => {
+        const sharedStyles = Gerrit._styleModules[this.name];
         if (sharedStyles) {
-          var pluginUrls = [];
-          var moduleNames = [];
-          sharedStyles.reduce(function(result, item) {
+          const pluginUrls = [];
+          const moduleNames = [];
+          sharedStyles.reduce((result, item) => {
             if (!result.pluginUrls.includes(item.pluginUrl)) {
               result.pluginUrls.push(item.pluginUrl);
             }
             result.moduleNames.push(item.moduleName);
             return result;
-          }, {pluginUrls: pluginUrls, moduleNames: moduleNames});
+          }, {pluginUrls, moduleNames});
           Promise.all(pluginUrls.map(this._import.bind(this)))
-            .then(function() {
-              moduleNames.forEach(function(name) {
-                this._applyStyle(name);
-              }.bind(this));
-            }.bind(this));
+              .then(() => {
+                for (const name of moduleNames) {
+                  this._applyStyle(name);
+                }
+              });
         }
-      }.bind(this));
+      });
     },
   });
 })();
diff --git a/polygerrit-ui/app/elements/plugins/gr-external-style/gr-external-style_test.html b/polygerrit-ui/app/elements/plugins/gr-external-style/gr-external-style_test.html
index f626f71..f0e254f 100644
--- a/polygerrit-ui/app/elements/plugins/gr-external-style/gr-external-style_test.html
+++ b/polygerrit-ui/app/elements/plugins/gr-external-style/gr-external-style_test.html
@@ -31,30 +31,30 @@
 </test-fixture>
 
 <script>
-  suite('gr-change-metadata integration tests', function() {
-    var sandbox;
-    var element;
+  suite('gr-change-metadata integration tests', () => {
+    let sandbox;
+    let element;
 
-    setup(function(done) {
+    setup(done => {
       sandbox = sinon.sandbox.create();
       sandbox.stub(Gerrit, 'awaitPluginsLoaded').returns(Promise.resolve());
-      Gerrit._styleModules = {'foo': [{pluginUrl: 'bar', moduleName: 'baz',}]};
+      Gerrit._styleModules = {foo: [{pluginUrl: 'bar', moduleName: 'baz'}]};
 
       element = fixture('basic');
       sandbox.stub(element, '_applyStyle');
-      sandbox.stub(element, 'importHref', function(url, resolve) { resolve() });
+      sandbox.stub(element, 'importHref', (url, resolve) => { resolve(); });
       flush(done);
     });
 
-    teardown(function() {
+    teardown(() => {
       sandbox.restore();
     });
 
-    test('imports plugin-provided module', function() {
+    test('imports plugin-provided module', () => {
       assert.isTrue(element.importHref.calledWith('bar'));
     });
 
-    test('applies plugin-provided styles', function() {
+    test('applies plugin-provided styles', () => {
       assert.isTrue(element._applyStyle.calledWith('baz'));
     });
   });
diff --git a/polygerrit-ui/app/elements/plugins/gr-plugin-host/gr-plugin-host.js b/polygerrit-ui/app/elements/plugins/gr-plugin-host/gr-plugin-host.js
index 1c78689..cd7059c 100644
--- a/polygerrit-ui/app/elements/plugins/gr-plugin-host/gr-plugin-host.js
+++ b/polygerrit-ui/app/elements/plugins/gr-plugin-host/gr-plugin-host.js
@@ -24,28 +24,27 @@
       },
     },
 
-    _configChanged: function(config) {
-      var jsPlugins = config.js_resource_paths || [];
-      var htmlPlugins = config.html_resource_paths || [];
+    _configChanged(config) {
+      const jsPlugins = config.js_resource_paths || [];
+      const htmlPlugins = config.html_resource_paths || [];
       Gerrit._setPluginsCount(jsPlugins.length + htmlPlugins.length);
       this._loadJsPlugins(jsPlugins);
       this._importHtmlPlugins(htmlPlugins);
     },
 
-    _importHtmlPlugins: function(plugins) {
-      plugins.forEach(function(url) {
-        if (url.indexOf('http') !== 0) {
+    _importHtmlPlugins(plugins) {
+      for (let url of plugins) {
+        if (!url.startsWith('http')) {
           url = '/' + url;
         }
         this.importHref(
             url, Gerrit._pluginInstalled, Gerrit._pluginInstalled, true);
-      }.bind(this));
+      }
     },
 
-    _loadJsPlugins: function(plugins) {
-      for (var i = 0; i < plugins.length; i++) {
-        var url = plugins[i];
-        var scriptEl = document.createElement('script');
+    _loadJsPlugins(plugins) {
+      for (let i = 0; i < plugins.length; i++) {
+        const scriptEl = document.createElement('script');
         scriptEl.defer = true;
         scriptEl.src = '/' + plugins[i];
         scriptEl.onerror = Gerrit._pluginInstalled;
diff --git a/polygerrit-ui/app/elements/plugins/gr-plugin-host/gr-plugin-host_test.html b/polygerrit-ui/app/elements/plugins/gr-plugin-host/gr-plugin-host_test.html
index 5965bc3..17f4875 100644
--- a/polygerrit-ui/app/elements/plugins/gr-plugin-host/gr-plugin-host_test.html
+++ b/polygerrit-ui/app/elements/plugins/gr-plugin-host/gr-plugin-host_test.html
@@ -30,22 +30,22 @@
 </test-fixture>
 
 <script>
-  suite('gr-diff tests', function() {
-    var element;
-    var sandbox;
+  suite('gr-diff tests', () => {
+    let element;
+    let sandbox;
 
-    setup(function() {
+    setup(() => {
       element = fixture('basic');
       sandbox = sinon.sandbox.create();
       sandbox.stub(document.body, 'appendChild');
       sandbox.stub(element, 'importHref');
     });
 
-    teardown(function() {
+    teardown(() => {
       sandbox.restore();
     });
 
-    test('counts plugins', function() {
+    test('counts plugins', () => {
       sandbox.stub(Gerrit, '_setPluginsCount');
       element.config = {
         html_resource_paths: ['foo/bar', 'baz'],
@@ -54,7 +54,7 @@
       assert.isTrue(Gerrit._setPluginsCount.calledWith(3));
     });
 
-    test('imports html plugins from config', function() {
+    test('imports html plugins from config', () => {
       element.config = {
         html_resource_paths: ['foo/bar', 'baz'],
       };
diff --git a/polygerrit-ui/app/elements/settings/gr-change-table-editor/gr-change-table-editor.js b/polygerrit-ui/app/elements/settings/gr-change-table-editor/gr-change-table-editor.js
index 6a83a46..50a1146 100644
--- a/polygerrit-ui/app/elements/settings/gr-change-table-editor/gr-change-table-editor.js
+++ b/polygerrit-ui/app/elements/settings/gr-change-table-editor/gr-change-table-editor.js
@@ -28,13 +28,13 @@
       Gerrit.ChangeTableBehavior,
     ],
 
-    _getButtonText: function(isShown) {
+    _getButtonText(isShown) {
       return isShown ? 'Hide' : 'Show';
     },
 
-    _updateDisplayedColumns: function(displayedColumns, name, checked) {
+    _updateDisplayedColumns(displayedColumns, name, checked) {
       if (!checked) {
-        return displayedColumns.filter(function(column) {
+        return displayedColumns.filter(column => {
           return name.toLowerCase() !== column.toLowerCase();
         });
       } else {
@@ -45,8 +45,8 @@
     /**
      * Handles tap on either the checkbox itself or the surrounding table cell.
      */
-    _handleTargetTap: function(e) {
-      var checkbox = Polymer.dom(e.target).querySelector('input');
+    _handleTargetTap(e) {
+      let checkbox = Polymer.dom(e.target).querySelector('input');
       if (checkbox) {
         checkbox.click();
       } else {
diff --git a/polygerrit-ui/app/elements/settings/gr-change-table-editor/gr-change-table-editor_test.html b/polygerrit-ui/app/elements/settings/gr-change-table-editor/gr-change-table-editor_test.html
index d4443ac..15edb94 100644
--- a/polygerrit-ui/app/elements/settings/gr-change-table-editor/gr-change-table-editor_test.html
+++ b/polygerrit-ui/app/elements/settings/gr-change-table-editor/gr-change-table-editor_test.html
@@ -33,12 +33,12 @@
 </test-fixture>
 
 <script>
-  suite('gr-change-table-editor tests', function() {
-    var element;
-    var columns;
-    var sandbox;
+  suite('gr-change-table-editor tests', () => {
+    let element;
+    let columns;
+    let sandbox;
 
-    setup(function() {
+    setup(() => {
       element = fixture('basic');
       sandbox = sinon.sandbox.create();
 
@@ -55,25 +55,25 @@
       flushAsynchronousOperations();
     });
 
-    teardown(function() {
+    teardown(() => {
       sandbox.restore();
     });
 
-    test('renders', function() {
-      var rows = element.$$('tbody').querySelectorAll('tr');
-      var tds;
+    test('renders', () => {
+      const rows = element.$$('tbody').querySelectorAll('tr');
+      let tds;
 
       assert.equal(rows.length, element.columnNames.length);
-      for (var i = 0; i < columns.length; i++) {
+      for (let i = 0; i < columns.length; i++) {
         tds = rows[i].querySelectorAll('td');
         assert.equal(tds[0].textContent, columns[i]);
       }
     });
 
-    test('hide item', function() {
-      var checkbox = element.$$('table input');
-      var isChecked = checkbox.checked;
-      var displayedLength = element.displayedColumns.length;
+    test('hide item', () => {
+      const checkbox = element.$$('table input');
+      const isChecked = checkbox.checked;
+      const displayedLength = element.displayedColumns.length;
       assert.isTrue(isChecked);
 
       MockInteractions.tap(checkbox);
@@ -83,7 +83,7 @@
           displayedLength - 1);
     });
 
-    test('show item', function() {
+    test('show item', () => {
       element.set('displayedColumns', [
         'Status',
         'Owner',
@@ -92,9 +92,9 @@
         'Updated',
       ]);
       flushAsynchronousOperations();
-      var checkbox = element.$$('table input');
-      var isChecked = checkbox.checked;
-      var displayedLength = element.displayedColumns.length;
+      const checkbox = element.$$('table input');
+      const isChecked = checkbox.checked;
+      const displayedLength = element.displayedColumns.length;
       assert.isFalse(isChecked);
       assert.equal(element.$$('table').style.display, '');
 
@@ -105,11 +105,11 @@
           displayedLength + 1);
     });
 
-    test('_handleTargetTap', function() {
-      var checkbox = element.$$('table input');
-      var originalDisplayedColumns = element.displayedColumns;
-      var td = element.$$('table .checkboxContainer');
-      var displayedColumnStub =
+    test('_handleTargetTap', () => {
+      const checkbox = element.$$('table input');
+      let originalDisplayedColumns = element.displayedColumns;
+      const td = element.$$('table .checkboxContainer');
+      const displayedColumnStub =
           sandbox.stub(element, '_updateDisplayedColumns');
 
       MockInteractions.tap(checkbox);
@@ -126,9 +126,9 @@
           checkbox.checked));
     });
 
-    test('_updateDisplayedColumns', function() {
-      var name = 'Subject';
-      var checked = false;
+    test('_updateDisplayedColumns', () => {
+      let name = 'Subject';
+      let checked = false;
       assert.deepEqual(element._updateDisplayedColumns(columns, name, checked),
           [
             'Status',
diff --git a/polygerrit-ui/app/elements/settings/gr-email-editor/gr-email-editor.js b/polygerrit-ui/app/elements/settings/gr-email-editor/gr-email-editor.js
index 90dd119c..8490c1e 100644
--- a/polygerrit-ui/app/elements/settings/gr-email-editor/gr-email-editor.js
+++ b/polygerrit-ui/app/elements/settings/gr-email-editor/gr-email-editor.js
@@ -27,7 +27,7 @@
       _emails: Array,
       _emailsToRemove: {
         type: Array,
-        value: function() { return []; },
+        value() { return []; },
       },
       _newPreferred: {
         type: String,
@@ -35,18 +35,17 @@
       },
     },
 
-    loadData: function() {
-      return this.$.restAPI.getAccountEmails().then(function(emails) {
+    loadData() {
+      return this.$.restAPI.getAccountEmails().then(emails => {
         this._emails = emails;
-      }.bind(this));
+      });
     },
 
-    save: function() {
-      var promises = [];
+    save() {
+      const promises = [];
 
-      for (var i = 0; i < this._emailsToRemove.length; i++) {
-        promises.push(this.$.restAPI.deleteAccountEmail(
-            this._emailsToRemove[i].email));
+      for (const emailObj of this._emailsToRemove) {
+        promises.push(this.$.restAPI.deleteAccountEmail(emailObj.email));
       }
 
       if (this._newPreferred) {
@@ -54,30 +53,30 @@
             this._newPreferred));
       }
 
-      return Promise.all(promises).then(function() {
+      return Promise.all(promises).then(() => {
         this._emailsToRemove = [];
         this._newPreferred = null;
         this.hasUnsavedChanges = false;
-      }.bind(this));
+      });
     },
 
-    _handleDeleteButton: function(e) {
-      var index = parseInt(e.target.getAttribute('data-index'));
-      var email = this._emails[index];
+    _handleDeleteButton(e) {
+      const index = parseInt(e.target.getAttribute('data-index'));
+      const email = this._emails[index];
       this.push('_emailsToRemove', email);
       this.splice('_emails', index, 1);
       this.hasUnsavedChanges = true;
     },
 
-    _handlePreferredControlTap: function(e) {
+    _handlePreferredControlTap(e) {
       if (e.target.classList.contains('preferredControl')) {
         e.target.firstElementChild.click();
       }
     },
 
-    _handlePreferredChange: function(e) {
-      var preferred = e.target.value;
-      for (var i = 0; i < this._emails.length; i++) {
+    _handlePreferredChange(e) {
+      const preferred = e.target.value;
+      for (let i = 0; i < this._emails.length; i++) {
         if (preferred === this._emails[i].email) {
           this.set(['_emails', i, 'preferred'], true);
           this._newPreferred = preferred;
diff --git a/polygerrit-ui/app/elements/settings/gr-email-editor/gr-email-editor_test.html b/polygerrit-ui/app/elements/settings/gr-email-editor/gr-email-editor_test.html
index b949643..608179e 100644
--- a/polygerrit-ui/app/elements/settings/gr-email-editor/gr-email-editor_test.html
+++ b/polygerrit-ui/app/elements/settings/gr-email-editor/gr-email-editor_test.html
@@ -33,18 +33,18 @@
 </test-fixture>
 
 <script>
-  suite('gr-email-editor tests', function() {
-    var element;
+  suite('gr-email-editor tests', () => {
+    let element;
 
-    setup(function(done) {
-      var emails = [
+    setup(done => {
+      const emails = [
         {email: 'email@one.com'},
         {email: 'email@two.com', preferred: true},
         {email: 'email@three.com'},
       ];
 
       stub('gr-rest-api-interface', {
-        getAccountEmails: function() { return Promise.resolve(emails); },
+        getAccountEmails() { return Promise.resolve(emails); },
       });
 
       element = fixture('basic');
@@ -52,8 +52,8 @@
       element.loadData().then(done);
     });
 
-    test('renders', function() {
-      var rows = element.$$('table').querySelectorAll('tbody tr');
+    test('renders', () => {
+      const rows = element.$$('table').querySelectorAll('tbody tr');
 
       assert.equal(rows.length, 3);
 
@@ -69,9 +69,9 @@
       assert.isFalse(element.hasUnsavedChanges);
     });
 
-    test('edit preferred', function() {
-      var preferredChangedSpy = sinon.spy(element, '_handlePreferredChange');
-      var radios = element.$$('table').querySelectorAll('input[type=radio]');
+    test('edit preferred', () => {
+      const preferredChangedSpy = sinon.spy(element, '_handlePreferredChange');
+      const radios = element.$$('table').querySelectorAll('input[type=radio]');
 
       assert.isFalse(element.hasUnsavedChanges);
       assert.isNotOk(element._newPreferred);
@@ -92,8 +92,8 @@
       assert.isTrue(preferredChangedSpy.called);
     });
 
-    test('delete email', function() {
-      var buttons = element.$$('table').querySelectorAll('gr-button');
+    test('delete email', () => {
+      const buttons = element.$$('table').querySelectorAll('gr-button');
 
       assert.isFalse(element.hasUnsavedChanges);
       assert.isNotOk(element._newPreferred);
@@ -110,11 +110,12 @@
       assert.equal(element._emailsToRemove[0].email, 'email@three.com');
     });
 
-    test('save changes', function(done) {
-      var deleteEmailStub = sinon.stub(element.$.restAPI, 'deleteAccountEmail');
-      var setPreferredStub = sinon.stub(element.$.restAPI,
+    test('save changes', done => {
+      const deleteEmailStub =
+          sinon.stub(element.$.restAPI, 'deleteAccountEmail');
+      const setPreferredStub = sinon.stub(element.$.restAPI,
           'setPreferredAccountEmail');
-      var rows = element.$$('table').querySelectorAll('tbody tr');
+      const rows = element.$$('table').querySelectorAll('tbody tr');
 
       assert.isFalse(element.hasUnsavedChanges);
       assert.isNotOk(element._newPreferred);
@@ -132,7 +133,7 @@
       assert.equal(element._emails.length, 2);
 
       // Save the changes.
-      element.save().then(function() {
+      element.save().then(() => {
         assert.equal(deleteEmailStub.callCount, 1);
         assert.equal(deleteEmailStub.getCall(0).args[0], 'email@one.com');
 
diff --git a/polygerrit-ui/app/elements/settings/gr-group-list/gr-group-list.js b/polygerrit-ui/app/elements/settings/gr-group-list/gr-group-list.js
index d14c755..d26482d 100644
--- a/polygerrit-ui/app/elements/settings/gr-group-list/gr-group-list.js
+++ b/polygerrit-ui/app/elements/settings/gr-group-list/gr-group-list.js
@@ -21,15 +21,15 @@
       _groups: Array,
     },
 
-    loadData: function() {
-      return this.$.restAPI.getAccountGroups().then(function(groups) {
-        this._groups = groups.sort(function(a, b) {
+    loadData() {
+      return this.$.restAPI.getAccountGroups().then(groups => {
+        this._groups = groups.sort((a, b) => {
           return a.name.localeCompare(b.name);
         });
-      }.bind(this));
+      });
     },
 
-    _computeVisibleToAll: function(group) {
+    _computeVisibleToAll(group) {
       return group.options.visible_to_all ? 'Yes' : 'No';
     },
   });
diff --git a/polygerrit-ui/app/elements/settings/gr-group-list/gr-group-list_test.html b/polygerrit-ui/app/elements/settings/gr-group-list/gr-group-list_test.html
index 2abf797..c0cecdf 100644
--- a/polygerrit-ui/app/elements/settings/gr-group-list/gr-group-list_test.html
+++ b/polygerrit-ui/app/elements/settings/gr-group-list/gr-group-list_test.html
@@ -32,11 +32,11 @@
 </test-fixture>
 
 <script>
-  suite('gr-group-list tests', function() {
-    var element;
-    var groups;
+  suite('gr-group-list tests', () => {
+    let element;
+    let groups;
 
-    setup(function(done) {
+    setup(done => {
       groups = [{
         url: 'some url',
         options: {},
@@ -46,39 +46,40 @@
         owner_id: '123',
         id: 'abc',
         name: 'Group 1',
-      },{
+      }, {
         options: {visible_to_all: true},
         id: '456',
         name: 'Group 2',
-      },{
+      }, {
         options: {},
         id: '789',
         name: 'Group 3',
       }];
 
       stub('gr-rest-api-interface', {
-        getAccountGroups: function() { return Promise.resolve(groups); },
+        getAccountGroups() { return Promise.resolve(groups); },
       });
 
       element = fixture('basic');
 
-      element.loadData().then(function() { flush(done); });
+      element.loadData().then(() => { flush(done); });
     });
 
-    test('renders', function() {
-      var rows = Polymer.dom(element.root).querySelectorAll('tbody tr');
+    test('renders', () => {
+      const rows = Polymer.dom(element.root).querySelectorAll('tbody tr');
 
       assert.equal(rows.length, 3);
 
-      var nameCells = rows.map(
-          function(row) { return row.querySelectorAll('td')[0].textContent; });
+      const nameCells = rows.map(row =>
+        row.querySelectorAll('td')[0].textContent
+      );
 
       assert.equal(nameCells[0], 'Group 1');
       assert.equal(nameCells[1], 'Group 2');
       assert.equal(nameCells[2], 'Group 3');
     });
 
-    test('_computeVisibleToAll', function() {
+    test('_computeVisibleToAll', () => {
       assert.equal(element._computeVisibleToAll(groups[0]), 'No');
       assert.equal(element._computeVisibleToAll(groups[1]), 'Yes');
     });
diff --git a/polygerrit-ui/app/elements/settings/gr-http-password/gr-http-password.js b/polygerrit-ui/app/elements/settings/gr-http-password/gr-http-password.js
index f4894e9..d9c19e2 100644
--- a/polygerrit-ui/app/elements/settings/gr-http-password/gr-http-password.js
+++ b/polygerrit-ui/app/elements/settings/gr-http-password/gr-http-password.js
@@ -23,33 +23,33 @@
       _passwordUrl: String,
     },
 
-    loadData: function() {
-      var promises = [];
+    loadData() {
+      const promises = [];
 
-      promises.push(this.$.restAPI.getAccount().then(function(account) {
+      promises.push(this.$.restAPI.getAccount().then(account => {
         this._username = account.username;
-      }.bind(this)));
+      }));
 
-      promises.push(this.$.restAPI.getConfig().then(function(info) {
+      promises.push(this.$.restAPI.getConfig().then(info => {
         this._passwordUrl = info.auth.http_password_url || null;
-      }.bind(this)));
+      }));
 
       return Promise.all(promises);
     },
 
-    _handleGenerateTap: function() {
+    _handleGenerateTap() {
       this._generatedPassword = 'Generating...';
       this.$.generatedPasswordOverlay.open();
-      this.$.restAPI.generateAccountHttpPassword().then(function(newPassword) {
+      this.$.restAPI.generateAccountHttpPassword().then(newPassword => {
         this._generatedPassword = newPassword;
-      }.bind(this));
+      });
     },
 
-    _closeOverlay: function() {
+    _closeOverlay() {
       this.$.generatedPasswordOverlay.close();
     },
 
-    _generatedPasswordOverlayClosed: function() {
+    _generatedPasswordOverlayClosed() {
       this._generatedPassword = null;
     },
   });
diff --git a/polygerrit-ui/app/elements/settings/gr-http-password/gr-http-password_test.html b/polygerrit-ui/app/elements/settings/gr-http-password/gr-http-password_test.html
index 787c2c4..acc9f60 100644
--- a/polygerrit-ui/app/elements/settings/gr-http-password/gr-http-password_test.html
+++ b/polygerrit-ui/app/elements/settings/gr-http-password/gr-http-password_test.html
@@ -33,33 +33,31 @@
 </test-fixture>
 
 <script>
-  suite('gr-http-password tests', function() {
-    var element;
-    var account;
-    var password;
-    var config;
+  suite('gr-http-password tests', () => {
+    let element;
+    let account;
+    let config;
 
-    setup(function(done) {
+    setup(done => {
       account = {username: 'user name'};
       config = {auth: {}};
-      password = 'the password';
 
       stub('gr-rest-api-interface', {
-        getAccount: function() { return Promise.resolve(account); },
-        getConfig: function() { return Promise.resolve(config); },
+        getAccount() { return Promise.resolve(account); },
+        getConfig() { return Promise.resolve(config); },
       });
 
       element = fixture('basic');
-      element.loadData().then(function() { flush(done); });
+      element.loadData().then(() => { flush(done); });
     });
 
-    test('generate password', function() {
-      var button = element.$.generateButton;
-      var nextPassword = 'the new password';
-      var generateResolve;
-      var generateStub = sinon.stub(element.$.restAPI,
-          'generateAccountHttpPassword', function() {
-            return new Promise(function(resolve) {
+    test('generate password', () => {
+      const button = element.$.generateButton;
+      const nextPassword = 'the new password';
+      let generateResolve;
+      const generateStub = sinon.stub(element.$.restAPI,
+          'generateAccountHttpPassword', () => {
+            return new Promise(resolve => {
               generateResolve = resolve;
             });
           });
@@ -73,18 +71,18 @@
 
       generateResolve(nextPassword);
 
-      generateStub.lastCall.returnValue.then(function() {
+      generateStub.lastCall.returnValue.then(() => {
         assert.equal(element._generatedPassword, nextPassword);
       });
     });
 
-    test('without http_password_url', function() {
+    test('without http_password_url', () => {
       assert.isNull(element._passwordUrl);
     });
 
-    test('with http_password_url', function(done) {
+    test('with http_password_url', done => {
       config.auth.http_password_url = 'http://example.com/';
-      element.loadData().then(function() {
+      element.loadData().then(() => {
         assert.isNotNull(element._passwordUrl);
         assert.equal(element._passwordUrl, config.auth.http_password_url);
         done();
diff --git a/polygerrit-ui/app/elements/settings/gr-menu-editor/gr-menu-editor.js b/polygerrit-ui/app/elements/settings/gr-menu-editor/gr-menu-editor.js
index d3a2e2d..543c86d 100644
--- a/polygerrit-ui/app/elements/settings/gr-menu-editor/gr-menu-editor.js
+++ b/polygerrit-ui/app/elements/settings/gr-menu-editor/gr-menu-editor.js
@@ -23,28 +23,28 @@
       _newUrl: String,
     },
 
-    _handleMoveUpButton: function(e) {
-      var index = e.target.dataIndex;
+    _handleMoveUpButton(e) {
+      const index = e.target.dataIndex;
       if (index === 0) { return; }
-      var row = this.menuItems[index];
-      var prev = this.menuItems[index - 1];
+      const row = this.menuItems[index];
+      const prev = this.menuItems[index - 1];
       this.splice('menuItems', index - 1, 2, row, prev);
     },
 
-    _handleMoveDownButton: function(e) {
-      var index = e.target.dataIndex;
+    _handleMoveDownButton(e) {
+      const index = e.target.dataIndex;
       if (index === this.menuItems.length - 1) { return; }
-      var row = this.menuItems[index];
-      var next = this.menuItems[index + 1];
+      const row = this.menuItems[index];
+      const next = this.menuItems[index + 1];
       this.splice('menuItems', index, 2, next, row);
     },
 
-    _handleDeleteButton: function(e) {
-      var index = e.target.dataIndex;
+    _handleDeleteButton(e) {
+      const index = e.target.dataIndex;
       this.splice('menuItems', index, 1);
     },
 
-    _handleAddButton: function() {
+    _handleAddButton() {
       if (this._computeAddDisabled(this._newName, this._newUrl)) { return; }
 
       this.splice('menuItems', this.menuItems.length, 0, {
@@ -57,11 +57,11 @@
       this._newUrl = '';
     },
 
-    _computeAddDisabled: function(newName, newUrl) {
+    _computeAddDisabled(newName, newUrl) {
       return !newName.length || !newUrl.length;
     },
 
-    _handleInputKeydown: function(e) {
+    _handleInputKeydown(e) {
       if (e.keyCode === 13) {
         e.stopPropagation();
         this._handleAddButton();
diff --git a/polygerrit-ui/app/elements/settings/gr-menu-editor/gr-menu-editor_test.html b/polygerrit-ui/app/elements/settings/gr-menu-editor/gr-menu-editor_test.html
index a7078093..f9e905d 100644
--- a/polygerrit-ui/app/elements/settings/gr-menu-editor/gr-menu-editor_test.html
+++ b/polygerrit-ui/app/elements/settings/gr-menu-editor/gr-menu-editor_test.html
@@ -33,14 +33,14 @@
 </test-fixture>
 
 <script>
-  suite('gr-settings-view tests', function() {
-    var element;
-    var menu;
+  suite('gr-settings-view tests', () => {
+    let element;
+    let menu;
 
     function assertMenuNamesEqual(element, expected) {
-      var names = element.menuItems.map(function(i) { return i.name; });
+      const names = element.menuItems.map(i => { return i.name; });
       assert.equal(names.length, expected.length);
-      for (var i = 0; i < names.length; i++) {
+      for (let i = 0; i < names.length; i++) {
         assert.equal(names[i], expected[i]);
       }
     }
@@ -48,13 +48,13 @@
     // Click the up/down button (according to direction) for the index'th row.
     // The index of the first row is 0, corresponding to the array.
     function move(element, index, direction) {
-      var selector =
+      const selector =
           'tr:nth-child(' + (index + 1) + ') .move-' + direction + '-button';
-      var button = element.$$('tbody').querySelector(selector);
+      const button = element.$$('tbody').querySelector(selector);
       MockInteractions.tap(button);
     }
 
-    setup(function() {
+    setup(() => {
       element = fixture('basic');
       menu = [
         {url: '/first/url', name: 'first name', target: '_blank'},
@@ -65,12 +65,12 @@
       Polymer.dom.flush();
     });
 
-    test('renders', function() {
-      var rows = element.$$('tbody').querySelectorAll('tr');
-      var tds;
+    test('renders', () => {
+      const rows = element.$$('tbody').querySelectorAll('tr');
+      let tds;
 
       assert.equal(rows.length, menu.length);
-      for (var i = 0; i < menu.length; i++) {
+      for (let i = 0; i < menu.length; i++) {
         tds = rows[i].querySelectorAll('td');
         assert.equal(tds[0].textContent, menu[i].name);
         assert.equal(tds[1].textContent, menu[i].url);
@@ -80,23 +80,23 @@
           element._newUrl));
     });
 
-    test('_computeAddDisabled', function() {
+    test('_computeAddDisabled', () => {
       assert.isTrue(element._computeAddDisabled('', ''));
       assert.isTrue(element._computeAddDisabled('name', ''));
       assert.isTrue(element._computeAddDisabled('', 'url'));
       assert.isFalse(element._computeAddDisabled('name', 'url'));
     });
 
-    test('add a new menu item', function() {
-      var newName = 'new name';
-      var newUrl = 'new url';
+    test('add a new menu item', () => {
+      const newName = 'new name';
+      const newUrl = 'new url';
 
       element._newName = newName;
       element._newUrl = newUrl;
       assert.isFalse(element._computeAddDisabled(element._newName,
           element._newUrl));
 
-      var originalMenuLength = element.menuItems.length;
+      const originalMenuLength = element.menuItems.length;
 
       element._handleAddButton();
 
@@ -106,7 +106,7 @@
       assert.equal(element.menuItems[element.menuItems.length - 1].url, newUrl);
     });
 
-    test('move items down', function() {
+    test('move items down', () => {
       assertMenuNamesEqual(element,
           ['first name', 'second name', 'third name']);
 
@@ -121,7 +121,7 @@
           ['first name', 'third name', 'second name']);
     });
 
-    test('move items up', function() {
+    test('move items up', () => {
       assertMenuNamesEqual(element,
           ['first name', 'second name', 'third name']);
 
@@ -137,7 +137,7 @@
           ['third name', 'first name', 'second name']);
     });
 
-    test('remove item', function() {
+    test('remove item', () => {
       assertMenuNamesEqual(element,
           ['first name', 'second name', 'third name']);
 
@@ -148,7 +148,7 @@
       assertMenuNamesEqual(element, ['first name', 'third name']);
 
       // Delete remaining items.
-      for (var i = 0; i < 2; i++) {
+      for (let i = 0; i < 2; i++) {
         MockInteractions.tap(
             element.$$('tbody').querySelector('tr:first-child .remove-button'));
       }
diff --git a/polygerrit-ui/app/elements/settings/gr-registration-dialog/gr-registration-dialog.js b/polygerrit-ui/app/elements/settings/gr-registration-dialog/gr-registration-dialog.js
index 9acdba9..319143a 100644
--- a/polygerrit-ui/app/elements/settings/gr-registration-dialog/gr-registration-dialog.js
+++ b/polygerrit-ui/app/elements/settings/gr-registration-dialog/gr-registration-dialog.js
@@ -38,39 +38,39 @@
       role: 'dialog',
     },
 
-    attached: function() {
-      this.$.restAPI.getAccount().then(function(account) {
+    attached() {
+      this.$.restAPI.getAccount().then(account => {
         this._account = account;
-      }.bind(this));
+      });
     },
 
-    _handleNameKeydown: function(e) {
+    _handleNameKeydown(e) {
       if (e.keyCode === 13) { // Enter
         e.stopPropagation();
         this._save();
       }
     },
 
-    _save: function() {
+    _save() {
       this._saving = true;
-      var promises = [
+      const promises = [
         this.$.restAPI.setAccountName(this.$.name.value),
         this.$.restAPI.setPreferredAccountEmail(this.$.email.value),
       ];
-      return Promise.all(promises).then(function() {
+      return Promise.all(promises).then(() => {
         this._saving = false;
         this.fire('account-detail-update');
-      }.bind(this));
+      });
     },
 
-    _handleSave: function(e) {
+    _handleSave(e) {
       e.preventDefault();
-      this._save().then(function() {
+      this._save().then(() => {
         this.fire('close');
-      }.bind(this));
+      });
     },
 
-    _handleClose: function(e) {
+    _handleClose(e) {
       e.preventDefault();
       this._saving = true; // disable buttons indefinitely
       this.fire('close');
diff --git a/polygerrit-ui/app/elements/settings/gr-registration-dialog/gr-registration-dialog_test.html b/polygerrit-ui/app/elements/settings/gr-registration-dialog/gr-registration-dialog_test.html
index ee5a206..1f8a34a 100644
--- a/polygerrit-ui/app/elements/settings/gr-registration-dialog/gr-registration-dialog_test.html
+++ b/polygerrit-ui/app/elements/settings/gr-registration-dialog/gr-registration-dialog_test.html
@@ -39,12 +39,12 @@
 </test-fixture>
 
 <script>
-  suite('gr-registration-dialog tests', function() {
-    var element;
-    var account;
-    var _listeners;
+  suite('gr-registration-dialog tests', () => {
+    let element;
+    let account;
+    let _listeners;
 
-    setup(function(done) {
+    setup(done => {
       _listeners = {};
 
       account = {
@@ -57,16 +57,16 @@
       };
 
       stub('gr-rest-api-interface', {
-        getAccount: function() {
-          // Once the account is resolved, we can let the test proceed.
+        getAccount() {
+        // Once the account is resolved, we can let the test proceed.
           flush(done);
           return Promise.resolve(account);
         },
-        setAccountName: function(name) {
+        setAccountName(name) {
           account.name = name;
           return Promise.resolve();
         },
-        setPreferredAccountEmail: function(email) {
+        setPreferredAccountEmail(email) {
           account.email = email;
           return Promise.resolve();
         },
@@ -75,8 +75,8 @@
       element = fixture('basic');
     });
 
-    teardown(function() {
-      for (var eventType in _listeners) {
+    teardown(() => {
+      for (const eventType in _listeners) {
         if (_listeners.hasOwnProperty(eventType)) {
           element.removeEventListener(eventType, _listeners[eventType]);
         }
@@ -84,14 +84,14 @@
     });
 
     function listen(eventType) {
-      return new Promise(function(resolve) {
+      return new Promise(resolve => {
         _listeners[eventType] = function() { resolve(); };
         element.addEventListener(eventType, _listeners[eventType]);
       });
     }
 
     function save(opt_action) {
-      var promise = listen('account-detail-update');
+      const promise = listen('account-detail-update');
       if (opt_action) {
         opt_action();
       } else {
@@ -101,7 +101,7 @@
     }
 
     function close(opt_action) {
-      var promise = listen('close');
+      const promise = listen('close');
       if (opt_action) {
         opt_action();
       } else {
@@ -110,18 +110,18 @@
       return promise;
     }
 
-    test('fires the close event on close', function(done) {
+    test('fires the close event on close', done => {
       close().then(done);
     });
 
-    test('fires the close event on save', function(done) {
-      close(function() {
+    test('fires the close event on save', done => {
+      close(() => {
         MockInteractions.tap(element.$.saveButton);
       }).then(done);
     });
 
-    test('saves name and preferred email', function(done) {
-      flush(function() {
+    test('saves name and preferred email', done => {
+      flush(() => {
         element.$.name.value = 'new name';
         element.$.email.value = 'email3';
 
@@ -130,18 +130,18 @@
         assert.equal(account.email, 'email');
 
         // Save and verify new values are committed.
-        save().then(function() {
+        save().then(() => {
           assert.equal(account.name, 'new name');
           assert.equal(account.email, 'email3');
         }).then(done);
       });
     });
 
-    test('pressing enter saves name', function(done) {
+    test('pressing enter saves name', done => {
       element.$.name.value = 'entered name';
-      save(function() {
+      save(() => {
         MockInteractions.pressAndReleaseKeyOn(element.$.name, 13);  // 'enter'
-      }).then(function() {
+      }).then(() => {
         assert.equal(account.name, 'entered name');
       }).then(done);
     });
diff --git a/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view.js b/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view.js
index 6c26550..d44fcfa 100644
--- a/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view.js
+++ b/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view.js
@@ -14,7 +14,7 @@
 (function() {
   'use strict';
 
-  var PREFS_SECTION_FIELDS = [
+  const PREFS_SECTION_FIELDS = [
     'changes_per_page',
     'date_format',
     'time_format',
@@ -43,11 +43,11 @@
     properties: {
       prefs: {
         type: Object,
-        value: function() { return {}; },
+        value() { return {}; },
       },
       params: {
         type: Object,
-        value: function() { return {}; },
+        value() { return {}; },
       },
       _accountNameMutable: Boolean,
       _accountInfoChanged: Boolean,
@@ -55,15 +55,15 @@
       _changeTableColumnsNotDisplayed: Array,
       _localPrefs: {
         type: Object,
-        value: function() { return {}; },
+        value() { return {}; },
       },
       _localChangeTableColumns: {
         type: Array,
-        value: function() { return []; },
+        value() { return []; },
       },
       _localMenu: {
         type: Array,
-        value: function() { return []; },
+        value() { return []; },
       },
       _loading: {
         type: Boolean,
@@ -122,68 +122,68 @@
       '_handleChangeTableChanged(_localChangeTableColumns)',
     ],
 
-    attached: function() {
+    attached() {
       this.fire('title-change', {title: 'Settings'});
 
-      var promises = [
+      const promises = [
         this.$.accountInfo.loadData(),
         this.$.watchedProjectsEditor.loadData(),
         this.$.groupList.loadData(),
         this.$.httpPass.loadData(),
       ];
 
-      promises.push(this.$.restAPI.getPreferences().then(function(prefs) {
+      promises.push(this.$.restAPI.getPreferences().then(prefs => {
         this.prefs = prefs;
         this._copyPrefs('_localPrefs', 'prefs');
         this._cloneMenu();
         this._cloneChangeTableColumns();
-      }.bind(this)));
+      }));
 
-      promises.push(this.$.restAPI.getDiffPreferences().then(function(prefs) {
+      promises.push(this.$.restAPI.getDiffPreferences().then(prefs => {
         this._diffPrefs = prefs;
-      }.bind(this)));
+      }));
 
-      promises.push(this.$.restAPI.getConfig().then(function(config) {
+      promises.push(this.$.restAPI.getConfig().then(config => {
         this._serverConfig = config;
         if (this._serverConfig.sshd) {
           return this.$.sshEditor.loadData();
         }
-      }.bind(this)));
+      }));
 
       if (this.params.emailToken) {
         promises.push(this.$.restAPI.confirmEmail(this.params.emailToken).then(
-          function(message) {
-            if (message) {
-              this.fire('show-alert', {message: message});
-            }
-            this.$.emailEditor.loadData();
-          }.bind(this)));
+            message => {
+              if (message) {
+                this.fire('show-alert', {message});
+              }
+              this.$.emailEditor.loadData();
+            }));
       } else {
         promises.push(this.$.emailEditor.loadData());
       }
 
-      this._loadingPromise = Promise.all(promises).then(function() {
+      this._loadingPromise = Promise.all(promises).then(() => {
         this._loading = false;
-      }.bind(this));
+      });
 
       this.listen(window, 'scroll', '_handleBodyScroll');
     },
 
-    detached: function() {
+    detached() {
       this.unlisten(window, 'scroll', '_handleBodyScroll');
     },
 
-    reloadAccountDetail: function() {
+    reloadAccountDetail() {
       Promise.all([
         this.$.accountInfo.loadData(),
         this.$.emailEditor.loadData(),
       ]);
     },
 
-    _handleBodyScroll: function(e) {
+    _handleBodyScroll(e) {
       if (this._headerHeight === undefined) {
-        var top = this.$.settingsNav.offsetTop;
-        for (var offsetParent = this.$.settingsNav.offsetParent;
+        let top = this.$.settingsNav.offsetTop;
+        for (let offsetParent = this.$.settingsNav.offsetParent;
            offsetParent;
            offsetParent = offsetParent.offsetParent) {
           top += offsetParent.offsetTop;
@@ -195,163 +195,163 @@
           window.scrollY >= this._headerHeight);
     },
 
-    _isLoading: function() {
+    _isLoading() {
       return this._loading || this._loading === undefined;
     },
 
-    _copyPrefs: function(to, from) {
-      for (var i = 0; i < PREFS_SECTION_FIELDS.length; i++) {
+    _copyPrefs(to, from) {
+      for (let i = 0; i < PREFS_SECTION_FIELDS.length; i++) {
         this.set([to, PREFS_SECTION_FIELDS[i]],
             this[from][PREFS_SECTION_FIELDS[i]]);
       }
     },
 
-    _cloneMenu: function() {
-      var menu = [];
-      this.prefs.my.forEach(function(item) {
+    _cloneMenu() {
+      const menu = [];
+      for (const item of this.prefs.my) {
         menu.push({
           name: item.name,
           url: item.url,
           target: item.target,
         });
-      });
+      }
       this._localMenu = menu;
     },
 
-    _cloneChangeTableColumns: function() {
-      var columns = this.prefs.change_table;
+    _cloneChangeTableColumns() {
+      let columns = this.prefs.change_table;
 
       if (columns.length === 0) {
         columns = this.columnNames;
         this._changeTableColumnsNotDisplayed = [];
       } else {
         this._changeTableColumnsNotDisplayed = this.getComplementColumns(
-          this.prefs.change_table);
+            this.prefs.change_table);
       }
       this._localChangeTableColumns = columns;
     },
 
-    _formatChangeTableColumns: function(changeTableArray) {
-      return changeTableArray.map(function(item) {
+    _formatChangeTableColumns(changeTableArray) {
+      return changeTableArray.map(item => {
         return {column: item};
       });
     },
 
-    _handleChangeTableChanged: function() {
+    _handleChangeTableChanged() {
       if (this._isLoading()) { return; }
       this._changeTableChanged = true;
     },
 
-    _handlePrefsChanged: function(prefs) {
+    _handlePrefsChanged(prefs) {
       if (this._isLoading()) { return; }
       this._prefsChanged = true;
     },
 
-    _handleDiffPrefsChanged: function() {
+    _handleDiffPrefsChanged() {
       if (this._isLoading()) { return; }
       this._diffPrefsChanged = true;
     },
 
-    _handleExpandInlineDiffsChanged: function() {
+    _handleExpandInlineDiffsChanged() {
       this.set('_localPrefs.expand_inline_diffs',
           this.$.expandInlineDiffs.checked);
     },
 
-    _handlePublishCommentsOnPushChanged: function() {
+    _handlePublishCommentsOnPushChanged() {
       this.set('_localPrefs.publish_comments_on_push',
           this.$.publishCommentsOnPush.checked);
     },
 
-    _handleMenuChanged: function() {
+    _handleMenuChanged() {
       if (this._isLoading()) { return; }
       this._menuChanged = true;
     },
 
-    _handleSaveAccountInfo: function() {
+    _handleSaveAccountInfo() {
       this.$.accountInfo.save();
     },
 
-    _handleSavePreferences: function() {
+    _handleSavePreferences() {
       this._copyPrefs('prefs', '_localPrefs');
 
-      return this.$.restAPI.savePreferences(this.prefs).then(function() {
+      return this.$.restAPI.savePreferences(this.prefs).then(() => {
         this._prefsChanged = false;
-      }.bind(this));
+      });
     },
 
-    _handleLineWrappingChanged: function() {
+    _handleLineWrappingChanged() {
       this.set('_diffPrefs.line_wrapping', this.$.lineWrapping.checked);
     },
 
-    _handleShowTabsChanged: function() {
+    _handleShowTabsChanged() {
       this.set('_diffPrefs.show_tabs', this.$.showTabs.checked);
     },
 
-    _handleShowTrailingWhitespaceChanged: function() {
+    _handleShowTrailingWhitespaceChanged() {
       this.set('_diffPrefs.show_whitespace_errors',
           this.$.showTrailingWhitespace.checked);
     },
 
-    _handleSyntaxHighlightingChanged: function() {
+    _handleSyntaxHighlightingChanged() {
       this.set('_diffPrefs.syntax_highlighting',
           this.$.syntaxHighlighting.checked);
     },
 
-    _handleSaveChangeTable: function() {
+    _handleSaveChangeTable() {
       this.set('prefs.change_table', this._localChangeTableColumns);
       this._cloneChangeTableColumns();
-      return this.$.restAPI.savePreferences(this.prefs).then(function() {
+      return this.$.restAPI.savePreferences(this.prefs).then(() => {
         this._changeTableChanged = false;
-      }.bind(this));
+      });
     },
 
-    _handleSaveDiffPreferences: function() {
+    _handleSaveDiffPreferences() {
       return this.$.restAPI.saveDiffPreferences(this._diffPrefs)
-          .then(function() {
+          .then(() => {
             this._diffPrefsChanged = false;
-          }.bind(this));
+          });
     },
 
-    _handleSaveMenu: function() {
+    _handleSaveMenu() {
       this.set('prefs.my', this._localMenu);
       this._cloneMenu();
-      return this.$.restAPI.savePreferences(this.prefs).then(function() {
+      return this.$.restAPI.savePreferences(this.prefs).then(() => {
         this._menuChanged = false;
-      }.bind(this));
+      });
     },
 
-    _handleSaveWatchedProjects: function() {
+    _handleSaveWatchedProjects() {
       this.$.watchedProjectsEditor.save();
     },
 
-    _computeHeaderClass: function(changed) {
+    _computeHeaderClass(changed) {
       return changed ? 'edited' : '';
     },
 
-    _handleSaveEmails: function() {
+    _handleSaveEmails() {
       this.$.emailEditor.save();
     },
 
-    _handleNewEmailKeydown: function(e) {
+    _handleNewEmailKeydown(e) {
       if (e.keyCode === 13) { // Enter
         e.stopPropagation();
         this._handleAddEmailButton();
       }
     },
 
-    _isNewEmailValid: function(newEmail) {
-      return newEmail.indexOf('@') !== -1;
+    _isNewEmailValid(newEmail) {
+      return newEmail.includes('@');
     },
 
-    _computeAddEmailButtonEnabled: function(newEmail, addingEmail) {
+    _computeAddEmailButtonEnabled(newEmail, addingEmail) {
       return this._isNewEmailValid(newEmail) && !addingEmail;
     },
 
-    _handleAddEmailButton: function() {
+    _handleAddEmailButton() {
       if (!this._isNewEmailValid(this._newEmail)) { return; }
 
       this._addingEmail = true;
-      this.$.restAPI.addAccountEmail(this._newEmail).then(function(response) {
+      this.$.restAPI.addAccountEmail(this._newEmail).then(response => {
         this._addingEmail = false;
 
         // If it was unsuccessful.
@@ -359,7 +359,7 @@
 
         this._lastSentVerificationEmail = this._newEmail;
         this._newEmail = '';
-      }.bind(this));
+      });
     },
   });
 })();
diff --git a/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view_test.html b/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view_test.html
index 33e6bd5..2d6c16d 100644
--- a/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view_test.html
+++ b/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view_test.html
@@ -39,18 +39,18 @@
 </test-fixture>
 
 <script>
-  suite('gr-settings-view tests', function() {
-    var element;
-    var account;
-    var preferences;
-    var diffPreferences;
-    var config;
-    var sandbox;
+  suite('gr-settings-view tests', () => {
+    let element;
+    let account;
+    let preferences;
+    let diffPreferences;
+    let config;
+    let sandbox;
 
     function valueOf(title, fieldsetid) {
-      var sections = element.$[fieldsetid].querySelectorAll('section');
-      var titleEl;
-      for (var i = 0; i < sections.length; i++) {
+      const sections = element.$[fieldsetid].querySelectorAll('section');
+      let titleEl;
+      for (let i = 0; i < sections.length; i++) {
         titleEl = sections[i].querySelector('.title');
         if (titleEl.textContent === title) {
           return sections[i].querySelector('.value');
@@ -61,7 +61,7 @@
     // Because deepEqual isn't behaving in Safari.
     function assertMenusEqual(actual, expected) {
       assert.equal(actual.length, expected.length);
-      for (var i = 0; i < actual.length; i++) {
+      for (let i = 0; i < actual.length; i++) {
         assert.equal(actual[i].name, expected[i].name);
         assert.equal(actual[i].url, expected[i].url);
       }
@@ -69,10 +69,10 @@
 
     function stubAddAccountEmail(statusCode) {
       return sandbox.stub(element.$.restAPI, 'addAccountEmail',
-          function() { return Promise.resolve({status: statusCode}); });
+          () => { return Promise.resolve({status: statusCode}); });
     }
 
-    setup(function(done) {
+    setup(done => {
       sandbox = sinon.sandbox.create();
       account = {
         _account_id: 123,
@@ -109,23 +109,23 @@
         syntax_highlighting: true,
         auto_hide_diff_table_header: true,
         theme: 'DEFAULT',
-        ignore_whitespace: 'IGNORE_NONE'
+        ignore_whitespace: 'IGNORE_NONE',
       };
       config = {auth: {editable_account_fields: []}};
 
       stub('gr-rest-api-interface', {
-        getLoggedIn: function() { return Promise.resolve(true); },
-        getAccount: function() { return Promise.resolve(account); },
-        getPreferences: function() { return Promise.resolve(preferences); },
-        getDiffPreferences: function() {
+        getLoggedIn() { return Promise.resolve(true); },
+        getAccount() { return Promise.resolve(account); },
+        getPreferences() { return Promise.resolve(preferences); },
+        getDiffPreferences() {
           return Promise.resolve(diffPreferences);
         },
-        getWatchedProjects: function() {
+        getWatchedProjects() {
           return Promise.resolve([]);
         },
-        getAccountEmails: function() { return Promise.resolve(); },
-        getConfig: function() { return Promise.resolve(config); },
-        getAccountGroups: function() { return Promise.resolve([]); },
+        getAccountEmails() { return Promise.resolve(); },
+        getConfig() { return Promise.resolve(config); },
+        getAccountGroups() { return Promise.resolve([]); },
       });
       element = fixture('basic');
 
@@ -133,19 +133,19 @@
       element._loadingPromise.then(done);
     });
 
-    teardown(function() {
+    teardown(() => {
       sandbox.restore();
     });
 
-    test('calls the title-change event', function() {
-      var titleChangedStub = sandbox.stub();
+    test('calls the title-change event', () => {
+      const titleChangedStub = sandbox.stub();
 
       // Create a new view.
-      var newElement = document.createElement('gr-settings-view');
+      const newElement = document.createElement('gr-settings-view');
       newElement.addEventListener('title-change', titleChangedStub);
 
       // Attach it to the fixture.
-      var blank = fixture('blank');
+      const blank = fixture('blank');
       blank.appendChild(newElement);
 
       Polymer.dom.flush();
@@ -155,7 +155,7 @@
           'Settings');
     });
 
-    test('user preferences', function(done) {
+    test('user preferences', done => {
       // Rendered with the expected preferences selected.
       assert.equal(valueOf('Changes per page', 'preferences')
           .firstElementChild.bindValue, preferences.changes_per_page);
@@ -178,10 +178,10 @@
       assert.isFalse(element._menuChanged);
 
       // Change the diff view element.
-      var diffSelect = valueOf('Diff view', 'preferences').firstElementChild;
+      const diffSelect = valueOf('Diff view', 'preferences').firstElementChild;
       diffSelect.bindValue = 'SIDE_BY_SIDE';
 
-      var expandInlineDiffs =
+      const expandInlineDiffs =
           valueOf('Expand inline diffs', 'preferences').firstElementChild;
       diffSelect.fire('change');
 
@@ -191,24 +191,24 @@
       assert.isFalse(element._menuChanged);
 
       stub('gr-rest-api-interface', {
-        savePreferences: function(prefs) {
+        savePreferences(prefs) {
           assert.equal(prefs.diff_view, 'SIDE_BY_SIDE');
           assertMenusEqual(prefs.my, preferences.my);
           assert.equal(prefs.expand_inline_diffs, true);
           return Promise.resolve();
-        }
+        },
       });
 
       // Save the change.
-      element._handleSavePreferences().then(function() {
+      element._handleSavePreferences().then(() => {
         assert.isFalse(element._prefsChanged);
         assert.isFalse(element._menuChanged);
         done();
       });
     });
 
-    test('publish comments on push', function(done) {
-      var publishCommentsOnPush =
+    test('publish comments on push', done => {
+      const publishCommentsOnPush =
         valueOf('Publish comments on push', 'preferences').firstElementChild;
       MockInteractions.tap(publishCommentsOnPush);
 
@@ -216,21 +216,21 @@
       assert.isTrue(element._prefsChanged);
 
       stub('gr-rest-api-interface', {
-        savePreferences: function(prefs) {
+        savePreferences(prefs) {
           assert.equal(prefs.publish_comments_on_push, true);
           return Promise.resolve();
-        }
+        },
       });
 
       // Save the change.
-      element._handleSavePreferences().then(function() {
+      element._handleSavePreferences().then(() => {
         assert.isFalse(element._prefsChanged);
         assert.isFalse(element._menuChanged);
         done();
       });
     });
 
-    test('diff preferences', function(done) {
+    test('diff preferences', done => {
       // Rendered with the expected preferences selected.
       assert.equal(valueOf('Context', 'diffPreferences')
           .firstElementChild.bindValue, diffPreferences.context);
@@ -249,7 +249,7 @@
 
       assert.isFalse(element._diffPrefsChanged);
 
-      var showTabsCheckbox = valueOf('Show tabs', 'diffPreferences')
+      const showTabsCheckbox = valueOf('Show tabs', 'diffPreferences')
           .firstElementChild;
       showTabsCheckbox.checked = false;
       element._handleShowTabsChanged();
@@ -257,20 +257,20 @@
       assert.isTrue(element._diffPrefsChanged);
 
       stub('gr-rest-api-interface', {
-        saveDiffPreferences: function(prefs) {
+        saveDiffPreferences(prefs) {
           assert.equal(prefs.show_tabs, false);
           return Promise.resolve();
-        }
+        },
       });
 
       // Save the change.
-      element._handleSaveDiffPreferences().then(function() {
+      element._handleSaveDiffPreferences().then(() => {
         assert.isFalse(element._diffPrefsChanged);
         done();
       });
     });
 
-    test('columns input is hidden with fit to scsreen is selected', function() {
+    test('columns input is hidden with fit to scsreen is selected', () => {
       assert.isFalse(element.$.columnsPref.hidden);
 
       MockInteractions.tap(element.$.lineWrapping);
@@ -280,14 +280,14 @@
       assert.isFalse(element.$.columnsPref.hidden);
     });
 
-    test('menu', function(done) {
+    test('menu', done => {
       assert.isFalse(element._menuChanged);
       assert.isFalse(element._prefsChanged);
 
       assertMenusEqual(element._localMenu, preferences.my);
 
-      var menu = element.$.menu.firstElementChild;
-      var tableRows = Polymer.dom(menu.root).querySelectorAll('tbody tr');
+      const menu = element.$.menu.firstElementChild;
+      let tableRows = Polymer.dom(menu.root).querySelectorAll('tbody tr');
       assert.equal(tableRows.length, preferences.my.length);
 
       // Add a menu item:
@@ -301,13 +301,13 @@
       assert.isFalse(element._prefsChanged);
 
       stub('gr-rest-api-interface', {
-        savePreferences: function(prefs) {
+        savePreferences(prefs) {
           assertMenusEqual(prefs.my, element._localMenu);
           return Promise.resolve();
-        }
+        },
       });
 
-      element._handleSaveMenu().then(function() {
+      element._handleSaveMenu().then(() => {
         assert.isFalse(element._menuChanged);
         assert.isFalse(element._prefsChanged);
         assertMenusEqual(element.prefs.my, element._localMenu);
@@ -315,7 +315,7 @@
       });
     });
 
-    test('add email validation', function() {
+    test('add email validation', () => {
       assert.isFalse(element._isNewEmailValid('invalid email'));
       assert.isTrue(element._isNewEmailValid('vaguely@valid.email'));
 
@@ -327,8 +327,8 @@
           element._computeAddEmailButtonEnabled('vaguely@valid.email', false));
     });
 
-    test('add email does not save invalid', function() {
-      var addEmailStub = stubAddAccountEmail(201);
+    test('add email does not save invalid', () => {
+      const addEmailStub = stubAddAccountEmail(201);
 
       assert.isFalse(element._addingEmail);
       assert.isNotOk(element._lastSentVerificationEmail);
@@ -343,8 +343,8 @@
       assert.isFalse(addEmailStub.called);
     });
 
-    test('add email does save valid', function(done) {
-      var addEmailStub = stubAddAccountEmail(201);
+    test('add email does save valid', done => {
+      const addEmailStub = stubAddAccountEmail(201);
 
       assert.isFalse(element._addingEmail);
       assert.isNotOk(element._lastSentVerificationEmail);
@@ -356,14 +356,14 @@
       assert.isTrue(addEmailStub.called);
 
       assert.isTrue(addEmailStub.called);
-      addEmailStub.lastCall.returnValue.then(function() {
+      addEmailStub.lastCall.returnValue.then(() => {
         assert.isOk(element._lastSentVerificationEmail);
         done();
       });
     });
 
-    test('add email does not set last-email if error', function(done) {
-      var addEmailStub = stubAddAccountEmail(500);
+    test('add email does not set last-email if error', done => {
+      const addEmailStub = stubAddAccountEmail(500);
 
       assert.isNotOk(element._lastSentVerificationEmail);
       element._newEmail = 'valid@email.com';
@@ -371,58 +371,57 @@
       element._handleAddEmailButton();
 
       assert.isTrue(addEmailStub.called);
-      addEmailStub.lastCall.returnValue.then(function() {
+      addEmailStub.lastCall.returnValue.then(() => {
         assert.isNotOk(element._lastSentVerificationEmail);
         done();
       });
     });
 
-    test('emails are loaded without emailToken', function() {
+    test('emails are loaded without emailToken', () => {
       sandbox.stub(element.$.emailEditor, 'loadData');
       element.params = {};
       element.attached();
       assert.isTrue(element.$.emailEditor.loadData.calledOnce);
     });
 
-    suite('when email verification token is provided', function() {
-      var resolveConfirm;
+    suite('when email verification token is provided', () => {
+      let resolveConfirm;
 
-      setup(function() {
+      setup(() => {
         sandbox.stub(element.$.emailEditor, 'loadData');
-        sandbox.stub(element.$.restAPI, 'confirmEmail', function() {
-          return new Promise(function(resolve) { resolveConfirm = resolve; });
+        sandbox.stub(element.$.restAPI, 'confirmEmail', () => {
+          return new Promise(resolve => { resolveConfirm = resolve; });
         });
         element.params = {emailToken: 'foo'};
         element.attached();
       });
 
-      test('it is used to confirm email via rest API', function() {
+      test('it is used to confirm email via rest API', () => {
         assert.isTrue(element.$.restAPI.confirmEmail.calledOnce);
         assert.isTrue(element.$.restAPI.confirmEmail.calledWith('foo'));
       });
 
-      test('emails are not loaded initially', function() {
+      test('emails are not loaded initially', () => {
         assert.isFalse(element.$.emailEditor.loadData.called);
       });
 
-      test('user emails are loaded after email confirmed', function(done) {
-        element._loadingPromise.then(function() {
+      test('user emails are loaded after email confirmed', done => {
+        element._loadingPromise.then(() => {
           assert.isTrue(element.$.emailEditor.loadData.calledOnce);
           done();
         });
         resolveConfirm();
       });
 
-      test('show-alert is fired when email is confirmed', function(done) {
+      test('show-alert is fired when email is confirmed', done => {
         sandbox.spy(element, 'fire');
-        element._loadingPromise.then(function() {
+        element._loadingPromise.then(() => {
           assert.isTrue(
               element.fire.calledWith('show-alert', {message: 'bar'}));
           done();
         });
         resolveConfirm('bar');
       });
-
     });
   });
 </script>
diff --git a/polygerrit-ui/app/elements/settings/gr-ssh-editor/gr-ssh-editor.js b/polygerrit-ui/app/elements/settings/gr-ssh-editor/gr-ssh-editor.js
index 2a05033..d9f02d5 100644
--- a/polygerrit-ui/app/elements/settings/gr-ssh-editor/gr-ssh-editor.js
+++ b/polygerrit-ui/app/elements/settings/gr-ssh-editor/gr-ssh-editor.js
@@ -31,64 +31,63 @@
       },
       _keysToRemove: {
         type: Array,
-        value: function() { return []; },
+        value() { return []; },
       },
     },
 
-    loadData: function() {
-      return this.$.restAPI.getAccountSSHKeys().then(function(keys) {
+    loadData() {
+      return this.$.restAPI.getAccountSSHKeys().then(keys => {
         this._keys = keys;
-      }.bind(this));
+      });
     },
 
-    save: function() {
-      var promises = this._keysToRemove.map(function(key) {
+    save() {
+      const promises = this._keysToRemove.map(key => {
         this.$.restAPI.deleteAccountSSHKey(key.seq);
-      }.bind(this));
+      });
 
-      return Promise.all(promises).then(function() {
+      return Promise.all(promises).then(() => {
         this._keysToRemove = [];
         this.hasUnsavedChanges = false;
-      }.bind(this));
+      });
     },
 
-    _getStatusLabel: function(isValid) {
+    _getStatusLabel(isValid) {
       return isValid ? 'Valid' : 'Invalid';
     },
 
-    _showKey: function(e) {
-      var index = parseInt(e.target.getAttribute('data-index'), 10);
+    _showKey(e) {
+      const index = parseInt(e.target.getAttribute('data-index'), 10);
       this._keyToView = this._keys[index];
       this.$.viewKeyOverlay.open();
     },
 
-    _closeOverlay: function() {
+    _closeOverlay() {
       this.$.viewKeyOverlay.close();
     },
 
-    _handleDeleteKey: function(e) {
-      var index = parseInt(e.target.getAttribute('data-index'), 10);
+    _handleDeleteKey(e) {
+      const index = parseInt(e.target.getAttribute('data-index'), 10);
       this.push('_keysToRemove', this._keys[index]);
       this.splice('_keys', index, 1);
       this.hasUnsavedChanges = true;
     },
 
-    _handleAddKey: function() {
+    _handleAddKey() {
       this.$.addButton.disabled = true;
       this.$.newKey.disabled = true;
       return this.$.restAPI.addAccountSSHKey(this._newKey.trim())
-          .then(function(key) {
+          .then(key => {
             this.$.newKey.disabled = false;
             this._newKey = '';
             this.push('_keys', key);
-          }.bind(this))
-          .catch(function() {
+          }).catch(() => {
             this.$.addButton.disabled = false;
             this.$.newKey.disabled = false;
-          }.bind(this));
+          });
     },
 
-    _computeAddButtonDisabled: function(newKey) {
+    _computeAddButtonDisabled(newKey) {
       return !newKey.length;
     },
   });
diff --git a/polygerrit-ui/app/elements/settings/gr-ssh-editor/gr-ssh-editor_test.html b/polygerrit-ui/app/elements/settings/gr-ssh-editor/gr-ssh-editor_test.html
index 7bb5528..09da19f 100644
--- a/polygerrit-ui/app/elements/settings/gr-ssh-editor/gr-ssh-editor_test.html
+++ b/polygerrit-ui/app/elements/settings/gr-ssh-editor/gr-ssh-editor_test.html
@@ -33,11 +33,11 @@
 </test-fixture>
 
 <script>
-  suite('gr-ssh-editor tests', function() {
-    var element;
-    var keys;
+  suite('gr-ssh-editor tests', () => {
+    let element;
+    let keys;
 
-    setup(function(done) {
+    setup(done => {
       keys = [{
         seq: 1,
         ssh_public_key: 'ssh-rsa <key 1> comment-one@machine-one',
@@ -55,37 +55,37 @@
       }];
 
       stub('gr-rest-api-interface', {
-        getAccountSSHKeys: function() { return Promise.resolve(keys); },
+        getAccountSSHKeys() { return Promise.resolve(keys); },
       });
 
       element = fixture('basic');
 
-      element.loadData().then(function() { flush(done); });
+      element.loadData().then(() => { flush(done); });
     });
 
-    test('renders', function() {
-      var rows = Polymer.dom(element.root).querySelectorAll('tbody tr');
+    test('renders', () => {
+      const rows = Polymer.dom(element.root).querySelectorAll('tbody tr');
 
       assert.equal(rows.length, 2);
 
-      var cells = rows[0].querySelectorAll('td');
+      let cells = rows[0].querySelectorAll('td');
       assert.equal(cells[0].textContent, keys[0].comment);
 
       cells = rows[1].querySelectorAll('td');
       assert.equal(cells[0].textContent, keys[1].comment);
     });
 
-    test('remove key', function(done) {
-      var lastKey = keys[1];
+    test('remove key', done => {
+      const lastKey = keys[1];
 
-      var saveStub = sinon.stub(element.$.restAPI, 'deleteAccountSSHKey',
-          function() { return Promise.resolve(); });
+      const saveStub = sinon.stub(element.$.restAPI, 'deleteAccountSSHKey',
+          () => { return Promise.resolve(); });
 
       assert.equal(element._keysToRemove.length, 0);
       assert.isFalse(element.hasUnsavedChanges);
 
       // Get the delete button for the last row.
-      var button = Polymer.dom(element.root).querySelector(
+      const button = Polymer.dom(element.root).querySelector(
           'tbody tr:last-of-type td:nth-child(4) gr-button');
 
       MockInteractions.tap(button);
@@ -96,7 +96,7 @@
       assert.isTrue(element.hasUnsavedChanges);
       assert.isFalse(saveStub.called);
 
-      element.save().then(function() {
+      element.save().then(() => {
         assert.isTrue(saveStub.called);
         assert.equal(saveStub.lastCall.args[0], lastKey.seq);
         assert.equal(element._keysToRemove.length, 0);
@@ -105,11 +105,11 @@
       });
     });
 
-    test('show key', function() {
-      var openSpy = sinon.spy(element.$.viewKeyOverlay, 'open');
+    test('show key', () => {
+      const openSpy = sinon.spy(element.$.viewKeyOverlay, 'open');
 
       // Get the show button for the last row.
-      var button = Polymer.dom(element.root).querySelector(
+      const button = Polymer.dom(element.root).querySelector(
           'tbody tr:last-of-type td:nth-child(3) gr-button');
 
       MockInteractions.tap(button);
@@ -118,9 +118,9 @@
       assert.isTrue(openSpy.called);
     });
 
-    test('add key', function(done) {
-      var newKeyString = 'ssh-rsa <key 3> comment-three@machine-three';
-      var newKeyObject = {
+    test('add key', done => {
+      const newKeyString = 'ssh-rsa <key 3> comment-three@machine-three';
+      const newKeyObject = {
         seq: 3,
         ssh_public_key: newKeyString,
         encoded_key: '<key 3>',
@@ -129,15 +129,15 @@
         valid: true,
       };
 
-      var addStub = sinon.stub(element.$.restAPI, 'addAccountSSHKey',
-          function() { return Promise.resolve(newKeyObject); });
+      const addStub = sinon.stub(element.$.restAPI, 'addAccountSSHKey',
+          () => { return Promise.resolve(newKeyObject); });
 
       element._newKey = newKeyString;
 
       assert.isFalse(element.$.addButton.disabled);
       assert.isFalse(element.$.newKey.disabled);
 
-      element._handleAddKey().then(function() {
+      element._handleAddKey().then(() => {
         assert.isTrue(element.$.addButton.disabled);
         assert.isFalse(element.$.newKey.disabled);
         assert.equal(element._keys.length, 3);
@@ -151,18 +151,18 @@
       assert.equal(addStub.lastCall.args[0], newKeyString);
     });
 
-    test('add invalid key', function(done) {
-      var newKeyString = 'not even close to valid';
+    test('add invalid key', done => {
+      const newKeyString = 'not even close to valid';
 
-      var addStub = sinon.stub(element.$.restAPI, 'addAccountSSHKey',
-          function() { return Promise.reject(); });
+      const addStub = sinon.stub(element.$.restAPI, 'addAccountSSHKey',
+          () => { return Promise.reject(); });
 
       element._newKey = newKeyString;
 
       assert.isFalse(element.$.addButton.disabled);
       assert.isFalse(element.$.newKey.disabled);
 
-      element._handleAddKey().then(function() {
+      element._handleAddKey().then(() => {
         assert.isFalse(element.$.addButton.disabled);
         assert.isFalse(element.$.newKey.disabled);
         assert.equal(element._keys.length, 2);
diff --git a/polygerrit-ui/app/elements/settings/gr-watched-projects-editor/gr-watched-projects-editor.js b/polygerrit-ui/app/elements/settings/gr-watched-projects-editor/gr-watched-projects-editor.js
index d65f512..c1eabad 100644
--- a/polygerrit-ui/app/elements/settings/gr-watched-projects-editor/gr-watched-projects-editor.js
+++ b/polygerrit-ui/app/elements/settings/gr-watched-projects-editor/gr-watched-projects-editor.js
@@ -14,7 +14,7 @@
 (function() {
   'use strict';
 
-  var NOTIFICATION_TYPES = [
+  const NOTIFICATION_TYPES = [
     {name: 'Changes', key: 'notify_new_changes'},
     {name: 'Patches', key: 'notify_new_patch_sets'},
     {name: 'Comments', key: 'notify_all_comments'},
@@ -35,24 +35,24 @@
       _projects: Array,
       _projectsToRemove: {
         type: Array,
-        value: function() { return []; },
+        value() { return []; },
       },
       _query: {
         type: Function,
-        value: function() {
+        value() {
           return this._getProjectSuggestions.bind(this);
         },
       },
     },
 
-    loadData: function() {
-      return this.$.restAPI.getWatchedProjects().then(function(projs) {
+    loadData() {
+      return this.$.restAPI.getWatchedProjects().then(projs => {
         this._projects = projs;
-      }.bind(this));
+      });
     },
 
-    save: function() {
-      var deletePromise;
+    save() {
+      let deletePromise;
       if (this._projectsToRemove.length) {
         deletePromise = this.$.restAPI.deleteWatchedProjects(
             this._projectsToRemove);
@@ -61,56 +61,57 @@
       }
 
       return deletePromise
-          .then(function() {
+          .then(() => {
             return this.$.restAPI.saveWatchedProjects(this._projects);
-          }.bind(this))
-          .then(function(projects) {
+          })
+          .then(projects => {
             this._projects = projects;
             this._projectsToRemove = [];
             this.hasUnsavedChanges = false;
-          }.bind(this));
+          });
     },
 
-    _getTypes: function() {
+    _getTypes() {
       return NOTIFICATION_TYPES;
     },
 
-    _getTypeCount: function() {
+    _getTypeCount() {
       return this._getTypes().length;
     },
 
-    _computeCheckboxChecked: function(project, key) {
+    _computeCheckboxChecked(project, key) {
       return project.hasOwnProperty(key);
     },
 
-    _getProjectSuggestions: function(input) {
+    _getProjectSuggestions(input) {
       return this.$.restAPI.getSuggestedProjects(input)
-        .then(function(response) {
-          var projects = [];
-          for (var key in response) {
-            projects.push({
-              name: key,
-              value: response[key],
-            });
-          }
-          return projects;
-        });
+          .then(response => {
+            const projects = [];
+            for (const key in response) {
+              if (!response.hasOwnProperty(key)) { continue; }
+              projects.push({
+                name: key,
+                value: response[key],
+              });
+            }
+            return projects;
+          });
     },
 
-    _handleRemoveProject: function(e) {
-      var index = parseInt(e.target.getAttribute('data-index'), 10);
-      var project = this._projects[index];
+    _handleRemoveProject(e) {
+      const index = parseInt(e.target.getAttribute('data-index'), 10);
+      const project = this._projects[index];
       this.splice('_projects', index, 1);
       this.push('_projectsToRemove', project);
       this.hasUnsavedChanges = true;
     },
 
-    _canAddProject: function(project, filter) {
+    _canAddProject(project, filter) {
       if (!project || !project.id) { return false; }
 
       // Check if the project with filter is already in the list. Compare
       // filters using == to coalesce null and undefined.
-      for (var i = 0; i < this._projects.length; i++) {
+      for (let i = 0; i < this._projects.length; i++) {
         if (this._projects[i].project === project.id &&
             this._projects[i].filter == filter) {
           return false;
@@ -120,8 +121,9 @@
       return true;
     },
 
-    _getNewProjectIndex: function(name, filter) {
-      for (var i = 0; i < this._projects.length; i++) {
+    _getNewProjectIndex(name, filter) {
+      let i;
+      for (i = 0; i < this._projects.length; i++) {
         if (this._projects[i].project > name ||
             (this._projects[i].project === name &&
                 this._projects[i].filter > filter)) {
@@ -131,18 +133,18 @@
       return i;
     },
 
-    _handleAddProject: function() {
-      var newProject = this.$.newProject.value;
-      var newProjectName = this.$.newProject.text;
-      var filter = this.$.newFilter.value || null;
+    _handleAddProject() {
+      const newProject = this.$.newProject.value;
+      const newProjectName = this.$.newProject.text;
+      const filter = this.$.newFilter.value || null;
 
       if (!this._canAddProject(newProject, filter)) { return; }
 
-      var insertIndex = this._getNewProjectIndex(newProjectName, filter);
+      const insertIndex = this._getNewProjectIndex(newProjectName, filter);
 
       this.splice('_projects', insertIndex, 0, {
         project: newProjectName,
-        filter: filter,
+        filter,
         _is_local: true,
       });
 
@@ -151,16 +153,16 @@
       this.hasUnsavedChanges = true;
     },
 
-    _handleCheckboxChange: function(e) {
-      var index = parseInt(e.target.getAttribute('data-index'), 10);
-      var key = e.target.getAttribute('data-key');
-      var checked = e.target.checked;
+    _handleCheckboxChange(e) {
+      const index = parseInt(e.target.getAttribute('data-index'), 10);
+      const key = e.target.getAttribute('data-key');
+      const checked = e.target.checked;
       this.set(['_projects', index, key], !!checked);
       this.hasUnsavedChanges = true;
     },
 
-    _handleNotifCellTap: function(e) {
-      var checkbox = Polymer.dom(e.target).querySelector('input');
+    _handleNotifCellTap(e) {
+      const checkbox = Polymer.dom(e.target).querySelector('input');
       if (checkbox) { checkbox.click(); }
     },
   });
diff --git a/polygerrit-ui/app/elements/settings/gr-watched-projects-editor/gr-watched-projects-editor_test.html b/polygerrit-ui/app/elements/settings/gr-watched-projects-editor/gr-watched-projects-editor_test.html
index 59e87b0..1e6ed7a 100644
--- a/polygerrit-ui/app/elements/settings/gr-watched-projects-editor/gr-watched-projects-editor_test.html
+++ b/polygerrit-ui/app/elements/settings/gr-watched-projects-editor/gr-watched-projects-editor_test.html
@@ -33,11 +33,12 @@
 </test-fixture>
 
 <script>
-  suite('gr-watched-projects-editor tests', function() {
-    var element;
+  suite('gr-watched-projects-editor tests', () => {
+    let element;
 
-    setup(function(done) {
-      var projects = [{
+    setup(done => {
+      const projects = [
+        {
           project: 'project a',
           notify_submitted_changes: true,
           notify_abandoned_changes: true,
@@ -57,8 +58,8 @@
       ];
 
       stub('gr-rest-api-interface', {
-        getSuggestedProjects: function(input) {
-          if (input.indexOf('the') === 0) {
+        getSuggestedProjects(input) {
+          if (input.startsWith('the')) {
             return Promise.resolve({'the project': {
               id: 'the project',
               state: 'ACTIVE',
@@ -68,27 +69,27 @@
             return Promise.resolve({});
           }
         },
-        getWatchedProjects: function() {
+        getWatchedProjects() {
           return Promise.resolve(projects);
         },
       });
 
       element = fixture('basic');
 
-      element.loadData().then(function() { flush(done); });
+      element.loadData().then(() => { flush(done); });
     });
 
-    test('renders', function() {
-      var rows = element.$$('table').querySelectorAll('tbody tr');
+    test('renders', () => {
+      const rows = element.$$('table').querySelectorAll('tbody tr');
       assert.equal(rows.length, 4);
 
       function getKeysOfRow(row) {
-        var boxes = rows[row].querySelectorAll('input[checked]');
+        const boxes = rows[row].querySelectorAll('input[checked]');
         return Array.prototype.map.call(boxes,
-            function(e) { return e.getAttribute('data-key'); });
+            e => { return e.getAttribute('data-key'); });
       }
 
-      var checkedKeys = getKeysOfRow(0);
+      let checkedKeys = getKeysOfRow(0);
       assert.equal(checkedKeys.length, 2);
       assert.equal(checkedKeys[0], 'notify_submitted_changes');
       assert.equal(checkedKeys[1], 'notify_abandoned_changes');
@@ -107,22 +108,22 @@
       assert.equal(checkedKeys[2], 'notify_all_comments');
     });
 
-    test('_getProjectSuggestions empty', function(done) {
-      element._getProjectSuggestions('nonexistent').then(function(projects) {
+    test('_getProjectSuggestions empty', done => {
+      element._getProjectSuggestions('nonexistent').then(projects => {
         assert.equal(projects.length, 0);
         done();
       });
     });
 
-    test('_getProjectSuggestions non-empty', function(done) {
-      element._getProjectSuggestions('the project').then(function(projects) {
+    test('_getProjectSuggestions non-empty', done => {
+      element._getProjectSuggestions('the project').then(projects => {
         assert.equal(projects.length, 1);
         assert.equal(projects[0].name, 'the project');
         done();
       });
     });
 
-    test('_canAddProject', function() {
+    test('_canAddProject', () => {
       assert.isFalse(element._canAddProject(null, null));
       assert.isFalse(element._canAddProject({}, null));
 
@@ -144,7 +145,7 @@
       assert.isTrue(element._canAddProject({id: 'project b'}, 'filter 3'));
     });
 
-    test('_getNewProjectIndex', function() {
+    test('_getNewProjectIndex', () => {
       // Projects are sorted in ASCII order.
       assert.equal(element._getNewProjectIndex('project A', 'filter'), 0);
       assert.equal(element._getNewProjectIndex('project a', 'filter'), 1);
@@ -158,7 +159,7 @@
       assert.equal(element._getNewProjectIndex('project c', 'filter'), 4);
     });
 
-    test('_handleAddProject', function() {
+    test('_handleAddProject', () => {
       element.$.newProject.value = {id: 'project d'};
       element.$.newProject.setText('project d');
       element.$.newFilter.bindValue = '';
@@ -171,7 +172,7 @@
       assert.isTrue(element._projects[4]._is_local);
     });
 
-    test('_handleAddProject with invalid inputs', function() {
+    test('_handleAddProject with invalid inputs', () => {
       element.$.newProject.value = {id: 'project b'};
       element.$.newProject.setText('project b');
       element.$.newFilter.bindValue = 'filter 1';
@@ -181,14 +182,14 @@
       assert.equal(element._projects.length, 4);
     });
 
-    test('_handleRemoveProject', function() {
+    test('_handleRemoveProject', () => {
       assert.equal(element._projectsToRemove, 0);
-      var button = element.$$('table tbody tr:nth-child(2) gr-button');
+      const button = element.$$('table tbody tr:nth-child(2) gr-button');
       MockInteractions.tap(button);
 
       flushAsynchronousOperations();
 
-      var rows = element.$$('table tbody').querySelectorAll('tr');
+      const rows = element.$$('table tbody').querySelectorAll('tr');
       assert.equal(rows.length, 3);
 
       assert.equal(element._projectsToRemove.length, 1);
diff --git a/polygerrit-ui/app/elements/shared/gr-account-chip/gr-account-chip.js b/polygerrit-ui/app/elements/shared/gr-account-chip/gr-account-chip.js
index 33fc50e..c4650f3e 100644
--- a/polygerrit-ui/app/elements/shared/gr-account-chip/gr-account-chip.js
+++ b/polygerrit-ui/app/elements/shared/gr-account-chip/gr-account-chip.js
@@ -47,23 +47,23 @@
       },
     },
 
-    ready: function() {
-      this._getHasAvatars().then(function(hasAvatars) {
+    ready() {
+      this._getHasAvatars().then(hasAvatars => {
         this.showAvatar = hasAvatars;
-      }.bind(this));
+      });
     },
 
-    _getBackgroundClass: function(transparent) {
+    _getBackgroundClass(transparent) {
       return transparent ? 'transparentBackground' : '';
     },
 
-    _handleRemoveTap: function(e) {
+    _handleRemoveTap(e) {
       e.preventDefault();
       this.fire('remove', {account: this.account});
     },
 
-    _getHasAvatars: function() {
-      return this.$.restAPI.getConfig().then(function(cfg) {
+    _getHasAvatars() {
+      return this.$.restAPI.getConfig().then(cfg => {
         return Promise.resolve(!!(cfg && cfg.plugin && cfg.plugin.has_avatars));
       });
     },
diff --git a/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label.js b/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label.js
index e9f18df..9ebef82 100644
--- a/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label.js
+++ b/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label.js
@@ -29,9 +29,9 @@
       },
     },
 
-    _computeAccountTitle: function(account) {
+    _computeAccountTitle(account) {
       if (!account || (!account.name && !account.email)) { return; }
-      var result = '';
+      let result = '';
       if (account.name) {
         result += account.name;
       }
@@ -41,11 +41,11 @@
       return result;
     },
 
-    _computeShowEmail: function(showEmail, account) {
+    _computeShowEmail(showEmail, account) {
       return !!(showEmail && account && account.email);
     },
 
-    _computeEmailStr: function(account) {
+    _computeEmailStr(account) {
       if (!account || !account.email) {
         return '';
       }
diff --git a/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label_test.html b/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label_test.html
index de7d6a3..2c43879 100644
--- a/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label_test.html
@@ -33,32 +33,32 @@
 </test-fixture>
 
 <script>
-  suite('gr-account-label tests', function() {
-    var element;
+  suite('gr-account-label tests', () => {
+    let element;
 
-    setup(function() {
+    setup(() => {
       stub('gr-rest-api-interface', {
-        getConfig: function() { return Promise.resolve({}); },
-        getLoggedIn: function() { return Promise.resolve(false); },
+        getConfig() { return Promise.resolve({}); },
+        getLoggedIn() { return Promise.resolve(false); },
       });
       element = fixture('basic');
     });
 
-    test('null guard', function() {
-      assert.doesNotThrow(function() {
+    test('null guard', () => {
+      assert.doesNotThrow(() => {
         element.account = null;
       });
     });
 
-    test('missing email', function() {
+    test('missing email', () => {
       assert.equal('', element._computeEmailStr({name: 'foo'}));
     });
 
-    test('computed fields', function() {
+    test('computed fields', () => {
       assert.equal(element._computeAccountTitle(
           {
             name: 'Andrew Bonventre',
-            email: 'andybons+gerrit@gmail.com'
+            email: 'andybons+gerrit@gmail.com',
           }),
           'Andrew Bonventre <andybons+gerrit@gmail.com>');
 
@@ -69,7 +69,7 @@
       assert.equal(element._computeShowEmail(true,
           {
             name: 'Andrew Bonventre',
-            email: 'andybons+gerrit@gmail.com'
+            email: 'andybons+gerrit@gmail.com',
           }), true);
 
       assert.equal(element._computeShowEmail(true,
@@ -88,6 +88,5 @@
           element._computeEmailStr({name: 'test', email: 'test'}), '(test)');
       assert.equal(element._computeEmailStr({email: 'test'}, ''), 'test');
     });
-
   });
 </script>
diff --git a/polygerrit-ui/app/elements/shared/gr-account-link/gr-account-link.js b/polygerrit-ui/app/elements/shared/gr-account-link/gr-account-link.js
index 69beb78..b30a26c 100644
--- a/polygerrit-ui/app/elements/shared/gr-account-link/gr-account-link.js
+++ b/polygerrit-ui/app/elements/shared/gr-account-link/gr-account-link.js
@@ -29,13 +29,13 @@
       Gerrit.BaseUrlBehavior,
     ],
 
-    _computeOwnerLink: function(account) {
+    _computeOwnerLink(account) {
       if (!account) { return; }
-      var accountID = account.email || account._account_id;
+      const accountID = account.email || account._account_id;
       return this.getBaseUrl() + '/q/owner:' + encodeURIComponent(accountID);
     },
 
-    _computeShowEmail: function(account) {
+    _computeShowEmail(account) {
       return !!(account && !account.name);
     },
   });
diff --git a/polygerrit-ui/app/elements/shared/gr-account-link/gr-account-link_test.html b/polygerrit-ui/app/elements/shared/gr-account-link/gr-account-link_test.html
index 5cc0600..29d1580 100644
--- a/polygerrit-ui/app/elements/shared/gr-account-link/gr-account-link_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-account-link/gr-account-link_test.html
@@ -32,21 +32,21 @@
 </test-fixture>
 
 <script>
-  suite('gr-account-link tests', function() {
-    var element;
+  suite('gr-account-link tests', () => {
+    let element;
 
-    setup(function() {
+    setup(() => {
       stub('gr-rest-api-interface', {
-        getConfig: function() { return Promise.resolve({}); },
+        getConfig() { return Promise.resolve({}); },
       });
       element = fixture('basic');
     });
 
-    test('computed fields', function() {
+    test('computed fields', () => {
       assert.equal(element._computeOwnerLink(
           {
             _account_id: 123,
-            email: 'andybons+gerrit@gmail.com'
+            email: 'andybons+gerrit@gmail.com',
           }),
           '/q/owner:andybons%2Bgerrit%40gmail.com');
 
@@ -57,6 +57,5 @@
 
       assert.equal(element._computeShowEmail({}), true);
     });
-
   });
 </script>
diff --git a/polygerrit-ui/app/elements/shared/gr-alert/gr-alert.js b/polygerrit-ui/app/elements/shared/gr-alert/gr-alert.js
index a2daeb3..bfe7c25 100644
--- a/polygerrit-ui/app/elements/shared/gr-alert/gr-alert.js
+++ b/polygerrit-ui/app/elements/shared/gr-alert/gr-alert.js
@@ -41,21 +41,21 @@
       _hideActionButton: Boolean,
       _boundTransitionEndHandler: {
         type: Function,
-        value: function() { return this._handleTransitionEnd.bind(this); },
+        value() { return this._handleTransitionEnd.bind(this); },
       },
       _actionCallback: Function,
     },
 
-    attached: function() {
+    attached() {
       this.addEventListener('transitionend', this._boundTransitionEndHandler);
     },
 
-    detached: function() {
+    detached() {
       this.removeEventListener('transitionend',
           this._boundTransitionEndHandler);
     },
 
-    show: function(text, opt_actionText, opt_actionCallback) {
+    show(text, opt_actionText, opt_actionCallback) {
       this.text = text;
       this.actionText = opt_actionText;
       this._hideActionButton = !opt_actionText;
@@ -64,27 +64,27 @@
       this._setShown(true);
     },
 
-    hide: function() {
+    hide() {
       this._setShown(false);
       if (this._hasZeroTransitionDuration()) {
         Gerrit.getRootElement().removeChild(this);
       }
     },
 
-    _hasZeroTransitionDuration: function() {
-      var style = window.getComputedStyle(this);
+    _hasZeroTransitionDuration() {
+      const style = window.getComputedStyle(this);
       // transitionDuration is always given in seconds.
-      var duration = Math.round(parseFloat(style.transitionDuration) * 100);
+      const duration = Math.round(parseFloat(style.transitionDuration) * 100);
       return duration === 0;
     },
 
-    _handleTransitionEnd: function(e) {
+    _handleTransitionEnd(e) {
       if (this.shown) { return; }
 
       Gerrit.getRootElement().removeChild(this);
     },
 
-    _handleActionTap: function(e) {
+    _handleActionTap(e) {
       e.preventDefault();
       if (this._actionCallback) { this._actionCallback(); }
     },
diff --git a/polygerrit-ui/app/elements/shared/gr-alert/gr-alert_test.html b/polygerrit-ui/app/elements/shared/gr-alert/gr-alert_test.html
index be21edd..6bbfcfb 100644
--- a/polygerrit-ui/app/elements/shared/gr-alert/gr-alert_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-alert/gr-alert_test.html
@@ -25,20 +25,20 @@
 <link rel="import" href="gr-alert.html">
 
 <script>
-  suite('gr-alert tests', function() {
-    var element;
+  suite('gr-alert tests', () => {
+    let element;
 
-    setup(function() {
+    setup(() => {
       element = document.createElement('gr-alert');
     });
 
-    teardown(function() {
+    teardown(() => {
       if (element.parentNode) {
         element.parentNode.removeChild(element);
       }
     });
 
-    test('show/hide', function() {
+    test('show/hide', () => {
       assert.isNull(element.parentNode);
       element.show();
       assert.equal(element.parentNode, document.body);
@@ -48,11 +48,10 @@
       assert.isNull(element.parentNode);
     });
 
-    test('action event', function(done) {
+    test('action event', done => {
       element.show();
       element._actionCallback = done;
       MockInteractions.tap(element.$$('.action'));
     });
-
   });
 </script>
diff --git a/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete.html b/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete.html
index d19afb7..81379af 100644
--- a/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete.html
+++ b/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete.html
@@ -16,6 +16,7 @@
 <link rel="import" href="../../../bower_components/polymer/polymer.html">
 <link rel="import" href="../../../bower_components/iron-a11y-keys-behavior/iron-a11y-keys-behavior.html">
 <link rel="import" href="../../../bower_components/iron-input/iron-input.html">
+<link rel="import" href="../../shared/gr-autocomplete-dropdown/gr-autocomplete-dropdown.html">
 <link rel="import" href="../../shared/gr-cursor-manager/gr-cursor-manager.html">
 
 <dom-module id="gr-autocomplete">
@@ -31,25 +32,6 @@
         border: none;
         outline: none;
       }
-      #suggestions {
-        background-color: #fff;
-        box-shadow: 0 1px 3px rgba(0, 0, 0, .3);
-        position: absolute;
-        z-index: 10;
-      }
-      ul {
-        list-style: none;
-      }
-      li {
-        cursor: pointer;
-        padding: .5em .75em;
-      }
-      li:focus {
-        outline: none;
-      }
-      li.selected {
-        background-color: #eee;
-      }
     </style>
     <input
         id="input"
@@ -61,29 +43,13 @@
         on-keydown="_handleKeydown"
         on-focus="_onInputFocus"
         autocomplete="off" />
-    <div
-        id="suggestions"
+    <gr-autocomplete-dropdown id="suggestions"
+        on-item-selected="_handleItemSelect"
+        suggestions="[[_suggestions]]"
         role="listbox"
+        index="[[index]]"
         hidden$="[[_computeSuggestionsHidden(_suggestions, _focused)]]">
-      <ul>
-        <template is="dom-repeat" items="[[_suggestions]]">
-          <li
-              data-index$="[[index]]"
-              tabindex="-1"
-              aria-label$="[[item.name]]"
-              on-keydown="_handleKeydown"
-              role="option"
-              on-tap="_handleSuggestionTap">[[item.name]]</li>
-        </template>
-      </ul>
-    </div>
-    <gr-cursor-manager
-        id="cursor"
-        index="{{_index}}"
-        cursor-target-class="selected"
-        scroll-behavior="keep-visible"
-        focus-on-move
-        stops="[[_suggestionEls]]"></gr-cursor-manager>
+    </gr-autocomplete-dropdown>
   </template>
   <script src="gr-autocomplete.js"></script>
 </dom-module>
diff --git a/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete.js b/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete.js
index 9cf67b4..56a3c23 100644
--- a/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete.js
+++ b/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete.js
@@ -116,17 +116,15 @@
       },
 
       _index: Number,
-
       _disableSuggestions: {
         type: Boolean,
         value: false,
       },
-
       _focused: {
         type: Boolean,
         value: false,
       },
-
+      _selected: Object,
     },
 
     attached() {
@@ -153,6 +151,18 @@
       this.text = '';
     },
 
+    _handleItemSelect(e) {
+      let silent = false;
+      if (e.detail.trigger === 'tab' && this.tabCompleteWithoutCommit) {
+        silent = true;
+      }
+      this._selected = e.detail.selected;
+      this._commit(silent);
+      if (e.detail.trigger === 'tap') {
+        this.focus();
+      }
+    },
+
     /**
      * Set the text of the input without triggering the suggestion dropdown.
      * @param {String} text The new text for the input.
@@ -182,10 +192,11 @@
           // Late response.
           return;
         }
+        for (const suggestion of suggestions) {
+          suggestion.text = suggestion.name;
+        }
         this._suggestions = suggestions;
         Polymer.dom.flush();
-        this._suggestionEls = this.$.suggestions.querySelectorAll('li');
-        this.$.cursor.moveToStart();
         if (this._index === -1) {
           this.value = null;
         }
@@ -209,11 +220,11 @@
       switch (e.keyCode) {
         case 38: // Up
           e.preventDefault();
-          this.$.cursor.previous();
+          this.$.suggestions.cursorUp();
           break;
         case 40: // Down
           e.preventDefault();
-          this.$.cursor.next();
+          this.$.suggestions.cursorDown();
           break;
         case 27: // Escape
           e.preventDefault();
@@ -222,12 +233,12 @@
         case 9: // Tab
           if (this._suggestions.length > 0) {
             e.preventDefault();
-            this._commit(this.tabCompleteWithoutCommit);
+            this._handleEnter(this.tabCompleteWithoutCommit);
           }
           break;
         case 13: // Enter
           e.preventDefault();
-          this._commit();
+          this._handleEnter();
           break;
         default:
           // For any normal keypress, return focus to the input to allow for
@@ -245,9 +256,15 @@
       }
     },
 
-    _updateValue(suggestions, index) {
-      if (!suggestions.length || index === -1) { return; }
-      const completed = suggestions[index].value;
+    _handleEnter(opt_tabCompleteWithoutCommit) {
+      this._selected = this.$.suggestions.getCursorTarget();
+      this._commit(opt_tabCompleteWithoutCommit);
+      this.focus();
+    },
+
+    _updateValue(suggestion, suggestions) {
+      if (!suggestion) { return; }
+      const completed = suggestions[suggestion.dataset.index].value;
       if (this.multi) {
         // Append the completed text to the end of the string.
         // Allow spaces within quoted terms.
@@ -286,7 +303,7 @@
     _commit(silent) {
       // Allow values that are not in suggestion list iff suggestions are empty.
       if (this._suggestions.length > 0) {
-        this._updateValue(this._suggestions, this._index);
+        this._updateValue(this._selected, this._suggestions);
       } else {
         this.value = this.text || '';
       }
@@ -297,8 +314,8 @@
       if (this.multi) {
         this.setText(this.value);
       } else {
-        if (!this.clearOnCommit && this._suggestions[this._index]) {
-          this.setText(this._suggestions[this._index].name);
+        if (!this.clearOnCommit && this._selected) {
+          this.setText(this._suggestions[this._selected.dataset.index].name);
         } else {
           this.clear();
         }
diff --git a/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete_test.html b/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete_test.html
index 6a3ae81..62d4079 100644
--- a/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete_test.html
@@ -58,9 +58,8 @@
         ]);
       });
       element.query = queryStub;
-
-      assert.isTrue(element.$.suggestions.hasAttribute('hidden'));
-      assert.equal(element.$.cursor.index, -1);
+      assert.isTrue(element.$.suggestions.hidden);
+      assert.equal(element.$.suggestions.$.cursor.index, -1);
 
       element.text = 'blah';
 
@@ -69,15 +68,15 @@
 
       promise.then(() => {
         assert.isFalse(element.$.suggestions.hasAttribute('hidden'));
-
-        const suggestions = element.$.suggestions.querySelectorAll('li');
+        const suggestions =
+            Polymer.dom(element.$.suggestions.root).querySelectorAll('li');
         assert.equal(suggestions.length, 5);
 
         for (let i = 0; i < 5; i++) {
           assert.equal(suggestions[i].textContent, 'blah ' + i);
         }
 
-        assert.notEqual(element.$.cursor.index, -1);
+        assert.notEqual(element.$.suggestions.$.cursor.index, -1);
         done();
       });
     });
@@ -91,20 +90,20 @@
       });
       element.query = queryStub;
 
-      assert.isTrue(element.$.suggestions.hasAttribute('hidden'));
+      assert.isTrue(element.$.suggestions.hidden);
 
       element._focused = true;
       element.text = 'blah';
 
       promise.then(() => {
-        assert.isFalse(element.$.suggestions.hasAttribute('hidden'));
+        assert.isFalse(element.$.suggestions.hidden);
 
         const cancelHandler = sandbox.spy();
         element.addEventListener('cancel', cancelHandler);
 
         MockInteractions.pressAndReleaseKeyOn(element.$.input, 27, null, 'esc');
         assert.isFalse(cancelHandler.called);
-        assert.isTrue(element.$.suggestions.hasAttribute('hidden'));
+        assert.isTrue(element.$.suggestions.hidden);
         assert.equal(element._suggestions.length, 0);
 
         MockInteractions.pressAndReleaseKeyOn(element.$.input, 27, null, 'esc');
@@ -126,32 +125,32 @@
       });
       element.query = queryStub;
 
-      assert.isTrue(element.$.suggestions.hasAttribute('hidden'));
-      assert.equal(element.$.cursor.index, -1);
+      assert.isTrue(element.$.suggestions.hidden);
+      assert.equal(element.$.suggestions.$.cursor.index, -1);
       element._focused = true;
       element.text = 'blah';
 
       promise.then(() => {
-        assert.isFalse(element.$.suggestions.hasAttribute('hidden'));
+        assert.isFalse(element.$.suggestions.hidden);
 
         const commitHandler = sandbox.spy();
         element.addEventListener('commit', commitHandler);
 
-        assert.equal(element.$.cursor.index, 0);
+        assert.equal(element.$.suggestions.$.cursor.index, 0);
 
         MockInteractions.pressAndReleaseKeyOn(element.$.input, 40, null,
             'down');
 
-        assert.equal(element.$.cursor.index, 1);
+        assert.equal(element.$.suggestions.$.cursor.index, 1);
 
         MockInteractions.pressAndReleaseKeyOn(element.$.input, 40, null,
             'down');
 
-        assert.equal(element.$.cursor.index, 2);
+        assert.equal(element.$.suggestions.$.cursor.index, 2);
 
         MockInteractions.pressAndReleaseKeyOn(element.$.input, 38, null, 'up');
 
-        assert.equal(element.$.cursor.index, 1);
+        assert.equal(element.$.suggestions.$.cursor.index, 1);
 
         MockInteractions.pressAndReleaseKeyOn(element.$.input, 13, null,
             'enter');
@@ -159,7 +158,7 @@
         assert.equal(element.value, 1);
         assert.isTrue(commitHandler.called);
         assert.equal(commitHandler.getCall(0).args[0].detail.value, 1);
-        assert.isTrue(element.$.suggestions.hasAttribute('hidden'));
+        assert.isTrue(element.$.suggestions.hidden);
 
         done();
       });
@@ -304,12 +303,12 @@
       element._focused = true;
       element._suggestions = [{name: 'first suggestion'}];
       Polymer.dom.flush();
-      assert.isFalse(element.$.suggestions.hasAttribute('hidden'));
-      MockInteractions.tap(element.$$('#suggestions li:first-child'));
+      assert.isFalse(element.$.suggestions.hidden);
+      MockInteractions.tap(element.$.suggestions.$$('li:first-child'));
       flushAsynchronousOperations();
       assert.isTrue(focusSpy.called);
       assert.isTrue(commitSpy.called);
-      assert.isTrue(element.$.suggestions.hasAttribute('hidden'));
+      assert.isTrue(element.$.suggestions.hidden);
       assert.isTrue(element._focused);
     });
 
diff --git a/polygerrit-ui/app/elements/shared/gr-avatar/gr-avatar.js b/polygerrit-ui/app/elements/shared/gr-avatar/gr-avatar.js
index 38e9924..166204bf 100644
--- a/polygerrit-ui/app/elements/shared/gr-avatar/gr-avatar.js
+++ b/polygerrit-ui/app/elements/shared/gr-avatar/gr-avatar.js
@@ -28,38 +28,38 @@
       },
     },
 
-    created: function() {
+    created() {
       this.hidden = true;
     },
 
-    attached: function() {
-      this.$.restAPI.getConfig().then(function(cfg) {
-        var hasAvatars = !!(cfg && cfg.plugin && cfg.plugin.has_avatars);
+    attached() {
+      this.$.restAPI.getConfig().then(cfg => {
+        const hasAvatars = !!(cfg && cfg.plugin && cfg.plugin.has_avatars);
         if (hasAvatars) {
           this.hidden = false;
           // src needs to be set if avatar becomes visible
           this._updateAvatarURL(this.account);
         }
-      }.bind(this));
+      });
     },
 
-    _accountChanged: function(account) {
+    _accountChanged(account) {
       this._updateAvatarURL(account);
     },
 
-    _updateAvatarURL: function(account) {
+    _updateAvatarURL(account) {
       if (!this.hidden && account) {
-        var url = this._buildAvatarURL(this.account);
+        const url = this._buildAvatarURL(this.account);
         if (url) {
           this.style.backgroundImage = 'url("' + url + '")';
         }
       }
     },
 
-    _buildAvatarURL: function(account) {
+    _buildAvatarURL(account) {
       if (!account) { return ''; }
-      var avatars = account.avatars || [];
-      for (var i = 0; i < avatars.length; i++) {
+      const avatars = account.avatars || [];
+      for (let i = 0; i < avatars.length; i++) {
         if (avatars[i].height === this.imageSize) {
           return avatars[i].url;
         }
diff --git a/polygerrit-ui/app/elements/shared/gr-avatar/gr-avatar_test.html b/polygerrit-ui/app/elements/shared/gr-avatar/gr-avatar_test.html
index fd05d62..0a1ac67 100644
--- a/polygerrit-ui/app/elements/shared/gr-avatar/gr-avatar_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-avatar/gr-avatar_test.html
@@ -32,20 +32,20 @@
 </test-fixture>
 
 <script>
-  suite('gr-avatar tests', function() {
-    var element;
+  suite('gr-avatar tests', () => {
+    let element;
 
-    setup(function() {
+    setup(() => {
       stub('gr-rest-api-interface', {
-        getConfig: function() { return Promise.resolve({}); },
+        getConfig() { return Promise.resolve({}); },
       });
       element = fixture('basic');
     });
 
-    test('methods', function() {
+    test('methods', () => {
       assert.equal(element._buildAvatarURL(
           {
-            _account_id: 123
+            _account_id: 123,
           }),
           '/accounts/123/avatar?s=16');
       assert.equal(element._buildAvatarURL(
@@ -54,15 +54,15 @@
             avatars: [
               {
                 url: 'https://cdn.example.com/s12-p/photo.jpg',
-                height: 12
+                height: 12,
               },
               {
                 url: 'https://cdn.example.com/s16-p/photo.jpg',
-                height: 16
+                height: 16,
               },
               {
                 url: 'https://cdn.example.com/s100-p/photo.jpg',
-                height: 100
+                height: 100,
               },
             ],
           }),
@@ -73,32 +73,31 @@
             avatars: [
               {
                 url: 'https://cdn.example.com/s95-p/photo.jpg',
-                height: 95
+                height: 95,
               },
             ],
           }),
           '/accounts/123/avatar?s=16');
     });
 
-    test('dom for existing account', function() {
+    test('dom for existing account', () => {
       assert.isTrue(element.hasAttribute('hidden'),
           'element not hidden initially');
       element.hidden = false;
       element.imageSize = 64;
       element.account = {
-        _account_id: 123
+        _account_id: 123,
       };
       assert.isFalse(element.hasAttribute('hidden'), 'element hidden');
-      assert.isTrue(element.style.backgroundImage.indexOf(
-          '/accounts/123/avatar?s=64') > -1);
+      assert.isTrue(
+          element.style.backgroundImage.includes('/accounts/123/avatar?s=64'));
     });
 
-    test('dom for non available account', function() {
+    test('dom for non available account', () => {
       assert.isTrue(element.hasAttribute('hidden'),
           'element not hidden initially');
       element.account = undefined;
       assert.isTrue(element.hasAttribute('hidden'), 'element not hidden');
     });
-
   });
 </script>
diff --git a/polygerrit-ui/app/elements/shared/gr-button/gr-button.js b/polygerrit-ui/app/elements/shared/gr-button/gr-button.js
index 800b1df..ddb2bc3 100644
--- a/polygerrit-ui/app/elements/shared/gr-button/gr-button.js
+++ b/polygerrit-ui/app/elements/shared/gr-button/gr-button.js
@@ -34,8 +34,8 @@
     },
 
     listeners: {
-      'tap': '_handleAction',
-      'click': '_handleAction',
+      tap: '_handleAction',
+      click: '_handleAction',
     },
 
     behaviors: [
@@ -52,21 +52,21 @@
       'space enter': '_handleCommitKey',
     },
 
-    _handleAction: function(e) {
+    _handleAction(e) {
       if (this.disabled) {
         e.preventDefault();
         e.stopImmediatePropagation();
       }
     },
 
-    _disabledChanged: function(disabled) {
+    _disabledChanged(disabled) {
       if (disabled) {
         this._enabledTabindex = this.getAttribute('tabindex');
       }
       this.setAttribute('tabindex', disabled ? '-1' : this._enabledTabindex);
     },
 
-    _handleCommitKey: function(e) {
+    _handleCommitKey(e) {
       e.preventDefault();
       this.click();
     },
diff --git a/polygerrit-ui/app/elements/shared/gr-button/gr-button_test.html b/polygerrit-ui/app/elements/shared/gr-button/gr-button_test.html
index c269cb5..536b777 100644
--- a/polygerrit-ui/app/elements/shared/gr-button/gr-button_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-button/gr-button_test.html
@@ -33,63 +33,65 @@
 </test-fixture>
 
 <script>
-  suite('gr-select tests', function() {
-    var element;
-    var sandbox;
+  suite('gr-select tests', () => {
+    let element;
+    let sandbox;
 
-    var addSpyOn = function(eventName) {
-      var spy = sandbox.spy();
+    const addSpyOn = function(eventName) {
+      const spy = sandbox.spy();
       element.addEventListener(eventName, spy);
       return spy;
     };
 
-    setup(function() {
+    setup(() => {
       element = fixture('basic');
       sandbox = sinon.sandbox.create();
     });
 
-    teardown(function() {
+    teardown(() => {
       sandbox.restore();
     });
 
-    ['tap', 'click'].forEach(function(eventName) {
-      test('dispatches ' + eventName + ' event', function() {
-        var spy = addSpyOn(eventName);
+    for (const eventName of ['tap', 'click']) {
+      test('dispatches ' + eventName + ' event', () => {
+        const spy = addSpyOn(eventName);
         MockInteractions.tap(element);
         assert.isTrue(spy.calledOnce);
       });
-    });
+    }
 
     // Keycodes: 32 for Space, 13 for Enter.
-    [32, 13].forEach(function(key) {
-      test('dispatches tap event on keycode ' + key, function() {
-        var tapSpy = sandbox.spy();
+    for (const key of [32, 13]) {
+      test('dispatches tap event on keycode ' + key, () => {
+        const tapSpy = sandbox.spy();
         element.addEventListener('tap', tapSpy);
         MockInteractions.pressAndReleaseKeyOn(element, key);
         assert.isTrue(tapSpy.calledOnce);
-      })});
+      });
+    }
 
-    suite('disabled', function() {
-      setup(function() {
+    suite('disabled', () => {
+      setup(() => {
         element.disabled = true;
       });
 
-      ['tap', 'click'].forEach(function(eventName) {
-        test('stops ' + eventName + ' event', function() {
-          var spy = addSpyOn(eventName);
+      for (const eventName of ['tap', 'click']) {
+        test('stops ' + eventName + ' event', () => {
+          const spy = addSpyOn(eventName);
           MockInteractions.tap(element);
           assert.isFalse(spy.called);
         });
-      });
+      }
 
       // Keycodes: 32 for Space, 13 for Enter.
-      [32, 13].forEach(function(key) {
-        test('stops tap event on keycode ' + key, function() {
-          var tapSpy = sandbox.spy();
+      for (const key of [32, 13]) {
+        test('stops tap event on keycode ' + key, () => {
+          const tapSpy = sandbox.spy();
           element.addEventListener('tap', tapSpy);
           MockInteractions.pressAndReleaseKeyOn(element, key);
           assert.isFalse(tapSpy.called);
-        })});
+        });
+      }
     });
   });
 </script>
diff --git a/polygerrit-ui/app/elements/shared/gr-change-star/gr-change-star.js b/polygerrit-ui/app/elements/shared/gr-change-star/gr-change-star.js
index beb0ff1..0e5ff04 100644
--- a/polygerrit-ui/app/elements/shared/gr-change-star/gr-change-star.js
+++ b/polygerrit-ui/app/elements/shared/gr-change-star/gr-change-star.js
@@ -26,16 +26,16 @@
       _xhrPromise: Object,  // Used for testing.
     },
 
-    _computeStarClass: function(starred) {
-      var classes = ['starButton'];
+    _computeStarClass(starred) {
+      const classes = ['starButton'];
       if (starred) {
         classes.push('starButton-active');
       }
       return classes.join(' ');
     },
 
-    toggleStar: function() {
-      var newVal = !this.change.starred;
+    toggleStar() {
+      const newVal = !this.change.starred;
       this.set('change.starred', newVal);
       this._xhrPromise = this.$.restAPI.saveChangeStarred(this.change._number,
           newVal);
diff --git a/polygerrit-ui/app/elements/shared/gr-change-star/gr-change-star_test.html b/polygerrit-ui/app/elements/shared/gr-change-star/gr-change-star_test.html
index 460d860..6286efe 100644
--- a/polygerrit-ui/app/elements/shared/gr-change-star/gr-change-star_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-change-star/gr-change-star_test.html
@@ -33,12 +33,12 @@
 </test-fixture>
 
 <script>
-  suite('gr-change-star tests', function() {
-    var element;
+  suite('gr-change-star tests', () => {
+    let element;
 
-    setup(function() {
+    setup(() => {
       stub('gr-rest-api-interface', {
-        saveChangeStarred: function() { return Promise.resolve({ok: true}); },
+        saveChangeStarred() { return Promise.resolve({ok: true}); },
       });
       element = fixture('basic');
       element.change = {
@@ -47,7 +47,7 @@
       };
     });
 
-    test('star visibility states', function() {
+    test('star visibility states', () => {
       element.set('change.starred', true);
       assert.isTrue(element.$$('button').classList.contains('starButton'));
       assert.isTrue(
@@ -59,21 +59,21 @@
           element.$$('button').classList.contains('starButton-active'));
     });
 
-    test('starring', function(done) {
+    test('starring', done => {
       element.set('change.starred', false);
       MockInteractions.tap(element.$$('button'));
 
-      element._xhrPromise.then(function(req) {
+      element._xhrPromise.then(req => {
         assert.equal(element.change.starred, true);
         done();
       });
     });
 
-    test('unstarring', function(done) {
+    test('unstarring', done => {
       element.set('change.starred', true);
       MockInteractions.tap(element.$$('button'));
 
-      element._xhrPromise.then(function(req) {
+      element._xhrPromise.then(req => {
         assert.equal(element.change.starred, false);
         done();
       });
diff --git a/polygerrit-ui/app/elements/shared/gr-confirm-dialog/gr-confirm-dialog.js b/polygerrit-ui/app/elements/shared/gr-confirm-dialog/gr-confirm-dialog.js
index dbddb04..3d5e781 100644
--- a/polygerrit-ui/app/elements/shared/gr-confirm-dialog/gr-confirm-dialog.js
+++ b/polygerrit-ui/app/elements/shared/gr-confirm-dialog/gr-confirm-dialog.js
@@ -44,12 +44,12 @@
       role: 'dialog',
     },
 
-    _handleConfirmTap: function(e) {
+    _handleConfirmTap(e) {
       e.preventDefault();
       this.fire('confirm', null, {bubbles: false});
     },
 
-    _handleCancelTap: function(e) {
+    _handleCancelTap(e) {
       e.preventDefault();
       this.fire('cancel', null, {bubbles: false});
     },
diff --git a/polygerrit-ui/app/elements/shared/gr-confirm-dialog/gr-confirm-dialog_test.html b/polygerrit-ui/app/elements/shared/gr-confirm-dialog/gr-confirm-dialog_test.html
index 3eec979..cb5d688 100644
--- a/polygerrit-ui/app/elements/shared/gr-confirm-dialog/gr-confirm-dialog_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-confirm-dialog/gr-confirm-dialog_test.html
@@ -33,15 +33,15 @@
 </test-fixture>
 
 <script>
-  suite('gr-confirm-dialog tests', function() {
-    var element;
+  suite('gr-confirm-dialog tests', () => {
+    let element;
 
-    setup(function() {
+    setup(() => {
       element = fixture('basic');
     });
 
-    test('events', function(done) {
-      var numEvents = 0;
+    test('events', done => {
+      let numEvents = 0;
       function handler() { if (++numEvents == 2) { done(); } }
 
       element.addEventListener('confirm', handler);
@@ -50,6 +50,5 @@
       MockInteractions.tap(element.$$('gr-button[primary]'));
       MockInteractions.tap(element.$$('gr-button:not([primary])'));
     });
-
   });
 </script>
diff --git a/polygerrit-ui/app/elements/shared/gr-date-formatter/gr-date-formatter.js b/polygerrit-ui/app/elements/shared/gr-date-formatter/gr-date-formatter.js
index 6f4cd3d..65a4c68 100644
--- a/polygerrit-ui/app/elements/shared/gr-date-formatter/gr-date-formatter.js
+++ b/polygerrit-ui/app/elements/shared/gr-date-formatter/gr-date-formatter.js
@@ -14,12 +14,12 @@
 (function() {
   'use strict';
 
-  var Duration = {
+  const Duration = {
     HOUR: 1000 * 60 * 60,
     DAY: 1000 * 60 * 60 * 24,
   };
 
-  var TimeFormats = {
+  const TimeFormats = {
     TIME_12: 'h:mm A', // 2:14 PM
     TIME_12_WITH_SEC: 'h:mm:ss A', // 2:14:00 PM
     TIME_24: 'HH:mm', // 14:14
@@ -61,16 +61,16 @@
       Gerrit.TooltipBehavior,
     ],
 
-    attached: function() {
+    attached() {
       this._loadPreferences();
     },
 
-    _getUtcOffsetString: function() {
+    _getUtcOffsetString() {
       return ' UTC' + moment().format('Z');
     },
 
-    _loadPreferences: function() {
-      return this._getLoggedIn().then(function(loggedIn) {
+    _loadPreferences() {
+      return this._getLoggedIn().then(loggedIn => {
         if (!loggedIn) {
           this._timeFormat = TimeFormats.TIME_24;
           this._relative = false;
@@ -80,12 +80,12 @@
           this._loadTimeFormat(),
           this._loadRelative(),
         ]);
-      }.bind(this));
+      });
     },
 
-    _loadTimeFormat: function() {
-      return this._getPreferences().then(function(preferences) {
-        var timeFormat = preferences && preferences.time_format;
+    _loadTimeFormat() {
+      return this._getPreferences().then(preferences => {
+        const timeFormat = preferences && preferences.time_format;
         switch (timeFormat) {
           case 'HHMM_12':
             this._timeFormat = TimeFormats.TIME_12;
@@ -96,55 +96,55 @@
           default:
             throw Error('Invalid time format: ' + timeFormat);
         }
-      }.bind(this));
+      });
     },
 
-    _loadRelative: function() {
-      return this._getPreferences().then(function(prefs) {
+    _loadRelative() {
+      return this._getPreferences().then(prefs => {
         // prefs.relative_date_in_change_table is not set when false.
         this._relative = !!(prefs && prefs.relative_date_in_change_table);
-      }.bind(this));
+      });
     },
 
-    _getLoggedIn: function() {
+    _getLoggedIn() {
       return this.$.restAPI.getLoggedIn();
     },
 
-    _getPreferences: function() {
+    _getPreferences() {
       return this.$.restAPI.getPreferences();
     },
 
     /**
      * Return true if date is within 24 hours and on the same day.
      */
-    _isWithinDay: function(now, date) {
-      var diff = -date.diff(now);
+    _isWithinDay(now, date) {
+      const diff = -date.diff(now);
       return diff < Duration.DAY && date.day() === now.getDay();
     },
 
     /**
      * Returns true if date is from one to six months.
      */
-    _isWithinHalfYear: function(now, date) {
-      var diff = -date.diff(now);
+    _isWithinHalfYear(now, date) {
+      const diff = -date.diff(now);
       return (date.day() !== now.getDay() || diff >= Duration.DAY) &&
           diff < 180 * Duration.DAY;
     },
 
-    _computeDateStr: function(dateStr, timeFormat, relative) {
+    _computeDateStr(dateStr, timeFormat, relative) {
       if (!dateStr) { return ''; }
-      var date = moment(util.parseDate(dateStr));
+      const date = moment(util.parseDate(dateStr));
       if (!date.isValid()) { return ''; }
       if (relative) {
-        var dateFromNow = date.fromNow();
+        const dateFromNow = date.fromNow();
         if (dateFromNow === 'a few seconds ago') {
           return 'just now';
         } else {
           return dateFromNow;
         }
       }
-      var now = new Date();
-      var format = TimeFormats.MONTH_DAY_YEAR;
+      const now = new Date();
+      let format = TimeFormats.MONTH_DAY_YEAR;
       if (this._isWithinDay(now, date)) {
         format = timeFormat;
       } else if (this._isWithinHalfYear(now, date)) {
@@ -153,17 +153,17 @@
       return date.format(format);
     },
 
-    _timeToSecondsFormat: function(timeFormat) {
+    _timeToSecondsFormat(timeFormat) {
       return timeFormat === TimeFormats.TIME_12 ?
           TimeFormats.TIME_12_WITH_SEC :
           TimeFormats.TIME_24_WITH_SEC;
     },
 
-    _computeFullDateStr: function(dateStr, timeFormat) {
+    _computeFullDateStr(dateStr, timeFormat) {
       if (!dateStr) { return ''; }
-      var date = moment(util.parseDate(dateStr));
+      const date = moment(util.parseDate(dateStr));
       if (!date.isValid()) { return ''; }
-      var format = TimeFormats.MONTH_DAY_YEAR + ', ';
+      let format = TimeFormats.MONTH_DAY_YEAR + ', ';
       format += this._timeToSecondsFormat(timeFormat);
       return date.format(format) + this._getUtcOffsetString();
     },
diff --git a/polygerrit-ui/app/elements/shared/gr-date-formatter/gr-date-formatter_test.html b/polygerrit-ui/app/elements/shared/gr-date-formatter/gr-date-formatter_test.html
index 4c6dfdf..8a3ea3a 100644
--- a/polygerrit-ui/app/elements/shared/gr-date-formatter/gr-date-formatter_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-date-formatter/gr-date-formatter_test.html
@@ -33,15 +33,15 @@
 </test-fixture>
 
 <script>
-  suite('gr-date-formatter tests', function() {
-    var element;
-    var sandbox;
+  suite('gr-date-formatter tests', () => {
+    let element;
+    let sandbox;
 
-    setup(function() {
+    setup(() => {
       sandbox = sinon.sandbox.create();
     });
 
-    teardown(function() {
+    teardown(() => {
       sandbox.restore();
     });
 
@@ -49,7 +49,7 @@
      * Parse server-formatter date and normalize into current timezone.
      */
     function normalizedDate(dateStr) {
-      var d = util.parseDate(dateStr);
+      const d = util.parseDate(dateStr);
       d.setMinutes(d.getMinutes() + d.getTimezoneOffset());
       return d;
     }
@@ -60,8 +60,8 @@
           .toJSON().replace('T', ' ').slice(0, -1);
       sandbox.useFakeTimers(normalizedDate(nowStr).getTime());
       element.dateStr = dateStr;
-      flush(function() {
-        var span = element.$$('span');
+      flush(() => {
+        const span = element.$$('span');
         assert.equal(span.textContent.trim(), expected);
         assert.equal(element.title, expectedTooltip);
         done();
@@ -69,8 +69,8 @@
     }
 
     function stubRestAPI(preferences) {
-      var loggedInPromise = Promise.resolve(preferences !== null);
-      var preferencesPromise = Promise.resolve(preferences);
+      const loggedInPromise = Promise.resolve(preferences !== null);
+      const preferencesPromise = Promise.resolve(preferences);
       stub('gr-rest-api-interface', {
         getLoggedIn: sinon.stub().returns(loggedInPromise),
         getPreferences: sinon.stub().returns(preferencesPromise),
@@ -78,115 +78,115 @@
       return Promise.all([loggedInPromise, preferencesPromise]);
     }
 
-    suite('24 hours time format preference', function() {
-      setup(function() {
+    suite('24 hours time format preference', () => {
+      setup(() => {
         return stubRestAPI(
           {time_format: 'HHMM_24', relative_date_in_change_table: false}
-        ).then(function() {
+        ).then(() => {
           element = fixture('basic');
           sandbox.stub(element, '_getUtcOffsetString').returns('');
           return element._loadPreferences();
         });
       });
 
-      test('invalid dates are quietly rejected', function() {
+      test('invalid dates are quietly rejected', () => {
         assert.notOk((new Date('foo')).valueOf());
         assert.equal(element._computeDateStr('foo', 'h:mm A'), '');
       });
 
-      test('Within 24 hours on same day', function(done) {
+      test('Within 24 hours on same day', done => {
         testDates('2015-07-29 20:34:14.985000000',
             '2015-07-29 15:34:14.985000000',
             '15:34', 'Jul 29, 2015, 15:34:14', done);
       });
 
-      test('Within 24 hours on different days', function(done) {
+      test('Within 24 hours on different days', done => {
         testDates('2015-07-29 03:34:14.985000000',
             '2015-07-28 20:25:14.985000000',
             'Jul 28', 'Jul 28, 2015, 20:25:14', done);
       });
 
-      test('More than 24 hours but less than six months', function(done) {
+      test('More than 24 hours but less than six months', done => {
         testDates('2015-07-29 20:34:14.985000000',
             '2015-06-15 03:25:14.985000000',
             'Jun 15', 'Jun 15, 2015, 03:25:14', done);
       });
 
-      test('More than six months', function(done) {
+      test('More than six months', done => {
         testDates('2015-09-15 20:34:00.000000000',
             '2015-01-15 03:25:00.000000000',
             'Jan 15, 2015', 'Jan 15, 2015, 03:25:00', done);
       });
     });
 
-    suite('12 hours time format preference', function() {
-      setup(function() {
+    suite('12 hours time format preference', () => {
+      setup(() => {
         // relative_date_in_change_table is not set when false.
         return stubRestAPI(
           {time_format: 'HHMM_12'}
-        ).then(function() {
+        ).then(() => {
           element = fixture('basic');
           sandbox.stub(element, '_getUtcOffsetString').returns('');
           return element._loadPreferences();
         });
       });
 
-      test('Within 24 hours on same day', function(done) {
+      test('Within 24 hours on same day', done => {
         testDates('2015-07-29 20:34:14.985000000',
             '2015-07-29 15:34:14.985000000',
             '3:34 PM', 'Jul 29, 2015, 3:34:14 PM', done);
       });
     });
 
-    suite('relative date preference', function() {
-      setup(function() {
+    suite('relative date preference', () => {
+      setup(() => {
         return stubRestAPI(
           {time_format: 'HHMM_12', relative_date_in_change_table: true}
-        ).then(function() {
+        ).then(() => {
           element = fixture('basic');
           sandbox.stub(element, '_getUtcOffsetString').returns('');
           return element._loadPreferences();
         });
       });
 
-      test('Within 24 hours on same day', function(done) {
+      test('Within 24 hours on same day', done => {
         testDates('2015-07-29 20:34:14.985000000',
             '2015-07-29 15:34:14.985000000',
             '5 hours ago', 'Jul 29, 2015, 3:34:14 PM', done);
       });
 
-      test('More than six months', function(done) {
+      test('More than six months', done => {
         testDates('2015-09-15 20:34:00.000000000',
             '2015-01-15 03:25:00.000000000',
             '8 months ago', 'Jan 15, 2015, 3:25:00 AM', done);
       });
     });
 
-    suite('logged in', function() {
-      setup(function() {
+    suite('logged in', () => {
+      setup(() => {
         return stubRestAPI(
           {time_format: 'HHMM_12', relative_date_in_change_table: true}
-        ).then(function() {
+        ).then(() => {
           element = fixture('basic');
           return element._loadPreferences();
         });
       });
 
-      test('Preferences are respected', function() {
+      test('Preferences are respected', () => {
         assert.equal(element._timeFormat, 'h:mm A');
         assert.isTrue(element._relative);
       });
     });
 
-    suite('logged out', function() {
-      setup(function() {
-        return stubRestAPI(null).then(function() {
+    suite('logged out', () => {
+      setup(() => {
+        return stubRestAPI(null).then(() => {
           element = fixture('basic');
           return element._loadPreferences();
         });
       });
 
-      test('Default preferences are respected', function() {
+      test('Default preferences are respected', () => {
         assert.equal(element._timeFormat, 'HH:mm');
         assert.isFalse(element._relative);
       });
diff --git a/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown.js b/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown.js
index 5a40e6f..42ae98b 100644
--- a/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown.js
+++ b/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown.js
@@ -56,7 +56,7 @@
        */
       disabledIds: {
         type: Array,
-        value: function() { return []; },
+        value() { return []; },
       },
 
       _hasAvatars: String,
@@ -66,54 +66,54 @@
       Gerrit.BaseUrlBehavior,
     ],
 
-    attached: function() {
-      this.$.restAPI.getConfig().then(function(cfg) {
+    attached() {
+      this.$.restAPI.getConfig().then(cfg => {
         this._hasAvatars = !!(cfg && cfg.plugin && cfg.plugin.has_avatars);
-      }.bind(this));
+      });
     },
 
-    _handleDropdownTap: function(e) {
+    _handleDropdownTap(e) {
       // async is needed so that that the click event is fired before the
       // dropdown closes (This was a bug for touch devices).
-      this.async(function() {
+      this.async(() => {
         this.$.dropdown.close();
       }, 1);
     },
 
-    _showDropdownTapHandler: function(e) {
+    _showDropdownTapHandler(e) {
       this.$.dropdown.open();
     },
 
-    _getClassIfBold: function(bold) {
+    _getClassIfBold(bold) {
       return bold ? 'bold-text' : '';
     },
 
-    _computeURLHelper: function(host, path) {
+    _computeURLHelper(host, path) {
       return '//' + host + this.getBaseUrl() + path;
     },
 
-    _computeRelativeURL: function(path) {
-      var host = window.location.host;
+    _computeRelativeURL(path) {
+      const host = window.location.host;
       return this._computeURLHelper(host, path);
     },
 
-    _computeLinkURL: function(link) {
+    _computeLinkURL(link) {
       if (link.target) {
         return link.url;
       }
       return this._computeRelativeURL(link.url);
     },
 
-    _computeLinkRel: function(link) {
+    _computeLinkRel(link) {
       return link.target ? 'noopener' : null;
     },
 
-    _handleItemTap: function(e) {
-      var id = e.target.getAttribute('data-id');
-      var item = this.items.find(function(item) {
+    _handleItemTap(e) {
+      const id = e.target.getAttribute('data-id');
+      const item = this.items.find(item => {
         return item.id === id;
       });
-      if (id && this.disabledIds.indexOf(id) === -1) {
+      if (id && !this.disabledIds.includes(id)) {
         if (item) {
           this.dispatchEvent(new CustomEvent('tap-item', {detail: item}));
         }
@@ -121,8 +121,8 @@
       }
     },
 
-    _computeDisabledClass: function(id, disabledIdsRecord) {
-      return disabledIdsRecord.base.indexOf(id) === -1 ? '' : 'disabled';
+    _computeDisabledClass(id, disabledIdsRecord) {
+      return disabledIdsRecord.base.includes(id) ? 'disabled' : '';
     },
   });
 })();
diff --git a/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown_test.html b/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown_test.html
index 5b2d0486..1815cca 100644
--- a/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown_test.html
@@ -33,30 +33,30 @@
 </test-fixture>
 
 <script>
-  suite('gr-dropdown tests', function() {
-    var element;
+  suite('gr-dropdown tests', () => {
+    let element;
 
-    setup(function() {
+    setup(() => {
       stub('gr-rest-api-interface', {
-        getConfig: function() { return Promise.resolve({}); },
+        getConfig() { return Promise.resolve({}); },
       });
       element = fixture('basic');
     });
 
-    test('tap on trigger opens menu', function() {
+    test('tap on trigger opens menu', () => {
       assert.isFalse(element.$.dropdown.opened);
       MockInteractions.tap(element.$.trigger);
       assert.isTrue(element.$.dropdown.opened);
     });
 
-    test('_computeURLHelper', function() {
-      var path = '/test';
-      var host = 'http://www.testsite.com';
-      var computedPath = element._computeURLHelper(host, path);
+    test('_computeURLHelper', () => {
+      const path = '/test';
+      const host = 'http://www.testsite.com';
+      const computedPath = element._computeURLHelper(host, path);
       assert.equal(computedPath, '//http://www.testsite.com/test');
     });
 
-    test('link URLs', function() {
+    test('link URLs', () => {
       assert.equal(
           element._computeLinkURL({url: '/test'}),
           '//' + window.location.host + '/test');
@@ -65,35 +65,35 @@
           '/test');
     });
 
-    test('link rel', function() {
+    test('link rel', () => {
       assert.isNull(element._computeLinkRel({url: '/test'}));
       assert.equal(
           element._computeLinkRel({url: '/test', target: '_blank'}),
           'noopener');
     });
 
-    test('_getClassIfBold', function() {
-      var bold = true;
+    test('_getClassIfBold', () => {
+      let bold = true;
       assert.equal(element._getClassIfBold(bold), 'bold-text');
 
       bold = false;
       assert.equal(element._getClassIfBold(bold), '');
     });
 
-    test('Top text exists and is bolded correctly', function() {
+    test('Top text exists and is bolded correctly', () => {
       element.topContent = [{text: 'User', bold: true}, {text: 'email'}];
       flushAsynchronousOperations();
-      var topItems = Polymer.dom(element.root).querySelectorAll('.top-item');
+      const topItems = Polymer.dom(element.root).querySelectorAll('.top-item');
       assert.equal(topItems.length, 2);
       assert.isTrue(topItems[0].classList.contains('bold-text'));
       assert.isFalse(topItems[1].classList.contains('bold-text'));
     });
 
-    test('non link items', function() {
-      var item0 = {name: 'item one', id: 'foo'};
+    test('non link items', () => {
+      const item0 = {name: 'item one', id: 'foo'};
       element.items = [item0, {name: 'item two', id: 'bar'}];
-      var fooTapped = sinon.stub();
-      var tapped = sinon.stub();
+      const fooTapped = sinon.stub();
+      const tapped = sinon.stub();
       element.addEventListener('tap-item-foo', fooTapped);
       element.addEventListener('tap-item', tapped);
       flushAsynchronousOperations();
@@ -103,12 +103,12 @@
       assert.deepEqual(tapped.lastCall.args[0].detail, item0);
     });
 
-    test('disabled non link item', function() {
+    test('disabled non link item', () => {
       element.items = [{name: 'item one', id: 'foo'}];
       element.disabledIds = ['foo'];
 
-      var stub = sinon.stub();
-      var tapped = sinon.stub();
+      const stub = sinon.stub();
+      const tapped = sinon.stub();
       element.addEventListener('tap-item-foo', stub);
       element.addEventListener('tap-item', tapped);
       flushAsynchronousOperations();
diff --git a/polygerrit-ui/app/elements/shared/gr-editable-content/gr-editable-content.js b/polygerrit-ui/app/elements/shared/gr-editable-content/gr-editable-content.js
index 86211a4..e6ea72d 100644
--- a/polygerrit-ui/app/elements/shared/gr-editable-content/gr-editable-content.js
+++ b/polygerrit-ui/app/elements/shared/gr-editable-content/gr-editable-content.js
@@ -53,11 +53,11 @@
       _newContent: String,
     },
 
-    focusTextarea: function() {
+    focusTextarea() {
       this.$$('iron-autogrow-textarea').textarea.focus();
     },
 
-    _editingChanged: function(editing) {
+    _editingChanged(editing) {
       if (!editing) { return; }
 
       // TODO(wyatta) switch linkify sequence, see issue 5526.
@@ -65,16 +65,16 @@
           this.content.replace(/^R=\u200B/gm, 'R=') : this.content;
     },
 
-    _computeSaveDisabled: function(disabled, content, newContent) {
+    _computeSaveDisabled(disabled, content, newContent) {
       return disabled || (content === newContent);
     },
 
-    _handleSave: function(e) {
+    _handleSave(e) {
       e.preventDefault();
       this.fire('editable-content-save', {content: this._newContent});
     },
 
-    _handleCancel: function(e) {
+    _handleCancel(e) {
       e.preventDefault();
       this.editing = false;
       this.fire('editable-content-cancel');
diff --git a/polygerrit-ui/app/elements/shared/gr-editable-content/gr-editable-content_test.html b/polygerrit-ui/app/elements/shared/gr-editable-content/gr-editable-content_test.html
index b25e815..df98d5a 100644
--- a/polygerrit-ui/app/elements/shared/gr-editable-content/gr-editable-content_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-editable-content/gr-editable-content_test.html
@@ -33,37 +33,37 @@
 </test-fixture>
 
 <script>
-  suite('gr-editable-content tests', function() {
-    var element;
+  suite('gr-editable-content tests', () => {
+    let element;
 
-    setup(function() {
+    setup(() => {
       element = fixture('basic');
     });
 
-    test('save event', function(done) {
+    test('save event', done => {
       element._newContent = 'foo';
-      element.addEventListener('editable-content-save', function(e) {
+      element.addEventListener('editable-content-save', e => {
         assert.equal(e.detail.content, 'foo');
         done();
       });
       MockInteractions.tap(element.$$('gr-button[primary]'));
     });
 
-    test('cancel event', function(done) {
-      element.addEventListener('editable-content-cancel', function() {
+    test('cancel event', done => {
+      element.addEventListener('editable-content-cancel', () => {
         done();
       });
       MockInteractions.tap(element.$$('gr-button:not([primary])'));
     });
 
-    test('enabling editing updates edit field contents', function() {
+    test('enabling editing updates edit field contents', () => {
       element.content = 'current content';
       element._newContent = 'stale content';
       element.editing = true;
       assert.equal(element._newContent, 'current content');
     });
 
-    test('disabling editing does not update edit field contents', function() {
+    test('disabling editing does not update edit field contents', () => {
       element.content = 'current content';
       element.editing = true;
       element._newContent = 'stale content';
@@ -71,24 +71,24 @@
       assert.equal(element._newContent, 'stale content');
     });
 
-    test('zero width spaces are removed properly', function() {
+    test('zero width spaces are removed properly', () => {
       element.removeZeroWidthSpace = true;
       element.content = 'R=\u200Btest@google.com';
       element.editing = true;
       assert.equal(element._newContent, 'R=test@google.com');
     });
 
-    suite('editing', function() {
-      setup(function() {
+    suite('editing', () => {
+      setup(() => {
         element.content = 'current content';
         element.editing = true;
       });
 
-      test('save button is disabled initially', function() {
+      test('save button is disabled initially', () => {
         assert.isTrue(element.$$('gr-button[primary]').disabled);
       });
 
-      test('save button is enabled when content changes', function() {
+      test('save button is enabled when content changes', () => {
         element._newContent = 'new content';
         assert.isFalse(element.$$('gr-button[primary]').disabled);
       });
diff --git a/polygerrit-ui/app/elements/shared/gr-editable-label/gr-editable-label.js b/polygerrit-ui/app/elements/shared/gr-editable-label/gr-editable-label.js
index f3e83f9..1839479 100644
--- a/polygerrit-ui/app/elements/shared/gr-editable-label/gr-editable-label.js
+++ b/polygerrit-ui/app/elements/shared/gr-editable-label/gr-editable-label.js
@@ -49,30 +49,30 @@
       tabindex: '0',
     },
 
-    _usePlaceholder: function(value, placeholder) {
+    _usePlaceholder(value, placeholder) {
       return (!value || !value.length) && placeholder;
     },
 
-    _computeLabel: function(value, placeholder) {
+    _computeLabel(value, placeholder) {
       if (this._usePlaceholder(value, placeholder)) {
         return placeholder;
       }
       return value;
     },
 
-    _open: function() {
+    _open() {
       if (this.readOnly || this.editing) { return; }
 
       this._inputText = this.value;
       this.editing = true;
 
-      this.async(function() {
+      this.async(() => {
         this.$.input.focus();
         this.$.input.setSelectionRange(0, this.$.input.value.length);
       });
     },
 
-    _save: function() {
+    _save() {
       if (!this.editing) { return; }
 
       this.value = this._inputText;
@@ -80,14 +80,14 @@
       this.fire('changed', this.value);
     },
 
-    _cancel: function() {
+    _cancel() {
       if (!this.editing) { return; }
 
       this.editing = false;
       this._inputText = this.value;
     },
 
-    _handleInputKeydown: function(e) {
+    _handleInputKeydown(e) {
       if (e.keyCode === 13) {  // Enter key
         e.preventDefault();
         this._save();
@@ -97,8 +97,8 @@
       }
     },
 
-    _computeLabelClass: function(readOnly, value, placeholder) {
-      var classes = [];
+    _computeLabelClass(readOnly, value, placeholder) {
+      const classes = [];
       if (!readOnly) { classes.push('editable'); }
       if (this._usePlaceholder(value, placeholder)) {
         classes.push('placeholder');
@@ -106,7 +106,7 @@
       return classes.join(' ');
     },
 
-    _updateTitle: function(value) {
+    _updateTitle(value) {
       this.setAttribute('title', (value && value.length) ? value : null);
     },
   });
diff --git a/polygerrit-ui/app/elements/shared/gr-editable-label/gr-editable-label_test.html b/polygerrit-ui/app/elements/shared/gr-editable-label/gr-editable-label_test.html
index 42770aa..ffd1f81 100644
--- a/polygerrit-ui/app/elements/shared/gr-editable-label/gr-editable-label_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-editable-label/gr-editable-label_test.html
@@ -44,19 +44,19 @@
 </test-fixture>
 
 <script>
-  suite('gr-editable-label tests', function() {
-    var element;
-    var input;
-    var label;
+  suite('gr-editable-label tests', () => {
+    let element;
+    let input;
+    let label;
 
-    setup(function() {
+    setup(() => {
       element = fixture('basic');
 
       input = element.$$('input');
       label = element.$$('label');
     });
 
-    test('element render', function() {
+    test('element render', () => {
       // The input is hidden and the label is visible:
       assert.isNotNull(input.getAttribute('hidden'));
       assert.isNull(label.getAttribute('hidden'));
@@ -76,8 +76,8 @@
       assert.equal(input.value, 'value text');
     });
 
-    test('edit value', function(done) {
-      var editedStub = sinon.stub();
+    test('edit value', done => {
+      const editedStub = sinon.stub();
       element.addEventListener('changed', editedStub);
 
       MockInteractions.tap(label);
@@ -88,7 +88,7 @@
 
       assert.isFalse(editedStub.called);
 
-      element.async(function() {
+      element.async(() => {
         assert.isTrue(editedStub.called);
         assert.equal(input.value, 'new text');
         done();
@@ -99,19 +99,19 @@
     });
   });
 
-  suite('gr-editable-label read-only tests', function() {
-    var element;
-    var input;
-    var label;
+  suite('gr-editable-label read-only tests', () => {
+    let element;
+    let input;
+    let label;
 
-    setup(function() {
+    setup(() => {
       element = fixture('read-only');
 
       input = element.$$('input');
       label = element.$$('label');
     });
 
-    test('disallows edit when read-only', function() {
+    test('disallows edit when read-only', () => {
       // The input is hidden and the label is visible:
       assert.isNotNull(input.getAttribute('hidden'));
       assert.isNull(label.getAttribute('hidden'));
@@ -125,7 +125,7 @@
       assert.isNull(label.getAttribute('hidden'));
     });
 
-    test('label is not marked as editable', function() {
+    test('label is not marked as editable', () => {
       assert.isFalse(label.classList.contains('editable'));
     });
   });
diff --git a/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text.js b/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text.js
index a2130b2..2c314bc 100644
--- a/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text.js
+++ b/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text.js
@@ -14,7 +14,8 @@
 (function() {
   'use strict';
 
-  var QUOTE_MARKER_PATTERN = /\n\s?>\s/g;
+  // eslint-disable-next-line no-unused-vars
+  const QUOTE_MARKER_PATTERN = /\n\s?>\s/g;
 
   Polymer({
     is: 'gr-formatted-text',
@@ -35,7 +36,7 @@
       '_contentOrConfigChanged(content, config)',
     ],
 
-    ready: function() {
+    ready() {
       if (this.noTrailingMargin) {
         this.classList.add('noTrailingMargin');
       }
@@ -50,11 +51,11 @@
      *
      * @return {string}
      */
-    getTextContent: function() {
+    getTextContent() {
       return this._blocksToText(this._computeBlocks(this.content));
     },
 
-    _contentChanged: function(content) {
+    _contentChanged(content) {
       // In the case where the config may not be set (perhaps due to the
       // request for it still being in flight), set the content anyway to
       // prevent waiting on the config to display the text.
@@ -65,8 +66,8 @@
     /**
      * Given a source string, update the DOM inside #container.
      */
-    _contentOrConfigChanged: function(content) {
-      var container = Polymer.dom(this.$.container);
+    _contentOrConfigChanged(content) {
+      const container = Polymer.dom(this.$.container);
 
       // Remove existing content.
       while (container.firstChild) {
@@ -74,10 +75,9 @@
       }
 
       // Add new content.
-      this._computeNodes(this._computeBlocks(content))
-          .forEach(function(node) {
+      for (const node of this._computeNodes(this._computeBlocks(content))) {
         container.appendChild(node);
-      });
+      }
     },
 
     /**
@@ -102,14 +102,14 @@
      * @param {string} content
      * @return {!Array<!Object>}
      */
-    _computeBlocks: function(content) {
+    _computeBlocks(content) {
       if (!content) { return []; }
 
-      var result = [];
-      var split = content.split('\n\n');
-      var p;
+      const result = [];
+      const split = content.split('\n\n');
+      let p;
 
-      for (var i = 0; i < split.length; i++) {
+      for (let i = 0; i < split.length; i++) {
         p = split[i];
         if (!p.length) { continue; }
 
@@ -153,14 +153,14 @@
      *   potential paragraph).
      * @param {!Array<!Object>} out The list of blocks to append to.
      */
-    _makeList: function(p, out) {
-      var block = null;
-      var inList = false;
-      var inParagraph = false;
-      var lines = p.split('\n');
-      var line;
+    _makeList(p, out) {
+      let block = null;
+      let inList = false;
+      let inParagraph = false;
+      const lines = p.split('\n');
+      let line;
 
-      for (var i = 0; i < lines.length; i++) {
+      for (let i = 0; i < lines.length; i++) {
         line = lines[i];
 
         if (line[0] === '-' || line[0] === '*') {
@@ -198,10 +198,10 @@
       }
     },
 
-    _makeQuote: function(p) {
-      var quotedLines = p
+    _makeQuote(p) {
+      const quotedLines = p
           .split('\n')
-          .map(function(l) { return l.replace(/^[ ]?>[ ]?/, ''); })
+          .map(l => l.replace(/^[ ]?>[ ]?/, ''))
           .join('\n');
       return {
         type: 'quote',
@@ -209,22 +209,22 @@
       };
     },
 
-    _isQuote: function(p) {
-      return p.indexOf('> ') === 0 || p.indexOf(' > ') === 0;
+    _isQuote(p) {
+      return p.startsWith('> ') || p.startsWith(' > ');
     },
 
-    _isPreFormat: function(p) {
-      return p.indexOf('\n ') !== -1 || p.indexOf('\n\t') !== -1 ||
-          p.indexOf(' ') === 0 || p.indexOf('\t') === 0;
+    _isPreFormat(p) {
+      return p.includes('\n ') || p.includes('\n\t') ||
+          p.startsWith(' ') || p.startsWith('\t');
     },
 
-    _isList: function(p) {
-      return p.indexOf('\n- ') !== -1 || p.indexOf('\n* ') !== -1 ||
-          p.indexOf('- ') === 0 || p.indexOf('* ') === 0;
+    _isList(p) {
+      return p.includes('\n- ') || p.includes('\n* ') ||
+          p.startsWith('- ') || p.startsWith('* ');
     },
 
-    _makeLinkedText: function(content, isPre) {
-      var text = document.createElement('gr-linked-text');
+    _makeLinkedText(content, isPre) {
+      const text = document.createElement('gr-linked-text');
       text.config = this.config;
       text.content = content;
       text.pre = true;
@@ -239,19 +239,19 @@
      * @param  {!Array<!Object>} blocks
      * @return {!Array<!HTMLElement>}
      */
-    _computeNodes: function(blocks) {
-      return blocks.map(function(block) {
+    _computeNodes(blocks) {
+      return blocks.map(block => {
         if (block.type === 'paragraph') {
-          var p = document.createElement('p');
+          const p = document.createElement('p');
           p.appendChild(this._makeLinkedText(block.text));
           return p;
         }
 
         if (block.type === 'quote') {
-          var bq = document.createElement('blockquote');
-          this._computeNodes(block.blocks).forEach(function(node) {
+          const bq = document.createElement('blockquote');
+          for (const node of this._computeNodes(block.blocks)) {
             bq.appendChild(node);
-          });
+          }
           return bq;
         }
 
@@ -260,19 +260,19 @@
         }
 
         if (block.type === 'list') {
-          var ul = document.createElement('ul');
-          block.items.forEach(function(item) {
-            var li = document.createElement('li');
+          const ul = document.createElement('ul');
+          for (const item of bloc.items) {
+            const li = document.createElement('li');
             li.appendChild(this._makeLinkedText(item));
             ul.appendChild(li);
-          }.bind(this));
+          }
           return ul;
         }
-      }.bind(this));
+      });
     },
 
-    _blocksToText: function(blocks) {
-      return blocks.map(function(block) {
+    _blocksToText(blocks) {
+      return blocks.map(block => {
         if (block.type === 'paragraph' || block.type === 'pre') {
           return block.text;
         }
@@ -282,7 +282,7 @@
         if (block.type === 'list') {
           return block.items.join('\n');
         }
-      }.bind(this)).join('\n\n');
+      }).join('\n\n');
     },
   });
 })();
diff --git a/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text_test.html b/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text_test.html
index 5afe60a..0192ea9 100644
--- a/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text_test.html
@@ -32,9 +32,9 @@
 </test-fixture>
 
 <script>
-  suite('gr-formatted-text tests', function() {
-    var element;
-    var sandbox;
+  suite('gr-formatted-text tests', () => {
+    let element;
+    let sandbox;
 
     function assertBlock(result, index, type, text) {
       assert.equal(result[index].type, type);
@@ -46,73 +46,73 @@
       assert.equal(result[resultIndex].items[itemIndex], text);
     }
 
-    setup(function() {
+    setup(() => {
       element = fixture('basic');
       sandbox = sinon.sandbox.create();
     });
 
-    teardown(function() {
+    teardown(() => {
       sandbox.restore();
     });
 
-    test('parse null undefined and empty', function() {
+    test('parse null undefined and empty', () => {
       assert.lengthOf(element._computeBlocks(null), 0);
       assert.lengthOf(element._computeBlocks(undefined), 0);
       assert.lengthOf(element._computeBlocks(''), 0);
     });
 
-    test('parse simple', function() {
-      var comment = 'Para1';
-      var result = element._computeBlocks(comment);
+    test('parse simple', () => {
+      const comment = 'Para1';
+      const result = element._computeBlocks(comment);
       assert.lengthOf(result, 1);
       assertBlock(result, 0, 'paragraph', comment);
     });
 
-    test('parse multiline para', function() {
-      var comment = 'Para 1\nStill para 1';
-      var result = element._computeBlocks(comment);
+    test('parse multiline para', () => {
+      const comment = 'Para 1\nStill para 1';
+      const result = element._computeBlocks(comment);
       assert.lengthOf(result, 1);
       assertBlock(result, 0, 'paragraph', comment);
     });
 
-    test('parse para break', function() {
-      var comment = 'Para 1\n\nPara 2\n\nPara 3';
-      var result = element._computeBlocks(comment);
+    test('parse para break', () => {
+      const comment = 'Para 1\n\nPara 2\n\nPara 3';
+      const result = element._computeBlocks(comment);
       assert.lengthOf(result, 3);
       assertBlock(result, 0, 'paragraph', 'Para 1');
       assertBlock(result, 1, 'paragraph', 'Para 2');
       assertBlock(result, 2, 'paragraph', 'Para 3');
     });
 
-    test('parse quote', function() {
-      var comment = '> Quote text';
-      var result = element._computeBlocks(comment);
+    test('parse quote', () => {
+      const comment = '> Quote text';
+      const result = element._computeBlocks(comment);
       assert.lengthOf(result, 1);
       assert.equal(result[0].type, 'quote');
       assert.lengthOf(result[0].blocks, 1);
       assertBlock(result[0].blocks, 0, 'paragraph', 'Quote text');
     });
 
-    test('parse quote lead space', function() {
-      var comment = ' > Quote text';
-      var result = element._computeBlocks(comment);
+    test('parse quote lead space', () => {
+      const comment = ' > Quote text';
+      const result = element._computeBlocks(comment);
       assert.lengthOf(result, 1);
       assert.equal(result[0].type, 'quote');
       assert.lengthOf(result[0].blocks, 1);
       assertBlock(result[0].blocks, 0, 'paragraph', 'Quote text');
     });
 
-    test('parse excludes empty', function() {
-      var comment = 'Para 1\n\n\n\nPara 2';
-      var result = element._computeBlocks(comment);
+    test('parse excludes empty', () => {
+      const comment = 'Para 1\n\n\n\nPara 2';
+      const result = element._computeBlocks(comment);
       assert.lengthOf(result, 2);
       assertBlock(result, 0, 'paragraph', 'Para 1');
       assertBlock(result, 1, 'paragraph', 'Para 2');
     });
 
-    test('parse multiline quote', function() {
-      var comment = '> Quote line 1\n> Quote line 2\n > Quote line 3\n';
-      var result = element._computeBlocks(comment);
+    test('parse multiline quote', () => {
+      const comment = '> Quote line 1\n> Quote line 2\n > Quote line 3\n';
+      const result = element._computeBlocks(comment);
       assert.lengthOf(result, 1);
       assert.equal(result[0].type, 'quote');
       assert.lengthOf(result[0].blocks, 1);
@@ -120,55 +120,55 @@
           'Quote line 1\nQuote line 2\nQuote line 3\n');
     });
 
-    test('parse pre', function() {
-      var comment = '    Four space indent.';
-      var result = element._computeBlocks(comment);
+    test('parse pre', () => {
+      const comment = '    Four space indent.';
+      const result = element._computeBlocks(comment);
       assert.lengthOf(result, 1);
       assertBlock(result, 0, 'pre', comment);
     });
 
-    test('parse one space pre', function() {
-      var comment = ' One space indent.\n Another line.';
-      var result = element._computeBlocks(comment);
+    test('parse one space pre', () => {
+      const comment = ' One space indent.\n Another line.';
+      const result = element._computeBlocks(comment);
       assert.lengthOf(result, 1);
       assertBlock(result, 0, 'pre', comment);
     });
 
-    test('parse tab pre', function() {
-      var comment = '\tOne tab indent.\n\tAnother line.\n  Yet another!';
-      var result = element._computeBlocks(comment);
+    test('parse tab pre', () => {
+      const comment = '\tOne tab indent.\n\tAnother line.\n  Yet another!';
+      const result = element._computeBlocks(comment);
       assert.lengthOf(result, 1);
       assertBlock(result, 0, 'pre', comment);
     });
 
-    test('parse intermediate leading whitespace pre', function() {
-      var comment = 'No indent.\n\tNonzero indent.\nNo indent again.';
-      var result = element._computeBlocks(comment);
+    test('parse intermediate leading whitespace pre', () => {
+      const comment = 'No indent.\n\tNonzero indent.\nNo indent again.';
+      const result = element._computeBlocks(comment);
       assert.lengthOf(result, 1);
       assertBlock(result, 0, 'pre', comment);
     });
 
-    test('parse star list', function() {
-      var comment = '* Item 1\n* Item 2\n* Item 3';
-      var result = element._computeBlocks(comment);
+    test('parse star list', () => {
+      const comment = '* Item 1\n* Item 2\n* Item 3';
+      const result = element._computeBlocks(comment);
       assert.lengthOf(result, 1);
       assertListBlock(result, 0, 0, 'Item 1');
       assertListBlock(result, 0, 1, 'Item 2');
       assertListBlock(result, 0, 2, 'Item 3');
     });
 
-    test('parse dash list', function() {
-      var comment = '- Item 1\n- Item 2\n- Item 3';
-      var result = element._computeBlocks(comment);
+    test('parse dash list', () => {
+      const comment = '- Item 1\n- Item 2\n- Item 3';
+      const result = element._computeBlocks(comment);
       assert.lengthOf(result, 1);
       assertListBlock(result, 0, 0, 'Item 1');
       assertListBlock(result, 0, 1, 'Item 2');
       assertListBlock(result, 0, 2, 'Item 3');
     });
 
-    test('parse mixed list', function() {
-      var comment = '- Item 1\n* Item 2\n- Item 3\n* Item 4';
-      var result = element._computeBlocks(comment);
+    test('parse mixed list', () => {
+      const comment = '- Item 1\n* Item 2\n- Item 3\n* Item 4';
+      const result = element._computeBlocks(comment);
       assert.lengthOf(result, 1);
       assertListBlock(result, 0, 0, 'Item 1');
       assertListBlock(result, 0, 1, 'Item 2');
@@ -176,8 +176,8 @@
       assertListBlock(result, 0, 3, 'Item 4');
     });
 
-    test('parse mixed block types', function() {
-      var comment = 'Paragraph\nacross\na\nfew\nlines.' +
+    test('parse mixed block types', () => {
+      const comment = 'Paragraph\nacross\na\nfew\nlines.' +
           '\n\n' +
           '> Quote\n> across\n> not many lines.' +
           '\n\n' +
@@ -190,7 +190,7 @@
           '\tPreformatted text.' +
           '\n\n' +
           'Parting words.';
-      var result = element._computeBlocks(comment);
+      const result = element._computeBlocks(comment);
       assert.lengthOf(result, 7);
       assertBlock(result, 0, 'paragraph', 'Paragraph\nacross\na\nfew\nlines.');
 
@@ -209,18 +209,18 @@
       assertBlock(result, 6, 'paragraph', 'Parting words.');
     });
 
-    test('bullet list 1', function() {
-      var comment = 'A\n\n* line 1\n* 2nd line';
-      var result = element._computeBlocks(comment);
+    test('bullet list 1', () => {
+      const comment = 'A\n\n* line 1\n* 2nd line';
+      const result = element._computeBlocks(comment);
       assert.lengthOf(result, 2);
       assertBlock(result, 0, 'paragraph', 'A');
       assertListBlock(result, 1, 0, 'line 1');
       assertListBlock(result, 1, 1, '2nd line');
     });
 
-    test('bullet list 2', function() {
-      var comment = 'A\n\n* line 1\n* 2nd line\n\nB';
-      var result = element._computeBlocks(comment);
+    test('bullet list 2', () => {
+      const comment = 'A\n\n* line 1\n* 2nd line\n\nB';
+      const result = element._computeBlocks(comment);
       assert.lengthOf(result, 3);
       assertBlock(result, 0, 'paragraph', 'A');
       assertListBlock(result, 1, 0, 'line 1');
@@ -228,50 +228,50 @@
       assertBlock(result, 2, 'paragraph', 'B');
     });
 
-    test('bullet list 3', function() {
-      var comment = '* line 1\n* 2nd line\n\nB';
-      var result = element._computeBlocks(comment);
+    test('bullet list 3', () => {
+      const comment = '* line 1\n* 2nd line\n\nB';
+      const result = element._computeBlocks(comment);
       assert.lengthOf(result, 2);
       assertListBlock(result, 0, 0, 'line 1');
       assertListBlock(result, 0, 1, '2nd line');
       assertBlock(result, 1, 'paragraph', 'B');
     });
 
-    test('bullet list 4', function() {
-      var comment = 'To see this bug, you have to:\n' +
+    test('bullet list 4', () => {
+      const comment = 'To see this bug, you have to:\n' +
           '* Be on IMAP or EAS (not on POP)\n' +
           '* Be very unlucky\n';
-      var result = element._computeBlocks(comment);
+      const result = element._computeBlocks(comment);
       assert.lengthOf(result, 2);
       assertBlock(result, 0, 'paragraph', 'To see this bug, you have to:');
       assertListBlock(result, 1, 0, 'Be on IMAP or EAS (not on POP)');
       assertListBlock(result, 1, 1, 'Be very unlucky');
     });
 
-    test('bullet list 5', function() {
-      var comment = 'To see this bug,\n' +
+    test('bullet list 5', () => {
+      const comment = 'To see this bug,\n' +
           'you have to:\n' +
           '* Be on IMAP or EAS (not on POP)\n' +
           '* Be very unlucky\n';
-      var result = element._computeBlocks(comment);
+      const result = element._computeBlocks(comment);
       assert.lengthOf(result, 2);
       assertBlock(result, 0, 'paragraph', 'To see this bug, you have to:');
       assertListBlock(result, 1, 0, 'Be on IMAP or EAS (not on POP)');
       assertListBlock(result, 1, 1, 'Be very unlucky');
     });
 
-    test('dash list 1', function() {
-      var comment = 'A\n\n- line 1\n- 2nd line';
-      var result = element._computeBlocks(comment);
+    test('dash list 1', () => {
+      const comment = 'A\n\n- line 1\n- 2nd line';
+      const result = element._computeBlocks(comment);
       assert.lengthOf(result, 2);
       assertBlock(result, 0, 'paragraph', 'A');
       assertListBlock(result, 1, 0, 'line 1');
       assertListBlock(result, 1, 1, '2nd line');
     });
 
-    test('dash list 2', function() {
-      var comment = 'A\n\n- line 1\n- 2nd line\n\nB';
-      var result = element._computeBlocks(comment);
+    test('dash list 2', () => {
+      const comment = 'A\n\n- line 1\n- 2nd line\n\nB';
+      const result = element._computeBlocks(comment);
       assert.lengthOf(result, 3);
       assertBlock(result, 0, 'paragraph', 'A');
       assertListBlock(result, 1, 0, 'line 1');
@@ -279,52 +279,52 @@
       assertBlock(result, 2, 'paragraph', 'B');
     });
 
-    test('dash list 3', function() {
-      var comment = '- line 1\n- 2nd line\n\nB';
-      var result = element._computeBlocks(comment);
+    test('dash list 3', () => {
+      const comment = '- line 1\n- 2nd line\n\nB';
+      const result = element._computeBlocks(comment);
       assert.lengthOf(result, 2);
       assertListBlock(result, 0, 0, 'line 1');
       assertListBlock(result, 0, 1, '2nd line');
       assertBlock(result, 1, 'paragraph', 'B');
     });
 
-    test('pre format 1', function() {
-      var comment = 'A\n\n  This is pre\n  formatted';
-      var result = element._computeBlocks(comment);
+    test('pre format 1', () => {
+      const comment = 'A\n\n  This is pre\n  formatted';
+      const result = element._computeBlocks(comment);
       assert.lengthOf(result, 2);
       assertBlock(result, 0, 'paragraph', 'A');
       assertBlock(result, 1, 'pre', '  This is pre\n  formatted');
     });
 
-    test('pre format 2', function() {
-      var comment = 'A\n\n  This is pre\n  formatted\n\nbut this is not';
-      var result = element._computeBlocks(comment);
+    test('pre format 2', () => {
+      const comment = 'A\n\n  This is pre\n  formatted\n\nbut this is not';
+      const result = element._computeBlocks(comment);
       assert.lengthOf(result, 3);
       assertBlock(result, 0, 'paragraph', 'A');
       assertBlock(result, 1, 'pre', '  This is pre\n  formatted');
       assertBlock(result, 2, 'paragraph', 'but this is not');
     });
 
-    test('pre format 3', function() {
-      var comment = 'A\n\n  Q\n    <R>\n  S\n\nB';
-      var result = element._computeBlocks(comment);
+    test('pre format 3', () => {
+      const comment = 'A\n\n  Q\n    <R>\n  S\n\nB';
+      const result = element._computeBlocks(comment);
       assert.lengthOf(result, 3);
       assertBlock(result, 0, 'paragraph', 'A');
       assertBlock(result, 1, 'pre', '  Q\n    <R>\n  S');
       assertBlock(result, 2, 'paragraph', 'B');
     });
 
-    test('pre format 4', function() {
-      var comment = '  Q\n    <R>\n  S\n\nB';
-      var result = element._computeBlocks(comment);
+    test('pre format 4', () => {
+      const comment = '  Q\n    <R>\n  S\n\nB';
+      const result = element._computeBlocks(comment);
       assert.lengthOf(result, 2);
       assertBlock(result, 0, 'pre', '  Q\n    <R>\n  S');
       assertBlock(result, 1, 'paragraph', 'B');
     });
 
-    test('quote 1', function() {
-      var comment = '> I\'m happy\n > with quotes!\n\nSee above.';
-      var result = element._computeBlocks(comment);
+    test('quote 1', () => {
+      const comment = '> I\'m happy\n > with quotes!\n\nSee above.';
+      const result = element._computeBlocks(comment);
       assert.lengthOf(result, 2);
       assert.equal(result[0].type, 'quote');
       assert.lengthOf(result[0].blocks, 1);
@@ -332,9 +332,9 @@
       assertBlock(result, 1, 'paragraph', 'See above.');
     });
 
-    test('quote 2', function() {
-      var comment = 'See this said:\n\n > a quoted\n > string block\n\nOK?';
-      var result = element._computeBlocks(comment);
+    test('quote 2', () => {
+      const comment = 'See this said:\n\n > a quoted\n > string block\n\nOK?';
+      const result = element._computeBlocks(comment);
       assert.lengthOf(result, 3);
       assertBlock(result, 0, 'paragraph', 'See this said:');
       assert.equal(result[1].type, 'quote');
@@ -343,9 +343,9 @@
       assertBlock(result, 2, 'paragraph', 'OK?');
     });
 
-    test('nested quotes', function() {
-      var comment = ' > > prior\n > \n > next\n';
-      var result = element._computeBlocks(comment);
+    test('nested quotes', () => {
+      const comment = ' > > prior\n > \n > next\n';
+      const result = element._computeBlocks(comment);
       assert.lengthOf(result, 1);
       assert.equal(result[0].type, 'quote');
       assert.lengthOf(result[0].blocks, 2);
@@ -355,25 +355,25 @@
       assertBlock(result[0].blocks, 1, 'paragraph', 'next\n');
     });
 
-    test('getTextContent', function() {
-      var comment = 'Paragraph\n\n  pre\n\n* List\n* Of\n* Items\n\n> Quote';
+    test('getTextContent', () => {
+      const comment = 'Paragraph\n\n  pre\n\n* List\n* Of\n* Items\n\n> Quote';
       element.content = comment;
-      var result = element.getTextContent();
-      var expected = 'Paragraph\n\n  pre\n\nList\nOf\nItems\n\nQuote';
+      const result = element.getTextContent();
+      const expected = 'Paragraph\n\n  pre\n\nList\nOf\nItems\n\nQuote';
       assert.equal(result, expected);
     });
 
-    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);
     });
 
-    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';
       element.config = {};
       assert.isTrue(contentStub.called);
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-actions-js-api.js b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-actions-js-api.js
index 9bcde07..99c4fed 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-actions-js-api.js
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-actions-js-api.js
@@ -22,13 +22,13 @@
   }
 
   GrChangeActionsInterface.prototype.addPrimaryActionKey = function(key) {
-    if (this._el.primaryActionKeys.indexOf(key) !== -1) { return; }
+    if (this._el.primaryActionKeys.includes(key)) { return; }
 
     this._el.push('primaryActionKeys', key);
   };
 
   GrChangeActionsInterface.prototype.removePrimaryActionKey = function(key) {
-    this._el.primaryActionKeys = this._el.primaryActionKeys.filter(function(k) {
+    this._el.primaryActionKeys = this._el.primaryActionKeys.filter(k => {
       return k !== key;
     });
   };
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-actions-js-api_test.html b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-actions-js-api_test.html
index d964cde..24fee39 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-actions-js-api_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-actions-js-api_test.html
@@ -37,43 +37,44 @@
 </test-fixture>
 
 <script>
-  suite('gr-js-api-interface tests', function() {
-    var element;
-    var changeActions;
+  suite('gr-js-api-interface tests', () => {
+    let element;
+    let changeActions;
 
     // Because deepEqual doesn’t behave in Safari.
     function assertArraysEqual(actual, expected) {
       assert.equal(actual.length, expected.length);
-      for (var i = 0; i < actual.length; i++) {
+      for (let i = 0; i < actual.length; i++) {
         assert.equal(actual[i], expected[i]);
       }
     }
 
-    setup(function() {
+    setup(() => {
       element = fixture('basic');
       element.change = {};
       element._hasKnownChainState = false;
-      var plugin;
-      Gerrit.install(function(p) { plugin = p; }, '0.1',
+      let plugin;
+      Gerrit.install(p => { plugin = p; }, '0.1',
           'http://test.com/plugins/testplugin/static/test.js');
       changeActions = plugin.changeActions();
     });
 
-    teardown(function() {
+    teardown(() => {
       changeActions = null;
     });
 
-    test('property existence', function() {
-      [
+    test('property existence', () => {
+      const properties = [
         'ActionType',
         'ChangeActions',
         'RevisionActions',
-      ].forEach(function(p) {
+      ];
+      for (const p of properties) {
         assertArraysEqual(changeActions[p], element[p]);
-      });
+      }
     });
 
-    test('add/remove primary action keys', function() {
+    test('add/remove primary action keys', () => {
       element.primaryActionKeys = [];
       changeActions.addPrimaryActionKey('foo');
       assertArraysEqual(element.primaryActionKeys, ['foo']);
@@ -89,34 +90,34 @@
       assertArraysEqual(element.primaryActionKeys, []);
     });
 
-    test('action buttons', function(done) {
-      var key = changeActions.add(changeActions.ActionType.REVISION, 'Bork!');
-      var handler = sinon.spy();
+    test('action buttons', done => {
+      const key = changeActions.add(changeActions.ActionType.REVISION, 'Bork!');
+      const handler = sinon.spy();
       changeActions.addTapListener(key, handler);
-      flush(function() {
+      flush(() => {
         MockInteractions.tap(element.$$('[data-action-key="' + key + '"]'));
         assert(handler.calledOnce);
         changeActions.removeTapListener(key, handler);
         MockInteractions.tap(element.$$('[data-action-key="' + key + '"]'));
         assert(handler.calledOnce);
         changeActions.remove(key);
-        flush(function() {
+        flush(() => {
           assert.isNull(element.$$('[data-action-key="' + key + '"]'));
           done();
         });
       });
     });
 
-    test('action button properties', function(done) {
-      var key = changeActions.add(changeActions.ActionType.REVISION, 'Bork!');
-      flush(function() {
-        var button = element.$$('[data-action-key="' + key + '"]');
+    test('action button properties', done => {
+      const key = changeActions.add(changeActions.ActionType.REVISION, 'Bork!');
+      flush(() => {
+        const button = element.$$('[data-action-key="' + key + '"]');
         assert.isOk(button);
         assert.equal(button.getAttribute('data-label'), 'Bork!');
         assert.isNotOk(button.disabled);
         changeActions.setLabel(key, 'Yo');
         changeActions.setEnabled(key, false);
-        flush(function() {
+        flush(() => {
           assert.equal(button.getAttribute('data-label'), 'Yo');
           assert.isTrue(button.disabled);
           done();
@@ -124,30 +125,30 @@
       });
     });
 
-    test('hide action buttons', function(done) {
-      var key = changeActions.add(changeActions.ActionType.REVISION, 'Bork!');
-      flush(function() {
-        var button = element.$$('[data-action-key="' + key + '"]');
+    test('hide action buttons', done => {
+      const key = changeActions.add(changeActions.ActionType.REVISION, 'Bork!');
+      flush(() => {
+        const button = element.$$('[data-action-key="' + key + '"]');
         assert.isOk(button);
         assert.isFalse(button.hasAttribute('hidden'));
         changeActions.setActionHidden(
             changeActions.ActionType.REVISION, key, true);
-        flush(function() {
-          var button = element.$$('[data-action-key="' + key + '"]');
+        flush(() => {
+          const button = element.$$('[data-action-key="' + key + '"]');
           assert.isNotOk(button);
           done();
         });
       });
     });
 
-    test('move action button to overflow', function(done) {
-      var key = changeActions.add(changeActions.ActionType.REVISION, 'Bork!');
-      flush(function() {
+    test('move action button to overflow', done => {
+      const key = changeActions.add(changeActions.ActionType.REVISION, 'Bork!');
+      flush(() => {
         assert.isTrue(element.$.moreActions.hidden);
         assert.isOk(element.$$('[data-action-key="' + key + '"]'));
         changeActions.setActionOverflow(
             changeActions.ActionType.REVISION, key, true);
-        flush(function() {
+        flush(() => {
           assert.isNotOk(element.$$('[data-action-key="' + key + '"]'));
           assert.isFalse(element.$.moreActions.hidden);
           assert.strictEqual(element.$.moreActions.items[0].name, 'Bork!');
@@ -156,17 +157,19 @@
       });
     });
 
-    test('change actions priority', function(done) {
-      var key1 = changeActions.add(changeActions.ActionType.REVISION, 'Bork!');
-      var key2 = changeActions.add(changeActions.ActionType.CHANGE, 'Squanch?');
-      flush(function() {
-        var buttons =
+    test('change actions priority', done => {
+      const key1 =
+          changeActions.add(changeActions.ActionType.REVISION, 'Bork!');
+      const key2 =
+          changeActions.add(changeActions.ActionType.CHANGE, 'Squanch?');
+      flush(() => {
+        let buttons =
             Polymer.dom(element.root).querySelectorAll('[data-action-key]');
         assert.equal(buttons[0].getAttribute('data-action-key'), key1);
         assert.equal(buttons[1].getAttribute('data-action-key'), key2);
         changeActions.setActionPriority(
             changeActions.ActionType.REVISION, key1, 10);
-        flush(function() {
+        flush(() => {
           buttons =
               Polymer.dom(element.root).querySelectorAll('[data-action-key]');
           assert.equal(buttons[0].getAttribute('data-action-key'), key2);
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-reply-js-api_test.html b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-reply-js-api_test.html
index c2357cc..73f3479 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-reply-js-api_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-reply-js-api_test.html
@@ -37,35 +37,35 @@
 </test-fixture>
 
 <script>
-  suite('gr-change-reply-js-api tests', function() {
-    var element;
-    var sandbox;
-    var changeReply;
+  suite('gr-change-reply-js-api tests', () => {
+    let element;
+    let sandbox;
+    let changeReply;
 
-    setup(function() {
+    setup(() => {
       stub('gr-rest-api-interface', {
-        getConfig: function() { return Promise.resolve({}); },
-        getAccount: function() { return Promise.resolve(null); },
+        getConfig() { return Promise.resolve({}); },
+        getAccount() { return Promise.resolve(null); },
       });
       element = fixture('basic');
       sandbox = sinon.sandbox.create();
-      var plugin;
-      Gerrit.install(function(p) { plugin = p; }, '0.1',
+      let plugin;
+      Gerrit.install(p => { plugin = p; }, '0.1',
           'http://test.com/plugins/testplugin/static/test.js');
       changeReply = plugin.changeReply();
     });
 
-    teardown(function() {
+    teardown(() => {
       changeReply = null;
       sandbox.restore();
     });
 
-    test('calls', function() {
-      var setLabelValueStub = sinon.stub(element, 'setLabelValue');
+    test('calls', () => {
+      const setLabelValueStub = sinon.stub(element, 'setLabelValue');
       changeReply.setLabelValue('My-Label', '+1337');
       assert(setLabelValueStub.calledWithExactly('My-Label', '+1337'));
 
-      var sendStub = sinon.stub(element, 'send');
+      const sendStub = sinon.stub(element, 'send');
       changeReply.send(false);
       assert(sendStub.calledWithExactly(false));
     });
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface.js b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface.js
index 34ca728..70a9bf5 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface.js
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface.js
@@ -14,7 +14,7 @@
 (function() {
   'use strict';
 
-  var EventType = {
+  const EventType = {
     HISTORY: 'history',
     LABEL_CHANGE: 'labelchange',
     SHOW_CHANGE: 'showchange',
@@ -25,7 +25,7 @@
     POST_REVERT: 'postrevert',
   };
 
-  var Element = {
+  const Element = {
     CHANGE_ACTIONS: 'changeactions',
     REPLY_DIALOG: 'replydialog',
   };
@@ -44,11 +44,11 @@
       },
     },
 
-    Element: Element,
-    EventType: EventType,
+    Element,
+    EventType,
 
-    handleEvent: function(type, detail) {
-      Gerrit.awaitPluginsLoaded().then(function() {
+    handleEvent(type, detail) {
+      Gerrit.awaitPluginsLoaded().then(() => {
         switch (type) {
           case EventType.HISTORY:
             this._handleHistory(detail);
@@ -67,27 +67,27 @@
                 type);
             break;
         }
-      }.bind(this));
+      });
     },
 
-    addElement: function(key, el) {
+    addElement(key, el) {
       this._elements[key] = el;
     },
 
-    getElement: function(key) {
+    getElement(key) {
       return this._elements[key];
     },
 
-    addEventCallback: function(eventName, callback) {
+    addEventCallback(eventName, callback) {
       if (!this._eventCallbacks[eventName]) {
         this._eventCallbacks[eventName] = [];
       }
       this._eventCallbacks[eventName].push(callback);
     },
 
-    canSubmitChange: function(change, revision) {
-      var submitCallbacks = this._getEventCallbacks(EventType.SUBMIT_CHANGE);
-      var cancelSubmit = submitCallbacks.some(function(callback) {
+    canSubmitChange(change, revision) {
+      const submitCallbacks = this._getEventCallbacks(EventType.SUBMIT_CHANGE);
+      const cancelSubmit = submitCallbacks.some(callback => {
         try {
           return callback(change, revision) === false;
         } catch (err) {
@@ -99,28 +99,29 @@
       return !cancelSubmit;
     },
 
-    _removeEventCallbacks: function() {
-      for (var k in EventType) {
+    _removeEventCallbacks() {
+      for (const k in EventType) {
+        if (!EventType.hasOwnProperty(k)) { continue; }
         this._eventCallbacks[EventType[k]] = [];
       }
     },
 
-    _handleHistory: function(detail) {
-      this._getEventCallbacks(EventType.HISTORY).forEach(function(cb) {
+    _handleHistory(detail) {
+      for (const cb of this._getEventCallbacks(EventType.HISTORY)) {
         try {
           cb(detail.path);
         } catch (err) {
           console.error(err);
         }
-      });
+      }
     },
 
-    _handleShowChange: function(detail) {
-      this._getEventCallbacks(EventType.SHOW_CHANGE).forEach(function(cb) {
-        var change = detail.change;
-        var patchNum = detail.patchNum;
-        var revision;
-        for (var rev in change.revisions) {
+    _handleShowChange(detail) {
+      for (const cb of this._getEventCallbacks(EventType.SHOW_CHANGE)) {
+        const change = detail.change;
+        const patchNum = detail.patchNum;
+        let revision;
+        for (const rev in change.revisions) {
           if (change.revisions[rev]._number == patchNum) {
             revision = change.revisions[rev];
             break;
@@ -131,67 +132,63 @@
         } catch (err) {
           console.error(err);
         }
-      });
+      }
     },
 
-    handleCommitMessage: function(change, msg) {
-      this._getEventCallbacks(EventType.COMMIT_MSG_EDIT).forEach(
-          function(cb) {
-            try {
-              cb(change, msg);
-            } catch (err) {
-              console.error(err);
-            }
-          }
-      );
+    handleCommitMessage(change, msg) {
+      for (const cb of this._getEventCallbacks(EventType.COMMIT_MSG_EDIT)) {
+        try {
+          cb(change, msg);
+        } catch (err) {
+          console.error(err);
+        }
+      }
     },
 
-    _handleComment: function(detail) {
-      this._getEventCallbacks(EventType.COMMENT).forEach(function(cb) {
+    _handleComment(detail) {
+      for (const cb of this._getEventCallbacks(EventType.COMMENT)) {
         try {
           cb(detail.node);
         } catch (err) {
           console.error(err);
         }
-      });
+      }
     },
 
-    _handleLabelChange: function(detail) {
-      this._getEventCallbacks(EventType.LABEL_CHANGE).forEach(function(cb) {
+    _handleLabelChange(detail) {
+      for (const cb of this._getEventCallbacks(EventType.LABEL_CHANGE)) {
         try {
           cb(detail.change);
         } catch (err) {
           console.error(err);
         }
-      });
+      }
     },
 
-    modifyRevertMsg: function(change, revertMsg, origMsg) {
-      this._getEventCallbacks(EventType.REVERT).forEach(function(callback) {
+    modifyRevertMsg(change, revertMsg, origMsg) {
+      for (const cb of this._getEventCallbacks(EventType.REVERT)) {
         try {
-          revertMsg = callback(change, revertMsg, origMsg);
+          revertMsg = cb(change, revertMsg, origMsg);
         } catch (err) {
           console.error(err);
         }
-      });
+      }
       return revertMsg;
     },
 
-    getLabelValuesPostRevert: function(change) {
-      var labels = {};
-      this._getEventCallbacks(EventType.POST_REVERT).forEach(
-          function(callback) {
-            try {
-              labels = callback(change);
-            } catch (err) {
-              console.error(err);
-            }
-          }
-      );
+    getLabelValuesPostRevert(change) {
+      let labels = {};
+      for (const cb of this._getEventCallbacks(EventType.POST_REVERT)) {
+        try {
+          labels = cb(change);
+        } catch (err) {
+          console.error(err);
+        }
+      }
       return labels;
     },
 
-    _getEventCallbacks: function(type) {
+    _getEventCallbacks(type) {
       return this._eventCallbacks[type] || [];
     },
   });
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface_test.html b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface_test.html
index d62bdd8..c3013bd 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface_test.html
@@ -31,45 +31,45 @@
 </test-fixture>
 
 <script>
-  suite('gr-js-api-interface tests', function() {
-    var element;
-    var plugin;
-    var errorStub;
-    var sandbox;
+  suite('gr-js-api-interface tests', () => {
+    let element;
+    let plugin;
+    let errorStub;
+    let sandbox;
 
-    var throwErrFn = function() {
+    const throwErrFn = function() {
       throw Error('Unfortunately, this handler has stopped');
     };
 
-    setup(function() {
+    setup(() => {
       sandbox = sinon.sandbox.create();
       stub('gr-rest-api-interface', {
-        getAccount: function() {
+        getAccount() {
           return Promise.resolve({name: 'Judy Hopps'});
         },
       });
       element = fixture('basic');
       errorStub = sandbox.stub(console, 'error');
       Gerrit._setPluginsCount(1);
-      Gerrit.install(function(p) { plugin = p; }, '0.1',
+      Gerrit.install(p => { plugin = p; }, '0.1',
           'http://test.com/plugins/testplugin/static/test.js');
     });
 
-    teardown(function() {
+    teardown(() => {
       sandbox.restore();
       element._removeEventCallbacks();
       plugin = null;
     });
 
-    test('url', function() {
+    test('url', () => {
       assert.equal(plugin.url(), 'http://test.com/plugins/testplugin/');
       assert.equal(plugin.url('/static/test.js'),
           'http://test.com/plugins/testplugin/static/test.js');
     });
 
-    test('history event', function(done) {
+    test('history event', done => {
       plugin.on(element.EventType.HISTORY, throwErrFn);
-      plugin.on(element.EventType.HISTORY, function(path) {
+      plugin.on(element.EventType.HISTORY, path => {
         assert.equal(path, '/path/to/awesomesauce');
         assert.isTrue(errorStub.calledOnce);
         done();
@@ -78,13 +78,13 @@
           {path: '/path/to/awesomesauce'});
     });
 
-    test('showchange event', function(done) {
-      var testChange = {
+    test('showchange event', done => {
+      const testChange = {
         _number: 42,
         revisions: {def: {_number: 2}, abc: {_number: 1}},
       };
       plugin.on(element.EventType.SHOW_CHANGE, throwErrFn);
-      plugin.on(element.EventType.SHOW_CHANGE, function(change, revision) {
+      plugin.on(element.EventType.SHOW_CHANGE, (change, revision) => {
         assert.deepEqual(change, testChange);
         assert.deepEqual(revision, testChange.revisions.abc);
         assert.isTrue(errorStub.calledOnce);
@@ -94,28 +94,28 @@
           {change: testChange, patchNum: 1});
     });
 
-    test('handleEvent awaits plugins load', function(done) {
-      var testChange = {
+    test('handleEvent awaits plugins load', done => {
+      const testChange = {
         _number: 42,
         revisions: {def: {_number: 2}, abc: {_number: 1}},
       };
-      var spy = sandbox.spy();
+      const spy = sandbox.spy();
       Gerrit._setPluginsCount(1);
       plugin.on(element.EventType.SHOW_CHANGE, spy);
       element.handleEvent(element.EventType.SHOW_CHANGE,
           {change: testChange, patchNum: 1});
       assert.isFalse(spy.called);
       Gerrit._setPluginsCount(0);
-      flush(function() {
+      flush(() => {
         assert.isTrue(spy.called);
         done();
       });
     });
 
-    test('comment event', function(done) {
-      var testCommentNode = {foo: 'bar'};
+    test('comment event', done => {
+      const testCommentNode = {foo: 'bar'};
       plugin.on(element.EventType.COMMENT, throwErrFn);
-      plugin.on(element.EventType.COMMENT, function(commentNode) {
+      plugin.on(element.EventType.COMMENT, commentNode => {
         assert.deepEqual(commentNode, testCommentNode);
         assert.isTrue(errorStub.calledOnce);
         done();
@@ -123,7 +123,7 @@
       element.handleEvent(element.EventType.COMMENT, {node: testCommentNode});
     });
 
-    test('revert event', function() {
+    test('revert event', () => {
       function appendToRevertMsg(c, revertMsg, originalMsg) {
         return revertMsg + '\n' + originalMsg.replace(/^/gm, '> ') + '\ninfo';
       }
@@ -134,16 +134,16 @@
       plugin.on(element.EventType.REVERT, throwErrFn);
       plugin.on(element.EventType.REVERT, appendToRevertMsg);
       assert.equal(element.modifyRevertMsg(null, 'test', 'origTest'),
-                   'test\n> origTest\ninfo');
+          'test\n> origTest\ninfo');
       assert.isTrue(errorStub.calledOnce);
 
       plugin.on(element.EventType.REVERT, appendToRevertMsg);
       assert.equal(element.modifyRevertMsg(null, 'test', 'origTest'),
-                   'test\n> origTest\ninfo\n> origTest\ninfo');
+          'test\n> origTest\ninfo\n> origTest\ninfo');
       assert.isTrue(errorStub.calledTwice);
     });
 
-    test('postrevert event', function() {
+    test('postrevert event', () => {
       function getLabels(c) {
         return {'Code-Review': 1};
       }
@@ -158,10 +158,10 @@
       assert.isTrue(errorStub.calledOnce);
     });
 
-    test('commitmsgedit event', function(done) {
-      var testMsg = 'Test CL commit message';
+    test('commitmsgedit event', done => {
+      const testMsg = 'Test CL commit message';
       plugin.on(element.EventType.COMMIT_MSG_EDIT, throwErrFn);
-      plugin.on(element.EventType.COMMIT_MSG_EDIT, function(change, msg) {
+      plugin.on(element.EventType.COMMIT_MSG_EDIT, (change, msg) => {
         assert.deepEqual(msg, testMsg);
         assert.isTrue(errorStub.calledOnce);
         done();
@@ -169,10 +169,10 @@
       element.handleCommitMessage(null, testMsg);
     });
 
-    test('labelchange event', function(done) {
-      var testChange = {_number: 42};
+    test('labelchange event', done => {
+      const testChange = {_number: 42};
       plugin.on(element.EventType.LABEL_CHANGE, throwErrFn);
-      plugin.on(element.EventType.LABEL_CHANGE, function(change) {
+      plugin.on(element.EventType.LABEL_CHANGE, change => {
         assert.deepEqual(change, testChange);
         assert.isTrue(errorStub.calledOnce);
         done();
@@ -180,41 +180,41 @@
       element.handleEvent(element.EventType.LABEL_CHANGE, {change: testChange});
     });
 
-    test('submitchange', function() {
+    test('submitchange', () => {
       plugin.on(element.EventType.SUBMIT_CHANGE, throwErrFn);
-      plugin.on(element.EventType.SUBMIT_CHANGE, function() { return true; });
+      plugin.on(element.EventType.SUBMIT_CHANGE, () => { return true; });
       assert.isTrue(element.canSubmitChange());
       assert.isTrue(errorStub.calledOnce);
-      plugin.on(element.EventType.SUBMIT_CHANGE, function() { return false; });
-      plugin.on(element.EventType.SUBMIT_CHANGE, function() { return true; });
+      plugin.on(element.EventType.SUBMIT_CHANGE, () => { return false; });
+      plugin.on(element.EventType.SUBMIT_CHANGE, () => { return true; });
       assert.isFalse(element.canSubmitChange());
       assert.isTrue(errorStub.calledTwice);
     });
 
-    test('versioning', function() {
-      var callback = sandbox.spy();
+    test('versioning', () => {
+      const callback = sandbox.spy();
       Gerrit.install(callback, '0.0pre-alpha');
       assert(callback.notCalled);
     });
 
-    test('getAccount', function(done) {
-      Gerrit.getLoggedIn().then(function(loggedIn) {
+    test('getAccount', done => {
+      Gerrit.getLoggedIn().then(loggedIn => {
         assert.isTrue(loggedIn);
         done();
       });
     });
 
-    test('_setPluginsCount', function(done) {
+    test('_setPluginsCount', done => {
       stub('gr-reporting', {
-        pluginsLoaded: function() {
+        pluginsLoaded() {
           assert.equal(Gerrit._pluginsPending, 0);
           done();
-        }
+        },
       });
       Gerrit._setPluginsCount(0);
     });
 
-    test('_arePluginsLoaded', function() {
+    test('_arePluginsLoaded', () => {
       assert.isTrue(Gerrit._arePluginsLoaded());
       Gerrit._setPluginsCount(1);
       assert.isFalse(Gerrit._arePluginsLoaded());
@@ -222,12 +222,12 @@
       assert.isTrue(Gerrit._arePluginsLoaded());
     });
 
-    test('_pluginInstalled', function(done) {
+    test('_pluginInstalled', done => {
       stub('gr-reporting', {
-        pluginsLoaded: function() {
+        pluginsLoaded() {
           assert.equal(Gerrit._pluginsPending, 0);
           done();
-        }
+        },
       });
       Gerrit._setPluginsCount(2);
       Gerrit._pluginInstalled();
@@ -235,34 +235,34 @@
       Gerrit._pluginInstalled();
     });
 
-    test('install calls _pluginInstalled', function() {
+    test('install calls _pluginInstalled', () => {
       sandbox.stub(Gerrit, '_pluginInstalled');
-      Gerrit.install(function(p) { plugin = p; }, '0.1',
+      Gerrit.install(p => { plugin = p; }, '0.1',
           'http://test.com/plugins/testplugin/static/test.js');
       assert.isTrue(Gerrit._pluginInstalled.calledOnce);
     });
 
-    test('install calls _pluginInstalled on error', function() {
+    test('install calls _pluginInstalled on error', () => {
       sandbox.stub(Gerrit, '_pluginInstalled');
-      Gerrit.install(function() {}, '0.0pre-alpha');
+      Gerrit.install(() => {}, '0.0pre-alpha');
       assert.isTrue(Gerrit._pluginInstalled.calledOnce);
     });
 
-    test('installGwt calls _pluginInstalled', function() {
+    test('installGwt calls _pluginInstalled', () => {
       sandbox.stub(Gerrit, '_pluginInstalled');
       Gerrit.installGwt();
       assert.isTrue(Gerrit._pluginInstalled.calledOnce);
     });
 
-    test('installGwt returns a stub object', function() {
-      var plugin = Gerrit.installGwt();
+    test('installGwt returns a stub object', () => {
+      const plugin = Gerrit.installGwt();
       sandbox.stub(console, 'warn');
       assert.isAbove(Object.keys(plugin).length, 0);
-      Object.keys(plugin).forEach(function(name) {
+      for (const name of Object.keys(plugin)) {
         console.warn.reset();
         plugin[name]();
         assert.isTrue(console.warn.calledOnce);
-      });
+      }
     });
   });
 </script>
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-public-js-api.js b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-public-js-api.js
index 402b371..a84eedd 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-public-js-api.js
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-public-js-api.js
@@ -14,17 +14,17 @@
 (function(window) {
   'use strict';
 
-  var warnNotSupported = function(opt_name) {
+  const warnNotSupported = function(opt_name) {
     console.warn('Plugin API method ' + (opt_name || '') + ' is not supported');
   };
 
-  var stubbedMethods = ['_loadedGwt', 'screen', 'settingsScreen', 'panel'];
-  var GWT_PLUGIN_STUB = {};
-  stubbedMethods.forEach(function(name) {
+  const stubbedMethods = ['_loadedGwt', 'screen', 'settingsScreen', 'panel'];
+  const GWT_PLUGIN_STUB = {};
+  for (const name of stubbedMethods) {
     GWT_PLUGIN_STUB[name] = warnNotSupported.bind(null, name);
-  });
+  }
 
-  var API_VERSION = '0.1';
+  const API_VERSION = '0.1';
 
   // GWT JSNI uses $wnd to refer to window.
   // http://www.gwtproject.org/doc/latest/DevGuideCodingBasicsJSNI.html
@@ -38,7 +38,7 @@
     }
 
     this._url = new URL(opt_url);
-    if (this._url.pathname.indexOf('/plugins') !== 0) {
+    if (!this._url.pathname.startsWith('/plugins')) {
       console.warn('Plugin not being loaded from /plugins base path:',
           this._url.href, '— Unable to determine name.');
       return;
@@ -54,14 +54,14 @@
     return this._name;
   };
 
-  Plugin.prototype.registerStyleModule =
-      function(stylingEndpointName, moduleName) {
+  Plugin.prototype.registerStyleModule = function(stylingEndpointName,
+      moduleName) {
     if (!Gerrit._styleModules[stylingEndpointName]) {
       Gerrit._styleModules[stylingEndpointName] = [];
     }
     Gerrit._styleModules[stylingEndpointName].push({
       pluginUrl: this._url,
-      moduleName: moduleName,
+      moduleName,
     });
   };
 
@@ -87,7 +87,7 @@
         Plugin._sharedAPIElement.Element.REPLY_DIALOG));
   };
 
-  var Gerrit = window.Gerrit || {};
+  const Gerrit = window.Gerrit || {};
 
   // Number of plugins to initialize, -1 means 'not yet known'.
   Gerrit._pluginsPending = -1;
@@ -102,12 +102,13 @@
 
   Gerrit.css = function(rulesStr) {
     if (!Gerrit._customStyleSheet) {
-      var styleEl = document.createElement('style');
+      const styleEl = document.createElement('style');
       document.head.appendChild(styleEl);
       Gerrit._customStyleSheet = styleEl.sheet;
     }
 
-    var name = '__pg_js_api_class_' + Gerrit._customStyleSheet.cssRules.length;
+    const name = '__pg_js_api_class_' +
+        Gerrit._customStyleSheet.cssRules.length;
     Gerrit._customStyleSheet.insertRule('.' + name + '{' + rulesStr + '}', 0);
     return name;
   };
@@ -121,9 +122,9 @@
     }
 
     // TODO(andybons): Polyfill currentScript for IE10/11 (edge supports it).
-    var src = opt_src || (document.currentScript &&
+    const src = opt_src || (document.currentScript &&
          document.currentScript.src || document.currentScript.baseURI);
-    var plugin = new Plugin(src);
+    const plugin = new Plugin(src);
     try {
       callback(plugin);
     } catch (e) {
@@ -155,7 +156,7 @@
       if (Gerrit._arePluginsLoaded()) {
         Gerrit._allPluginsPromise = Promise.resolve();
       } else {
-        Gerrit._allPluginsPromise = new Promise(function(resolve) {
+        Gerrit._allPluginsPromise = new Promise(resolve => {
           Gerrit._resolveAllPluginsLoaded = resolve;
         });
       }
diff --git a/polygerrit-ui/app/elements/shared/gr-linked-chip/gr-linked-chip.js b/polygerrit-ui/app/elements/shared/gr-linked-chip/gr-linked-chip.js
index c6a5e4e..bfba1c4 100644
--- a/polygerrit-ui/app/elements/shared/gr-linked-chip/gr-linked-chip.js
+++ b/polygerrit-ui/app/elements/shared/gr-linked-chip/gr-linked-chip.js
@@ -30,11 +30,11 @@
       },
     },
 
-    _getBackgroundClass: function(transparent) {
+    _getBackgroundClass(transparent) {
       return transparent ? 'transparentBackground' : '';
     },
 
-    _handleRemoveTap: function(e) {
+    _handleRemoveTap(e) {
       e.preventDefault();
       this.fire('remove');
     },
diff --git a/polygerrit-ui/app/elements/shared/gr-linked-chip/gr-linked-chip_test.html b/polygerrit-ui/app/elements/shared/gr-linked-chip/gr-linked-chip_test.html
index eefc79d..3182653 100644
--- a/polygerrit-ui/app/elements/shared/gr-linked-chip/gr-linked-chip_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-linked-chip/gr-linked-chip_test.html
@@ -34,21 +34,21 @@
 </test-fixture>
 
 <script>
-  suite('gr-linked-chip tests', function() {
-    var element;
-    var sandbox;
+  suite('gr-linked-chip tests', () => {
+    let element;
+    let sandbox;
 
-    setup(function() {
+    setup(() => {
       element = fixture('basic');
       sandbox = sinon.sandbox.create();
     });
 
-    teardown(function() {
+    teardown(() => {
       sandbox.restore();
     });
 
-    test('remove fired', function() {
-      var spy = sandbox.spy();
+    test('remove fired', () => {
+      const spy = sandbox.spy();
       element.addEventListener('remove', spy);
       flushAsynchronousOperations();
       MockInteractions.tap(element.$.remove);
diff --git a/polygerrit-ui/app/elements/shared/gr-overlay/gr-overlay.js b/polygerrit-ui/app/elements/shared/gr-overlay/gr-overlay.js
index 9f271ed..8db8004 100644
--- a/polygerrit-ui/app/elements/shared/gr-overlay/gr-overlay.js
+++ b/polygerrit-ui/app/elements/shared/gr-overlay/gr-overlay.js
@@ -14,8 +14,8 @@
 (function() {
   'use strict';
 
-  var AWAIT_MAX_ITERS = 10;
-  var AWAIT_STEP = 5;
+  const AWAIT_MAX_ITERS = 10;
+  const AWAIT_STEP = 5;
 
   Polymer({
     is: 'gr-overlay',
@@ -24,17 +24,17 @@
       Polymer.IronOverlayBehavior,
     ],
 
-    open: function() {
-      return new Promise(function(resolve) {
-        Polymer.IronOverlayBehaviorImpl.open.apply(this, arguments);
+    open(...args) {
+      return new Promise(resolve => {
+        Polymer.IronOverlayBehaviorImpl.open.apply(this, args);
         this._awaitOpen(resolve);
-      }.bind(this));
+      });
     },
 
     /**
      * Override the focus stops that iron-overlay-behavior tries to find.
      */
-    setFocusStops: function(stops) {
+    setFocusStops(stops) {
       this.__firstFocusableNode = stops.start;
       this.__lastFocusableNode = stops.end;
     },
@@ -43,21 +43,21 @@
      * NOTE: (wyatta) Slightly hacky way to listen to the overlay actually
      * opening. Eventually replace with a direct way to listen to the overlay.
      */
-    _awaitOpen: function(fn) {
-      var iters = 0;
-      var step = function() {
-        this.async(function() {
+    _awaitOpen(fn) {
+      let iters = 0;
+      const step = () => {
+        this.async(() => {
           if (this.style.display !== 'none') {
             fn.call(this);
           } else if (iters++ < AWAIT_MAX_ITERS) {
             step.call(this);
           }
-        }.bind(this), AWAIT_STEP);
-      }.bind(this);
+        }, AWAIT_STEP);
+      };
       step.call(this);
     },
 
-    _id: function() {
+    _id() {
       return this.getAttribute('id') || 'global';
     },
   });
diff --git a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.js b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.js
index ae42c2a..68576b8 100644
--- a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.js
+++ b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.js
@@ -14,20 +14,20 @@
 (function() {
   'use strict';
 
-  var DiffViewMode = {
+  const DiffViewMode = {
     SIDE_BY_SIDE: 'SIDE_BY_SIDE',
     UNIFIED: 'UNIFIED_DIFF',
   };
-  var JSON_PREFIX = ')]}\'';
-  var MAX_UNIFIED_DEFAULT_WINDOW_WIDTH_PX = 900;
-  var PARENT_PATCH_NUM = 'PARENT';
+  const JSON_PREFIX = ')]}\'';
+  const MAX_UNIFIED_DEFAULT_WINDOW_WIDTH_PX = 900;
+  const PARENT_PATCH_NUM = 'PARENT';
 
-  var Requests = {
+  const Requests = {
     SEND_DIFF_DRAFT: 'sendDiffDraft',
   };
 
   // Must be kept in sync with the ListChangesOption enum and protobuf.
-  var ListChangesOption = {
+  const ListChangesOption = {
     LABELS: 0,
     DETAILED_LABELS: 8,
 
@@ -115,20 +115,20 @@
       },
     },
 
-    fetchJSON: function(url, opt_errFn, opt_cancelCondition, opt_params,
+    fetchJSON(url, opt_errFn, opt_cancelCondition, opt_params,
         opt_opts) {
       opt_opts = opt_opts || {};
       // Issue 5715, This can be reverted back once
       // iOS 10.3 and mac os 10.12.4 has the fetch api fix.
-      var fetchOptions = {
-        credentials: 'same-origin'
+      const fetchOptions = {
+        credentials: 'same-origin',
       };
       if (opt_opts.headers !== undefined) {
         fetchOptions['headers'] = opt_opts.headers;
       }
 
-      var urlWithParams = this._urlWithParams(url, opt_params);
-      return fetch(urlWithParams, fetchOptions).then(function(response) {
+      const urlWithParams = this._urlWithParams(url, opt_params);
+      return fetch(urlWithParams, fetchOptions).then(response => {
         if (opt_cancelCondition && opt_cancelCondition()) {
           response.body.cancel();
           return;
@@ -139,12 +139,12 @@
             opt_errFn.call(null, response);
             return;
           }
-          this.fire('server-error', {response: response});
+          this.fire('server-error', {response});
           return;
         }
 
         return this.getResponseObject(response);
-      }.bind(this)).catch(function(err) {
+      }).catch(err => {
         if (opt_errFn) {
           opt_errFn.call(null, null, err);
         } else {
@@ -152,31 +152,28 @@
           throw err;
         }
         throw err;
-      }.bind(this));
+      });
     },
 
-    _urlWithParams: function(url, opt_params) {
+    _urlWithParams(url, opt_params) {
       if (!opt_params) { return this.getBaseUrl() + url; }
 
-      var params = [];
-      for (var p in opt_params) {
+      const params = [];
+      for (const p in opt_params) {
         if (opt_params[p] == null) {
           params.push(encodeURIComponent(p));
           continue;
         }
-        var values = [].concat(opt_params[p]);
-        for (var i = 0; i < values.length; i++) {
-          params.push(
-            encodeURIComponent(p) + '=' +
-            encodeURIComponent(values[i]));
+        for (const value of [].concat(opt_params[p])) {
+          params.push(`${encodeURIComponent(p)}=${encodeURIComponent(value)}`);
         }
       }
       return this.getBaseUrl() + url + '?' + params.join('&');
     },
 
-    getResponseObject: function(response) {
-      return response.text().then(function(text) {
-        var result;
+    getResponseObject(response) {
+      return response.text().then(text => {
+        let result;
         try {
           result = JSON.parse(text.substring(JSON_PREFIX.length));
         } catch (_) {
@@ -186,21 +183,21 @@
       });
     },
 
-    getConfig: function() {
+    getConfig() {
       return this._fetchSharedCacheURL('/config/server/info');
     },
 
-    getProjectConfig: function(project) {
+    getProjectConfig(project) {
       return this._fetchSharedCacheURL(
           '/projects/' + encodeURIComponent(project) + '/config');
     },
 
-    getVersion: function() {
+    getVersion() {
       return this._fetchSharedCacheURL('/config/server/version');
     },
 
-    getDiffPreferences: function() {
-      return this.getLoggedIn().then(function(loggedIn) {
+    getDiffPreferences() {
+      return this.getLoggedIn().then(loggedIn => {
         if (loggedIn) {
           return this._fetchSharedCacheURL('/accounts/self/preferences.diff');
         }
@@ -224,10 +221,10 @@
           tab_size: 8,
           theme: 'DEFAULT',
         });
-      }.bind(this));
+      });
     },
 
-    savePreferences: function(prefs, opt_errFn, opt_ctx) {
+    savePreferences(prefs, opt_errFn, opt_ctx) {
       // Note (Issue 5142): normalize the download scheme with lower case before
       // saving.
       if (prefs.download_scheme) {
@@ -238,127 +235,127 @@
           opt_ctx);
     },
 
-    saveDiffPreferences: function(prefs, opt_errFn, opt_ctx) {
+    saveDiffPreferences(prefs, opt_errFn, opt_ctx) {
       // Invalidate the cache.
       this._cache['/accounts/self/preferences.diff'] = undefined;
       return this.send('PUT', '/accounts/self/preferences.diff', prefs,
           opt_errFn, opt_ctx);
     },
 
-    getAccount: function() {
-      return this._fetchSharedCacheURL('/accounts/self/detail', function(resp) {
+    getAccount() {
+      return this._fetchSharedCacheURL('/accounts/self/detail', resp => {
         if (resp.status === 403) {
           this._cache['/accounts/self/detail'] = null;
         }
-      }.bind(this));
+      });
     },
 
-    getAccountEmails: function() {
+    getAccountEmails() {
       return this._fetchSharedCacheURL('/accounts/self/emails');
     },
 
-    addAccountEmail: function(email, opt_errFn, opt_ctx) {
+    addAccountEmail(email, opt_errFn, opt_ctx) {
       return this.send('PUT', '/accounts/self/emails/' +
           encodeURIComponent(email), null, opt_errFn, opt_ctx);
     },
 
-    deleteAccountEmail: function(email, opt_errFn, opt_ctx) {
+    deleteAccountEmail(email, opt_errFn, opt_ctx) {
       return this.send('DELETE', '/accounts/self/emails/' +
           encodeURIComponent(email), null, opt_errFn, opt_ctx);
     },
 
-    setPreferredAccountEmail: function(email, opt_errFn, opt_ctx) {
+    setPreferredAccountEmail(email, opt_errFn, opt_ctx) {
       return this.send('PUT', '/accounts/self/emails/' +
           encodeURIComponent(email) + '/preferred', null,
-          opt_errFn, opt_ctx).then(function() {
-        // If result of getAccountEmails is in cache, update it in the cache
-        // so we don't have to invalidate it.
-        var cachedEmails = this._cache['/accounts/self/emails'];
-        if (cachedEmails) {
-          var emails = cachedEmails.map(function(entry) {
-            if (entry.email === email) {
-              return {email: email, preferred: true};
-            } else {
-              return {email: email};
+          opt_errFn, opt_ctx).then(() => {
+            // If result of getAccountEmails is in cache, update it in the cache
+            // so we don't have to invalidate it.
+            const cachedEmails = this._cache['/accounts/self/emails'];
+            if (cachedEmails) {
+              const emails = cachedEmails.map(entry => {
+                if (entry.email === email) {
+                  return {email, preferred: true};
+                } else {
+                  return {email};
+                }
+              });
+              this._cache['/accounts/self/emails'] = emails;
             }
           });
-          this._cache['/accounts/self/emails'] = emails;
-        }
-      }.bind(this));
     },
 
-    setAccountName: function(name, opt_errFn, opt_ctx) {
-      return this.send('PUT', '/accounts/self/name', {name: name}, opt_errFn,
-          opt_ctx).then(function(response) {
+    setAccountName(name, opt_errFn, opt_ctx) {
+      return this.send('PUT', '/accounts/self/name', {name}, opt_errFn,
+          opt_ctx).then(response => {
             // If result of getAccount is in cache, update it in the cache
             // so we don't have to invalidate it.
-            var cachedAccount = this._cache['/accounts/self/detail'];
+            const cachedAccount = this._cache['/accounts/self/detail'];
             if (cachedAccount) {
-              return this.getResponseObject(response).then(function(newName) {
+              return this.getResponseObject(response).then(newName => {
                 // Replace object in cache with new object to force UI updates.
                 // TODO(logan): Polyfill for Object.assign in IE
                 this._cache['/accounts/self/detail'] = Object.assign(
                     {}, cachedAccount, {name: newName});
-              }.bind(this));
+              });
             }
-          }.bind(this));
+          });
     },
 
-    setAccountStatus: function(status, opt_errFn, opt_ctx) {
-      return this.send('PUT', '/accounts/self/status', {status: status},
-          opt_errFn, opt_ctx).then(function(response) {
+    setAccountStatus(status, opt_errFn, opt_ctx) {
+      return this.send('PUT', '/accounts/self/status', {status},
+          opt_errFn, opt_ctx).then(response => {
             // If result of getAccount is in cache, update it in the cache
             // so we don't have to invalidate it.
-            var cachedAccount = this._cache['/accounts/self/detail'];
+            const cachedAccount = this._cache['/accounts/self/detail'];
             if (cachedAccount) {
-              return this.getResponseObject(response).then(function(newStatus) {
+              return this.getResponseObject(response).then(newStatus => {
                 // Replace object in cache with new object to force UI updates.
                 // TODO(logan): Polyfill for Object.assign in IE
                 this._cache['/accounts/self/detail'] = Object.assign(
                     {}, cachedAccount, {status: newStatus});
-              }.bind(this));
+              });
             }
-          }.bind(this));
+          });
     },
 
-    getAccountGroups: function() {
+    getAccountGroups() {
       return this._fetchSharedCacheURL('/accounts/self/groups');
     },
 
-    getAccountCapabilities: function(opt_params) {
-      var queryString = '';
+    getAccountCapabilities(opt_params) {
+      let queryString = '';
       if (opt_params) {
         queryString = '?q=' + opt_params
-            .map(function(param) { return encodeURIComponent(param); })
+            .map(param => { return encodeURIComponent(param); })
             .join('&q=');
       }
       return this._fetchSharedCacheURL('/accounts/self/capabilities' +
           queryString);
     },
 
-    getLoggedIn: function() {
-      return this.getAccount().then(function(account) {
+    getLoggedIn() {
+      return this.getAccount().then(account => {
         return account != null;
       });
     },
 
-    checkCredentials: function() {
+    checkCredentials() {
       // Skip the REST response cache.
       return this.fetchJSON('/accounts/self/detail');
     },
 
-    getPreferences: function() {
-      return this.getLoggedIn().then(function(loggedIn) {
+    getPreferences() {
+      return this.getLoggedIn().then(loggedIn => {
         if (loggedIn) {
           return this._fetchSharedCacheURL('/accounts/self/preferences').then(
-              function(res) {
-            if (this._isNarrowScreen()) {
-              res.default_diff_view = DiffViewMode.UNIFIED;
-            } else {
-              res.default_diff_view = res.diff_view;
-            }
-            return Promise.resolve(res);
-          }.bind(this));
+              res => {
+                if (this._isNarrowScreen()) {
+                  res.default_diff_view = DiffViewMode.UNIFIED;
+                } else {
+                  res.default_diff_view = res.diff_view;
+                }
+                return Promise.resolve(res);
+              });
         }
 
         return Promise.resolve({
@@ -367,27 +364,27 @@
               DiffViewMode.UNIFIED : DiffViewMode.SIDE_BY_SIDE,
           diff_view: 'SIDE_BY_SIDE',
         });
-      }.bind(this));
+      });
     },
 
-    getWatchedProjects: function() {
+    getWatchedProjects() {
       return this._fetchSharedCacheURL('/accounts/self/watched.projects');
     },
 
-    saveWatchedProjects: function(projects, opt_errFn, opt_ctx) {
+    saveWatchedProjects(projects, opt_errFn, opt_ctx) {
       return this.send('POST', '/accounts/self/watched.projects', projects,
           opt_errFn, opt_ctx)
-          .then(function(response) {
+          .then(response => {
             return this.getResponseObject(response);
-          }.bind(this));
+          });
     },
 
-    deleteWatchedProjects: function(projects, opt_errFn, opt_ctx) {
+    deleteWatchedProjects(projects, opt_errFn, opt_ctx) {
       return this.send('POST', '/accounts/self/watched.projects:delete',
           projects, opt_errFn, opt_ctx);
     },
 
-    _fetchSharedCacheURL: function(url, opt_errFn) {
+    _fetchSharedCacheURL(url, opt_errFn) {
       if (this._sharedFetchPromises[url]) {
         return this._sharedFetchPromises[url];
       }
@@ -396,25 +393,25 @@
         return Promise.resolve(this._cache[url]);
       }
       this._sharedFetchPromises[url] = this.fetchJSON(url, opt_errFn).then(
-        function(response) {
-          if (response !== undefined) {
-            this._cache[url] = response;
-          }
-          this._sharedFetchPromises[url] = undefined;
-          return response;
-        }.bind(this)).catch(function(err) {
-          this._sharedFetchPromises[url] = undefined;
-          throw err;
-        }.bind(this));
+          response => {
+            if (response !== undefined) {
+              this._cache[url] = response;
+            }
+            this._sharedFetchPromises[url] = undefined;
+            return response;
+          }).catch(err => {
+            this._sharedFetchPromises[url] = undefined;
+            throw err;
+          });
       return this._sharedFetchPromises[url];
     },
 
-    _isNarrowScreen: function() {
+    _isNarrowScreen() {
       return window.innerWidth < MAX_UNIFIED_DEFAULT_WINDOW_WIDTH_PX;
     },
 
-    getChanges: function(changesPerPage, opt_query, opt_offset) {
-      var options = this._listChangesOptionsToHex(
+    getChanges(changesPerPage, opt_query, opt_offset) {
+      const options = this._listChangesOptionsToHex(
           ListChangesOption.LABELS,
           ListChangesOption.DETAILED_ACCOUNTS
       );
@@ -422,7 +419,7 @@
       if (opt_offset === 'n,z') {
         opt_offset = 0;
       }
-      var params = {
+      const params = {
         n: changesPerPage,
         O: options,
         S: opt_offset || 0,
@@ -433,13 +430,13 @@
       return this.fetchJSON('/changes/', null, null, params);
     },
 
-    getDashboardChanges: function() {
-      var options = this._listChangesOptionsToHex(
+    getDashboardChanges() {
+      const options = this._listChangesOptionsToHex(
           ListChangesOption.LABELS,
           ListChangesOption.DETAILED_ACCOUNTS,
           ListChangesOption.REVIEWED
       );
-      var params = {
+      const params = {
         O: options,
         q: [
           'is:open owner:self',
@@ -451,12 +448,12 @@
       return this.fetchJSON('/changes/', null, null, params);
     },
 
-    getChangeActionURL: function(changeNum, opt_patchNum, endpoint) {
+    getChangeActionURL(changeNum, opt_patchNum, endpoint) {
       return this._changeBaseURL(changeNum, opt_patchNum) + endpoint;
     },
 
-    getChangeDetail: function(changeNum, opt_errFn, opt_cancelCondition) {
-      var options = this._listChangesOptionsToHex(
+    getChangeDetail(changeNum, opt_errFn, opt_cancelCondition) {
+      const options = this._listChangesOptionsToHex(
           ListChangesOption.ALL_REVISIONS,
           ListChangesOption.CHANGE_ACTIONS,
           ListChangesOption.CURRENT_ACTIONS,
@@ -467,18 +464,18 @@
       );
       return this._getChangeDetail(
           changeNum, options, opt_errFn, opt_cancelCondition)
-            .then(GrReviewerUpdatesParser.parse);
+          .then(GrReviewerUpdatesParser.parse);
     },
 
-    getDiffChangeDetail: function(changeNum, opt_errFn, opt_cancelCondition) {
-      var options = this._listChangesOptionsToHex(
+    getDiffChangeDetail(changeNum, opt_errFn, opt_cancelCondition) {
+      const options = this._listChangesOptionsToHex(
           ListChangesOption.ALL_REVISIONS
       );
       return this._getChangeDetail(changeNum, options, opt_errFn,
           opt_cancelCondition);
     },
 
-    _getChangeDetail: function(changeNum, options, opt_errFn,
+    _getChangeDetail(changeNum, options, opt_errFn,
         opt_cancelCondition) {
       return this.fetchJSON(
           this.getChangeActionURL(changeNum, null, '/detail'),
@@ -487,13 +484,13 @@
           {O: options});
     },
 
-    getChangeCommitInfo: function(changeNum, patchNum) {
+    getChangeCommitInfo(changeNum, patchNum) {
       return this.fetchJSON(
           this.getChangeActionURL(changeNum, patchNum, '/commit?links'));
     },
 
-    getChangeFiles: function(changeNum, patchRange) {
-      var endpoint = '/files';
+    getChangeFiles(changeNum, patchRange) {
+      let endpoint = '/files';
       if (patchRange.basePatchNum !== 'PARENT') {
         endpoint += '?base=' + encodeURIComponent(patchRange.basePatchNum);
       }
@@ -501,23 +498,23 @@
           this.getChangeActionURL(changeNum, patchRange.patchNum, endpoint));
     },
 
-    getChangeFilesAsSpeciallySortedArray: function(changeNum, patchRange) {
+    getChangeFilesAsSpeciallySortedArray(changeNum, patchRange) {
       return this.getChangeFiles(changeNum, patchRange).then(
           this._normalizeChangeFilesResponse.bind(this));
     },
 
-    getChangeFilePathsAsSpeciallySortedArray: function(changeNum, patchRange) {
-      return this.getChangeFiles(changeNum, patchRange).then(function(files) {
+    getChangeFilePathsAsSpeciallySortedArray(changeNum, patchRange) {
+      return this.getChangeFiles(changeNum, patchRange).then(files => {
         return Object.keys(files).sort(this.specialFilePathCompare);
-      }.bind(this));
+      });
     },
 
-    _normalizeChangeFilesResponse: function(response) {
+    _normalizeChangeFilesResponse(response) {
       if (!response) { return []; }
-      var paths = Object.keys(response).sort(this.specialFilePathCompare);
-      var files = [];
-      for (var i = 0; i < paths.length; i++) {
-        var info = response[paths[i]];
+      const paths = Object.keys(response).sort(this.specialFilePathCompare);
+      const files = [];
+      for (let i = 0; i < paths.length; i++) {
+        const info = response[paths[i]];
         info.__path = paths[i];
         info.lines_inserted = info.lines_inserted || 0;
         info.lines_deleted = info.lines_deleted || 0;
@@ -526,58 +523,59 @@
       return files;
     },
 
-    getChangeRevisionActions: function(changeNum, patchNum) {
+    getChangeRevisionActions(changeNum, patchNum) {
       return this.fetchJSON(
           this.getChangeActionURL(changeNum, patchNum, '/actions')).then(
-              function(revisionActions) {
+          revisionActions => {
                 // The rebase button on change screen is always enabled.
-                if (revisionActions.rebase) {
-                  revisionActions.rebase.rebaseOnCurrent =
+            if (revisionActions.rebase) {
+              revisionActions.rebase.rebaseOnCurrent =
                       !!revisionActions.rebase.enabled;
-                  revisionActions.rebase.enabled = true;
-                }
-                return revisionActions;
-              });
+              revisionActions.rebase.enabled = true;
+            }
+            return revisionActions;
+          });
     },
 
-    getChangeSuggestedReviewers: function(changeNum, inputVal, opt_errFn,
+    getChangeSuggestedReviewers(changeNum, inputVal, opt_errFn,
         opt_ctx) {
-      var url = this.getChangeActionURL(changeNum, null, '/suggest_reviewers');
+      const url =
+          this.getChangeActionURL(changeNum, null, '/suggest_reviewers');
       return this.fetchJSON(url, opt_errFn, opt_ctx, {
         n: 10,  // Return max 10 results
         q: inputVal,
       });
     },
 
-    getSuggestedGroups: function(inputVal, opt_n, opt_errFn, opt_ctx) {
-      var params = {s: inputVal};
+    getSuggestedGroups(inputVal, opt_n, opt_errFn, opt_ctx) {
+      const params = {s: inputVal};
       if (opt_n) { params.n = opt_n; }
       return this.fetchJSON('/groups/', opt_errFn, opt_ctx, params);
     },
 
-    getSuggestedProjects: function(inputVal, opt_n, opt_errFn, opt_ctx) {
-      var params = {p: inputVal};
+    getSuggestedProjects(inputVal, opt_n, opt_errFn, opt_ctx) {
+      const params = {p: inputVal};
       if (opt_n) { params.n = opt_n; }
       return this.fetchJSON('/projects/', opt_errFn, opt_ctx, params);
     },
 
-    getSuggestedAccounts: function(inputVal, opt_n, opt_errFn, opt_ctx) {
-      var params = {q: inputVal, suggest: null};
+    getSuggestedAccounts(inputVal, opt_n, opt_errFn, opt_ctx) {
+      const params = {q: inputVal, suggest: null};
       if (opt_n) { params.n = opt_n; }
       return this.fetchJSON('/accounts/', opt_errFn, opt_ctx, params);
     },
 
-    addChangeReviewer: function(changeNum, reviewerID) {
+    addChangeReviewer(changeNum, reviewerID) {
       return this._sendChangeReviewerRequest('POST', changeNum, reviewerID);
     },
 
-    removeChangeReviewer: function(changeNum, reviewerID) {
+    removeChangeReviewer(changeNum, reviewerID) {
       return this._sendChangeReviewerRequest('DELETE', changeNum, reviewerID);
     },
 
-    _sendChangeReviewerRequest: function(method, changeNum, reviewerID) {
-      var url = this.getChangeActionURL(changeNum, null, '/reviewers');
-      var body;
+    _sendChangeReviewerRequest(method, changeNum, reviewerID) {
+      let url = this.getChangeActionURL(changeNum, null, '/reviewers');
+      let body;
       switch (method) {
         case 'POST':
           body = {reviewer: reviewerID};
@@ -592,124 +590,122 @@
       return this.send(method, url, body);
     },
 
-    getRelatedChanges: function(changeNum, patchNum) {
+    getRelatedChanges(changeNum, patchNum) {
       return this.fetchJSON(
           this.getChangeActionURL(changeNum, patchNum, '/related'));
     },
 
-    getChangesSubmittedTogether: function(changeNum) {
+    getChangesSubmittedTogether(changeNum) {
       return this.fetchJSON(
           this.getChangeActionURL(changeNum, null, '/submitted_together'));
     },
 
-    getChangeConflicts: function(changeNum) {
-      var options = this._listChangesOptionsToHex(
+    getChangeConflicts(changeNum) {
+      const options = this._listChangesOptionsToHex(
           ListChangesOption.CURRENT_REVISION,
           ListChangesOption.CURRENT_COMMIT
       );
-      var params = {
+      const params = {
         O: options,
         q: 'status:open is:mergeable conflicts:' + changeNum,
       };
       return this.fetchJSON('/changes/', null, null, params);
     },
 
-    getChangeCherryPicks: function(project, changeID, changeNum) {
-      var options = this._listChangesOptionsToHex(
+    getChangeCherryPicks(project, changeID, changeNum) {
+      const options = this._listChangesOptionsToHex(
           ListChangesOption.CURRENT_REVISION,
           ListChangesOption.CURRENT_COMMIT
       );
-      var query = [
+      const query = [
         'project:' + project,
         'change:' + changeID,
         '-change:' + changeNum,
         '-is:abandoned',
       ].join(' ');
-      var params = {
+      const params = {
         O: options,
         q: query,
       };
       return this.fetchJSON('/changes/', null, null, params);
     },
 
-    getChangesWithSameTopic: function(topic) {
-      var options = this._listChangesOptionsToHex(
+    getChangesWithSameTopic(topic) {
+      const options = this._listChangesOptionsToHex(
           ListChangesOption.LABELS,
           ListChangesOption.CURRENT_REVISION,
           ListChangesOption.CURRENT_COMMIT,
           ListChangesOption.DETAILED_LABELS
       );
-      var params = {
+      const params = {
         O: options,
         q: 'status:open topic:' + topic,
       };
       return this.fetchJSON('/changes/', null, null, params);
     },
 
-    getReviewedFiles: function(changeNum, patchNum) {
+    getReviewedFiles(changeNum, patchNum) {
       return this.fetchJSON(
           this.getChangeActionURL(changeNum, patchNum, '/files?reviewed'));
     },
 
-    saveFileReviewed: function(changeNum, patchNum, path, reviewed, opt_errFn,
-        opt_ctx) {
-      var method = reviewed ? 'PUT' : 'DELETE';
-      var url = this.getChangeActionURL(changeNum, patchNum,
+    saveFileReviewed(changeNum, patchNum, path, reviewed, opt_errFn, opt_ctx) {
+      const method = reviewed ? 'PUT' : 'DELETE';
+      const url = this.getChangeActionURL(changeNum, patchNum,
           '/files/' + encodeURIComponent(path) + '/reviewed');
 
       return this.send(method, url, null, opt_errFn, opt_ctx);
     },
 
-    saveChangeReview: function(changeNum, patchNum, review, opt_errFn,
-        opt_ctx) {
-      var url = this.getChangeActionURL(changeNum, patchNum, '/review');
+    saveChangeReview(changeNum, patchNum, review, opt_errFn, opt_ctx) {
+      const url = this.getChangeActionURL(changeNum, patchNum, '/review');
       return this.send('POST', url, review, opt_errFn, opt_ctx);
     },
 
-    getFileInChangeEdit: function(changeNum, path) {
+    getFileInChangeEdit(changeNum, path) {
       return this.send('GET',
           this.getChangeActionURL(changeNum, null,
               '/edit/' + encodeURIComponent(path)
           ));
     },
 
-    rebaseChangeEdit: function(changeNum) {
+    rebaseChangeEdit(changeNum) {
       return this.send('POST',
           this.getChangeActionURL(changeNum, null,
               '/edit:rebase'
           ));
     },
 
-    deleteChangeEdit: function(changeNum) {
+    deleteChangeEdit(changeNum) {
       return this.send('DELETE',
           this.getChangeActionURL(changeNum, null,
               '/edit'
           ));
     },
 
-    restoreFileInChangeEdit: function(changeNum, restore_path) {
+    restoreFileInChangeEdit(changeNum, restore_path) {
       return this.send('POST',
           this.getChangeActionURL(changeNum, null, '/edit'),
-          {restore_path: restore_path}
+          {restore_path}
       );
     },
 
-    renameFileInChangeEdit: function(changeNum, old_path, new_path) {
+    renameFileInChangeEdit(changeNum, old_path, new_path) {
       return this.send('POST',
           this.getChangeActionURL(changeNum, null, '/edit'),
-          {old_path: old_path},
-          {new_path: new_path}
+          {old_path},
+          {new_path}
       );
     },
 
-    deleteFileInChangeEdit: function(changeNum, path) {
+    deleteFileInChangeEdit(changeNum, path) {
       return this.send('DELETE',
           this.getChangeActionURL(changeNum, null,
               '/edit/' + encodeURIComponent(path)
           ));
     },
 
-    saveChangeEdit: function(changeNum, path, contents) {
+    saveChangeEdit(changeNum, path, contents) {
       return this.send('PUT',
           this.getChangeActionURL(changeNum, null,
               '/edit/' + encodeURIComponent(path)
@@ -718,29 +714,29 @@
       );
     },
 
-    saveChangeCommitMessageEdit: function(changeNum, message) {
-      var url = this.getChangeActionURL(changeNum, null, '/edit:message');
-      return this.send('PUT', url, {message: message});
+    saveChangeCommitMessageEdit(changeNum, message) {
+      const url = this.getChangeActionURL(changeNum, null, '/edit:message');
+      return this.send('PUT', url, {message});
     },
 
-    publishChangeEdit: function(changeNum) {
+    publishChangeEdit(changeNum) {
       return this.send('POST',
           this.getChangeActionURL(changeNum, null, '/edit:publish'));
     },
 
-    saveChangeStarred: function(changeNum, starred) {
-      var url = '/accounts/self/starred.changes/' + changeNum;
-      var method = starred ? 'PUT' : 'DELETE';
+    saveChangeStarred(changeNum, starred) {
+      const url = '/accounts/self/starred.changes/' + changeNum;
+      const method = starred ? 'PUT' : 'DELETE';
       return this.send(method, url);
     },
 
-    send: function(method, url, opt_body, opt_errFn, opt_ctx, opt_contentType) {
-      var headers = new Headers({
+    send(method, url, opt_body, opt_errFn, opt_ctx, opt_contentType) {
+      const headers = new Headers({
         'X-Gerrit-Auth': this._getCookie('XSRF_TOKEN'),
       });
-      var options = {
-        method: method,
-        headers: headers,
+      const options = {
+        method,
+        headers,
         credentials: 'same-origin',
       };
       if (opt_body) {
@@ -750,30 +746,30 @@
         }
         options.body = opt_body;
       }
-      return fetch(this.getBaseUrl() + url, options).then(function(response) {
+      return fetch(this.getBaseUrl() + url, options).then(response => {
         if (!response.ok) {
           if (opt_errFn) {
             opt_errFn.call(opt_ctx || null, response);
             return undefined;
           }
-          this.fire('server-error', {response: response});
+          this.fire('server-error', {response});
         }
 
         return response;
-      }.bind(this)).catch(function(err) {
+      }).catch(err => {
         this.fire('network-error', {error: err});
         if (opt_errFn) {
           opt_errFn.call(opt_ctx, null, err);
         } else {
           throw err;
         }
-      }.bind(this));
+      });
     },
 
-    getDiff: function(changeNum, basePatchNum, patchNum, path,
+    getDiff(changeNum, basePatchNum, patchNum, path,
         opt_errFn, opt_cancelCondition) {
-      var url = this._getDiffFetchURL(changeNum, patchNum, path);
-      var params = {
+      const url = this._getDiffFetchURL(changeNum, patchNum, path);
+      const params = {
         context: 'ALL',
         intraline: null,
         whitespace: 'IGNORE_NONE',
@@ -785,32 +781,29 @@
       return this.fetchJSON(url, opt_errFn, opt_cancelCondition, params);
     },
 
-    _getDiffFetchURL: function(changeNum, patchNum, path) {
+    _getDiffFetchURL(changeNum, patchNum, path) {
       return this._changeBaseURL(changeNum, patchNum) + '/files/' +
           encodeURIComponent(path) + '/diff';
     },
 
-    getDiffComments: function(changeNum, opt_basePatchNum, opt_patchNum,
-        opt_path) {
+    getDiffComments(changeNum, opt_basePatchNum, opt_patchNum, opt_path) {
       return this._getDiffComments(changeNum, '/comments', opt_basePatchNum,
           opt_patchNum, opt_path);
     },
 
-    getDiffRobotComments: function(changeNum, basePatchNum, patchNum,
-        opt_path) {
+    getDiffRobotComments(changeNum, basePatchNum, patchNum, opt_path) {
       return this._getDiffComments(changeNum, '/robotcomments', basePatchNum,
           patchNum, opt_path);
     },
 
-    getDiffDrafts: function(changeNum, opt_basePatchNum, opt_patchNum,
-        opt_path) {
+    getDiffDrafts(changeNum, opt_basePatchNum, opt_patchNum, opt_path) {
       return this._getDiffComments(changeNum, '/drafts', opt_basePatchNum,
           opt_patchNum, opt_path);
     },
 
-    _setRange: function(comments, comment) {
+    _setRange(comments, comment) {
       if (comment.in_reply_to && !comment.range) {
-        for (var i = 0; i < comments.length; i++) {
+        for (let i = 0; i < comments.length; i++) {
           if (comments[i].id === comment.in_reply_to) {
             comment.range = comments[i].range;
             break;
@@ -820,18 +813,18 @@
       return comment;
     },
 
-    _setRanges: function(comments) {
+    _setRanges(comments) {
       comments = comments || [];
-      comments.sort(function(a, b) {
+      comments.sort((a, b) => {
         return util.parseDate(a.updated) - util.parseDate(b.updated);
       });
-      comments.forEach(function(comment) {
+      for (const comment of comments) {
         this._setRange(comments, comment);
-      }.bind(this));
+      }
       return comments;
     },
 
-    _getDiffComments: function(changeNum, endpoint, opt_basePatchNum,
+    _getDiffComments(changeNum, endpoint, opt_basePatchNum,
         opt_patchNum, opt_path) {
       if (!opt_basePatchNum && !opt_patchNum && !opt_path) {
         return this.fetchJSON(
@@ -842,12 +835,12 @@
       function withoutParent(c) { return c.side != PARENT_PATCH_NUM; }
       function setPath(c) { c.path = opt_path; }
 
-      var promises = [];
-      var comments;
-      var baseComments;
-      var url =
+      const promises = [];
+      let comments;
+      let baseComments;
+      const url =
           this._getDiffCommentsFetchURL(changeNum, endpoint, opt_patchNum);
-      promises.push(this.fetchJSON(url).then(function(response) {
+      promises.push(this.fetchJSON(url).then(response => {
         comments = response[opt_path] || [];
 
         // TODO(kaspern): Implement this on in the backend so this can be
@@ -864,50 +857,50 @@
         comments = comments.filter(withoutParent);
 
         comments.forEach(setPath);
-      }.bind(this)));
+      }));
 
       if (opt_basePatchNum != PARENT_PATCH_NUM) {
-        var baseURL = this._getDiffCommentsFetchURL(changeNum, endpoint,
+        const baseURL = this._getDiffCommentsFetchURL(changeNum, endpoint,
             opt_basePatchNum);
-        promises.push(this.fetchJSON(baseURL).then(function(response) {
+        promises.push(this.fetchJSON(baseURL).then(response => {
           baseComments = (response[opt_path] || []).filter(withoutParent);
 
           baseComments = this._setRanges(baseComments);
 
           baseComments.forEach(setPath);
-        }.bind(this)));
+        }));
       }
 
-      return Promise.all(promises).then(function() {
+      return Promise.all(promises).then(() => {
         return Promise.resolve({
-          baseComments: baseComments,
-          comments: comments,
+          baseComments,
+          comments,
         });
       });
     },
 
-    _getDiffCommentsFetchURL: function(changeNum, endpoint, opt_patchNum) {
+    _getDiffCommentsFetchURL(changeNum, endpoint, opt_patchNum) {
       return this._changeBaseURL(changeNum, opt_patchNum) + endpoint;
     },
 
-    saveDiffDraft: function(changeNum, patchNum, draft) {
+    saveDiffDraft(changeNum, patchNum, draft) {
       return this._sendDiffDraftRequest('PUT', changeNum, patchNum, draft);
     },
 
-    deleteDiffDraft: function(changeNum, patchNum, draft) {
+    deleteDiffDraft(changeNum, patchNum, draft) {
       return this._sendDiffDraftRequest('DELETE', changeNum, patchNum, draft);
     },
 
-    hasPendingDiffDrafts: function() {
+    hasPendingDiffDrafts() {
       return !!this._pendingRequests[Requests.SEND_DIFF_DRAFT];
     },
 
-    _sendDiffDraftRequest: function(method, changeNum, patchNum, draft) {
-      var url = this.getChangeActionURL(changeNum, patchNum, '/drafts');
+    _sendDiffDraftRequest(method, changeNum, patchNum, draft) {
+      let url = this.getChangeActionURL(changeNum, patchNum, '/drafts');
       if (draft.id) {
         url += '/' + draft.id;
       }
-      var body;
+      let body;
       if (method === 'PUT') {
         body = draft;
       }
@@ -917,14 +910,14 @@
       }
       this._pendingRequests[Requests.SEND_DIFF_DRAFT]++;
 
-      return this.send(method, url, body).then(function(res) {
+      return this.send(method, url, body).then(res => {
         this._pendingRequests[Requests.SEND_DIFF_DRAFT]--;
         return res;
-      }.bind(this));
+      });
     },
 
-    _changeBaseURL: function(changeNum, opt_patchNum) {
-      var v = '/changes/' + changeNum;
+    _changeBaseURL(changeNum, opt_patchNum) {
+      let v = '/changes/' + changeNum;
       if (opt_patchNum) {
         v += '/revisions/' + opt_patchNum;
       }
@@ -933,49 +926,49 @@
 
     // Derived from
     // gerrit-extension-api/src/main/j/c/g/gerrit/extensions/client/ListChangesOption.java
-    _listChangesOptionsToHex: function() {
-      var v = 0;
-      for (var i = 0; i < arguments.length; i++) {
-        v |= 1 << arguments[i];
+    _listChangesOptionsToHex(...args) {
+      let v = 0;
+      for (let i = 0; i < args.length; i++) {
+        v |= 1 << args[i];
       }
       return v.toString(16);
     },
 
-    _getCookie: function(name) {
-      var key = name + '=';
-      var cookies = document.cookie.split(';');
-      for (var i = 0; i < cookies.length; i++) {
-        var c = cookies[i];
+    _getCookie(name) {
+      const key = name + '=';
+      const cookies = document.cookie.split(';');
+      for (let i = 0; i < cookies.length; i++) {
+        let c = cookies[i];
         while (c.charAt(0) == ' ') {
           c = c.substring(1);
         }
-        if (c.indexOf(key) == 0) {
+        if (c.startsWith(key)) {
           return c.substring(key.length, c.length);
         }
       }
       return '';
     },
 
-    getCommitInfo: function(project, commit) {
+    getCommitInfo(project, commit) {
       return this.fetchJSON(
           '/projects/' + encodeURIComponent(project) +
           '/commits/' + encodeURIComponent(commit));
     },
 
-    _fetchB64File: function(url) {
+    _fetchB64File(url) {
       return fetch(this.getBaseUrl() + url, {credentials: 'same-origin'})
-          .then(function(response) {
+          .then(response => {
             if (!response.ok) { return Promise.reject(response.statusText); }
-            var type = response.headers.get('X-FYI-Content-Type');
+            const type = response.headers.get('X-FYI-Content-Type');
             return response.text()
-              .then(function(text) {
-                return {body: text, type: type};
-              });
+                .then(text => {
+                  return {body: text, type};
+                });
           });
     },
 
-    getChangeFileContents: function(changeId, patchNum, path, opt_parentIndex) {
-      var parent = typeof opt_parentIndex === 'number' ?
+    getChangeFileContents(changeId, patchNum, path, opt_parentIndex) {
+      const parent = typeof opt_parentIndex === 'number' ?
           '?parent=' + opt_parentIndex : '';
       return this._fetchB64File(
           '/changes/' + encodeURIComponent(changeId) +
@@ -984,11 +977,11 @@
           '/content' + parent);
     },
 
-    getImagesForDiff: function(changeNum, diff, patchRange) {
-      var promiseA;
-      var promiseB;
+    getImagesForDiff(changeNum, diff, patchRange) {
+      let promiseA;
+      let promiseB;
 
-      if (diff.meta_a && diff.meta_a.content_type.indexOf('image/') === 0) {
+      if (diff.meta_a && diff.meta_a.content_type.startsWith('image/')) {
         if (patchRange.basePatchNum === 'PARENT') {
           // Note: we only attempt to get the image from the first parent.
           promiseA = this.getChangeFileContents(changeNum, patchRange.patchNum,
@@ -1001,83 +994,82 @@
         promiseA = Promise.resolve(null);
       }
 
-      if (diff.meta_b && diff.meta_b.content_type.indexOf('image/') === 0) {
+      if (diff.meta_b && diff.meta_b.content_type.startsWith('image/')) {
         promiseB = this.getChangeFileContents(changeNum, patchRange.patchNum,
             diff.meta_b.name);
       } else {
         promiseB = Promise.resolve(null);
       }
 
-      return Promise.all([promiseA, promiseB])
-        .then(function(results) {
-          var baseImage = results[0];
-          var revisionImage = results[1];
+      return Promise.all([promiseA, promiseB]).then(results => {
+        const baseImage = results[0];
+        const revisionImage = results[1];
 
-          // Sometimes the server doesn't send back the content type.
-          if (baseImage) {
-            baseImage._expectedType = diff.meta_a.content_type;
-            baseImage._name = diff.meta_a.name;
-          }
-          if (revisionImage) {
-            revisionImage._expectedType = diff.meta_b.content_type;
-            revisionImage._name = diff.meta_b.name;
-          }
+        // Sometimes the server doesn't send back the content type.
+        if (baseImage) {
+          baseImage._expectedType = diff.meta_a.content_type;
+          baseImage._name = diff.meta_a.name;
+        }
+        if (revisionImage) {
+          revisionImage._expectedType = diff.meta_b.content_type;
+          revisionImage._name = diff.meta_b.name;
+        }
 
-          return {baseImage: baseImage, revisionImage: revisionImage};
-        }.bind(this));
+        return {baseImage, revisionImage};
+      });
     },
 
-    setChangeTopic: function(changeNum, topic) {
+    setChangeTopic(changeNum, topic) {
       return this.send('PUT', '/changes/' + encodeURIComponent(changeNum) +
-          '/topic', {topic: topic});
+          '/topic', {topic});
     },
 
-    deleteAccountHttpPassword: function() {
+    deleteAccountHttpPassword() {
       return this.send('DELETE', '/accounts/self/password.http');
     },
 
-    generateAccountHttpPassword: function() {
+    generateAccountHttpPassword() {
       return this.send('PUT', '/accounts/self/password.http', {generate: true})
           .then(this.getResponseObject);
     },
 
-    getAccountSSHKeys: function() {
+    getAccountSSHKeys() {
       return this._fetchSharedCacheURL('/accounts/self/sshkeys');
     },
 
-    addAccountSSHKey: function(key) {
+    addAccountSSHKey(key) {
       return this.send('POST', '/accounts/self/sshkeys', key, null, null,
           'plain/text')
-          .then(function(response) {
+          .then(response => {
             if (response.status < 200 && response.status >= 300) {
               return Promise.reject();
             }
             return this.getResponseObject(response);
-          }.bind(this))
-          .then(function(obj) {
+          })
+          .then(obj => {
             if (!obj.valid) { return Promise.reject(); }
             return obj;
           });
     },
 
-    deleteAccountSSHKey: function(id) {
+    deleteAccountSSHKey(id) {
       return this.send('DELETE', '/accounts/self/sshkeys/' + id);
     },
 
-    deleteVote: function(changeID, account, label) {
+    deleteVote(changeID, account, label) {
       return this.send('DELETE', '/changes/' + changeID +
           '/reviewers/' + account + '/votes/' + encodeURIComponent(label));
     },
 
-    setDescription: function(changeNum, patchNum, desc) {
+    setDescription(changeNum, patchNum, desc) {
       return this.send('PUT',
           this.getChangeActionURL(changeNum, patchNum, '/description'),
           {description: desc});
     },
 
-    confirmEmail: function(token) {
-      return this.send('PUT', '/config/server/email.confirm', {token: token})
-          .then(function(response) {
+    confirmEmail(token) {
+      return this.send('PUT', '/config/server/email.confirm', {token})
+          .then(response => {
             if (response.status === 204) {
               return 'Email confirmed successfully.';
             }
@@ -1085,39 +1077,39 @@
           });
     },
 
-    setAssignee: function(changeNum, assignee) {
+    setAssignee(changeNum, assignee) {
       return this.send('PUT',
           this.getChangeActionURL(changeNum, null, '/assignee'),
-          {assignee: assignee});
+          {assignee});
     },
 
-    deleteAssignee: function(changeNum) {
+    deleteAssignee(changeNum) {
       return this.send('DELETE',
           this.getChangeActionURL(changeNum, null, '/assignee'));
     },
 
-    probePath: function(path) {
+    probePath(path) {
       return fetch(new Request(path, {method: 'HEAD'}))
-        .then(function(response) {
-          return response.ok;
-        });
+          .then(response => {
+            return response.ok;
+          });
     },
 
-    startWorkInProgress: function(changeNum, opt_message) {
-      var payload = {};
+    startWorkInProgress(changeNum, opt_message) {
+      const payload = {};
       if (opt_message) {
         payload.message = opt_message;
       }
-      var url = this.getChangeActionURL(changeNum, null, '/wip');
+      const url = this.getChangeActionURL(changeNum, null, '/wip');
       return this.send('POST', url, payload)
-          .then(function(response) {
+          .then(response => {
             if (response.status === 204) {
               return 'Change marked as Work In Progress.';
             }
           });
     },
 
-    startReview: function(changeNum, review) {
+    startReview(changeNum, review) {
       return this.send(
           'POST', this.getChangeActionURL(changeNum, null, '/ready'), review);
     },
diff --git a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface_test.html b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface_test.html
index 933b4f4..1ff27d8 100644
--- a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface_test.html
@@ -614,7 +614,7 @@
       );
     });
 
-    test('startWorkInProgress', function() {
+    test('startWorkInProgress', () => {
       sandbox.stub(element, 'send').returns(Promise.resolve('ok'));
       element.startWorkInProgress('42');
       assert.isTrue(element.send.calledWith(
@@ -624,7 +624,7 @@
           'POST', '/changes/42/wip', {message: 'revising...'}));
     });
 
-    test('startReview', function() {
+    test('startReview', () => {
       sandbox.stub(element, 'send').returns(Promise.resolve({}));
       element.startReview('42', {message: 'Please review.'});
       assert.isTrue(element.send.calledWith(
diff --git a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-reviewer-updates-parser.js b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-reviewer-updates-parser.js
index 21a6bc6..4f8deab 100644
--- a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-reviewer-updates-parser.js
+++ b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-reviewer-updates-parser.js
@@ -21,7 +21,7 @@
     // TODO (viktard): Polyfill Object.assign for IE.
     this.result = Object.assign({}, change);
     this._lastState = {};
-  };
+  }
 
   GrReviewerUpdatesParser.parse = function(change) {
     if (!change ||
@@ -30,7 +30,7 @@
         !change.reviewer_updates.length) {
       return change;
     }
-    var parser = new GrReviewerUpdatesParser(change);
+    const parser = new GrReviewerUpdatesParser(change);
     parser._filterRemovedMessages();
     parser._groupUpdates();
     parser._formatUpdates();
@@ -49,7 +49,7 @@
    * are used.
    */
   GrReviewerUpdatesParser.prototype._filterRemovedMessages = function() {
-    this.result.messages = this.result.messages.filter(function(message) {
+    this.result.messages = this.result.messages.filter(message => {
       return message.tag !== 'autogenerated:gerrit:deleteReviewer';
     });
   };
@@ -74,10 +74,10 @@
    * @param {Object} update instance of ReviewerUpdateInfo
    */
   GrReviewerUpdatesParser.prototype._completeBatch = function(update) {
-    var items = [];
-    for (var accountId in this._updateItems) {
+    const items = [];
+    for (const accountId in this._updateItems) {
       if (!this._updateItems.hasOwnProperty(accountId)) continue;
-      var updateItem = this._updateItems[accountId];
+      const updateItem = this._updateItems[accountId];
       if (this._lastState[accountId] !== updateItem.state) {
         this._lastState[accountId] = updateItem.state;
         items.push(updateItem);
@@ -96,14 +96,14 @@
    * - Groups with no-change updates are discarded (eg CC -> CC)
    */
   GrReviewerUpdatesParser.prototype._groupUpdates = function() {
-    var updates = this.result.reviewer_updates;
-    var newUpdates = updates.reduce(function(newUpdates, update) {
+    const updates = this.result.reviewer_updates;
+    const newUpdates = updates.reduce((newUpdates, update) => {
       if (!this._batch) {
         this._batch = this._startBatch(update);
       }
-      var updateDate = util.parseDate(update.updated).getTime();
-      var batchUpdateDate = util.parseDate(this._batch.date).getTime();
-      var reviewerId = update.reviewer._account_id.toString();
+      const updateDate = util.parseDate(update.updated).getTime();
+      const batchUpdateDate = util.parseDate(this._batch.date).getTime();
+      const reviewerId = update.reviewer._account_id.toString();
       if (updateDate - batchUpdateDate >
           GrReviewerUpdatesParser.REVIEWER_UPDATE_THRESHOLD_MILLIS ||
           update.updated_by._account_id !== this._batch.author._account_id) {
@@ -122,7 +122,7 @@
         this._updateItems[reviewerId].prev_state = this._lastState[reviewerId];
       }
       return newUpdates;
-    }.bind(this), []);
+    }, []);
     this._completeBatch();
     if (this._batch.updates && this._batch.updates.length) {
       newUpdates.push(this._batch);
@@ -157,14 +157,14 @@
    * @return {!Object} Hash of arrays of AccountInfo, message as key.
    */
   GrReviewerUpdatesParser.prototype._groupUpdatesByMessage = function(updates) {
-    return updates.reduce(function(result, item) {
-      var message = this._getUpdateMessage(item.prev_state, item.state);
+    return updates.reduce((result, item) => {
+      const message = this._getUpdateMessage(item.prev_state, item.state);
       if (!result[message]) {
         result[message] = [];
       }
       result[message].push(item.reviewer);
       return result;
-    }.bind(this), {});
+    }, {});
   };
 
   /**
@@ -173,21 +173,20 @@
    * @see https://gerrit-review.googlesource.com/c/94490/
    */
   GrReviewerUpdatesParser.prototype._formatUpdates = function() {
-    this.result.reviewer_updates.forEach(function(update) {
-      var grouppedReviewers = this._groupUpdatesByMessage(update.updates);
-      var newUpdates = [];
-      for (var message in grouppedReviewers) {
+    for (const update of this.result.reviewer_updates) {
+      const grouppedReviewers = this._groupUpdatesByMessage(update.updates);
+      const newUpdates = [];
+      for (const message in grouppedReviewers) {
         if (grouppedReviewers.hasOwnProperty(message)) {
           newUpdates.push({
-            message: message,
+            message,
             reviewers: grouppedReviewers[message],
           });
         }
       }
       update.updates = newUpdates;
-    }.bind(this));
+    }
   };
 
   window.GrReviewerUpdatesParser = GrReviewerUpdatesParser;
-
 })(window);
diff --git a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/mock-diff-response_test.html b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/mock-diff-response_test.html
index 8141c8a..0385f64 100644
--- a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/mock-diff-response_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/mock-diff-response_test.html
@@ -22,44 +22,44 @@
     (function() {
       'use strict';
 
-      var RESPONSE = {
-        'meta_a': {
-          'name': 'lorem-ipsum.txt',
-          'content_type': 'text/plain',
-          'lines': 45,
+      const RESPONSE = {
+        meta_a: {
+          name: 'lorem-ipsum.txt',
+          content_type: 'text/plain',
+          lines: 45,
         },
-        'meta_b': {
-          'name': 'lorem-ipsum.txt',
-          'content_type': 'text/plain',
-          'lines': 48,
+        meta_b: {
+          name: 'lorem-ipsum.txt',
+          content_type: 'text/plain',
+          lines: 48,
         },
-        'intraline_status': 'OK',
-        'change_type': 'MODIFIED',
-        'diff_header': [
+        intraline_status: 'OK',
+        change_type: 'MODIFIED',
+        diff_header: [
           'diff --git a/lorem-ipsum.txt b/lorem-ipsum.txt',
           'index b2adcf4..554ae49 100644',
           '--- a/lorem-ipsum.txt',
           '+++ b/lorem-ipsum.txt',
         ],
-        'content': [
+        content: [
           {
-            'ab': [
+            ab: [
               'Lorem ipsum dolor sit amet, suspendisse inceptos vehicula, ' +
                 'nulla phasellus.',
               'Mattis lectus.',
               'Sodales duis.',
               'Orci a faucibus.',
-            ]
+            ],
           },
           {
-            'b': [
+            b: [
               'Nullam neque, ligula ac, id blandit.',
               'Sagittis tincidunt torquent, tempor nunc amet.',
               'At rhoncus id.',
             ],
           },
           {
-            'ab': [
+            ab: [
               'Sem nascetur, erat ut, non in.',
               'A donec, venenatis pellentesque dis.',
               'Mauris mauris.',
@@ -68,7 +68,7 @@
             ],
           },
           {
-            'a': [
+            a: [
               'Est amet, vestibulum pellentesque.',
               'Erat ligula.',
               'Justo eros.',
@@ -76,25 +76,25 @@
             ],
           },
           {
-            'ab': [
+            ab: [
               'Arcu eget, rhoncus amet cursus, ipsum elementum.',
               'Eros suspendisse.',
             ],
           },
           {
-            'a': [
+            a: [
               'Rhoncus tempor, ultricies aliquam ipsum.',
             ],
-            'b': [
+            b: [
               'Rhoncus tempor, ultricies praesent ipsum.',
             ],
-            'edit_a': [
+            edit_a: [
               [
                 26,
                 7,
               ],
             ],
-            'edit_b': [
+            edit_b: [
               [
                 26,
                 8,
@@ -102,7 +102,7 @@
             ],
           },
           {
-            'ab': [
+            ab: [
               'Sollicitudin duis.',
               'Blandit blandit, ante nisl fusce.',
               'Felis ac at, tellus consectetuer.',
@@ -131,7 +131,7 @@
             ],
           },
           {
-            'b': [
+            b: [
               'Eu congue risus.',
               'Enim ac, quis elementum.',
               'Non et elit.',
@@ -139,7 +139,7 @@
             ],
           },
           {
-            'ab': [
+            ab: [
               'Nec at.',
               'Arcu mauris, venenatis lacus fermentum, praesent duis.',
               'Pellentesque amet et, tellus duis.',
@@ -155,7 +155,7 @@
         properties: {
           diffResponse: {
             type: Object,
-            value: function() {
+            value() {
               return RESPONSE;
             },
           },
diff --git a/polygerrit-ui/app/elements/shared/gr-select/gr-select.js b/polygerrit-ui/app/elements/shared/gr-select/gr-select.js
index bef260e9..09787cb 100644
--- a/polygerrit-ui/app/elements/shared/gr-select/gr-select.js
+++ b/polygerrit-ui/app/elements/shared/gr-select/gr-select.js
@@ -26,21 +26,21 @@
     },
 
     listeners: {
-      change: '_valueChanged',
+      'change': '_valueChanged',
       'dom-change': '_updateValue',
     },
 
-    _updateValue: function() {
+    _updateValue() {
       if (this.bindValue) {
         this.value = this.bindValue;
       }
     },
 
-    _valueChanged: function() {
+    _valueChanged() {
       this.bindValue = this.value;
     },
 
-    ready: function() {
+    ready() {
       // If not set via the property, set bind-value to the element value.
       if (!this.bindValue) { this.bindValue = this.value; }
     },
diff --git a/polygerrit-ui/app/elements/shared/gr-select/gr-select_test.html b/polygerrit-ui/app/elements/shared/gr-select/gr-select_test.html
index bd22505..83ae5af 100644
--- a/polygerrit-ui/app/elements/shared/gr-select/gr-select_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-select/gr-select_test.html
@@ -36,15 +36,15 @@
 </test-fixture>
 
 <script>
-  suite('gr-select tests', function() {
-    var element;
+  suite('gr-select tests', () => {
+    let element;
 
-    setup(function() {
+    setup(() => {
       element = fixture('basic');
     });
 
-    test('bidirectional binding property-to-attribute', function() {
-      var changeStub = sinon.stub();
+    test('bidirectional binding property-to-attribute', () => {
+      const changeStub = sinon.stub();
       element.addEventListener('bind-value-changed', changeStub);
 
       // The selected element should be the first one by default.
@@ -61,8 +61,8 @@
       assert.isTrue(changeStub.called);
     });
 
-    test('bidirectional binding attribute-to-property', function() {
-      var changeStub = sinon.stub();
+    test('bidirectional binding attribute-to-property', () => {
+      const changeStub = sinon.stub();
       element.addEventListener('bind-value-changed', changeStub);
 
       // The selected element should be the first one by default.
diff --git a/polygerrit-ui/app/elements/shared/gr-storage/gr-storage.js b/polygerrit-ui/app/elements/shared/gr-storage/gr-storage.js
index 77d1c05..2e7f17c 100644
--- a/polygerrit-ui/app/elements/shared/gr-storage/gr-storage.js
+++ b/polygerrit-ui/app/elements/shared/gr-storage/gr-storage.js
@@ -15,10 +15,10 @@
   'use strict';
 
   // Date cutoff is one day:
-  var DRAFT_MAX_AGE = 24 * 60 * 60 * 1000;
+  const DRAFT_MAX_AGE = 24 * 60 * 60 * 1000;
 
   // Clean up old entries no more frequently than one day.
-  var CLEANUP_THROTTLE_INTERVAL = 24 * 60 * 60 * 1000;
+  const CLEANUP_THROTTLE_INTERVAL = 24 * 60 * 60 * 1000;
 
   Polymer({
     is: 'gr-storage',
@@ -27,7 +27,7 @@
       _lastCleanup: Number,
       _storage: {
         type: Object,
-        value: function() {
+        value() {
           return window.localStorage;
         },
       },
@@ -37,42 +37,43 @@
       },
     },
 
-    getDraftComment: function(location) {
+    getDraftComment(location) {
       this._cleanupDrafts();
       return this._getObject(this._getDraftKey(location));
     },
 
-    setDraftComment: function(location, message) {
-      var key = this._getDraftKey(location);
-      this._setObject(key, {message: message, updated: Date.now()});
+    setDraftComment(location, message) {
+      const key = this._getDraftKey(location);
+      this._setObject(key, {message, updated: Date.now()});
     },
 
-    eraseDraftComment: function(location) {
-      var key = this._getDraftKey(location);
+    eraseDraftComment(location) {
+      const key = this._getDraftKey(location);
       this._storage.removeItem(key);
     },
 
-    getPreferences: function() {
+    getPreferences() {
       return this._getObject('localPrefs');
     },
 
-    savePreferences: function(localPrefs) {
+    savePreferences(localPrefs) {
       this._setObject('localPrefs', localPrefs || null);
     },
 
-    _getDraftKey: function(location) {
-      var range = location.range ? location.range.start_line + '-' +
-          location.range.start_character + '-' + location.range.end_character +
-          '-' + location.range.end_line : null;
-      var key = ['draft', location.changeNum, location.patchNum, location.path,
-          location.line || ''].join(':');
+    _getDraftKey(location) {
+      const range = location.range ?
+          `${location.range.start_line}-${location.range.start_character}` +
+              `-${location.range.end_character}-${location.range.end_line}` :
+          null;
+      let key = ['draft', location.changeNum, location.patchNum, location.path,
+        location.line || ''].join(':');
       if (range) {
         key = key + ':' + range;
       }
       return key;
     },
 
-    _cleanupDrafts: function() {
+    _cleanupDrafts() {
       // Throttle cleanup to the throttle interval.
       if (this._lastCleanup &&
           Date.now() - this._lastCleanup < CLEANUP_THROTTLE_INTERVAL) {
@@ -80,9 +81,9 @@
       }
       this._lastCleanup = Date.now();
 
-      var draft;
-      for (var key in this._storage) {
-        if (key.indexOf('draft:') === 0) {
+      let draft;
+      for (const key in this._storage) {
+        if (key.startsWith('draft:')) {
           draft = this._getObject(key);
           if (Date.now() - draft.updated > DRAFT_MAX_AGE) {
             this._storage.removeItem(key);
@@ -91,13 +92,13 @@
       }
     },
 
-    _getObject: function(key) {
-      var serial = this._storage.getItem(key);
+    _getObject(key) {
+      const serial = this._storage.getItem(key);
       if (!serial) { return null; }
       return JSON.parse(serial);
     },
 
-    _setObject: function(key, obj) {
+    _setObject(key, obj) {
       if (this._exceededQuota) { return; }
       try {
         this._storage.setItem(key, JSON.stringify(obj));
diff --git a/polygerrit-ui/app/elements/shared/gr-storage/gr-storage_test.html b/polygerrit-ui/app/elements/shared/gr-storage/gr-storage_test.html
index 6d77c55..4171939 100644
--- a/polygerrit-ui/app/elements/shared/gr-storage/gr-storage_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-storage/gr-storage_test.html
@@ -31,43 +31,44 @@
 </test-fixture>
 
 <script>
-  suite('gr-storage tests', function() {
-    var element;
+  suite('gr-storage tests', () => {
+    let element;
 
     function mockStorage(opt_quotaExceeded) {
       return {
-        getItem: function(key) { return this[key]; },
-        removeItem: function(key) { delete this[key]; },
-        setItem: function(key, value) {
+        getItem(key) { return this[key]; },
+        removeItem(key) { delete this[key]; },
+        setItem(key, value) {
+          // eslint-disable-next-line no-throw-literal
           if (opt_quotaExceeded) { throw {code: 22}; /* Quota exceeded */ }
           this[key] = value;
         },
       };
     }
 
-    setup(function() {
+    setup(() => {
       element = fixture('basic');
       element._storage = mockStorage();
     });
 
-    test('storing, retrieving and erasing drafts', function() {
-      var changeNum = 1234;
-      var patchNum = 5;
-      var path = 'my_source_file.js';
-      var line = 123;
-      var location = {
-        changeNum: changeNum,
-        patchNum: patchNum,
-        path: path,
-        line: line,
+    test('storing, retrieving and erasing drafts', () => {
+      const changeNum = 1234;
+      const patchNum = 5;
+      const path = 'my_source_file.js';
+      const line = 123;
+      const location = {
+        changeNum,
+        patchNum,
+        path,
+        line,
       };
 
       // The key is in the expected format.
-      var key = element._getDraftKey(location);
+      const key = element._getDraftKey(location);
       assert.equal(key, ['draft', changeNum, patchNum, path, line].join(':'));
 
       // There should be no draft initially.
-      var draft = element.getDraftComment(location);
+      const draft = element.getDraftComment(location);
       assert.isNotOk(draft);
 
       // Setting the draft stores it under the expected key.
@@ -82,24 +83,24 @@
       assert.isNotOk(element._storage.getItem(key));
     });
 
-    test('automatically removes old drafts', function() {
-      var changeNum = 1234;
-      var patchNum = 5;
-      var path = 'my_source_file.js';
-      var line = 123;
-      var location = {
-        changeNum: changeNum,
-        patchNum: patchNum,
-        path: path,
-        line: line,
+    test('automatically removes old drafts', () => {
+      const changeNum = 1234;
+      const patchNum = 5;
+      const path = 'my_source_file.js';
+      const line = 123;
+      const location = {
+        changeNum,
+        patchNum,
+        path,
+        line,
       };
 
-      var key = element._getDraftKey(location);
+      const key = element._getDraftKey(location);
 
       // Make sure that the call to cleanup doesn't get throttled.
       element._lastCleanup = 0;
 
-      var cleanupSpy = sinon.spy(element, '_cleanupDrafts');
+      const cleanupSpy = sinon.spy(element, '_cleanupDrafts');
 
       // Create a message with a timestamp that is a second behind the max age.
       element._storage.setItem(key, JSON.stringify({
@@ -108,7 +109,7 @@
       }));
 
       // Getting the draft should cause it to be removed.
-      var draft = element.getDraftComment(location);
+      const draft = element.getDraftComment(location);
 
       assert.isTrue(cleanupSpy.called);
       assert.isNotOk(draft);
@@ -117,18 +118,18 @@
       cleanupSpy.restore();
     });
 
-    test('_getDraftKey', function() {
-      var changeNum = 1234;
-      var patchNum = 5;
-      var path = 'my_source_file.js';
-      var line = 123;
-      var location = {
-        changeNum: changeNum,
-        patchNum: patchNum,
-        path: path,
-        line: line,
+    test('_getDraftKey', () => {
+      const changeNum = 1234;
+      const patchNum = 5;
+      const path = 'my_source_file.js';
+      const line = 123;
+      const location = {
+        changeNum,
+        patchNum,
+        path,
+        line,
       };
-      var expectedResult = 'draft:1234:5:my_source_file.js:123';
+      let expectedResult = 'draft:1234:5:my_source_file.js:123';
       assert.equal(element._getDraftKey(location), expectedResult);
       location.range = {
         start_character: 1,
@@ -140,21 +141,21 @@
       assert.equal(element._getDraftKey(location), expectedResult);
     });
 
-    test('exceeded quota disables storage', function() {
+    test('exceeded quota disables storage', () => {
       element._storage = mockStorage(true);
       assert.isFalse(element._exceededQuota);
 
-      var changeNum = 1234;
-      var patchNum = 5;
-      var path = 'my_source_file.js';
-      var line = 123;
-      var location = {
-        changeNum: changeNum,
-        patchNum: patchNum,
-        path: path,
-        line: line,
+      const changeNum = 1234;
+      const patchNum = 5;
+      const path = 'my_source_file.js';
+      const line = 123;
+      const location = {
+        changeNum,
+        patchNum,
+        path,
+        line,
       };
-      var key = element._getDraftKey(location);
+      const key = element._getDraftKey(location);
       element.setDraftComment(location, 'my comment');
       assert.isTrue(element._exceededQuota);
       assert.isNotOk(element._storage.getItem(key));
diff --git a/polygerrit-ui/app/elements/shared/gr-tooltip-content/gr-tooltip-content_test.html b/polygerrit-ui/app/elements/shared/gr-tooltip-content/gr-tooltip-content_test.html
index aac2ea8..35c9a61 100644
--- a/polygerrit-ui/app/elements/shared/gr-tooltip-content/gr-tooltip-content_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-tooltip-content/gr-tooltip-content_test.html
@@ -32,18 +32,18 @@
 </test-fixture>
 
 <script>
-  suite('gr-tooltip-content tests', function() {
-    var element;
-    setup(function() {
+  suite('gr-tooltip-content tests', () => {
+    let element;
+    setup(() => {
       element = fixture('basic');
     });
 
-    test('icon is not visible by default', function() {
+    test('icon is not visible by default', () => {
       assert.equal(Polymer.dom(element.root)
           .querySelector('.arrow').hidden, true);
     });
 
-    test('icon is visible with showIcon property', function() {
+    test('icon is visible with showIcon property', () => {
       element.showIcon = true;
       assert.equal(Polymer.dom(element.root)
           .querySelector('.arrow').hidden, false);
diff --git a/polygerrit-ui/app/elements/shared/gr-tooltip/gr-tooltip.js b/polygerrit-ui/app/elements/shared/gr-tooltip/gr-tooltip.js
index 4a5f631..30038e4 100644
--- a/polygerrit-ui/app/elements/shared/gr-tooltip/gr-tooltip.js
+++ b/polygerrit-ui/app/elements/shared/gr-tooltip/gr-tooltip.js
@@ -25,7 +25,7 @@
       },
     },
 
-    _updateWidth: function(maxWidth) {
+    _updateWidth(maxWidth) {
       this.customStyle['--tooltip-max-width'] = maxWidth;
       this.updateStyles();
     },
diff --git a/polygerrit-ui/app/elements/shared/gr-tooltip/gr-tooltip_test.html b/polygerrit-ui/app/elements/shared/gr-tooltip/gr-tooltip_test.html
index 69a5b75..efc2a00 100644
--- a/polygerrit-ui/app/elements/shared/gr-tooltip/gr-tooltip_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-tooltip/gr-tooltip_test.html
@@ -32,13 +32,13 @@
 </test-fixture>
 
 <script>
-  suite('gr-tooltip tests', function() {
-    var element;
-    setup(function() {
+  suite('gr-tooltip tests', () => {
+    let element;
+    setup(() => {
       element = fixture('basic');
     });
 
-    test('max-width is respected if set', function() {
+    test('max-width is respected if set', () => {
       element.text = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit' +
           ', sed do eiusmod tempor incididunt ut labore et dolore magna aliqua';
       element.maxWidth = '50px';
diff --git a/polygerrit-ui/app/elements/test/plugin.html b/polygerrit-ui/app/elements/test/plugin.html
index 4efd6cf..cc4f3c3 100644
--- a/polygerrit-ui/app/elements/test/plugin.html
+++ b/polygerrit-ui/app/elements/test/plugin.html
@@ -1,8 +1,8 @@
 <dom-module id="my-plugin">
   <script>
-    Gerrit.install(function(plugin) {
-        plugin.registerStyleModule('app-theme', 'myplugin-app-theme');
-    });
+    Gerrit.install(plugin =>
+      plugin.registerStyleModule('app-theme', 'myplugin-app-theme');
+    );
   </script>
 </dom-module>
 
diff --git a/polygerrit-ui/app/scripts/hiddenscroll.js b/polygerrit-ui/app/scripts/hiddenscroll.js
new file mode 100644
index 0000000..bb9a160
--- /dev/null
+++ b/polygerrit-ui/app/scripts/hiddenscroll.js
@@ -0,0 +1,29 @@
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+(function(window) {
+  window.Gerrit = window.Gerrit || {};
+  if (window.Gerrit.hasOwnProperty('hiddenscroll')) { return; }
+
+  window.Gerrit.hiddenscroll = undefined;
+
+  window.addEventListener('WebComponentsReady', function() {
+    var elem = document.createElement('div');
+    elem.setAttribute(
+      'style', 'width:100px;height:100px;overflow:scroll');
+    document.body.appendChild(elem);
+    window.Gerrit.hiddenscroll = elem.offsetWidth === elem.clientWidth;
+    elem.remove();
+  });
+})(window);