### # Copyright (C) 2014 Andrey Antukh # Copyright (C) 2014 Jesús Espino Garcia # Copyright (C) 2014 David Barragán Merino # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as # published by the Free Software Foundation, either version 3 of the # License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . # # File: modules/admin/memberships.coffee ### taiga = @.taiga mixOf = @.taiga.mixOf module = angular.module("taigaAdmin") ############################################################################# ## Project Memberships Controller ############################################################################# class MembershipsController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.FiltersMixin) @.$inject = [ "$scope", "$rootScope", "$tgRepo", "$tgConfirm", "$tgResources", "$routeParams", "$q", "$location" ] constructor: (@scope, @rootscope, @repo, @confirm, @rs, @params, @q, @location) -> _.bindAll(@) @scope.sectionName = "Memberships" #i18n @scope.project = {} @scope.filters = {} promise = @.loadInitialData() promise.then null, -> console.log "FAIL" #TODO @scope.$on("membersform:new:success", @.loadMembers) loadProject: -> return @rs.projects.get(@scope.projectId).then (project) => @scope.project = project return project loadMembers: -> httpFilters = @.getUrlFilters() return @rs.memberships.list(@scope.projectId, httpFilters).then (data) => @scope.memberships = data.models @scope.page = data.current @scope.count = data.count @scope.paginatedBy = data.paginatedBy return data loadInitialData: -> promise = @repo.resolve({pslug: @params.pslug}).then (data) => @scope.projectId = data.project return data return promise.then(=> @.loadProject()) .then(=> @.loadUsersAndRoles()) .then(=> @.loadMembers()) getUrlFilters: -> filters = _.pick(@location.search(), "page") filters.page = 1 if not filters.page return filters addNewMembers: -> @rootscope.$broadcast("membersform:new") module.controller("MembershipsController", MembershipsController) ############################################################################# ## Member Avatar Directive ############################################################################# paginatorTemplate = """
    <% if (showPrevious) { %> <% } %> <% _.each(pages, function(item) { %>
  • <% if (item.type === "page") { %> <%= item.num %> <% } else if (item.type === "page-active") { %> <%= item.num %> <% } else { %> ... <% } %>
  • <% }); %> <% if (showNext) { %> <% } %>
