James Allen 12 лет назад
Родитель
Сommit
242a866bce

+ 28 - 0
services/web/app/coffee/Features/Editor/EditorHttpController.coffee

@@ -36,3 +36,31 @@ module.exports = EditorHttpController =
 		EditorController.addFolder project_id, parent_folder_id, name, (error, doc) ->
 			return next(error) if error?
 			res.json doc
+
+	renameEntity: (req, res, next) ->
+		project_id  = req.params.Project_id
+		entity_id   = req.params.entity_id
+		entity_type = req.params.entity_type
+		name = req.body.name
+		EditorController.renameEntity project_id, entity_id, entity_type, name, (error) ->
+			return next(error) if error?
+			res.send 204
+
+	moveEntity: (req, res, next) ->
+		project_id  = req.params.Project_id
+		entity_id   = req.params.entity_id
+		entity_type = req.params.entity_type
+		folder_id = req.body.folder_id
+		EditorController.moveEntity project_id, entity_id, folder_id, entity_type, (error) ->
+			return next(error) if error?
+			res.send 204
+
+	deleteEntity: (req, res, next) ->
+		project_id  = req.params.Project_id
+		entity_id   = req.params.entity_id
+		entity_type = req.params.entity_type
+		EditorController.deleteEntity project_id, entity_id, entity_type, (error) ->
+			return next(error) if error?
+			res.send 204
+
+

+ 4 - 0
services/web/app/coffee/router.coffee

@@ -90,6 +90,10 @@ module.exports = class Router
 		app.post '/project/:Project_id/doc', SecurityManager.requestCanModifyProject, EditorHttpController.addDoc
 		app.post '/project/:Project_id/folder', SecurityManager.requestCanModifyProject, EditorHttpController.addFolder
 
+		app.post '/project/:Project_id/:entity_type/:entity_id/rename', SecurityManager.requestCanModifyProject, EditorHttpController.renameEntity
+		app.post '/project/:Project_id/:entity_type/:entity_id/move', SecurityManager.requestCanModifyProject, EditorHttpController.moveEntity
+		app.post '/project/:Project_id/:entity_type/:entity_id/delete', SecurityManager.requestCanModifyProject, EditorHttpController.deleteEntity
+
 		app.post '/project/:Project_id/compile', SecurityManager.requestCanAccessProject, CompileController.compile
 		app.get  '/Project/:Project_id/output/output.pdf', SecurityManager.requestCanAccessProject, CompileController.downloadPdf
 		app.get  /^\/project\/([^\/]*)\/output\/(.*)$/,

+ 1 - 2
services/web/app/views/project/editor.jade

@@ -15,7 +15,6 @@ block scripts
 block content
 
 	.editor(ng-controller="IdeController")
-
 		.loading-screen(ng-show="state.loading")
 			.container
 				h3 Loading...
@@ -41,7 +40,7 @@ block content
 
 		#editor-content(ng-cloak, layout="main", ng-hide="state.loading")
 			include ./editor/file-tree
-			
+
 			.ui-layout-center
 
 	//- #loadingScreen

+ 22 - 5
services/web/app/views/project/editor/file-tree.jade

@@ -23,7 +23,12 @@ aside#file-tree.ui-layout-west(ng-controller="FileTreeController")
 			i.fa.fa-upload
 
 		.toolbar-right
-			a(href, tooltip="Rename", tooltip-placement="bottom")
+			a(
+				href,
+				ng-click="startRenamingSelected()",
+				tooltip="Rename",
+				tooltip-placement="bottom"
+			)
 				i.fa.fa-pencil
 			a(href, tooltip="Delete", tooltip-placement="bottom", tooltip-append-to-body="true")
 				i.fa.fa-trash-o
@@ -41,11 +46,23 @@ script(type='text/ng-template', id='entityListItemTemplate')
 		ng-controller="FileTreeEntityController"
 	)
 		.entity(ng-if="entity.type == 'doc'")
-			.entity-name(ng-click="select()")
+			.entity-name(
+				ng-click="select()"
+				ng-dblclick="startRenaming()"
+			)
 				//- Just a spacer to align with folders
 				i.fa.fa-fw.toggle
 				i.fa.fa-fw.fa-file
