FileTreeManager.coffee 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. define [
  2. "models/Doc"
  3. "models/File"
  4. "models/Folder"
  5. "file-tree/FileTreeView"
  6. "file-tree/FolderView"
  7. "file-tree/DeletedDocsFolderView"
  8. "utils/Effects"
  9. "utils/Modal"
  10. "libs/backbone"
  11. "libs/jquery.storage"
  12. ], (Doc, File, Folder, FileTreeView, FolderView, DeletedDocsFolderView, Effects, Modal) ->
  13. class FileTreeManager
  14. constructor: (@ide) ->
  15. _.extend(@, Backbone.Events)
  16. @views = {}
  17. @multiSelectedEntities = []
  18. @ide.on "afterJoinProject", (@project) =>
  19. @populateFileTree()
  20. @project_id = @project.id
  21. if @ide.editor?.current_doc_id?
  22. @openDoc(@ide.editor.current_doc_id)
  23. else if location.hash.length > 1
  24. fileName = location.hash.slice(1)
  25. @openDocByPath(fileName)
  26. else if openDoc_id = $.localStorage("doc.open_id.#{@project_id}") and @getEntity(openDoc_id)
  27. @openDoc(openDoc_id)
  28. else if @project.get("rootDoc_id")?
  29. @openDoc(project.get("rootDoc_id"))
  30. else
  31. $('#settings').click()
  32. @view = new FileTreeView(@)
  33. @ide.sideBarView.addLink
  34. identifier: "file-tree"
  35. element: @view.$el
  36. prepend: true
  37. @view.render()
  38. @listenForUpdates()
  39. populateFileTree: () ->
  40. @view.bindToRootFolder(@project.get("rootFolder"))
  41. if @deletedDocsView?
  42. @deletedDocsView.$el.remove()
  43. @deletedDocsView = new DeletedDocsFolderView(model: @project.get("deletedDocs"), manager: @)
  44. @deletedDocsView.render()
  45. $("#sections").append(@deletedDocsView.$el)
  46. @hideDeletedDocs()
  47. listenForUpdates: () ->
  48. @ide.socket.on 'reciveNewDoc', (folder_id, doc) =>
  49. @addEntityToFolder(
  50. new Doc(id: doc._id, name: doc.name)
  51. folder_id
  52. )
  53. @ide.socket.on 'reciveNewFolder', (folder_id, folder) =>
  54. @addEntityToFolder(
  55. new Folder(id: folder._id, name: folder.name)
  56. folder_id
  57. )
  58. @ide.socket.on 'reciveNewFile', (folder_id, file) =>
  59. @addEntityToFolder(
  60. new File(id: file._id, name: file.name)
  61. folder_id
  62. )
  63. @ide.socket.on 'removeEntity', (entity_id) =>
  64. @onDeleteEntity(entity_id)
  65. @ide.socket.on 'reciveEntityRename', (entity_id, newName) =>
  66. @onRenameEntity(entity_id, newName)
  67. @ide.socket.on 'reciveEntityMove', (entity_id, folder_id) =>
  68. @onMoveEntity(entity_id, folder_id)
  69. registerView: (entity_id, view) ->
  70. @views[entity_id] = view
  71. addEntityToFolder: (entity, folder_id) ->
  72. folder = @views[folder_id].model
  73. children = folder.get("children")
  74. children.add(entity)
  75. openDoc: (doc, line) ->
  76. return if !doc?
  77. doc_id = doc.id or doc
  78. @trigger "open:doc", doc_id, line: line
  79. @selectEntity(doc_id)
  80. $.localStorage "doc.open_id.#{@project_id}", doc_id
  81. openDocByPath: (path, line) ->
  82. doc_id = @getDocIdOfPath(path)
  83. return null if !doc_id?
  84. @openDoc(doc_id, line)
  85. openFile: (file) ->
  86. @trigger "open:file", file
  87. @selectEntity(file.id)
  88. openFolder: (folder) ->
  89. @selectEntity(folder.id)
  90. selectEntity: (entity_id) ->
  91. if @views[@selected_entity_id]?
  92. @views[@selected_entity_id].deselect()
  93. @selected_entity_id = entity_id
  94. @ide.sideBarView.deselectAll()
  95. @views[entity_id]?.select()
  96. getEntity: (entity_id, options = {include_deleted: false}) ->
  97. model = @views[entity_id]?.model
  98. if !model? or (model.get("deleted") and !options.include_deleted)
  99. return
  100. else
  101. return model
  102. getSelectedEntity: () -> @getEntity(@selected_entity_id)
  103. getSelectedEntityId: () -> @getSelectedEntity()?.id
  104. getCurrentFolder: () ->
  105. selected_entity = @getSelectedEntity()
  106. if !selected_entity?
  107. return @project.get("rootFolder")
  108. else if selected_entity instanceof Folder
  109. return selected_entity
  110. else
  111. return selected_entity.collection.parentFolder
  112. getDocIdOfPath: (path) ->
  113. parts = path.split("/")
  114. folder = @project.get("rootFolder")
  115. lastPart = parts.pop()
  116. getChildWithName = (folder, name) ->
  117. return folder if name == "."
  118. foundChild = null
  119. for child in folder.get("children").models
  120. if child.get("name") == name
  121. foundChild = child
  122. return foundChild
  123. for part in parts
  124. folder = getChildWithName(folder, part)
  125. return null if !folder or !(folder instanceof Folder)
  126. doc = getChildWithName(folder, lastPart)
  127. return null if !doc or !(doc instanceof Doc)
  128. return doc.id
  129. getPathOfEntityId: (entity_id) ->
  130. entity = @getEntity(entity_id)
  131. return if !entity?
  132. path = entity.get("name")
  133. while (entity = entity.collection?.parentFolder)
  134. if entity.collection?
  135. # it's not the root folder so keep going
  136. path = entity.get("name") + "/" + path
  137. return path
  138. getRootFolderPath: () ->
  139. rootFilePath = @getPathOfEntityId(@project.get("rootDoc_id"))
  140. return rootFilePath.split("/").slice(0, -1).join("/")
  141. getNameOfEntityId: (entity_id) ->
  142. entity = @getEntity(entity_id)
  143. return if !entity?
  144. return entity.get("name")
  145. # RENAMING
  146. renameSelected: () ->
  147. entity_id = @getSelectedEntityId()
  148. return if !entity_id?
  149. @views[entity_id]?.startRename()
  150. ga('send', 'event', 'editor-interaction', 'renameEntity', "topMenu")
  151. renameEntity: (entity, name) ->
  152. name = name?.trim()
  153. @ide.socket.emit 'renameEntity', entity.id, entity.get("type"), name
  154. entity.set("name", name)
  155. onRenameEntity: (entity_id, name) ->
  156. @getEntity(entity_id)?.set("name", name)
  157. # MOVING
  158. onMoveEntity: (entity_id, folder_id) ->
  159. entity = @getEntity(entity_id)
  160. destFolder = @getEntity(folder_id)
  161. return if !entity? or !destFolder?
  162. if entity.collection == destFolder.get("children")
  163. # Already in parent folder
  164. return
  165. return if @_isParent(entity_id, folder_id)
  166. entity.collection.remove(entity)
  167. destFolder.get("children").add(entity)
  168. _isParent: (parent_folder_id, child_folder_id) ->
  169. childFolder = @getEntity(child_folder_id)
  170. return false unless childFolder? and childFolder instanceof Folder
  171. parentIds = childFolder.getParentFolderIds()
  172. if parentIds.indexOf(parent_folder_id) > -1
  173. return true
  174. else
  175. return false
  176. moveEntity: (entity_id, folder_id, type) ->
  177. return if @_isParent(entity_id, folder_id)
  178. @ide.socket.emit 'moveEntity', entity_id, folder_id, type
  179. @onMoveEntity(entity_id, folder_id)
  180. # CREATING
  181. showNewEntityModal: (type, defaultName, callback = (name) ->) ->
  182. el = $($("#newEntityModalTemplate").html())
  183. input = el.find("input")
  184. create = _.once () =>
  185. name = input.val()?.trim()
  186. if name != ""
  187. callback(name)
  188. modal = new Modal
  189. title: "New #{type}"
  190. el: el
  191. buttons: [{
  192. text: "Cancel"
  193. }, {
  194. text: "Create"
  195. callback: create
  196. class: "btn-primary"
  197. }]
  198. input.on "keydown", (e) ->
  199. if e.keyCode == 13 # Enter
  200. create()
  201. modal.remove()
  202. input.val(defaultName.replace("|", ""))
  203. if input[0].setSelectionRange?
  204. # value is "name.tex"
  205. input[0].setSelectionRange(0, defaultName.indexOf("|"))
  206. showNewDocModal: (parentFolder = @getCurrentFolder()) ->
  207. return if !parentFolder?
  208. @showNewEntityModal "Document", "name|.tex", (name) =>
  209. @addDocToFolder parentFolder, name
  210. showNewFolderModal: (parentFolder = @getCurrentFolder()) ->
  211. return if !parentFolder?
  212. @showNewEntityModal "Folder", "name|", (name) =>
  213. @addFolderToFolder parentFolder, name
  214. showUploadFileModal: (parentFolder = @getCurrentFolder()) ->
  215. return if !parentFolder?
  216. @ide.fileUploadManager.showUploadDialog parentFolder.id
  217. addDoc: (folder_id, name) ->
  218. @ide.socket.emit 'addDoc', folder_id, name
  219. addDocToFolder: (parentFolder, name) ->
  220. @addDoc parentFolder.id, name
  221. addFolder: (parent_folder_id, name) ->
  222. @ide.socket.emit 'addFolder', parent_folder_id, name
  223. addFolderToFolder: (parentFolder, name) ->
  224. return if !parentFolder?
  225. @addFolder parentFolder.id, name
  226. # DELETING
  227. confirmDelete: (entity) ->
  228. ga('send', 'event', 'editor-interaction', 'deleteEntity', "topMenu")
  229. Modal.createModal
  230. title: "Confirm Deletion"
  231. message: "Are you sure you want to delete <strong>#{entity.get("name")}</strong>?"
  232. buttons: [{
  233. text: "Cancel"
  234. class: "btn"
  235. },{
  236. text: "Delete"
  237. class: "btn btn-danger"
  238. callback: () => @_doDelete(entity)
  239. }]
  240. confirmDeleteOfSelectedEntity: () ->
  241. entity = @getSelectedEntity()
  242. return if !entity?
  243. @confirmDelete(entity)
  244. _doDelete: (entity) ->
  245. @ide.socket.emit 'deleteEntity', entity.id, entity.get("type")
  246. @onDeleteEntity entity.id
  247. onDeleteEntity: (entity_id) ->
  248. entity = @getEntity(entity_id)
  249. return if !entity?
  250. entity.set("deleted", true)
  251. entity.collection?.remove(entity)
  252. delete @views[entity_id]
  253. # Do this after the remove so that it's never in two places at once
  254. # and so that it doesn't get reset by deleting from @views
  255. if entity.get("type") == "doc"
  256. @project.get("deletedDocs").get("children").add entity
  257. setLabels: (labels) ->
  258. @view.setLabels(labels)
  259. @deletedDocsView.setLabels(labels)
  260. showDeletedDocs: () ->
  261. if @project.get("deletedDocs").get("children").length > 0
  262. @deletedDocsView.$el.show()
  263. hideDeletedDocs: () ->
  264. @deletedDocsView.$el.hide()