/** * @license * Copyright (C) 2016 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. */ (function() { 'use strict'; const PATCH_SET_PREFIX_PATTERN = /^Patch Set \d+: /; const LABEL_TITLE_SCORE_PATTERN = /^([A-Za-z0-9-]+)([+-]\d+)$/; /** * @appliesMixin Gerrit.FireMixin */ class GrMessage extends Polymer.mixinBehaviors( [ Gerrit.FireBehavior, ], Polymer.GestureEventListeners( Polymer.LegacyElementMixin( Polymer.Element))) { static get is() { return 'gr-message'; } /** * Fired when this message's reply link is tapped. * * @event reply */ /** * Fired when the message's timestamp is tapped. * * @event message-anchor-tap */ static get properties() { return { changeNum: Number, /** @type {?} */ message: Object, author: { type: Object, computed: '_computeAuthor(message)', }, comments: { type: Object, observer: '_commentsChanged', }, config: Object, hideAutomated: { type: Boolean, value: false, }, hidden: { type: Boolean, computed: '_computeIsHidden(hideAutomated, isAutomated)', reflectToAttribute: true, }, isAutomated: { type: Boolean, computed: '_computeIsAutomated(message)', }, showAvatar: { type: Boolean, computed: '_computeShowAvatar(author, config)', }, showOnBehalfOf: { type: Boolean, computed: '_computeShowOnBehalfOf(message)', }, showReplyButton: { type: Boolean, computed: '_computeShowReplyButton(message, _loggedIn)', }, projectName: { type: String, observer: '_projectNameChanged', }, /** * A mapping from label names to objects representing the minimum and * maximum possible values for that label. */ labelExtremes: Object, /** * @type {{ commentlinks: Array }} */ _projectConfig: Object, // Computed property needed to trigger Polymer value observing. _expanded: { type: Object, computed: '_computeExpanded(message.expanded)', }, _loggedIn: { type: Boolean, value: false, }, }; } static get observers() { return [ '_updateExpandedClass(message.expanded)', ]; } created() { super.created(); this.addEventListener('click', e => this._handleClick(e)); } ready() { super.ready(); this.$.restAPI.getConfig().then(config => { this.config = config; }); this.$.restAPI.getLoggedIn().then(loggedIn => { this._loggedIn = loggedIn; }); } _updateExpandedClass(expanded) { if (expanded) { this.classList.add('expanded'); } else { this.classList.remove('expanded'); } } _computeAuthor(message) { return message.author || message.updated_by; } _computeShowAvatar(author, config) { return !!(author && config && config.plugin && config.plugin.has_avatars); } _computeShowOnBehalfOf(message) { const author = message.author || message.updated_by; return !!(author && message.real_author && author._account_id != message.real_author._account_id); } _computeShowReplyButton(message, loggedIn) { return message && !!message.message && loggedIn && !this._computeIsAutomated(message); } _computeExpanded(expanded) { return expanded; } /** * If there is no value set on the message object as to whether _expanded * should be true or not, then _expanded is set to true if there are * inline comments (otherwise false). */ _commentsChanged(value) { if (this.message && this.message.expanded === undefined) { this.set('message.expanded', Object.keys(value || {}).length > 0); } } _handleClick(e) { if (this.message.expanded) { return; } e.stopPropagation(); this.set('message.expanded', true); } _handleAuthorClick(e) { if (!this.message.expanded) { return; } e.stopPropagation(); this.set('message.expanded', false); } _computeIsAutomated(message) { return !!(message.reviewer || this._computeIsReviewerUpdate(message) || (message.tag && message.tag.startsWith('autogenerated'))); } _computeIsHidden(hideAutomated, isAutomated) { return hideAutomated && isAutomated; } _computeIsReviewerUpdate(event) { return event.type === 'REVIEWER_UPDATE'; } _getScores(message) { if (!message.message) { return []; } const line = message.message.split('\n', 1)[0]; const patchSetPrefix = PATCH_SET_PREFIX_PATTERN; if (!line.match(patchSetPrefix)) { return []; } const scoresRaw = line.split(patchSetPrefix)[1]; if (!scoresRaw) { return []; } return scoresRaw.split(' ') .map(s => s.match(LABEL_TITLE_SCORE_PATTERN)) .filter(ms => ms && ms.length === 3) .map(ms => ({label: ms[1], value: ms[2]})); } _computeScoreClass(score, labelExtremes) { // Polymer 2: check for undefined if ([score, labelExtremes].some(arg => arg === undefined)) { return ''; } const classes = []; if (score.value > 0) { classes.push('positive'); } else if (score.value < 0) { classes.push('negative'); } const extremes = labelExtremes[score.label]; if (extremes) { const intScore = parseInt(score.value, 10); if (intScore === extremes.max) { classes.push('max'); } else if (intScore === extremes.min) { classes.push('min'); } } return classes.join(' '); } _computeClass(expanded, showAvatar, message) { const classes = []; classes.push(expanded ? 'expanded' : 'collapsed'); classes.push(showAvatar ? 'showAvatar' : 'hideAvatar'); return classes.join(' '); } _handleAnchorClick(e) { e.preventDefault(); this.dispatchEvent(new CustomEvent('message-anchor-tap', { bubbles: true, composed: true, detail: {id: this.message.id}, })); } _handleReplyTap(e) { e.preventDefault(); this.fire('reply', {message: this.message}); } _projectNameChanged(name) { this.$.restAPI.getProjectConfig(name).then(config => { this._projectConfig = config; }); } _computeExpandToggleIcon(expanded) { return expanded ? 'gr-icons:expand-less' : 'gr-icons:expand-more'; } _toggleExpanded(e) { e.stopPropagation(); this.set('message.expanded', !this.message.expanded); } } customElements.define(GrMessage.is, GrMessage); })();