diff --git a/app/coffee/modules/backlog/main.coffee b/app/coffee/modules/backlog/main.coffee
index 301a1f3a..9c95771d 100644
--- a/app/coffee/modules/backlog/main.coffee
+++ b/app/coffee/modules/backlog/main.coffee
@@ -137,6 +137,7 @@ class BacklogController extends mixOf(taiga.Controller, taiga.PageMixin)
@rootscope.$broadcast("usform:edit", us)
deleteUserStory: (us) ->
+ #TODO: i18n
title = "Delete User Story"
subtitle = us.subject
@@ -446,7 +447,7 @@ BacklogSprintDirective = ($repo) ->
itemScope.$destroy()
dom = $el.find(".sprint-table")
-
+
sortable = new Sortable(dom[0], {
group: "backlog",
selector: ".milestone-us-item-row",
diff --git a/app/coffee/modules/base/bind.coffee b/app/coffee/modules/base/bind.coffee
index 04f6787c..d316a62e 100644
--- a/app/coffee/modules/base/bind.coffee
+++ b/app/coffee/modules/base/bind.coffee
@@ -36,6 +36,26 @@ BindOnceRefDirective = ->
$el.html("##{val} ")
return {link:link}
+# Object src bind once helper.
+BindOnceSrcDirective = ->
+ link = ($scope, $el, $attrs) ->
+ bindOnce $scope, $attrs.tgBoSrc, (val) ->
+ $el.attr("src", val)
+ return {link:link}
+
+# Object alt bind once helper.
+BindOnceAltDirective = ->
+ link = ($scope, $el, $attrs) ->
+ bindOnce $scope, $attrs.tgBoAlt, (val) ->
+ $el.attr("alt", val)
+ return {link:link}
+
+# Object title bind once helper.
+BindOnceTitleDirective = ->
+ link = ($scope, $el, $attrs) ->
+ bindOnce $scope, $attrs.tgBoTitle, (val) ->
+ $el.attr("title", val)
+ return {link:link}
BindHtmlDirective = ->
link = ($scope, $el, $attrs) ->
@@ -48,4 +68,7 @@ BindHtmlDirective = ->
module = angular.module("taigaBase")
module.directive("tgBoHtml", BindOnceHtmlDirective)
module.directive("tgBoRef", BindOnceRefDirective)
+module.directive("tgBoSrc", BindOnceSrcDirective)
+module.directive("tgBoAlt", BindOnceAltDirective)
+module.directive("tgBoTitle", BindOnceTitleDirective)
module.directive("tgBindHtml", BindHtmlDirective)
diff --git a/app/coffee/modules/issues/detail.coffee b/app/coffee/modules/issues/detail.coffee
index 088bf038..108a4246 100644
--- a/app/coffee/modules/issues/detail.coffee
+++ b/app/coffee/modules/issues/detail.coffee
@@ -168,3 +168,78 @@ TagLineDirective = ($log) ->
}
module.directive("tgTagLine", ["$log", TagLineDirective])
+
+#############################################################################
+## Watchers directive
+#############################################################################
+
+WatchersDirective = ($rootscope, $confirm) ->
+ #TODO: i18n
+ template = _.template("""
+
""")
+
+ renderWatchers = ($scope, $el, watcherIds, editable) ->
+ watchers = _.map(watcherIds, (watcherId) -> $scope.usersById[watcherId])
+ html = template({watchers: watchers, editable:editable})
+ $el.html(html)
+
+ link = ($scope, $el, $attrs, $model) ->
+ editable = $attrs.editable?
+ watcherIds = []
+ $scope.$watch $attrs.ngModel, (val) ->
+ watcherIds = val
+ if watcherIds?
+ renderWatchers($scope, $el, watcherIds, editable)
+
+ if not editable
+ $el.find(".add-watcher").remove()
+
+ $el.on "click", ".icon-delete", (event) ->
+ event.preventDefault()
+ target = angular.element(event.currentTarget)
+ watcherId = target.data("watcher-id")
+ title = "Remove watcher"
+ subtitle = $scope.usersById[watcherId].full_name_display
+ $confirm.ask(title, subtitle).then =>
+ watcherIds = _.pull(watcherIds, watcherId)
+ $attrs.ngModel = watcherIds
+ renderWatchers($scope, $el, watcherIds, editable)
+
+ $el.on "click", ".add-watcher", (event) ->
+ event.preventDefault()
+ target = angular.element(event.currentTarget)
+ $rootscope.$broadcast("watcher:add")
+
+ $scope.$on "watcher:added", (ctx, watcher) ->
+ watcherIds.push(watcher.id)
+ watcherIds = _.uniq(watcherIds)
+ $attrs.ngModel = watcherIds
+ renderWatchers($scope, $el, watcherIds, editable)
+
+ return {link:link, require:"ngModel"}
+
+module.directive("tgWatchers", ["$rootScope", "$tgConfirm", WatchersDirective])
diff --git a/app/coffee/modules/issues/lightboxes.coffee b/app/coffee/modules/issues/lightboxes.coffee
index 9556f1e5..51ac7530 100644
--- a/app/coffee/modules/issues/lightboxes.coffee
+++ b/app/coffee/modules/issues/lightboxes.coffee
@@ -45,3 +45,29 @@ module.directive("tgLbCreateIssue", [
"$rootScope",
CreateIssueDirective
])
+
+AddWatcherDirective = () ->
+ link = ($scope, $el, $attrs) ->
+ $scope.watcherSearch = {}
+ $scope.$on "watcher:add", ->
+ $el.removeClass("hidden")
+ $scope.$apply ->
+ $scope.watcherSearch = {}
+
+ $scope.$on "$destroy", ->
+ $el.off()
+
+ $el.on "click", ".close", (event) ->
+ event.preventDefault()
+ $el.addClass("hidden")
+
+ $el.on "click", ".watcher-single", (event) ->
+ event.preventDefault()
+ target = angular.element(event.currentTarget)
+ watcher = target.scope().user
+ $el.addClass("hidden")
+ $scope.$broadcast("watcher:added", watcher)
+
+ return {link:link}
+
+module.directive("tgLbAddWatcher", AddWatcherDirective)
diff --git a/app/partials/issues-detail.jade b/app/partials/issues-detail.jade
index 89c6334c..5cf98e2f 100644
--- a/app/partials/issues-detail.jade
+++ b/app/partials/issues-detail.jade
@@ -22,7 +22,7 @@ block content
// p We need Pilar to make a prototype out of this or we are not sure
// a.button.button-red.button-block(href="", title="Unblock US") Unblock
- div.user-story-tags(tg-tag-line editable="true", ng-model="issue.tags")
+ div.user-story-tags(tg-tag-line, ng-model="issue.tags")
section.us-content(tg-bind-html="issue.description_html")
@@ -61,8 +61,7 @@ block content
span.role UX
include views/components/assigned-to
- section.watchers
- include views/components/watchers
+ section.watchers(tg-watchers, ng-model="issue.watchers")
// NOTE: only for user story?
// section.us-detail-settings
@@ -70,8 +69,8 @@ block content
// a.button.button-gray(href="", title="Team requirement") Team requirement
// a.button.button-red(href="", title="Block") Block
- div.lightbox.lightbox_block.hidden
- include views/modules/lightbox_block
+ div.lightbox.lightbox_block.hidden
+ include views/modules/lightbox_block
- div.lightbox.lightbox_watchers.hidden
- include views/modules/lightbox_watchers
+ div.lightbox.lightbox_watchers.hidden(tg-lb-add-watcher)
+ include views/modules/lightbox_watchers
diff --git a/app/partials/views/modules/lightbox_watchers.jade b/app/partials/views/modules/lightbox_watchers.jade
index 48680e13..ebbd845f 100644
--- a/app/partials/views/modules/lightbox_watchers.jade
+++ b/app/partials/views/modules/lightbox_watchers.jade
@@ -3,14 +3,14 @@ a.close(href="", title="close")
form
h2.title Add watchers
fieldset
- input(type="text", data-maxlength="500", placeholder="Search for users")
+ input(type="text", data-maxlength="500", placeholder="Search for users", ng-model="watcherSearch.$")
div.watchers
- - for(var y=0; y<5; y++)
- div.watcher-single
- div.watcher-avatar
- a.avatar(href="", title="Assigned to")
- img(src="http://thecodeplayer.com/u/uifaces/32.jpg", alt="username")
- a.watcher-name(href="", title="Jesús Espino") Jesús
+ div.watcher-single(ng-repeat="user in users|filter:watcherSearch:strict|limitTo:5 track by user.id")
+ div.watcher-avatar
+ a.avatar(href="", title="Assigned to")
+ img(tg-bo-src="user.photo", tg-bo-alt="user.photo")
+ a.watcher-name(href="", tg-bo-title="user.full_name_display", tg-bo-html="user.full_name_display")
+
div.more-watchers
- span ...too many users, keep filtering
\ No newline at end of file
+ span ...too many users, keep filtering