Add support for inline diffs

Bug: Issue 4003
Change-Id: Iadb610616c29c4b308155d9f3bee3b5224096025
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 b7dd078..9a7537b 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
@@ -277,6 +277,7 @@
           comments="[[_comments]]"
           drafts="[[_diffDrafts]]"
           revisions="[[_change.revisions]]"
+          projectConfig="[[projectConfig]]"
           selected-index="{{viewState.selectedFileIndex}}"></gr-file-list>
       <gr-messages-list id="messageList"
           change-num="[[_changeNum]]"
diff --git a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.html b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.html
index 7ce687c..90b60cf 100644
--- a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.html
+++ b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.html
@@ -16,6 +16,8 @@
 
 <link rel="import" href="../../../bower_components/polymer/polymer.html">
 <link rel="import" href="../../../behaviors/keyboard-shortcut-behavior.html">
+<link rel="import" href="../../diff/gr-diff/gr-diff.html">
+<link rel="import" href="../../shared/gr-button/gr-button.html">
 <link rel="import" href="../../shared/gr-rest-api-interface/gr-rest-api-interface.html">
 
 <dom-module id="gr-file-list">
@@ -34,7 +36,7 @@
         justify-content: space-between;
         margin-bottom: .5em;
       }
-      .diffAgainst {
+      .rightControls {
         font-weight: normal;
       }
       .positionIndicator,
@@ -106,6 +108,11 @@
         color: #C62828;
         font-weight: bold;
       }
+      gr-diff {
+        box-shadow: 0 1px 3px rgba(0, 0, 0, .3);
+        display: block;
+        margin: .25em 0 1em;
+      }
       @media screen and (max-width: 50em) {
         .row[selected] {
           background-color: transparent;
@@ -125,7 +132,11 @@
     </style>
     <header>
       <div>Files</div>
-      <div class="diffAgainst">
+      <div class="rightControls">
+        <gr-button link on-tap="_expandAllDiffs">Show diffs</gr-button>
+        /
+        <gr-button link on-tap="_collapseAllDiffs">Hide diffs</gr-button>
+        /
         <label>
           Diff against
           <select on-change="_handlePatchChange">
@@ -168,6 +179,13 @@
           <span class="removed">-[[file.lines_deleted]]</span>
         </div>
       </div>
+      <gr-diff id="diff" hidden
+          change-num="[[changeNum]]"
+          patch-range="[[patchRange]]"
+          path="[[file.__path]]"
+          prefs="[[_diffPrefs]]"
+          project-config="[[projectConfig]]"
+          view-mode="[[_userPrefs.diff_view]]"></gr-diff>
     </template>
     <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
   </template>
diff --git a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.js b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.js
index a9ce44e..d739e07 100644
--- a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.js
+++ b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.js
@@ -26,6 +26,7 @@
       comments: Object,
       drafts: Object,
       revisions: Object,
+      projectConfig: Object,
       selectedIndex: {
         type: Number,
         notify: true,
@@ -44,6 +45,9 @@
         type: Array,
         value: function() { return []; },
       },
+      _diffPrefs: Object,
+      _userPrefs: Object,
+      _showInlineDiffs: Boolean,
     },
 
     behaviors: [
@@ -71,7 +75,21 @@
         });
       }));
 
-      return Promise.all(promises);
+      promises.push(this._getDiffPreferences().then(function(prefs) {
+        this._diffPrefs = prefs;
+      }.bind(this)));
+
+      promises.push(this._getPreferences().then(function(prefs) {
+        this._userPrefs = prefs;
+      }.bind(this)));
+    },
+
+    _getDiffPreferences: function() {
+      return this.$.restAPI.getDiffPreferences();
+    },
+
+    _getPreferences: function() {
+      return this.$.restAPI.getPreferences();
     },
 
     _computePatchSets: function(revisions) {
@@ -96,6 +114,28 @@
           encodeURIComponent(this._patchRangeStr(this.patchRange)));
     },
 
