1b3d9536eb
Some additional cleanup of event names and fixing of the bubbles property not being placed in the right place. TODO in a follow-up change: + Comments are not considered in context, yet. So if there is a comment made in a span of common lines that are hidden, it will be there underneath the context control but wont show the code. Feature: Issue 3649 Change-Id: I8117b243a7d8d529e0c1cea155a4b6b436c0c768
317 lines
9.0 KiB
HTML
317 lines
9.0 KiB
HTML
<!--
|
|
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="../bower_components/iron-autogrow-textarea/iron-autogrow-textarea.html">
|
|
<link rel="import" href="../bower_components/iron-dropdown/iron-dropdown.html">
|
|
<link rel="import" href="../bower_components/iron-selector/iron-selector.html">
|
|
<link rel="import" href="gr-ajax.html">
|
|
<link rel="import" href="gr-request.html">
|
|
|
|
<dom-module id="gr-reply-dropdown">
|
|
<style>
|
|
:host {
|
|
display: inline-block;
|
|
}
|
|
:host([disabled]) {
|
|
pointer-events: none;
|
|
}
|
|
:host([disabled]) .dropdown-content {
|
|
opacity: .5;
|
|
}
|
|
.dropdown-content {
|
|
background-color: #fff;
|
|
box-shadow: 0 1px 5px rgba(0, 0, 0, .3);
|
|
}
|
|
button {
|
|
font: inherit;
|
|
background-color: #f1f2f3;
|
|
border: 1px solid #aaa;
|
|
border-radius: 2px;
|
|
padding: .2em .5em;
|
|
}
|
|
section {
|
|
border-top: 1px solid #ddd;
|
|
padding: .5em .75em;
|
|
}
|
|
.textareaContainer {
|
|
position: relative;
|
|
}
|
|
iron-autogrow-textarea {
|
|
padding: 0;
|
|
}
|
|
/* https://github.com/PolymerElements/iron-autogrow-textarea/pull/61 */
|
|
iron-autogrow-textarea::shadow #mirror,
|
|
iron-autogrow-textarea::shadow textarea {
|
|
white-space: pre-wrap;
|
|
}
|
|
.message {
|
|
border: none;
|
|
}
|
|
.label:first-of-type {
|
|
margin-bottom: .25em;
|
|
}
|
|
.labelName {
|
|
display: inline-block;
|
|
text-align: right;
|
|
width: 6em;
|
|
margin-right: .5em;
|
|
}
|
|
iron-selector {
|
|
display: inline-flex;
|
|
}
|
|
iron-selector > button {
|
|
background-color: #fff;
|
|
border: 1px solid #ddd;
|
|
border-left: none;
|
|
padding: .25em 0;
|
|
cursor: pointer;
|
|
width: 3em;
|
|
text-align: center;
|
|
}
|
|
iron-selector > button:first-of-type {
|
|
border-top-left-radius: 2px;
|
|
border-bottom-left-radius: 2px;
|
|
border-left: 1px solid #ddd;
|
|
}
|
|
iron-selector > button:last-of-type {
|
|
border-top-right-radius: 2px;
|
|
border-bottom-right-radius: 2px;
|
|
}
|
|
iron-selector > button.iron-selected {
|
|
background-color: #ddd;
|
|
}
|
|
.draftsContainer h3 {
|
|
margin-top: .25em;
|
|
}
|
|
.actionsContainer {
|
|
display: flex;
|
|
}
|
|
.action:link,
|
|
.action:visited {
|
|
color: #00e;
|
|
}
|
|
.danger {
|
|
display: flex;
|
|
flex: 1;
|
|
justify-content: flex-end;
|
|
}
|
|
</style>
|
|
<template>
|
|
<gr-ajax id="draftsXHR"
|
|
url="[[_computeDraftsURL(changeNum)]]"
|
|
last-response="{{_drafts}}"></gr-ajax>
|
|
<button id="trigger" on-tap="_showPopupTapHandler">Reply</button>
|
|
<iron-dropdown id="dropdown"
|
|
vertical-align="top"
|
|
vertical-offset="25"
|
|
horizontal-align="right">
|
|
<div class="dropdown-content">
|
|
<section class="textareaContainer">
|
|
<iron-autogrow-textarea
|
|
id="textarea"
|
|
class="message"
|
|
placeholder="Say something..."
|
|
disabled="{{disabled}}"
|
|
rows="1"
|
|
bind-value="{{_draft}}"></iron-autogrow-textarea>
|
|
</section>
|
|
<section>
|
|
<template is="dom-repeat"
|
|
items="[[_computeLabelArray(permittedLabels)]]" as="label">
|
|
<span class="labelName">[[label]]</span>
|
|
<iron-selector data-label$="[[label]]"
|
|
selected="[[_computeIndexOfLabelValue(labels, permittedLabels, label, _account)]]">
|
|
<template is="dom-repeat"
|
|
items="[[_computePermittedLabelValues(permittedLabels, label)]]"
|
|
as="value">
|
|
<button data-value$="[[value]]">[[value]]</button>
|
|
</template>
|
|
</iron-selector>
|
|
</template>
|
|
</section>
|
|
<section class="draftsContainer" hidden$="[[_computeHideDraftList(_drafts)]]">
|
|
<h3>[[_computeDraftsTitle(_drafts)]]</h3>
|
|
<gr-comment-list
|
|
comments="[[_drafts]]"
|
|
change-num="[[changeNum]]"
|
|
patch-num="[[patchNum]]"></gr-comment-list>
|
|
</section>
|
|
<section class="actionsContainer">
|
|
<a class="action send" href="#" on-tap="_sendTapHandler">Send</a>
|
|
<div class="danger">
|
|
<a class="action cancel" href="#" on-tap="_cancelTapHandler">Cancel</a>
|
|
</div>
|
|
</section>
|
|
</div>
|
|
</iron-dropdown>
|
|
</template>
|
|
<script>
|
|
(function() {
|
|
'use strict';
|
|
|
|
Polymer({
|
|
is: 'gr-reply-dropdown',
|
|
|
|
/**
|
|
* Fired when a reply is successfully sent.
|
|
*
|
|
* @event send
|
|
*/
|
|
|
|
properties: {
|
|
changeNum: String,
|
|
patchNum: String,
|
|
disabled: {
|
|
type: Boolean,
|
|
value: false,
|
|
reflectToAttribute: true,
|
|
},
|
|
labels: Object,
|
|
permittedLabels: Object,
|
|
|
|
_account: Object,
|
|
_drafts: Object,
|
|
_xhrPromise: Object, // Used for testing.
|
|
_draft: String,
|
|
},
|
|
|
|
get opened() {
|
|
return this.$.dropdown.opened;
|
|
},
|
|
|
|
ready: function() {
|
|
app.accountReady.then(function() {
|
|
this._account = app.account;
|
|
}.bind(this));
|
|
},
|
|
|
|
open: function() {
|
|
this.$.draftsXHR.generateRequest();
|
|
this.$.dropdown.open();
|
|
this.async(function() {
|
|
this.$.textarea.textarea.focus();
|
|
}.bind(this));
|
|
},
|
|
|
|
close: function() {
|
|
this._drafts = null;
|
|
this.$.dropdown.close();
|
|
},
|
|
|
|
_computeDraftsURL: function(changeNum) {
|
|
return '/changes/' + changeNum + '/drafts';
|
|
},
|
|
|
|
_computeHideDraftList: function(drafts) {
|
|
return Object.keys(drafts || {}).length == 0;
|
|
},
|
|
|
|
_computeDraftsTitle: function(drafts) {
|
|
var total = 0;
|
|
for (var file in drafts) {
|
|
total += drafts[file].length;
|
|
}
|
|
if (total == 0) { return ''; }
|
|
if (total == 1) { return '1 Draft'; }
|
|
if (total > 1) { return total + ' Drafts'; };
|
|
},
|
|
|
|
_computeLabelArray: function(labelsObj) {
|
|
return Object.keys(labelsObj).sort();
|
|
},
|
|
|
|
_computeIndexOfLabelValue: function(
|
|
labels, permittedLabels, labelName, account) {
|
|
var labelValue = labels[labelName].default_value;
|
|
|
|
// Is there an existing vote for the current user? If so, use that.
|
|
var votes = labels[labelName];
|
|
if (votes.all && votes.all.length > 0) {
|
|
for (var i = 0; i < votes.all.length; i++) {
|
|
if (votes.all[i]._account_id == account._account_id) {
|
|
labelValue = votes.all[i].value;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
for (var i = 0; i < permittedLabels[labelName].length; i++) {
|
|
var val = parseInt(permittedLabels[labelName][i], 10);
|
|
if (val == labelValue) {
|
|
return i;
|
|
}
|
|
}
|
|
return null;
|
|
},
|
|
|
|
_computePermittedLabelValues: function(permittedLabels, label) {
|
|
return permittedLabels[label];
|
|
},
|
|
|
|
_showPopupTapHandler: function(e) {
|
|
e.preventDefault();
|
|
this.open();
|
|
},
|
|
|
|
_cancelTapHandler: function(e) {
|
|
e.preventDefault();
|
|
this.$.dropdown.close();
|
|
},
|
|
|
|
_sendTapHandler: function(e) {
|
|
e.preventDefault();
|
|
var obj = {
|
|
drafts: 'PUBLISH_ALL_REVISIONS',
|
|
labels: {},
|
|
};
|
|
for (var label in this.permittedLabels) {
|
|
var selectorEl = this.$$('iron-selector[data-label="' + label + '"]');
|
|
var selectedVal = selectorEl.selectedItem.getAttribute('data-value');
|
|
selectedVal = parseInt(selectedVal, 10);
|
|
obj.labels[label] = selectedVal;
|
|
}
|
|
if (this._draft != null) {
|
|
obj.message = this._draft;
|
|
}
|
|
this.disabled = true;
|
|
this._send(obj).then(function(req) {
|
|
this.fire('send', null, {bubbles: false});
|
|
this._draft = '';
|
|
this.disabled = false;
|
|
this.$.dropdown.close();
|
|
}.bind(this)).catch(function(err) {
|
|
alert('Oops. Something went wrong. Check the console and bug the ' +
|
|
'PolyGerrit team for assistance.');
|
|
throw err;
|
|
}.bind(this));
|
|
},
|
|
|
|
_send: function(payload) {
|
|
var xhr = document.createElement('gr-request');
|
|
this._xhrPromise = xhr.send({
|
|
method: 'POST',
|
|
url: Changes.baseURL(this.changeNum, this.patchNum) + '/review',
|
|
body: payload,
|
|
});
|
|
|
|
return this._xhrPromise;
|
|
},
|
|
});
|
|
})();
|
|
</script>
|
|
</dom-module>
|