Merge "Refactor account-links and avatars code"

This commit is contained in:
Dave Borowitz
2016-01-11 02:13:25 +00:00
committed by Gerrit Code Review
10 changed files with 324 additions and 88 deletions

View File

@@ -0,0 +1,91 @@
<!--
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="gr-avatar.html">
<dom-module id="gr-account-link">
<template>
<style>
:host {
display: inline;
}
a {
color: var(--default-text-color);
text-decoration: none;
}
a:hover span {
text-decoration: underline;
}
img {
height: 1.3em;
width: 1.3em;
vertical-align: -.3em;
}
</style>
<span>
<a href$="[[_computeOwnerLink(account)]]"
title$="[[_computeAccountTitle(account)]]">
<img is="gr-avatar" account="[[account]]" size="[[avatarSize]]">
<span>[[account.name]]</span>
<span hidden$="[[!_computeShowEmail(showEmail, account)]]">
(<span>[[account.email]]</span>)
</span>
</a>
</span>
</template>
<script>
(function() {
'use strict';
Polymer({
is: 'gr-account-link',
properties: {
account: Object,
avatarSize: {
type: Number,
value: 32,
},
showEmail: {
type: Boolean,
value: false,
},
},
_computeOwnerLink: function(account) {
if (!account) { return ''; }
var accountID = account.email || account._account_id;
return '/q/owner:' + encodeURIComponent(accountID) + '+status:open';
},
_computeAccountTitle: function(account) {
if (!account || !account.name) { return ''; }
var result = util.escapeHTML(account.name);
if (account.email) {
result += ' <' + util.escapeHTML(account.email) + '>';
}
return result;
},
_computeShowEmail: function(showEmail, account) {
return showEmail && account && account.email;
},
});
})();
</script>
</dom-module>

View File

@@ -0,0 +1,79 @@
<!--
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">
<dom-module id="gr-avatar">
<template>
<style>
:host {
border-radius: 50%;
}
</style>
</template>
<script>
(function() {
'use strict';
Polymer({
is: 'gr-avatar',
extends: 'img',
properties: {
account: {
type: Object,
observer: '_accountChanged',
},
size: {
type: Number,
value: 16,
},
},
created: function() {
this.hidden = true;
},
ready: function() {
app.configReady.then(function(cfg) {
var showAvatar = !!(cfg && cfg.plugin && cfg.plugin.has_avatars);
if (showAvatar) {
this.hidden = false;
this.updateAvatarSrc(this.account); // src needs to be set if avatar becomes visible
}
}.bind(this));
},
_accountChanged: function(account) {
this.updateAvatarSrc(account);
},
updateAvatarSrc: function(account) {
if (!this.hidden && account) {
this.setAttribute('src', this._buildAvatarURL(account));
}
},
_buildAvatarURL: function(account) {
if (!account) { return ''; }
return '/accounts/' + account._account_id + '/avatar?s=' + this.size;
},
});
})();
</script>
</dom-module>

View File

@@ -16,6 +16,7 @@ limitations under the License.
<link rel="import" href="../bower_components/polymer/polymer.html">
<link rel="import" href="../styles/gr-change-list-styles.html">
<link rel="import" href="gr-account-link.html">
<link rel="import" href="gr-date-formatter.html">
<dom-module id="gr-change-list-item">
@@ -45,12 +46,6 @@ limitations under the License.
:host([selected]) .positionIndicator {
visibility: visible;
}
.avatarImage {
border-radius: 50%;
height: 1.3em;
vertical-align: -.3em;
width: 1.3em;
}
.u-monospace {
font-family: var(--monospace-font-family);
}
@@ -68,11 +63,7 @@ limitations under the License.
<a class="cell subject" href$="[[changeURL]]">[[change.subject]]</a>
<span class="cell status">[[_computeChangeStatusString(change)]]</span>
<span class="cell owner">
<template is="dom-if" if="[[showAvatar]]">
<img class="avatarImage" src$="[[_computeAvatarURL(change.owner)]]">
</template>
<a href$="[[_computeOwnerLink(change.owner)]]"
title$="[[_computeOwnerTitle(change.owner)]]">[[change.owner.name]]</a>
<gr-account-link account="[[change.owner]]"></gr-account-link>
</span>
<a class="cell project" href$="[[_computeProjectURL(change.project)]]">[[change.project]]</a>
<a class="cell branch" href$="[[_computeProjectBranchURL(change.project, change.branch)]]">[[change.branch]]</a>
@@ -102,16 +93,6 @@ limitations under the License.
type: String,
computed: '_computeChangeURL(change._number)',
},
showAvatar: {
type: Boolean,
value: false,
},
},
ready: function() {
app.configReady.then(function(cfg) {
this.showAvatar = !!(cfg && cfg.plugin && cfg.plugin.has_avatars);
}.bind(this));
},
_computeChangeURL: function(changeNum) {
@@ -177,26 +158,6 @@ limitations under the License.
return ''
},
_computeAvatarURL: function(owner) {
if (!owner) { return ''; }
return '/accounts/' + owner._account_id + '/avatar?s=32'
},
_computeOwnerLink: function(owner) {
if (!owner) { return ''; }
var ownerID = owner.email || owner._account_id;
return '/q/owner:' + encodeURIComponent(ownerID) + '+status:open';
},
_computeOwnerTitle: function(owner) {
if (!owner || !owner.name) { return ''; }
var result = util.escapeHTML(owner.name);
if (owner.email) {
result += ' <' + util.escapeHTML(owner.email) + '>';
}
return result;
},
_computeProjectURL: function(project) {
return '/projects/' + project + ',dashboards/default';
},