-				|  {{ entity.name }}
+				span(
+					ng-hide="entity.renaming"
+				)  {{ entity.name }}
+				input(
+					ng-show="entity.renaming",
+					ng-model="inputs.name",
+					ng-blur="finishRenaming()",
+					focus-input="entity.renaming",
+					on-enter="finishRenaming()"
+				)
 
 		.entity(ng-if="entity.type == 'file'")
 			.entity-name(ng-click="select()")
@@ -82,7 +99,7 @@ script(type='text/ng-template', id='newDocModalTemplate')
 				placeholder="File Name",
 				required,
 				ng-model="inputs.name",
-				ng-enter="create()",
+				on-enter="create()",
 				focus-on="open"
 			)
 	.modal-footer
@@ -107,7 +124,7 @@ script(type='text/ng-template', id='newFolderModalTemplate')
 				placeholder="Folder Name",
 				required,
 				ng-model="inputs.name",
-				ng-enter="create()",
+				on-enter="create()",
 				focus-on="open"
 			)
 	.modal-footer

+ 4 - 4
services/web/app/views/project/list.jade

@@ -312,7 +312,7 @@ block content
 						placeholder="New Folder Name",
 						required,
 						ng-model="inputs.newTagName",
-						ng-enter="create()",
+						on-enter="create()",
 						focus-on="open"
 					)
 			.modal-footer
@@ -332,7 +332,7 @@ block content
 						placeholder="Project Name",
 						ng-model="inputs.projectName",
 						required,
-						ng-enter="rename()",
+						on-enter="rename()",
 						focus-on="open"
 					)
 			.modal-footer
@@ -354,7 +354,7 @@ block content
 							placeholder="New Project Name",
 							required,
 							ng-model="inputs.projectName",
-							ng-enter="clone()",
+							on-enter="clone()",
 							focus-on="open"
 						)
 			.modal-footer
@@ -379,7 +379,7 @@ block content
 						placeholder="Project Name",
 						required,
 						ng-model="inputs.projectName",
-						ng-enter="create()",
+						on-enter="create()",
 						focus-on="open"
 					)
 			.modal-footer

+ 10 - 0
services/web/public/coffee/app/directives/onEnter.coffee

@@ -0,0 +1,10 @@
+define [
+	"base"
+], (App) ->
+	App.directive 'onEnter', () ->
+		return (scope, element, attrs) ->
+			element.bind "keydown keypress", (event) ->
+				if event.which == 13
+					scope.$apply () ->
+						scope.$eval(attrs.onEnter, event: event)
+					event.preventDefault()

+ 2 - 0
services/web/public/coffee/app/ide.coffee

