Imperative named Slots
The idea is to instead of imperatively appending slotted comments to threadGroupEls (which results in them being removed from the light DOM of the gr-diff element and thus causing all kinds of tracking difficulties), to slot them into a named slot in the appropriate line. Change-Id: I17e99b236240baab581f8c266bed3d400a302408
This commit is contained in:
@@ -20,10 +20,8 @@
|
|||||||
// Prevent redefinition.
|
// Prevent redefinition.
|
||||||
if (window.GrDiffBuilderBinary) { return; }
|
if (window.GrDiffBuilderBinary) { return; }
|
||||||
|
|
||||||
function GrDiffBuilderBinary(diff, commentThreadEls, prefs,
|
function GrDiffBuilderBinary(diff, prefs, outputEl) {
|
||||||
outputEl) {
|
GrDiffBuilder.call(this, diff, prefs, outputEl);
|
||||||
GrDiffBuilder.call(this, diff, commentThreadEls, prefs,
|
|
||||||
outputEl);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GrDiffBuilderBinary.prototype = Object.create(GrDiffBuilder.prototype);
|
GrDiffBuilderBinary.prototype = Object.create(GrDiffBuilder.prototype);
|
||||||
|
|||||||
@@ -22,10 +22,8 @@
|
|||||||
|
|
||||||
const IMAGE_MIME_PATTERN = /^image\/(bmp|gif|jpeg|jpg|png|tiff|webp)$/;
|
const IMAGE_MIME_PATTERN = /^image\/(bmp|gif|jpeg|jpg|png|tiff|webp)$/;
|
||||||
|
|
||||||
function GrDiffBuilderImage(diff, commentThreadEls, prefs,
|
function GrDiffBuilderImage(diff, prefs, outputEl, baseImage, revisionImage) {
|
||||||
outputEl, baseImage, revisionImage) {
|
GrDiffBuilderSideBySide.call(this, diff, prefs, outputEl, []);
|
||||||
GrDiffBuilderSideBySide.call(this, diff, commentThreadEls,
|
|
||||||
prefs, outputEl, []);
|
|
||||||
this._baseImage = baseImage;
|
this._baseImage = baseImage;
|
||||||
this._revisionImage = revisionImage;
|
this._revisionImage = revisionImage;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,10 +20,8 @@
|
|||||||
// Prevent redefinition.
|
// Prevent redefinition.
|
||||||
if (window.GrDiffBuilderSideBySide) { return; }
|
if (window.GrDiffBuilderSideBySide) { return; }
|
||||||
|
|
||||||
function GrDiffBuilderSideBySide(diff, commentThreadEls,
|
function GrDiffBuilderSideBySide(diff, prefs, outputEl, layers) {
|
||||||
prefs, outputEl, layers) {
|
GrDiffBuilder.call(this, diff, prefs, outputEl, layers);
|
||||||
GrDiffBuilder.call(this, diff, commentThreadEls, prefs,
|
|
||||||
outputEl, layers);
|
|
||||||
}
|
}
|
||||||
GrDiffBuilderSideBySide.prototype = Object.create(GrDiffBuilder.prototype);
|
GrDiffBuilderSideBySide.prototype = Object.create(GrDiffBuilder.prototype);
|
||||||
GrDiffBuilderSideBySide.prototype.constructor = GrDiffBuilderSideBySide;
|
GrDiffBuilderSideBySide.prototype.constructor = GrDiffBuilderSideBySide;
|
||||||
@@ -99,10 +97,6 @@
|
|||||||
row.appendChild(action);
|
row.appendChild(action);
|
||||||
} else {
|
} else {
|
||||||
const textEl = this._createTextEl(line, side);
|
const textEl = this._createTextEl(line, side);
|
||||||
const threadGroupEl = this._commentThreadGroupForLine(line, side);
|
|
||||||
if (threadGroupEl) {
|
|
||||||
textEl.appendChild(threadGroupEl);
|
|
||||||
}
|
|
||||||
row.appendChild(textEl);
|
row.appendChild(textEl);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -20,10 +20,8 @@
|
|||||||
// Prevent redefinition.
|
// Prevent redefinition.
|
||||||
if (window.GrDiffBuilderUnified) { return; }
|
if (window.GrDiffBuilderUnified) { return; }
|
||||||
|
|
||||||
function GrDiffBuilderUnified(diff, commentThreadEls, prefs,
|
function GrDiffBuilderUnified(diff, prefs, outputEl, layers) {
|
||||||
outputEl, layers) {
|
GrDiffBuilder.call(this, diff, prefs, outputEl, layers);
|
||||||
GrDiffBuilder.call(this, diff, commentThreadEls, prefs,
|
|
||||||
outputEl, layers);
|
|
||||||
}
|
}
|
||||||
GrDiffBuilderUnified.prototype = Object.create(GrDiffBuilder.prototype);
|
GrDiffBuilderUnified.prototype = Object.create(GrDiffBuilder.prototype);
|
||||||
GrDiffBuilderUnified.prototype.constructor = GrDiffBuilderUnified;
|
GrDiffBuilderUnified.prototype.constructor = GrDiffBuilderUnified;
|
||||||
@@ -88,10 +86,6 @@
|
|||||||
row.appendChild(action);
|
row.appendChild(action);
|
||||||
} else {
|
} else {
|
||||||
const textEl = this._createTextEl(line);
|
const textEl = this._createTextEl(line);
|
||||||
const threadGroupEl = this._commentThreadGroupForLine(line);
|
|
||||||
if (threadGroupEl) {
|
|
||||||
textEl.appendChild(threadGroupEl);
|
|
||||||
}
|
|
||||||
row.appendChild(textEl);
|
row.appendChild(textEl);
|
||||||
}
|
}
|
||||||
return row;
|
return row;
|
||||||
|
|||||||
@@ -121,10 +121,6 @@ limitations under the License.
|
|||||||
return this.queryEffectiveChildren('#diffTable');
|
return this.queryEffectiveChildren('#diffTable');
|
||||||
},
|
},
|
||||||
|
|
||||||
get _commentThreadElements() {
|
|
||||||
return this.queryAllEffectiveChildren('.comment-thread');
|
|
||||||
},
|
|
||||||
|
|
||||||
observers: [
|
observers: [
|
||||||
'_groupsChanged(_groups.splices)',
|
'_groupsChanged(_groups.splices)',
|
||||||
],
|
],
|
||||||
@@ -292,20 +288,16 @@ limitations under the License.
|
|||||||
|
|
||||||
let builder = null;
|
let builder = null;
|
||||||
if (this.isImageDiff) {
|
if (this.isImageDiff) {
|
||||||
builder = new GrDiffBuilderImage(diff,
|
builder = new GrDiffBuilderImage(diff, prefs, this.diffElement,
|
||||||
this._commentThreadElements, prefs, this.diffElement,
|
|
||||||
this.baseImage, this.revisionImage);
|
this.baseImage, this.revisionImage);
|
||||||
} else if (diff.binary) {
|
} else if (diff.binary) {
|
||||||
// If the diff is binary, but not an image.
|
// If the diff is binary, but not an image.
|
||||||
return new GrDiffBuilderBinary(diff,
|
return new GrDiffBuilderBinary(diff, prefs, this.diffElement);
|
||||||
this._commentThreadElements, prefs, this.diffElement);
|
|
||||||
} else if (this.viewMode === DiffViewMode.SIDE_BY_SIDE) {
|
} else if (this.viewMode === DiffViewMode.SIDE_BY_SIDE) {
|
||||||
builder = new GrDiffBuilderSideBySide(diff,
|
builder = new GrDiffBuilderSideBySide(diff, prefs, this.diffElement,
|
||||||
this._commentThreadElements, prefs, this.diffElement,
|
|
||||||
this._layers);
|
this._layers);
|
||||||
} else if (this.viewMode === DiffViewMode.UNIFIED) {
|
} else if (this.viewMode === DiffViewMode.UNIFIED) {
|
||||||
builder = new GrDiffBuilderUnified(diff,
|
builder = new GrDiffBuilderUnified(diff, prefs, this.diffElement,
|
||||||
this._commentThreadElements, prefs, this.diffElement,
|
|
||||||
this._layers);
|
this._layers);
|
||||||
}
|
}
|
||||||
if (!builder) {
|
if (!builder) {
|
||||||
|
|||||||
@@ -20,60 +20,6 @@
|
|||||||
// Prevent redefinition.
|
// Prevent redefinition.
|
||||||
if (window.GrDiffBuilder) { return; }
|
if (window.GrDiffBuilder) { return; }
|
||||||
|
|
||||||
/** @enum {string} */
|
|
||||||
Gerrit.DiffSide = {
|
|
||||||
LEFT: 'left',
|
|
||||||
RIGHT: 'right',
|
|
||||||
BOTH: 'both',
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {!Array<!HTMLElement>} threadEls
|
|
||||||
* @param {!{beforeNumber: (number|string|undefined),
|
|
||||||
* afterNumber: (number|string|undefined)}}
|
|
||||||
* lineInfo
|
|
||||||
* @param {!Gerrit.DiffSide=} side The side (LEFT, RIGHT, BOTH) for
|
|
||||||
* which to return the threads (default: BOTH).
|
|
||||||
* @return {!Array<!HTMLElement>} The thread elements matching the given
|
|
||||||
* location.
|
|
||||||
*/
|
|
||||||
Gerrit.filterThreadElsForLocation = function(
|
|
||||||
threadEls, lineInfo, side = Gerrit.DiffSide.BOTH) {
|
|
||||||
function matchesLeftLine(threadEl) {
|
|
||||||
return threadEl.getAttribute('comment-side') ==
|
|
||||||
Gerrit.DiffSide.LEFT &&
|
|
||||||
threadEl.getAttribute('line-num') == lineInfo.beforeNumber;
|
|
||||||
}
|
|
||||||
function matchesRightLine(threadEl) {
|
|
||||||
return threadEl.getAttribute('comment-side') ==
|
|
||||||
Gerrit.DiffSide.RIGHT &&
|
|
||||||
threadEl.getAttribute('line-num') == lineInfo.afterNumber;
|
|
||||||
}
|
|
||||||
function matchesFileComment(threadEl) {
|
|
||||||
return (side === Gerrit.DiffSide.BOTH ||
|
|
||||||
threadEl.getAttribute('comment-side') == side) &&
|
|
||||||
// line/range comments have 1-based line set, if line is falsy it's
|
|
||||||
// a file comment
|
|
||||||
!threadEl.getAttribute('line-num');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Select the appropriate matchers for the desired side and line
|
|
||||||
// If side is BOTH, we want both the left and right matcher.
|
|
||||||
const matchers = [];
|
|
||||||
if (side !== Gerrit.DiffSide.RIGHT) {
|
|
||||||
matchers.push(matchesLeftLine);
|
|
||||||
}
|
|
||||||
if (side !== Gerrit.DiffSide.LEFT) {
|
|
||||||
matchers.push(matchesRightLine);
|
|
||||||
}
|
|
||||||
if (lineInfo.afterNumber === 'FILE' ||
|
|
||||||
lineInfo.beforeNumber === 'FILE') {
|
|
||||||
matchers.push(matchesFileComment);
|
|
||||||
}
|
|
||||||
return threadEls.filter(threadEl =>
|
|
||||||
matchers.some(matcher => matcher(threadEl)));
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* In JS, unicode code points above 0xFFFF occupy two elements of a string.
|
* In JS, unicode code points above 0xFFFF occupy two elements of a string.
|
||||||
* For example '𐀏'.length is 2. An occurence of such a code point is called a
|
* For example '𐀏'.length is 2. An occurence of such a code point is called a
|
||||||
@@ -96,8 +42,7 @@
|
|||||||
*/
|
*/
|
||||||
const REGEX_TAB_OR_SURROGATE_PAIR = /\t|[\uD800-\uDBFF][\uDC00-\uDFFF]/;
|
const REGEX_TAB_OR_SURROGATE_PAIR = /\t|[\uD800-\uDBFF][\uDC00-\uDFFF]/;
|
||||||
|
|
||||||
function GrDiffBuilder(diff, commentThreadEls, prefs,
|
function GrDiffBuilder(diff, prefs, outputEl, layers) {
|
||||||
outputEl, layers) {
|
|
||||||
this._diff = diff;
|
this._diff = diff;
|
||||||
this._prefs = prefs;
|
this._prefs = prefs;
|
||||||
this._outputEl = outputEl;
|
this._outputEl = outputEl;
|
||||||
@@ -119,8 +64,6 @@
|
|||||||
layer.addListener(this._handleLayerUpdate.bind(this));
|
layer.addListener(this._handleLayerUpdate.bind(this));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this._threadEls = commentThreadEls;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GrDiffBuilder.GroupType = {
|
GrDiffBuilder.GroupType = {
|
||||||
@@ -373,31 +316,6 @@
|
|||||||
return button;
|
return button;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {!GrDiffLine} line
|
|
||||||
* @param {!GrDiffBuilder.Side=} side The side (LEFT, RIGHT, BOTH) for which
|
|
||||||
* to return the thread group (default: BOTH).
|
|
||||||
* @return {!Object}
|
|
||||||
*/
|
|
||||||
GrDiffBuilder.prototype._commentThreadGroupForLine = function(
|
|
||||||
line, commentSide = GrDiffBuilder.Side.BOTH) {
|
|
||||||
const threadElsForGroup =
|
|
||||||
Gerrit.filterThreadElsForLocation(this._threadEls, line, commentSide);
|
|
||||||
if (!threadElsForGroup || threadElsForGroup.length === 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const threadGroupEl = document.createElement('div');
|
|
||||||
threadGroupEl.className = 'thread-group';
|
|
||||||
for (const threadEl of threadElsForGroup) {
|
|
||||||
Polymer.dom(threadGroupEl).appendChild(threadEl);
|
|
||||||
}
|
|
||||||
if (commentSide) {
|
|
||||||
threadGroupEl.setAttribute('data-side', commentSide);
|
|
||||||
}
|
|
||||||
return threadGroupEl;
|
|
||||||
};
|
|
||||||
|
|
||||||
GrDiffBuilder.prototype._createLineEl = function(
|
GrDiffBuilder.prototype._createLineEl = function(
|
||||||
line, number, type, opt_class) {
|
line, number, type, opt_class) {
|
||||||
const td = this._createElement('td');
|
const td = this._createElement('td');
|
||||||
|
|||||||
@@ -75,70 +75,11 @@ limitations under the License.
|
|||||||
show_tabs: true,
|
show_tabs: true,
|
||||||
tab_size: 4,
|
tab_size: 4,
|
||||||
};
|
};
|
||||||
builder = new GrDiffBuilder({content: []}, [], prefs);
|
builder = new GrDiffBuilder({content: []}, prefs);
|
||||||
});
|
});
|
||||||
|
|
||||||
teardown(() => { sandbox.restore(); });
|
teardown(() => { sandbox.restore(); });
|
||||||
|
|
||||||
test('filterThreadElsForLocation with no threads', () => {
|
|
||||||
const line = {beforeNumber: 3, afterNumber: 5};
|
|
||||||
|
|
||||||
const threads = [];
|
|
||||||
assert.deepEqual(Gerrit.filterThreadElsForLocation(threads, line), []);
|
|
||||||
assert.deepEqual(Gerrit.filterThreadElsForLocation(threads, line,
|
|
||||||
Gerrit.DiffSide.LEFT), []);
|
|
||||||
assert.deepEqual(Gerrit.filterThreadElsForLocation(threads, line,
|
|
||||||
Gerrit.DiffSide.RIGHT), []);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('filterThreadElsForLocation for line comments', () => {
|
|
||||||
const line = {beforeNumber: 3, afterNumber: 5};
|
|
||||||
|
|
||||||
const l3 = document.createElement('div');
|
|
||||||
l3.setAttribute('line-num', 3);
|
|
||||||
l3.setAttribute('comment-side', 'left');
|
|
||||||
|
|
||||||
const l5 = document.createElement('div');
|
|
||||||
l5.setAttribute('line-num', 5);
|
|
||||||
l5.setAttribute('comment-side', 'left');
|
|
||||||
|
|
||||||
const r3 = document.createElement('div');
|
|
||||||
r3.setAttribute('line-num', 3);
|
|
||||||
r3.setAttribute('comment-side', 'right');
|
|
||||||
|
|
||||||
const r5 = document.createElement('div');
|
|
||||||
r5.setAttribute('line-num', 5);
|
|
||||||
r5.setAttribute('comment-side', 'right');
|
|
||||||
|
|
||||||
const threadEls = [l3, l5, r3, r5];
|
|
||||||
assert.deepEqual(Gerrit.filterThreadElsForLocation(threadEls, line),
|
|
||||||
[l3, r5]);
|
|
||||||
assert.deepEqual(Gerrit.filterThreadElsForLocation(threadEls, line,
|
|
||||||
Gerrit.DiffSide.LEFT), [l3]);
|
|
||||||
assert.deepEqual(Gerrit.filterThreadElsForLocation(threadEls, line,
|
|
||||||
Gerrit.DiffSide.RIGHT), [r5]);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('filterThreadElsForLocation for file comments', () => {
|
|
||||||
const line = {beforeNumber: 'FILE', afterNumber: 'FILE'};
|
|
||||||
|
|
||||||
const l = document.createElement('div');
|
|
||||||
l.setAttribute('comment-side', 'left');
|
|
||||||
|
|
||||||
const r = document.createElement('div');
|
|
||||||
r.setAttribute('comment-side', 'right');
|
|
||||||
|
|
||||||
const threadEls = [l, r];
|
|
||||||
assert.deepEqual(Gerrit.filterThreadElsForLocation(threadEls, line),
|
|
||||||
[l, r]);
|
|
||||||
assert.deepEqual(Gerrit.filterThreadElsForLocation(threadEls, line,
|
|
||||||
Gerrit.DiffSide.BOTH), [l, r]);
|
|
||||||
assert.deepEqual(Gerrit.filterThreadElsForLocation(threadEls, line,
|
|
||||||
Gerrit.DiffSide.LEFT), [l]);
|
|
||||||
assert.deepEqual(Gerrit.filterThreadElsForLocation(threadEls, line,
|
|
||||||
Gerrit.DiffSide.RIGHT), [r]);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('_createElement classStr applies all classes', () => {
|
test('_createElement classStr applies all classes', () => {
|
||||||
const node = builder._createElement('div', 'test classes');
|
const node = builder._createElement('div', 'test classes');
|
||||||
assert.isTrue(node.classList.contains('gr-diff'));
|
assert.isTrue(node.classList.contains('gr-diff'));
|
||||||
@@ -312,73 +253,6 @@ limitations under the License.
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test('comment thread group creation', () => {
|
|
||||||
const l3 = document.createElement('div');
|
|
||||||
l3.className = 'comment-thread';
|
|
||||||
l3.setAttribute('comment-side', 'left');
|
|
||||||
l3.setAttribute('line-num', 3);
|
|
||||||
|
|
||||||
const l5 = document.createElement('div');
|
|
||||||
l5.className = 'comment-thread';
|
|
||||||
l5.setAttribute('comment-side', 'left');
|
|
||||||
l5.setAttribute('line-num', 5);
|
|
||||||
|
|
||||||
const r5 = document.createElement('div');
|
|
||||||
r5.className = 'comment-thread';
|
|
||||||
r5.setAttribute('comment-side', 'right');
|
|
||||||
r5.setAttribute('line-num', 5);
|
|
||||||
|
|
||||||
builder = new GrDiffBuilder({content: []}, [l3, l5, r5], prefs);
|
|
||||||
|
|
||||||
function checkThreadGroupProps(threadGroupEl,
|
|
||||||
expectedThreadEls) {
|
|
||||||
const threadEls = Polymer.dom(threadGroupEl).queryDistributedElements(
|
|
||||||
'.comment-thread');
|
|
||||||
assert.equal(threadEls.length, expectedThreadEls.length);
|
|
||||||
for (let i=0; i<expectedThreadEls.length; i++) {
|
|
||||||
assert.equal(threadEls[i], expectedThreadEls[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let line = new GrDiffLine(GrDiffLine.Type.BOTH);
|
|
||||||
line.beforeNumber = 5;
|
|
||||||
line.afterNumber = 5;
|
|
||||||
let threadGroupEl = builder._commentThreadGroupForLine(line);
|
|
||||||
checkThreadGroupProps(threadGroupEl, [l5, r5]);
|
|
||||||
|
|
||||||
threadGroupEl =
|
|
||||||
builder._commentThreadGroupForLine(line, GrDiffBuilder.Side.RIGHT);
|
|
||||||
checkThreadGroupProps(threadGroupEl, [r5]);
|
|
||||||
|
|
||||||
threadGroupEl =
|
|
||||||
builder._commentThreadGroupForLine(line, GrDiffBuilder.Side.LEFT);
|
|
||||||
checkThreadGroupProps(threadGroupEl, [l5]);
|
|
||||||
|
|
||||||
threadGroupEl = builder._commentThreadGroupForLine(line);
|
|
||||||
checkThreadGroupProps(threadGroupEl, [l5, r5]);
|
|
||||||
|
|
||||||
threadEl =
|
|
||||||
builder._commentThreadGroupForLine(line, GrDiffBuilder.Side.LEFT);
|
|
||||||
checkThreadGroupProps(threadEl, [l5]);
|
|
||||||
|
|
||||||
threadGroupEl =
|
|
||||||
builder._commentThreadGroupForLine(line, GrDiffBuilder.Side.RIGHT);
|
|
||||||
checkThreadGroupProps(threadGroupEl, [r5]);
|
|
||||||
|
|
||||||
line = new GrDiffLine(GrDiffLine.Type.REMOVE);
|
|
||||||
line.beforeNumber = 5;
|
|
||||||
line.afterNumber = 5;
|
|
||||||
threadGroupEl = builder._commentThreadGroupForLine(line);
|
|
||||||
checkThreadGroupProps(threadGroupEl, [l5, r5]);
|
|
||||||
|
|
||||||
line = new GrDiffLine(GrDiffLine.Type.ADD);
|
|
||||||
line.beforeNumber = 3;
|
|
||||||
line.afterNumber = 5;
|
|
||||||
threadGroupEl = builder._commentThreadGroupForLine(line);
|
|
||||||
checkThreadGroupProps(threadGroupEl, [l3, r5]);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
test('_handlePreferenceError called with invalid preference', () => {
|
test('_handlePreferenceError called with invalid preference', () => {
|
||||||
sandbox.stub(element, '_handlePreferenceError');
|
sandbox.stub(element, '_handlePreferenceError');
|
||||||
const prefs = {tab_size: 0};
|
const prefs = {tab_size: 0};
|
||||||
@@ -913,7 +787,7 @@ limitations under the License.
|
|||||||
outputEl = element.queryEffectiveChildren('#diffTable');
|
outputEl = element.queryEffectiveChildren('#diffTable');
|
||||||
keyLocations = {left: {}, right: {}};
|
keyLocations = {left: {}, right: {}};
|
||||||
sandbox.stub(element, '_getDiffBuilder', () => {
|
sandbox.stub(element, '_getDiffBuilder', () => {
|
||||||
const builder = new GrDiffBuilder({content}, [], prefs, outputEl);
|
const builder = new GrDiffBuilder({content}, prefs, outputEl);
|
||||||
sandbox.stub(builder, 'addColumns');
|
sandbox.stub(builder, 'addColumns');
|
||||||
builder.buildSectionElement = function(group) {
|
builder.buildSectionElement = function(group) {
|
||||||
const section = document.createElement('stub');
|
const section = document.createElement('stub');
|
||||||
|
|||||||
@@ -74,8 +74,16 @@
|
|||||||
this.debounce('selectionChange', this._handleSelection, 200);
|
this.debounce('selectionChange', this._handleSelection, 200);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_getThreadEl(e) {
|
||||||
|
const path = Polymer.dom(e).path || [];
|
||||||
|
for (const pathEl of path) {
|
||||||
|
if (pathEl.classList.contains('comment-thread')) return pathEl;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
|
||||||
_handleCommentThreadMouseenter(e) {
|
_handleCommentThreadMouseenter(e) {
|
||||||
const threadEl = Polymer.dom(e).localTarget;
|
const threadEl = this._getThreadEl(e);
|
||||||
const index = this._indexForThreadEl(threadEl);
|
const index = this._indexForThreadEl(threadEl);
|
||||||
|
|
||||||
if (index !== undefined) {
|
if (index !== undefined) {
|
||||||
@@ -84,7 +92,7 @@
|
|||||||
},
|
},
|
||||||
|
|
||||||
_handleCommentThreadMouseleave(e) {
|
_handleCommentThreadMouseleave(e) {
|
||||||
const threadEl = Polymer.dom(e).localTarget;
|
const threadEl = this._getThreadEl(e);
|
||||||
const index = this._indexForThreadEl(threadEl);
|
const index = this._indexForThreadEl(threadEl);
|
||||||
|
|
||||||
if (index !== undefined) {
|
if (index !== undefined) {
|
||||||
|
|||||||
@@ -199,6 +199,7 @@ limitations under the License.
|
|||||||
|
|
||||||
test('comment-thread-mouseenter from line comments is ignored', () => {
|
test('comment-thread-mouseenter from line comments is ignored', () => {
|
||||||
const threadEl = document.createElement('div');
|
const threadEl = document.createElement('div');
|
||||||
|
threadEl.className = 'comment-thread';
|
||||||
threadEl.setAttribute('comment-side', 'right');
|
threadEl.setAttribute('comment-side', 'right');
|
||||||
threadEl.setAttribute('line-num', 3);
|
threadEl.setAttribute('line-num', 3);
|
||||||
element.appendChild(threadEl);
|
element.appendChild(threadEl);
|
||||||
@@ -212,6 +213,7 @@ limitations under the License.
|
|||||||
|
|
||||||
test('comment-thread-mouseenter from ranged comment causes set', () => {
|
test('comment-thread-mouseenter from ranged comment causes set', () => {
|
||||||
const threadEl = document.createElement('div');
|
const threadEl = document.createElement('div');
|
||||||
|
threadEl.className = 'comment-thread';
|
||||||
threadEl.setAttribute('comment-side', 'right');
|
threadEl.setAttribute('comment-side', 'right');
|
||||||
threadEl.setAttribute('line-num', 3);
|
threadEl.setAttribute('line-num', 3);
|
||||||
threadEl.setAttribute('range', JSON.stringify({
|
threadEl.setAttribute('range', JSON.stringify({
|
||||||
@@ -239,6 +241,7 @@ limitations under the License.
|
|||||||
|
|
||||||
test('comment-thread-mouseleave from line comments is ignored', () => {
|
test('comment-thread-mouseleave from line comments is ignored', () => {
|
||||||
const threadEl = document.createElement('div');
|
const threadEl = document.createElement('div');
|
||||||
|
threadEl.className = 'comment-thread';
|
||||||
threadEl.setAttribute('comment-side', 'right');
|
threadEl.setAttribute('comment-side', 'right');
|
||||||
threadEl.setAttribute('line-num', 3);
|
threadEl.setAttribute('line-num', 3);
|
||||||
element.appendChild(threadEl);
|
element.appendChild(threadEl);
|
||||||
|
|||||||
@@ -63,6 +63,12 @@
|
|||||||
a.end_character === b.end_character;
|
a.end_character === b.end_character;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @enum {string} */
|
||||||
|
Gerrit.DiffSide = {
|
||||||
|
LEFT: 'left',
|
||||||
|
RIGHT: 'right',
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wrapper around gr-diff.
|
* Wrapper around gr-diff.
|
||||||
*
|
*
|
||||||
@@ -196,11 +202,6 @@
|
|||||||
type: Number,
|
type: Number,
|
||||||
computed: '_computeParentIndex(patchRange.*)',
|
computed: '_computeParentIndex(patchRange.*)',
|
||||||
},
|
},
|
||||||
|
|
||||||
_threadEls: {
|
|
||||||
type: Array,
|
|
||||||
value: () => [],
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
|
||||||
behaviors: [
|
behaviors: [
|
||||||
@@ -344,7 +345,7 @@
|
|||||||
* @return {!Array<!HTMLElement>}
|
* @return {!Array<!HTMLElement>}
|
||||||
*/
|
*/
|
||||||
getThreadEls() {
|
getThreadEls() {
|
||||||
return this._threadEls;
|
return Polymer.dom(this.$.diff).querySelectorAll('.comment-thread');
|
||||||
},
|
},
|
||||||
|
|
||||||
/** @param {HTMLElement} el */
|
/** @param {HTMLElement} el */
|
||||||
@@ -471,7 +472,6 @@
|
|||||||
return isImageDiff(diff);
|
return isImageDiff(diff);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
_commentsChanged(newComments) {
|
_commentsChanged(newComments) {
|
||||||
const allComments = [];
|
const allComments = [];
|
||||||
for (const side of [GrDiffBuilder.Side.LEFT, GrDiffBuilder.Side.RIGHT]) {
|
for (const side of [GrDiffBuilder.Side.LEFT, GrDiffBuilder.Side.RIGHT]) {
|
||||||
@@ -590,21 +590,20 @@
|
|||||||
},
|
},
|
||||||
|
|
||||||
_attachThreadElement(threadEl) {
|
_attachThreadElement(threadEl) {
|
||||||
this._threadEls.push(threadEl);
|
|
||||||
Polymer.dom(this.$.diff).appendChild(threadEl);
|
Polymer.dom(this.$.diff).appendChild(threadEl);
|
||||||
},
|
},
|
||||||
|
|
||||||
_clearThreads() {
|
_clearThreads() {
|
||||||
for (const threadEl of this._threadEls) {
|
for (const threadEl of this.getThreadEls()) {
|
||||||
const parent = Polymer.dom(threadEl).parentNode;
|
const parent = Polymer.dom(threadEl).parentNode;
|
||||||
Polymer.dom(parent).removeChild(threadEl);
|
Polymer.dom(parent).removeChild(threadEl);
|
||||||
}
|
}
|
||||||
this._threadEls = [];
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_createThreadElement(thread) {
|
_createThreadElement(thread) {
|
||||||
const threadEl = document.createElement('gr-diff-comment-thread');
|
const threadEl = document.createElement('gr-diff-comment-thread');
|
||||||
threadEl.className = 'comment-thread';
|
threadEl.className = 'comment-thread';
|
||||||
|
threadEl.slot = `${thread.commentSide}-${thread.lineNum}`;
|
||||||
threadEl.comments = thread.comments;
|
threadEl.comments = thread.comments;
|
||||||
threadEl.commentSide = thread.commentSide;
|
threadEl.commentSide = thread.commentSide;
|
||||||
threadEl.isOnParent = !!thread.isOnParent;
|
threadEl.isOnParent = !!thread.isOnParent;
|
||||||
@@ -625,10 +624,6 @@
|
|||||||
const parent = Polymer.dom(threadEl).parentNode;
|
const parent = Polymer.dom(threadEl).parentNode;
|
||||||
Polymer.dom(parent).removeChild(threadEl);
|
Polymer.dom(parent).removeChild(threadEl);
|
||||||
|
|
||||||
const i = this._threadEls.findIndex(
|
|
||||||
threadEl => threadEl.rootId == e.detail.rootId);
|
|
||||||
this._threadEls.splice(i, 1);
|
|
||||||
|
|
||||||
threadEl.removeEventListener('root-id-changed', rootIdChangedListener);
|
threadEl.removeEventListener('root-id-changed', rootIdChangedListener);
|
||||||
threadEl.removeEventListener('thread-discard', threadDiscardListener);
|
threadEl.removeEventListener('thread-discard', threadDiscardListener);
|
||||||
};
|
};
|
||||||
@@ -660,11 +655,56 @@
|
|||||||
return rangesEqual(threadRange, range);
|
return rangesEqual(threadRange, range);
|
||||||
}
|
}
|
||||||
|
|
||||||
const filteredThreadEls = Gerrit.filterThreadElsForLocation(
|
const filteredThreadEls = this._filterThreadElsForLocation(
|
||||||
this._threadEls, line, commentSide).filter(matchesRange);
|
this.getThreadEls(), line, commentSide).filter(matchesRange);
|
||||||
return filteredThreadEls.length ? filteredThreadEls[0] : null;
|
return filteredThreadEls.length ? filteredThreadEls[0] : null;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {!Array<!HTMLElement>} threadEls
|
||||||
|
* @param {!{beforeNumber: (number|string|undefined|null),
|
||||||
|
* afterNumber: (number|string|undefined|null)}}
|
||||||
|
* lineInfo
|
||||||
|
* @param {!Gerrit.DiffSide=} side The side (LEFT, RIGHT) for
|
||||||
|
* which to return the threads.
|
||||||
|
* @return {!Array<!HTMLElement>} The thread elements matching the given
|
||||||
|
* location.
|
||||||
|
*/
|
||||||
|
_filterThreadElsForLocation(threadEls, lineInfo, side) {
|
||||||
|
function matchesLeftLine(threadEl) {
|
||||||
|
return threadEl.getAttribute('comment-side') ==
|
||||||
|
Gerrit.DiffSide.LEFT &&
|
||||||
|
threadEl.getAttribute('line-num') == lineInfo.beforeNumber;
|
||||||
|
}
|
||||||
|
function matchesRightLine(threadEl) {
|
||||||
|
return threadEl.getAttribute('comment-side') ==
|
||||||
|
Gerrit.DiffSide.RIGHT &&
|
||||||
|
threadEl.getAttribute('line-num') == lineInfo.afterNumber;
|
||||||
|
}
|
||||||
|
function matchesFileComment(threadEl) {
|
||||||
|
return threadEl.getAttribute('comment-side') == side &&
|
||||||
|
// line/range comments have 1-based line set, if line is falsy it's
|
||||||
|
// a file comment
|
||||||
|
!threadEl.getAttribute('line-num');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Select the appropriate matchers for the desired side and line
|
||||||
|
// If side is BOTH, we want both the left and right matcher.
|
||||||
|
const matchers = [];
|
||||||
|
if (side !== Gerrit.DiffSide.RIGHT) {
|
||||||
|
matchers.push(matchesLeftLine);
|
||||||
|
}
|
||||||
|
if (side !== Gerrit.DiffSide.LEFT) {
|
||||||
|
matchers.push(matchesRightLine);
|
||||||
|
}
|
||||||
|
if (lineInfo.afterNumber === 'FILE' ||
|
||||||
|
lineInfo.beforeNumber === 'FILE') {
|
||||||
|
matchers.push(matchesFileComment);
|
||||||
|
}
|
||||||
|
return threadEls.filter(threadEl =>
|
||||||
|
matchers.some(matcher => matcher(threadEl)));
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Take a diff that was loaded with a ignore-whitespace other than
|
* Take a diff that was loaded with a ignore-whitespace other than
|
||||||
* IGNORE_NONE, and convert delta chunks labeled as common into shared
|
* IGNORE_NONE, and convert delta chunks labeled as common into shared
|
||||||
|
|||||||
@@ -769,10 +769,11 @@ limitations under the License.
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('getThreadEls() returns _threadEls', () => {
|
test('getThreadEls() returns .comment-threads', () => {
|
||||||
const returnValue = [document.createElement('b')];
|
const threadEl = document.createElement('div');
|
||||||
element._threadEls = returnValue;
|
threadEl.className = 'comment-thread';
|
||||||
assert.equal(element.getThreadEls(), returnValue);
|
Polymer.dom(element.$.diff).appendChild(threadEl);
|
||||||
|
assert.deepEqual(element.getThreadEls(), [threadEl]);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('delegates addDraftAtLine(el)', () => {
|
test('delegates addDraftAtLine(el)', () => {
|
||||||
@@ -1159,6 +1160,65 @@ limitations under the License.
|
|||||||
assert.equal(threads[1].patchNum, 3);
|
assert.equal(threads[1].patchNum, 3);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('_filterThreadElsForLocation with no threads', () => {
|
||||||
|
const line = {beforeNumber: 3, afterNumber: 5};
|
||||||
|
|
||||||
|
const threads = [];
|
||||||
|
assert.deepEqual(element._filterThreadElsForLocation(threads, line), []);
|
||||||
|
assert.deepEqual(element._filterThreadElsForLocation(threads, line,
|
||||||
|
Gerrit.DiffSide.LEFT), []);
|
||||||
|
assert.deepEqual(element._filterThreadElsForLocation(threads, line,
|
||||||
|
Gerrit.DiffSide.RIGHT), []);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('_filterThreadElsForLocation for line comments', () => {
|
||||||
|
const line = {beforeNumber: 3, afterNumber: 5};
|
||||||
|
|
||||||
|
const l3 = document.createElement('div');
|
||||||
|
l3.setAttribute('line-num', 3);
|
||||||
|
l3.setAttribute('comment-side', 'left');
|
||||||
|
|
||||||
|
const l5 = document.createElement('div');
|
||||||
|
l5.setAttribute('line-num', 5);
|
||||||
|
l5.setAttribute('comment-side', 'left');
|
||||||
|
|
||||||
|
const r3 = document.createElement('div');
|
||||||
|
r3.setAttribute('line-num', 3);
|
||||||
|
r3.setAttribute('comment-side', 'right');
|
||||||
|
|
||||||
|
const r5 = document.createElement('div');
|
||||||
|
r5.setAttribute('line-num', 5);
|
||||||
|
r5.setAttribute('comment-side', 'right');
|
||||||
|
|
||||||
|
const threadEls = [l3, l5, r3, r5];
|
||||||
|
assert.deepEqual(element._filterThreadElsForLocation(threadEls, line),
|
||||||
|
[l3, r5]);
|
||||||
|
assert.deepEqual(element._filterThreadElsForLocation(threadEls, line,
|
||||||
|
Gerrit.DiffSide.LEFT), [l3]);
|
||||||
|
assert.deepEqual(element._filterThreadElsForLocation(threadEls, line,
|
||||||
|
Gerrit.DiffSide.RIGHT), [r5]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('_filterThreadElsForLocation for file comments', () => {
|
||||||
|
const line = {beforeNumber: 'FILE', afterNumber: 'FILE'};
|
||||||
|
|
||||||
|
const l = document.createElement('div');
|
||||||
|
l.setAttribute('comment-side', 'left');
|
||||||
|
|
||||||
|
const r = document.createElement('div');
|
||||||
|
r.setAttribute('comment-side', 'right');
|
||||||
|
|
||||||
|
const threadEls = [l, r];
|
||||||
|
assert.deepEqual(element._filterThreadElsForLocation(threadEls, line),
|
||||||
|
[l, r]);
|
||||||
|
assert.deepEqual(element._filterThreadElsForLocation(threadEls, line,
|
||||||
|
Gerrit.DiffSide.BOTH), [l, r]);
|
||||||
|
assert.deepEqual(element._filterThreadElsForLocation(threadEls, line,
|
||||||
|
Gerrit.DiffSide.LEFT), [l]);
|
||||||
|
assert.deepEqual(element._filterThreadElsForLocation(threadEls, line,
|
||||||
|
Gerrit.DiffSide.RIGHT), [r]);
|
||||||
|
});
|
||||||
|
|
||||||
suite('_translateChunksToIgnore', () => {
|
suite('_translateChunksToIgnore', () => {
|
||||||
let content;
|
let content;
|
||||||
|
|
||||||
|
|||||||
@@ -294,7 +294,6 @@ limitations under the License.
|
|||||||
is-image-diff="[[isImageDiff]]"
|
is-image-diff="[[isImageDiff]]"
|
||||||
base-image="[[baseImage]]"
|
base-image="[[baseImage]]"
|
||||||
revision-image="[[revisionImage]]">
|
revision-image="[[revisionImage]]">
|
||||||
<slot></slot>
|
|
||||||
<table
|
<table
|
||||||
id="diffTable"
|
id="diffTable"
|
||||||
class$="[[_diffTableClass]]"
|
class$="[[_diffTableClass]]"
|
||||||
|
|||||||
@@ -60,6 +60,20 @@
|
|||||||
node.classList.contains('comment-thread');
|
node.classList.contains('comment-thread');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Turn a slot element into the corresponding content element.
|
||||||
|
* Slots are only fully supported in Polymer 2 - in Polymer 1, they are
|
||||||
|
* replaced with content elements during template parsing. This conversion is
|
||||||
|
* not applied for imperatively created slot elements, so this method
|
||||||
|
* implements the same behavior as the template parsing for imperative slots.
|
||||||
|
*/
|
||||||
|
Gerrit.slotToContent = function(slot) {
|
||||||
|
const content = document.createElement('content');
|
||||||
|
content.name = slot.name;
|
||||||
|
content.setAttribute('select', `[slot='${slot.name}']`);
|
||||||
|
return content;
|
||||||
|
};
|
||||||
|
|
||||||
Polymer({
|
Polymer({
|
||||||
is: 'gr-diff',
|
is: 'gr-diff',
|
||||||
|
|
||||||
@@ -455,14 +469,16 @@
|
|||||||
* Gets or creates a comment thread group for a specific line and side on a
|
* Gets or creates a comment thread group for a specific line and side on a
|
||||||
* diff.
|
* diff.
|
||||||
* @param {!Object} contentEl
|
* @param {!Object} contentEl
|
||||||
|
* @param {!Gerrit.DiffSide} commentSide
|
||||||
* @return {!Node}
|
* @return {!Node}
|
||||||
*/
|
*/
|
||||||
_getOrCreateThreadGroup(contentEl) {
|
_getOrCreateThreadGroup(contentEl, commentSide) {
|
||||||
// Check if thread group exists.
|
// Check if thread group exists.
|
||||||
let threadGroupEl = this._getThreadGroupForLine(contentEl);
|
let threadGroupEl = this._getThreadGroupForLine(contentEl);
|
||||||
if (!threadGroupEl) {
|
if (!threadGroupEl) {
|
||||||
threadGroupEl = document.createElement('div');
|
threadGroupEl = document.createElement('div');
|
||||||
threadGroupEl.className = 'thread-group';
|
threadGroupEl.className = 'thread-group';
|
||||||
|
threadGroupEl.setAttribute('data-side', commentSide);
|
||||||
contentEl.appendChild(threadGroupEl);
|
contentEl.appendChild(threadGroupEl);
|
||||||
}
|
}
|
||||||
return threadGroupEl;
|
return threadGroupEl;
|
||||||
@@ -624,8 +640,17 @@
|
|||||||
lineNumString, commentSide);
|
lineNumString, commentSide);
|
||||||
const contentText = this.$.diffBuilder.getContentByLineEl(lineEl);
|
const contentText = this.$.diffBuilder.getContentByLineEl(lineEl);
|
||||||
const contentEl = contentText.parentElement;
|
const contentEl = contentText.parentElement;
|
||||||
const threadGroupEl = this._getOrCreateThreadGroup(contentEl);
|
const threadGroupEl = this._getOrCreateThreadGroup(
|
||||||
Polymer.dom(threadGroupEl).appendChild(threadEl);
|
contentEl, commentSide);
|
||||||
|
// Create a slot for the thread and attach it to the thread group.
|
||||||
|
// The Polyfill has some bugs and this only works if the slot is
|
||||||
|
// attached to the group after the group is attached to the DOM.
|
||||||
|
// The thread group may already have a slot with the right name, but
|
||||||
|
// that is okay because the first matching slot is used and the rest
|
||||||
|
// are ignored.
|
||||||
|
const slot = document.createElement('slot');
|
||||||
|
slot.name = threadEl.slot;
|
||||||
|
Polymer.dom(threadGroupEl).appendChild(Gerrit.slotToContent(slot));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user