It's undesired because it is used in other places to check if a comment is in the same place. Change-Id: Ic674acd307dedc1573aae61decaefec2f2b4234b
		
			
				
	
	
		
			192 lines
		
	
	
		
			6.8 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			192 lines
		
	
	
		
			6.8 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
/**
 | 
						|
 * @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 HOVER_PATH_PATTERN = /^commentRanges\.\#(\d+)\.hovering$/;
 | 
						|
 | 
						|
  const RANGE_HIGHLIGHT = 'range';
 | 
						|
  const HOVER_HIGHLIGHT = 'rangeHighlight';
 | 
						|
 | 
						|
  const NORMALIZE_RANGE_EVENT = 'normalize-range';
 | 
						|
 | 
						|
  /** @typedef {{side: string, range: Gerrit.Range, hovering: boolean}} */
 | 
						|
  Gerrit.HoveredRange;
 | 
						|
 | 
						|
  Polymer({
 | 
						|
    is: 'gr-ranged-comment-layer',
 | 
						|
 | 
						|
    properties: {
 | 
						|
      /** @type {!Array<!Gerrit.HoveredRange>} */
 | 
						|
      commentRanges: Array,
 | 
						|
      _listeners: {
 | 
						|
        type: Array,
 | 
						|
        value() { return []; },
 | 
						|
      },
 | 
						|
      _rangesMap: {
 | 
						|
        type: Object,
 | 
						|
        value() { return {left: {}, right: {}}; },
 | 
						|
      },
 | 
						|
    },
 | 
						|
 | 
						|
    observers: [
 | 
						|
      '_handleCommentRangesChange(commentRanges.*)',
 | 
						|
    ],
 | 
						|
 | 
						|
    /**
 | 
						|
     * Layer method to add annotations to a line.
 | 
						|
     * @param {!HTMLElement} el The DIV.contentText element to apply the
 | 
						|
     *     annotation to.
 | 
						|
     * @param {!Object} line The line object. (GrDiffLine)
 | 
						|
     */
 | 
						|
    annotate(el, line) {
 | 
						|
      let ranges = [];
 | 
						|
      if (line.type === GrDiffLine.Type.REMOVE || (
 | 
						|
          line.type === GrDiffLine.Type.BOTH &&
 | 
						|
          el.getAttribute('data-side') !== 'right')) {
 | 
						|
        ranges = ranges.concat(this._getRangesForLine(line, 'left'));
 | 
						|
      }
 | 
						|
      if (line.type === GrDiffLine.Type.ADD || (
 | 
						|
          line.type === GrDiffLine.Type.BOTH &&
 | 
						|
          el.getAttribute('data-side') !== 'left')) {
 | 
						|
        ranges = ranges.concat(this._getRangesForLine(line, 'right'));
 | 
						|
      }
 | 
						|
 | 
						|
      for (const range of ranges) {
 | 
						|
        GrAnnotation.annotateElement(el, range.start,
 | 
						|
            range.end - range.start,
 | 
						|
            range.hovering ? HOVER_HIGHLIGHT : RANGE_HIGHLIGHT);
 | 
						|
      }
 | 
						|
    },
 | 
						|
 | 
						|
    /**
 | 
						|
     * Register a listener for layer updates.
 | 
						|
     * @param {function(number, number, string)} 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(fn) {
 | 
						|
      this._listeners.push(fn);
 | 
						|
    },
 | 
						|
 | 
						|
    /**
 | 
						|
     * Notify Layer listeners of changes to annotations.
 | 
						|
     * @param {number} start The line where the update starts.
 | 
						|
     * @param {number} end The line where the update ends.
 | 
						|
     * @param {string} side The side of the update. ('left' or 'right')
 | 
						|
     */
 | 
						|
    _notifyUpdateRange(start, end, side) {
 | 
						|
      for (const listener of this._listeners) {
 | 
						|
        listener(start, end, side);
 | 
						|
      }
 | 
						|
    },
 | 
						|
 | 
						|
    /**
 | 
						|
     * Handle change in the ranges by updating the ranges maps and by
 | 
						|
     * emitting appropriate update notifications.
 | 
						|
     * @param {Object} record The change record.
 | 
						|
     */
 | 
						|
    _handleCommentRangesChange(record) {
 | 
						|
      if (!record) return;
 | 
						|
 | 
						|
      // If the entire set of comments was changed.
 | 
						|
      if (record.path === 'commentRanges') {
 | 
						|
        this._rangesMap = {left: {}, right: {}};
 | 
						|
        for (const {side, range, hovering} of record.value) {
 | 
						|
          this._updateRangesMap(
 | 
						|
              side, range, hovering, (forLine, start, end, hovering) => {
 | 
						|
                forLine.push({start, end, hovering});
 | 
						|
              });
 | 
						|
        }
 | 
						|
      }
 | 
						|
 | 
						|
      // If the change only changed the `hovering` property of a comment.
 | 
						|
      const match = record.path.match(HOVER_PATH_PATTERN);
 | 
						|
      if (match) {
 | 
						|
        const commentRangesIndex = match[1];
 | 
						|
        const {side, range, hovering} = this.commentRanges[commentRangesIndex];
 | 
						|
        this._updateRangesMap(
 | 
						|
            side, range, hovering, (forLine, start, end, hovering) => {
 | 
						|
              const index = forLine.findIndex(lineRange =>
 | 
						|
                  lineRange.start === start && lineRange.end === end);
 | 
						|
              forLine[index].hovering = hovering;
 | 
						|
            });
 | 
						|
      }
 | 
						|
 | 
						|
      // If comments were spliced in or out.
 | 
						|
      if (record.path === 'commentRanges.splices') {
 | 
						|
        for (const indexSplice of record.value.indexSplices) {
 | 
						|
          const removed = indexSplice.removed;
 | 
						|
          for (const {side, range, hovering} of removed) {
 | 
						|
            this._updateRangesMap(
 | 
						|
                side, range, hovering, (forLine, start, end) => {
 | 
						|
                  const index = forLine.findIndex(lineRange =>
 | 
						|
                      lineRange.start === start && lineRange.end === end);
 | 
						|
                  forLine.splice(index, 1);
 | 
						|
                });
 | 
						|
          }
 | 
						|
          const added = indexSplice.object.slice(
 | 
						|
              indexSplice.index, indexSplice.index + indexSplice.addedCount);
 | 
						|
          for (const {side, range, hovering} of added) {
 | 
						|
            this._updateRangesMap(
 | 
						|
                side, range, hovering, (forLine, start, end, hovering) => {
 | 
						|
                  forLine.push({start, end, hovering});
 | 
						|
                });
 | 
						|
          }
 | 
						|
        }
 | 
						|
      }
 | 
						|
    },
 | 
						|
 | 
						|
    _updateRangesMap(side, range, hovering, operation) {
 | 
						|
      const forSide = this._rangesMap[side] || (this._rangesMap[side] = {});
 | 
						|
      for (let line = range.start_line; line <= range.end_line; line++) {
 | 
						|
        const forLine = forSide[line] || (forSide[line] = []);
 | 
						|
        const start = line === range.start_line ? range.start_character : 0;
 | 
						|
        const end = line === range.end_line ? range.end_character : -1;
 | 
						|
        operation(forLine, start, end, hovering);
 | 
						|
      }
 | 
						|
      this._notifyUpdateRange(range.start_line, range.end_line, side);
 | 
						|
    },
 | 
						|
 | 
						|
    _getRangesForLine(line, side) {
 | 
						|
      const lineNum = side === 'left' ? line.beforeNumber : line.afterNumber;
 | 
						|
      const ranges = this.get(['_rangesMap', side, lineNum]) || [];
 | 
						|
      return ranges
 | 
						|
          .map(range => {
 | 
						|
            // Make a copy, so that the normalization below does not mess with
 | 
						|
            // our map.
 | 
						|
            range = Object.assign({}, range);
 | 
						|
            range.end = range.end === -1 ? line.text.length : range.end;
 | 
						|
 | 
						|
            // Normalize invalid ranges where the start is after the end but the
 | 
						|
            // start still makes sense. Set the end to the end of the line.
 | 
						|
            // @see Issue 5744
 | 
						|
            if (range.start >= range.end && range.start < line.text.length) {
 | 
						|
              range.end = line.text.length;
 | 
						|
              this.$.reporting.reportInteraction(NORMALIZE_RANGE_EVENT,
 | 
						|
                  'Modified invalid comment range on l.' + lineNum +
 | 
						|
                  ' of the ' + side + ' side');
 | 
						|
            }
 | 
						|
 | 
						|
            return range;
 | 
						|
          })
 | 
						|
          // Sort the ranges so that hovering highlights are on top.
 | 
						|
          .sort((a, b) => a.hovering && !b.hovering ? 1 : 0);
 | 
						|
    },
 | 
						|
  });
 | 
						|
})();
 |