mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-07 20:31:06 -05:00
Track and highlight comment ranges
This commit is contained in:
parent
e85cb161b2
commit
8c65cb5835
3 changed files with 121 additions and 12 deletions
|
@ -49,16 +49,57 @@ define [
|
|||
# Ids are used to uniquely identify a change, e.g. for updating it in the database, or keeping in
|
||||
# sync with Ace ranges.
|
||||
@changes = []
|
||||
@comments = []
|
||||
@id = 0
|
||||
|
||||
addComment: (offset, length, metadata) ->
|
||||
# TODO: Don't allow overlapping comments?
|
||||
@comments.push comment = {
|
||||
id: @_newId()
|
||||
offset, length, metadata
|
||||
}
|
||||
@emit "comment:added", comment
|
||||
|
||||
applyOp: (op, metadata) ->
|
||||
# Apply an op that has been applied to the document to our changes to keep them up to date
|
||||
if op.i?
|
||||
@applyInsert(op, metadata)
|
||||
@applyInsertToChanges(op, metadata)
|
||||
@applyInsertToComments(op)
|
||||
else if op.d?
|
||||
@applyDelete(op, metadata)
|
||||
|
||||
applyInsert: (op, metadata) ->
|
||||
@applyDeleteToChanges(op, metadata)
|
||||
@applyDeleteToComments(op)
|
||||
|
||||
applyInsertToComments: (op) ->
|
||||
for comment in @comments
|
||||
if op.p <= comment.offset
|
||||
comment.offset += op.i.length
|
||||
@emit "comment:moved", comment
|
||||
else if op.p < comment.offset + comment.length
|
||||
comment.length += op.i.length
|
||||
@emit "comment:moved", comment
|
||||
|
||||
applyDeleteToComments: (op) ->
|
||||
op_start = op.p
|
||||
op_length = op.d.length
|
||||
op_end = op.p + op_length
|
||||
for comment in @comments
|
||||
comment_end = comment.offset + comment.length
|
||||
if op_end <= comment.offset
|
||||
# delete is fully before comment
|
||||
comment.offset -= op_length
|
||||
@emit "comment:moved", comment
|
||||
else if op_start >= comment_end
|
||||
# delete is fully after comment, nothing to do
|
||||
else
|
||||
# delete and comment overlap
|
||||
delete_length_before = Math.max(0, comment.offset - op_start)
|
||||
delete_length_after = Math.max(0, op_end - comment_end)
|
||||
delete_length_overlapping = op_length - delete_length_before - delete_length_after
|
||||
comment.offset = Math.min(comment.offset, op_start)
|
||||
comment.length -= delete_length_overlapping
|
||||
@emit "comment:moved", comment
|
||||
|
||||
applyInsertToChanges: (op, metadata) ->
|
||||
op_start = op.p
|
||||
op_length = op.i.length
|
||||
op_end = op.p + op_length
|
||||
|
@ -148,7 +189,7 @@ define [
|
|||
if moved_changes.length > 0
|
||||
@emit "changes:moved", moved_changes
|
||||
|
||||
applyDelete: (op, metadata) ->
|
||||
applyDeleteToChanges: (op, metadata) ->
|
||||
op_start = op.p
|
||||
op_length = op.d.length
|
||||
op_end = op.p + op_length
|
||||
|
|
|
@ -12,7 +12,7 @@ define [
|
|||
@changesTracker.track_changes = true
|
||||
@changeIdToMarkerIdMap = {}
|
||||
@enabled = false
|
||||
window.changesTracker ?= @changesTracker
|
||||
window.trackChangesManager ?= @
|
||||
|
||||
@changesTracker.on "insert:added", (change) =>
|
||||
sl_console.log "[insert:added]", change
|
||||
|
@ -30,6 +30,13 @@ define [
|
|||
sl_console.log "[changes:moved]", changes
|
||||
@_onChangesMoved(changes)
|
||||
|
||||
@changesTracker.on "comment:added", (comment) =>
|
||||
sl_console.log "[comment:added]", comment
|
||||
@_onCommentAdded(comment)
|
||||
@changesTracker.on "comment:moved", (comment) =>
|
||||
sl_console.log "[comment:moved]", comment
|
||||
@_onCommentMoved(comment)
|
||||
|
||||
onChange = (e) =>
|
||||
if !@editor.initing and @enabled
|
||||
# This change is trigger by a sharejs 'change' event, which is before the
|
||||
|
@ -62,6 +69,19 @@ define [
|
|||
@editor.renderer.on "resize", () =>
|
||||
@recalculateReviewEntriesScreenPositions()
|
||||
|
||||
addComment: (offset, length, comment) ->
|
||||
@changesTracker.addComment offset, length, {
|
||||
comment: comment
|
||||
user_id: window.user_id
|
||||
}
|
||||
|
||||
addCommentToSelection: (comment) ->
|
||||
range = @editor.getSelectionRange()
|
||||
offset = @_aceRangeToShareJs(range.start)
|
||||
end = @_aceRangeToShareJs(range.end)
|
||||
length = end - offset
|
||||
@addComment(offset, length, comment)
|
||||
|
||||
checkMapping: () ->
|
||||
session = @editor.getSession()
|
||||
|
||||
|
@ -104,6 +124,12 @@ define [
|
|||
content: change.op.i or change.op.d
|
||||
offset: change.op.p
|
||||
}
|
||||
for comment in @changesTracker.comments
|
||||
@$scope.reviewPanel.entries[comment.id] = {
|
||||
content: comment.metadata.comment
|
||||
offset: comment.offset
|
||||
}
|
||||
|
||||
@recalculateReviewEntriesScreenPositions()
|
||||
|
||||
recalculateReviewEntriesScreenPositions: () ->
|
||||
|
@ -178,16 +204,52 @@ define [
|
|||
session.removeMarker marker_id
|
||||
@updateReviewEntriesScope()
|
||||
|
||||
_aceChangeToShareJs: (delta) ->
|
||||
start = delta.start
|
||||
lines = @editor.getSession().getDocument().getLines 0, start.row
|
||||
_onCommentAdded: (comment) ->
|
||||
start = @_shareJsOffsetToAcePosition(comment.offset)
|
||||
end = @_shareJsOffsetToAcePosition(comment.offset + comment.length)
|
||||
session = @editor.getSession()
|
||||
doc = session.getDocument()
|
||||
ace_range = new Range(start.row, start.column, end.row, end.column)
|
||||
|
||||
hue = ColorManager.getHueForUserId(comment.metadata.user_id)
|
||||
colorScheme = ColorManager.getColorScheme(hue, @element)
|
||||
markerLayer = @editor.renderer.$markerBack
|
||||
klass = "track-changes-comment-marker"
|
||||
style = "border-color: #{colorScheme.cursor}"
|
||||
marker_id = session.addMarker ace_range, klass, (html, range, left, top, config) ->
|
||||
if range.isMultiLine()
|
||||
markerLayer.drawTextMarker(html, range, klass, config, style)
|
||||
else
|
||||
markerLayer.drawSingleLineMarker(html, range, "#{klass} ace_start", config, 0, style)
|
||||
|
||||
@changeIdToMarkerIdMap[comment.id] = marker_id
|
||||
@updateReviewEntriesScope()
|
||||
|
||||
_onCommentMoved: (comment) ->
|
||||
start = @_shareJsOffsetToAcePosition(comment.offset)
|
||||
end = @_shareJsOffsetToAcePosition(comment.offset + comment.length)
|
||||
session = @editor.getSession()
|
||||
ace_range = new Range(start.row, start.column, end.row, end.column)
|
||||
marker_id = @changeIdToMarkerIdMap[comment.id]
|
||||
markers = session.getMarkers()
|
||||
marker = markers[marker_id]
|
||||
marker.range.start = start
|
||||
marker.range.end = end
|
||||
@editor.renderer.updateBackMarkers()
|
||||
@updateReviewEntriesScope()
|
||||
|
||||
_aceRangeToShareJs: (range) ->
|
||||
lines = @editor.getSession().getDocument().getLines 0, range.row
|
||||
offset = 0
|
||||
for line, i in lines
|
||||
offset += if i < start.row
|
||||
offset += if i < range.row
|
||||
line.length
|
||||
else
|
||||
start.column
|
||||
offset += start.row # Include newlines
|
||||
range.column
|
||||
offset += range.row # Include newlines
|
||||
|
||||
_aceChangeToShareJs: (delta) ->
|
||||
offset = @_aceRangeToShareJs(delta.start)
|
||||
|
||||
text = delta.lines.join('\n')
|
||||
switch delta.action
|
||||
|
|
|
@ -147,6 +147,12 @@
|
|||
border-bottom: 1px dashed green;
|
||||
background-color: hsl(100, 70%, 85%);
|
||||
}
|
||||
.track-changes-comment-marker {
|
||||
border-radius: 0;
|
||||
position: absolute;
|
||||
border-bottom: 1px dashed orange;
|
||||
background-color: #fde5b7;
|
||||
}
|
||||
.track-changes-deleted-marker {
|
||||
border-radius: 0;
|
||||
position: absolute;
|
||||
|
|
Loading…
Reference in a new issue