Merge "Fix split text issue"
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-diff-highlight.js b/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-diff-highlight.js
index bfe103b..cc3846c 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-diff-highlight.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-diff-highlight.js
@@ -94,6 +94,43 @@
}
},
+ _getContentTextParent: function(target) {
+ var element = target;
+ if (element.nodeName === '#text') {
+ element = element.parentElement;
+ }
+ while (!element.classList.contains('contentText')) {
+ if (element.parentElement === null) {
+ return target;
+ }
+ element = element.parentElement;
+ }
+ return element;
+ },
+
+ /**
+ * Remap DOM range to whole lines of a diff if necessary. If the start or
+ * end containers are DOM elements that are singular pieces of syntax
+ * highlighting, the containers are remapped to the .contentText divs that
+ * contain the entire line of code.
+ *
+ * @param {Object} range - the standard DOM selector range.
+ * @return {Object} A modified version of the range that correctly accounts
+ * for syntax highlighting.
+ */
+ _normalizeRange: function(range) {
+ var startContainer = this._getContentTextParent(range.startContainer);
+ var startOffset = range.startOffset + this._getTextOffset(startContainer,
+ range.startContainer);
+ var endContainer = this._getContentTextParent(range.endContainer);
+ var endOffset = range.endOffset + this._getTextOffset(endContainer,
+ range.endContainer);
+ return {
+ start: this._normalizeSelectionSide(startContainer, startOffset),
+ end: this._normalizeSelectionSide(endContainer, endOffset),
+ };
+ },
+
/**
* Convert DOM Range selection to concrete numbers (line, column, side).
* Moves range end if it's not inside td.content.
@@ -160,13 +197,12 @@
if (range.collapsed) {
return;
}
- var start =
- this._normalizeSelectionSide(range.startContainer, range.startOffset);
+ var normalizedRange = this._normalizeRange(range);
+ var start = normalizedRange.start;
if (!start) {
return;
}
- var end =
- this._normalizeSelectionSide(range.endContainer, range.endOffset);
+ var end = normalizedRange.end;
if (!end) {
return;
}
@@ -270,5 +306,36 @@
return GrAnnotation.getLength(node);
}
},
+
+ /**
+ * Gets the character offset of the child within the parent.
+ * Performs a synchronous in-order traversal from top to bottom of the node
+ * element, counting the length of the syntax until child is found.
+ *
+ * @param {!Element} The root DOM element to be searched through.
+ * @param {!Element} The child element being searched for.
+ * @return {number}
+ */
+ _getTextOffset: function(node, child) {
+ var count = 0;
+ var stack = [node];
+ while (stack.length) {
+ var n = stack.pop();
+ if (n === child) {
+ break;
+ }
+ if (n.childNodes && n.childNodes.length !== 0) {
+ var arr = [];
+ n.childNodes.forEach(function(_child) {
+ arr.push(_child);
+ });
+ arr.reverse();
+ stack = stack.concat(arr);
+ } else {
+ count += this._getLength(n);
+ }
+ }
+ return count;
+ },
});
})();
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-diff-highlight_test.html b/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-diff-highlight_test.html
index 5f84e4f..2612f9a 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-diff-highlight_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-diff-highlight_test.html
@@ -487,6 +487,27 @@
assert.equal(getActionSide(), 'left');
});
+ test('properly accounts for syntax highlighting', function() {
+ var content = stubContent(140, 'left');
+ var spy = sinon.spy(element, '_normalizeRange');
+ emulateSelection(
+ content.querySelectorAll('hl')[3], 0,
+ content.querySelectorAll('span')[1], 0);
+ var spyCall = spy.getCall(0);
+ var range = window.getSelection().getRangeAt(0);
+ assert.notDeepEqual(spyCall.returnValue, range);
+ });
+
+ test('_getTextOffset computes text offset', function() {
+ var content = stubContent(140, 'left');
+ var child = content.lastChild.lastChild;
+ var result = element._getTextOffset(content, child);
+ assert.equal(result, 73);
+ content = stubContent(146, 'right');
+ child = content.lastChild;
+ result = element._getTextOffset(content, child);
+ assert.equal(result, 0);
+ });
// TODO (viktard): Selection starts in line number.
// TODO (viktard): Empty lines in selection start.
// TODO (viktard): Empty lines in selection end.