taiga-front/app/coffee/modules/search.coffee

258 lines
8.4 KiB
CoffeeScript

###
# Copyright (C) 2014 Andrey Antukh <niwi@niwi.be>
# Copyright (C) 2014 Jesús Espino Garcia <jespinog@gmail.com>
# Copyright (C) 2014 David Barragán Merino <bameda@dbarragan.com>
#
# 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 <http://www.gnu.org/licenses/>.
#
# File: modules/search.coffee
###
taiga = @.taiga
groupBy = @.taiga.groupBy
bindOnce = @.taiga.bindOnce
mixOf = @.taiga.mixOf
debounceLeading = @.taiga.debounceLeading
trim = @.taiga.trim
debounce = @.taiga.debounce
module = angular.module("taigaSearch", [])
#############################################################################
## Search Controller
#############################################################################
class SearchController extends mixOf(taiga.Controller, taiga.PageMixin)
@.$inject = [
"$scope",
"$tgRepo",
"$tgResources",
"$routeParams",
"$q",
"$tgLocation",
"tgAppMetaService",
"$tgNavUrls",
"$translate"
]
constructor: (@scope, @repo, @rs, @params, @q, @location, @appMetaService, @navUrls, @translate) ->
@scope.sectionName = "Search"
promise = @.loadInitialData()
promise.then () =>
title = @translate.instant("SEARCH.PAGE_TITLE", {projectName: @scope.project.name})
description = @translate.instant("SEARCH.PAGE_DESCRIPTION", {
projectName: @scope.project.name,
projectDescription: @scope.project.description
})
@appMetaService.setAll(title, description)
promise.then null, @.onInitialDataError.bind(@)
# Search input watcher
@scope.searchTerm = ""
loadSearchData = debounceLeading(100, (t) => @.loadSearchData(t))
@scope.$watch "searchTerm", (term) =>
if term
loadSearchData(term)
loadFilters: ->
defered = @q.defer()
defered.resolve()
return defered.promise
loadProject: ->
return @rs.projects.getBySlug(@params.pslug).then (project) =>
@scope.project = project
@scope.$emit('project:loaded', project)
@scope.issueStatusById = groupBy(project.issue_statuses, (x) -> x.id)
@scope.taskStatusById = groupBy(project.task_statuses, (x) -> x.id)
@scope.severityById = groupBy(project.severities, (x) -> x.id)
@scope.priorityById = groupBy(project.priorities, (x) -> x.id)
@scope.membersById = groupBy(project.memberships, (x) -> x.user)
@scope.usStatusById = groupBy(project.us_statuses, (x) -> x.id)
return project
loadSearchData: (term) ->
promise = @rs.search.do(@scope.projectId, term).then (data) =>
@scope.searchResults = data
return data
return promise
loadInitialData: ->
return @.loadProject().then (project) =>
@scope.projectId = project.id
@.fillUsersAndRoles(project.users, project.roles)
module.controller("SearchController", SearchController)
#############################################################################
## Search box directive
#############################################################################
SearchBoxDirective = (projectService, $lightboxService, $navurls, $location, $route)->
link = ($scope, $el, $attrs) ->
project = null
submit = debounce 2000, (event) =>
event.preventDefault()
form = $el.find("form").checksley()
if not form.validate()
return
text = $el.find("#search-text").val()
url = $navurls.resolve("project-search", {project: project.get("slug")})
$scope.$apply ->
$lightboxService.close($el)
$location.path(url)
$location.search("text", text).path(url)
$route.reload()
openLightbox = () ->
project = projectService.project
$lightboxService.open($el).then () ->
$el.find("#search-text").focus()
$el.on "submit", "form", submit
openLightbox()
return {
templateUrl: "search/lightbox-search.html",
link:link
}
SearchBoxDirective.$inject = [
"tgProjectService",
"lightboxService",
"$tgNavUrls",
"$tgLocation",
"$route"
]
module.directive("tgSearchBox", SearchBoxDirective)
#############################################################################
## Search Directive
#############################################################################
SearchDirective = ($log, $compile, $templatecache, $routeparams, $location) ->
linkTable = ($scope, $el, $attrs, $ctrl) ->
tabsDom = $el.find("section.search-filter")
lastSeatchResults = null
getActiveSection = (data) ->
maxVal = 0
selectedSectionName = null
selectedSectionData = null
if data
for name in ["userstories", "issues", "tasks", "wikipages"]
value = data[name]
if value.length > maxVal
maxVal = value.length
selectedSectionName = name
selectedSectionData = value
break;
if maxVal == 0
return {name: "userstories", value: []}
return {name:selectedSectionName, value: selectedSectionData}
renderFilterTabs = (data) ->
for name, value of data
continue if name == "count"
tabsDom.find("li.#{name} .num").html(value.length)
markSectionTabActive = (section) ->
# Mark as active the item with max amount of results
tabsDom.find("a.active").removeClass("active")
tabsDom.find("li.#{section.name} a").addClass("active")
templates = {
issues: $templatecache.get("search-issues")
tasks: $templatecache.get("search-tasks")
userstories: $templatecache.get("search-userstories")
wikipages: $templatecache.get("search-wikipages")
}
renderTableContent = (section) ->
oldElements = $el.find(".search-result-table").children()
oldScope = oldElements.scope()
if oldScope
oldScope.$destroy()
oldElements.remove()
scope = $scope.$new()
scope[section.name] = section.value
template = angular.element.parseHTML(trim(templates[section.name]))
element = $compile(template)(scope)
$el.find(".search-result-table").html(element)
$scope.$watch "searchResults", (data) ->
lastSeatchResults = data
activeSection = getActiveSection(data)
renderFilterTabs(data)
renderTableContent(activeSection)
markSectionTabActive(activeSection)
$scope.$watch "searchTerm", (searchTerm) ->
$location.search("text", searchTerm) if searchTerm
$el.on "click", ".search-filter li > a", (event) ->
event.preventDefault()
target = angular.element(event.currentTarget)
sectionName = target.parent().data("name")
sectionData = lastSeatchResults[sectionName]
section = {
name: sectionName,
value: sectionData
}
$scope.$apply ->
renderTableContent(section)
markSectionTabActive(section)
link = ($scope, $el, $attrs) ->
$ctrl = $el.controller()
linkTable($scope, $el, $attrs, $ctrl)
searchText = $routeparams.text
$scope.$watch "projectId", (projectId) ->
$scope.searchTerm = searchText if projectId?
return {link:link}
module.directive("tgSearch", ["$log", "$compile", "$templateCache", "$routeParams", "$tgLocation",
SearchDirective])