Merge "Add dropdown for selecting diff view mode to file list"
This commit is contained in:
@@ -302,7 +302,8 @@ limitations under the License.
|
|||||||
drafts="[[_diffDrafts]]"
|
drafts="[[_diffDrafts]]"
|
||||||
revisions="[[_change.revisions]]"
|
revisions="[[_change.revisions]]"
|
||||||
projectConfig="[[_projectConfig]]"
|
projectConfig="[[_projectConfig]]"
|
||||||
selected-index="{{viewState.selectedFileIndex}}"></gr-file-list>
|
selected-index="{{viewState.selectedFileIndex}}"
|
||||||
|
diff-view-mode="{{viewState.diffMode}}"></gr-file-list>
|
||||||
</section>
|
</section>
|
||||||
<gr-messages-list id="messageList"
|
<gr-messages-list id="messageList"
|
||||||
change-num="[[_changeNum]]"
|
change-num="[[_changeNum]]"
|
||||||
|
|||||||
@@ -147,9 +147,18 @@ limitations under the License.
|
|||||||
/
|
/
|
||||||
<gr-button link on-tap="_collapseAllDiffs">Hide diffs</gr-button>
|
<gr-button link on-tap="_collapseAllDiffs">Hide diffs</gr-button>
|
||||||
/
|
/
|
||||||
|
<select
|
||||||
|
id="modeSelect"
|
||||||
|
is="gr-select"
|
||||||
|
bind-value="{{diffViewMode}}"
|
||||||
|
on-change="_handleDropdownChange">
|
||||||
|
<option value="SIDE_BY_SIDE">Side By Side</option>
|
||||||
|
<option value="UNIFIED_DIFF">Unified</option>
|
||||||
|
</select>
|
||||||
|
/
|
||||||
<label>
|
<label>
|
||||||
Diff against
|
Diff against
|
||||||
<select on-change="_handlePatchChange">
|
<select id="patchChange" on-change="_handlePatchChange">
|
||||||
<option value="PARENT">Base</option>
|
<option value="PARENT">Base</option>
|
||||||
<template is="dom-repeat" items="[[_computePatchSets(revisions, patchRange.*)]]" as="patchNum">
|
<template is="dom-repeat" items="[[_computePatchSets(revisions, patchRange.*)]]" as="patchNum">
|
||||||
<option
|
<option
|
||||||
@@ -210,7 +219,7 @@ limitations under the License.
|
|||||||
path="[[file.__path]]"
|
path="[[file.__path]]"
|
||||||
prefs="[[_diffPrefs]]"
|
prefs="[[_diffPrefs]]"
|
||||||
project-config="[[projectConfig]]"
|
project-config="[[projectConfig]]"
|
||||||
view-mode="[[_userPrefs.diff_view]]"></gr-diff>
|
view-mode="[[_diffMode]]"></gr-diff>
|
||||||
</template>
|
</template>
|
||||||
<gr-button
|
<gr-button
|
||||||
class="fileListButton"
|
class="fileListButton"
|
||||||
|
|||||||
@@ -16,6 +16,11 @@
|
|||||||
|
|
||||||
var COMMIT_MESSAGE_PATH = '/COMMIT_MSG';
|
var COMMIT_MESSAGE_PATH = '/COMMIT_MSG';
|
||||||
|
|
||||||
|
var DiffViewMode = {
|
||||||
|
SIDE_BY_SIDE: 'SIDE_BY_SIDE',
|
||||||
|
UNIFIED: 'UNIFIED_DIFF',
|
||||||
|
};
|
||||||
|
|
||||||
Polymer({
|
Polymer({
|
||||||
is: 'gr-file-list',
|
is: 'gr-file-list',
|
||||||
|
|
||||||
@@ -36,7 +41,10 @@
|
|||||||
value: function() { return document.body; },
|
value: function() { return document.body; },
|
||||||
},
|
},
|
||||||
change: Object,
|
change: Object,
|
||||||
|
diffViewMode: {
|
||||||
|
type: String,
|
||||||
|
notify: true,
|
||||||
|
},
|
||||||
_files: {
|
_files: {
|
||||||
type: Array,
|
type: Array,
|
||||||
observer: '_filesChanged',
|
observer: '_filesChanged',
|
||||||
@@ -67,6 +75,10 @@
|
|||||||
type: Array,
|
type: Array,
|
||||||
computed: '_computeFilesShown(_numFilesShown, _files.*)',
|
computed: '_computeFilesShown(_numFilesShown, _files.*)',
|
||||||
},
|
},
|
||||||
|
_diffMode: {
|
||||||
|
type: String,
|
||||||
|
computed: '_getDiffViewMode(diffViewMode, _userPrefs)',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
behaviors: [
|
behaviors: [
|
||||||
@@ -100,8 +112,17 @@
|
|||||||
this._diffPrefs = prefs;
|
this._diffPrefs = prefs;
|
||||||
}.bind(this)));
|
}.bind(this)));
|
||||||
|
|
||||||
|
// Initialize with user's diff mode preference. Default to
|
||||||
|
// SIDE_BY_SIDE in the meantime.
|
||||||
|
var setDiffViewMode = this.diffViewMode === null;
|
||||||
|
if (setDiffViewMode) {
|
||||||
|
this.set('diffViewMode', DiffViewMode.SIDE_BY_SIDE);
|
||||||
|
}
|
||||||
promises.push(this._getPreferences().then(function(prefs) {
|
promises.push(this._getPreferences().then(function(prefs) {
|
||||||
this._userPrefs = prefs;
|
this._userPrefs = prefs;
|
||||||
|
if (setDiffViewMode) {
|
||||||
|
this.set('diffViewMode', prefs.diff_view);
|
||||||
|
}
|
||||||
}.bind(this)));
|
}.bind(this)));
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -474,5 +495,32 @@
|
|||||||
_showAllFiles: function() {
|
_showAllFiles: function() {
|
||||||
this._numFilesShown = this._files.length;
|
this._numFilesShown = this._files.length;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* _getDiffViewMode: Get the diff view (side-by-side or unified) based on
|
||||||
|
* the current state.
|
||||||
|
*
|
||||||
|
* The expected behavior is to use the mode specified in the user's
|
||||||
|
* preferences unless they have manually chosen the alternative view. If the
|
||||||
|
* user navigates up to the change view, it should clear this choice and
|
||||||
|
* revert to the preference the next time a diff is viewed.
|
||||||
|
*
|
||||||
|
* Use side-by-side if the user is not logged in.
|
||||||
|
*
|
||||||
|
* @return {String}
|
||||||
|
*/
|
||||||
|
_getDiffViewMode: function() {
|
||||||
|
if (this.diffViewMode) {
|
||||||
|
return this.diffViewMode;
|
||||||
|
} else if (this._userPrefs && this._userPrefs.diff_view) {
|
||||||
|
return this.diffViewMode = this._userPrefs.diff_view;
|
||||||
|
}
|
||||||
|
|
||||||
|
return DiffViewMode.SIDE_BY_SIDE;
|
||||||
|
},
|
||||||
|
|
||||||
|
_handleDropdownChange: function(e) {
|
||||||
|
e.target.blur();
|
||||||
|
},
|
||||||
});
|
});
|
||||||
})();
|
})();
|
||||||
|
|||||||
@@ -32,20 +32,36 @@ limitations under the License.
|
|||||||
</template>
|
</template>
|
||||||
</test-fixture>
|
</test-fixture>
|
||||||
|
|
||||||
|
<test-fixture id="blank">
|
||||||
|
<template>
|
||||||
|
<div></div>
|
||||||
|
</template>
|
||||||
|
</test-fixture>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
suite('gr-file-list tests', function() {
|
suite('gr-file-list tests', function() {
|
||||||
var element;
|
var element;
|
||||||
|
var sandbox;
|
||||||
|
|
||||||
setup(function() {
|
setup(function() {
|
||||||
|
sandbox = sinon.sandbox.create();
|
||||||
stub('gr-rest-api-interface', {
|
stub('gr-rest-api-interface', {
|
||||||
getLoggedIn: function() { return Promise.resolve(true); },
|
getLoggedIn: function() { return Promise.resolve(true); },
|
||||||
getPreferences: function() { return Promise.resolve({}); },
|
getPreferences: function() { return Promise.resolve({}); },
|
||||||
|
fetchJSON: function() { return Promise.resolve({}); },
|
||||||
|
});
|
||||||
|
stub('gr-date-formatter', {
|
||||||
|
_loadTimeFormat: function() { return Promise.resolve(''); }
|
||||||
});
|
});
|
||||||
element = fixture('basic');
|
element = fixture('basic');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
teardown(function() {
|
||||||
|
sandbox.restore();
|
||||||
|
});
|
||||||
|
|
||||||
test('get file list', function(done) {
|
test('get file list', function(done) {
|
||||||
var getChangeFilesStub = sinon.stub(element.$.restAPI, 'getChangeFiles',
|
var getChangeFilesStub = sandbox.stub(element.$.restAPI, 'getChangeFiles',
|
||||||
function() {
|
function() {
|
||||||
return Promise.resolve({
|
return Promise.resolve({
|
||||||
'/COMMIT_MSG': {lines_inserted: 9},
|
'/COMMIT_MSG': {lines_inserted: 9},
|
||||||
@@ -97,12 +113,15 @@ limitations under the License.
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('toggle left diff via shortcut', function() {
|
test('toggle left diff via shortcut', function() {
|
||||||
var toggleLeftDiffStub = sinon.stub();
|
var toggleLeftDiffStub = sandbox.stub();
|
||||||
sinon.stub(element, 'diffs', {get: function() {
|
// Property getter cannot be stubbed w/ sandbox due to a bug in Sinon.
|
||||||
|
// https://github.com/sinonjs/sinon/issues/781
|
||||||
|
var diffsStub = sinon.stub(element, 'diffs', {get: function() {
|
||||||
return [{toggleLeftDiff: toggleLeftDiffStub}];
|
return [{toggleLeftDiff: toggleLeftDiffStub}];
|
||||||
}});
|
}});
|
||||||
MockInteractions.pressAndReleaseKeyOn(element, 65, 'shift'); // 'A'
|
MockInteractions.pressAndReleaseKeyOn(element, 65, 'shift'); // 'A'
|
||||||
assert.isTrue(toggleLeftDiffStub.calledOnce);
|
assert.isTrue(toggleLeftDiffStub.calledOnce);
|
||||||
|
diffsStub.restore();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('keyboard shortcuts', function() {
|
test('keyboard shortcuts', function() {
|
||||||
@@ -117,7 +136,7 @@ limitations under the License.
|
|||||||
assert.equal(element.selectedIndex, 1);
|
assert.equal(element.selectedIndex, 1);
|
||||||
MockInteractions.pressAndReleaseKeyOn(element, 74); // 'J'
|
MockInteractions.pressAndReleaseKeyOn(element, 74); // 'J'
|
||||||
|
|
||||||
var showStub = sinon.stub(page, 'show');
|
var showStub = sandbox.stub(page, 'show');
|
||||||
assert.equal(element.selectedIndex, 2);
|
assert.equal(element.selectedIndex, 2);
|
||||||
MockInteractions.pressAndReleaseKeyOn(element, 13); // 'ENTER'
|
MockInteractions.pressAndReleaseKeyOn(element, 13); // 'ENTER'
|
||||||
assert(showStub.lastCall.calledWith('/c/42/2/myfile.txt'),
|
assert(showStub.lastCall.calledWith('/c/42/2/myfile.txt'),
|
||||||
@@ -241,7 +260,7 @@ limitations under the License.
|
|||||||
assert.isFalse(fileAdded.checked);
|
assert.isFalse(fileAdded.checked);
|
||||||
assert.isTrue(myFile.checked);
|
assert.isTrue(myFile.checked);
|
||||||
|
|
||||||
var saveStub = sinon.stub(element, '_saveReviewedState',
|
var saveStub = sandbox.stub(element, '_saveReviewedState',
|
||||||
function() { return Promise.resolve(); });
|
function() { return Promise.resolve(); });
|
||||||
|
|
||||||
MockInteractions.tap(commitMsg);
|
MockInteractions.tap(commitMsg);
|
||||||
@@ -272,7 +291,7 @@ limitations under the License.
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('diff against dropdown', function(done) {
|
test('diff against dropdown', function(done) {
|
||||||
var showStub = sinon.stub(page, 'show');
|
var showStub = sandbox.stub(page, 'show');
|
||||||
element.changeNum = '42';
|
element.changeNum = '42';
|
||||||
element.patchRange = {
|
element.patchRange = {
|
||||||
basePatchNum: 'PARENT',
|
basePatchNum: 'PARENT',
|
||||||
@@ -284,7 +303,7 @@ limitations under the License.
|
|||||||
rev3: {_number: 3},
|
rev3: {_number: 3},
|
||||||
};
|
};
|
||||||
flush(function() {
|
flush(function() {
|
||||||
var selectEl = element.$$('select');
|
var selectEl = element.$.patchChange;
|
||||||
assert.equal(selectEl.value, 'PARENT');
|
assert.equal(selectEl.value, 'PARENT');
|
||||||
assert.isTrue(element.$$('option[value="3"]').hasAttribute('disabled'));
|
assert.isTrue(element.$$('option[value="3"]').hasAttribute('disabled'));
|
||||||
selectEl.addEventListener('change', function() {
|
selectEl.addEventListener('change', function() {
|
||||||
@@ -313,7 +332,7 @@ limitations under the License.
|
|||||||
var fileRows =
|
var fileRows =
|
||||||
Polymer.dom(element.root).querySelectorAll('.row:not(.header)');
|
Polymer.dom(element.root).querySelectorAll('.row:not(.header)');
|
||||||
// Prevent diff from making API call.
|
// Prevent diff from making API call.
|
||||||
var diffStub = sinon.stub(element.diffs[0], 'reload');
|
var diffStub = sandbox.stub(element.diffs[0], 'reload');
|
||||||
var showHideCheck = fileRows[0].querySelector(
|
var showHideCheck = fileRows[0].querySelector(
|
||||||
'input.show-hide[type="checkbox"]');
|
'input.show-hide[type="checkbox"]');
|
||||||
assert.isTrue(showHideCheck.checked);
|
assert.isTrue(showHideCheck.checked);
|
||||||
@@ -339,5 +358,50 @@ limitations under the License.
|
|||||||
element.$$('a').getAttribute('href'),
|
element.$$('a').getAttribute('href'),
|
||||||
'/c/42/2/foo+bar/my%252Bfile.txt%2525');
|
'/c/42/2/foo+bar/my%252Bfile.txt%2525');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('diff mode correctly toggles the diffs', function() {
|
||||||
|
element._files = [
|
||||||
|
{__path: 'myfile.txt', __expanded: false},
|
||||||
|
];
|
||||||
|
element.changeNum = '42';
|
||||||
|
element.patchRange = {
|
||||||
|
basePatchNum: 'PARENT',
|
||||||
|
patchNum: '2',
|
||||||
|
};
|
||||||
|
element.selectedIndex = 0;
|
||||||
|
flushAsynchronousOperations();
|
||||||
|
var select = element.$.modeSelect;
|
||||||
|
var diffDisplay = element.diffs[0];
|
||||||
|
element._userPrefs = {diff_view: 'SIDE_BY_SIDE'};
|
||||||
|
assert.equal(element._getDiffViewMode(), 'SIDE_BY_SIDE');
|
||||||
|
assert.equal(element.diffViewMode, 'SIDE_BY_SIDE');
|
||||||
|
assert.equal(diffDisplay.viewMode, 'SIDE_BY_SIDE');
|
||||||
|
element.set('diffViewMode', 'UNIFIED_DIFF');
|
||||||
|
assert.equal(element._getDiffViewMode(), 'UNIFIED_DIFF');
|
||||||
|
assert.equal(diffDisplay.viewMode, 'UNIFIED_DIFF');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('diff mode selector initializes from preferences', function() {
|
||||||
|
var resolvePrefs;
|
||||||
|
var prefsPromise = new Promise(function(resolve) {
|
||||||
|
resolvePrefs = resolve;
|
||||||
|
});
|
||||||
|
sandbox.stub(element, '_getPreferences').returns(prefsPromise);
|
||||||
|
|
||||||
|
// Attach a new gr-file-list so we can intercept the preferences fetch.
|
||||||
|
var view = document.createElement('gr-file-list');
|
||||||
|
var select = view.$.modeSelect;
|
||||||
|
fixture('blank').appendChild(view);
|
||||||
|
flushAsynchronousOperations();
|
||||||
|
|
||||||
|
// At this point the diff mode doesn't yet have the user's preference.
|
||||||
|
assert.equal(select.value, 'SIDE_BY_SIDE');
|
||||||
|
|
||||||
|
// Receive the overriding preference.
|
||||||
|
resolvePrefs({diff_view: 'UNIFIED'});
|
||||||
|
flushAsynchronousOperations();
|
||||||
|
assert.equal(select.value, 'SIDE_BY_SIDE');
|
||||||
|
document.getElementById('blank').restore();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -104,7 +104,6 @@
|
|||||||
this._setReviewed(true);
|
this._setReviewed(true);
|
||||||
}
|
}
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
|
|
||||||
if (this.changeViewState.diffMode === null) {
|
if (this.changeViewState.diffMode === null) {
|
||||||
// Initialize with user's diff mode preference. Default to
|
// Initialize with user's diff mode preference. Default to
|
||||||
// SIDE_BY_SIDE in the meantime.
|
// SIDE_BY_SIDE in the meantime.
|
||||||
|
|||||||
@@ -457,7 +457,6 @@ limitations under the License.
|
|||||||
|
|
||||||
// We will simulate a user change of the selected mode.
|
// We will simulate a user change of the selected mode.
|
||||||
var newMode = 'UNIFIED_DIFF';
|
var newMode = 'UNIFIED_DIFF';
|
||||||
|
|
||||||
// Set the actual value of the select, and simulate the change event.
|
// Set the actual value of the select, and simulate the change event.
|
||||||
select.value = newMode;
|
select.value = newMode;
|
||||||
element.fire('change', {}, {node: select});
|
element.fire('change', {}, {node: select});
|
||||||
|
|||||||
Reference in New Issue
Block a user