View File

@@ -16,6 +16,7 @@ limitations under the License.
<link rel="import" href="../bower_components/polymer/polymer.html">
<link rel="import" href="../bower_components/iron-a11y-keys-behavior/iron-a11y-keys-behavior.html">
<link rel="import" href="gr-account-link.html">
<link rel="import" href="gr-ajax.html">
<link rel="import" href="gr-change-actions.html">
<link rel="import" href="gr-date-formatter.html">
@@ -177,10 +178,8 @@ limitations under the License.
<tr>
<td class="changeInfo-label">Owner</td>
<td>
<span>[[_change.owner.name]]</span>
<span hidden$="[[!_change.owner.email]]">
(<span>[[_change.owner.email]]</span>)
</span>
<gr-account-link account="[[_change.owner]]"
show-email></gr-account-link>
</td>
</tr>
<tr>
@@ -226,8 +225,8 @@ limitations under the License.
<div class="labelValue">
<span class$="[[label.className]]">
<span>[[label.value]]</span>
<span>[[label.accountName]]</span>
<span hidden$="[[!label.accountEmail]]">([[label.accountEmail]])</span>
<gr-account-link account="[[label.account]]"
show-email></gr-account-link>
</span>
</div>
</template>
@@ -444,8 +443,7 @@ limitations under the License.
result.push({
value: labelValPrefix + label.value,
className: labelClassName,
accountName: label.name,
accountEmail: label.email,
account: label,
});
}
});

View File

@@ -15,6 +15,7 @@ limitations under the License.
-->
<link rel="import" href="../bower_components/polymer/polymer.html">
<link rel="import" href="gr-account-link.html">
<link rel="import" href="gr-comment-list.html">
<link rel="import" href="gr-date-formatter.html">
@@ -29,15 +30,10 @@ limitations under the License.
:host(:not([expanded])) {
cursor: pointer;
}
.avatar {
border-radius: 50%;
[is="gr-avatar"] {
position: absolute;
left: var(--default-horizontal-margin);
}
:not(.hideAvatar):not(.showAvatar) .avatar,
.hideAvatar .avatar {
display: none;
}
.collapsed .contentContainer {
color: #777;
white-space: nowrap;
@@ -57,17 +53,13 @@ limitations under the License.
margin-left: 0;
padding: 10px 75px 10px 0;
}
.collapsed .avatar {
.collapsed [is="gr-avatar"] {
top: 8px;
}
.expanded .avatar {
top: 12px;
}
.collapsed .avatar {
height: 1.75em;
width: 1.75em;
}
.expanded .avatar {
.expanded [is="gr-avatar"] {
top: 12px;
height: 2.5em;
width: 2.5em;
}
@@ -100,7 +92,7 @@ limitations under the License.
}
</style>
<div class$="[[_computeClass(expanded, showAvatar)]]">
<img class="avatar" src$="[[_computeAvatarURL(message.author, showAvatar)]]">
<img is="gr-avatar" account="[[message.author]]" size="100">
<div class="contentContainer">
<div class="name" id="name">[[message.author.name]]</div>
<div class="content">
@@ -146,7 +138,8 @@ limitations under the License.
ready: function() {
app.configReady.then(function(cfg) {
this.showAvatar = !!(cfg && cfg.plugin && cfg.plugin.has_avatars);
this.showAvatar = !!(cfg && cfg.plugin && cfg.plugin.has_avatars) &&
this.message && this.message.author;
}.bind(this));
},
@@ -172,11 +165,6 @@ limitations under the License.
return classes.join(' ');
},
_computeAvatarURL: function(author, showAvatar) {
if (!showAvatar || !author) { return '' }
return '/accounts/' + author._account_id + '/avatar?s=100';
},
});
})();
</script>

