Procházet zdrojové kódy

Merge pull request #491 from sharelatex/pr-project-list-improvements

Project list improvements
Paulo Jorge Reis před 9 roky
rodič
revize
9d2d217d35

+ 19 - 7
services/web/app/views/project/list/project-list.pug

@@ -140,23 +140,35 @@
 					ng-repeat="project in visibleProjects | orderBy:predicate:reverse",
 					ng-controller="ProjectListItemController"
 				)
-					.row
+					.row(select-row)
 						.col-xs-6
 							input.select-item(
 								select-individual,
 								type="checkbox",
 								ng-model="project.selected"
+								stop-propagation="click"
 							)
 							span
-								a.projectName(href="/project/{{project.id}}") {{project.name}}
+								a.projectName(
+									href="/project/{{project.id}}"
+									stop-propagation="click"
+								) {{project.name}}
 								span(
 									ng-controller="TagListController"
 								)
-									a.label.label-default.tag-label(
-										href,
-										ng-repeat='tag in project.tags',
-										ng-click="selectTag(tag)"
-									) {{tag.name}}
+									.tag-label(
+										ng-repeat='tag in project.tags'
+										stop-propagation="click"
+									)
+										a.label.label-default.tag-label-name(
+											href,
+											ng-click="selectTag(tag)"
+										) {{tag.name}} 
+										a.label.label-default.tag-label-remove(
+											href
+											ng-click="removeProjectFromTag(project, tag)"
+										) ×
+
 						.col-xs-2
 							span.owner {{ownerName()}}
 						.col-xs-4

+ 9 - 0
services/web/app/views/project/list/side-bar.pug

@@ -79,6 +79,15 @@
 					li
 						a(href, ng-click="deleteTag(tag)", stop-propagation="click")
 							| #{translate("delete")}
+		li.tag.untagged(
+			ng-if="tags.length",
+			ng-cloak,
+			ng-click="selectUntagged()"
+			ng-class="{active: filter === 'untagged'}",
+		) 	
+			a.tag-name(href)
+				| #{translate("uncategorized")}
+				span.subdued  ({{ nUntagged }})
 		li(ng-cloak)
 			a.tag(href, ng-click="openNewTagModal()")
 				i.fa.fa-fw.fa-plus

+ 14 - 0
services/web/public/coffee/directives/selectAll.coffee

@@ -58,4 +58,18 @@ define [
 					scope.$apply () ->
 						scope.ngModel = false
 					ignoreChanges = false
+
+				scope.$on "select-all:row-clicked", () ->
+					ignoreChanges = true
+					scope.$apply () ->
+						scope.ngModel = !scope.ngModel
+					ignoreChanges = false
+		}
+
+	App.directive "selectRow", () ->
+		return {
+			scope: true
+			link: (scope, element, attrs) ->
+				element.on "click", (e) ->
+					scope.$broadcast "select-all:row-clicked"
 		}

+ 47 - 2
services/web/public/coffee/main/project-list/project-list.coffee

@@ -2,7 +2,7 @@ define [
 	"base"
 ], (App) ->
 
-	App.controller "ProjectPageController", ($scope, $modal, $q, $window, queuedHttp, event_tracking, $timeout) ->
+	App.controller "ProjectPageController", ($scope, $modal, $q, $window, queuedHttp, event_tracking, $timeout, localStorage) ->
 		$scope.projects = window.data.projects
 		$scope.tags = window.data.tags
 		$scope.notifications = window.data.notifications
