Merge "Refactor `GrAnnotation`"
diff --git a/polygerrit-ui/app/embed/diff/gr-diff-builder/token-highlight-layer.ts b/polygerrit-ui/app/embed/diff/gr-diff-builder/token-highlight-layer.ts
index e9076aa..9478d13 100644
--- a/polygerrit-ui/app/embed/diff/gr-diff-builder/token-highlight-layer.ts
+++ b/polygerrit-ui/app/embed/diff/gr-diff-builder/token-highlight-layer.ts
@@ -6,7 +6,10 @@
import {DiffLayer} from '../../../types/types';
import {GrDiffLine, Side, TokenHighlightListener} from '../../../api/diff';
import {assertIsDefined} from '../../../utils/common-util';
-import {GrAnnotation} from '../gr-diff-highlight/gr-annotation';
+import {
+ GrAnnotationImpl,
+ getStringLength,
+} from '../gr-diff-highlight/gr-annotation';
import {debounce, DelayedTask} from '../../../utils/async-util';
import {getLineElByChild, getSideByLineEl} from '../gr-diff/gr-diff-utils';
@@ -147,8 +150,8 @@
// This is to correctly count surrogate pairs in text and token.
// If the index calculation becomes a hotspot, we could precompute a code
// unit to code point index map for text before iterating over the results
- const index = GrAnnotation.getStringLength(text.slice(0, match.index));
- const length = GrAnnotation.getStringLength(token);
+ const index = getStringLength(text.slice(0, match.index));
+ const length = getStringLength(token);
atLeastOneTokenMatched = true;
const highlightTypeClass =
@@ -158,7 +161,7 @@
// We add the TOKEN_TEXT_PREFIX class so that we can look up the token later easily
// even if the token element was split up into multiple smaller nodes.
// All parts of a single token will share a common TOKEN_INDEX_PREFIX class within the line of code.
- GrAnnotation.annotateElement(
+ GrAnnotationImpl.annotateElement(
el,
index,
length,
@@ -345,7 +348,7 @@
start_line: line,
start_column: index + 1, // 1-based inclusive
end_line: line,
- end_column: index + GrAnnotation.getStringLength(token), // 1-based inclusive
+ end_column: index + getStringLength(token), // 1-based inclusive
};
this.tokenHighlightListener({token, element, side, range});
}
diff --git a/polygerrit-ui/app/embed/diff/gr-diff-builder/token-highlight-layer_test.ts b/polygerrit-ui/app/embed/diff/gr-diff-builder/token-highlight-layer_test.ts
index 5651dcf..8d0050f 100644
--- a/polygerrit-ui/app/embed/diff/gr-diff-builder/token-highlight-layer_test.ts
+++ b/polygerrit-ui/app/embed/diff/gr-diff-builder/token-highlight-layer_test.ts
@@ -11,7 +11,7 @@
} from '../../../api/diff';
import {GrDiffLine} from '../gr-diff/gr-diff-line';
import {HOVER_DELAY_MS, TokenHighlightLayer} from './token-highlight-layer';
-import {GrAnnotation} from '../gr-diff-highlight/gr-annotation';
+import {GrAnnotationImpl} from '../gr-diff-highlight/gr-annotation';
import {html, render} from 'lit';
import {_testOnly_allTasks} from '../../../utils/async-util';
import {queryAndAssert} from '../../../test/test-utils';
@@ -123,10 +123,13 @@
}
test('annotate adds css token', () => {
- const annotateElementStub = sinon.stub(GrAnnotation, 'annotateElement');
+ const annotateElementStub = sinon.stub(
+ GrAnnotationImpl,
+ 'annotateElement'
+ );
const el = createLine('these are words');
annotate(el);
- assert.isTrue(annotateElementStub.calledThrice);
+ assert.equal(annotateElementStub.callCount, 3);
assertAnnotation(annotateElementStub.args[0], {
parent: el,
offset: 0,
@@ -148,7 +151,10 @@
});
test('annotate adds css tokens w/ emojis', () => {
- const annotateElementStub = sinon.stub(GrAnnotation, 'annotateElement');
+ const annotateElementStub = sinon.stub(
+ GrAnnotationImpl,
+ 'annotateElement'
+ );
const el = createLine('these 💩 are 👨👩👧👦 words');
annotate(el);
diff --git a/polygerrit-ui/app/embed/diff/gr-diff-highlight/gr-annotation.ts b/polygerrit-ui/app/embed/diff/gr-diff-highlight/gr-annotation.ts
index 5669bcf..bddfcac 100644
--- a/polygerrit-ui/app/embed/diff/gr-diff-highlight/gr-annotation.ts
+++ b/polygerrit-ui/app/embed/diff/gr-diff-highlight/gr-annotation.ts
@@ -4,6 +4,7 @@
* SPDX-License-Identifier: Apache-2.0
*/
import {getSanitizeDOMValue} from '@polymer/polymer/lib/utils/settings';
+import {GrAnnotation} from '../../../api/diff';
// TODO(wyatta): refactor this to be <MARK> rather than <HL>.
const ANNOTATION_TAG = 'HL';
@@ -11,268 +12,271 @@
// Astral code point as per https://mathiasbynens.be/notes/javascript-unicode
const REGEX_ASTRAL_SYMBOL = /[\uD800-\uDBFF][\uDC00-\uDFFF]/;
-export const GrAnnotation = {
- /**
- * The DOM API textContent.length calculation is broken when the text
- * contains Unicode. See https://mathiasbynens.be/notes/javascript-unicode .
- *
- */
- getLength(node: Node) {
- if (node instanceof Comment) return 0;
- return GrAnnotation.getStringLength(node.textContent || '');
- },
+/**
+ * The DOM API textContent.length calculation is broken when the text
+ * contains Unicode. See https://mathiasbynens.be/notes/javascript-unicode .
+ */
+export function getLength(node: Node) {
+ if (node instanceof Comment) return 0;
+ return getStringLength(node.textContent || '');
+}
- /**
- * Returns the number of Unicode code points in the given string
- *
- * This is not necessarily the same as the number of visible symbols.
- * See https://mathiasbynens.be/notes/javascript-unicode for more details.
- */
- getStringLength(str: string) {
- return [...str].length;
- },
+/**
+ * Returns the number of Unicode code points in the given string
+ *
+ * This is not necessarily the same as the number of visible symbols.
+ * See https://mathiasbynens.be/notes/javascript-unicode for more details.
+ */
+export function getStringLength(str: string) {
+ return [...str].length;
+}
- /**
- * Annotates the [offset, offset+length) text segment in the parent with the
- * element definition provided as arguments.
- *
- * @param parent the node whose contents will be annotated.
- * If parent is Text then parent.parentNode must not be null
- * @param offset the 0-based offset from which the annotation will
- * start.
- * @param length of the annotated text.
- * @param elementSpec the spec to create the
- * annotating element.
- */
- annotateWithElement(
- parent: Node,
- offset: number,
- length: number,
- elSpec: ElementSpec
+/**
+ * Annotates the [offset, offset+length) text segment in the parent with the
+ * element definition provided as arguments.
+ *
+ * @param parent the node whose contents will be annotated.
+ * If parent is Text then parent.parentNode must not be null
+ * @param offset the 0-based offset from which the annotation will
+ * start.
+ * @param length of the annotated text.
+ * @param elementSpec the spec to create the
+ * annotating element.
+ */
+export function annotateWithElement(
+ parent: Node,
+ offset: number,
+ length: number,
+ elSpec: ElementSpec
+) {
+ const tagName = elSpec.tagName;
+ const attributes = elSpec.attributes || {};
+ let childNodes: Node[];
+
+ if (parent instanceof Element) {
+ childNodes = Array.from(parent.childNodes);
+ } else if (parent instanceof Text) {
+ childNodes = [parent];
+ parent = parent.parentNode!;
+ } else {
+ return;
+ }
+
+ const nestedNodes: Node[] = [];
+ for (let node of childNodes) {
+ const initialNodeLength = getLength(node);
+ // If the current node is completely before the offset.
+ if (offset > 0 && initialNodeLength <= offset) {
+ offset -= initialNodeLength;
+ continue;
+ }
+
+ if (offset > 0) {
+ node = splitNode(node, offset);
+ offset = 0;
+ }
+ if (getLength(node) > length) {
+ splitNode(node, length);
+ }
+ nestedNodes.push(node);
+
+ length -= getLength(node);
+ if (!length) break;
+ }
+
+ const wrapper = document.createElement(tagName);
+ const sanitizer = getSanitizeDOMValue();
+ for (let [name, value] of Object.entries(attributes)) {
+ if (!value) continue;
+ if (sanitizer) {
+ value = sanitizer(value, name, 'attribute', wrapper) as string;
+ }
+ wrapper.setAttribute(name, value);
+ }
+ for (const inner of nestedNodes) {
+ parent.replaceChild(wrapper, inner);
+ wrapper.appendChild(inner);
+ }
+}
+
+/**
+ * Surrounds the element's text at specified range in an ANNOTATION_TAG
+ * element. If the element has child elements, the range is split and
+ * applied as deeply as possible.
+ */
+export function annotateElement(
+ parent: HTMLElement,
+ offset: number,
+ length: number,
+ cssClass: string
+) {
+ const nodes: Array<HTMLElement | Text> = [].slice.apply(parent.childNodes);
+ let nodeLength;
+ let subLength;
+
+ for (const node of nodes) {
+ nodeLength = getLength(node);
+
+ // If the current node is completely before the offset.
+ if (nodeLength <= offset) {
+ offset -= nodeLength;
+ continue;
+ }
+
+ // Sublength is the annotation length for the current node.
+ subLength = Math.min(length, nodeLength - offset);
+
+ if (node instanceof Text) {
+ _annotateText(node, offset, subLength, cssClass);
+ } else if (node instanceof Element) {
+ annotateElement(node, offset, subLength, cssClass);
+ }
+
+ // If there is still more to annotate, then shift the indices, otherwise
+ // work is done, so break the loop.
+ if (subLength < length) {
+ length -= subLength;
+ offset = 0;
+ } else {
+ break;
+ }
+ }
+}
+
+/**
+ * Wraps node in annotation tag with cssClass, replacing the node in DOM.
+ */
+function wrapInHighlight(node: Element | Text, cssClass: string) {
+ let hl;
+ if (!(node instanceof Text) && node.tagName === ANNOTATION_TAG) {
+ hl = node;
+ hl.classList.add(cssClass);
+ } else {
+ hl = document.createElement(ANNOTATION_TAG);
+ hl.className = cssClass;
+ if (node.parentElement) node.parentElement.replaceChild(hl, node);
+ hl.appendChild(node);
+ }
+ return hl;
+}
+
+/**
+ * Splits Text Node and wraps it in hl with cssClass.
+ * Wraps trailing part after split, tailing one if firstPart is true.
+ */
+function splitAndWrapInHighlight(
+ node: Text,
+ offset: number,
+ cssClass: string,
+ firstPart?: boolean
+) {
+ if (
+ (getLength(node) === offset && firstPart) ||
+ (offset === 0 && !firstPart)
) {
- const tagName = elSpec.tagName;
- const attributes = elSpec.attributes || {};
- let childNodes: Node[];
+ return wrapInHighlight(node, cssClass);
+ }
+ if (firstPart) {
+ splitNode(node, offset);
+ // Node points to first part of the Text, second one is sibling.
+ } else {
+ // if node is Text then splitNode will return a Text
+ node = splitNode(node, offset) as Text;
+ }
+ return wrapInHighlight(node, cssClass);
+}
- if (parent instanceof Element) {
- childNodes = Array.from(parent.childNodes);
- } else if (parent instanceof Text) {
- childNodes = [parent];
- parent = parent.parentNode!;
- } else {
- return;
+/**
+ * Splits Node at offset.
+ * If Node is Element, it's cloned and the node at offset is split too.
+ */
+function splitNode(element: Node, offset: number) {
+ if (element instanceof Text) {
+ return splitTextNode(element, offset);
+ }
+ const tail = element.cloneNode(false);
+
+ if (element.parentElement)
+ element.parentElement.insertBefore(tail, element.nextSibling);
+ // Skip nodes before offset.
+ let node = element.firstChild;
+ while (node && (getLength(node) <= offset || getLength(node) === 0)) {
+ offset -= getLength(node);
+ node = node.nextSibling;
+ }
+ if (node && getLength(node) > offset) {
+ tail.appendChild(splitNode(node, offset));
+ }
+ while (node && node.nextSibling) {
+ tail.appendChild(node.nextSibling);
+ }
+ return tail;
+}
+
+/**
+ * Node.prototype.splitText Unicode-valid alternative.
+ *
+ * DOM Api for splitText() is broken for Unicode:
+ * https://mathiasbynens.be/notes/javascript-unicode
+ *
+ * @return Trailing Text Node.
+ */
+function splitTextNode(node: Text, offset: number) {
+ if (node.textContent?.match(REGEX_ASTRAL_SYMBOL)) {
+ const head = Array.from(node.textContent);
+ const tail = head.splice(offset);
+ const parent = node.parentNode;
+
+ // Split the content of the original node.
+ node.textContent = head.join('');
+
+ const tailNode = document.createTextNode(tail.join(''));
+ if (parent) {
+ parent.insertBefore(tailNode, node.nextSibling);
}
+ return tailNode;
+ } else {
+ return node.splitText(offset);
+ }
+}
- const nestedNodes: Node[] = [];
- for (let node of childNodes) {
- const initialNodeLength = GrAnnotation.getLength(node);
- // If the current node is completely before the offset.
- if (offset > 0 && initialNodeLength <= offset) {
- offset -= initialNodeLength;
- continue;
- }
+function _annotateText(
+ node: Text,
+ offset: number,
+ length: number,
+ cssClass: string
+) {
+ const nodeLength = getLength(node);
- if (offset > 0) {
- node = GrAnnotation.splitNode(node, offset);
- offset = 0;
- }
- if (GrAnnotation.getLength(node) > length) {
- GrAnnotation.splitNode(node, length);
- }
- nestedNodes.push(node);
+ // There are four cases:
+ // 1) Entire node is highlighted.
+ // 2) Highlight is at the start.
+ // 3) Highlight is at the end.
+ // 4) Highlight is in the middle.
- length -= GrAnnotation.getLength(node);
- if (!length) break;
- }
+ if (offset === 0 && nodeLength === length) {
+ // Case 1.
+ wrapInHighlight(node, cssClass);
+ } else if (offset === 0) {
+ // Case 2.
+ splitAndWrapInHighlight(node, length, cssClass, true);
+ } else if (offset + length === nodeLength) {
+ // Case 3
+ splitAndWrapInHighlight(node, offset, cssClass, false);
+ } else {
+ // Case 4
+ splitAndWrapInHighlight(
+ splitTextNode(node, offset),
+ length,
+ cssClass,
+ true
+ );
+ }
+}
- const wrapper = document.createElement(tagName);
- const sanitizer = getSanitizeDOMValue();
- for (let [name, value] of Object.entries(attributes)) {
- if (!value) continue;
- if (sanitizer) {
- value = sanitizer(value, name, 'attribute', wrapper) as string;
- }
- wrapper.setAttribute(name, value);
- }
- for (const inner of nestedNodes) {
- parent.replaceChild(wrapper, inner);
- wrapper.appendChild(inner);
- }
- },
-
- /**
- * Surrounds the element's text at specified range in an ANNOTATION_TAG
- * element. If the element has child elements, the range is split and
- * applied as deeply as possible.
- */
- annotateElement(
- parent: HTMLElement,
- offset: number,
- length: number,
- cssClass: string
- ) {
- const nodes: Array<HTMLElement | Text> = [].slice.apply(parent.childNodes);
- let nodeLength;
- let subLength;
-
- for (const node of nodes) {
- nodeLength = GrAnnotation.getLength(node);
-
- // If the current node is completely before the offset.
- if (nodeLength <= offset) {
- offset -= nodeLength;
- continue;
- }
-
- // Sublength is the annotation length for the current node.
- subLength = Math.min(length, nodeLength - offset);
-
- if (node instanceof Text) {
- GrAnnotation._annotateText(node, offset, subLength, cssClass);
- } else if (node instanceof Element) {
- GrAnnotation.annotateElement(node, offset, subLength, cssClass);
- }
-
- // If there is still more to annotate, then shift the indices, otherwise
- // work is done, so break the loop.
- if (subLength < length) {
- length -= subLength;
- offset = 0;
- } else {
- break;
- }
- }
- },
-
- /**
- * Wraps node in annotation tag with cssClass, replacing the node in DOM.
- */
- wrapInHighlight(node: Element | Text, cssClass: string) {
- let hl;
- if (!(node instanceof Text) && node.tagName === ANNOTATION_TAG) {
- hl = node;
- hl.classList.add(cssClass);
- } else {
- hl = document.createElement(ANNOTATION_TAG);
- hl.className = cssClass;
- if (node.parentElement) node.parentElement.replaceChild(hl, node);
- hl.appendChild(node);
- }
- return hl;
- },
-
- /**
- * Splits Text Node and wraps it in hl with cssClass.
- * Wraps trailing part after split, tailing one if firstPart is true.
- */
- splitAndWrapInHighlight(
- node: Text,
- offset: number,
- cssClass: string,
- firstPart?: boolean
- ) {
- if (
- (GrAnnotation.getLength(node) === offset && firstPart) ||
- (offset === 0 && !firstPart)
- ) {
- return GrAnnotation.wrapInHighlight(node, cssClass);
- }
- if (firstPart) {
- GrAnnotation.splitNode(node, offset);
- // Node points to first part of the Text, second one is sibling.
- } else {
- // if node is Text then splitNode will return a Text
- node = GrAnnotation.splitNode(node, offset) as Text;
- }
- return GrAnnotation.wrapInHighlight(node, cssClass);
- },
-
- /**
- * Splits Node at offset.
- * If Node is Element, it's cloned and the node at offset is split too.
- */
- splitNode(element: Node, offset: number) {
- if (element instanceof Text) {
- return GrAnnotation.splitTextNode(element, offset);
- }
- const tail = element.cloneNode(false);
-
- if (element.parentElement)
- element.parentElement.insertBefore(tail, element.nextSibling);
- // Skip nodes before offset.
- let node = element.firstChild;
- while (
- node &&
- (GrAnnotation.getLength(node) <= offset ||
- GrAnnotation.getLength(node) === 0)
- ) {
- offset -= GrAnnotation.getLength(node);
- node = node.nextSibling;
- }
- if (node && GrAnnotation.getLength(node) > offset) {
- tail.appendChild(GrAnnotation.splitNode(node, offset));
- }
- while (node && node.nextSibling) {
- tail.appendChild(node.nextSibling);
- }
- return tail;
- },
-
- /**
- * Node.prototype.splitText Unicode-valid alternative.
- *
- * DOM Api for splitText() is broken for Unicode:
- * https://mathiasbynens.be/notes/javascript-unicode
- *
- * @return Trailing Text Node.
- */
- splitTextNode(node: Text, offset: number) {
- if (node.textContent?.match(REGEX_ASTRAL_SYMBOL)) {
- const head = Array.from(node.textContent);
- const tail = head.splice(offset);
- const parent = node.parentNode;
-
- // Split the content of the original node.
- node.textContent = head.join('');
-
- const tailNode = document.createTextNode(tail.join(''));
- if (parent) {
- parent.insertBefore(tailNode, node.nextSibling);
- }
- return tailNode;
- } else {
- return node.splitText(offset);
- }
- },
-
- _annotateText(node: Text, offset: number, length: number, cssClass: string) {
- const nodeLength = GrAnnotation.getLength(node);
-
- // There are four cases:
- // 1) Entire node is highlighted.
- // 2) Highlight is at the start.
- // 3) Highlight is at the end.
- // 4) Highlight is in the middle.
-
- if (offset === 0 && nodeLength === length) {
- // Case 1.
- GrAnnotation.wrapInHighlight(node, cssClass);
- } else if (offset === 0) {
- // Case 2.
- GrAnnotation.splitAndWrapInHighlight(node, length, cssClass, true);
- } else if (offset + length === nodeLength) {
- // Case 3
- GrAnnotation.splitAndWrapInHighlight(node, offset, cssClass, false);
- } else {
- // Case 4
- GrAnnotation.splitAndWrapInHighlight(
- GrAnnotation.splitTextNode(node, offset),
- length,
- cssClass,
- true
- );
- }
- },
+export const GrAnnotationImpl: GrAnnotation = {
+ annotateElement,
+ annotateWithElement,
};
/**
@@ -283,3 +287,8 @@
tagName: string;
attributes?: {[attributeName: string]: string | undefined};
}
+
+export const TEST_ONLY = {
+ _annotateText,
+ splitTextNode,
+};
diff --git a/polygerrit-ui/app/embed/diff/gr-diff-highlight/gr-annotation_test.ts b/polygerrit-ui/app/embed/diff/gr-diff-highlight/gr-annotation_test.ts
index 3e1ce66..15a6a15 100644
--- a/polygerrit-ui/app/embed/diff/gr-diff-highlight/gr-annotation_test.ts
+++ b/polygerrit-ui/app/embed/diff/gr-diff-highlight/gr-annotation_test.ts
@@ -4,7 +4,12 @@
* SPDX-License-Identifier: Apache-2.0
*/
import '../../../test/common-test-setup';
-import {GrAnnotation} from './gr-annotation';
+import {
+ TEST_ONLY,
+ annotateElement,
+ annotateWithElement,
+ getStringLength,
+} from './gr-annotation';
import {
getSanitizeDOMValue,
setSanitizeDOMValue,
@@ -27,7 +32,7 @@
});
test('_annotateText length:0 offset:0', () => {
- GrAnnotation._annotateText(textNode, 0, 0, 'foobar');
+ TEST_ONLY._annotateText(textNode, 0, 0, 'foobar');
assert.equal(parent.textContent, str);
assert.equal(
@@ -37,7 +42,7 @@
});
test('_annotateText length:0 offset:1', () => {
- GrAnnotation._annotateText(textNode, 1, 0, 'foobar');
+ TEST_ONLY._annotateText(textNode, 1, 0, 'foobar');
assert.equal(parent.textContent, str);
assert.equal(
@@ -47,7 +52,7 @@
});
test('_annotateText length:0 offset:str.length', () => {
- GrAnnotation._annotateText(textNode, str.length, 0, 'foobar');
+ TEST_ONLY._annotateText(textNode, str.length, 0, 'foobar');
assert.equal(parent.textContent, str);
assert.equal(
@@ -57,7 +62,7 @@
});
test('_annotateText Case 1', () => {
- GrAnnotation._annotateText(textNode, 0, str.length, 'foobar');
+ TEST_ONLY._annotateText(textNode, 0, str.length, 'foobar');
assert.equal(parent.textContent, str);
assert.equal(
@@ -67,7 +72,7 @@
});
test('_annotateText Case 2', () => {
- GrAnnotation._annotateText(textNode, 0, 12, 'foobar');
+ TEST_ONLY._annotateText(textNode, 0, 12, 'foobar');
assert.equal(parent.textContent, str);
assert.equal(
@@ -77,7 +82,7 @@
});
test('_annotateText Case 3', () => {
- GrAnnotation._annotateText(textNode, 12, str.length - 12, 'foobar');
+ TEST_ONLY._annotateText(textNode, 12, str.length - 12, 'foobar');
assert.equal(parent.textContent, str);
assert.equal(
@@ -90,7 +95,7 @@
const index = str.indexOf('dolor');
const length = 'dolor '.length;
- GrAnnotation._annotateText(textNode, index, length, 'foobar');
+ TEST_ONLY._annotateText(textNode, index, length, 'foobar');
assert.equal(parent.textContent, str);
assert.equal(
@@ -104,7 +109,7 @@
// Apply the layers successively.
layers.forEach((layer, i) => {
- GrAnnotation.annotateElement(
+ annotateElement(
parent,
str.indexOf(layer),
layer.length,
@@ -129,13 +134,13 @@
// Non-unicode path:
node = document.createTextNode(helloString + asciiString);
- tail = GrAnnotation.splitTextNode(node, helloString.length);
+ tail = TEST_ONLY.splitTextNode(node, helloString.length);
assert(node.textContent, helloString);
assert(tail.textContent, asciiString);
// Unicdoe path:
node = document.createTextNode(helloString + unicodeString);
- tail = GrAnnotation.splitTextNode(node, helloString.length);
+ tail = TEST_ONLY.splitTextNode(node, helloString.length);
assert(node.textContent, helloString);
assert(tail.textContent, unicodeString);
});
@@ -166,7 +171,7 @@
const length = 10;
const container = document.createElement('div');
container.textContent = fullText;
- GrAnnotation.annotateWithElement(container, 1, length, {
+ annotateWithElement(container, 1, length, {
tagName: 'test-wrapper',
});
@@ -180,8 +185,8 @@
const length = 10;
const container = document.createElement('div');
container.textContent = fullText;
- GrAnnotation.annotateElement(container, 5, length, 'testclass');
- GrAnnotation.annotateWithElement(container, 1, length, {
+ annotateElement(container, 5, length, 'testclass');
+ annotateWithElement(container, 1, length, {
tagName: 'test-wrapper',
});
@@ -201,7 +206,7 @@
const length = 10;
const container = document.createElement('div');
container.textContent = fullText;
- GrAnnotation.annotateWithElement(container.childNodes[0], 1, length, {
+ annotateWithElement(container.childNodes[0], 1, length, {
tagName: 'test-wrapper',
});
@@ -216,7 +221,7 @@
container.appendChild(document.createTextNode('0123456789'));
container.appendChild(document.createElement('span'));
container.appendChild(document.createTextNode('0123456789'));
- GrAnnotation.annotateWithElement(container, 1, 10, {
+ annotateWithElement(container, 1, 10, {
tagName: 'test-wrapper',
});
@@ -233,7 +238,7 @@
container.appendChild(document.createComment('comment2'));
container.appendChild(document.createElement('span'));
container.appendChild(document.createTextNode('0123456789'));
- GrAnnotation.annotateWithElement(container, 1, 10, {
+ annotateWithElement(container, 1, 10, {
tagName: 'test-wrapper',
});
@@ -254,7 +259,7 @@
'data-foo': 'bar',
class: 'hello world',
};
- GrAnnotation.annotateWithElement(container, 1, length, {
+ annotateWithElement(container, 1, length, {
tagName: 'test-wrapper',
attributes,
});
@@ -291,17 +296,17 @@
suite('getStringLength', () => {
test('ASCII characters are counted correctly', () => {
- assert.equal(GrAnnotation.getStringLength('ASCII'), 5);
+ assert.equal(getStringLength('ASCII'), 5);
});
test('Unicode surrogate pairs count as one symbol', () => {
- assert.equal(GrAnnotation.getStringLength('Unic💢de'), 7);
- assert.equal(GrAnnotation.getStringLength('💢💢'), 2);
+ assert.equal(getStringLength('Unic💢de'), 7);
+ assert.equal(getStringLength('💢💢'), 2);
});
test('Grapheme clusters count as multiple symbols', () => {
- assert.equal(GrAnnotation.getStringLength('man\u0303ana'), 7); // mañana
- assert.equal(GrAnnotation.getStringLength('q\u0307\u0323'), 3); // q̣̇
+ assert.equal(getStringLength('man\u0303ana'), 7); // mañana
+ assert.equal(getStringLength('q\u0307\u0323'), 3); // q̣̇
});
});
});
diff --git a/polygerrit-ui/app/embed/diff/gr-diff-highlight/gr-diff-highlight.ts b/polygerrit-ui/app/embed/diff/gr-diff-highlight/gr-diff-highlight.ts
index 0d9250c..1cdfbc3 100644
--- a/polygerrit-ui/app/embed/diff/gr-diff-highlight/gr-diff-highlight.ts
+++ b/polygerrit-ui/app/embed/diff/gr-diff-highlight/gr-diff-highlight.ts
@@ -5,7 +5,7 @@
*/
import '../../../styles/shared-styles';
import '../gr-selection-action-box/gr-selection-action-box';
-import {GrAnnotation} from './gr-annotation';
+import {getLength} from './gr-annotation';
import {normalize} from './gr-range-normalizer';
import {strToClassName} from '../../../utils/dom-util';
import {Side} from '../../../constants/constants';
@@ -508,7 +508,7 @@
if (node instanceof Element && node.classList.contains('content')) {
return this.getLength(queryAndAssert(node, '.contentText'));
} else {
- return GrAnnotation.getLength(node);
+ return getLength(node);
}
}
}
diff --git a/polygerrit-ui/app/embed/diff/gr-diff-processor/gr-diff-processor.ts b/polygerrit-ui/app/embed/diff/gr-diff-processor/gr-diff-processor.ts
index 98c0ab7..5db6db9 100644
--- a/polygerrit-ui/app/embed/diff/gr-diff-processor/gr-diff-processor.ts
+++ b/polygerrit-ui/app/embed/diff/gr-diff-processor/gr-diff-processor.ts
@@ -13,7 +13,7 @@
import {Side} from '../../../constants/constants';
import {debounce, DelayedTask} from '../../../utils/async-util';
import {assert} from '../../../utils/common-util';
-import {GrAnnotation} from '../gr-diff-highlight/gr-annotation';
+import {getStringLength} from '../gr-diff-highlight/gr-annotation';
import {GrDiffLineType, LineNumber} from '../../../api/diff';
import {FULL_CONTEXT, KeyLocations} from '../gr-diff/gr-diff-utils';
@@ -633,7 +633,7 @@
intralineInfos: number[][]
): Highlights[] {
// +1 to account for the \n that is not part of the rows passed here
- const lineLengths = rows.map(r => GrAnnotation.getStringLength(r) + 1);
+ const lineLengths = rows.map(r => getStringLength(r) + 1);
let rowIndex = 0;
let idx = 0;
diff --git a/polygerrit-ui/app/embed/diff/gr-diff/gr-diff.ts b/polygerrit-ui/app/embed/diff/gr-diff/gr-diff.ts
index 42cffdb..2834f08 100644
--- a/polygerrit-ui/app/embed/diff/gr-diff/gr-diff.ts
+++ b/polygerrit-ui/app/embed/diff/gr-diff/gr-diff.ts
@@ -79,7 +79,10 @@
import {grDiffStyles} from './gr-diff-styles';
import {getDiffLength} from '../../../utils/diff-util';
import {GrCoverageLayer} from '../gr-coverage-layer/gr-coverage-layer';
-import {GrAnnotation} from '../gr-diff-highlight/gr-annotation';
+import {
+ GrAnnotationImpl,
+ getStringLength,
+} from '../gr-diff-highlight/gr-annotation';
import {
GrDiffGroup,
GrDiffGroupType,
@@ -1204,10 +1207,10 @@
// If endIndex isn't present, continue to the end of the line.
const endIndex =
highlight.endIndex === undefined
- ? GrAnnotation.getStringLength(line.text)
+ ? getStringLength(line.text)
: highlight.endIndex;
- GrAnnotation.annotateElement(
+ GrAnnotationImpl.annotateElement(
contentEl,
highlight.startIndex,
endIndex - highlight.startIndex,
@@ -1255,11 +1258,9 @@
if (match) {
// Normalize string positions in case there is unicode before or
// within the match.
- const index = GrAnnotation.getStringLength(
- line.text.substr(0, match.index)
- );
- const length = GrAnnotation.getStringLength(match[0]);
- GrAnnotation.annotateElement(
+ const index = getStringLength(line.text.substr(0, match.index));
+ const length = getStringLength(match[0]);
+ GrAnnotationImpl.annotateElement(
contentEl,
index,
length,
@@ -1460,7 +1461,7 @@
// Skip forward by the length of the content
pos += split[i].length;
- GrAnnotation.annotateElement(contentEl, pos, 1, `gr-diff ${className}`);
+ GrAnnotationImpl.annotateElement(contentEl, pos, 1, `gr-diff ${className}`);
pos++;
}
diff --git a/polygerrit-ui/app/embed/diff/gr-diff/gr-diff_test.ts b/polygerrit-ui/app/embed/diff/gr-diff/gr-diff_test.ts
index 88682d9..30f85cc 100644
--- a/polygerrit-ui/app/embed/diff/gr-diff/gr-diff_test.ts
+++ b/polygerrit-ui/app/embed/diff/gr-diff/gr-diff_test.ts
@@ -41,7 +41,10 @@
import {fixture, html, assert} from '@open-wc/testing';
import {createDefaultDiffPrefs} from '../../../constants/constants';
import {GrDiffRow} from '../gr-diff-builder/gr-diff-row';
-import {GrAnnotation} from '../gr-diff-highlight/gr-annotation';
+import {
+ GrAnnotationImpl,
+ getStringLength,
+} from '../gr-diff-highlight/gr-annotation';
import {GrDiffLine} from './gr-diff-line';
const DEFAULT_PREFS = createDefaultDiffPrefs();
@@ -4013,7 +4016,7 @@
<div>Lorem ipsum dolor sit amet, suspendisse inceptos vehicula</div>
`);
str = el.textContent ?? '';
- annotateElementSpy = sinon.spy(GrAnnotation, 'annotateElement');
+ annotateElementSpy = sinon.spy(GrAnnotationImpl, 'annotateElement');
layer = element.createIntralineLayer();
});
@@ -4125,7 +4128,7 @@
const str0 = slice(str, 0, 6);
const str1 = slice(str, 6);
- const numHighlightedChars = GrAnnotation.getStringLength(str1);
+ const numHighlightedChars = getStringLength(str1);
layer.annotate(el, lineNumberEl, l, Side.LEFT);
@@ -4152,7 +4155,10 @@
test('does nothing with empty line', () => {
const l = line('');
const el = document.createElement('div');
- const annotateElementStub = sinon.stub(GrAnnotation, 'annotateElement');
+ const annotateElementStub = sinon.stub(
+ GrAnnotationImpl,
+ 'annotateElement'
+ );
layer.annotate(el, lineNumberEl, l, Side.LEFT);
@@ -4164,7 +4170,10 @@
const l = line(str);
const el = document.createElement('div');
el.textContent = str;
- const annotateElementStub = sinon.stub(GrAnnotation, 'annotateElement');
+ const annotateElementStub = sinon.stub(
+ GrAnnotationImpl,
+ 'annotateElement'
+ );
layer.annotate(el, lineNumberEl, l, Side.LEFT);
@@ -4176,7 +4185,10 @@
const l = line(str);
const el = document.createElement('div');
el.textContent = str;
- const annotateElementStub = sinon.stub(GrAnnotation, 'annotateElement');
+ const annotateElementStub = sinon.stub(
+ GrAnnotationImpl,
+ 'annotateElement'
+ );
layer.annotate(el, lineNumberEl, l, Side.LEFT);
@@ -4195,7 +4207,10 @@
const l = line(str);
const el = document.createElement('div');
el.textContent = str;
- const annotateElementStub = sinon.stub(GrAnnotation, 'annotateElement');
+ const annotateElementStub = sinon.stub(
+ GrAnnotationImpl,
+ 'annotateElement'
+ );
layer.annotate(el, lineNumberEl, l, Side.LEFT);
@@ -4207,7 +4222,10 @@
const l = line(str);
const el = document.createElement('div');
el.textContent = str;
- const annotateElementStub = sinon.stub(GrAnnotation, 'annotateElement');
+ const annotateElementStub = sinon.stub(
+ GrAnnotationImpl,
+ 'annotateElement'
+ );
layer.annotate(el, lineNumberEl, l, Side.LEFT);
@@ -4231,7 +4249,10 @@
const l = line(str);
const el = document.createElement('div');
el.textContent = str;
- const annotateElementStub = sinon.stub(GrAnnotation, 'annotateElement');
+ const annotateElementStub = sinon.stub(
+ GrAnnotationImpl,
+ 'annotateElement'
+ );
layer.annotate(el, lineNumberEl, l, Side.LEFT);
@@ -4259,7 +4280,10 @@
test('does nothing with empty line', () => {
const l = line('');
const el = document.createElement('div');
- const annotateElementStub = sinon.stub(GrAnnotation, 'annotateElement');
+ const annotateElementStub = sinon.stub(
+ GrAnnotationImpl,
+ 'annotateElement'
+ );
layer.annotate(el, lineNumberEl, l, Side.LEFT);
assert.isFalse(annotateElementStub.called);
});
@@ -4269,7 +4293,10 @@
const l = line(str);
const el = document.createElement('div');
el.textContent = str;
- const annotateElementStub = sinon.stub(GrAnnotation, 'annotateElement');
+ const annotateElementStub = sinon.stub(
+ GrAnnotationImpl,
+ 'annotateElement'
+ );
layer.annotate(el, lineNumberEl, l, Side.LEFT);
assert.isFalse(annotateElementStub.called);
});
@@ -4279,7 +4306,10 @@
const l = line(str);
const el = document.createElement('div');
el.textContent = str;
- const annotateElementStub = sinon.stub(GrAnnotation, 'annotateElement');
+ const annotateElementStub = sinon.stub(
+ GrAnnotationImpl,
+ 'annotateElement'
+ );
layer.annotate(el, lineNumberEl, l, Side.LEFT);
assert.isTrue(annotateElementStub.called);
assert.equal(annotateElementStub.lastCall.args[1], 11);
@@ -4291,7 +4321,10 @@
const l = line(str);
const el = document.createElement('div');
el.textContent = str;
- const annotateElementStub = sinon.stub(GrAnnotation, 'annotateElement');
+ const annotateElementStub = sinon.stub(
+ GrAnnotationImpl,
+ 'annotateElement'
+ );
layer.annotate(el, lineNumberEl, l, Side.LEFT);
assert.isTrue(annotateElementStub.called);
assert.equal(annotateElementStub.lastCall.args[1], 11);
@@ -4303,7 +4336,10 @@
const l = line(str);
const el = document.createElement('div');
el.textContent = str;
- const annotateElementStub = sinon.stub(GrAnnotation, 'annotateElement');
+ const annotateElementStub = sinon.stub(
+ GrAnnotationImpl,
+ 'annotateElement'
+ );
layer.annotate(el, lineNumberEl, l, Side.LEFT);
assert.isTrue(annotateElementStub.called);
assert.equal(annotateElementStub.lastCall.args[1], 11);
@@ -4315,7 +4351,10 @@
const l = line(str);
const el = document.createElement('div');
el.textContent = str;
- const annotateElementStub = sinon.stub(GrAnnotation, 'annotateElement');
+ const annotateElementStub = sinon.stub(
+ GrAnnotationImpl,
+ 'annotateElement'
+ );
layer.annotate(el, lineNumberEl, l, Side.LEFT);
assert.isTrue(annotateElementStub.called);
assert.equal(annotateElementStub.lastCall.args[1], 1);
@@ -4331,7 +4370,10 @@
const l = line(str);
const el = document.createElement('div');
el.textContent = str;
- const annotateElementStub = sinon.stub(GrAnnotation, 'annotateElement');
+ const annotateElementStub = sinon.stub(
+ GrAnnotationImpl,
+ 'annotateElement'
+ );
layer.annotate(el, lineNumberEl, l, Side.LEFT);
assert.isFalse(annotateElementStub.called);
});
diff --git a/polygerrit-ui/app/embed/diff/gr-ranged-comment-layer/gr-ranged-comment-layer.ts b/polygerrit-ui/app/embed/diff/gr-ranged-comment-layer/gr-ranged-comment-layer.ts
index e2837ab..24729ff 100644
--- a/polygerrit-ui/app/embed/diff/gr-ranged-comment-layer/gr-ranged-comment-layer.ts
+++ b/polygerrit-ui/app/embed/diff/gr-ranged-comment-layer/gr-ranged-comment-layer.ts
@@ -3,7 +3,7 @@
* Copyright 2016 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
-import {GrAnnotation} from '../gr-diff-highlight/gr-annotation';
+import {GrAnnotationImpl} from '../gr-diff-highlight/gr-annotation';
import {GrDiffLine} from '../gr-diff/gr-diff-line';
import {strToClassName} from '../../../utils/dom-util';
import {Side} from '../../../constants/constants';
@@ -94,7 +94,7 @@
}
for (const range of ranges) {
- GrAnnotation.annotateElement(
+ GrAnnotationImpl.annotateElement(
el,
range.start,
range.end - range.start,
diff --git a/polygerrit-ui/app/embed/diff/gr-ranged-comment-layer/gr-ranged-comment-layer_test.ts b/polygerrit-ui/app/embed/diff/gr-ranged-comment-layer/gr-ranged-comment-layer_test.ts
index b90d6f7..5bfd94d 100644
--- a/polygerrit-ui/app/embed/diff/gr-ranged-comment-layer/gr-ranged-comment-layer_test.ts
+++ b/polygerrit-ui/app/embed/diff/gr-ranged-comment-layer/gr-ranged-comment-layer_test.ts
@@ -10,11 +10,11 @@
CommentRangeLayer,
GrRangedCommentLayer,
} from './gr-ranged-comment-layer';
-import {GrAnnotation} from '../gr-diff-highlight/gr-annotation';
import {GrDiffLine} from '../gr-diff/gr-diff-line';
import {GrDiffLineType, Side} from '../../../api/diff';
import {SinonStub} from 'sinon';
import {assert} from '@open-wc/testing';
+import {GrAnnotationImpl} from '../gr-diff-highlight/gr-annotation';
const rangeA: CommentRangeLayer = {
side: Side.LEFT,
@@ -130,7 +130,7 @@
}
setup(() => {
- annotateElementStub = sinon.stub(GrAnnotation, 'annotateElement');
+ annotateElementStub = sinon.stub(GrAnnotationImpl, 'annotateElement');
el = document.createElement('div');
el.setAttribute('data-side', Side.LEFT);
line = new GrDiffLine(GrDiffLineType.BOTH);
diff --git a/polygerrit-ui/app/embed/diff/gr-syntax-layer/gr-syntax-layer-worker.ts b/polygerrit-ui/app/embed/diff/gr-syntax-layer/gr-syntax-layer-worker.ts
index baa2ab4..4e166ba 100644
--- a/polygerrit-ui/app/embed/diff/gr-syntax-layer/gr-syntax-layer-worker.ts
+++ b/polygerrit-ui/app/embed/diff/gr-syntax-layer/gr-syntax-layer-worker.ts
@@ -3,7 +3,7 @@
* Copyright 2022 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
-import {GrAnnotation} from '../gr-diff-highlight/gr-annotation';
+import {annotateElement} from '../gr-diff-highlight/gr-annotation';
import {GrDiffLine} from '../gr-diff/gr-diff-line';
import {DiffFileMetaInfo, DiffInfo} from '../../../types/diff';
import {DiffLayer, DiffLayerListener} from '../../../types/types';
@@ -212,7 +212,7 @@
for (const range of ranges) {
if (!CLASS_SAFELIST.has(range.className)) continue;
if (range.length === 0) continue;
- GrAnnotation.annotateElement(
+ annotateElement(
el,
range.start,
range.length,