View File

@@ -76,10 +76,7 @@ limitations under the License.
<template is="dom-repeat" items="[[_reviewers]]" as="reviewer">
<div class="reviewer">
<span>[[reviewer.name]]</span>
<span hidden$="[[!reviewer.email]]">
(<span>[[reviewer.email]]</span>)
</span>
<gr-account-link account="[[reviewer]]" show-email></gr-account-link>
<a class="remove"
href="#"
data-account-id$="[[reviewer._account_id]]"

View File

@@ -0,0 +1,66 @@
<!DOCTYPE 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.
-->
<meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
<title>gr-account-link</title>
<script src="../../bower_components/webcomponentsjs/webcomponents-lite.min.js"></script>
<script src="../../bower_components/web-component-tester/browser.js"></script>
<script src="../scripts/fake-app.js"></script>
<script src="../scripts/util.js"></script>
<link rel="import" href="../elements/gr-account-link.html">
<test-fixture id="basic">
<template>
<gr-account-link></gr-account-link>
</template>
</test-fixture>
<script>
suite('gr-account-link tests', function() {
var element;
setup(function() {
element = fixture('basic');
});
test('computed fields', function() {
assert.equal(element._computeOwnerLink(
{
_account_id: 123,
email: 'andybons+gerrit@gmail.com'
}),
'/q/owner:andybons%2Bgerrit%40gmail.com+status:open');
assert.equal(element._computeOwnerLink({ _account_id: 42 }),
'/q/owner:42+status:open');
assert.equal(element._computeAccountTitle(
{
name: 'Andrew Bonventre',
email: 'andybons+gerrit@gmail.com'
}),
'Andrew Bonventre <andybons+gerrit@gmail.com>');
assert.equal(element._computeAccountTitle(
{ name: 'Andrew Bonventre' }),
'Andrew Bonventre');
});
});
</script>

View File

@@ -0,0 +1,69 @@
<!DOCTYPE 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.
-->
<meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
<title>gr-avatar</title>
<script src="../../bower_components/webcomponentsjs/webcomponents-lite.min.js"></script>
<script src="../../bower_components/web-component-tester/browser.js"></script>
<script src="../scripts/fake-app.js"></script>
<link rel="import" href="../elements/gr-avatar.html">
<test-fixture id="basic">
<template>
<img is="gr-avatar">
</template>
</test-fixture>
<script>
suite('gr-avatar tests', function() {
var element;
setup(function() {
element = fixture('basic');
});
test('methods', function() {
assert.equal(element._buildAvatarURL(
{
_account_id: 123
}),
'/accounts/123/avatar?s=16');
});
test('dom for existing account', function() {
assert.isTrue(element.hasAttribute('hidden'), 'element not hidden initially');
element.hidden = false;
assert.isFalse(element.hasAttribute('hidden'), 'element hidden');
element.size = 64;
element.account = {
_account_id: 123
};
assert.equal(element.getAttribute('src'), '/accounts/123/avatar?s=64');
});
test('dom for non available account', function() {
assert.isTrue(element.hasAttribute('hidden'), 'element not hidden initially');
element.account = undefined;
assert.isFalse(element.hasAttribute('src'), 'src not set');
});
});
</script>

View File

@@ -72,21 +72,6 @@ limitations under the License.
assert.equal(element._computeVerifiedLabel({}), '');
assert.equal(element._computeVerifiedLabel({approved: true}), '✓');
assert.equal(element._computeOwnerLink(
{ email: 'andybons+gerrit@gmail.com' }),
'/q/owner:andybons%2Bgerrit%40gmail.com+status:open');
assert.equal(element._computeOwnerLink({ _account_id: 42 }),
'/q/owner:42+status:open');
assert.equal(element._computeOwnerTitle(
{
name: 'Andrew Bonventre',
email: 'andybons+gerrit@gmail.com'
}),
'Andrew Bonventre <andybons+gerrit@gmail.com>');
assert.equal(element._computeProjectURL('combustible-stuff'),
'/projects/combustible-stuff,dashboards/default');

View File

@@ -24,6 +24,8 @@ limitations under the License.
var testFiles = [];
[ 'gr-account-dropdown-test.html',
'gr-account-link-test.html',
'gr-avatar-test.html',
'gr-change-actions-test.html',
'gr-change-list-item-test.html',
'gr-change-list-test.html',