ソースを参照

Add in dropdown and context menu for files

James Allen 12 年 前
親
コミット
7aab6c4c0b

+ 7 - 0
services/web/app/views/templates.jade

@@ -66,6 +66,8 @@
 				i(class="sprite-{{ type }}")
 				span.name {{ name }}
 				input.rename.js-rename
+			.dropdown-caret
+				i.icon-chevron-down
 
 	script(type="text/template")#folderTemplate
 		.entity-list-item(class="entity-{{ type }}", entity-type="{{ type }}", id="{{ id }}")
@@ -76,6 +78,8 @@
 				i(class="sprite-{{ type }}")
 				span.name {{ name }}
 				input.rename.js-rename
+			.dropdown-caret
+				i.icon-chevron-down
 	
 	script(type="text/template")#entityListTemplate
 		.contents
@@ -110,6 +114,9 @@
 	script(type="text/template")#contextMenuEntryTemplate
 		li
 			a(href="#") {{text}}
+
+	script(type="text/template")#contextMenuDividerTemplate
+		li.divider
 	
 	script(type="text/template")#genericModalTemplate
 		.modal

+ 45 - 1
services/web/public/coffee/file-tree/EntityView.coffee

@@ -1,7 +1,8 @@
 define [
+	"utils/ContextMenu"
 	"libs/backbone"
 	"libs/mustache"
-], () ->
+], (ContextMenu) ->
 	EntityView = Backbone.View.extend
 		entityTemplate: $("#entityTemplate").html()
 
