diff --git a/services/web/app/views/layout.jade b/services/web/app/views/layout.jade index 34188caa3f..ae5cf857d4 100644 --- a/services/web/app/views/layout.jade +++ b/services/web/app/views/layout.jade @@ -35,6 +35,7 @@ html(itemscope, itemtype='http://schema.org/Product') script(src=jsPath+'libs/angular-1.2.17.js') script(src=jsPath+'libs/moment.js') script(src=jsPath+'libs/bootstrap.js') + script(src=jsPath+'libs/ui-bootstrap-0.11.0.js') block scripts - if (typeof(bodyClasses) == "undefined") diff --git a/services/web/app/views/project/list.jade b/services/web/app/views/project/list.jade index 7e00e1874e..4cc1cbd598 100644 --- a/services/web/app/views/project/list.jade +++ b/services/web/app/views/project/list.jade @@ -10,10 +10,6 @@ block scripts script(src=jsPath+'project-list.js') block content - - script(type="text/x-handlebars", data-template-name="projects") - - .content.content-alt(ng-app="ProjectPageApp", ng-controller="ProjectPageController") .container .row @@ -53,9 +49,15 @@ block content //- a.menu-indent(href="#") Shared with you li h2 Folders - li(ng-repeat="tag in tags", ng-controller="TagListItemController", ng-class="{active: tag.selected}") + li( + ng-repeat="tag in tags", + ng-controller="TagListItemController", + ng-class="{active: tag.selected}" + ) a.menu-indent(href="#", ng-click="selectTag()") - i.icon.fa(ng-class="{'fa-folder-open-o': tag.selected, 'fa-folder-o': !tag.selected}") + i.icon.fa( + ng-class="{'fa-folder-open-o': tag.selected, 'fa-folder-o': !tag.selected}" + ) | {{tag.name}} span.small ({{tag.project_ids.length}}) @@ -76,29 +78,61 @@ block content .col-md-12 form.project-search.form-horizontal(role="form") .form-group.has-feedback.col-md-7 - input(placeholder='Search projects…', autofocus='autofocus', ng-model="searchText").form-control.col-md-7 + input.form-control.col-md-7( + placeholder='Search projects…', + autofocus='autofocus', + ng-model="searchText" + ) i.fa.fa-search.form-control-feedback //- i.fa.fa-remove .project-tools.js-toggle-tools .btn-toolbar .btn-group - a.btn.btn-default(href='#', data-toggle="tooltip", data-placement="bottom", title="", data-original-title="Download") + a.btn.btn-default( + href='#', + data-original-title="Download", + data-toggle="tooltip", + data-placement="bottom", + title="" + ) i.fa.fa-cloud-download - a.btn.btn-default(href='#', data-toggle="tooltip", data-placement="bottom", title="", data-original-title="Delete") + a.btn.btn-default( + href='#', + data-original-title="Delete", + data-toggle="tooltip", + data-placement="bottom", + title="" + ) i.fa.fa-trash-o .btn-group - a.btn.btn-default.dropdown-toggle(href="#", data-toggle="dropdown") + a.btn.btn-default.dropdown-toggle( + href="#", + data-toggle="dropdown" + ) i.fa.fa-folder-open-o | span.caret - ul.dropdown-menu.dropdown-menu-right(role="menu") + ul.dropdown-menu.dropdown-menu-right.js-tags-dropdown-menu( + role="menu" + ) li.dropdown-header Add to folder - li(ng-repeat="tag in tags", ng-controller="TagDropdownItemController") - a.menu-indent(href="#", ng-click="addOrRemoveProjectsFromTag()") - i.fa.fa-check(ng-if="areSelectedProjectsInTag") + li( + ng-repeat="tag in tags | orderBy:'name'", + ng-controller="TagDropdownItemController" + ) + a(href="#", ng-click="addOrRemoveProjectsFromTag()") + i.fa( + ng-class="{\ + 'fa-check-square-o': areSelectedProjectsInTag,\ + 'fa-square-o': !areSelectedProjectsInTag\ + }" + ) | {{tag.name}} + li.divider + li + a(href="#", ng-click="openNewTagModal()") Create New Folder .btn-group a.btn.btn-default.dropdown-toggle(data-toggle="dropdown", href="#") More @@ -126,7 +160,10 @@ block content span.owner OWNER .col-md-4 span.last-modified LAST MODIFIED - li.project_entry.container-fluid(ng-repeat="project in visibleProjects", ng-controller="ProjectListItemController") + li.project_entry.container-fluid( + ng-repeat="project in visibleProjects | orderBy:'lastUpdated':true", + ng-controller="ProjectListItemController" + ) .row .col-md-6 input.select-item(type="checkbox", ng-model="project.selected", ng-change="onSelectedChange()") @@ -148,3 +185,19 @@ block content | or a(href="/learn") help guides | . + + script(type='text/ng-template', id='newTagModalTemplate') + .modal-header + h3 Create New Folder + .modal-body + div {{inputs.newTagName}} + input.form-control( + type="text", + placeholder="New Folder Name", + ng-model="inputs.newTagName", + ng-enter="create()", + ng-focus-on="open" + ) + .modal-footer + button.btn.btn-default(ng-click="cancel()") Cancel + button.btn.btn-primary(ng-click="create()") Create \ No newline at end of file diff --git a/services/web/public/coffee/project-list.coffee b/services/web/public/coffee/project-list.coffee index 276c356cae..cab87097a1 100644 --- a/services/web/public/coffee/project-list.coffee +++ b/services/web/public/coffee/project-list.coffee @@ -1,10 +1,30 @@ -window.ProjectPageApp = angular.module("ProjectPageApp", []) +window.ProjectPageApp = angular.module("ProjectPageApp", ['ui.bootstrap']) + +$ () -> + $(".js-tags-dropdown-menu input, .js-tags-dropdown-menu a").click (e) -> + e.stopPropagation() + +ProjectPageApp.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() + +ProjectPageApp.directive 'ngFocusOn', ($timeout) -> + return { + restrict: 'AC' + link: (scope, element, attrs) -> + scope.$on attrs.ngFocusOn, () -> + element.focus() + } ProjectPageApp.filter "formatDate", () -> (date, format = "Do MMM YYYY, h:mm a") -> moment(date).format(format) -ProjectPageApp.controller "ProjectPageController", ($scope) -> +ProjectPageApp.controller "ProjectPageController", ($scope, $modal, $http) -> $scope.projects = window.data.projects $scope.visibleProjects = $scope.projects $scope.tags = window.data.tags @@ -45,7 +65,6 @@ ProjectPageApp.controller "ProjectPageController", ($scope) -> visible = false if visible $scope.visibleProjects.push project - console.log "visible", $scope.visibleProjects $scope.clearProjectSelections() $scope.getSelectedProjects = () -> @@ -59,6 +78,58 @@ ProjectPageApp.controller "ProjectPageController", ($scope) -> return tag if tag.selected return null + $scope.removeSelectedProjectsFromTag = (tag) -> + selected_project_ids = $scope.getSelectedProjectIds() + remaining_project_ids = [] + removed_project_ids = [] + for project_id in tag.project_ids + if project_id not in selected_project_ids + remaining_project_ids.push project_id + else + removed_project_ids.push project_id + tag.project_ids = remaining_project_ids + + for project_id in removed_project_ids + $http.post "/project/#{project_id}/tag", { + deletedTag: tag.name + _csrf: window.csrfToken + } + + # If we're filtering by this tag then we need to remove + # the projects from view + $scope.updateVisibleProjects() + + $scope.addSelectedProjectsToTag = (tag) -> + added_project_ids = [] + for project_id in $scope.getSelectedProjectIds() + unless project_id in tag.project_ids + tag.project_ids.push project_id + added_project_ids.push project_id + + for project_id in added_project_ids + # TODO Factor this out into another provider? + $http.post "/project/#{project_id}/tag", { + tag: tag.name + _csrf: window.csrfToken + } + + $scope.createTag = (name) -> + $scope.tags.push { + name: name + project_ids: [] + } + + $scope.openNewTagModal = () -> + modalInstance = $modal.open( + templateUrl: "newTagModalTemplate" + controller: "NewTagModalController" + ) + + modalInstance.result.then( + (newTagName) -> + $scope.createTag(newTagName) + ) + ProjectPageApp.controller "ProjectListItemController", ($scope) -> $scope.onSelectedChange = () -> $scope.$emit "selected:on-change" @@ -85,9 +156,8 @@ ProjectPageApp.controller "TagListItemController", ($scope) -> $scope.setActiveItem("tag") $scope.updateVisibleProjects() -ProjectPageApp.controller "TagDropdownItemController", ($scope, $http) -> +ProjectPageApp.controller "TagDropdownItemController", ($scope) -> $scope.$on "selection:change", (e, newValue, oldValue) -> - console.log "selected watch listen" $scope.recalculateProjectsInTag() $scope.recalculateProjectsInTag = () -> @@ -98,35 +168,24 @@ ProjectPageApp.controller "TagDropdownItemController", ($scope, $http) -> $scope.addOrRemoveProjectsFromTag = () -> if $scope.areSelectedProjectsInTag - $scope.removeSelectedProjectsFromTag() + $scope.removeSelectedProjectsFromTag($scope.tag) + $scope.areSelectedProjectsInTag = false else - $scope.addSelectedProjectsToTag() + $scope.addSelectedProjectsToTag($scope.tag) + $scope.areSelectedProjectsInTag = true - $scope.removeSelectedProjectsFromTag = () -> - selected_project_ids = $scope.getSelectedProjectIds() - remaining_project_ids = [] - removed_project_ids = [] - for project_id in $scope.tag.project_ids - if project_id not in selected_project_ids - remaining_project_ids.push project_id - else - removed_project_ids.push project_id - $scope.tag.project_ids = remaining_project_ids +ProjectPageApp.controller 'NewTagModalController', ($scope, $modalInstance, $timeout) -> + $scope.inputs = + newTagName: "original" - for project_id in removed_project_ids - $http.post "/project/#{project_id}/tag", { deletedTag: $scope.tag.name, _csrf: window.csrfToken } + $modalInstance.opened.then () -> + $timeout () -> + $scope.$broadcast "open" + , 700 - $scope.areSelectedProjectsInTag = false + $scope.create = () -> + console.log $scope.inputs.newTagName + $modalInstance.close($scope.inputs.newTagName) - $scope.addSelectedProjectsToTag = () -> - added_project_ids = [] - for project_id in $scope.getSelectedProjectIds() - unless project_id in $scope.tag.project_ids - $scope.tag.project_ids.push project_id - added_project_ids.push project_id - - for project_id in added_project_ids - # TODO Factor this out into another provider? - $http.post "/project/#{project_id}/tag", {tag: $scope.tag.name, _csrf: window.csrfToken} - - $scope.areSelectedProjectsInTag = true + $scope.cancel = () -> + $modalInstance.dismiss('cancel')