diff --git a/app/coffee/modules/common/components.coffee b/app/coffee/modules/common/components.coffee
index ef71e14a..52ddac9e 100644
--- a/app/coffee/modules/common/components.coffee
+++ b/app/coffee/modules/common/components.coffee
@@ -422,6 +422,134 @@ DeleteButtonDirective = ($tgrepo, $confirm, $navurls, $location) ->
module.directive("tgDeleteButton", ["$tgRepo", "$tgConfirm", "$tgNavUrls", "$tgLocation", DeleteButtonDirective])
+#############################################################################
+## Editable subject directive
+#############################################################################
+
+EditableSubjectDirective = ($rootscope, $tgrepo, $confirm, $navurls, $location) ->
+ viewTemplate = _.template("""
+ <%- item.subject %>
+ <% if (canEdit) { %>
+
+ <% } %>
+ """)
+
+ editTemplate = _.template("""
+
+ """)
+
+ link = ($scope, $el, $attrs, $model) ->
+ editing = false
+ scope = $scope.$new()
+
+ render = ->
+ if editing
+ $el.html(editTemplate({item: scope.item}))
+ else
+ canEdit = $scope.project.my_permissions.indexOf($attrs.requiredPerm) != -1
+ $el.html(viewTemplate({item: scope.item, canEdit: canEdit}))
+
+ $scope.$watch $attrs.ngModel, (item) ->
+ return if not item
+ scope.item = item.clone()
+ scope.item.revert()
+ render()
+
+ $scope.$on "$destroy", ->
+ $el.off()
+
+ $el.click ->
+ if not editing and $scope.project.my_permissions.indexOf($attrs.requiredPerm) != -1
+ editing = true
+ render()
+ $el.find('input').focus()
+
+ $el.on "keyup", "input", ->
+ if event.keyCode == 13
+ scope.item.subject = $el.find('input').val()
+ $tgrepo.save(scope.item).then ->
+ $rootscope.$broadcast("history:reload")
+ editing = false
+ render()
+ else if event.keyCode == 27
+ editing = false
+ scope.item.revert()
+ render()
+
+ return {
+ link: link
+ restrict: "EA"
+ require: "ngModel"
+ }
+
+module.directive("tgEditableSubject", ["$rootScope", "$tgRepo", "$tgConfirm", "$tgNavUrls", "$tgLocation", EditableSubjectDirective])
+
+#############################################################################
+## Editable subject directive
+#############################################################################
+
+EditableDescriptionDirective = ($rootscope, $tgrepo, $confirm, $navurls, $location, $compile) ->
+ viewTemplate = _.template("""
+
+ <% if (canEdit) { %>
+
+ <% } %>
+ """)
+
+ editTemplate = _.template("""
+
+
+ """)
+
+ link = ($scope, $el, $attrs, $model) ->
+ editing = false
+ scope = $scope.$new()
+
+ render = ->
+ if editing
+ $el.html($compile(editTemplate({item: scope.item}))(scope))
+ else
+ canEdit = $scope.project.my_permissions.indexOf($attrs.requiredPerm) != -1
+ $el.html(viewTemplate({descriptionHtml: scope.item.description_html, canEdit: canEdit}))
+
+ $scope.$watch $attrs.ngModel, (item) ->
+ return if not item
+ scope.item = item.clone()
+ scope.item.revert()
+ render()
+
+ $scope.$on "$destroy", ->
+ $el.off()
+
+ $el.click ->
+ if not editing and $scope.project.my_permissions.indexOf($attrs.requiredPerm) != -1
+ editing = true
+ render()
+ $el.find('textarea').focus()
+
+ $el.on "click", ".save", ->
+ $tgrepo.save(scope.item).then ->
+ $rootscope.$broadcast("history:reload")
+ editing = false
+ render()
+
+ $el.on "keyup", "textarea", ->
+ if event.keyCode == 27
+ editing = false
+ scope.item.revert()
+ render()
+
+
+ return {
+ link: link
+ restrict: "EA"
+ require: "ngModel"
+ }
+
+module.directive("tgEditableDescription", ["$rootScope", "$tgRepo", "$tgConfirm", "$tgNavUrls", "$tgLocation", "$compile", EditableDescriptionDirective])
+
#############################################################################
## Common list directives
#############################################################################
diff --git a/app/partials/issues-detail.jade b/app/partials/issues-detail.jade
index 4e72b2fb..d1d348e8 100644
--- a/app/partials/issues-detail.jade
+++ b/app/partials/issues-detail.jade
@@ -14,7 +14,7 @@ block content
div.us-title(ng-class="{blocked: issue.is_blocked}")
h2.us-title-text
span.us-number(tg-bo-ref="issue.ref")
- span.us-name(ng-bind="issue.subject")
+ span.us-name(tg-editable-subject, ng-model="issue", required-perm="modify_issue")
p.us-related-task(ng-if="issue.generated_user_stories") This issue has been promoted to US:
a(ng-repeat="us in issue.generated_user_stories",
@@ -33,7 +33,7 @@ block content
div(tg-tag-line, editable="true", autosave-model="issue", ng-model="issue.tags")
- section.us-content.wysiwyg(tg-bind-html="issue.description_html")
+ section.us-content.wysiwyg(tg-editable-description, ng-model="issue", required-perm="modify_issue")
tg-attachments(ng-model="issue", type="issue")
tg-history(ng-model="issue", type="issue")
diff --git a/app/partials/task-detail.jade b/app/partials/task-detail.jade
index e1d6796c..59786dae 100644
--- a/app/partials/task-detail.jade
+++ b/app/partials/task-detail.jade
@@ -20,7 +20,7 @@ block content
div.us-title(ng-class="{blocked: task.is_blocked}")
h2.us-title-text
span.us-number(tg-bo-ref="task.ref")
- span.us-name(ng-bind="task.subject")
+ span.us-name(tg-editable-subject, ng-model="task", required-perm="modify_task")
h3.us-related-task This task belongs to
a(tg-check-permission="view_us", href="", title="Go to user story",
tg-nav="project-userstories-detail:project=project.slug, ref=us.ref",
@@ -36,7 +36,7 @@ block content
div(tg-tag-line, editable="true", autosave-model="task", ng-model="task.tags")
- section.us-content.wysiwyg(tg-bind-html="task.description_html")
+ section.us-content.wysiwyg(tg-editable-description, ng-model="task", required-perm="modify_task")
tg-attachments(ng-model="task", type="task")
tg-history(ng-model="task", type="task")
diff --git a/app/partials/us-detail.jade b/app/partials/us-detail.jade
index 0350c8c5..4c6393c9 100644
--- a/app/partials/us-detail.jade
+++ b/app/partials/us-detail.jade
@@ -20,7 +20,7 @@ block content
div.us-title(ng-class="{blocked: us.is_blocked}")
h2.us-title-text
span.us-number(tg-bo-ref="us.ref")
- span.us-name(ng-bind="us.subject")
+ span.us-name(tg-editable-subject, ng-model="us", required-perm="modify_us")
p.us-related-task(ng-if="us.origin_issue") This US has been promoted from Issue
a(tg-check-permission="view_us", href="", title="Go to issue",
@@ -38,7 +38,7 @@ block content
div(tg-tag-line, editable="true", autosave-model="us", ng-model="us.tags")
- section.us-content.wysiwyg(tg-bind-html="us.description_html")
+ section.us-content.wysiwyg(tg-editable-description, ng-model="us", required-perm="modify_us")
include views/modules/related-tasks