| <!-- |
| @license |
| Copyright (C) 2015 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. |
| --> |
| |
| <link rel="import" href="/bower_components/polymer/polymer.html"> |
| <link rel="import" href="../../../behaviors/async-foreach-behavior/async-foreach-behavior.html"> |
| <link rel="import" href="../../../behaviors/dom-util-behavior/dom-util-behavior.html"> |
| <link rel="import" href="../../../behaviors/fire-behavior/fire-behavior.html"> |
| <link rel="import" href="../../../behaviors/keyboard-shortcut-behavior/keyboard-shortcut-behavior.html"> |
| <link rel="import" href="../../../behaviors/gr-patch-set-behavior/gr-patch-set-behavior.html"> |
| <link rel="import" href="../../../styles/shared-styles.html"> |
| <link rel="import" href="../../core/gr-navigation/gr-navigation.html"> |
| <link rel="import" href="../../core/gr-reporting/gr-reporting.html"> |
| <link rel="import" href="../../diff/gr-diff-cursor/gr-diff-cursor.html"> |
| <link rel="import" href="../../diff/gr-diff-host/gr-diff-host.html"> |
| <link rel="import" href="../../diff/gr-diff-preferences-dialog/gr-diff-preferences-dialog.html"> |
| <link rel="import" href="../../edit/gr-edit-file-controls/gr-edit-file-controls.html"> |
| <link rel="import" href="../../shared/gr-button/gr-button.html"> |
| <link rel="import" href="../../shared/gr-cursor-manager/gr-cursor-manager.html"> |
| <link rel="import" href="../../shared/gr-icons/gr-icons.html"> |
| <link rel="import" href="../../shared/gr-linked-text/gr-linked-text.html"> |
| <link rel="import" href="../../shared/gr-rest-api-interface/gr-rest-api-interface.html"> |
| <link rel="import" href="../../shared/gr-select/gr-select.html"> |
| <link rel="import" href="../../shared/gr-count-string-formatter/gr-count-string-formatter.html"> |
| <link rel="import" href="../../shared/gr-tooltip-content/gr-tooltip-content.html"> |
| <link rel="import" href="../gr-file-list-constants.html"> |
| |
| <dom-module id="gr-file-list"> |
| <template> |
| <style include="shared-styles"> |
| :host { |
| display: block; |
| } |
| .row { |
| align-items: center; |
| border-top: 1px solid var(--border-color); |
| display: flex; |
| min-height: 2.25em; |
| padding: .2em var(--default-horizontal-margin) .2em calc(var(--default-horizontal-margin) - .35rem); |
| } |
| :host(.loading) .row { |
| opacity: .5; |
| }; |
| :host(.editMode) .hideOnEdit { |
| display: none; |
| } |
| .showOnEdit { |
| display: none; |
| } |
| :host(.editMode) .showOnEdit { |
| display: initial; |
| } |
| .invisible { |
| visibility: hidden; |
| } |
| .controlRow { |
| align-items: center; |
| display: flex; |
| height: 2.25em; |
| justify-content: center; |
| } |
| .controlRow.invisible, |
| .show-hide.invisible { |
| display: none; |
| } |
| .reviewed, |
| .status { |
| align-items: center; |
| display: inline-flex; |
| } |
| .reviewed, |
| .status { |
| display: inline-block; |
| text-align: left; |
| width: 1.5em; |
| } |
| .file-row { |
| cursor: pointer; |
| } |
| .file-row.expanded { |
| border-bottom: 1px solid var(--border-color); |
| position: -webkit-sticky; |
| position: sticky; |
| top: 0; |
| /* Has to visible above the diff view, and by default has a lower |
| z-index. setting to 1 places it directly above. */ |
| z-index: 1; |
| } |
| .file-row:hover { |
| background-color: var(--hover-background-color); |
| } |
| .file-row.selected { |
| background-color: var(--selection-background-color); |
| } |
| .file-row.expanded, |
| .file-row.expanded:hover { |
| background-color: var(--expanded-background-color); |
| } |
| .path { |
| cursor: pointer; |
| flex: 1; |
| text-decoration: none; |
| white-space: nowrap; |
| } |
| .path:hover :first-child { |
| text-decoration: underline; |
| } |
| .path, |
| .path div { |
| overflow: hidden; |
| text-overflow: ellipsis; |
| } |
| .oldPath { |
| color: var(--deemphasized-text-color); |
| } |
| .comments, |
| .stats { |
| text-align: right; |
| } |
| .comments { |
| padding-left: 2em; |
| } |
| .stats { |
| min-width: 7em; |
| } |
| .row:not(.header) .stats, |
| .total-stats { |
| font-family: var(--monospace-font-family); |
| } |
| .sizeBars { |
| margin-left: .5em; |
| } |
| .sizeBars.hide { |
| display: none; |
| } |
| .added, |
| .removed { |
| display: inline-block; |
| min-width: 3.5em; |
| } |
| .added { |
| color: var(--vote-text-color-recommended); |
| } |
| .removed { |
| color: var(--vote-text-color-disliked); |
| text-align: left; |
| } |
| .drafts { |
| color: #C62828; |
| font-weight: var(--font-weight-bold); |
| } |
| .show-hide { |
| margin-left: .35em; |
| width: 1.9em; |
| } |
| .fileListButton { |
| margin: .5em; |
| } |
| .totalChanges { |
| justify-content: flex-end; |
| text-align: right; |
| } |
| .warning { |
| color: var(--deemphasized-text-color); |
| } |
| input.show-hide { |
| display: none; |
| } |
| label.show-hide { |
| cursor: pointer; |
| display: block; |
| min-width: 2em; |
| } |
| gr-diff { |
| display: block; |
| overflow-x: auto; |
| } |
| .truncatedFileName { |
| display: none; |
| } |
| .expanded .fullFileName { |
| white-space: normal; |
| word-wrap: break-word; |
| } |
| .mobile { |
| display: none; |
| } |
| .reviewed { |
| margin-left: 2em; |
| width: 15em; |
| } |
| .reviewed label { |
| color: var(--link-color); |
| opacity: 0; |
| justify-content: flex-end; |
| width: 100%; |
| } |
| .reviewed label:hover { |
| cursor: pointer; |
| opacity: 100; |
| } |
| .row:focus { |
| outline: none; |
| } |
| .row:hover .reviewed label, |
| .row:focus .reviewed label, |
| .row.expanded .reviewed label { |
| opacity: 100; |
| } |
| .reviewed input { |
| display: none; |
| } |
| .reviewedLabel { |
| color: var(--deemphasized-text-color); |
| margin-right: 1em; |
| opacity: 0; |
| } |
| .reviewedLabel.isReviewed { |
| display: initial; |
| opacity: 100; |
| } |
| .editFileControls { |
| width: 7em; |
| } |
| .markReviewed, |
| .pathLink { |
| display: inline-block; |
| margin: -.2em 0; |
| padding: .4em 0; |
| } |
| @media screen and (max-width: 50em) { |
| .desktop { |
| display: none; |
| } |
| .mobile { |
| display: block; |
| } |
| .row.selected { |
| background-color: var(--view-background-color); |
| } |
| .stats { |
| display: none; |
| } |
| .reviewed, |
| .status { |
| justify-content: flex-start; |
| } |
| .reviewed { |
| display: none; |
| } |
| .comments { |
| min-width: initial; |
| } |
| .expanded .fullFileName, |
| .truncatedFileName { |
| display: block; |
| } |
| .expanded .truncatedFileName, |
| .fullFileName { |
| display: none; |
| } |
| } |
| </style> |
| <div |
| id="container" |
| on-tap="_handleFileListTap"> |
| <template is="dom-repeat" |
| items="[[_shownFiles]]" |
| id="files" |
| as="file" |
| initial-count="[[fileListIncrement]]" |
| target-framerate="1"> |
| [[_reportRenderedRow(index)]] |
| <div class="stickyArea"> |
| <div class$="file-row row [[_computePathClass(file.__path, _expandedFilePaths.*)]]" |
| data-path$="[[file.__path]]" tabindex="-1"> |
| <div class$="[[_computeClass('status', file.__path)]]" |
| tabindex="0" |
| title$="[[_computeFileStatusLabel(file.status)]]" |
| aria-label$="[[_computeFileStatusLabel(file.status)]]"> |
| [[_computeFileStatus(file.status)]] |
| </div> |
| <span |
| data-url="[[_computeDiffURL(change, patchRange.patchNum, patchRange.basePatchNum, file.__path, editMode)]]" |
| class="path"> |
| <a class="pathLink" href$="[[_computeDiffURL(change, patchRange.patchNum, patchRange.basePatchNum, file.__path, editMode)]]"> |
| <span title$="[[computeDisplayPath(file.__path)]]" |
| class="fullFileName"> |
| [[computeDisplayPath(file.__path)]] |
| </span> |
| <span title$="[[computeDisplayPath(file.__path)]]" |
| class="truncatedFileName"> |
| [[computeTruncatedPath(file.__path)]] |
| </span> |
| </a> |
| <div class="oldPath" hidden$="[[!file.old_path]]" hidden |
| title$="[[file.old_path]]"> |
| [[file.old_path]] |
| </div> |
| </span> |
| <div class="comments desktop"> |
| <span class="drafts"> |
| [[_computeDraftsString(changeComments, patchRange, file.__path)]] |
| </span> |
| [[_computeCommentsString(changeComments, patchRange, file.__path)]] |
| </div> |
| <div class="comments mobile"> |
| <span class="drafts"> |
| [[_computeDraftsStringMobile(changeComments, patchRange, |
| file.__path)]] |
| </span> |
| [[_computeCommentsStringMobile(changeComments, patchRange, |
| file.__path)]] |
| </div> |
| <div class$="[[_computeSizeBarsClass(_showSizeBars, file.__path)]]"> |
| <svg width="61" height="8"> |
| <rect |
| x$="[[_computeBarAdditionX(file, _sizeBarLayout)]]" |
| y="0" |
| height="8" |
| fill="#388E3C" |
| width$="[[_computeBarAdditionWidth(file, _sizeBarLayout)]]" /> |
| <rect |
| x$="[[_computeBarDeletionX(_sizeBarLayout)]]" |
| y="0" |
| height="8" |
| fill="#D32F2F" |
| width$="[[_computeBarDeletionWidth(file, _sizeBarLayout)]]" /> |
| </svg> |
| </div> |
| <div class$="[[_computeClass('stats', file.__path)]]"> |
| <span |
| class="added" |
| tabindex="0" |
| aria-label$="[[file.lines_inserted]] lines added" |
| hidden$=[[file.binary]]> |
| +[[file.lines_inserted]] |
| </span> |
| <span |
| class="removed" |
| tabindex="0" |
| aria-label$="[[file.lines_deleted]] lines removed" |
| hidden$=[[file.binary]]> |
| -[[file.lines_deleted]] |
| </span> |
| <span class$="[[_computeBinaryClass(file.size_delta)]]" |
| hidden$=[[!file.binary]]> |
| [[_formatBytes(file.size_delta)]] |
| [[_formatPercentage(file.size, file.size_delta)]] |
| </span> |
| </div> |
| <div class="reviewed hideOnEdit" hidden$="[[!_loggedIn]]" hidden> |
| <span class$="reviewedLabel [[_computeReviewedClass(file.isReviewed)]]">Reviewed</span> |
| <label> |
| <input class="reviewed" type="checkbox" checked="[[file.isReviewed]]"> |
| <span class="markReviewed" title$="[[_reviewedTitle(file.isReviewed)]]">[[_computeReviewedText(file.isReviewed)]]</span> |
| </label> |
| </div> |
| <div class="editFileControls showOnEdit"> |
| <template is="dom-if" if="[[editMode]]"> |
| <gr-edit-file-controls |
| class$="[[_computeClass('', file.__path)]]" |
| file-path="[[file.__path]]"></gr-edit-file-controls> |
| </template> |
| </div> |
| <div class="show-hide"> |
| <label class="show-hide" data-path$="[[file.__path]]" |
| data-expand=true> |
| <input type="checkbox" class="show-hide" |
| checked$="[[_isFileExpanded(file.__path, _expandedFilePaths.*)]]" |
| data-path$="[[file.__path]]" data-expand=true> |
| <iron-icon |
| id="icon" |
| icon="[[_computeShowHideIcon(file.__path, _expandedFilePaths.*)]]"> |
| </iron-icon> |
| </label> |
| </div> |
| </div> |
| <template is="dom-if" |
| if="[[_isFileExpanded(file.__path, _expandedFilePaths.*)]]"> |
| <gr-diff-host |
| no-auto-render |
| show-load-failure |
| display-line="[[_displayLine]]" |
| inline-index=[[index]] |
| hidden="[[!_isFileExpanded(file.__path, _expandedFilePaths.*)]]" |
| change-num="[[changeNum]]" |
| patch-range="[[patchRange]]" |
| path="[[file.__path]]" |
| prefs="[[diffPrefs]]" |
| project-name="[[change.project]]" |
| on-line-selected="_onLineSelected" |
| no-render-on-prefs-change |
| view-mode="[[diffViewMode]]"></gr-diff-host> |
| </template> |
| </div> |
| </template> |
| </div> |
| <div |
| class="row totalChanges" |
| hidden$="[[_hideChangeTotals]]"> |
| <div class="total-stats"> |
| <span |
| class="added" |
| tabindex="0" |
| aria-label$="[[_patchChange.inserted]] lines added"> |
| +[[_patchChange.inserted]] |
| </span> |
| <span |
| class="removed" |
| tabindex="0" |
| aria-label$="[[_patchChange.deleted]] lines removed"> |
| -[[_patchChange.deleted]] |
| </span> |
| </div> |
| <!-- Empty div here exists to keep spacing in sync with file rows. --> |
| <div class="reviewed hideOnEdit" hidden$="[[!_loggedIn]]" hidden></div> |
| <div class="editFileControls showOnEdit"></div> |
| <div class="show-hide"></div> |
| </div> |
| <div |
| class="row totalChanges" |
| hidden$="[[_hideBinaryChangeTotals]]"> |
| <div class="total-stats"> |
| <span class="added" aria-label="Total lines added"> |
| [[_formatBytes(_patchChange.size_delta_inserted)]] |
| [[_formatPercentage(_patchChange.total_size, |
| _patchChange.size_delta_inserted)]] |
| </span> |
| <span class="removed" aria-label="Total lines removed"> |
| [[_formatBytes(_patchChange.size_delta_deleted)]] |
| [[_formatPercentage(_patchChange.total_size, |
| _patchChange.size_delta_deleted)]] |
| </span> |
| </div> |
| </div> |
| <div class$="row controlRow [[_computeFileListControlClass(numFilesShown, _files)]]"> |
| <gr-button |
| class="fileListButton" |
| id="incrementButton" |
| link on-click="_incrementNumFilesShown"> |
| [[_computeIncrementText(numFilesShown, _files)]] |
| </gr-button> |
| <gr-tooltip-content |
| has-tooltip="[[_computeWarnShowAll(_files)]]" |
| show-icon="[[_computeWarnShowAll(_files)]]" |
| title$="[[_computeShowAllWarning(_files)]]"> |
| <gr-button |
| class="fileListButton" |
| id="showAllButton" |
| link on-click="_showAllFiles"> |
| [[_computeShowAllText(_files)]] |
| </gr-button><!-- |
| --></gr-tooltip-content> |
| </div> |
| <gr-diff-preferences-dialog |
| id="diffPreferencesDialog" |
| diff-prefs="{{diffPrefs}}" |
| on-reload-diff-preference="_handleReloadingDiffPreference"> |
| </gr-diff-preferences-dialog> |
| <gr-rest-api-interface id="restAPI"></gr-rest-api-interface> |
| <gr-storage id="storage"></gr-storage> |
| <gr-diff-cursor id="diffCursor"></gr-diff-cursor> |
| <gr-cursor-manager |
| id="fileCursor" |
| scroll-behavior="keep-visible" |
| focus-on-move |
| cursor-target-class="selected"></gr-cursor-manager> |
| <gr-reporting id="reporting"></gr-reporting> |
| </template> |
| <script src="gr-file-list.js"></script> |
| </dom-module> |