| /** |
| * @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 EventType = { |
| HISTORY: 'history', |
| LABEL_CHANGE: 'labelchange', |
| SHOW_CHANGE: 'showchange', |
| SUBMIT_CHANGE: 'submitchange', |
| COMMIT_MSG_EDIT: 'commitmsgedit', |
| COMMENT: 'comment', |
| REVERT: 'revert', |
| REVERT_SUBMISSION: 'revert_submission', |
| POST_REVERT: 'postrevert', |
| ANNOTATE_DIFF: 'annotatediff', |
| ADMIN_MENU_LINKS: 'admin-menu-links', |
| HIGHLIGHTJS_LOADED: 'highlightjs-loaded', |
| }; |
| |
| const Element = { |
| CHANGE_ACTIONS: 'changeactions', |
| REPLY_DIALOG: 'replydialog', |
| }; |
| |
| /** |
| * @appliesMixin Gerrit.PatchSetMixin |
| */ |
| class GrJsApiInterface extends Polymer.mixinBehaviors( [ |
| Gerrit.PatchSetBehavior, |
| ], Polymer.GestureEventListeners( |
| Polymer.LegacyElementMixin( |
| Polymer.Element))) { |
| static get is() { return 'gr-js-api-interface'; } |
| |
| constructor() { |
| super(); |
| this.Element = Element; |
| this.EventType = EventType; |
| } |
| |
| static get properties() { |
| return { |
| _elements: { |
| type: Object, |
| value: {}, // Shared across all instances. |
| }, |
| _eventCallbacks: { |
| type: Object, |
| value: {}, // Shared across all instances. |
| }, |
| }; |
| } |
| |
| handleEvent(type, detail) { |
| Gerrit.awaitPluginsLoaded().then(() => { |
| switch (type) { |
| case EventType.HISTORY: |
| this._handleHistory(detail); |
| break; |
| case EventType.SHOW_CHANGE: |
| this._handleShowChange(detail); |
| break; |
| case EventType.COMMENT: |
| this._handleComment(detail); |
| break; |
| case EventType.LABEL_CHANGE: |
| this._handleLabelChange(detail); |
| break; |
| case EventType.HIGHLIGHTJS_LOADED: |
| this._handleHighlightjsLoaded(detail); |
| break; |
| default: |
| console.warn('handleEvent called with unsupported event type:', |
| type); |
| break; |
| } |
| }); |
| } |
| |
| addElement(key, el) { |
| this._elements[key] = el; |
| } |
| |
| getElement(key) { |
| return this._elements[key]; |
| } |
| |
| addEventCallback(eventName, callback) { |
| if (!this._eventCallbacks[eventName]) { |
| this._eventCallbacks[eventName] = []; |
| } |
| this._eventCallbacks[eventName].push(callback); |
| } |
| |
| canSubmitChange(change, revision) { |
| const submitCallbacks = this._getEventCallbacks(EventType.SUBMIT_CHANGE); |
| const cancelSubmit = submitCallbacks.some(callback => { |
| try { |
| return callback(change, revision) === false; |
| } catch (err) { |
| console.error(err); |
| } |
| return false; |
| }); |
| |
| return !cancelSubmit; |
| } |
| |
| _removeEventCallbacks() { |
| for (const k in EventType) { |
| if (!EventType.hasOwnProperty(k)) { continue; } |
| this._eventCallbacks[EventType[k]] = []; |
| } |
| } |
| |
| _handleHistory(detail) { |
| for (const cb of this._getEventCallbacks(EventType.HISTORY)) { |
| try { |
| cb(detail.path); |
| } catch (err) { |
| console.error(err); |
| } |
| } |
| } |
| |
| _handleShowChange(detail) { |
| // Note (issue 8221) Shallow clone the change object and add a mergeable |
| // getter with deprecation warning. This makes the change detail appear as |
| // though SKIP_MERGEABLE was not set, so that plugins that expect it can |
| // still access. |
| // |
| // This clone and getter can be removed after plugins migrate to use |
| // info.mergeable. |
| const change = Object.assign({ |
| get mergeable() { |
| console.warn('Accessing change.mergeable from SHOW_CHANGE is ' + |
| 'deprecated! Use info.mergeable instead.'); |
| return detail.info.mergeable; |
| }, |
| }, detail.change); |
| const patchNum = detail.patchNum; |
| const info = detail.info; |
| |
| let revision; |
| for (const rev of Object.values(change.revisions || {})) { |
| if (this.patchNumEquals(rev._number, patchNum)) { |
| revision = rev; |
| break; |
| } |
| } |
| |
| for (const cb of this._getEventCallbacks(EventType.SHOW_CHANGE)) { |
| try { |
| cb(change, revision, info); |
| } catch (err) { |
| console.error(err); |
| } |
| } |
| } |
| |
| handleCommitMessage(change, msg) { |
| for (const cb of this._getEventCallbacks(EventType.COMMIT_MSG_EDIT)) { |
| try { |
| cb(change, msg); |
| } catch (err) { |
| console.error(err); |
| } |
| } |
| } |
| |
| _handleComment(detail) { |
| for (const cb of this._getEventCallbacks(EventType.COMMENT)) { |
| try { |
| cb(detail.node); |
| } catch (err) { |
| console.error(err); |
| } |
| } |
| } |
| |
| _handleLabelChange(detail) { |
| for (const cb of this._getEventCallbacks(EventType.LABEL_CHANGE)) { |
| try { |
| cb(detail.change); |
| } catch (err) { |
| console.error(err); |
| } |
| } |
| } |
| |
| _handleHighlightjsLoaded(detail) { |
| for (const cb of this._getEventCallbacks(EventType.HIGHLIGHTJS_LOADED)) { |
| try { |
| cb(detail.hljs); |
| } catch (err) { |
| console.error(err); |
| } |
| } |
| } |
| |
| modifyRevertMsg(change, revertMsg, origMsg) { |
| for (const cb of this._getEventCallbacks(EventType.REVERT)) { |
| try { |
| revertMsg = cb(change, revertMsg, origMsg); |
| } catch (err) { |
| console.error(err); |
| } |
| } |
| return revertMsg; |
| } |
| |
| modifyRevertSubmissionMsg(change, revertSubmissionMsg, origMsg) { |
| for (const cb of this._getEventCallbacks(EventType.REVERT_SUBMISSION)) { |
| try { |
| revertSubmissionMsg = cb(change, revertSubmissionMsg, origMsg); |
| } catch (err) { |
| console.error(err); |
| } |
| } |
| return revertSubmissionMsg; |
| } |
| |
| getDiffLayers(path, changeNum, patchNum) { |
| const layers = []; |
| for (const annotationApi of |
| this._getEventCallbacks(EventType.ANNOTATE_DIFF)) { |
| try { |
| const layer = annotationApi.getLayer(path, changeNum, patchNum); |
| layers.push(layer); |
| } catch (err) { |
| console.error(err); |
| } |
| } |
| return layers; |
| } |
| |
| /** |
| * Retrieves coverage data possibly provided by a plugin. |
| * |
| * Will wait for plugins to be loaded. If multiple plugins offer a coverage |
| * provider, the first one is used. If no plugin offers a coverage provider, |
| * will resolve to []. |
| * |
| * @param {string|number} changeNum |
| * @param {string} path |
| * @param {string|number} basePatchNum |
| * @param {string|number} patchNum |
| * @return {!Promise<!Array<!Gerrit.CoverageRange>>} |
| */ |
| getCoverageRanges(changeNum, path, basePatchNum, patchNum) { |
| return Gerrit.awaitPluginsLoaded().then(() => { |
| for (const annotationApi of |
| this._getEventCallbacks(EventType.ANNOTATE_DIFF)) { |
| const provider = annotationApi.getCoverageProvider(); |
| // Only one coverage provider makes sense. If there are more, then we |
| // simply ignore them. |
| if (provider) { |
| return provider(changeNum, path, basePatchNum, patchNum); |
| } |
| } |
| return []; |
| }); |
| } |
| |
| getAdminMenuLinks() { |
| const links = []; |
| for (const adminApi of |
| this._getEventCallbacks(EventType.ADMIN_MENU_LINKS)) { |
| links.push(...adminApi.getMenuLinks()); |
| } |
| return links; |
| } |
| |
| getLabelValuesPostRevert(change) { |
| let labels = {}; |
| for (const cb of this._getEventCallbacks(EventType.POST_REVERT)) { |
| try { |
| labels = cb(change); |
| } catch (err) { |
| console.error(err); |
| } |
| } |
| return labels; |
| } |
| |
| _getEventCallbacks(type) { |
| return this._eventCallbacks[type] || []; |
| } |
| } |
| |
| customElements.define(GrJsApiInterface.is, GrJsApiInterface); |
| })(); |