
Until the thread list was added, we rarely rendered a large number of diff comments at once. A diff would add them incrementally in an asynchronous loop, and even then, their number was reduced by being filtered to to the given path and patch range. Rendering all comments at once in the thread list exposed inefficiencies in instantiating gr-diff-comments, and, for changes with many comments, could temporarily lockup the browser. The biggest cause of slowness in comment instantiation was the textarea for editing. Because existing comments are not in an edit state by default (...and because only the final comment in a thread can be edited anyway ... assuming the user even chooses to edit ... assuming there even is an authenticated user...) it's more efficient to put the textarea in a dom-if until it's needed. The overlays are also expensive but infrequently used. These are put inside a dom-if as well. Change-Id: I50702afe2b178221110ad3200c5e3862a7722c5d
372 lines
12 KiB
HTML
372 lines
12 KiB
HTML
<!--
|
|
@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/keyboard-shortcut-behavior/keyboard-shortcut-behavior.html">
|
|
<link rel="import" href="../../../bower_components/iron-autogrow-textarea/iron-autogrow-textarea.html">
|
|
<link rel="import" href="../../../styles/shared-styles.html">
|
|
<link rel="import" href="../../plugins/gr-endpoint-decorator/gr-endpoint-decorator.html">
|
|
<link rel="import" href="../../plugins/gr-endpoint-param/gr-endpoint-param.html">
|
|
<link rel="import" href="../../shared/gr-button/gr-button.html">
|
|
<link rel="import" href="../../shared/gr-confirm-dialog/gr-confirm-dialog.html">
|
|
<link rel="import" href="../../shared/gr-date-formatter/gr-date-formatter.html">
|
|
<link rel="import" href="../../shared/gr-formatted-text/gr-formatted-text.html">
|
|
<link rel="import" href="../../shared/gr-overlay/gr-overlay.html">
|
|
<link rel="import" href="../../shared/gr-rest-api-interface/gr-rest-api-interface.html">
|
|
<link rel="import" href="../../shared/gr-storage/gr-storage.html">
|
|
<link rel="import" href="../../shared/gr-textarea/gr-textarea.html">
|
|
<link rel="import" href="../../shared/gr-tooltip-content/gr-tooltip-content.html">
|
|
<link rel="import" href="../gr-confirm-delete-comment-dialog/gr-confirm-delete-comment-dialog.html">
|
|
|
|
<script src="../../../scripts/rootElement.js"></script>
|
|
|
|
<dom-module id="gr-diff-comment">
|
|
<template>
|
|
<style include="shared-styles">
|
|
:host {
|
|
display: block;
|
|
font-family: var(--font-family);
|
|
padding: .7em .7em;
|
|
--iron-autogrow-textarea: {
|
|
box-sizing: border-box;
|
|
padding: 2px;
|
|
};
|
|
}
|
|
:host([disabled]) {
|
|
pointer-events: none;
|
|
}
|
|
:host([disabled]) .body,
|
|
:host([disabled]) .date {
|
|
opacity: .5;
|
|
}
|
|
.header {
|
|
align-items: baseline;
|
|
cursor: pointer;
|
|
display: flex;
|
|
font-family: 'Open Sans', sans-serif;
|
|
margin-bottom: 0.7em;
|
|
padding-bottom: 0;
|
|
}
|
|
.container.collapsed .header {
|
|
margin: 0;
|
|
}
|
|
.headerMiddle {
|
|
color: #666;
|
|
flex: 1;
|
|
overflow: hidden;
|
|
}
|
|
.authorName,
|
|
.draftLabel,
|
|
.draftTooltip {
|
|
font-family: var(--font-family-bold);
|
|
}
|
|
.draftLabel,
|
|
.draftTooltip {
|
|
color: #999;
|
|
display: none;
|
|
}
|
|
.date {
|
|
justify-content: flex-end;
|
|
margin-left: 5px;
|
|
min-width: 4.5em;
|
|
text-align: right;
|
|
white-space: nowrap;
|
|
}
|
|
a.date:link,
|
|
a.date:visited {
|
|
color: #666;
|
|
}
|
|
.actions {
|
|
display: flex;
|
|
justify-content: flex-end;
|
|
padding-top: 0;
|
|
}
|
|
.action {
|
|
margin-left: 1em;
|
|
--gr-button-color: #212121;
|
|
}
|
|
.robotActions {
|
|
display: flex;
|
|
justify-content: flex-start;
|
|
padding-top: 0;
|
|
}
|
|
.robotActions .action {
|
|
/* Keep button text lined up with output text */
|
|
margin-left: -.3rem;
|
|
margin-right: 1em;
|
|
}
|
|
.rightActions {
|
|
display: flex;
|
|
justify-content: flex-end;
|
|
}
|
|
.editMessage {
|
|
display: none;
|
|
margin: .5em 0;
|
|
width: 100%;
|
|
}
|
|
.container:not(.draft) .actions .hideOnPublished {
|
|
display: none;
|
|
}
|
|
.draft .reply,
|
|
.draft .quote,
|
|
.draft .ack,
|
|
.draft .done {
|
|
display: none;
|
|
}
|
|
.draft .draftLabel,
|
|
.draft .draftTooltip {
|
|
display: inline;
|
|
}
|
|
.draft:not(.editing) .save,
|
|
.draft:not(.editing) .cancel {
|
|
display: none;
|
|
}
|
|
.editing .message,
|
|
.editing .reply,
|
|
.editing .quote,
|
|
.editing .ack,
|
|
.editing .done,
|
|
.editing .edit,
|
|
.editing .discard,
|
|
.editing .unresolved {
|
|
display: none;
|
|
}
|
|
.editing .editMessage {
|
|
display: block;
|
|
}
|
|
.show-hide {
|
|
margin-left: .4em;
|
|
}
|
|
.robotId {
|
|
color: #808080;
|
|
margin-bottom: .8em;
|
|
margin-top: -.4em;
|
|
}
|
|
.runIdInformation {
|
|
margin: .7em 0;
|
|
}
|
|
.robotRun {
|
|
margin-left: .5em;
|
|
}
|
|
.robotRunLink {
|
|
margin-left: .5em;
|
|
}
|
|
input.show-hide {
|
|
display: none;
|
|
}
|
|
label.show-hide {
|
|
color: #000;
|
|
cursor: pointer;
|
|
display: block;
|
|
font-size: .8rem;
|
|
height: 1.1em;
|
|
margin-top: .1em;
|
|
}
|
|
#container .collapsedContent {
|
|
display: none;
|
|
}
|
|
#container.collapsed {
|
|
padding-bottom: 3px;
|
|
}
|
|
#container.collapsed .collapsedContent {
|
|
display: block;
|
|
overflow: hidden;
|
|
padding-left: 5px;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
}
|
|
#container.collapsed .actions,
|
|
#container.collapsed gr-formatted-text,
|
|
#container.collapsed gr-textarea {
|
|
display: none;
|
|
}
|
|
.resolve,
|
|
.unresolved {
|
|
align-items: center;
|
|
display: flex;
|
|
flex: 1;
|
|
margin: 0;
|
|
}
|
|
.resolve label {
|
|
color: #333;
|
|
font-size: var(--font-size-small);
|
|
}
|
|
gr-confirm-dialog .main {
|
|
background-color: #fef;
|
|
display: flex;
|
|
flex-direction: column;
|
|
width: 100%;
|
|
}
|
|
#deleteBtn {
|
|
display: none;
|
|
--gr-button: {
|
|
color: #666;
|
|
padding: 0;
|
|
}
|
|
}
|
|
#deleteBtn.showDeleteButtons {
|
|
display: block;
|
|
}
|
|
#savingMessage {
|
|
display: none;
|
|
}
|
|
:host([disabled]) #savingMessage {
|
|
display: inline;
|
|
}
|
|
</style>
|
|
<div id="container"
|
|
class="container"
|
|
on-mouseenter="_handleMouseEnter"
|
|
on-mouseleave="_handleMouseLeave">
|
|
<div class="header" id="header" on-click="_handleToggleCollapsed">
|
|
<div class="headerLeft">
|
|
<span class="authorName">[[comment.author.name]]</span>
|
|
<span class="draftLabel">DRAFT</span>
|
|
<gr-tooltip-content class="draftTooltip"
|
|
has-tooltip
|
|
title="This draft is only visible to you. To publish drafts, click the red 'Reply' button at the top of the change or press the 'A' key."
|
|
max-width="20em"
|
|
show-icon></gr-tooltip-content>
|
|
<span id="savingMessage">[[_savingMessage]]</span>
|
|
</div>
|
|
<div class="headerMiddle">
|
|
<span class="collapsedContent">[[comment.message]]</span>
|
|
</div>
|
|
<gr-button
|
|
id="deleteBtn"
|
|
link
|
|
class$="action delete [[_computeDeleteButtonClass(_isAdmin, draft)]]"
|
|
on-tap="_handleCommentDelete">
|
|
(Delete)
|
|
</gr-button>
|
|
<a class="date" href$="[[_computeLinkToComment(comment)]]" on-tap="_handleLinkTap">
|
|
<gr-date-formatter
|
|
has-tooltip
|
|
date-str="[[comment.updated]]"></gr-date-formatter>
|
|
</a>
|
|
<div class="show-hide">
|
|
<label class="show-hide">
|
|
<input type="checkbox" class="show-hide"
|
|
checked$="[[collapsed]]"
|
|
on-change="_handleToggleCollapsed">
|
|
[[_computeShowHideText(collapsed)]]
|
|
</label>
|
|
</div>
|
|
</div>
|
|
<div class="body">
|
|
<template is="dom-if" if="[[comment.robot_id]]">
|
|
<div class="robotId" hidden$="[[collapsed]]">
|
|
[[comment.robot_id]]
|
|
</div>
|
|
</template>
|
|
<template is="dom-if" if="[[editing]]">
|
|
<gr-textarea
|
|
id="editTextarea"
|
|
class="editMessage"
|
|
autocomplete="on"
|
|
monospace
|
|
disabled="{{disabled}}"
|
|
rows="4"
|
|
text="{{_messageText}}"></gr-textarea>
|
|
</template>
|
|
<!--The message class is needed to ensure selectability from
|
|
gr-diff-selection.-->
|
|
<gr-formatted-text class="message"
|
|
content="[[comment.message]]"
|
|
no-trailing-margin="[[!comment.__draft]]"
|
|
collapsed="[[collapsed]]"
|
|
config="[[projectConfig.commentlinks]]"></gr-formatted-text>
|
|
<div hidden$="[[!comment.robot_run_id]]" class="message">
|
|
<div class="runIdInformation" hidden$="[[collapsed]]">
|
|
Run ID:
|
|
<template is="dom-if" if="[[comment.url]]">
|
|
<a class="robotRunLink" href$="[[comment.url]]">
|
|
<span class="robotRun link">[[comment.robot_run_id]]</span>
|
|
</a>
|
|
</template>
|
|
<template is="dom-if" if="[[!comment.url]]">
|
|
<span class="robotRun text">[[comment.robot_run_id]]</span>
|
|
</template>
|
|
</div>
|
|
</div>
|
|
<div class="actions humanActions" hidden$="[[!_showHumanActions]]">
|
|
<div class="action resolve hideOnPublished">
|
|
<label>
|
|
<input type="checkbox"
|
|
id="resolvedCheckbox"
|
|
checked="[[resolved]]"
|
|
on-change="_handleToggleResolved">
|
|
Resolved
|
|
</label>
|
|
</div>
|
|
<div class="rightActions">
|
|
<gr-button link class="action cancel hideOnPublished"
|
|
on-tap="_handleCancel">Cancel</gr-button>
|
|
<gr-button link class="action discard hideOnPublished"
|
|
on-tap="_handleDiscard">Discard</gr-button>
|
|
<gr-button link class="action edit hideOnPublished"
|
|
on-tap="_handleEdit">Edit</gr-button>
|
|
<gr-button link class="action save hideOnPublished"
|
|
on-tap="_handleSave"
|
|
disabled$="[[_computeSaveDisabled(_messageText, comment, resolved)]]">Save
|
|
</gr-button>
|
|
</div>
|
|
</div>
|
|
<div class="robotActions" hidden$="[[!_showRobotActions]]">
|
|
<template is="dom-if" if="[[isRobotComment]]">
|
|
<gr-button link class="action fix"
|
|
on-tap="_handleFix"
|
|
disabled="[[robotButtonDisabled]]">
|
|
Please Fix
|
|
</gr-button>
|
|
<gr-endpoint-decorator name="robot-comment-controls">
|
|
<gr-endpoint-param name="comment" value="[[comment]]">
|
|
</gr-endpoint-param>
|
|
</gr-endpoint-decorator>
|
|
</template>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<template is="dom-if" if="[[_enableOverlay]]">
|
|
<gr-overlay id="confirmDeleteOverlay" with-backdrop>
|
|
<gr-confirm-delete-comment-dialog id="confirmDeleteComment"
|
|
on-confirm="_handleConfirmDeleteComment"
|
|
on-cancel="_handleCancelDeleteComment">
|
|
</gr-confirm-delete-comment-dialog>
|
|
</gr-overlay>
|
|
<gr-overlay id="confirmDiscardOverlay" with-backdrop>
|
|
<gr-confirm-dialog
|
|
id="confirmDiscardDialog"
|
|
confirm-label="Discard"
|
|
confirm-on-enter
|
|
on-confirm="_handleConfirmDiscard"
|
|
on-cancel="_closeConfirmDiscardOverlay">
|
|
<div class="header" slot="header">
|
|
Discard comment
|
|
</div>
|
|
<div class="main" slot="main">
|
|
Are you sure you want to discard this draft comment?
|
|
</div>
|
|
</gr-confirm-dialog>
|
|
</gr-overlay>
|
|
</template>
|
|
<gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
|
|
<gr-storage id="storage"></gr-storage>
|
|
</template>
|
|
<script src="gr-diff-comment.js"></script>
|
|
</dom-module>
|