EditorManager.coffee 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. define [
  2. "ide/editor/Document"
  3. "ide/editor/directives/aceEditor"
  4. "ide/editor/controllers/SavingNotificationController"
  5. ], (Document) ->
  6. class EditorManager
  7. constructor: (@ide, @$scope) ->
  8. @$scope.editor = {
  9. sharejs_doc: null
  10. open_doc_id: null
  11. open_doc_name: null
  12. opening: true
  13. trackChanges: false
  14. wantTrackChanges: false
  15. }
  16. @$scope.$on "entity:selected", (event, entity) =>
  17. if (@$scope.ui.view != "history" and entity.type == "doc")
  18. @openDoc(entity)
  19. @$scope.$on "entity:deleted", (event, entity) =>
  20. if @$scope.editor.open_doc_id == entity.id
  21. return if !@$scope.project.rootDoc_id
  22. doc = @ide.fileTreeManager.findEntityById(@$scope.project.rootDoc_id)
  23. return if !doc?
  24. @openDoc(doc)
  25. initialized = false
  26. @$scope.$on "file-tree:initialized", () =>
  27. if !initialized
  28. initialized = true
  29. @autoOpenDoc()
  30. @$scope.$on "flush-changes", () =>
  31. Document.flushAll()
  32. @$scope.$watch "editor.wantTrackChanges", (value) =>
  33. return if !value?
  34. @_syncTrackChangesState(@$scope.editor.sharejs_doc)
  35. @$scope.$watch "project.features.trackChanges", (trackChangesFeature) =>
  36. return if !trackChangesFeature?
  37. @$scope.editor.wantTrackChanges = window.trackChangesEnabled and trackChangesFeature
  38. autoOpenDoc: () ->
  39. open_doc_id =
  40. @ide.localStorage("doc.open_id.#{@$scope.project_id}") or
  41. @$scope.project.rootDoc_id
  42. return if !open_doc_id?
  43. doc = @ide.fileTreeManager.findEntityById(open_doc_id)
  44. return if !doc?
  45. @openDoc(doc)
  46. openDocId: (doc_id, options = {}) ->
  47. doc = @ide.fileTreeManager.findEntityById(doc_id)
  48. return if !doc?
  49. @openDoc(doc, options)
  50. openDoc: (doc, options = {}) ->
  51. sl_console.log "[openDoc] Opening #{doc.id}"
  52. @$scope.ui.view = "editor"
  53. done = () =>
  54. if options.gotoLine?
  55. # allow Ace to display document before moving, delay until next tick
  56. # added delay to make this happen later that gotoStoredPosition in
  57. # CursorPositionManager
  58. setTimeout () =>
  59. @$scope.$broadcast "editor:gotoLine", options.gotoLine, options.gotoColumn
  60. , 0
  61. else if options.gotoOffset?
  62. setTimeout () =>
  63. @$scope.$broadcast "editor:gotoOffset", options.gotoOffset
  64. , 0
  65. if doc.id == @$scope.editor.open_doc_id and !options.forceReopen
  66. @$scope.$apply () =>
  67. done()
  68. return
  69. @$scope.editor.open_doc_id = doc.id
  70. @$scope.editor.open_doc_name = doc.name
  71. @ide.localStorage "doc.open_id.#{@$scope.project_id}", doc.id
  72. @ide.fileTreeManager.selectEntity(doc)
  73. @$scope.editor.opening = true
  74. @_openNewDocument doc, (error, sharejs_doc) =>
  75. if error?
  76. @ide.showGenericMessageModal(
  77. "Error opening document"
  78. "Sorry, something went wrong opening this document. Please try again."
  79. )
  80. return
  81. @_syncTrackChangesState(sharejs_doc)
  82. @$scope.$broadcast "doc:opened"
  83. @$scope.$apply () =>
  84. @$scope.editor.opening = false
  85. @$scope.editor.sharejs_doc = sharejs_doc
  86. done()
  87. _openNewDocument: (doc, callback = (error, sharejs_doc) ->) ->
  88. sl_console.log "[_openNewDocument] Opening..."
  89. current_sharejs_doc = @$scope.editor.sharejs_doc
  90. if current_sharejs_doc?
  91. sl_console.log "[_openNewDocument] Leaving existing open doc..."
  92. current_sharejs_doc.leaveAndCleanUp()
  93. @_unbindFromDocumentEvents(current_sharejs_doc)
  94. new_sharejs_doc = Document.getDocument @ide, doc.id
  95. new_sharejs_doc.join (error) =>
  96. return callback(error) if error?
  97. @_bindToDocumentEvents(doc, new_sharejs_doc)
  98. callback null, new_sharejs_doc
  99. _bindToDocumentEvents: (doc, sharejs_doc) ->
  100. sharejs_doc.on "error", (error, meta) =>
  101. if error?.message?
  102. message = error.message
  103. else if typeof error == "string"
  104. message = error
  105. else
  106. message = ""
  107. if message.match "maxDocLength"
  108. @ide.showGenericMessageModal(
  109. "Document Too Long"
  110. "Sorry, this file is too long to be edited manually. Please upload it directly."
  111. )
  112. else if message.match "too many comments or tracked changes"
  113. @ide.showGenericMessageModal(
  114. "Too many comments or tracked changes"
  115. "Sorry, this file has too many comments or tracked changes. Please try accepting or rejecting some existing changes, or resolving and deleting some comments."
  116. )
  117. else
  118. @ide.socket.disconnect()
  119. @ide.reportError(error, meta)
  120. @ide.showGenericMessageModal(
  121. "Out of sync"
  122. "Sorry, this file has gone out of sync and we need to do a full refresh. <br> <a href='/learn/Kb/Editor_out_of_sync_problems'>Please see this help guide for more information</a>"
  123. )
  124. @openDoc(doc, forceReopen: true)
  125. sharejs_doc.on "externalUpdate", (update) =>
  126. return if @_ignoreExternalUpdates
  127. @ide.showGenericMessageModal(
  128. "Document Updated Externally"
  129. "This document was just updated externally. Any recent changes you have made may have been overwritten. To see previous versions please look in the history."
  130. )
  131. _unbindFromDocumentEvents: (document) ->
  132. document.off()
  133. getCurrentDocValue: () ->
  134. @$scope.editor.sharejs_doc?.getSnapshot()
  135. getCurrentDocId: () ->
  136. @$scope.editor.open_doc_id
  137. startIgnoringExternalUpdates: () ->
  138. @_ignoreExternalUpdates = true
  139. stopIgnoringExternalUpdates: () ->
  140. @_ignoreExternalUpdates = false
  141. _syncTimeout: null
  142. _syncTrackChangesState: (doc) ->
  143. return if !doc?
  144. if @_syncTimeout?
  145. clearTimeout @_syncTimeout
  146. @_syncTimeout = null
  147. want = @$scope.editor.wantTrackChanges
  148. have = doc.getTrackingChanges()
  149. if want == have
  150. @$scope.editor.trackChanges = want
  151. return
  152. do tryToggle = () =>
  153. saved = !doc.getInflightOp()? and !doc.getPendingOp()?
  154. if saved
  155. doc.setTrackingChanges(want)
  156. @$scope.$apply () =>
  157. @$scope.editor.trackChanges = want
  158. else
  159. @_syncTimeout = setTimeout tryToggle, 100