diff options
Diffstat (limited to 'polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.js')
-rw-r--r-- | polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.js | 628 |
1 files changed, 368 insertions, 260 deletions
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.js b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.js index d1ac8426bd..b97d974520 100644 --- a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.js +++ b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.js @@ -14,18 +14,17 @@ (function() { 'use strict'; - var COMMIT_MESSAGE_PATH = '/COMMIT_MSG'; - var MERGE_LIST_PATH = '/MERGE_LIST'; + const ERR_REVIEW_STATUS = 'Couldn’t change file review status.'; + const MSG_LOADING_BLAME = 'Loading blame...'; + const MSG_LOADED_BLAME = 'Blame loaded'; - var COMMENT_SAVE = 'Try again when all comments have saved.'; + const PARENT = 'PARENT'; - var DiffSides = { + const DiffSides = { LEFT: 'left', RIGHT: 'right', }; - var HASH_PATTERN = /^[ab]?\d+$/; - Polymer({ is: 'gr-diff-view', @@ -51,21 +50,32 @@ }, keyEventTarget: { type: Object, - value: function() { return document.body; }, + value() { return document.body; }, }, + /** + * @type {{ diffMode: (string|undefined) }} + */ changeViewState: { type: Object, notify: true, - value: function() { return {}; }, + value() { return {}; }, + observer: '_changeViewStateChanged', }, - + /** @type {?} */ _patchRange: Object, + /** + * @type {{ + * subject: string, + * project: string, + * revisions: string, + * }} + */ _change: Object, _changeNum: String, _diff: Object, _fileList: { type: Array, - value: function() { return []; }, + value() { return []; }, }, _path: { type: String, @@ -96,6 +106,8 @@ */ _commentMap: Object, + _commentsForDiff: Object, + /** * Object to contain the path of the next and previous file in the current * change and patch range that has comments. @@ -104,18 +116,40 @@ type: Object, computed: '_computeCommentSkips(_commentMap, _fileList, _path)', }, + _panelFloatingDisabled: { + type: Boolean, + value: () => { return window.PANEL_FLOATING_DISABLED; }, + }, + _editLoaded: { + type: Boolean, + computed: '_computeEditLoaded(_patchRange.*)', + }, + _isBlameSupported: { + type: Boolean, + value: false, + }, + _isBlameLoaded: Boolean, + _isBlameLoading: { + type: Boolean, + value: false, + }, + _allPatchSets: { + type: Array, + computed: 'computeAllPatchSets(_change, _change.revisions.*)', + }, }, behaviors: [ - Gerrit.BaseUrlBehavior, Gerrit.KeyboardShortcutBehavior, + Gerrit.PatchSetBehavior, + Gerrit.PathListBehavior, Gerrit.RESTClientBehavior, - Gerrit.URLEncodingBehavior, ], observers: [ '_getProjectConfig(_change.project)', '_getFiles(_changeNum, _patchRange.*)', + '_setReviewedObserver(_loggedIn, params.*)', ], keyBindings: { @@ -134,85 +168,78 @@ ',': '_handleCommaKey', }, - attached: function() { - this._getLoggedIn().then(function(loggedIn) { + attached() { + this._getLoggedIn().then(loggedIn => { this._loggedIn = loggedIn; - if (loggedIn) { - this._setReviewed(true); - } - }.bind(this)); - if (this.changeViewState.diffMode === null) { - // If screen size is small, always default to unified view. - this.$.restAPI.getPreferences().then(function(prefs) { - this.set('changeViewState.diffMode', prefs.default_diff_view); - }.bind(this)); - } + }); - if (this._path) { - this.fire('title-change', - {title: this._computeFileDisplayName(this._path)}); - } + this.$.restAPI.getConfig().then(config => { + this._isBlameSupported = config.change.allow_blame; + }); this.$.cursor.push('diffs', this.$.diff); }, - _getLoggedIn: function() { + _getLoggedIn() { return this.$.restAPI.getLoggedIn(); }, - _getProjectConfig: function(project) { + _getProjectConfig(project) { return this.$.restAPI.getProjectConfig(project).then( - function(config) { + config => { this._projectConfig = config; - }.bind(this)); + }); + }, + + _getChangeDetail(changeNum) { + return this.$.restAPI.getDiffChangeDetail(changeNum).then(change => { + this._change = change; + }); }, - _getChangeDetail: function(changeNum) { - return this.$.restAPI.getDiffChangeDetail(changeNum).then( - function(change) { - this._change = change; - }.bind(this)); + _getChangeEdit(changeNum) { + return this.$.restAPI.getChangeEdit(this._changeNum); }, - _getFiles: function(changeNum, patchRangeRecord) { - var patchRange = patchRangeRecord.base; + _getFiles(changeNum, patchRangeRecord) { + const patchRange = patchRangeRecord.base; return this.$.restAPI.getChangeFilePathsAsSpeciallySortedArray( - changeNum, patchRange).then(function(files) { + changeNum, patchRange).then(files => { this._fileList = files; - }.bind(this)); + }); }, - _getDiffPreferences: function() { + _getDiffPreferences() { return this.$.restAPI.getDiffPreferences(); }, - _getPreferences: function() { + _getPreferences() { return this.$.restAPI.getPreferences(); }, - _getWindowWidth: function() { + _getWindowWidth() { return window.innerWidth; }, - _handleReviewedChange: function(e) { + _handleReviewedChange(e) { this._setReviewed(Polymer.dom(e).rootTarget.checked); }, - _setReviewed: function(reviewed) { + _setReviewed(reviewed) { + if (this._editLoaded) { return; } this.$.reviewed.checked = reviewed; - this._saveReviewedState(reviewed).catch(function(err) { - alert('Couldn’t change file review status. Check the console ' + - 'and contact the PolyGerrit team for assistance.'); + this._saveReviewedState(reviewed).catch(err => { + this.fire('show-alert', {message: ERR_REVIEW_STATUS}); throw err; - }.bind(this)); + }); }, - _saveReviewedState: function(reviewed) { + _saveReviewedState(reviewed) { return this.$.restAPI.saveFileReviewed(this._changeNum, this._patchRange.patchNum, this._path, reviewed); }, - _handleEscKey: function(e) { + _handleEscKey(e) { if (this.shouldSuppressKeyboardShortcut(e) || this.modifierPressed(e)) { return; } @@ -220,21 +247,21 @@ this.$.diff.displayLine = false; }, - _handleShiftLeftKey: function(e) { + _handleShiftLeftKey(e) { if (this.shouldSuppressKeyboardShortcut(e)) { return; } e.preventDefault(); this.$.cursor.moveLeft(); }, - _handleShiftRightKey: function(e) { + _handleShiftRightKey(e) { if (this.shouldSuppressKeyboardShortcut(e)) { return; } e.preventDefault(); this.$.cursor.moveRight(); }, - _handleUpKey: function(e) { + _handleUpKey(e) { if (this.shouldSuppressKeyboardShortcut(e)) { return; } if (e.detail.keyboardEvent.shiftKey && e.detail.keyboardEvent.keyCode === 75) { // 'K' @@ -248,7 +275,7 @@ this.$.cursor.moveUp(); }, - _handleDownKey: function(e) { + _handleDownKey(e) { if (this.shouldSuppressKeyboardShortcut(e)) { return; } if (e.detail.keyboardEvent.shiftKey && e.detail.keyboardEvent.keyCode === 74) { // 'J' @@ -262,49 +289,51 @@ this.$.cursor.moveDown(); }, - _moveToPreviousFileWithComment: function() { + _moveToPreviousFileWithComment() { if (this._commentSkips && this._commentSkips.previous) { - page.show(this._getDiffURL(this._changeNum, this._patchRange, - this._commentSkips.previous)); + Gerrit.Nav.navigateToDiff(this._change, this._commentSkips.previous, + this._patchRange.patchNum, this._patchRange.basePatchNum); } }, - _moveToNextFileWithComment: function() { + _moveToNextFileWithComment() { if (this._commentSkips && this._commentSkips.next) { - page.show(this._getDiffURL(this._changeNum, this._patchRange, - this._commentSkips.next)); + Gerrit.Nav.navigateToDiff(this._change, this._commentSkips.next, + this._patchRange.patchNum, this._patchRange.basePatchNum); } }, - _handleCKey: function(e) { + _handleCKey(e) { if (this.shouldSuppressKeyboardShortcut(e)) { return; } if (this.$.diff.isRangeSelected()) { return; } if (this.modifierPressed(e)) { return; } e.preventDefault(); - var line = this.$.cursor.getTargetLineElement(); + const line = this.$.cursor.getTargetLineElement(); if (line) { this.$.diff.addDraftAtLine(line); } }, - _handleLeftBracketKey: function(e) { + _handleLeftBracketKey(e) { + // Check for meta key to avoid overriding native chrome shortcut. if (this.shouldSuppressKeyboardShortcut(e) || - this.modifierPressed(e)) { return; } + this.getKeyboardEvent(e).metaKey) { return; } e.preventDefault(); this._navToFile(this._path, this._fileList, -1); }, - _handleRightBracketKey: function(e) { + _handleRightBracketKey(e) { + // Check for meta key to avoid overriding native chrome shortcut. if (this.shouldSuppressKeyboardShortcut(e) || - this.modifierPressed(e)) { return; } + this.getKeyboardEvent(e).metaKey) { return; } e.preventDefault(); this._navToFile(this._path, this._fileList, 1); }, - _handleNKey: function(e) { + _handleNKey(e) { if (this.shouldSuppressKeyboardShortcut(e)) { return; } e.preventDefault(); @@ -316,7 +345,7 @@ } }, - _handlePKey: function(e) { + _handlePKey(e) { if (this.shouldSuppressKeyboardShortcut(e)) { return; } e.preventDefault(); @@ -328,7 +357,7 @@ } }, - _handleAKey: function(e) { + _handleAKey(e) { if (this.shouldSuppressKeyboardShortcut(e)) { return; } if (e.detail.keyboardEvent.shiftKey) { // Hide left diff. @@ -340,18 +369,13 @@ if (this.modifierPressed(e)) { return; } if (!this._loggedIn) { return; } - if (this.$.restAPI.hasPendingDiffDrafts()) { - this.dispatchEvent(new CustomEvent('show-alert', - {detail: {message: COMMENT_SAVE}, bubbles: true})); - return; - } this.set('changeViewState.showReplyDialog', true); e.preventDefault(); this._navToChangeView(); }, - _handleUKey: function(e) { + _handleUKey(e) { if (this.shouldSuppressKeyboardShortcut(e) || this.modifierPressed(e)) { return; } @@ -359,49 +383,41 @@ this._navToChangeView(); }, - _handleCommaKey: function(e) { + _handleCommaKey(e) { if (this.shouldSuppressKeyboardShortcut(e) || this.modifierPressed(e)) { return; } e.preventDefault(); - this._openPrefs(); + this.$.diffPreferences.open(); }, - _navToChangeView: function() { + _navToChangeView() { if (!this._changeNum || !this._patchRange.patchNum) { return; } - - page.show(this._getChangePath( - this._changeNum, + this._navigateToChange( + this._change, this._patchRange, - this._change && this._change.revisions)); - }, - - _computeUpURL: function(changeNum, patchRange, change, changeRevisions) { - return this._getChangePath( - changeNum, - patchRange, - change && changeRevisions); + this._change && this._change.revisions); }, - _navToFile: function(path, fileList, direction) { - var url = this._computeNavLinkURL(path, fileList, direction); - if (!url) { return; } + _navToFile(path, fileList, direction) { + const newPath = this._getNavLinkPath(path, fileList, direction); + if (!newPath) { return; } - page.show(this._computeNavLinkURL(path, fileList, direction)); - }, + if (newPath.up) { + this._navigateToChange( + this._change, + this._patchRange, + this._change && this._change.revisions); + return; + } - _openPrefs: function() { - this.$.prefsOverlay.open().then(function() { - var diffPreferences = this.$.diffPreferences; - var focusStops = diffPreferences.getFocusStops(); - this.$.prefsOverlay.setFocusStops(focusStops); - this.$.diffPreferences.resetFocus(); - }.bind(this)); + Gerrit.Nav.navigateToDiff(this._change, newPath.path, + this._patchRange.patchNum, this._patchRange.basePatchNum); }, /** * @param {?string} path The path of the current file being shown. - * @param {Array.<string>} fileList The list of files in this change and + * @param {!Array<string>} fileList The list of files in this change and * patch range. * @param {number} direction Either 1 (next file) or -1 (prev file). * @param {(number|boolean)} opt_noUp Whether to return to the change view @@ -410,13 +426,46 @@ * @return {?string} The next URL when proceeding in the specified * direction. */ - _computeNavLinkURL: function(path, fileList, direction, opt_noUp) { + _computeNavLinkURL(change, path, fileList, direction, opt_noUp) { + const newPath = this._getNavLinkPath(path, fileList, direction, opt_noUp); + if (!newPath) { return null; } + + if (newPath.up) { + return this._getChangePath( + this._change, + this._patchRange, + this._change && this._change.revisions); + } + return this._getDiffUrl(this._change, this._patchRange, newPath.path); + }, + + /** + * Gives an object representing the target of navigating either left or + * right through the change. The resulting object will have one of the + * following forms: + * * {path: "<target file path>"} - When another file path should be the + * result of the navigation. + * * {up: true} - When the result of navigating should go back to the + * change view. + * * null - When no navigation is possible for the given direction. + * + * @param {?string} path The path of the current file being shown. + * @param {!Array<string>} fileList The list of files in this change and + * patch range. + * @param {number} direction Either 1 (next file) or -1 (prev file). + * @param {?number|boolean=} opt_noUp Whether to return to the change view + * when advancing the file goes outside the bounds of fileList. + * @return {?Object} + */ + _getNavLinkPath(path, fileList, direction, opt_noUp) { if (!path || fileList.length === 0) { return null; } - var idx = fileList.indexOf(path); + let idx = fileList.indexOf(path); if (idx === -1) { - var file = direction > 0 ? fileList[0] : fileList[fileList.length - 1]; - return this._getDiffURL(this._changeNum, this._patchRange, file); + const file = direction > 0 ? + fileList[0] : + fileList[fileList.length - 1]; + return {path: file}; } idx += direction; @@ -424,28 +473,31 @@ // outside the bounds of [0, fileList.length). if (idx < 0 || idx > fileList.length - 1) { if (opt_noUp) { return null; } - return this._getChangePath( - this._changeNum, - this._patchRange, - this._change && this._change.revisions); + return {up: true}; } - return this._getDiffURL(this._changeNum, this._patchRange, fileList[idx]); + + return {path: fileList[idx]}; }, - _paramsChanged: function(value) { - if (value.view != this.tagName.toLowerCase()) { return; } + _paramsChanged(value) { + if (value.view !== Gerrit.Nav.View.DIFF) { return; } - this._loadHash(location.hash); + this._initCursor(this.params); this._changeNum = value.changeNum; this._patchRange = { patchNum: value.patchNum, - basePatchNum: value.basePatchNum || 'PARENT', + basePatchNum: value.basePatchNum || PARENT, }; this._path = value.path; - this.fire('title-change', - {title: this._computeFileDisplayName(this._path)}); + // NOTE: This may be called before attachment (e.g. while parentElement is + // null). Fire title-change in an async so that, if attachment to the DOM + // has been queued, the event can bubble up to the handler in gr-app. + this.async(() => { + this.fire('title-change', + {title: this.computeTruncatedPath(this._path)}); + }); // When navigating away from the page, there is a possibility that the // patch number is no longer a part of the URL (say when navigating to @@ -454,128 +506,146 @@ return; } - var promises = []; + const promises = []; this._localPrefs = this.$.storage.getPreferences(); - promises.push(this._getDiffPreferences().then(function(prefs) { + promises.push(this._getDiffPreferences().then(prefs => { this._prefs = prefs; - }.bind(this))); + })); - promises.push(this._getPreferences().then(function(prefs) { + promises.push(this._getPreferences().then(prefs => { this._userPrefs = prefs; - }.bind(this))); + })); promises.push(this._getChangeDetail(this._changeNum)); - Promise.all(promises).then(function() { + promises.push(this._loadComments()); + + promises.push(this._getChangeEdit(this._changeNum)); + + this._loading = true; + Promise.all(promises).then(r => { + const edit = r[4]; + if (edit) { + this.set('_change.revisions.' + edit.commit.commit, { + _number: this.EDIT_NAME, + basePatchNum: edit.base_patch_set_number, + commit: edit.commit, + }); + } this._loading = false; + this.$.diff.comments = this._commentsForDiff; this.$.diff.reload(); - }.bind(this)); + }); + }, - this._loadCommentMap().then(function(commentMap) { - this._commentMap = commentMap; - }.bind(this)); + _changeViewStateChanged(changeViewState) { + if (changeViewState.diffMode === null) { + // If screen size is small, always default to unified view. + this.$.restAPI.getPreferences().then(prefs => { + this.set('changeViewState.diffMode', prefs.default_diff_view); + }); + } + }, + + _setReviewedObserver(_loggedIn) { + if (_loggedIn) { + this._setReviewed(true); + } }, /** - * If the URL hash is a diff address then configure the diff cursor. + * If the params specify a diff address then configure the diff cursor. */ - _loadHash: function(hash) { - hash = hash.replace(/^#/, ''); - if (!HASH_PATTERN.test(hash)) { return; } - if (hash[0] === 'a' || hash[0] === 'b') { + _initCursor(params) { + if (params.lineNum === undefined) { return; } + if (params.leftSide) { this.$.cursor.side = DiffSides.LEFT; - hash = hash.substring(1); } else { this.$.cursor.side = DiffSides.RIGHT; } - this.$.cursor.initialLineNumber = parseInt(hash, 10); + this.$.cursor.initialLineNumber = params.lineNum; }, - _pathChanged: function(path) { + _pathChanged(path) { + if (path) { + this.fire('title-change', + {title: this.computeTruncatedPath(path)}); + } + if (this._fileList.length == 0) { return; } this.set('changeViewState.selectedFileIndex', this._fileList.indexOf(path)); - - if (this._loggedIn) { - this._setReviewed(true); - } }, - _getDiffURL: function(changeNum, patchRange, path) { - return this.getBaseUrl() + '/c/' + changeNum + '/' + - this._patchRangeStr(patchRange) + '/' + this.encodeURL(path, true); + _getDiffUrl(change, patchRange, path) { + return Gerrit.Nav.getUrlForDiff(change, path, patchRange.patchNum, + patchRange.basePatchNum); }, - _computeDiffURL: function(changeNum, patchRangeRecord, path) { - return this._getDiffURL(changeNum, patchRangeRecord.base, path); + _computeDiffURL(change, patchRangeRecord, path) { + return this._getDiffUrl(change, patchRangeRecord.base, path); }, - _patchRangeStr: function(patchRange) { - var patchStr = patchRange.patchNum; + _patchRangeStr(patchRange) { + let patchStr = patchRange.patchNum; if (patchRange.basePatchNum != null && - patchRange.basePatchNum != 'PARENT') { + patchRange.basePatchNum != PARENT) { patchStr = patchRange.basePatchNum + '..' + patchRange.patchNum; } return patchStr; }, - _computeAvailablePatches: function(revisions) { - var patchNums = []; - for (var rev in revisions) { - patchNums.push(revisions[rev]._number); - } - return patchNums.sort(function(a, b) { return a - b; }); - }, - - _getChangePath: function(changeNum, patchRange, revisions) { - var base = this.getBaseUrl() + '/c/' + changeNum + '/'; - - // The change may not have loaded yet, making revisions unavailable. - if (!revisions) { - return base + this._patchRangeStr(patchRange); - } - - var latestPatchNum = -1; - for (var rev in revisions) { - latestPatchNum = Math.max(latestPatchNum, revisions[rev]._number); + /** + * When the latest patch of the change is selected (and there is no base + * patch) then the patch range need not appear in the URL. Return a patch + * range object with undefined values when a range is not needed. + * + * @param {!Object} patchRange + * @param {!Object} revisions + * @return {!Object} + */ + _getChangeUrlRange(patchRange, revisions) { + let patchNum = undefined; + let basePatchNum = undefined; + let latestPatchNum = -1; + for (const rev of Object.values(revisions || {})) { + latestPatchNum = Math.max(latestPatchNum, rev._number); } - if (patchRange.basePatchNum !== 'PARENT' || + if (patchRange.basePatchNum !== PARENT || parseInt(patchRange.patchNum, 10) !== latestPatchNum) { - return base + this._patchRangeStr(patchRange); + patchNum = patchRange.patchNum; + basePatchNum = patchRange.basePatchNum; } - - return base; + return {patchNum, basePatchNum}; }, - _computeChangePath: function(changeNum, patchRangeRecord, revisions) { - return this._getChangePath(changeNum, patchRangeRecord.base, revisions); + _getChangePath(change, patchRange, revisions) { + const range = this._getChangeUrlRange(patchRange, revisions); + return Gerrit.Nav.getUrlForChange(change, range.patchNum, + range.basePatchNum); }, - _computeFileDisplayName: function(path) { - if (path === COMMIT_MESSAGE_PATH) { - return 'Commit message'; - } else if (path === MERGE_LIST_PATH) { - return 'Merge list'; - } - return path; + _navigateToChange(change, patchRange, revisions) { + const range = this._getChangeUrlRange(patchRange, revisions); + Gerrit.Nav.navigateToChange(change, range.patchNum, range.basePatchNum); }, - _computeTruncatedFileDisplayName: function(path) { - return util.truncatePath(this._computeFileDisplayName(path)); + _computeChangePath(change, patchRangeRecord, revisions) { + return this._getChangePath(change, patchRangeRecord.base, revisions); }, - _computeFileSelected: function(path, currentPath) { + _computeFileSelected(path, currentPath) { return path == currentPath; }, - _computePrefsButtonHidden: function(prefs, loggedIn) { + _computePrefsButtonHidden(prefs, loggedIn) { return !loggedIn || !prefs; }, - _computeKeyNav: function(path, selectedPath, fileList) { - var selectedIndex = fileList.indexOf(selectedPath); + _computeKeyNav(path, selectedPath, fileList) { + const selectedIndex = fileList.indexOf(selectedPath); if (fileList.indexOf(path) == selectedIndex - 1) { return '['; } @@ -585,46 +655,50 @@ return ''; }, - _handleFileTap: function(e) { - this.$.dropdown.close(); + _handleFileTap(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(() => { + this.$.dropdown.close(); + }, 1); }, - _handleMobileSelectChange: function(e) { - var path = Polymer.dom(e).rootTarget.value; - page.show(this._getDiffURL(this._changeNum, this._patchRange, path)); + _handleMobileSelectChange(e) { + const path = Polymer.dom(e).rootTarget.value; + Gerrit.Nav.navigateToDiff(this._change, path, this._patchRange.patchNum, + this._patchRange.basePatchNum); }, - _showDropdownTapHandler: function(e) { + _showDropdownTapHandler(e) { this.$.dropdown.open(); }, - _handlePrefsTap: function(e) { + _handlePatchChange(e) { + const {basePatchNum, patchNum} = e.detail; + if (this.patchNumEquals(basePatchNum, this._patchRange.basePatchNum) && + this.patchNumEquals(patchNum, this._patchRange.patchNum)) { return; } + Gerrit.Nav.navigateToDiff( + this._change, this._path, patchNum, basePatchNum); + }, + + _handlePrefsTap(e) { e.preventDefault(); - this._openPrefs(); + this.$.diffPreferences.open(); }, - _handlePrefsSave: function(e) { + _handlePrefsSave(e) { e.stopPropagation(); - 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)); - }, - - _saveDiffPreferences: function() { - return this.$.restAPI.saveDiffPreferences(this._prefs); - }, - - _handlePrefsCancel: function(e) { - e.stopPropagation(); - this.$.prefsOverlay.close(); + }); }, /** @@ -639,9 +713,9 @@ * * Use side-by-side if the user is not logged in. * - * @return {String} + * @return {string} */ - _getDiffViewMode: function() { + _getDiffViewMode() { if (this.changeViewState.diffMode) { return this.changeViewState.diffMode; } else if (this._userPrefs) { @@ -652,66 +726,48 @@ } }, - _computeModeSelectHidden: function() { + _computeModeSelectHidden() { return this._isImageDiff; }, - _onLineSelected: function(e, detail) { + _onLineSelected(e, detail) { this.$.cursor.moveToLineNumber(detail.number, detail.side); - history.replaceState(null, null, '#' + this.$.cursor.getAddress()); - }, - - _computeDownloadLink: function(changeNum, patchRange, path) { - var url = this.changeBaseURL(changeNum, patchRange.patchNum); + if (!this._change) { return; } + const cursorAddress = this.$.cursor.getAddress(); + const number = cursorAddress ? cursorAddress.number : undefined; + const leftSide = cursorAddress ? cursorAddress.leftSide : undefined; + const url = Gerrit.Nav.getUrlForDiffById(this._changeNum, + this._change.project, this._path, this._patchRange.patchNum, + this._patchRange.basePatchNum, number, leftSide); + history.replaceState(null, '', url); + }, + + _computeDownloadLink(changeNum, patchRange, path) { + let url = this.changeBaseURL(changeNum, patchRange.patchNum); url += '/patch?zip&path=' + encodeURIComponent(path); return url; }, - /** - * Request all comments (and drafts and robot comments) for the current - * change and construct the map of file paths that have comments for the - * current patch range. - * @return {Promise} A promise that yields a comment map object. - */ - _loadCommentMap: function() { - function filterByRange(comment) { - var patchNum = comment.patch_set + ''; - return patchNum === this._patchRange.patchNum || - patchNum === this._patchRange.basePatchNum; - }; + _loadComments() { + return this.$.commentAPI.loadAll(this._changeNum).then(() => { + this._commentMap = this.$.commentAPI.getPaths(this._patchRange); + + this._commentsForDiff = this.$.commentAPI.getCommentsForPath(this._path, + this._patchRange, this._projectConfig); + }); + }, + + _getDiffDrafts() { + return this.$.restAPI.getDiffDrafts(this._changeNum); + }, - return Promise.all([ - this.$.restAPI.getDiffComments(this._changeNum), - this._getDiffDrafts(), - this.$.restAPI.getDiffRobotComments(this._changeNum), - ]).then(function(results) { - var commentMap = {}; - results.forEach(function(response) { - for (var path in response) { - if (response.hasOwnProperty(path) && - response[path].filter(filterByRange.bind(this)).length) { - commentMap[path] = true; - } - } - }.bind(this)); - return commentMap; - }.bind(this)); - }, - - _getDiffDrafts: function() { - return this._getLoggedIn().then(function(loggedIn) { - if (!loggedIn) { return Promise.resolve({}); } - return this.$.restAPI.getDiffDrafts(this._changeNum); - }.bind(this)); - }, - - _computeCommentSkips: function(commentMap, fileList, path) { - var skips = {previous: null, next: null}; + _computeCommentSkips(commentMap, fileList, path) { + const skips = {previous: null, next: null}; if (!fileList.length) { return skips; } - var pathIndex = fileList.indexOf(path); + const pathIndex = fileList.indexOf(path); // Scan backward for the previous file. - for (var i = pathIndex - 1; i >= 0; i--) { + for (let i = pathIndex - 1; i >= 0; i--) { if (commentMap[fileList[i]]) { skips.previous = fileList[i]; break; @@ -719,7 +775,7 @@ } // Scan forward for the next file. - for (i = pathIndex + 1; i < fileList.length; i++) { + for (let i = pathIndex + 1; i < fileList.length; i++) { if (commentMap[fileList[i]]) { skips.next = fileList[i]; break; @@ -728,5 +784,57 @@ return skips; }, + + _computeDiffClass(panelFloatingDisabled) { + if (panelFloatingDisabled) { + return 'noOverflow'; + } + }, + + /** + * @param {!Object} patchRangeRecord + */ + _computeEditLoaded(patchRangeRecord) { + const patchRange = patchRangeRecord.base || {}; + return this.patchNumEquals(patchRange.patchNum, this.EDIT_NAME); + }, + + /** + * @param {boolean} editLoaded + */ + _computeContainerClass(editLoaded) { + return editLoaded ? 'editLoaded' : ''; + }, + + _computeBlameToggleLabel(loaded, loading) { + if (loaded) { return 'Hide blame'; } + return 'Show blame'; + }, + + /** + * Load and display blame information if it has not already been loaded. + * Otherwise hide it. + */ + _toggleBlame() { + if (this._isBlameLoaded) { + this.$.diff.clearBlame(); + return; + } + + this._isBlameLoading = true; + this.fire('show-alert', {message: MSG_LOADING_BLAME}); + this.$.diff.loadBlame() + .then(() => { + this._isBlameLoading = false; + this.fire('show-alert', {message: MSG_LOADED_BLAME}); + }) + .catch(() => { + this._isBlameLoading = false; + }); + }, + + _computeBlameLoaderClass(isImageDiff, supported) { + return !isImageDiff && supported ? 'show' : ''; + }, }); })(); |