Merge "Apply special file sorting to gr-comment-list"
diff --git a/polygerrit-ui/app/behaviors/gr-path-list-behavior.html b/polygerrit-ui/app/behaviors/gr-path-list-behavior.html
new file mode 100644
index 0000000..fefecd4
--- /dev/null
+++ b/polygerrit-ui/app/behaviors/gr-path-list-behavior.html
@@ -0,0 +1,61 @@
+<!--
+Copyright (C) 2016 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.
+-->
+<script>
+(function(window) {
+  'use strict';
+
+  /** @polymerBehavior Gerrit.PathListBehavior */
+  var PathListBehavior = {
+    specialFilePathCompare: function(a, b) {
+      var COMMIT_MESSAGE_PATH = '/COMMIT_MSG';
+      // The commit message always goes first.
+      if (a === COMMIT_MESSAGE_PATH) {
+        return -1;
+      }
+      if (b === COMMIT_MESSAGE_PATH) {
+        return 1;
+      }
+
+      var aLastDotIndex = a.lastIndexOf('.');
+      var aExt = a.substr(aLastDotIndex + 1);
+      var aFile = a.substr(0, aLastDotIndex);
+
+      var bLastDotIndex = b.lastIndexOf('.');
+      var bExt = b.substr(bLastDotIndex + 1);
+      var bFile = b.substr(0, bLastDotIndex);
+
+      // Sort header files above others with the same base name.
+      var headerExts = ['h', 'hxx', 'hpp'];
+      if (aFile.length > 0 && aFile === bFile) {
+        if (headerExts.indexOf(aExt) !== -1 &&
+            headerExts.indexOf(bExt) !== -1) {
+          return a.localeCompare(b);
+        }
+        if (headerExts.indexOf(aExt) !== -1) {
+          return -1;
+        }
+        if (headerExts.indexOf(bExt) !== -1) {
+          return 1;
+        }
+      }
+      return aFile.localeCompare(bFile) || a.localeCompare(b);
+    },
+  };
+
+  window.Gerrit = window.Gerrit || {};
+  window.Gerrit.PathListBehavior = PathListBehavior;
+})(window);
+</script>
diff --git a/polygerrit-ui/app/elements/change/gr-comment-list/gr-comment-list.html b/polygerrit-ui/app/elements/change/gr-comment-list/gr-comment-list.html
index f58f762..d462c12 100644
--- a/polygerrit-ui/app/elements/change/gr-comment-list/gr-comment-list.html
+++ b/polygerrit-ui/app/elements/change/gr-comment-list/gr-comment-list.html
@@ -14,6 +14,7 @@
 limitations under the License.
 -->
 