@@ -4,7 +4,9 @@ define [
 	"ide/directives/layout"
 	"ide/services/ide"
 	"directives/focusOn"
+	"directives/focusInput"
 	"directives/fineUpload"
+	"directives/onEnter"
 ], (
 	App
 	FileTreeManager

+ 17 - 0
services/web/public/coffee/app/ide/file-tree/FileTreeManager.coffee

@@ -154,3 +154,20 @@ define [
 					callback(null, folder)
 				failure: (error) -> callback(error)
 			}
+
+		renameEntity: (entity, name, callback = (error) ->) ->
+			return if entity.name == name
+			entity.name = name
+			$.ajax {
+				url:  "/project/#{@ide.project_id}/#{entity.type}/#{entity.id}/rename"
+				type: "POST"
+				contentType: "application/json; charset=utf-8"
+				data: JSON.stringify {
+					name: name,
+					_csrf: window.csrfToken
+				}
+				dataType: "json"
+				success: () -> callback()
+				failure: (error) -> callback(error)
+			}
+

+ 3 - 0
services/web/public/coffee/app/ide/file-tree/controllers/FileTreeController.coffee

@@ -24,6 +24,9 @@ define [
 		$scope.orderByFoldersFirst = (entity) ->
 			return 0 if entity.type == "folder"
 			return 1
+
+		$scope.startRenamingSelected = () ->
+			$scope.$broadcast "rename:selected"
 	]
 
 	App.controller "NewDocModalController", [

+ 14 - 1
services/web/public/coffee/app/ide/file-tree/controllers/FileTreeEntityController.coffee

@@ -2,8 +2,21 @@ define [
 	"base"
 ], (App) ->
 	App.controller "FileTreeEntityController", ["$scope", "ide", ($scope, ide) ->
-		$scope.select = ($event) ->
+		$scope.select = () ->
 			ide.fileTreeManager.forEachEntity (entity) ->
 				entity.selected = false
 			$scope.entity.selected = true
+
+		$scope.inputs =
+			name: $scope.entity.name
+
+		$scope.startRenaming = () ->
+			$scope.entity.renaming = true
+
+		$scope.finishRenaming = () ->
+			delete $scope.entity.renaming
+			ide.fileTreeManager.renameEntity($scope.entity, $scope.inputs.name)
+
+		$scope.$on "rename:selected", () ->
+			$scope.startRenaming() if $scope.entity.selected
 	]

+ 1 - 0
services/web/public/coffee/app/main.coffee

@@ -8,5 +8,6 @@ define [
 	"directives/focusOn"
 	"directives/equals"
 	"directives/fineUpload"
+	"directives/onEnter"
 ], () ->
 	angular.bootstrap(document.body, ["SharelatexApp"])

+ 0 - 8
services/web/public/coffee/app/project-list.coffee

@@ -1,14 +1,6 @@
 define [
 	"base"
 ], (App) ->
-	App.directive 'ngEnter', () ->
-		return (scope, element, attrs) ->
-			element.bind "keydown keypress", (event) ->
-				if event.which == 13
-					scope.$apply () ->
-						scope.$eval(attrs.ngEnter, event: event)
-					event.preventDefault()
-
 	App.filter "formatDate", () ->
 		(date, format = "Do MMM YYYY, h:mm a") ->
 			moment(date).format(format)

+ 3 - 0
services/web/public/stylesheets/app/editor.less

@@ -96,6 +96,9 @@
 				&:hover {
 					background-color: @gray-lightest;
 				}
+				input {
+					line-height: 1.6;
+				}
 			}
 
 			i.fa-folder-open, i.fa-folder {

+ 54 - 0
services/web/test/UnitTests/coffee/Editor/EditorHttpControllerTests.coffee

@@ -89,3 +89,57 @@ describe "EditorHttpController", ->
 				.calledWith(@folder)
 				.should.equal true
 
+	describe "renameEntity", ->
+		beforeEach ->
+			@req.params =
+				Project_id: @project_id
+				entity_id: @entity_id = "entity-id-123"
+				entity_type: @entity_type = "entity-type"
+			@req.body =
+				name: @name = "new-name"
+			@EditorController.renameEntity = sinon.stub().callsArg(4)
+			@EditorHttpController.renameEntity @req, @res
+
+		it "should call EditorController.renameEntity", ->
+			@EditorController.renameEntity
+				.calledWith(@project_id, @entity_id, @entity_type, @name)
+				.should.equal true
+
+		it "should send back a success response", ->
+			@res.send.calledWith(204).should.equal true
+
+	describe "moveEntity", ->
+		beforeEach ->
+			@req.params =
+				Project_id: @project_id
+				entity_id: @entity_id = "entity-id-123"
+				entity_type: @entity_type = "entity-type"
+			@req.body =
+				folder_id: @folder_id = "folder-id-123"
+			@EditorController.moveEntity = sinon.stub().callsArg(4)
+			@EditorHttpController.moveEntity @req, @res
+
+		it "should call EditorController.moveEntity", ->
+			@EditorController.moveEntity
+				.calledWith(@project_id, @entity_id, @folder_id, @entity_type)
+				.should.equal true
+
+		it "should send back a success response", ->
+			@res.send.calledWith(204).should.equal true
+
+	describe "deleteEntity", ->
+		beforeEach ->
+			@req.params =
+				Project_id: @project_id
+				entity_id: @entity_id = "entity-id-123"
+				entity_type: @entity_type = "entity-type"
+			@EditorController.deleteEntity = sinon.stub().callsArg(3)
+			@EditorHttpController.deleteEntity @req, @res
+
+		it "should call EditorController.deleteEntity", ->
+			@EditorController.deleteEntity
+				.calledWith(@project_id, @entity_id, @entity_type)
+				.should.equal true
+
+		it "should send back a success response", ->
+			@res.send.calledWith(204).should.equal true