Move computation of key locations into diff model
This is a preparation of change 373057. We want to the model to be
responsible for diff processing. So it needs to control the key
locations, which are one of the processing inputs.
We are also moving the information about currently attached comment
widgets into the model, which will be valuable in other changes. So
you have one place to look up information about potentially existing
comments. See change 373406 for how this will be used later.
Google-Bug-Id: b/280018663
Release-Notes: skip
Change-Id: I877a732ac508bc49d559177d4dc62385930306b1
diff --git a/polygerrit-ui/app/embed/diff/gr-diff/gr-diff-utils.ts b/polygerrit-ui/app/embed/diff/gr-diff/gr-diff-utils.ts
index e1de348..d309556 100644
--- a/polygerrit-ui/app/embed/diff/gr-diff/gr-diff-utils.ts
+++ b/polygerrit-ui/app/embed/diff/gr-diff/gr-diff-utils.ts
@@ -8,6 +8,7 @@
import {
DiffPreferencesInfo,
DiffResponsiveMode,
+ DisplayLine,
FILE,
LOST,
LineNumber,
@@ -159,6 +160,87 @@
return range;
}
+/**
+ * This is all the data that gr-diff extracts from comment thread elements.
+ * Otherwise gr-diff treats such elements as a black box.
+ */
+export interface GrDiffCommentThread {
+ side: Side;
+ line: LineNumber;
+ range?: CommentRange;
+ rootId?: string;
+}
+
+export function toCommentThreadModel(
+ threadEl: HTMLElement
+): GrDiffCommentThread | undefined {
+ if (!isThreadEl(threadEl)) return undefined;
+ const side = getSide(threadEl);
+ const line = getLine(threadEl);
+ const range = getRange(threadEl);
+ if (!side) return undefined;
+ if (!line) return undefined;
+ return {side, line, range, rootId: threadEl.rootId};
+}
+
+export interface KeyLocations {
+ left: {[key: string]: boolean};
+ right: {[key: string]: boolean};
+}
+
+export function computeKeyLocations(
+ lineOfInterest: DisplayLine | undefined,
+ comments: GrDiffCommentThread[]
+) {
+ const keyLocations: KeyLocations = {left: {}, right: {}};
+
+ if (lineOfInterest) {
+ keyLocations[lineOfInterest.side][lineOfInterest.lineNum] = true;
+ }
+
+ for (const comment of comments) {
+ keyLocations[comment.side][comment.line] = true;
+ if (comment.range?.start_line) {
+ keyLocations[comment.side][comment.range.start_line] = true;
+ }
+ }
+
+ return keyLocations;
+}
+
+export function compareComments(
+ c1: GrDiffCommentThread,
+ c2: GrDiffCommentThread
+): number {
+ if (c1.side !== c2.side) {
+ return c1.side === Side.RIGHT ? 1 : -1;
+ }
+
+ if (c1.line !== c2.line) {
+ if (c1.line === FILE && c2.line !== FILE) return -1;
+ if (c1.line !== FILE && c2.line === FILE) return 1;
+ if (c1.line === LOST && c2.line !== LOST) return -1;
+ if (c1.line !== LOST && c2.line === LOST) return 1;
+ return (c1.line as number) - (c2.line as number);
+ }
+
+ if (c1.rootId !== c2.rootId) {
+ if (!c1.rootId) return -1;
+ if (!c2.rootId) return 1;
+ return c1.rootId > c2.rootId ? 1 : -1;
+ }
+
+ if (c1.range && c2.range) {
+ const r1 = JSON.stringify(c1.range);
+ const r2 = JSON.stringify(c2.range);
+ return r1 > r2 ? 1 : -1;
+ }
+ if (c1.range) return 1;
+ if (c2.range) return -1;
+
+ return 0;
+}
+
// TODO: This type should be exposed to gr-diff clients in a separate type file.
// For Gerrit these are instances of GrCommentThread, but other gr-diff users
// have different HTML elements in use for comment threads.