summaryrefslogtreecommitdiffstats
path: root/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-annotation-actions-js-api.ts
blob: 82c7118f421f687507ed52b1694d2e5ec4a2e8ca (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
/**
 * @license
 * Copyright (C) 2017 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.
 */
import {DiffLayer, DiffLayerListener} from '../../../types/types';
import {Side} from '../../../constants/constants';
import {EventType, PluginApi} from '../../../api/plugin';
import {appContext} from '../../../services/app-context';
import {AnnotationPluginApi, CoverageProvider} from '../../../api/annotation';

export class GrAnnotationActionsInterface implements AnnotationPluginApi {
  /**
   * Collect all annotation layers instantiated by createLayer. This is only
   * used for being able to look up the appropriate layer when notify() is
   * being called by plugins.
   */
  private annotationLayers: AnnotationLayer[] = [];

  private coverageProvider?: CoverageProvider;

  private readonly reporting = appContext.reportingService;

  constructor(private readonly plugin: PluginApi) {
    this.reporting.trackApi(this.plugin, 'annotation', 'constructor');
    plugin.on(EventType.ANNOTATE_DIFF, this);
  }

  setCoverageProvider(
    coverageProvider: CoverageProvider
  ): GrAnnotationActionsInterface {
    this.reporting.trackApi(this.plugin, 'annotation', 'setCoverageProvider');
    if (this.coverageProvider) {
      this.reporting.error(
        new Error(`Overwriting cov provider: ${this.plugin.getPluginName()}`)
      );
    }
    this.coverageProvider = coverageProvider;
    return this;
  }

  /**
   * Used by Gerrit to look up the coverage provider. Not intended to be called
   * by plugins.
   */
  getCoverageProvider() {
    return this.coverageProvider;
  }

  notify(path: string, start: number, end: number, side: Side) {
    this.reporting.trackApi(this.plugin, 'annotation', 'notify');
    for (const annotationLayer of this.annotationLayers) {
      // Notify only the annotation layer that is associated with the specified
      // path.
      if (annotationLayer.path === path) {
        annotationLayer.notifyListeners(start, end, side);
      }
    }
  }

  /**
   * Factory method called by Gerrit for creating a DiffLayer for each diff that
   * is rendered.
   *
   * Don't forget to also call disposeLayer().
   */
  createLayer(path: string) {
    const annotationLayer = new AnnotationLayer(path);
    this.annotationLayers.push(annotationLayer);
    return annotationLayer;
  }

  /**
   * Called by Gerrit for each diff renderer that had called createLayer().
   */
  disposeLayer(path: string) {
    this.annotationLayers = this.annotationLayers.filter(
      annotationLayer => annotationLayer.path !== path
    );
  }
}

/**
 * An AnnotationLayer exists for each file that is being rendered. This class is
 * not exposed to plugins, but being used by Gerrit's diff rendering.
 */
export class AnnotationLayer implements DiffLayer {
  private listeners: DiffLayerListener[] = [];

  /**
   * Used to create an instance of the Annotation Layer interface.
   *
   * @param path The file path (eg: /COMMIT_MSG').
   */
  constructor(readonly path: string) {
    this.listeners = [];
  }

  /**
   * Register a listener for layer updates.
   * Don't forget to removeListener when you stop using layer.
   *
   * @param fn The update handler function.
   * Should accept as arguments the line numbers for the start and end of
   * the update and the side as a string.
   */
  addListener(listener: DiffLayerListener) {
    this.listeners.push(listener);
  }

  removeListener(listener: DiffLayerListener) {
    this.listeners = this.listeners.filter(f => f !== listener);
  }

  annotate() {}

  /**
   * Notify layer listeners (which typically is just Gerrit's diff renderer) of
   * changes to annotations after the diff rendering had already completed. This
   * is indirectly called by plugins using the AnnotationPluginApi.notify().
   *
   * @param start The line where the update starts.
   * @param end The line where the update ends.
   * @param side The side of the update. ('left' or 'right')
   */
  notifyListeners(start: number, end: number, side: Side) {
    for (const listener of this.listeners) {
      listener(start, end, side);
    }
  }
}