EditorManager.coffee 5.8 KB

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