Show nice diffs using ace and markers

This commit is contained in:
James Allen 2014-03-06 14:08:12 +00:00
parent bf21305c68
commit 1a91036bb6
7 changed files with 201 additions and 10 deletions

View file

@ -1,5 +1,4 @@
define [ define [
"history/util"
"libs/mustache" "libs/mustache"
"libs/backbone" "libs/backbone"
], (util)-> ], (util)->
@ -9,7 +8,7 @@ define [
events: events:
"scroll" : "loadUntilFull" "scroll" : "loadUntilFull"
initialize: -> initialize: () ->
@itemViews = [] @itemViews = []
@atEndOfCollection = false @atEndOfCollection = false
@ -34,6 +33,8 @@ define [
index = @collection.indexOf(model) index = @collection.indexOf(model)
elementAtIndex = @$(".change-list").children()[index] elementAtIndex = @$(".change-list").children()[index]
view.$el.insertBefore(elementAtIndex) view.$el.insertBefore(elementAtIndex)
view.on "click", (e, v) =>
@trigger "change_diff", v.model.get("version")
listShorterThanContainer: -> listShorterThanContainer: ->
@$el.height() > @$(".change-list").height() @$el.height() > @$(".change-list").height()
@ -81,6 +82,9 @@ define [
ChangeListItemView = Backbone.View.extend ChangeListItemView = Backbone.View.extend
tagName: "li" tagName: "li"
events:
"click a": "onClick"
template : $("#changeListItemTemplate").html() template : $("#changeListItemTemplate").html()
@ -97,5 +101,9 @@ define [
# modelView.end_ts = util.formatDate(modelView.end_ts) # modelView.end_ts = util.formatDate(modelView.end_ts)
return modelView return modelView
onClick: (e) ->
e.preventDefault()
@trigger "click", e, @
return ChangeListView return ChangeListView

View file

@ -0,0 +1,139 @@
define [
"ace/ace"
"ace/mode/latex"
"ace/range"
"libs/backbone"
], (Ace, LatexMode, Range)->
DiffView = Backbone.View.extend
initialize: () ->
@model.on "change:diff", () => @render()
@render()
render: ->
diff = @model.get("diff")
return unless diff?
@createAceEditor()
@aceEditor.setValue(@getPlainDiffContent())
@aceEditor.clearSelection()
session = @aceEditor.getSession()
session.setMode(new LatexMode.Mode())
session.setUseWrapMode(true)
@insertMarkers()
return @
createAceEditor: () ->
@$el.empty()
$editor = $("<div/>")
@$el.append($editor)
@aceEditor = Ace.edit($editor[0])
@aceEditor.setTheme("ace/theme/#{window.userSettings.theme}")
@aceEditor.setReadOnly true
@aceEditor.setShowPrintMargin(false)
@aceEditor.on "mousemove", (e) =>
position = @aceEditor.renderer.screenToTextCoordinates(e.clientX, e.clientY)
e.position = position
@updateVisibleNames(e)
getPlainDiffContent: () ->
content = ""
for entry in @model.get("diff") or []
content += entry.u or entry.i or entry.d or ""
return content
insertMarkers: () ->
row = 0
column = 0
for entry, i in @model.get("diff") or []
content = entry.u or entry.i or entry.d
lines = content.split("\n")
startRow = row
startColumn = column
if lines.length > 1
endRow = startRow + lines.length - 1
endColumn = lines[lines.length - 1].length
else
endRow = startRow
endColumn = startColumn + lines[0].length
row = endRow
column = endColumn
range = new Range.Range(
startRow, startColumn, endRow, endColumn
)
@addMarker(range, "change-marker-#{i}", entry)
addMarker: (range, id, entry) ->
session = @aceEditor.getSession()
markerBackLayer = @aceEditor.renderer.$markerBack
markerFrontLayer = @aceEditor.renderer.$markerFront
lineHeight = @aceEditor.renderer.lineHeight
if entry.i? or entry.d?
hue = 200
if entry.i?
@_addMarkerWithCustomStyle session, markerBackLayer, range, "deleted-change-background", false, """
background-color : hsl(#{hue}, 70%, 85%);
"""
tag = "Added by #{entry.meta.user_id}"
if entry.d?
@_addMarkerWithCustomStyle session, markerBackLayer, range, "deleted-change-background", false, """
background-color : hsl(#{hue}, 70%, 95%);
"""
@_addMarkerWithCustomStyle session, markerBackLayer, range, "deleted-change-foreground", true, """
height: #{Math.round(lineHeight/2) - 1}px;
border-bottom: 2px solid hsl(#{hue}, 70%, 40%);
"""
tag = "Deleted by #{entry.meta.user_id}"
tag += " on #{entry.meta.end_ts}"
@_addNameTag session, id, range, tag, """
background-color : hsl(#{hue}, 70%, 85%);
"""
_addMarkerWithCustomStyle: (session, markerLayer, range, klass, foreground, style) ->
session.addMarker 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)
, foreground
_addNameTag: (session, id, range, content, style) ->
@nameMarkers ||= []
@nameMarkers.push
range: range
id: id
startRange = new Range.Range(
range.start.row, range.start.column
range.start.row, session.getScreenLastRowColumn(range.start.row)
)
session.addMarker startRange, "change-name-marker", (html, range, left, top, config) ->
html.push """
<div
id = '#{id}'
class = 'change-name-marker'
style = '
height: #{config.lineHeight}px;
top: #{top}px;
left: #{left}px;
'
>
<div
class="name" style="
display: none;
bottom: #{config.lineHeight + 2}px;
#{style}
">#{content}</div>
</div>
"""
, true
updateVisibleNames: (e) ->
for marker in @nameMarkers or []
if marker.range.contains(e.position.row, e.position.column)
$("##{marker.id}").find(".name").show()
else
$("##{marker.id}").find(".name").hide()
return DiffView

View file

@ -1,7 +1,9 @@
define [ define [
"track-changes/models/ChangeList" "track-changes/models/ChangeList"
"track-changes/models/Diff"
"track-changes/ChangeListView" "track-changes/ChangeListView"
], (ChangeList, ChangeListView) -> "track-changes/DiffView"
], (ChangeList, Diff, ChangeListView, DiffView) ->
class TrackChangesManager class TrackChangesManager
template: $("#trackChangesPanelTemplate").html() template: $("#trackChangesPanelTemplate").html()
@ -11,9 +13,9 @@ define [
@hideEl() @hideEl()
show: () -> show: () ->
project_id = window.userSettings.project_id @project_id = window.userSettings.project_id
doc_id = @ide.editor.current_doc_id @doc_id = @ide.editor.current_doc_id
@changes = new ChangeList([], doc_id: doc_id, project_id: project_id) @changes = new ChangeList([], doc_id: @doc_id, project_id: @project_id)
@changeListView = new ChangeListView( @changeListView = new ChangeListView(
collection : @changes, collection : @changes,
@ -22,6 +24,19 @@ define [
@changeListView.render() @changeListView.render()
@changeListView.loadUntilFull() @changeListView.loadUntilFull()
@changeListView.on "change_diff", (version) =>
@diff = new Diff({
project_id: @project_id
doc_id: @doc_id
from: version
to: version
})
@diffView = new DiffView(
model: @diff
el: @$el.find(".track-changes-diff")
)
@diff.fetch()
@showEl() @showEl()
showEl: -> showEl: ->

View file

@ -7,4 +7,5 @@ define [
start_ts: change.meta.start_ts start_ts: change.meta.start_ts
end_ts: change.meta.end_ts end_ts: change.meta.end_ts
user_id: change.meta.user_id user_id: change.meta.user_id
version: change.v
} }

View file

@ -7,13 +7,12 @@ define [
batchSize: 3 batchSize: 3
initialize: (models, @options) -> initialize: (models, @options) ->
console.log arguments
url: () -> url: () ->
url = "/project/#{@options.project_id}/doc/#{@options.doc_id}/updates?limit=#{@batchSize}" url = "/project/#{@options.project_id}/doc/#{@options.doc_id}/updates?limit=#{@batchSize}"
if @models.length > 0 if @models.length > 0
last = @models[@models.length - 1] last = @models[@models.length - 1]
url += "&to=#{last.get("start_ts") - 1}" url += "&to=#{last.get("version") - 1}"
return url return url
parse: (json) -> parse: (json) ->

View file

@ -0,0 +1,6 @@
define [
"libs/backbone"
], ()->
Diff = Backbone.Model.extend
url: () ->
"/project/#{@get("project_id")}/doc/#{@get("doc_id")}/diff?from=#{@get("from")}&to=#{@get("to")}"

View file

@ -5,10 +5,18 @@
.track-changes-diff { .track-changes-diff {
position: absolute; position: absolute;
right: @versionsListWidth + 1px; right: @versionsListWidth + 1px;
right: 0; left: 0;
top: 0;
bottom: 0;
padding: 0px 12px; padding: 0px 12px;
overflow: scroll;
height: 100%; height: 100%;
.ace_editor {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
} }
.track-changes-side-bar { .track-changes-side-bar {
@ -27,4 +35,19 @@
top: 0px; top: 0px;
bottom: 0px; bottom: 0px;
} }
.deleted-change-background, .deleted-change-foreground, .inserted-change, .change-name-marker {
position: absolute;
z-index: 2;
}
.change-name-marker {
.name {
font-size: 0.8em;
padding: 2px 6px;
.border-radius(3px 3px 3px 3px);
position: absolute;
left: 0;
}
}
} }