+<link rel="import" href="../../../behaviors/gr-path-list-behavior.html">
 <link rel="import" href="../../../bower_components/polymer/polymer.html">
 <link rel="import" href="../../shared/gr-linked-text/gr-linked-text.html">
 
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 0362089..1adfb01 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
@@ -16,6 +16,7 @@
 
   Polymer({
     is: 'gr-comment-list',
+    behaviors: [Gerrit.PathListBehavior],
 
     properties: {
       changeNum: Number,
@@ -25,7 +26,8 @@
     },
 
     _computeFilesFromComments: function(comments) {
-      return Object.keys(comments || {}).sort();
+      var arr = Object.keys(comments || {});
+      return arr.sort(this.specialFilePathCompare);
     },
 
     _computeFileDiffURL: function(file, changeNum, patchNum) {
@@ -56,6 +58,6 @@
         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 56a927b..a132d43 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
@@ -36,9 +36,21 @@
       element = fixture('basic');
     });
 
-    test('_computeFilesFromComments', function() {
-      var comments = {'file_b.html': [], 'file_c.css': [], 'file_a.js': []};
-      var expected = ['file_a.js', 'file_b.html', 'file_c.css'];
+    test('_computeFilesFromComments w/ special file path sorting', function() {
+      var comments = {
+        'file_b.html': [],
+        'file_c.css': [],
+        'file_a.js': [],
+        'test.cc': [],
+        'test.h': [],
+      };
+      var expected = [
+        'file_a.js',
+        'file_b.html',
+        'file_c.css',
+        'test.h',
+        'test.cc'
+      ];
       var actual = element._computeFilesFromComments(comments);
       assert.deepEqual(actual, expected);
 
diff --git a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.html b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.html
index 4980cba..d823f8c 100644
--- a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.html
+++ b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.html
@@ -14,6 +14,7 @@
 limitations under the License.
 -->
 
+<link rel="import" href="../../../behaviors/gr-path-list-behavior.html">
 <link rel="import" href="../../../bower_components/polymer/polymer.html">
 <script src="../../../bower_components/es6-promise/dist/es6-promise.min.js"></script>
 <script src="../../../bower_components/fetch/fetch.js"></script>
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 ab497c1..5eb6e35 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
@@ -67,6 +67,7 @@
 
   Polymer({
     is: 'gr-rest-api-interface',
+    behaviors: [Gerrit.PathListBehavior],
 
     /**
      * Fired when an server error occurs.
@@ -395,13 +396,12 @@
 
     getChangeFilePathsAsSpeciallySortedArray: function(changeNum, patchRange) {
       return this.getChangeFiles(changeNum, patchRange).then(function(files) {
-        return Object.keys(files).sort(this._specialFilePathCompare.bind(this));
+        return Object.keys(files).sort(this.specialFilePathCompare);
       }.bind(this));
     },
 
     _normalizeChangeFilesResponse: function(response) {
-      var paths = Object.keys(response).sort(
-          this._specialFilePathCompare.bind(this));
+      var paths = Object.keys(response).sort(this.specialFilePathCompare);
       var files = [];
       for (var i = 0; i < paths.length; i++) {
         var info = response[paths[i]];
@@ -413,41 +413,6 @@
       return files;
     },
 
-    _specialFilePathCompare: function(a, b) {
-      var COMMIT_MESSAGE_PATH = '/COMMIT_MSG';
-      // The commit message always goes first.
-      if (a === COMMIT_MESSAGE_PATH) {
-        return -1;
-      }
-      if (b === COMMIT_MESSAGE_PATH) {
-        return 1;
-      }
-
-      var aLastDotIndex = a.lastIndexOf('.');
-      var aExt = a.substr(aLastDotIndex + 1);
-      var aFile = a.substr(0, aLastDotIndex);
-
-      var bLastDotIndex = b.lastIndexOf('.');
-      var bExt = b.substr(bLastDotIndex + 1);
-      var bFile = b.substr(0, bLastDotIndex);
-
-      // Sort header files above others with the same base name.
-      var headerExts = ['h', 'hxx', 'hpp'];
-      if (aFile.length > 0 && aFile === bFile) {
-        if (headerExts.indexOf(aExt) !== -1 &&
-            headerExts.indexOf(bExt) !== -1) {
-          return a.localeCompare(b);
-        }
-        if (headerExts.indexOf(aExt) !== -1) {
-          return -1;
-        }
-        if (headerExts.indexOf(bExt) !== -1) {
-          return 1;
-        }
-      }
-      return aFile.localeCompare(bFile) || a.localeCompare(b);
-    },
-
     getChangeRevisionActions: function(changeNum, patchNum) {
       return this.fetchJSON(
           this.getChangeActionURL(changeNum, patchNum, '/actions')).then(
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 c340ee3..ecd1a07 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
@@ -215,27 +215,27 @@
     test('special file path sorting', function() {
       assert.deepEqual(
           ['.b', '/COMMIT_MSG', '.a', 'file'].sort(
-              element._specialFilePathCompare),
+              element.specialFilePathCompare),
           ['/COMMIT_MSG', '.a', '.b', 'file']);
 
       assert.deepEqual(
           ['.b', '/COMMIT_MSG', 'foo/bar/baz.cc', 'foo/bar/baz.h'].sort(
-              element._specialFilePathCompare),
+              element.specialFilePathCompare),
           ['/COMMIT_MSG', '.b', 'foo/bar/baz.h', 'foo/bar/baz.cc']);
 
       assert.deepEqual(
           ['.b', '/COMMIT_MSG', 'foo/bar/baz.cc', 'foo/bar/baz.hpp'].sort(
-              element._specialFilePathCompare),
+              element.specialFilePathCompare),
           ['/COMMIT_MSG', '.b', 'foo/bar/baz.hpp', 'foo/bar/baz.cc']);
 
       assert.deepEqual(
           ['.b', '/COMMIT_MSG', 'foo/bar/baz.cc', 'foo/bar/baz.hxx'].sort(
-              element._specialFilePathCompare),
+              element.specialFilePathCompare),
           ['/COMMIT_MSG', '.b', 'foo/bar/baz.hxx', 'foo/bar/baz.cc']);
 
       assert.deepEqual(
           ['foo/bar.h', 'foo/bar.hxx', 'foo/bar.hpp'].sort(
-              element._specialFilePathCompare),
+              element.specialFilePathCompare),
           ['foo/bar.h', 'foo/bar.hpp', 'foo/bar.hxx']);
 
       // Regression test for Issue 4448.
@@ -245,7 +245,7 @@
           'minidump/minidump_thread_writer.cc',
           'minidump/minidump_thread_writer.h',
           ]
-        .sort(element._specialFilePathCompare),
+        .sort(element.specialFilePathCompare),
           [
             'minidump/minidump_memory_writer.h',
             'minidump/minidump_memory_writer.cc',
@@ -258,7 +258,7 @@
           'task_test.go',
           'task.go',
           ]
-        .sort(element._specialFilePathCompare),
+        .sort(element.specialFilePathCompare),
           [
             'task.go',
             'task_test.go',