/** * @license * Copyright (C) 2018 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'; /** * Fired when a comment is saved or deleted * * @event thread-list-modified */ class GrThreadList extends Polymer.GestureEventListeners( Polymer.LegacyElementMixin( Polymer.Element)) { static get is() { return 'gr-thread-list'; } static get properties() { return { /** @type {?} */ change: Object, threads: Array, changeNum: String, loggedIn: Boolean, _sortedThreads: { type: Array, }, _filteredThreads: { type: Array, computed: '_computeFilteredThreads(_sortedThreads, ' + '_unresolvedOnly, _draftsOnly)', }, _unresolvedOnly: { type: Boolean, value: false, }, _draftsOnly: { type: Boolean, value: false, }, }; } static get observers() { return ['_computeSortedThreads(threads.*)']; } _computeShowDraftToggle(loggedIn) { return loggedIn ? 'show' : ''; } /** * Order as follows: * - Unresolved threads with drafts (reverse chronological) * - Unresolved threads without drafts (reverse chronological) * - Resolved threads with drafts (reverse chronological) * - Resolved threads without drafts (reverse chronological) * @param {!Object} changeRecord */ _computeSortedThreads(changeRecord) { const threads = changeRecord.base; if (!threads) { return []; } this._updateSortedThreads(threads); } _updateSortedThreads(threads) { this._sortedThreads = threads.map(this._getThreadWithSortInfo).sort((c1, c2) => { const c1Date = c1.__date || util.parseDate(c1.updated); const c2Date = c2.__date || util.parseDate(c2.updated); const dateCompare = c2Date - c1Date; if (c2.unresolved || c1.unresolved) { if (!c1.unresolved) { return 1; } if (!c2.unresolved) { return -1; } } if (c2.hasDraft || c1.hasDraft) { if (!c1.hasDraft) { return 1; } if (!c2.hasDraft) { return -1; } } if (dateCompare === 0 && (!c1.id || !c1.id.localeCompare)) { return 0; } return dateCompare ? dateCompare : c1.id.localeCompare(c2.id); }); } _computeFilteredThreads(sortedThreads, unresolvedOnly, draftsOnly) { // Polymer 2: check for undefined if ([ sortedThreads, unresolvedOnly, draftsOnly, ].some(arg => arg === undefined)) { return undefined; } return sortedThreads.filter(c => { if (draftsOnly) { return c.hasDraft; } else if (unresolvedOnly) { return c.unresolved; } else { const comments = c && c.thread && c.thread.comments; let robotComment = false; let humanReplyToRobotComment = false; comments.forEach(comment => { if (comment.robot_id) { robotComment = true; } else if (robotComment) { // Robot comment exists and human comment exists after it humanReplyToRobotComment = true; } }); if (robotComment) { return humanReplyToRobotComment ? c : false; } return c; } }).map(threadInfo => threadInfo.thread); } _getThreadWithSortInfo(thread) { const lastComment = thread.comments[thread.comments.length - 1] || {}; const lastNonDraftComment = (lastComment.__draft && thread.comments.length > 1) ? thread.comments[thread.comments.length - 2] : lastComment; return { thread, // Use the unresolved bit for the last non draft comment. This is what // anybody other than the current user would see. unresolved: !!lastNonDraftComment.unresolved, hasDraft: !!lastComment.__draft, updated: lastComment.updated, }; } removeThread(rootId) { for (let i = 0; i < this.threads.length; i++) { if (this.threads[i].rootId === rootId) { this.splice('threads', i, 1); // Needed to ensure threads get re-rendered in the correct order. Polymer.dom.flush(); return; } } } _handleThreadDiscard(e) { this.removeThread(e.detail.rootId); } _handleCommentsChanged(e) { // Reset threads so thread computations occur on deep array changes to // threads comments that are not observed naturally. this._updateSortedThreads(this.threads); this.dispatchEvent(new CustomEvent('thread-list-modified', {detail: {rootId: e.detail.rootId, path: e.detail.path}})); } _isOnParent(side) { return !!side; } } customElements.define(GrThreadList.is, GrThreadList); })();