overleaf/services/web/public/coffee/app/ide/track-changes/TrackChangesManager.coffee

257 lines
7.1 KiB
CoffeeScript
Raw Normal View History

2014-06-26 11:39:52 -04:00
define [
2014-06-27 12:11:26 -04:00
"ide/track-changes/controllers/TrackChangesListController"
"ide/track-changes/controllers/TrackChangesDiffController"
"ide/track-changes/directives/infiniteScroll"
2014-06-26 11:39:52 -04:00
], () ->
class TrackChangesManager
constructor: (@ide, @$scope) ->
2014-06-27 08:46:38 -04:00
@reset()
@$scope.toggleTrackChanges = () =>
if @$scope.ui.view == "track-changes"
@hide()
2014-06-27 08:46:38 -04:00
else
@show()
2014-06-27 08:46:38 -04:00
@$scope.$watch "trackChanges.selection.updates", (updates) =>
if updates? and updates.length > 0
@_selectDocFromUpdates()
@reloadDiff()
@$scope.$on "entity:selected", (event, entity) =>
if (@$scope.ui.view == "track-changes") and (entity.type == "doc")
@$scope.trackChanges.selection.doc = entity
@reloadDiff()
show: () ->
@$scope.ui.view = "track-changes"
2014-06-27 08:46:38 -04:00
@reset()
hide: () ->
@$scope.ui.view = "editor"
# Make sure we run the 'open' logic for whatever is currently selected
@$scope.$emit "entity:selected", @ide.fileTreeManager.findSelectedEntity()
2014-06-27 08:46:38 -04:00
reset: () ->
2014-06-26 11:39:52 -04:00
@$scope.trackChanges = {
updates: []
nextBeforeTimestamp: null
atEnd: false
2014-06-27 07:45:37 -04:00
selection: {
updates: []
doc: null
range: {
fromV: null
toV: null
start_ts: null
end_ts: null
}
}
diff: null
2014-06-26 11:39:52 -04:00
}
2014-06-27 08:46:38 -04:00
autoSelectRecentUpdates: () ->
console.log "AUTO SELECTING UPDATES", @$scope.trackChanges.updates.length
return if @$scope.trackChanges.updates.length == 0
2014-06-26 11:39:52 -04:00
2014-06-27 08:46:38 -04:00
@$scope.trackChanges.updates[0].selectedTo = true
2014-06-26 11:39:52 -04:00
2014-06-27 08:46:38 -04:00
indexOfLastUpdateNotByMe = 0
for update, i in @$scope.trackChanges.updates
if @_updateContainsUserId(update, @$scope.user.id)
break
indexOfLastUpdateNotByMe = i
2014-06-27 07:45:37 -04:00
2014-06-27 08:46:38 -04:00
@$scope.trackChanges.updates[indexOfLastUpdateNotByMe].selectedFrom = true
2014-06-27 07:45:37 -04:00
2014-06-26 11:39:52 -04:00
BATCH_SIZE: 4
fetchNextBatchOfUpdates: () ->
2014-06-26 11:39:52 -04:00
url = "/project/#{@ide.project_id}/updates?min_count=#{@BATCH_SIZE}"
if @$scope.trackChanges.nextBeforeTimestamp?
2014-06-26 11:39:52 -04:00
url += "&before=#{@$scope.trackChanges.nextBeforeTimestamp}"
@$scope.trackChanges.loading = true
2014-06-26 11:39:52 -04:00
@ide.$http
.get(url)
.success (data) =>
@_loadUpdates(data.updates)
@$scope.trackChanges.nextBeforeTimestamp = data.nextBeforeTimestamp
if !data.nextBeforeTimestamp?
@$scope.trackChanges.atEnd = true
@$scope.trackChanges.loading = false
2014-06-26 11:39:52 -04:00
2014-06-27 07:45:37 -04:00
reloadDiff: () ->
diff = @$scope.trackChanges.diff
{updates, doc} = @$scope.trackChanges.selection
{fromV, toV} = @_calculateRangeFromSelection()
console.log "Checking if diff has changed", doc?.id, fromV, toV, updates
2014-06-27 07:45:37 -04:00
return if !doc?
return if diff? and
diff.doc == doc and
diff.fromV == fromV and
diff.toV == toV
console.log "Loading diff", fromV, toV, doc?.id
@$scope.trackChanges.diff = diff = {
fromV: fromV
toV: toV
doc: doc
error: false
}
2014-06-27 12:11:26 -04:00
if !doc.deleted
diff.loading = true
url = "/project/#{@$scope.project_id}/doc/#{diff.doc.id}/diff"
if diff.fromV? and diff.toV?
url += "?from=#{diff.fromV}&to=#{diff.toV}"
@ide.$http
.get(url)
.success (data) =>
diff.loading = false
{text, highlights} = @_parseDiff(data)
2014-06-27 12:11:26 -04:00
diff.text = text
diff.highlights = highlights
2014-06-27 12:11:26 -04:00
.error () ->
diff.loading = false
diff.error = true
else
diff.deleted = true
console.log "DOC IS DELETED - NO DIFF FOR YOU!"
2014-06-27 07:45:37 -04:00
2014-06-27 12:11:26 -04:00
restoreDeletedDoc: (doc) ->
@ide.$http.post "/project/#{@$scope.project_id}/doc/#{doc.id}/restore", {
name: doc.name
_csrf: window.csrfToken
}
2014-06-27 07:45:37 -04:00
_parseDiff: (diff) ->
row = 0
column = 0
highlights = []
2014-06-27 07:45:37 -04:00
text = ""
for entry, i in diff.diff or []
content = entry.u or entry.i or entry.d
content ||= ""
text += content
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 = {
start:
row: startRow
column: startColumn
end:
row: endRow
column: endColumn
}
if entry.i? or entry.d?
if entry.meta.user?
name = "#{entry.meta.user.first_name} #{entry.meta.user.last_name}"
else
name = "Anonymous"
if entry.meta.user?.id == @$scope.user.id
name = "you"
date = moment(entry.meta.end_ts).format("Do MMM YYYY, h:mm a")
if entry.i?
highlights.push {
label: "Added by #{name} on #{date}"
highlight: range
hue: @ide.onlineUsersManager.getHueForUserId(entry.meta.user?.id)
}
else if entry.d?
highlights.push {
label: "Deleted by #{name} on #{date}"
strikeThrough: range
hue: @ide.onlineUsersManager.getHueForUserId(entry.meta.user?.id)
}
2014-06-27 07:45:37 -04:00
return {text, highlights}
2014-06-27 07:45:37 -04:00
2014-06-26 11:39:52 -04:00
_loadUpdates: (updates = []) ->
previousUpdate = @$scope.trackChanges.updates[@$scope.trackChanges.updates.length - 1]
for update in updates
for doc_id, doc of update.docs or {}
2014-06-27 12:11:26 -04:00
doc.entity = @ide.fileTreeManager.findEntityById(doc_id, includeDeleted: true)
2014-06-26 11:39:52 -04:00
for user in update.meta.users or []
user.hue = @ide.onlineUsersManager.getHueForUserId(user.id)
if !previousUpdate? or !moment(previousUpdate.meta.end_ts).isSame(update.meta.end_ts, "day")
update.meta.first_in_day = true
update.selectedFrom = false
update.selectedTo = false
update.inSelection = false
previousUpdate = update
firstLoad = @$scope.trackChanges.updates.length == 0
2014-06-26 11:39:52 -04:00
@$scope.trackChanges.updates =
@$scope.trackChanges.updates.concat(updates)
2014-06-27 07:45:37 -04:00
@autoSelectRecentUpdates() if firstLoad
2014-06-27 07:45:37 -04:00
_calculateRangeFromSelection: () ->
fromV = toV = start_ts = end_ts = null
selected_doc_id = @$scope.trackChanges.selection.doc?.id
for update in @$scope.trackChanges.selection.updates or []
for doc_id, doc of update.docs
if doc_id == selected_doc_id
if fromV? and toV?
fromV = Math.min(fromV, doc.fromV)
toV = Math.max(toV, doc.toV)
start_ts = Math.min(start_ts, update.meta.start_ts)
end_ts = Math.max(end_ts, update.meta.end_ts)
else
fromV = doc.fromV
toV = doc.toV
start_ts = update.meta.start_ts
end_ts = update.meta.end_ts
break
return {fromV, toV, start_ts, end_ts}
2014-06-27 08:46:38 -04:00
# Set the track changes selected doc to one of the docs in the range
# of currently selected updates. If we already have a selected doc
# then prefer this one if present.
_selectDocFromUpdates: () ->
affected_docs = {}
for update in @$scope.trackChanges.selection.updates
for doc_id, doc of update.docs
2014-06-27 12:11:26 -04:00
affected_docs[doc_id] = doc.entity
2014-06-27 08:46:38 -04:00
selected_doc = @$scope.trackChanges.selection.doc
2014-06-27 12:11:26 -04:00
if selected_doc? and affected_docs[selected_doc.id]?
2014-06-27 08:46:38 -04:00
console.log "An affected doc is already open, bravo!"
else
console.log "selected doc is not open, selecting first one"
for doc_id, doc of affected_docs
2014-06-27 12:11:26 -04:00
selected_doc = doc
2014-06-27 08:46:38 -04:00
break
2014-06-27 12:11:26 -04:00
@$scope.trackChanges.selection.doc = selected_doc
@ide.fileTreeManager.selectEntity(selected_doc)
2014-06-27 08:46:38 -04:00
_updateContainsUserId: (update, user_id) ->
for user in update.meta.users
return true if user.id == user_id
return false