""" MembershipsDirective = -> template = _.template(paginatorTemplate) linkPagination = ($scope, $el, $attrs, $ctrl) -> # Constants afterCurrent = 2 beforeCurrent = 4 atBegin = 2 atEnd = 2 $pagEl = $el.find(".memberships-paginator") getNumPages = -> numPages = $scope.count / $scope.paginatedBy if parseInt(numPages, 10) < numPages numPages = parseInt(numPages, 10) + 1 else numPages = parseInt(numPages, 10) return numPages renderPagination = -> numPages = getNumPages() if numPages <= 1 $pagEl.hide() return pages = [] options = {} options.pages = pages options.showPrevious = ($scope.page > 1) options.showNext = not ($scope.page == numPages) cpage = $scope.page for i in [1..numPages] if i == (cpage + afterCurrent) and numPages > (cpage + afterCurrent + atEnd) pages.push({classes: "dots", type: "dots"}) else if i == (cpage - beforeCurrent) and cpage > (atBegin + beforeCurrent) pages.push({classes: "dots", type: "dots"}) else if i > (cpage + afterCurrent) and i <= (numPages - atEnd) else if i < (cpage - beforeCurrent) and i > atBegin else if i == cpage pages.push({classes: "active", num: i, type: "page-active"}) else pages.push({classes: "page", num: i, type: "page"}) $pagEl.html(template(options)) $scope.$watch "memberships", (value) -> # Do nothing if value is not logical true return if not value renderPagination() $el.on "click", ".memberships-paginator a.next", (event) -> event.preventDefault() $scope.$apply -> $ctrl.selectFilter("page", $scope.page + 1) $ctrl.loadMembers() $el.on "click", ".memberships-paginator a.previous", (event) -> event.preventDefault() $scope.$apply -> $ctrl.selectFilter("page", $scope.page - 1) $ctrl.loadMembers() $el.on "click", ".memberships-paginator li.page > a", (event) -> event.preventDefault() target = angular.element(event.currentTarget) pagenum = target.data("pagenum") $scope.$apply -> $ctrl.selectFilter("page", pagenum) $ctrl.loadMembers() link = ($scope, $el, $attrs) -> $ctrl = $el.controller() linkPagination($scope, $el, $attrs, $ctrl) $scope.$on "$destroy", -> $el.off() return {link:link} module.directive("tgMemberships", MembershipsDirective) ############################################################################# ## Member Avatar Directive ############################################################################# MembershipsRowAvatarDirective = ($log) -> template = _.template("""
<%- full_name %>
<%- full_name %>
""") link = ($scope, $el, $attrs) -> render = (member) -> ctx = { full_name: if member.full_name then member.full_name else "" email: member.email imgurl: if member.photo then member.photo else "/image/unnamed.png" } html = template(ctx) $el.html(html) if not $attrs.tgMembershipsRowAvatar? return $log.error "MembershipsRowAvatarDirective: the directive need a member" member = $scope.$eval($attrs.tgMembershipsRowAvatar) render(member) $scope.$on "$destroy", -> $el.off() return {link: link} module.directive("tgMembershipsRowAvatar", ["$log", MembershipsRowAvatarDirective]) ############################################################################# ## Member Actions Directive ############################################################################# MembershipsRowActionsDirective = ($log, $repo, $confirm) -> activedTemplate = _.template("""
Active
""") # i18n pendingTemplate = _.template(""" Pending """) # i18n link = ($scope, $el, $attrs) -> render = (member) -> if member.user html = activedTemplate() else html = pendingTemplate() $el.html(html) if not $attrs.tgMembershipsRowActions? return $log.error "MembershipsRowActionsDirective: the directive need a member" $ctrl = $el.controller() member = $scope.$eval($attrs.tgMembershipsRowActions) render(member) $el.on "click", ".pending", (event) -> event.preventDefault() #TODO: Re-send the invitation console.log "re-sending the invitation to #{member.email}" $el.on "click", ".delete", (event) -> event.preventDefault() title = "Delete member" # i18n subtitle = if member.user then member.full_name else "the invitation to #{member.email}" # i18n $confirm.ask(title, subtitle).then -> $repo.remove(member).then -> $ctrl.loadMembers() $confirm.notify("success", null, "We've deleted #{subtitle}.") # i18n $scope.$on "$destroy", -> $el.off() return {link: link} module.directive("tgMembershipsRowActions", ["$log", "$tgRepo", "$tgConfirm", MembershipsRowActionsDirective]) ############################################################################# ## Member IsAdminCheckbox Directive ############################################################################# MembershipsRowAdminCheckboxDirective = ($log, $repo, $confirm) -> template = _.template(""" """) # i18n link = ($scope, $el, $attrs) -> render = (member) -> ctx = {inputId: "is-admin-#{member.id}"} html = template(ctx) $el.html(html) if not $attrs.tgMembershipsRowAdminCheckbox? return $log.error "MembershipsRowAdminCheckboxDirective: the directive need a member" member = $scope.$eval($attrs.tgMembershipsRowAdminCheckbox) html = render(member) if member.is_admin $el.find(":checkbox").prop("checked", true) $el.on "click", ":checkbox", (event) => onSuccess = -> $confirm.notify("success") onError = -> $confirm.notify("error") target = angular.element(event.currentTarget) member.is_admin = target.prop("checked") $repo.save(member).then(onSuccess, onError) $scope.$on "$destroy", -> $el.off() return {link: link} module.directive("tgMembershipsRowAdminCheckbox", ["$log", "$tgRepo", "$tgConfirm", MembershipsRowAdminCheckboxDirective]) ############################################################################# ## Member RoleSelector Directive ############################################################################# MembershipsRowRoleSelectorDirective = ($log, $repo, $confirm) -> template = _.template(""" """) link = ($scope, $el, $attrs) -> render = (member) -> ctx = { roleList: $scope.roles, selectedRole: member.role } html = template(ctx) $el.html(html) if not $attrs.tgMembershipsRowRoleSelector? return $log.error "MembershipsRowRoleSelectorDirective: the directive need a member" $ctrl = $el.controller() member = $scope.$eval($attrs.tgMembershipsRowRoleSelector) html = render(member) $el.on "click", "select", (event) => onSuccess = -> $confirm.notify("success") onError = -> $confirm.notify("error") target = angular.element(event.currentTarget) newRole = parseInt(target.val(), 10) if member.role != newRole member.role = newRole $repo.save(member).then(onSuccess, onError) $scope.$on "$destroy", -> $el.off() return {link: link} module.directive("tgMembershipsRowRoleSelector", ["$log", "$tgRepo", "$tgConfirm", MembershipsRowRoleSelectorDirective])