@@ -10,6 +10,7 @@ define [
 		$scope.selectedProjects = []
 		$scope.filter = "all"
 		$scope.predicate = "lastUpdated"
+		$scope.nUntagged = 0
 		$scope.reverse = true
 		$scope.searchText = 
 			value : ""
@@ -18,6 +19,12 @@ define [
 			recalculateProjectListHeight()
 		, 10
 
+		$scope.$watch((
+			() -> $scope.projects.filter((project) -> !project.tags? or project.tags.length == 0).length
+		), (newVal) -> $scope.nUntagged = newVal)
+
+		storedUIOpts = JSON.parse(localStorage("project_list"))
+
 		recalculateProjectListHeight = () ->
 			topOffset = $(".project-list-card")?.offset()?.top
 			bottomOffset = $("footer").outerHeight() + 25
@@ -52,6 +59,13 @@ define [
 					project.tags ||= []
 					project.tags.push tag
 
+		markTagAsSelected = (id) ->
+			for tag in $scope.tags
+				if tag._id == id
+					tag.selected = true
+				else
+					tag.selected = false
+		
 		$scope.changePredicate = (newPredicate)->
 			if $scope.predicate == newPredicate
 				$scope.reverse = !$scope.reverse
@@ -104,6 +118,10 @@ define [
 				if $scope.filter == "tag" and selectedTag? and project.id not in selectedTag.project_ids
 					visible = false
 
+				# Hide tagged projects if we only want to see the uncategorized ones
+				if $scope.filter == "untagged" and project.tags?.length > 0
+					visible = false
+
 				# Hide projects we own if we only want to see shared projects
 				if $scope.filter == "shared" and project.accessLevel == "owner"
 					visible = false
@@ -126,6 +144,11 @@ define [
 				else
 					# We don't want hidden selections
 					project.selected = false
+
+			localStorage("project_list", JSON.stringify({ 
+				filter: $scope.filter,
+				selectedTagId: selectedTag?._id
+			}))
 			$scope.updateSelectedProjects()
 
 		$scope.getSelectedTag = () ->
@@ -178,6 +201,23 @@ define [
 			# the projects from view
 			$scope.updateVisibleProjects()
 
+		$scope.removeProjectFromTag = (project, tag) ->
+			tag.showWhenEmpty = true
+
+			project.tags ||= []
+			index = project.tags.indexOf tag
+
+			if index > -1
+				$scope._removeProjectIdsFromTagArray(tag, [ project.id ])
+				project.tags.splice(index, 1)
+				queuedHttp({
+					method: "DELETE"
+					url: "/tag/#{tag._id}/project/#{project.id}"
+					headers:
+						"X-CSRF-Token": window.csrfToken
+				})
+				$scope.updateVisibleProjects()
+
 		$scope.addSelectedProjectsToTag = (tag) ->
 			selected_projects = $scope.getSelectedProjects()
 			event_tracking.send 'project-list-page-interaction', 'project action', 'addSelectedProjectsToTag'
@@ -425,7 +465,12 @@ define [
 
 			window.location = path
 			
-		$scope.updateVisibleProjects()
+		if storedUIOpts?.filter?
+			if storedUIOpts.filter == "tag" and storedUIOpts.selectedTagId?
+				markTagAsSelected(storedUIOpts.selectedTagId)
+			$scope.setFilter(storedUIOpts.filter)
+		else
+			$scope.updateVisibleProjects()
 
 	App.controller "ProjectListItemController", ($scope) ->
 		$scope.ownerName = () ->

+ 5 - 1
services/web/public/coffee/main/project-list/tag-controllers.coffee

@@ -15,7 +15,11 @@ define [
 			$scope._clearTags()
 			tag.selected = true
 			$scope.setFilter("tag")
-		
+
+		$scope.selectUntagged = () ->
+			$scope._clearTags()
+			$scope.setFilter("untagged")
+
 		$scope.deleteTag = (tag) ->
 			modalInstance = $modal.open(
 				templateUrl: "deleteTagModalTemplate"

+ 30 - 2
services/web/public/stylesheets/app/project-list.less

@@ -124,6 +124,20 @@ ul.folders-menu {
 				}
 			}
 		}
+		&.untagged {
+			font-style: italic;
+			margin-bottom: @line-height-computed / 4;
+			a {
+				line-height: 1.7;
+				&:hover,
+				&:focus {
+					text-decoration: none;
+				}
+			}
+			span.subdued {
+				font-style: normal;
+			}
+		}
 		&:hover {
 			&:not(.active) {
 				background-color: darken(@gray-lightest, 2%);
@@ -246,10 +260,24 @@ ul.project-list {
 			margin-left: @line-height-computed / 4;
 			position: relative;
 			top: -2px;
-			padding-top: 0.25em;
 			display: inline-block;
-			color: white;
 		}
+			.tag-label-name,
+			.tag-label-remove {
+				display: inline-block;
+				padding-top: 0.3em;
+				color: #FFF;
+			}
+			.tag-label-name {
+				padding-right: 0.3em;
+				border-top-right-radius: 0;
+				border-bottom-right-radius: 0;	
+			}
+			.tag-label-remove {
+				padding-left: 0.3em;
+				border-top-left-radius: 0;
+				border-bottom-left-radius: 0;
+			}
 	}
 	i.tablesort {
 		padding-left: 8px;