2016-10-12 12:27:20 -04:00
|
|
|
define [
|
|
|
|
"base",
|
|
|
|
"utils/EventEmitter"
|
2016-11-09 11:23:08 -05:00
|
|
|
"ide/colors/ColorManager"
|
2016-12-08 09:10:30 -05:00
|
|
|
"ide/review-panel/RangesTracker"
|
|
|
|
], (App, EventEmitter, ColorManager, RangesTracker) ->
|
2017-04-03 12:11:33 -04:00
|
|
|
App.controller "ReviewPanelController", ($scope, $element, ide, $timeout, $http, $modal, event_tracking, localStorage) ->
|
2016-11-17 07:02:45 -05:00
|
|
|
$reviewPanelEl = $element.find "#review-panel"
|
|
|
|
|
2016-11-16 07:31:47 -05:00
|
|
|
$scope.SubViews =
|
|
|
|
CUR_FILE : "cur_file"
|
|
|
|
OVERVIEW : "overview"
|
|
|
|
|
2017-01-10 10:58:59 -05:00
|
|
|
$scope.reviewPanel =
|
2016-10-12 12:27:20 -04:00
|
|
|
entries: {}
|
2017-01-13 09:27:45 -05:00
|
|
|
resolvedComments: {}
|
2016-11-15 10:04:29 -05:00
|
|
|
hasEntries: false
|
2016-11-16 07:31:47 -05:00
|
|
|
subView: $scope.SubViews.CUR_FILE
|
2016-11-17 09:57:11 -05:00
|
|
|
openSubView: $scope.SubViews.CUR_FILE
|
2016-12-09 10:43:08 -05:00
|
|
|
overview:
|
|
|
|
loading: false
|
2017-02-21 09:43:05 -05:00
|
|
|
docsCollapsedState: JSON.parse(localStorage("docs_collapsed_state:#{$scope.project_id}")) or {}
|
2017-01-09 09:59:01 -05:00
|
|
|
dropdown:
|
|
|
|
loading: false
|
2016-12-16 11:42:41 -05:00
|
|
|
commentThreads: {}
|
2017-01-10 11:29:27 -05:00
|
|
|
resolvedThreadIds: {}
|
2017-01-13 08:52:08 -05:00
|
|
|
rendererData: {}
|
2017-01-17 10:55:18 -05:00
|
|
|
loadingThreads: false
|
2017-05-03 11:53:04 -04:00
|
|
|
selectedEntryIds: []
|
2017-01-12 11:49:47 -05:00
|
|
|
|
2017-02-21 09:20:51 -05:00
|
|
|
window.addEventListener "beforeunload", () ->
|
|
|
|
collapsedStates = {}
|
|
|
|
for doc, state of $scope.reviewPanel.overview.docsCollapsedState
|
2017-02-21 09:43:05 -05:00
|
|
|
if state
|
|
|
|
collapsedStates[doc] = state
|
2017-02-21 09:20:51 -05:00
|
|
|
valToStore = if Object.keys(collapsedStates).length > 0 then JSON.stringify(collapsedStates) else null
|
|
|
|
localStorage("docs_collapsed_state:#{$scope.project_id}", valToStore)
|
|
|
|
|
2017-01-12 11:49:47 -05:00
|
|
|
$scope.$on "layout:pdf:linked", (event, state) ->
|
2017-02-07 10:45:45 -05:00
|
|
|
$scope.$broadcast "review-panel:layout"
|
2017-01-12 11:49:47 -05:00
|
|
|
|
|
|
|
$scope.$on "layout:pdf:resize", (event, state) ->
|
2017-02-13 03:49:51 -05:00
|
|
|
$scope.$broadcast "review-panel:layout", false
|
2017-01-12 11:49:47 -05:00
|
|
|
|
2017-01-26 09:35:01 -05:00
|
|
|
$scope.$on "expandable-text-area:resize", (event) ->
|
|
|
|
$timeout () ->
|
|
|
|
$scope.$broadcast "review-panel:layout"
|
|
|
|
|
2017-02-20 06:56:26 -05:00
|
|
|
$scope.$on "review-panel:sizes", (e, sizes) ->
|
|
|
|
$scope.$broadcast "editor:set-scroll-size", sizes
|
2017-02-14 03:38:58 -05:00
|
|
|
|
|
|
|
$scope.$watch "project.features.trackChangesVisible", (visible) ->
|
|
|
|
return if !visible?
|
|
|
|
if !visible
|
|
|
|
$scope.ui.reviewPanelOpen = false
|
2016-11-15 10:04:29 -05:00
|
|
|
|
2016-11-09 09:50:58 -05:00
|
|
|
$scope.commentState =
|
|
|
|
adding: false
|
|
|
|
content: ""
|
2016-11-15 10:48:12 -05:00
|
|
|
|
2017-01-06 07:41:58 -05:00
|
|
|
$scope.users = {}
|
|
|
|
|
2016-11-17 05:40:08 -05:00
|
|
|
$scope.reviewPanelEventsBridge = new EventEmitter()
|
2016-12-16 11:42:41 -05:00
|
|
|
|
|
|
|
ide.socket.on "new-comment", (thread_id, comment) ->
|
2017-01-16 09:25:10 -05:00
|
|
|
thread = getThread(thread_id)
|
|
|
|
delete thread.submitting
|
|
|
|
thread.messages.push(formatComment(comment))
|
2016-12-16 11:42:41 -05:00
|
|
|
$scope.$apply()
|
|
|
|
$timeout () ->
|
|
|
|
$scope.$broadcast "review-panel:layout"
|
2017-01-09 09:54:12 -05:00
|
|
|
|
|
|
|
ide.socket.on "accept-change", (doc_id, change_id) ->
|
|
|
|
if doc_id != $scope.editor.open_doc_id
|
|
|
|
getChangeTracker(doc_id).removeChangeId(change_id)
|
|
|
|
else
|
|
|
|
$scope.$broadcast "change:accept", change_id
|
|
|
|
updateEntries(doc_id)
|
|
|
|
$scope.$apply () ->
|
2017-05-16 09:27:06 -04:00
|
|
|
|
|
|
|
ide.socket.on "accept-changes", (doc_id, change_ids) ->
|
|
|
|
if doc_id != $scope.editor.open_doc_id
|
|
|
|
getChangeTracker(doc_id).removeChangeIds(change_ids)
|
|
|
|
else
|
|
|
|
$scope.$broadcast "change:bulk-accept", change_ids
|
|
|
|
updateEntries(doc_id)
|
|
|
|
$scope.$apply () ->
|
2017-01-09 10:09:29 -05:00
|
|
|
|
|
|
|
ide.socket.on "resolve-thread", (thread_id, user) ->
|
|
|
|
_onCommentResolved(thread_id, user)
|
|
|
|
|
|
|
|
ide.socket.on "reopen-thread", (thread_id) ->
|
|
|
|
_onCommentReopened(thread_id)
|
2017-01-24 10:18:49 -05:00
|
|
|
|
2017-01-26 09:12:59 -05:00
|
|
|
ide.socket.on "delete-thread", (thread_id) ->
|
|
|
|
_onThreadDeleted(thread_id)
|
|
|
|
$scope.$apply () ->
|
|
|
|
|
2017-01-24 10:18:49 -05:00
|
|
|
ide.socket.on "edit-message", (thread_id, message_id, content) ->
|
|
|
|
_onCommentEdited(thread_id, message_id, content)
|
|
|
|
$scope.$apply () ->
|
|
|
|
|
|
|
|
ide.socket.on "delete-message", (thread_id, message_id) ->
|
|
|
|
_onCommentDeleted(thread_id, message_id)
|
|
|
|
$scope.$apply () ->
|
2016-11-17 05:40:08 -05:00
|
|
|
|
2016-12-08 09:10:30 -05:00
|
|
|
rangesTrackers = {}
|
2016-11-21 10:18:46 -05:00
|
|
|
|
2016-11-21 11:57:52 -05:00
|
|
|
getDocEntries = (doc_id) ->
|
|
|
|
$scope.reviewPanel.entries[doc_id] ?= {}
|
|
|
|
return $scope.reviewPanel.entries[doc_id]
|
|
|
|
|
2017-01-13 09:27:45 -05:00
|
|
|
getDocResolvedComments = (doc_id) ->
|
|
|
|
$scope.reviewPanel.resolvedComments[doc_id] ?= {}
|
|
|
|
return $scope.reviewPanel.resolvedComments[doc_id]
|
2017-01-16 09:25:10 -05:00
|
|
|
|
|
|
|
getThread = (thread_id) ->
|
|
|
|
$scope.reviewPanel.commentThreads[thread_id] ?= { messages: [] }
|
|
|
|
return $scope.reviewPanel.commentThreads[thread_id]
|
2017-01-13 09:27:45 -05:00
|
|
|
|
2016-11-21 11:57:52 -05:00
|
|
|
getChangeTracker = (doc_id) ->
|
2017-01-10 05:55:59 -05:00
|
|
|
if !rangesTrackers[doc_id]?
|
|
|
|
rangesTrackers[doc_id] = new RangesTracker()
|
2017-01-10 11:29:27 -05:00
|
|
|
rangesTrackers[doc_id].resolvedThreadIds = $scope.reviewPanel.resolvedThreadIds
|
2016-12-08 09:10:30 -05:00
|
|
|
return rangesTrackers[doc_id]
|
2016-11-21 11:57:52 -05:00
|
|
|
|
2016-11-17 09:29:35 -05:00
|
|
|
scrollbar = {}
|
2016-11-17 07:02:45 -05:00
|
|
|
$scope.reviewPanelEventsBridge.on "aceScrollbarVisibilityChanged", (isVisible, scrollbarWidth) ->
|
2016-11-17 09:29:35 -05:00
|
|
|
scrollbar = {isVisible, scrollbarWidth}
|
|
|
|
updateScrollbar()
|
2017-01-10 06:23:06 -05:00
|
|
|
|
2016-11-17 09:29:35 -05:00
|
|
|
updateScrollbar = () ->
|
|
|
|
if scrollbar.isVisible and $scope.reviewPanel.subView == $scope.SubViews.CUR_FILE
|
|
|
|
$reviewPanelEl.css "right", "#{ scrollbar.scrollbarWidth }px"
|
2016-11-17 07:02:45 -05:00
|
|
|
else
|
|
|
|
$reviewPanelEl.css "right", "0"
|
2017-01-09 09:30:29 -05:00
|
|
|
|
2017-05-11 05:17:25 -04:00
|
|
|
$scope.$watch "!ui.reviewPanelOpen && reviewPanel.hasEntries", (open, prevVal) ->
|
|
|
|
return if !open?
|
|
|
|
$scope.ui.miniReviewPanelVisible = open
|
|
|
|
if open != prevVal
|
|
|
|
$timeout () -> $scope.$broadcast "review-panel:toggle"
|
|
|
|
|
2016-11-17 09:57:11 -05:00
|
|
|
$scope.$watch "ui.reviewPanelOpen", (open) ->
|
|
|
|
return if !open?
|
|
|
|
if !open
|
|
|
|
# Always show current file when not open, but save current state
|
|
|
|
$scope.reviewPanel.openSubView = $scope.reviewPanel.subView
|
|
|
|
$scope.reviewPanel.subView = $scope.SubViews.CUR_FILE
|
|
|
|
else
|
|
|
|
# Reset back to what we had when previously open
|
|
|
|
$scope.reviewPanel.subView = $scope.reviewPanel.openSubView
|
2017-05-11 05:23:41 -04:00
|
|
|
$timeout () ->
|
|
|
|
$scope.$broadcast "review-panel:toggle"
|
|
|
|
$scope.$broadcast "review-panel:layout", false
|
|
|
|
|
2016-12-09 10:43:08 -05:00
|
|
|
$scope.$watch "reviewPanel.subView", (view) ->
|
|
|
|
return if !view?
|
2017-01-09 09:30:29 -05:00
|
|
|
updateScrollbar()
|
2016-12-09 10:43:08 -05:00
|
|
|
if view == $scope.SubViews.OVERVIEW
|
|
|
|
refreshOverviewPanel()
|
2016-11-15 10:48:12 -05:00
|
|
|
|
2017-01-09 04:49:03 -05:00
|
|
|
$scope.$watch "editor.sharejs_doc", (doc, old_doc) ->
|
2016-12-13 12:34:29 -05:00
|
|
|
return if !doc?
|
|
|
|
# The open doc range tracker is kept up to date in real-time so
|
|
|
|
# replace any outdated info with this
|
|
|
|
rangesTrackers[doc.doc_id] = doc.ranges
|
2017-01-10 11:29:27 -05:00
|
|
|
rangesTrackers[doc.doc_id].resolvedThreadIds = $scope.reviewPanel.resolvedThreadIds
|
2016-12-13 12:34:29 -05:00
|
|
|
$scope.reviewPanel.rangesTracker = rangesTrackers[doc.doc_id]
|
2017-01-09 04:49:03 -05:00
|
|
|
if old_doc?
|
|
|
|
old_doc.off "flipped_pending_to_inflight"
|
|
|
|
doc.on "flipped_pending_to_inflight", () ->
|
|
|
|
regenerateTrackChangesId(doc)
|
|
|
|
regenerateTrackChangesId(doc)
|
2016-11-15 10:48:12 -05:00
|
|
|
|
2016-11-16 12:17:50 -05:00
|
|
|
$scope.$watch (() ->
|
|
|
|
entries = $scope.reviewPanel.entries[$scope.editor.open_doc_id] or {}
|
2017-03-17 12:28:21 -04:00
|
|
|
permEntries = {}
|
|
|
|
for entry, entryData of entries
|
2017-05-02 10:43:45 -04:00
|
|
|
if entry not in [ "add-comment", "bulk-actions" ]
|
2017-03-20 09:56:36 -04:00
|
|
|
permEntries[entry] = entryData
|
2017-03-17 12:28:21 -04:00
|
|
|
Object.keys(permEntries).length
|
2016-11-16 12:17:50 -05:00
|
|
|
), (nEntries) ->
|
2017-02-13 08:39:43 -05:00
|
|
|
$scope.reviewPanel.hasEntries = nEntries > 0 and $scope.project.features.trackChangesVisible
|
2016-11-16 11:28:01 -05:00
|
|
|
|
2017-01-09 09:30:48 -05:00
|
|
|
regenerateTrackChangesId = (doc) ->
|
|
|
|
old_id = getChangeTracker(doc.doc_id).getIdSeed()
|
2017-01-10 05:55:59 -05:00
|
|
|
new_id = RangesTracker.generateIdSeed()
|
2017-01-09 04:49:03 -05:00
|
|
|
getChangeTracker(doc.doc_id).setIdSeed(new_id)
|
|
|
|
doc.setTrackChangesIdSeeds({pending: new_id, inflight: old_id})
|
|
|
|
|
2017-01-09 09:59:01 -05:00
|
|
|
refreshRanges = () ->
|
2016-12-09 10:43:08 -05:00
|
|
|
$http.get "/project/#{$scope.project_id}/ranges"
|
|
|
|
.success (docs) ->
|
|
|
|
for doc in docs
|
2017-02-16 10:48:58 -05:00
|
|
|
if !$scope.reviewPanel.overview.docsCollapsedState[doc.id]?
|
|
|
|
$scope.reviewPanel.overview.docsCollapsedState[doc.id] = false
|
2016-12-09 10:43:08 -05:00
|
|
|
if doc.id != $scope.editor.open_doc_id # this is kept up to date in real-time, don't overwrite
|
2017-01-09 09:54:12 -05:00
|
|
|
rangesTracker = getChangeTracker(doc.id)
|
|
|
|
rangesTracker.comments = doc.ranges?.comments or []
|
|
|
|
rangesTracker.changes = doc.ranges?.changes or []
|
2017-01-11 08:13:49 -05:00
|
|
|
updateEntries(doc.id)
|
2017-01-09 09:59:01 -05:00
|
|
|
|
|
|
|
refreshOverviewPanel = () ->
|
|
|
|
$scope.reviewPanel.overview.loading = true
|
|
|
|
refreshRanges()
|
|
|
|
.then () ->
|
2016-12-09 10:43:08 -05:00
|
|
|
$scope.reviewPanel.overview.loading = false
|
2017-01-09 09:59:01 -05:00
|
|
|
.catch () ->
|
2016-12-09 10:43:08 -05:00
|
|
|
$scope.reviewPanel.overview.loading = false
|
2017-01-09 09:59:01 -05:00
|
|
|
|
|
|
|
$scope.refreshResolvedCommentsDropdown = () ->
|
|
|
|
$scope.reviewPanel.dropdown.loading = true
|
2017-01-16 10:55:14 -05:00
|
|
|
q = refreshRanges()
|
|
|
|
q.then () ->
|
|
|
|
$scope.reviewPanel.dropdown.loading = false
|
|
|
|
q.catch () ->
|
|
|
|
$scope.reviewPanel.dropdown.loading = false
|
|
|
|
return q
|
2017-01-09 09:59:01 -05:00
|
|
|
|
2016-11-21 11:57:52 -05:00
|
|
|
updateEntries = (doc_id) ->
|
2016-12-08 09:10:30 -05:00
|
|
|
rangesTracker = getChangeTracker(doc_id)
|
2016-11-21 11:57:52 -05:00
|
|
|
entries = getDocEntries(doc_id)
|
2017-01-13 09:27:45 -05:00
|
|
|
resolvedComments = getDocResolvedComments(doc_id)
|
2016-11-21 11:57:52 -05:00
|
|
|
|
2017-01-11 08:13:49 -05:00
|
|
|
changed = false
|
|
|
|
|
2016-11-21 11:57:52 -05:00
|
|
|
# Assume we'll delete everything until we see it, then we'll remove it from this object
|
|
|
|
delete_changes = {}
|
2017-01-11 07:41:07 -05:00
|
|
|
for change_id, change of entries
|
|
|
|
if change_id != "add-comment"
|
|
|
|
delete_changes[change_id] = true
|
2017-01-13 09:27:45 -05:00
|
|
|
for change_id, change of resolvedComments
|
|
|
|
delete_changes[change_id] = true
|
2016-11-21 11:57:52 -05:00
|
|
|
|
2016-12-08 09:10:30 -05:00
|
|
|
for change in rangesTracker.changes
|
2017-01-11 08:13:49 -05:00
|
|
|
changed = true
|
2016-11-21 11:57:52 -05:00
|
|
|
delete delete_changes[change.id]
|
|
|
|
entries[change.id] ?= {}
|
|
|
|
|
|
|
|
# Update in place to avoid a full DOM redraw via angular
|
|
|
|
metadata = {}
|
|
|
|
metadata[key] = value for key, value of change.metadata
|
|
|
|
new_entry = {
|
|
|
|
type: if change.op.i then "insert" else "delete"
|
|
|
|
content: change.op.i or change.op.d
|
|
|
|
offset: change.op.p
|
|
|
|
metadata: change.metadata
|
|
|
|
}
|
|
|
|
for key, value of new_entry
|
|
|
|
entries[change.id][key] = value
|
|
|
|
|
2017-01-06 07:41:58 -05:00
|
|
|
if !$scope.users[change.metadata.user_id]?
|
|
|
|
refreshChangeUsers(change.metadata.user_id)
|
|
|
|
|
2017-01-17 09:04:49 -05:00
|
|
|
if rangesTracker.comments.length > 0
|
|
|
|
ensureThreadsAreLoaded()
|
|
|
|
|
2016-12-08 09:10:30 -05:00
|
|
|
for comment in rangesTracker.comments
|
2017-01-11 08:13:49 -05:00
|
|
|
changed = true
|
2016-11-21 11:57:52 -05:00
|
|
|
delete delete_changes[comment.id]
|
2017-01-13 09:27:45 -05:00
|
|
|
if $scope.reviewPanel.resolvedThreadIds[comment.op.t]
|
|
|
|
new_comment = resolvedComments[comment.id] ?= {}
|
2017-01-26 09:08:30 -05:00
|
|
|
delete entries[comment.id]
|
2017-01-13 09:27:45 -05:00
|
|
|
else
|
|
|
|
new_comment = entries[comment.id] ?= {}
|
2017-01-26 09:08:30 -05:00
|
|
|
delete resolvedComments[comment.id]
|
2016-11-21 11:57:52 -05:00
|
|
|
new_entry = {
|
|
|
|
type: "comment"
|
2016-12-16 11:42:41 -05:00
|
|
|
thread_id: comment.op.t
|
2016-12-13 12:57:46 -05:00
|
|
|
content: comment.op.c
|
|
|
|
offset: comment.op.p
|
2016-11-21 11:57:52 -05:00
|
|
|
}
|
|
|
|
for key, value of new_entry
|
2017-01-13 09:27:45 -05:00
|
|
|
new_comment[key] = value
|
2016-11-21 11:57:52 -05:00
|
|
|
|
|
|
|
for change_id, _ of delete_changes
|
2017-01-11 08:13:49 -05:00
|
|
|
changed = true
|
2016-11-21 11:57:52 -05:00
|
|
|
delete entries[change_id]
|
2017-01-13 09:27:45 -05:00
|
|
|
delete resolvedComments[change_id]
|
2017-01-11 08:13:49 -05:00
|
|
|
|
|
|
|
if changed
|
|
|
|
$scope.$broadcast "entries:changed"
|
2016-11-21 11:57:52 -05:00
|
|
|
|
|
|
|
$scope.$on "editor:track-changes:changed", () ->
|
|
|
|
doc_id = $scope.editor.open_doc_id
|
|
|
|
updateEntries(doc_id)
|
|
|
|
$scope.$broadcast "review-panel:recalculate-screen-positions"
|
|
|
|
$scope.$broadcast "review-panel:layout"
|
2017-02-20 10:03:02 -05:00
|
|
|
|
|
|
|
$scope.$on "editor:track-changes:visibility_changed", () ->
|
|
|
|
$timeout () ->
|
|
|
|
$scope.$broadcast "review-panel:layout", false
|
|
|
|
|
2017-01-13 08:17:47 -05:00
|
|
|
$scope.$on "editor:focus:changed", (e, selection_offset_start, selection_offset_end, selection) ->
|
2016-11-21 11:57:52 -05:00
|
|
|
doc_id = $scope.editor.open_doc_id
|
|
|
|
entries = getDocEntries(doc_id)
|
2017-05-03 11:53:04 -04:00
|
|
|
$scope.reviewPanel.selectedEntryIds = []
|
2016-11-21 11:57:52 -05:00
|
|
|
|
2017-01-13 08:17:47 -05:00
|
|
|
delete entries["add-comment"]
|
2017-05-02 10:43:45 -04:00
|
|
|
delete entries["bulk-actions"]
|
2017-05-02 10:34:05 -04:00
|
|
|
|
2017-01-13 08:17:47 -05:00
|
|
|
if selection
|
2017-03-28 11:50:30 -04:00
|
|
|
entries["add-comment"] = {
|
|
|
|
type: "add-comment"
|
|
|
|
offset: selection_offset_start
|
|
|
|
length: selection_offset_end - selection_offset_start
|
|
|
|
}
|
2017-05-02 10:43:45 -04:00
|
|
|
entries["bulk-actions"] = {
|
|
|
|
type: "bulk-actions"
|
2017-05-02 10:34:05 -04:00
|
|
|
offset: selection_offset_start
|
|
|
|
length: selection_offset_end - selection_offset_start
|
|
|
|
}
|
2016-11-21 11:57:52 -05:00
|
|
|
|
|
|
|
for id, entry of entries
|
2017-01-13 08:17:47 -05:00
|
|
|
if entry.type == "comment" and not $scope.reviewPanel.resolvedThreadIds[entry.thread_id]
|
|
|
|
entry.focused = (entry.offset <= selection_offset_start <= entry.offset + entry.content.length)
|
2016-11-21 11:57:52 -05:00
|
|
|
else if entry.type == "insert"
|
2017-05-02 12:02:30 -04:00
|
|
|
isEntryWithinSelection = entry.offset >= selection_offset_start and entry.offset + entry.content.length <= selection_offset_end
|
2017-01-13 08:17:47 -05:00
|
|
|
entry.focused = (entry.offset <= selection_offset_start <= entry.offset + entry.content.length)
|
2017-05-03 11:53:04 -04:00
|
|
|
$scope.reviewPanel.selectedEntryIds.push id if isEntryWithinSelection
|
2016-11-21 11:57:52 -05:00
|
|
|
else if entry.type == "delete"
|
2017-05-02 12:08:41 -04:00
|
|
|
isEntryWithinSelection = selection_offset_start <= entry.offset <= selection_offset_end
|
2017-01-13 08:17:47 -05:00
|
|
|
entry.focused = (entry.offset == selection_offset_start)
|
2017-05-03 11:53:04 -04:00
|
|
|
$scope.reviewPanel.selectedEntryIds.push id if isEntryWithinSelection
|
2017-05-02 10:43:45 -04:00
|
|
|
else if entry.type in [ "add-comment", "bulk-actions" ] and selection
|
2016-11-21 11:57:52 -05:00
|
|
|
entry.focused = true
|
|
|
|
|
|
|
|
$scope.$broadcast "review-panel:recalculate-screen-positions"
|
|
|
|
$scope.$broadcast "review-panel:layout"
|
2017-01-09 09:25:27 -05:00
|
|
|
|
2016-11-10 05:52:09 -05:00
|
|
|
$scope.acceptChange = (entry_id) ->
|
2017-01-09 09:25:27 -05:00
|
|
|
$http.post "/project/#{$scope.project_id}/doc/#{$scope.editor.open_doc_id}/changes/#{entry_id}/accept", {_csrf: window.csrfToken}
|
2016-11-10 05:52:09 -05:00
|
|
|
$scope.$broadcast "change:accept", entry_id
|
2017-01-17 09:39:31 -05:00
|
|
|
event_tracking.sendMB "rp-change-accepted", { view: if $scope.ui.reviewPanelOpen then $scope.reviewPanel.subView else 'mini' }
|
2016-11-10 05:52:09 -05:00
|
|
|
|
|
|
|
$scope.rejectChange = (entry_id) ->
|
|
|
|
$scope.$broadcast "change:reject", entry_id
|
2017-01-17 09:39:31 -05:00
|
|
|
event_tracking.sendMB "rp-change-rejected", { view: if $scope.ui.reviewPanelOpen then $scope.reviewPanel.subView else 'mini' }
|
2016-11-10 05:52:09 -05:00
|
|
|
|
2017-05-09 11:06:34 -04:00
|
|
|
bulkAccept = () ->
|
2017-05-04 10:33:47 -04:00
|
|
|
entry_ids = $scope.reviewPanel.selectedEntryIds.slice()
|
|
|
|
$http.post "/project/#{$scope.project_id}/doc/#{$scope.editor.open_doc_id}/changes/accept", { change_ids: entry_ids, _csrf: window.csrfToken}
|
|
|
|
$scope.$broadcast "change:bulk-accept", entry_ids
|
2017-05-03 12:16:29 -04:00
|
|
|
$scope.reviewPanel.selectedEntryIds = []
|
|
|
|
event_tracking.sendMB "rp-bulk-accept", {
|
|
|
|
view: if $scope.ui.reviewPanelOpen then $scope.reviewPanel.subView else 'mini',
|
|
|
|
nEntries: $scope.reviewPanel.selectedEntryIds.length
|
|
|
|
}
|
2017-05-03 11:53:04 -04:00
|
|
|
|
2017-05-09 11:06:34 -04:00
|
|
|
bulkReject = () ->
|
2017-05-03 12:16:29 -04:00
|
|
|
$scope.$broadcast "change:bulk-reject", $scope.reviewPanel.selectedEntryIds.slice()
|
|
|
|
$scope.reviewPanel.selectedEntryIds = []
|
|
|
|
event_tracking.sendMB "rp-bulk-reject", {
|
|
|
|
view: if $scope.ui.reviewPanelOpen then $scope.reviewPanel.subView else 'mini',
|
|
|
|
nEntries: $scope.reviewPanel.selectedEntryIds.length
|
|
|
|
}
|
2017-05-03 11:53:04 -04:00
|
|
|
|
2017-05-09 11:06:34 -04:00
|
|
|
$scope.showBulkAcceptDialog = () ->
|
|
|
|
showBulkActionsDialog true
|
|
|
|
|
|
|
|
$scope.showBulkRejectDialog = () -> showBulkActionsDialog false
|
|
|
|
|
|
|
|
showBulkActionsDialog = (isAccept) ->
|
|
|
|
$modal.open({
|
|
|
|
templateUrl: "bulkActionsModalTemplate"
|
|
|
|
controller: "BulkActionsModalController"
|
|
|
|
resolve:
|
|
|
|
isAccept: () -> isAccept
|
|
|
|
nChanges: () -> $scope.reviewPanel.selectedEntryIds.length
|
|
|
|
scope: $scope.$new()
|
|
|
|
}).result.then (isAccept) ->
|
|
|
|
if isAccept
|
|
|
|
bulkAccept()
|
|
|
|
else
|
|
|
|
bulkReject()
|
|
|
|
|
2017-03-20 07:18:29 -04:00
|
|
|
$scope.addNewComment = () ->
|
|
|
|
$scope.$broadcast "comment:start_adding"
|
|
|
|
$scope.toggleReviewPanel()
|
|
|
|
|
2017-05-19 10:28:49 -04:00
|
|
|
$scope.addNewCommentFromKbdShortcut = () ->
|
|
|
|
$scope.$broadcast "comment:start_adding"
|
|
|
|
if !$scope.ui.reviewPanelOpen
|
|
|
|
$scope.toggleReviewPanel()
|
|
|
|
|
2016-11-09 10:25:41 -05:00
|
|
|
$scope.startNewComment = () ->
|
2016-11-09 09:50:58 -05:00
|
|
|
$scope.$broadcast "comment:select_line"
|
2016-11-16 11:03:06 -05:00
|
|
|
$timeout () ->
|
|
|
|
$scope.$broadcast "review-panel:layout"
|
2017-03-23 11:00:43 -04:00
|
|
|
|
2016-11-16 10:47:05 -05:00
|
|
|
$scope.submitNewComment = (content) ->
|
2017-02-14 07:41:04 -05:00
|
|
|
return if !content? or content == ""
|
|
|
|
doc_id = $scope.editor.open_doc_id
|
|
|
|
entries = getDocEntries(doc_id)
|
|
|
|
return if !entries["add-comment"]?
|
|
|
|
{offset, length} = entries["add-comment"]
|
2017-01-10 05:55:59 -05:00
|
|
|
thread_id = RangesTracker.generateId()
|
2017-01-16 09:25:10 -05:00
|
|
|
thread = getThread(thread_id)
|
|
|
|
thread.submitting = true
|
2017-02-14 07:41:04 -05:00
|
|
|
$scope.$broadcast "comment:add", thread_id, offset, length
|
2016-12-16 11:42:41 -05:00
|
|
|
$http.post("/project/#{$scope.project_id}/thread/#{thread_id}/messages", {content, _csrf: window.csrfToken})
|
|
|
|
.error (error) ->
|
|
|
|
ide.showGenericMessageModal("Error submitting comment", "Sorry, there was a problem submitting your comment")
|
2017-02-03 08:17:09 -05:00
|
|
|
$scope.$broadcast "editor:clearSelection"
|
2016-11-16 11:03:06 -05:00
|
|
|
$timeout () ->
|
|
|
|
$scope.$broadcast "review-panel:layout"
|
2017-01-17 09:39:31 -05:00
|
|
|
event_tracking.sendMB "rp-new-comment", { size: content.length }
|
|
|
|
|
2016-11-09 10:51:40 -05:00
|
|
|
$scope.cancelNewComment = (entry) ->
|
2016-11-16 11:03:06 -05:00
|
|
|
$timeout () ->
|
|
|
|
$scope.$broadcast "review-panel:layout"
|
2016-11-09 10:51:40 -05:00
|
|
|
|
2016-11-09 10:25:41 -05:00
|
|
|
$scope.startReply = (entry) ->
|
|
|
|
entry.replying = true
|
2016-11-16 11:03:06 -05:00
|
|
|
$timeout () ->
|
|
|
|
$scope.$broadcast "review-panel:layout"
|
2016-11-11 05:51:32 -05:00
|
|
|
|
2017-01-11 05:53:46 -05:00
|
|
|
$scope.submitReply = (entry, entry_id) ->
|
2016-12-16 11:42:41 -05:00
|
|
|
thread_id = entry.thread_id
|
|
|
|
content = entry.replyContent
|
|
|
|
$http.post("/project/#{$scope.project_id}/thread/#{thread_id}/messages", {content, _csrf: window.csrfToken})
|
|
|
|
.error (error) ->
|
|
|
|
ide.showGenericMessageModal("Error submitting comment", "Sorry, there was a problem submitting your comment")
|
2017-01-17 09:39:31 -05:00
|
|
|
|
|
|
|
trackingMetadata =
|
|
|
|
view: if $scope.ui.reviewPanelOpen then $scope.reviewPanel.subView else 'mini'
|
|
|
|
size: entry.replyContent.length
|
|
|
|
thread: thread_id
|
2016-11-11 11:10:26 -05:00
|
|
|
|
2017-01-16 09:25:10 -05:00
|
|
|
thread = getThread(thread_id)
|
|
|
|
thread.submitting = true
|
2016-11-11 11:10:26 -05:00
|
|
|
entry.replyContent = ""
|
|
|
|
entry.replying = false
|
2016-11-14 06:47:36 -05:00
|
|
|
$timeout () ->
|
|
|
|
$scope.$broadcast "review-panel:layout"
|
2017-01-17 09:39:31 -05:00
|
|
|
event_tracking.sendMB "rp-comment-reply", trackingMetadata
|
2016-12-16 11:42:41 -05:00
|
|
|
|
2016-11-09 10:51:40 -05:00
|
|
|
$scope.cancelReply = (entry) ->
|
|
|
|
entry.replying = false
|
|
|
|
entry.replyContent = ""
|
2016-11-09 11:23:08 -05:00
|
|
|
$scope.$broadcast "review-panel:layout"
|
2016-11-17 13:06:08 -05:00
|
|
|
|
|
|
|
$scope.resolveComment = (entry, entry_id) ->
|
2016-11-21 06:16:23 -05:00
|
|
|
entry.focused = false
|
2017-01-09 10:09:29 -05:00
|
|
|
$http.post "/project/#{$scope.project_id}/thread/#{entry.thread_id}/resolve", {_csrf: window.csrfToken}
|
|
|
|
_onCommentResolved(entry.thread_id, ide.$scope.user)
|
2017-01-17 09:39:31 -05:00
|
|
|
event_tracking.sendMB "rp-comment-resolve", { view: if $scope.ui.reviewPanelOpen then $scope.reviewPanel.subView else 'mini' }
|
2017-01-09 10:09:29 -05:00
|
|
|
|
2017-01-09 12:22:01 -05:00
|
|
|
$scope.unresolveComment = (thread_id) ->
|
|
|
|
_onCommentReopened(thread_id)
|
|
|
|
$http.post "/project/#{$scope.project_id}/thread/#{thread_id}/reopen", {_csrf: window.csrfToken}
|
2017-01-17 09:39:31 -05:00
|
|
|
event_tracking.sendMB "rp-comment-reopen"
|
2017-01-09 10:09:29 -05:00
|
|
|
|
|
|
|
_onCommentResolved = (thread_id, user) ->
|
2017-01-24 10:18:49 -05:00
|
|
|
thread = getThread(thread_id)
|
|
|
|
return if !thread?
|
2017-01-04 10:26:02 -05:00
|
|
|
thread.resolved = true
|
2017-01-09 10:09:29 -05:00
|
|
|
thread.resolved_by_user = formatUser(user)
|
2017-03-31 09:29:28 -04:00
|
|
|
thread.resolved_at = new Date().toISOString()
|
2017-01-10 11:29:27 -05:00
|
|
|
$scope.reviewPanel.resolvedThreadIds[thread_id] = true
|
2017-01-26 09:08:30 -05:00
|
|
|
$scope.$broadcast "comment:resolve_threads", [thread_id]
|
2016-11-17 13:06:08 -05:00
|
|
|
|
2017-01-09 10:09:29 -05:00
|
|
|
_onCommentReopened = (thread_id) ->
|
2017-01-24 10:18:49 -05:00
|
|
|
thread = getThread(thread_id)
|
|
|
|
return if !thread?
|
2017-01-04 10:26:02 -05:00
|
|
|
delete thread.resolved
|
|
|
|
delete thread.resolved_by_user
|
|
|
|
delete thread.resolved_at
|
2017-01-10 11:29:27 -05:00
|
|
|
delete $scope.reviewPanel.resolvedThreadIds[thread_id]
|
2017-01-09 10:09:29 -05:00
|
|
|
$scope.$broadcast "comment:unresolve_thread", thread_id
|
2017-01-10 06:23:06 -05:00
|
|
|
|
2017-01-24 10:18:49 -05:00
|
|
|
_onThreadDeleted = (thread_id) ->
|
|
|
|
delete $scope.reviewPanel.resolvedThreadIds[thread_id]
|
2017-01-10 06:23:06 -05:00
|
|
|
delete $scope.reviewPanel.commentThreads[thread_id]
|
2017-01-26 09:12:59 -05:00
|
|
|
$scope.$broadcast "comment:remove", thread_id
|
2016-11-09 11:23:08 -05:00
|
|
|
|
2017-01-24 10:18:49 -05:00
|
|
|
_onCommentEdited = (thread_id, comment_id, content) ->
|
|
|
|
thread = getThread(thread_id)
|
|
|
|
return if !thread?
|
|
|
|
for message in thread.messages
|
|
|
|
if message.id == comment_id
|
|
|
|
message.content = content
|
|
|
|
updateEntries()
|
|
|
|
|
|
|
|
_onCommentDeleted = (thread_id, comment_id) ->
|
|
|
|
thread = getThread(thread_id)
|
|
|
|
return if !thread?
|
|
|
|
thread.messages = thread.messages.filter (m) -> m.id != comment_id
|
|
|
|
updateEntries()
|
|
|
|
|
|
|
|
$scope.deleteThread = (entry_id, doc_id, thread_id) ->
|
|
|
|
_onThreadDeleted(thread_id)
|
|
|
|
$http({
|
|
|
|
method: "DELETE"
|
|
|
|
url: "/project/#{$scope.project_id}/doc/#{doc_id}/thread/#{thread_id}",
|
|
|
|
headers: {
|
|
|
|
'X-CSRF-Token': window.csrfToken
|
|
|
|
}
|
|
|
|
})
|
2017-01-17 09:39:31 -05:00
|
|
|
event_tracking.sendMB "rp-comment-delete"
|
2017-01-24 10:18:49 -05:00
|
|
|
|
|
|
|
$scope.saveEdit = (thread_id, comment) ->
|
|
|
|
$http.post("/project/#{$scope.project_id}/thread/#{thread_id}/messages/#{comment.id}/edit", {
|
|
|
|
content: comment.content
|
|
|
|
_csrf: window.csrfToken
|
|
|
|
})
|
|
|
|
$timeout () ->
|
|
|
|
$scope.$broadcast "review-panel:layout"
|
|
|
|
|
|
|
|
$scope.deleteComment = (thread_id, comment) ->
|
|
|
|
_onCommentDeleted(thread_id, comment.id)
|
|
|
|
$http({
|
|
|
|
method: "DELETE"
|
|
|
|
url: "/project/#{$scope.project_id}/thread/#{thread_id}/messages/#{comment.id}",
|
|
|
|
headers: {
|
|
|
|
'X-CSRF-Token': window.csrfToken
|
|
|
|
}
|
|
|
|
})
|
|
|
|
$timeout () ->
|
|
|
|
$scope.$broadcast "review-panel:layout"
|
2016-11-17 13:06:08 -05:00
|
|
|
|
2016-11-16 07:31:47 -05:00
|
|
|
$scope.setSubView = (subView) ->
|
|
|
|
$scope.reviewPanel.subView = subView
|
2017-01-17 09:39:31 -05:00
|
|
|
event_tracking.sendMB "rp-subview-change", { subView }
|
2016-11-18 10:08:16 -05:00
|
|
|
|
2016-11-17 10:55:18 -05:00
|
|
|
$scope.gotoEntry = (doc_id, entry) ->
|
2016-11-22 11:34:39 -05:00
|
|
|
ide.editorManager.openDocId(doc_id, { gotoOffset: entry.offset })
|
2017-01-10 10:11:12 -05:00
|
|
|
|
|
|
|
$scope.toggleTrackChanges = (value) ->
|
2017-02-03 08:36:11 -05:00
|
|
|
if $scope.project.features.trackChanges
|
2017-02-02 07:12:14 -05:00
|
|
|
$scope.editor.wantTrackChanges = value
|
|
|
|
$http.post "/project/#{$scope.project_id}/track_changes", {_csrf: window.csrfToken, on: value}
|
|
|
|
event_tracking.sendMB "rp-trackchanges-toggle", { value }
|
|
|
|
else
|
2017-02-01 11:52:18 -05:00
|
|
|
$scope.openTrackChangesUpgradeModal()
|
2017-05-19 10:28:49 -04:00
|
|
|
|
|
|
|
$scope.toggleTrackChangesFromKbdShortcut = () ->
|
|
|
|
if $scope.editor.wantTrackChanges
|
|
|
|
$scope.toggleTrackChanges false
|
|
|
|
else
|
|
|
|
$scope.toggleTrackChanges true
|
2017-01-10 10:11:12 -05:00
|
|
|
|
|
|
|
ide.socket.on "toggle-track-changes", (value) ->
|
|
|
|
$scope.$apply () ->
|
|
|
|
$scope.editor.wantTrackChanges = value
|
2016-11-17 10:55:18 -05:00
|
|
|
|
2017-01-06 07:41:58 -05:00
|
|
|
_refreshingRangeUsers = false
|
|
|
|
_refreshedForUserIds = {}
|
|
|
|
refreshChangeUsers = (refresh_for_user_id) ->
|
|
|
|
if refresh_for_user_id?
|
|
|
|
if _refreshedForUserIds[refresh_for_user_id]?
|
|
|
|
# We've already tried to refresh to get this user id, so stop it looping
|
|
|
|
return
|
|
|
|
_refreshedForUserIds[refresh_for_user_id] = true
|
|
|
|
|
|
|
|
# Only do one refresh at once
|
|
|
|
if _refreshingRangeUsers
|
|
|
|
return
|
|
|
|
_refreshingRangeUsers = true
|
|
|
|
|
2017-01-10 07:43:53 -05:00
|
|
|
$http.get "/project/#{$scope.project_id}/changes/users"
|
2017-01-06 07:41:58 -05:00
|
|
|
.success (users) ->
|
|
|
|
_refreshingRangeUsers = false
|
|
|
|
$scope.users = {}
|
2017-01-12 07:29:57 -05:00
|
|
|
# Always include ourself, since if we submit an op, we might need to display info
|
|
|
|
# about it locally before it has been flushed through the server
|
|
|
|
if ide.$scope.user?.id?
|
|
|
|
$scope.users[ide.$scope.user.id] = formatUser(ide.$scope.user)
|
2017-01-06 07:41:58 -05:00
|
|
|
for user in users
|
2017-01-12 07:29:57 -05:00
|
|
|
if user.id?
|
|
|
|
$scope.users[user.id] = formatUser(user)
|
2017-01-06 07:41:58 -05:00
|
|
|
.error () ->
|
|
|
|
_refreshingRangeUsers = false
|
|
|
|
|
2017-01-17 09:04:49 -05:00
|
|
|
_threadsLoaded = false
|
|
|
|
ensureThreadsAreLoaded = () ->
|
|
|
|
if _threadsLoaded
|
|
|
|
# We get any updates in real time so only need to load them once.
|
|
|
|
return
|
|
|
|
_threadsLoaded = true
|
2017-01-17 10:55:18 -05:00
|
|
|
$scope.reviewPanel.loadingThreads = true
|
2017-01-06 07:41:58 -05:00
|
|
|
$http.get "/project/#{$scope.project_id}/threads"
|
|
|
|
.success (threads) ->
|
2017-01-17 10:55:18 -05:00
|
|
|
$scope.reviewPanel.loadingThreads = false
|
2017-01-10 11:29:27 -05:00
|
|
|
for thread_id, _ of $scope.reviewPanel.resolvedThreadIds
|
|
|
|
delete $scope.reviewPanel.resolvedThreadIds[thread_id]
|
2017-01-06 07:41:58 -05:00
|
|
|
for thread_id, thread of threads
|
|
|
|
for comment in thread.messages
|
|
|
|
formatComment(comment)
|
|
|
|
if thread.resolved_by_user?
|
2017-01-06 10:24:33 -05:00
|
|
|
thread.resolved_by_user = formatUser(thread.resolved_by_user)
|
2017-01-10 11:29:27 -05:00
|
|
|
$scope.reviewPanel.resolvedThreadIds[thread_id] = true
|
2017-01-26 09:08:30 -05:00
|
|
|
$scope.$broadcast "comment:resolve_threads", [thread_id]
|
2017-01-06 07:41:58 -05:00
|
|
|
$scope.reviewPanel.commentThreads = threads
|
2017-01-17 09:10:44 -05:00
|
|
|
$timeout () ->
|
|
|
|
$scope.$broadcast "review-panel:layout"
|
2017-01-06 07:41:58 -05:00
|
|
|
|
2016-12-16 11:42:41 -05:00
|
|
|
formatComment = (comment) ->
|
2017-01-12 06:05:35 -05:00
|
|
|
comment.user = formatUser(comment.user)
|
2016-12-16 11:42:41 -05:00
|
|
|
comment.timestamp = new Date(comment.timestamp)
|
|
|
|
return comment
|
2016-11-11 11:10:26 -05:00
|
|
|
|
2016-12-16 11:42:41 -05:00
|
|
|
formatUser = (user) ->
|
2017-01-12 06:31:01 -05:00
|
|
|
id = user?._id or user?.id
|
|
|
|
|
|
|
|
if !id?
|
2016-12-16 11:42:41 -05:00
|
|
|
return {
|
|
|
|
email: null
|
|
|
|
name: "Anonymous"
|
|
|
|
isSelf: false
|
|
|
|
hue: ColorManager.ANONYMOUS_HUE
|
|
|
|
avatar_text: "A"
|
2016-11-09 11:23:08 -05:00
|
|
|
}
|
2016-12-16 11:42:41 -05:00
|
|
|
if id == window.user_id
|
|
|
|
name = "You"
|
|
|
|
isSelf = true
|
|
|
|
else
|
2017-01-17 09:10:44 -05:00
|
|
|
name = [user.first_name, user.last_name].filter((n) -> n? and n != "").join(" ")
|
2017-01-12 06:31:01 -05:00
|
|
|
if name == ""
|
2017-01-17 09:10:44 -05:00
|
|
|
name = user.email?.split("@")[0] or "Unknown"
|
2016-12-16 11:42:41 -05:00
|
|
|
isSelf = false
|
|
|
|
return {
|
|
|
|
id: id
|
|
|
|
email: user.email
|
|
|
|
name: name
|
|
|
|
isSelf: isSelf
|
|
|
|
hue: ColorManager.getHueForUserId(id)
|
|
|
|
avatar_text: [user.first_name, user.last_name].filter((n) -> n?).map((n) -> n[0]).join ""
|
|
|
|
}
|
2017-02-01 11:52:18 -05:00
|
|
|
|
|
|
|
$scope.openTrackChangesUpgradeModal = () ->
|
|
|
|
$modal.open {
|
|
|
|
templateUrl: "trackChangesUpgradeModalTemplate"
|
|
|
|
controller: "TrackChangesUpgradeModalController"
|
|
|
|
scope: $scope.$new()
|
|
|
|
}
|