| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253 |
- define [
- "ide/track-changes/controllers/TrackChangesListController"
- "ide/track-changes/controllers/TrackChangesDiffController"
- "ide/track-changes/directives/infiniteScroll"
- ], () ->
- class TrackChangesManager
- constructor: (@ide, @$scope) ->
- @reset()
- @$scope.toggleTrackChanges = () =>
- if @$scope.ui.view == "track-changes"
- @hide()
- else
- @show()
- @$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"
- @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()
- reset: () ->
- @$scope.trackChanges = {
- updates: []
- nextBeforeTimestamp: null
- atEnd: false
- selection: {
- updates: []
- doc: null
- range: {
- fromV: null
- toV: null
- start_ts: null
- end_ts: null
- }
- }
- diff: null
- }
- autoSelectRecentUpdates: () ->
- return if @$scope.trackChanges.updates.length == 0
- @$scope.trackChanges.updates[0].selectedTo = true
- indexOfLastUpdateNotByMe = 0
- for update, i in @$scope.trackChanges.updates
- if @_updateContainsUserId(update, @$scope.user.id)
- break
- indexOfLastUpdateNotByMe = i
- @$scope.trackChanges.updates[indexOfLastUpdateNotByMe].selectedFrom = true
- BATCH_SIZE: 10
- fetchNextBatchOfUpdates: () ->
- url = "/project/#{@ide.project_id}/updates?min_count=#{@BATCH_SIZE}"
- if @$scope.trackChanges.nextBeforeTimestamp?
- url += "&before=#{@$scope.trackChanges.nextBeforeTimestamp}"
- @$scope.trackChanges.loading = true
- @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
- reloadDiff: () ->
- diff = @$scope.trackChanges.diff
- {updates, doc} = @$scope.trackChanges.selection
- {fromV, toV, start_ts, end_ts} = @_calculateRangeFromSelection()
- return if !doc?
- return if diff? and
- diff.doc == doc and
- diff.fromV == fromV and
- diff.toV == toV
- @$scope.trackChanges.diff = diff = {
- fromV: fromV
- toV: toV
- start_ts: start_ts
- end_ts: end_ts
- doc: doc
- error: false
- }
- 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)
- diff.text = text
- diff.highlights = highlights
- .error () ->
- diff.loading = false
- diff.error = true
- else
- diff.deleted = true
- restoreDeletedDoc: (doc) ->
- url = "/project/#{@$scope.project_id}/doc/#{doc.id}/restore"
- @ide.$http.post(url, name: doc.name, _csrf: window.csrfToken)
- restoreDiff: (diff) ->
- url = "/project/#{@$scope.project_id}/doc/#{diff.doc.id}/version/#{diff.fromV}/restore"
- @ide.$http.post(url, _csrf: window.csrfToken)
- _parseDiff: (diff) ->
- row = 0
- column = 0
- highlights = []
- 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)
- }
- return {text, highlights}
- _loadUpdates: (updates = []) ->
- previousUpdate = @$scope.trackChanges.updates[@$scope.trackChanges.updates.length - 1]
- for update in updates
- for doc_id, doc of update.docs or {}
- doc.entity = @ide.fileTreeManager.findEntityById(doc_id, includeDeleted: true)
- 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
- @$scope.trackChanges.updates =
- @$scope.trackChanges.updates.concat(updates)
- @autoSelectRecentUpdates() if firstLoad
- _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}
- # 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
- affected_docs[doc_id] = doc.entity
- selected_doc = @$scope.trackChanges.selection.doc
- if selected_doc? and affected_docs[selected_doc.id]?
- # Selected doc is already open
- else
- for doc_id, doc of affected_docs
- selected_doc = doc
- break
- @$scope.trackChanges.selection.doc = selected_doc
- @ide.fileTreeManager.selectEntity(selected_doc)
- _updateContainsUserId: (update, user_id) ->
- for user in update.meta.users
- return true if user.id == user_id
- return false
|