+    _forEachDiff: function(fn) {
+      var diffs = Polymer.dom(this.root).querySelectorAll('gr-diff');
+      for (var i = 0; i < diffs.length; i++) {
+        fn(diffs[i]);
+      }
+    },
+
+    _expandAllDiffs: function() {
+      this._showInlineDiffs = true;
+      this._forEachDiff(function(diff) {
+        diff.hidden = false;
+        diff.reload();
+      });
+    },
+
+    _collapseAllDiffs: function() {
+      this._showInlineDiffs = false;
+      this._forEachDiff(function(diff) {
+        diff.hidden = true;
+      });
+    },
+
     _computeCommentsString: function(comments, patchNum, path) {
       return this._computeCountString(comments, patchNum, path, 'comment');
     },
@@ -159,6 +199,11 @@
       if (this.shouldSupressKeyboardShortcut(e)) { return; }
 
       switch (e.keyCode) {
+        case 73:  // 'i'
+          if (!e.shiftKey) { return; }
+          e.preventDefault();
+          this._toggleInlineDiffs();
+          break;
         case 74:  // 'j'
           e.preventDefault();
           this.selectedIndex =
@@ -184,6 +229,14 @@
       }
     },
 
+    _toggleInlineDiffs: function() {
+      if (this._showInlineDiffs) {
+        this._collapseAllDiffs();
+      } else {
+        this._expandAllDiffs();
+      }
+    },
+
     _openSelectedFile: function(opt_index) {
       if (opt_index != null) {
         this.selectedIndex = opt_index;
diff --git a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_test.html b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_test.html
index f80d211..055f961 100644
--- a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_test.html
+++ b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_test.html
@@ -35,17 +35,12 @@
 <script>
   suite('gr-file-list tests', function() {
     var element;
-    var getLoggedInStub;
 
     setup(function() {
-      element = fixture('basic');
-      getLoggedInStub = sinon.stub(element, '_getLoggedIn', function() {
-        return Promise.resolve(true);
+      stub('gr-rest-api-interface', {
+        getLoggedIn: function() { return Promise.resolve(true); },
       });
-    });
-
-    teardown(function() {
-      getLoggedInStub.restore();
+      element = fixture('basic');
     });
 
     test('get file list', function(done) {
@@ -83,6 +78,11 @@
     });
 
     test('keyboard shortcuts', function() {
+      var toggleInlineDiffsStub = sinon.stub(element, '_toggleInlineDiffs');
+      MockInteractions.pressAndReleaseKeyOn(element, 73, 'shift');  // 'I'
+      assert.isTrue(toggleInlineDiffsStub.calledOnce);
+      toggleInlineDiffsStub.restore();
+
       element._files = [
         {__path: '/COMMIT_MSG'},
         {__path: 'file_added_in_rev2.txt'},
diff --git a/polygerrit-ui/app/elements/core/gr-keyboard-shortcuts-dialog/gr-keyboard-shortcuts-dialog.html b/polygerrit-ui/app/elements/core/gr-keyboard-shortcuts-dialog/gr-keyboard-shortcuts-dialog.html
index 9a75fa9..32de08a 100644
--- a/polygerrit-ui/app/elements/core/gr-keyboard-shortcuts-dialog/gr-keyboard-shortcuts-dialog.html
+++ b/polygerrit-ui/app/elements/core/gr-keyboard-shortcuts-dialog/gr-keyboard-shortcuts-dialog.html
@@ -98,6 +98,13 @@
             <td><span class="key">u</span></td>
             <td>Up to change list</td>
           </tr>
+          <tr>
+            <td>
+              <span class="key modifier">Shift</span>
+              <span class="key">i</span>
+            </td>
+            <td>Show/hide inline diffs</td>
+          </tr>
         </tbody>
         <!-- Diff View -->
         <tbody hidden$="[[!_computeInView(view, 'gr-diff-view')]]" hidden>
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 3cb37b6..3795aa8 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
@@ -220,6 +220,7 @@
 
         return Promise.resolve({
           changes_per_page: 25,
+          diff_view: 'SIDE_BY_SIDE',
         });
       }.bind(this));
     },