@@ -14,6 +15,8 @@ define [
 		events: () ->
 			events = {}
 			events["click ##{@model.id} > .js-clickable"] = "parentOnClick"
+			events["click .dropdown-caret"] = "showContextMenuFromCaret"
+			events["contextmenu"] = "showContextMenuFromRightClick"
 			return events
 
 		render: () ->
@@ -71,6 +74,47 @@ define [
 			if @ide.isAllowedToDoIt "readAndWrite"
 				@startRename()
 
+		showContextMenuFromCaret: (e) ->
+			e.stopPropagation()
+			caret = @$(".dropdown-caret")
+			offset = caret.offset()
+			position =
+				top: offset.top + caret.outerHeight()
+				right: $(document.body).width() - (offset.left + caret.outerWidth())
+			@toggleContextMenu(position)
+
+		showContextMenuFromRightClick: (e) ->
+			e.preventDefault()
+			e.stopPropagation()
+			position =
+				left: e.pageX
+				top: e.pageY
+			@showContextMenu(position)
+
+		toggleContextMenu: (position) ->
+			if @contextMenu?
+				@contextMenu.destroy()
+			else
+				@showContextMenu(position)
+
+		showContextMenu: (position) ->
+			entries = @getContextMenuEntries()
+
+			@contextMenu = new ContextMenu(position, entries)
+			@contextMenu.on "destroy", () =>
+				delete @contextMenu
+
+		getContextMenuEntries: () ->
+			return [{
+				text: "Rename"
+				onClick: () =>
+					@startRename()
+			}, {
+				text: "Delete"
+				onClick: () =>
+					@manager.confirmDelete(@model)
+			}]
+
 		_initializeDrag: () ->
 			@$entityListItemEl.draggable
 				delay: 250

+ 19 - 18
services/web/public/coffee/file-tree/FileTreeManager.coffee

@@ -218,52 +218,53 @@ define [
 				# value is "name.tex"
 				input[0].setSelectionRange(0, defaultName.indexOf("|"))
 
-		showNewDocModal: () ->
+		showNewDocModal: (parentFolder = @getCurrentFolder()) ->
+			return if !parentFolder?
 			@showNewEntityModal "Document", "name|.tex", (name) =>
-				@addDocToCurrentFolder name
+				@addDocToFolder parentFolder, name
 				
-		showNewFolderModal: () ->
+		showNewFolderModal:  (parentFolder = @getCurrentFolder()) ->
+			return if !parentFolder?
 			@showNewEntityModal "Folder", "name|", (name) =>
-				@addFolderToCurrentFolder name
+				@addFolderToFolder parentFolder, name
 
-		showUploadFileModal: () ->
-			folder = @getCurrentFolder()
-			return if !folder?
-			@ide.fileUploadManager.showUploadDialog folder.id
+		showUploadFileModal: (parentFolder = @getCurrentFolder()) ->
+			return if !parentFolder?
+			@ide.fileUploadManager.showUploadDialog parentFolder.id
 
 		addDoc: (folder_id, name) ->
 			@ide.socket.emit 'addDoc', folder_id, name
 
-		addDocToCurrentFolder: (name) ->
-			folder = @getCurrentFolder()
-			return if !folder?
-			@addDoc folder.id, name
+		addDocToFolder: (parentFolder, name) ->
+			@addDoc parentFolder.id, name
 
 		addFolder: (parent_folder_id, name) ->
 			@ide.socket.emit 'addFolder', parent_folder_id, name
 
-		addFolderToCurrentFolder: (name) ->
-			parentFolder = @getCurrentFolder()
+		addFolderToFolder: (parentFolder, name) ->
 			return if !parentFolder?
 			@addFolder parentFolder.id, name
 
 		# DELETING
-		confirmDelete: () ->
+		confirmDelete: (entity) ->
 			Modal.createModal
 				title: "Confirm Deletion"
-				message: "Are you sure you want to delete the selected files?"
+				message: "Are you sure you want to delete <strong>#{entity.get("name")}</strong>?"
 				buttons: [{
 					text: "Cancel"
 					class: "btn"
 				},{
 					text: "Delete"
 					class: "btn btn-danger"
-					callback: () => @_doDelete()
+					callback: () => @_doDelete(entity)
 				}]
 
-		_doDelete: () ->
+		confirmDeleteOfSelectedEntity: () ->
 			entity = @getSelectedEntity()
 			return if !entity?
+			@confirmDelete(entity)
+
+		_doDelete: (entity) ->
 			@ide.socket.emit 'deleteEntity', entity.id, entity.get("type")
 			@onDeleteEntity entity.id
 

+ 24 - 0
services/web/public/coffee/file-tree/FolderView.coffee

@@ -119,3 +119,27 @@ define [
 				@hideEntries()
 			else
 				@showEntries()
+
+		getContextMenuEntries: (args...) ->
+			entries = EntityView::getContextMenuEntries.apply(this, args)
+			entries.push {
+				divider: true
+			}
+			entries.push @getFolderContextMenuEntries()...
+			return entries
+
+		getFolderContextMenuEntries: () ->
+			return [{
+				text: "New file"
+				onClick: () =>
+					@manager.showNewDocModal(@model)
+			}, {
+				text: "New folder"
+				onClick: () =>
+					@manager.showNewFolderModal(@model)
+			}, {
+				text: "Upload file"
+				onClick: () =>
+					@manager.showUploadFileModal(@model)
+			}]
+

+ 4 - 1
services/web/public/coffee/file-tree/RootFolderView.coffee

@@ -19,7 +19,7 @@ define [
 						@manager.showUploadFileModal()
 					"click .js-delete-btn"  : (e) ->
 						e.preventDefault()
-						@manager.confirmDelete()
+						@manager.confirmDeleteOfSelectedEntity()
 					"click .js-rename-btn"  : (e) ->
 						e.preventDefault()
 						@manager.renameSelected()
@@ -50,6 +50,9 @@ define [
 		onToggle: () ->
 			e.preventDefault()
 
+		getContextMenuEntries: () ->
+			@getFolderContextMenuEntries()
+
 		hideToggle: () ->
 			@$(".js-toggle").hide()
 

+ 24 - 18
services/web/public/coffee/utils/ContextMenu.coffee

@@ -13,44 +13,50 @@ define [
 			return @
 
 		onClick: (e) ->
+			e.preventDefault()
 			if @options.onClick
 				@options.onClick()
 
 	ContextMenu = Backbone.View.extend
-		template: $("#contextMenuTemplate").html()
-
-		initialize: () ->
-			@entries = []
+		templates:
+			menu: $("#contextMenuTemplate").html()
+			divider: $("#contextMenuDividerTemplate").html()
+
+		initialize: (position, entries) ->
+			if ContextMenu.currentMenu?
+				ContextMenu.currentMenu.destroy()
+			ContextMenu.currentMenu = @
 			@render()
-			@hide()
+			for entry in entries
+				@addEntry(entry)
+			@show(position)
 
 		render: () ->
-			@setElement($(@template))
+			@setElement($(@templates.menu))
 			$(document.body).append(@$el)
 			return @
 
-		hide: () -> @$el.hide()
+		destroy: () ->
+			@$el.remove()
+			@trigger "destroy"
 
-		show: (left, top) ->
+		show: (position) ->
 			page = $(document.body)
 			page.on "click.hideContextMenu", (e) =>
 				page.off "click.hideContextMenu"
-				@hide()
+				@destroy()
 			@$el.css
 				position: "absolute"
 				"z-index": 10000
-				top: (top || 0) + "px"
-				left: (left || 0) + "px"
-			@$el.show()
+			@$el.css position
 
 		addEntry: (options) ->
-			entry = new ContextMenuEntry(options)
-			@$el.append entry.render().el
-			@entries.push entry
+			if options.divider
+				@$el.append $(@templates.divider)
+			else
+				entry = new ContextMenuEntry(options)
+				@$el.append entry.render().el
 
-		clearEntries: () ->
-			while @entries.length > 0
-				@entries.pop().remove()
 			
 
 

+ 37 - 3
services/web/public/stylesheets/less/editor.less

@@ -443,7 +443,7 @@ body.editor {
 	overflow: hidden;
 	cursor: default;
 	border-right: 1px solid #aaa;
-	background: url('/img/noise.png') #eee;
+	background-color: rgb(238,238,238);
 	padding: 6px 0 0 6px;
 
 	ul {
@@ -459,10 +459,14 @@ body.editor {
 		list-style: none;
 		white-space: nowrap;
 		cursor: pointer;
+		position: relative;
 		.clickable {
 			height: 24px;
 			margin-left: 20px;
 		}
+		.dropdown-caret {
+			display: none;
+		}
 	}
 
 	.entity-folder {
@@ -495,9 +499,33 @@ body.editor {
 	}
 
 	li.selected, .entity-list-item.selected {
-		background-color: rgba(55,120,194,0.3);
+		background-color: rgb(185,201,227);
 		.border-radius(5px 0 0 5px);
-		color: #3d5979
+		color: #3d5979;
+		.dropdown-caret {
+			display: block;
+			padding: 4px 6px 4px 4px;
+			position: absolute;
+			top: 0;
+			right: 0;
+			bottom: 0;
+			background-color: rgb(185,201,227);
+			&:before {
+				content: " ";
+				#gradient > .horizontal(rgba(185,201,227,0), rgb(185,201,227));
+				background-color: transparent;
+				width: 12px;
+				height: 100%;
+				position: absolute;
+				top: 0;
+				bottom: 0;
+				right: 20px
+			}
+			i {
+				vertical-align: top;
+				margin: 0;
+			}
+		}
 	}
 	
 	li img, .entity-list-item i {
@@ -600,6 +628,12 @@ table {
 	}
 }
 
+.context-menu {
+	display: block;
+	left: auto;
+	.border-radius(0);
+}
+
 .clear-modal-backdrop {
 	background: none;
 }