Convert tg-tag-line in two directives
parent
5952ab306b
commit
5a73910a89
|
@ -93,89 +93,274 @@ ColorizeTagsDirective = ->
|
||||||
|
|
||||||
module.directive("tgColorizeTags", ColorizeTagsDirective)
|
module.directive("tgColorizeTags", ColorizeTagsDirective)
|
||||||
|
|
||||||
|
|
||||||
#############################################################################
|
#############################################################################
|
||||||
## TagLine (possible should be moved as generic directive)
|
## TagLine Directive (for Lightboxes)
|
||||||
#############################################################################
|
#############################################################################
|
||||||
|
|
||||||
TagLineDirective = ($rootscope, $log, $rs, $tgrepo, $confirm) ->
|
LbTagLineDirective = ($rs) ->
|
||||||
# Main directive template (rendered by angular)
|
ENTER_KEY = 13
|
||||||
|
|
||||||
template = """
|
template = """
|
||||||
<div class="tags-container"></div>
|
<div class="tags-container"></div>
|
||||||
<a href="#" class="add-tag" title="Add tag">
|
|
||||||
<span class="icon icon-plus"></span>
|
|
||||||
<span class="add-tag-text">Add tag</span>
|
|
||||||
</a>
|
|
||||||
<input type="text" placeholder="Write tag..." class="tag-input" />
|
<input type="text" placeholder="Write tag..." class="tag-input" />
|
||||||
<a href="" title="Save" class="save icon icon-floppy"></a>
|
<a href="" title="Save" class="save icon icon-floppy hidden"></a>
|
||||||
"""
|
""" # TODO: i18n
|
||||||
|
|
||||||
# Tags template (rendered manually using lodash)
|
# Tags template (rendered manually using lodash)
|
||||||
templateTags = _.template("""
|
templateTags = _.template("""
|
||||||
<% _.each(tags, function(tag) { %>
|
<% _.each(tags, function(tag) { %>
|
||||||
<span class="tag" style="border-left: 5px solid <%- tag.color %>;">
|
<span class="tag" style="border-left: 5px solid <%- tag.color %>;">
|
||||||
<span class="tag-name"><%- tag.name %></span>
|
<span class="tag-name"><%- tag.name %></span>
|
||||||
<% if (editable) { %>
|
|
||||||
<a href="" title="delete tag" class="icon icon-delete"></a>
|
<a href="" title="delete tag" class="icon icon-delete"></a>
|
||||||
<% } %>
|
|
||||||
</span>
|
</span>
|
||||||
<% }); %>""")
|
<% }); %>
|
||||||
|
""") # TODO: i18n
|
||||||
|
|
||||||
link = ($scope, $el, $attrs, $model) ->
|
link = ($scope, $el, $attrs, $model) ->
|
||||||
editable = false
|
renderTags = (tags, tagsColors) ->
|
||||||
|
|
||||||
$el.addClass("tags-block")
|
|
||||||
$el.find("input").hide()
|
|
||||||
|
|
||||||
renderTags = ($el, tags, editable, tagsColors) ->
|
|
||||||
ctx = {
|
ctx = {
|
||||||
tags: _.map(tags, (t) -> {name: t, color: tagsColors[t]})
|
tags: _.map(tags, (t) -> {name: t, color: tagsColors[t]})
|
||||||
editable: editable
|
|
||||||
}
|
}
|
||||||
html = templateTags(ctx)
|
html = templateTags(ctx)
|
||||||
$el.find("div.tags-container").html(html)
|
$el.find("div.tags-container").html(html)
|
||||||
|
|
||||||
normalizeTags = (tags) ->
|
showSaveButton = -> $el.find(".save").removeClass("hidden")
|
||||||
tags = _.map(tags, trim)
|
hideSaveButton = -> $el.find(".save").addClass("hidden")
|
||||||
tags = _.map(tags, (x) -> x.toLowerCase())
|
|
||||||
return _.uniq(tags)
|
resetInput = ->
|
||||||
|
$el.find("input").val("")
|
||||||
|
$el.find("input").autocomplete("close")
|
||||||
|
|
||||||
addValue = (value) ->
|
addValue = (value) ->
|
||||||
value = trim(value)
|
value = trim(value.toLowerCase())
|
||||||
return if value.length <= 0
|
return if value.length == 0
|
||||||
|
|
||||||
tags = _.clone($model.$modelValue, false)
|
tags = _.clone($model.$modelValue, false)
|
||||||
tags = [] if not tags?
|
tags = [] if not tags?
|
||||||
tags.push(value)
|
tags.push(value) if value not in tags
|
||||||
|
|
||||||
$scope.$apply ->
|
$scope.$apply ->
|
||||||
$model.$setViewValue(normalizeTags(tags))
|
$model.$setViewValue(tags)
|
||||||
autosaveModel = $scope.$eval($attrs.autosaveModel)
|
|
||||||
if autosaveModel
|
|
||||||
promise = $tgrepo.save(autosaveModel)
|
|
||||||
promise.then ->
|
|
||||||
$rootscope.$broadcast("history:reload")
|
|
||||||
promise.then null, ->
|
|
||||||
$confirm.notify("error")
|
|
||||||
|
|
||||||
saveInputTag = () ->
|
saveInputTag = () ->
|
||||||
input = $el.find('input')
|
value = $el.find("input").val()
|
||||||
|
|
||||||
addValue(input.val())
|
addValue(value)
|
||||||
input.val("")
|
resetInput()
|
||||||
input.autocomplete("close")
|
hideSaveButton()
|
||||||
$el.find('.save').hide()
|
|
||||||
|
$el.on "keypress", "input", (event) ->
|
||||||
|
return if event.keyCode != ENTER_KEY
|
||||||
|
event.preventDefault()
|
||||||
|
|
||||||
|
$el.on "keyup", "input", (event) ->
|
||||||
|
target = angular.element(event.currentTarget)
|
||||||
|
|
||||||
|
if event.keyCode == ENTER_KEY
|
||||||
|
saveInputTag()
|
||||||
|
else
|
||||||
|
if target.val().length
|
||||||
|
showSaveButton()
|
||||||
|
else
|
||||||
|
hideSaveButton()
|
||||||
|
|
||||||
|
$el.on "click", ".save", (event) ->
|
||||||
|
event.preventDefault()
|
||||||
|
saveInputTag
|
||||||
|
|
||||||
|
$el.on "click", ".icon-delete", (event) ->
|
||||||
|
event.preventDefault()
|
||||||
|
target = angular.element(event.currentTarget)
|
||||||
|
|
||||||
|
value = target.siblings(".tag-name").text()
|
||||||
|
tags = _.clone($model.$modelValue, false)
|
||||||
|
tags = _.pull(tags, value)
|
||||||
|
|
||||||
|
$scope.$apply ->
|
||||||
|
$model.$setViewValue(tags)
|
||||||
|
|
||||||
bindOnce $scope, "project", (project) ->
|
bindOnce $scope, "project", (project) ->
|
||||||
# If not editable, no tags preloading is needed.
|
positioningFunction = (position, elements) ->
|
||||||
editable = project.my_permissions.indexOf($attrs.requiredPerm) != -1
|
menu = elements.element.element
|
||||||
|
menu.css("width", elements.target.width)
|
||||||
|
menu.css("top", position.top)
|
||||||
|
menu.css("left", position.left)
|
||||||
|
|
||||||
if not $scope.$eval($attrs.autosaveModel)?
|
$rs.projects.tags(project.id).then (data) ->
|
||||||
$el.find("a.save").remove()
|
$el.find("input").autocomplete({
|
||||||
|
source: data
|
||||||
|
position: {
|
||||||
|
my: "left top",
|
||||||
|
using: positioningFunction
|
||||||
|
}
|
||||||
|
select: (event, ui) ->
|
||||||
|
addValue(ui.item.value)
|
||||||
|
ui.item.value = ""
|
||||||
|
})
|
||||||
|
|
||||||
if not editable
|
$scope.$watch $attrs.ngModel, (tags) ->
|
||||||
|
tagsColors = $scope.project?.tags_colors or []
|
||||||
|
renderTags(tags, tagsColors)
|
||||||
|
|
||||||
|
$scope.$on "$destroy", ->
|
||||||
|
$el.off()
|
||||||
|
|
||||||
|
return {
|
||||||
|
link:link,
|
||||||
|
require:"ngModel"
|
||||||
|
template: template
|
||||||
|
}
|
||||||
|
|
||||||
|
module.directive("tgLbTagLine", ["$tgResources", LbTagLineDirective])
|
||||||
|
|
||||||
|
|
||||||
|
#############################################################################
|
||||||
|
## TagLine Directive (for detail pages)
|
||||||
|
#############################################################################
|
||||||
|
|
||||||
|
TagLineDirective = ($rootScope, $repo, $rs, $confirm) ->
|
||||||
|
ENTER_KEY = 13
|
||||||
|
ESC_KEY = 27
|
||||||
|
|
||||||
|
template = """
|
||||||
|
<div class="tags-container"></div>
|
||||||
|
<a href="#" class="add-tag hidden" title="Add tag">
|
||||||
|
<span class="icon icon-plus"></span>
|
||||||
|
<span class="add-tag-text">Add tag</span>
|
||||||
|
</a>
|
||||||
|
<input type="text" placeholder="Write tag..." class="tag-input hidden" />
|
||||||
|
<a href="" title="Save" class="save icon icon-floppy hidden"></a>
|
||||||
|
""" # TODO: i18n
|
||||||
|
|
||||||
|
# Tags template (rendered manually using lodash)
|
||||||
|
templateTags = _.template("""
|
||||||
|
<% _.each(tags, function(tag) { %>
|
||||||
|
<span class="tag" style="border-left: 5px solid <%- tag.color %>;">
|
||||||
|
<span class="tag-name"><%- tag.name %></span>
|
||||||
|
<% if (isEditable) { %>
|
||||||
|
<a href="" title="delete tag" class="icon icon-delete"></a>
|
||||||
|
<% } %>
|
||||||
|
</span>
|
||||||
|
<% }); %>
|
||||||
|
""") # TODO: i18n
|
||||||
|
|
||||||
|
link = ($scope, $el, $attrs, $model) ->
|
||||||
|
isEditable = ->
|
||||||
|
return $scope.project.my_permissions.indexOf($attrs.requiredPerm) != -1
|
||||||
|
|
||||||
|
renderTags = (tags, tagsColors) ->
|
||||||
|
ctx = {
|
||||||
|
tags: _.map(tags, (t) -> {name: t, color: tagsColors[t]})
|
||||||
|
isEditable: isEditable()
|
||||||
|
}
|
||||||
|
html = templateTags(ctx)
|
||||||
|
$el.find("div.tags-container").html(html)
|
||||||
|
|
||||||
|
renderInReadModeOnly = ->
|
||||||
|
$el.find(".add-tag").remove()
|
||||||
$el.find("input").remove()
|
$el.find("input").remove()
|
||||||
|
$el.find(".save").remove()
|
||||||
|
|
||||||
|
showAddTagButton = -> $el.find(".add-tag").removeClass("hidden")
|
||||||
|
hideAddTagButton = -> $el.find(".add-tag").addClass("hidden")
|
||||||
|
|
||||||
|
showAddTagButtonText = -> $el.find(".add-tag-text").removeClass("hidden")
|
||||||
|
hideAddTagButtonText = -> $el.find(".add-tag-text").addClass("hidden")
|
||||||
|
|
||||||
|
showSaveButton = -> $el.find(".save").removeClass("hidden")
|
||||||
|
hideSaveButton = -> $el.find(".save").addClass("hidden")
|
||||||
|
|
||||||
|
showInput = -> $el.find("input").removeClass("hidden")
|
||||||
|
hideInput = -> $el.find("input").addClass("hidden")
|
||||||
|
resetInput = ->
|
||||||
|
$el.find("input").val("")
|
||||||
|
$el.find("input").autocomplete("close")
|
||||||
|
|
||||||
|
addValue = (value) ->
|
||||||
|
value = trim(value.toLowerCase())
|
||||||
|
return if value.length == 0
|
||||||
|
|
||||||
|
tags = _.clone($model.$modelValue, false)
|
||||||
|
tags = [] if not tags?
|
||||||
|
tags.push(value) if value not in tags
|
||||||
|
|
||||||
|
$scope.$apply ->
|
||||||
|
$model.$setViewValue(tags)
|
||||||
|
|
||||||
|
autosaveModel = $scope.$eval($attrs.autosaveModel)
|
||||||
|
if autosaveModel
|
||||||
|
onSuccess = ->
|
||||||
|
$rootScope.$broadcast("history:reload")
|
||||||
|
onError = ->
|
||||||
|
$confirm.notify("error")
|
||||||
|
$scope.$apply ->
|
||||||
|
autosaveModel.revert()
|
||||||
|
$repo.save(autosaveModel).then(onSuccess, onError)
|
||||||
|
|
||||||
|
saveInputTag = () ->
|
||||||
|
value = $el.find("input").val()
|
||||||
|
|
||||||
|
addValue(value)
|
||||||
|
resetInput()
|
||||||
|
hideSaveButton()
|
||||||
|
|
||||||
|
$el.on "keypress", "input", (event) ->
|
||||||
|
return if event.keyCode not in [ENTER_KEY, ESC_KEY]
|
||||||
|
event.preventDefault()
|
||||||
|
|
||||||
|
$el.on "keyup", "input", (event) ->
|
||||||
|
target = angular.element(event.currentTarget)
|
||||||
|
|
||||||
|
if event.keyCode == ENTER_KEY
|
||||||
|
saveInputTag()
|
||||||
|
else if event.keyCode == ESC_KEY
|
||||||
|
resetInput()
|
||||||
|
hideInput()
|
||||||
|
hideSaveButton()
|
||||||
|
showAddTagButton()
|
||||||
|
else
|
||||||
|
if target.val().length
|
||||||
|
showSaveButton()
|
||||||
|
else
|
||||||
|
hideSaveButton()
|
||||||
|
|
||||||
|
$el.on "click", ".save", (event) ->
|
||||||
|
event.preventDefault()
|
||||||
|
saveInputTag()
|
||||||
|
|
||||||
|
$el.on "click", ".add-tag", (event) ->
|
||||||
|
event.preventDefault()
|
||||||
|
hideAddTagButton()
|
||||||
|
showInput()
|
||||||
|
|
||||||
|
$el.on "click", ".icon-delete", (event) ->
|
||||||
|
event.preventDefault()
|
||||||
|
target = angular.element(event.currentTarget)
|
||||||
|
|
||||||
|
value = target.siblings(".tag-name").text()
|
||||||
|
tags = _.clone($model.$modelValue, false)
|
||||||
|
tags = _.pull(tags, value)
|
||||||
|
|
||||||
|
$scope.$apply ->
|
||||||
|
$model.$setViewValue(tags)
|
||||||
|
|
||||||
|
autosaveModel = $scope.$eval($attrs.autosaveModel)
|
||||||
|
if autosaveModel
|
||||||
|
onSuccess = ->
|
||||||
|
$rootScope.$broadcast("history:reload")
|
||||||
|
onError = ->
|
||||||
|
$confirm.notify("error")
|
||||||
|
$scope.$apply ->
|
||||||
|
autosaveModel.revert()
|
||||||
|
$repo.save(autosaveModel).then(onSuccess, onError)
|
||||||
|
|
||||||
|
bindOnce $scope, "project", (project) ->
|
||||||
|
if not isEditable()
|
||||||
|
renderInReadModeOnly()
|
||||||
return
|
return
|
||||||
|
|
||||||
|
showAddTagButton()
|
||||||
|
|
||||||
positioningFunction = (position, elements) ->
|
positioningFunction = (position, elements) ->
|
||||||
menu = elements.element.element
|
menu = elements.element.element
|
||||||
|
@ -195,62 +380,17 @@ TagLineDirective = ($rootscope, $log, $rs, $tgrepo, $confirm) ->
|
||||||
ui.item.value = ""
|
ui.item.value = ""
|
||||||
})
|
})
|
||||||
|
|
||||||
$el.on "keypress", "input", (event) ->
|
$scope.$watch $attrs.ngModel, (tags) ->
|
||||||
return if event.keyCode not in [13, 27]
|
return if not tags
|
||||||
event.preventDefault()
|
|
||||||
|
|
||||||
$el.on "keyup", "input", (event) ->
|
if tags.length
|
||||||
target = angular.element(event.currentTarget)
|
hideAddTagButtonText()
|
||||||
|
|
||||||
if event.keyCode == 13
|
|
||||||
saveInputTag()
|
|
||||||
else if event.keyCode == 27
|
|
||||||
$el.find('.save').hide()
|
|
||||||
$el.find("input").hide()
|
|
||||||
$el.find("input").val('')
|
|
||||||
$el.find('.add-tag').show()
|
|
||||||
else if target.val().length
|
|
||||||
$el.find('.save').show()
|
|
||||||
else
|
else
|
||||||
$el.find('.save').hide()
|
showAddTagButtonText()
|
||||||
|
|
||||||
$el.on "click", ".save", saveInputTag
|
tagsColors = $scope.project?.tags_colors or []
|
||||||
|
renderTags(tags, tagsColors)
|
||||||
|
|
||||||
$el.on "click", ".add-tag", (event) ->
|
|
||||||
event.preventDefault()
|
|
||||||
target = angular.element(event.currentTarget)
|
|
||||||
target.hide()
|
|
||||||
target.siblings('input').show()
|
|
||||||
|
|
||||||
$el.on "click", ".icon-delete", (event) ->
|
|
||||||
event.preventDefault()
|
|
||||||
target = angular.element(event.currentTarget)
|
|
||||||
value = trim(target.siblings(".tag-name").text())
|
|
||||||
|
|
||||||
if value.length <= 0
|
|
||||||
return
|
|
||||||
|
|
||||||
tags = _.clone($model.$modelValue, false)
|
|
||||||
tags = _.pull(tags, value)
|
|
||||||
|
|
||||||
$scope.$apply ->
|
|
||||||
$model.$setViewValue(normalizeTags(tags))
|
|
||||||
autosaveModel = $scope.$eval($attrs.autosaveModel)
|
|
||||||
if autosaveModel
|
|
||||||
promise = $tgrepo.save(autosaveModel)
|
|
||||||
promise.then ->
|
|
||||||
$rootscope.$broadcast("history:reload")
|
|
||||||
promise.then null, ->
|
|
||||||
$confirm.notify("error")
|
|
||||||
|
|
||||||
$scope.$watch $attrs.ngModel, (val) ->
|
|
||||||
tags_colors = if $scope.project?.tags_colors? then $scope.project.tags_colors else []
|
|
||||||
renderTags($el, val, editable, tags_colors)
|
|
||||||
|
|
||||||
if val? and val.length > 0
|
|
||||||
$el.find("span.add-tag-text").hide()
|
|
||||||
else
|
|
||||||
$el.find("span.add-tag-text").show()
|
|
||||||
|
|
||||||
$scope.$on "$destroy", ->
|
$scope.$on "$destroy", ->
|
||||||
$el.off()
|
$el.off()
|
||||||
|
@ -261,4 +401,4 @@ TagLineDirective = ($rootscope, $log, $rs, $tgrepo, $confirm) ->
|
||||||
template: template
|
template: template
|
||||||
}
|
}
|
||||||
|
|
||||||
module.directive("tgTagLine", ["$rootScope", "$log", "$tgResources", "$tgRepo", "$tgConfirm", TagLineDirective])
|
module.directive("tgTagLine", ["$rootScope", "$tgRepo", "$tgResources", "$tgConfirm", TagLineDirective])
|
||||||
|
|
|
@ -14,7 +14,7 @@ form
|
||||||
select.severity(ng-model="issue.severity", ng-options="s.id as s.name for s in severityList")
|
select.severity(ng-model="issue.severity", ng-options="s.id as s.name for s in severityList")
|
||||||
|
|
||||||
fieldset
|
fieldset
|
||||||
div(tg-tag-line, ng-model="issue.tags", required-perm="add_issue")
|
div.tags-block(tg-lb-tag-line, ng-model="issue.tags")
|
||||||
|
|
||||||
fieldset
|
fieldset
|
||||||
textarea.description(placeholder="Description", ng-model="issue.description")
|
textarea.description(placeholder="Description", ng-model="issue.description")
|
||||||
|
|
|
@ -15,9 +15,8 @@ form
|
||||||
placeholder="Assigned to")
|
placeholder="Assigned to")
|
||||||
option(value="") Unassigned
|
option(value="") Unassigned
|
||||||
|
|
||||||
fieldset(ng-switch="isNew")
|
fieldset
|
||||||
div(ng-switch-when="true", tg-tag-line, ng-model="task.tags", required-perm="add_task")
|
div.tags-block(tg-lb-tag-line, ng-model="task.tags")
|
||||||
div(ng-switch-default, tg-tag-line, ng-model="task.tags", required-perm="modify_task")
|
|
||||||
|
|
||||||
fieldset
|
fieldset
|
||||||
textarea.description(placeholder="Type a short description", ng-model="task.description")
|
textarea.description(placeholder="Type a short description", ng-model="task.description")
|
||||||
|
|
|
@ -13,9 +13,8 @@ form
|
||||||
select(name="status", ng-model="us.status", ng-options="s.id as s.name for s in usStatusList",
|
select(name="status", ng-model="us.status", ng-options="s.id as s.name for s in usStatusList",
|
||||||
tr="placeholder:common.status")
|
tr="placeholder:common.status")
|
||||||
|
|
||||||
fieldset(ng-switch="isNew")
|
fieldset
|
||||||
div(ng-switch-when="true", tg-tag-line, ng-model="us.tags", required-perm="add_us")
|
div.tags-block(tg-lb-tag-line, ng-model="us.tags")
|
||||||
div(ng-switch-default, tg-tag-line, ng-model="us.tags", required-perm="modify_us")
|
|
||||||
|
|
||||||
fieldset
|
fieldset
|
||||||
textarea.description(name="description", ng-model="us.description",
|
textarea.description(name="description", ng-model="us.description",
|
||||||
|
|
|
@ -54,9 +54,6 @@
|
||||||
.add-tag-text {
|
.add-tag-text {
|
||||||
@extend %small;
|
@extend %small;
|
||||||
}
|
}
|
||||||
.save {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue