Comment events wiring for ranged comments
Listen and update diff on comment events: - call appropriate methods to apply comment ranges on comment creation - re-render diff on and thread comment discard - apply highlight on comment mouse over - remove highlight on comment mouse out - tests for all above Feature: Issue 3910 Change-Id: I501ddcd063407777355b9c887118fcae53dcb5f1
This commit is contained in:
@@ -16,6 +16,8 @@
|
||||
|
||||
// Astral code point as per https://mathiasbynens.be/notes/javascript-unicode
|
||||
var REGEX_ASTRAL_SYMBOL = /[\uD800-\uDBFF][\uDC00-\uDFFF]/;
|
||||
var RANGE_HIGHLIGHT = 'range';
|
||||
var HOVER_HIGHLIGHT = 'rangeHighlight';
|
||||
|
||||
Polymer({
|
||||
is: 'gr-diff-highlight',
|
||||
@@ -28,12 +30,15 @@
|
||||
},
|
||||
loggedIn: Boolean,
|
||||
_cachedDiffBuilder: Object,
|
||||
_diffElement: Object,
|
||||
_enabledListeners: {
|
||||
type: Object,
|
||||
value: function() {
|
||||
return {
|
||||
'down': '_handleDown',
|
||||
'comment-discard': '_handleCommentDiscard',
|
||||
'comment-mouse-out': '_handleCommentMouseOut',
|
||||
'comment-mouse-over': '_handleCommentMouseOver',
|
||||
'create-comment': '_createComment',
|
||||
'thread-discard': '_handleThreadDiscard',
|
||||
};
|
||||
},
|
||||
},
|
||||
@@ -66,13 +71,75 @@
|
||||
return !!this.$$('gr-selection-action-box');
|
||||
},
|
||||
|
||||
_handleDown: function(e) {
|
||||
var actionBox = this.$$('gr-selection-action-box');
|
||||
if (actionBox && !actionBox.contains(e.target)) {
|
||||
this._removeActionBox();
|
||||
_handleThreadDiscard: function(e) {
|
||||
var comment = e.detail.lastComment;
|
||||
// Comment Element was removed from DOM already.
|
||||
if (comment.range) {
|
||||
this._renderCommentRange(comment, e.target);
|
||||
}
|
||||
},
|
||||
|
||||
_handleCommentDiscard: function(e) {
|
||||
var comment = e.detail.comment;
|
||||
if (comment.range) {
|
||||
this._renderCommentRange(comment, e.target);
|
||||
}
|
||||
},
|
||||
|
||||
_handleCommentMouseOver: function(e) {
|
||||
var comment = e.detail.comment;
|
||||
var range = comment.range;
|
||||
if (!range) {
|
||||
return;
|
||||
}
|
||||
var lineEl = this.diffBuilder.getLineElByChild(e.target);
|
||||
var side = this.diffBuilder.getSideByLineEl(lineEl);
|
||||
this._applyRangedHighlight(
|
||||
HOVER_HIGHLIGHT, range.start_line, range.start_character,
|
||||
range.end_line, range.end_character, side);
|
||||
},
|
||||
|
||||
_handleCommentMouseOut: function(e) {
|
||||
var comment = e.detail.comment;
|
||||
var range = comment.range;
|
||||
if (!range) {
|
||||
return;
|
||||
}
|
||||
var lineEl = this.diffBuilder.getLineElByChild(e.target);
|
||||
var side = this.diffBuilder.getSideByLineEl(lineEl);
|
||||
var contentEls = this.diffBuilder.getContentsByLineRange(
|
||||
range.start_line, range.end_line, side);
|
||||
contentEls.forEach(function(content) {
|
||||
Polymer.dom(content).querySelectorAll('.' + HOVER_HIGHLIGHT).forEach(
|
||||
function(el) {
|
||||
el.classList.remove(HOVER_HIGHLIGHT);
|
||||
el.classList.add(RANGE_HIGHLIGHT);
|
||||
});
|
||||
}, this);
|
||||
},
|
||||
|
||||
_renderCommentRange: function(comment, el) {
|
||||
var lineEl = this.diffBuilder.getLineElByChild(el);
|
||||
if (!lineEl) {
|
||||
return;
|
||||
}
|
||||
var side = this.diffBuilder.getSideByLineEl(lineEl);
|
||||
this._rerenderByLines(
|
||||
comment.range.start_line, comment.range.end_line, side);
|
||||
},
|
||||
|
||||
_createComment: function(e) {
|
||||
this._removeActionBox();
|
||||
var side = e.detail.side;
|
||||
var range = e.detail.range;
|
||||
if (!range) {
|
||||
return;
|
||||
}
|
||||
this._applyRangedHighlight(
|
||||
RANGE_HIGHLIGHT, range.startLine, range.startChar,
|
||||
range.endLine, range.endChar, side);
|
||||
},
|
||||
|
||||
_removeActionBox: function() {
|
||||
var actionBox = this.$$('gr-selection-action-box');
|
||||
if (actionBox) {
|
||||
@@ -122,7 +189,7 @@
|
||||
}
|
||||
return length;
|
||||
} else {
|
||||
// DOM API for textConten.length is broken for Unicode:
|
||||
// DOM API for textContent.length is broken for Unicode:
|
||||
// https://mathiasbynens.be/notes/javascript-unicode
|
||||
return node.textContent.replace(REGEX_ASTRAL_SYMBOL, '_').length;
|
||||
}
|
||||
@@ -374,5 +441,11 @@
|
||||
}, this);
|
||||
}
|
||||
},
|
||||
|
||||
_rerenderByLines: function(startLine, endLine, opt_side) {
|
||||
this.async(function() {
|
||||
this.diffBuilder.renderLineRange(startLine, endLine, opt_side);
|
||||
}, 1);
|
||||
},
|
||||
});
|
||||
})();
|
||||
|
||||
@@ -92,14 +92,162 @@ limitations under the License.
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
test('handles down only when enabled ', function() {
|
||||
sinon.stub(element, '_handleDown');
|
||||
MockInteractions.down(element);
|
||||
assert.isFalse(element._handleDown.called);
|
||||
test('_enabledListeners', function() {
|
||||
var listeners = element._enabledListeners;
|
||||
for (var eventName in listeners) {
|
||||
sandbox.stub(element, listeners[eventName]);
|
||||
}
|
||||
// Enable all the listeners.
|
||||
element.enabled = true;
|
||||
MockInteractions.down(element);
|
||||
assert.isTrue(element._handleDown.called);
|
||||
element._handleDown.restore();
|
||||
for (var eventName in listeners) {
|
||||
var methodName = listeners[eventName];
|
||||
var stub = element[methodName];
|
||||
element.fire(eventName);
|
||||
assert.isTrue(stub.called);
|
||||
stub.reset();
|
||||
}
|
||||
// Disable all the listeners.
|
||||
element.enabled = false;
|
||||
for (var eventName in listeners) {
|
||||
var methodName = listeners[eventName];
|
||||
var stub = element[methodName];
|
||||
element.fire(eventName);
|
||||
assert.isFalse(stub.called);
|
||||
}
|
||||
});
|
||||
|
||||
suite('comment events', function() {
|
||||
var builder;
|
||||
|
||||
setup(function() {
|
||||
builder = {
|
||||
getContentsByLineRange: sandbox.stub().returns([]),
|
||||
getLineElByChild: sandbox.stub().returns({}),
|
||||
getSideByLineEl: sandbox.stub().returns('other-side'),
|
||||
renderLineRange: sandbox.stub(),
|
||||
};
|
||||
element._cachedDiffBuilder = builder;
|
||||
element.enabled = true;
|
||||
});
|
||||
|
||||
test('ignores thread discard for line comment', function(done) {
|
||||
element.fire('thread-discard', {lastComment: {}});
|
||||
flush(function() {
|
||||
assert.isFalse(builder.renderLineRange.called);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
test('ignores comment discard for line comment', function(done) {
|
||||
element.fire('comment-discard', {comment: {}});
|
||||
flush(function() {
|
||||
assert.isFalse(builder.renderLineRange.called);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
test('renders lines in comment range on thread discard', function(done) {
|
||||
element.fire('thread-discard', {
|
||||
lastComment: {
|
||||
range: {
|
||||
start_line: 10,
|
||||
end_line: 24,
|
||||
},
|
||||
},
|
||||
});
|
||||
flush(function() {
|
||||
assert.isTrue(
|
||||
builder.renderLineRange.calledWithExactly(10, 24, 'other-side'));
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
test('renders lines in comment range on comment discard', function(done) {
|
||||
element.fire('comment-discard', {
|
||||
comment: {
|
||||
range: {
|
||||
start_line: 10,
|
||||
end_line: 24,
|
||||
},
|
||||
},
|
||||
});
|
||||
flush(function() {
|
||||
assert.isTrue(
|
||||
builder.renderLineRange.calledWithExactly(10, 24, 'other-side'));
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
test('comment-mouse-over from line comments is ignored', function() {
|
||||
sandbox.stub(element, '_applyRangedHighlight');
|
||||
element.fire('comment-mouse-over', {comment: {}});
|
||||
assert.isFalse(element._applyRangedHighlight.called);
|
||||
});
|
||||
|
||||
test('comment-mouse-out from line comments is ignored', function() {
|
||||
element.fire('comment-mouse-over', {comment: {}});
|
||||
assert.isFalse(builder.getContentsByLineRange.called);
|
||||
});
|
||||
|
||||
test('on comment-mouse-out highlight classes are removed', function() {
|
||||
var testEl = fixture('highlighted');
|
||||
builder.getContentsByLineRange.returns([testEl]);
|
||||
element.fire('comment-mouse-out', {
|
||||
comment: {
|
||||
range: {
|
||||
start_line: 3,
|
||||
start_character: 14,
|
||||
end_line: 10,
|
||||
end_character: 24,
|
||||
}
|
||||
}});
|
||||
assert.isTrue(builder.getContentsByLineRange.calledWithExactly(
|
||||
3, 10, 'other-side'));
|
||||
assert.equal(0, testEl.querySelectorAll('.rangeHighlight').length);
|
||||
assert.equal(2, testEl.querySelectorAll('.range').length);
|
||||
});
|
||||
|
||||
test('on comment-mouse-over range is highlighted', function() {
|
||||
sandbox.stub(element, '_applyRangedHighlight');
|
||||
element.fire('comment-mouse-over', {
|
||||
comment: {
|
||||
range: {
|
||||
start_line: 3,
|
||||
start_character: 14,
|
||||
end_line: 10,
|
||||
end_character: 24,
|
||||
},
|
||||
}});
|
||||
assert.isTrue(element._applyRangedHighlight.calledWithExactly(
|
||||
'rangeHighlight', 3, 14, 10, 24, 'other-side'));
|
||||
});
|
||||
|
||||
test('on create-comment range is highlighted', function() {
|
||||
sandbox.stub(element, '_applyRangedHighlight');
|
||||
element.fire('create-comment', {
|
||||
range: {
|
||||
startLine: 3,
|
||||
startChar: 14,
|
||||
endLine: 10,
|
||||
endChar: 24,
|
||||
},
|
||||
side: 'some-side',
|
||||
});
|
||||
assert.isTrue(element._applyRangedHighlight.calledWithExactly(
|
||||
'range', 3, 14, 10, 24, 'some-side'));
|
||||
});
|
||||
|
||||
test('on create-comment action box is removed', function() {
|
||||
sandbox.stub(element, '_applyRangedHighlight');
|
||||
sandbox.stub(element, '_removeActionBox');
|
||||
element.fire('create-comment', {
|
||||
comment: {
|
||||
range: {},
|
||||
},
|
||||
});
|
||||
assert.isTrue(element._removeActionBox.called);
|
||||
});
|
||||
});
|
||||
|
||||
test('apply multiline highlight', function() {
|
||||
|
||||
Reference in New Issue
Block a user