Merge branch 'master' into stable

stable
David Barragán Merino 2016-04-29 11:52:38 +02:00
commit af069abae5
451 changed files with 4688 additions and 14709 deletions

View File

@ -21,6 +21,7 @@ answer newbie questions, and generally made Taiga that much better:
- Brett Profitt <brett.profitt@gmail.com>
- Chris Wilson <chris.wilson@aridhia.com>
- Daniel Koch
- Everardo Medina <everblut@gmail.com>
- Florian Bezagu
- Guilhem Got <guilhem.got@gmail.com>
- Jordan Rinke

View File

@ -1,6 +1,15 @@
# Changelog #
## 2.1.0 Ursus Americanus (2016-05-03)
### Features
- Add sprint title on search results for user stories (thanks to [@everblut](https://github.com/everblut))
### Misc
- Lots of small and not so small bugfixes.
## 2.0.0 Pulsatilla Patens (2016-04-04)
### Features

View File

@ -601,6 +601,9 @@ i18nInit = (lang, $translate) ->
# i18n - moment.js
moment.locale(lang)
if (lang != 'en') # en is the default, the file doesn't exist
ljs.load "/#{window._version}/locales/moment-locales/" + lang + ".js"
# i18n - checksley.js
messages = {
defaultMessage: $translate.instant("COMMON.FORM_ERRORS.DEFAULT_MESSAGE")

View File

@ -240,7 +240,7 @@ module.directive("tgMemberships", ["$tgTemplate", "$compile", MembershipsDirecti
## Member Avatar Directive
#############################################################################
MembershipsRowAvatarDirective = ($log, $template, $translate) ->
MembershipsRowAvatarDirective = ($log, $template, $translate, $compile) ->
template = $template.get("admin/memberships-row-avatar.html", true)
link = ($scope, $el, $attrs) ->
@ -255,6 +255,8 @@ MembershipsRowAvatarDirective = ($log, $template, $translate) ->
}
html = template(ctx)
html = $compile(html)($scope)
$el.html(html)
if not $attrs.tgMembershipsRowAvatar?
@ -269,7 +271,7 @@ MembershipsRowAvatarDirective = ($log, $template, $translate) ->
return {link: link}
module.directive("tgMembershipsRowAvatar", ["$log", "$tgTemplate", '$translate', MembershipsRowAvatarDirective])
module.directive("tgMembershipsRowAvatar", ["$log", "$tgTemplate", '$translate', "$compile", MembershipsRowAvatarDirective])
#############################################################################
@ -393,9 +395,7 @@ MembershipsRowActionsDirective = ($log, $repo, $rs, $confirm, $compile, $transla
</div>
<a class="delete" href=""
title="{{ 'ADMIN.MEMBERSHIP.DELETE_MEMBER' | translate }}">
<svg class="icon icon-trash">
<use xlink:href="#icon-trash">
</svg>
<tg-svg svg-icon="icon-trash"></tg-svg>
</a>
"""
@ -406,9 +406,7 @@ MembershipsRowActionsDirective = ($log, $repo, $rs, $confirm, $compile, $transla
</a>
<a class="delete" href=""
title="{{ 'ADMIN.MEMBERSHIP.DELETE_MEMBER' | translate }}">
<svg class="icon icon-trash">
<use xlink:href="#icon-trash">
</svg>
<tg-svg svg-icon="icon-trash"></tg-svg>
</a>
"""

View File

@ -228,7 +228,7 @@ ProjectModulesDirective = ($repo, $confirm, $loading, projectService) ->
event.preventDefault()
submit()
$el.on "click", ".icon-save", (event) ->
$el.on "click", ".save", (event) ->
event.preventDefault()
submit()

View File

@ -137,22 +137,31 @@ ProjectValuesDirective = ($log, $repo, $confirm, $location, animationFrame, $tra
itemEl = null
tdom = $el.find(".sortable")
tdom.sortable({
handle: ".row.table-main.visualization",
dropOnEmpty: true
connectWith: ".project-values-body"
revert: 400
axis: "y"
drake = dragula([tdom[0]], {
direction: 'vertical',
copySortSource: false,
copy: false,
mirrorContainer: tdom[0],
moves: (item) -> return $(item).is('div[tg-bind-scope]')
})
tdom.on "sortstop", (event, ui) ->
itemEl = ui.item
drake.on 'dragend', (item) ->
itemEl = $(item)
itemValue = itemEl.scope().value
itemIndex = itemEl.index()
$scope.$broadcast("admin:project-values:move", itemValue, itemIndex)
scroll = autoScroll(window, {
margin: 20,
pixels: 30,
scrollWhenOutside: true,
autoScroll: () ->
return this.down && drake.dragging;
})
$scope.$on "$destroy", ->
$el.off()
drake.destroy()
## Value Link
@ -441,7 +450,7 @@ class ProjectCustomAttributesController extends mixOf(taiga.Controller, taiga.Pa
loadCustomAttributes: =>
return @rs.customAttributes[@scope.type].list(@scope.projectId).then (customAttributes) =>
@scope.customAttributes = customAttributes
@scope.maxOrder = _.maxBy(customAttributes, "order").order
@scope.maxOrder = _.maxBy(customAttributes, "order")?.order
return customAttributes
createCustomAttribute: (attrValues) =>
@ -483,16 +492,16 @@ ProjectCustomAttributesDirective = ($log, $confirm, animationFrame, $translate)
# Drag & Drop
##################################
sortableEl = $el.find(".js-sortable")
sortableEl.sortable({
handle: ".js-view-custom-field",
dropOnEmpty: true
revert: 400
axis: "y"
drake = dragula([sortableEl[0]], {
direction: 'vertical',
copySortSource: false,
copy: false,
mirrorContainer: sortableEl[0],
moves: (item) -> return $(item).is('div[tg-bind-scope]')
})
sortableEl.on "sortstop", (event, ui) ->
itemEl = ui.item
drake.on 'dragend', (item) ->
itemEl = $(item)
itemAttr = itemEl.scope().attr
itemIndex = itemEl.index()
$ctrl.moveCustomAttributes(itemAttr, itemIndex)

View File

@ -162,8 +162,7 @@ class RolesController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.Fil
subtitle = @translate.instant("ADMIN.ROLES.DISABLE_COMPUTABLE_ALERT_SUBTITLE", {
roleName: @scope.role.name
})
message = @translate.instant("ADMIN.ROLES.DISABLE_COMPUTABLE_ALERT_MESSAGE")
return @confirm.ask(title, subtitle, message).then askOnSuccess, askOnError
return @confirm.ask(title, subtitle, "").then askOnSuccess, askOnError
toggleComputable: debounce 2000, ->
if not @scope.role.computable
@ -292,9 +291,7 @@ RolePermissionsDirective = ($rootscope, $repo, $confirm, $compile) ->
title="{{ '<%- permission.name %>' | translate }}"></div>
<% }) %>
</div>
<svg class="icon icon-arrow-right">
<use xlink:href="#icon-arrow-right">
</svg>
<tg-svg svg-icon="icon-arrow-right"></tg-svg>
""")
categoryTemplate = _.template("""

View File

@ -275,6 +275,13 @@ LoginDirective = ($auth, $confirm, $location, $config, $routeParams, $navUrls, $
onError = (response) ->
$confirm.notify("light-error", $translate.instant("LOGIN_FORM.ERROR_AUTH_INCORRECT"))
$scope.onKeyUp = (event) ->
target = angular.element(event.currentTarget)
value = target.val()
$scope.iscapsLockActivated = false
if value != value.toLowerCase()
$scope.iscapsLockActivated = true
submit = debounce 2000, (event) =>
event.preventDefault()

View File

@ -38,9 +38,9 @@ module = angular.module("taigaBacklog")
## Issues Filters Directive
#############################################################################
BacklogFiltersDirective = ($q, $log, $location, $templates) ->
template = $templates.get("backlog/filters.html", true)
templateSelected = $templates.get("backlog/filter-selected.html", true)
BacklogFiltersDirective = ($q, $log, $location, $template, $compile) ->
template = $template.get("backlog/filters.html", true)
templateSelected = $template.get("backlog/filter-selected.html", true)
link = ($scope, $el, $attrs) ->
currentFiltersType = ''
@ -78,6 +78,8 @@ BacklogFiltersDirective = ($q, $log, $location, $templates) ->
f.style = "border-left: 3px solid #{f.color}"
html = templateSelected({filters: selectedFilters})
html = $compile(html)($scope)
$el.find(".filters-applied").html(html)
renderFilters = (filters) ->
@ -86,6 +88,7 @@ BacklogFiltersDirective = ($q, $log, $location, $templates) ->
f.style = "border-left: 3px solid #{f.color}"
html = template({filters:filters})
html = $compile(html)($scope)
$el.find(".filter-list").html(html)
getFiltersType = () ->
@ -94,7 +97,7 @@ BacklogFiltersDirective = ($q, $log, $location, $templates) ->
reloadUserstories = () ->
currentFiltersType = getFiltersType()
$q.all([$ctrl.loadUserstories(), $ctrl.generateFilters()]).then () ->
$q.all([$ctrl.loadUserstories(true), $ctrl.generateFilters()]).then () ->
currentFilters = $scope.filters[currentFiltersType]
renderFilters(_.reject(currentFilters, "selected"))
@ -158,9 +161,9 @@ BacklogFiltersDirective = ($q, $log, $location, $templates) ->
event.preventDefault()
showCategories()
$el.on "click", ".filters-applied a", (event) ->
$el.on "click", ".remove-filter", (event) ->
event.preventDefault()
target = angular.element(event.currentTarget)
target = angular.element(event.currentTarget).parent()
id = target.data("id")
type = target.data("type")
toggleFilterSelection(type, id)
@ -179,4 +182,4 @@ BacklogFiltersDirective = ($q, $log, $location, $templates) ->
return {link:link}
module.directive("tgBacklogFilters", ["$q", "$log", "$tgLocation", "$tgTemplate", BacklogFiltersDirective])
module.directive("tgBacklogFilters", ["$q", "$log", "$tgLocation", "$tgTemplate", "$compile", BacklogFiltersDirective])

View File

@ -62,6 +62,10 @@ class BacklogController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.F
@location, @appMetaService, @navUrls, @events, @analytics, @translate, @loading, @rs2) ->
bindMethods(@)
@.page = 1
@.disablePagination = false
@scope.userstories = []
@scope.sectionName = @translate.instant("BACKLOG.SECTION_NAME")
@showTags = false
@activeFilters = false
@ -90,7 +94,7 @@ class BacklogController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.F
initializeEventHandlers: ->
@scope.$on "usform:bulk:success", =>
@.loadUserstories()
@.loadUserstories(true)
@.loadProjectStats()
@analytics.trackEvent("userstory", "create", "bulk create userstory on backlog", 1)
@ -100,7 +104,7 @@ class BacklogController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.F
@analytics.trackEvent("sprint", "create", "create sprint on backlog", 1)
@scope.$on "usform:new:success", =>
@.loadUserstories()
@.loadUserstories(true)
@.loadProjectStats()
@rootscope.$broadcast("filters:update")
@ -112,20 +116,25 @@ class BacklogController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.F
@scope.$on "sprintform:remove:success", (event, sprint) =>
@.loadSprints()
@.loadProjectStats()
@.loadUserstories()
@.loadUserstories(true)
if sprint.closed
@.loadClosedSprints()
@rootscope.$broadcast("filters:update")
@scope.$on "usform:edit:success", =>
@.loadUserstories()
@scope.$on "usform:edit:success", (event, data) =>
index = _.findIndex @scope.userstories, (us) ->
return us.id == data.id
@scope.userstories[index] = data
@rootscope.$broadcast("filters:update")
@scope.$on("sprint:us:move", @.moveUs)
@scope.$on("sprint:us:moved", @.loadSprints)
@scope.$on("sprint:us:moved", @.loadProjectStats)
@scope.$on "sprint:us:moved", () =>
@.loadSprints()
@.loadProjectStats()
@scope.$on("backlog:load-closed-sprints", @.loadClosedSprints)
@scope.$on("backlog:unload-closed-sprints", @.unloadClosedSprints)
@ -248,18 +257,37 @@ class BacklogController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.F
@.loadUserstories()
loadUserstories: ->
loadUserstories: (resetPagination = false)->
@.loadingUserstories = true
@.disablePagination = true
@scope.httpParams = @.getUrlFilters()
@rs.userstories.storeQueryParams(@scope.projectId, @scope.httpParams)
if resetPagination
@.page = 1
@scope.httpParams.page = @.page
promise = @rs.userstories.listUnassigned(@scope.projectId, @scope.httpParams)
return promise.then (userstories) =>
return promise.then (result) =>
userstories = result[0]
header = result[1]
if resetPagination
@scope.userstories = []
# NOTE: Fix order of USs because the filter orderBy does not work propertly in the partials files
@scope.userstories = _.sortBy(userstories, "backlog_order")
@scope.userstories = @scope.userstories.concat(_.sortBy(userstories, "backlog_order"))
@.setSearchDataFilters()
@.loadingUserstories = false
if header('x-pagination-next')
@.disablePagination = false
@.page++
# The broadcast must be executed when the DOM has been fully reloaded.
# We can't assure when this exactly happens so we need a defer
scopeDefer @scope, =>
@ -362,8 +390,7 @@ class BacklogController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.F
# Persist in bulk all affected
# userstories with order change
@rs.userstories.bulkUpdateBacklogOrder(project, data).then =>
for us in usList
@rootscope.$broadcast("sprint:us:moved", us, oldSprintId, newSprintId)
@rootscope.$broadcast("sprint:us:moved")
# For sprint
else
@ -374,8 +401,7 @@ class BacklogController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.F
# Persist in bulk all affected
# userstories with order change
@rs.userstories.bulkUpdateSprintOrder(project, data).then =>
for us in usList
@rootscope.$broadcast("sprint:us:moved", us, oldSprintId, newSprintId)
@rootscope.$broadcast("sprint:us:moved")
return promise
@ -402,7 +428,7 @@ class BacklogController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.F
items = @.resortUserStories(@scope.userstories, "backlog_order")
data = @.prepareBulkUpdateData(items, "backlog_order")
return @rs.userstories.bulkUpdateBacklogOrder(us.project, data).then =>
@rootscope.$broadcast("sprint:us:moved", us, oldSprintId, newSprintId)
@rootscope.$broadcast("sprint:us:moved")
if movedFromClosedSprint
@rootscope.$broadcast("backlog:load-closed-sprints")
@ -415,17 +441,15 @@ class BacklogController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.F
# From backlog to sprint
if oldSprintId == null
us.milestone = newSprintId for us in usList
args = [newUsIndex, 0].concat(usList)
@scope.$apply =>
args = [newUsIndex, 0].concat(usList)
# Add moving us to sprint user stories list
Array.prototype.splice.apply(newSprint.user_stories, args)
# Add moving us to sprint user stories list
Array.prototype.splice.apply(newSprint.user_stories, args)
# Remove moving us from backlog userstories lists.
for us, key in usList
r = @scope.userstories.indexOf(us)
@scope.userstories.splice(r, 1)
# Remove moving us from backlog userstories lists.
for us, key in usList
r = @scope.userstories.indexOf(us)
@scope.userstories.splice(r, 1)
# From sprint to sprint
else
@ -442,21 +466,20 @@ class BacklogController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.F
r = sprint.user_stories.indexOf(us)
sprint.user_stories.splice(r, 1)
# Persist the milestone change of userstory
#Persist the milestone change of userstory
promises = _.map usList, (us) => @repo.save(us)
# Rehash userstories order field
# and persist in bulk all changes.
#Rehash userstories order field
#and persist in bulk all changes.
promise = @q.all(promises).then =>
items = @.resortUserStories(newSprint.user_stories, "sprint_order")
data = @.prepareBulkUpdateData(items, "sprint_order")
@rs.userstories.bulkUpdateSprintOrder(project, data).then (result) =>
@rootscope.$broadcast("sprint:us:moved", us, oldSprintId, newSprintId)
@rootscope.$broadcast("sprint:us:moved")
@rs.userstories.bulkUpdateBacklogOrder(project, data).then =>
for us in usList
@rootscope.$broadcast("sprint:us:moved", us, oldSprintId, newSprintId)
@rootscope.$broadcast("sprint:us:moved")
if movedToClosedSprint || movedFromClosedSprint
@scope.$broadcast("backlog:load-closed-sprints")
@ -583,7 +606,11 @@ class BacklogController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.F
promise = @.repo.remove(us)
promise.then =>
askResponse.finish()
@.loadBacklog()
@q.all([
@.loadProjectStats(),
@.loadSprints()
])
promise.then null, =>
askResponse.finish(false)
@confirm.notify("error")
@ -652,7 +679,7 @@ BacklogDirective = ($repo, $rootscope, $translate) ->
return _.map(rowElements, (x) -> angular.element(x))
$scope.$on("userstories:loaded", reloadDoomLine)
$scope.$watch "stats", reloadDoomLine
$scope.$watch("stats", reloadDoomLine)
## Move to current sprint link
@ -807,8 +834,6 @@ BacklogDirective = ($repo, $rootscope, $translate) ->
linkFilters($scope, $el, $attrs, $ctrl)
linkDoomLine($scope, $el, $attrs, $ctrl)
$el.find(".backlog-table-body").disableSelection()
filters = $ctrl.getUrlFilters()
if filters.status ||
filters.tags ||
@ -843,7 +868,7 @@ UsRolePointsSelectorDirective = ($rootscope, $template, $compile, $translate) ->
if numberOfRoles > 1
$el.append($compile(selectionTemplate({"roles": roles}))($scope))
else
$el.find(".icon-arrow-bottom").remove()
$el.find(".icon-arrow-down").remove()
$el.find(".header-points").addClass("not-clickable")
$scope.$on "uspoints:select", (ctx, roleId, roleName) ->

View File

@ -38,187 +38,117 @@ module = angular.module("taigaBacklog")
#############################################################################
deleteElement = (el) ->
el.scope().$destroy()
el.off()
el.remove()
$(el).scope().$destroy()
$(el).off()
$(el).remove()
BacklogSortableDirective = ($repo, $rs, $rootscope, $tgConfirm, $translate) ->
# Notes about jquery bug:
# http://stackoverflow.com/questions/5791886/jquery-draggable-shows-
# helper-in-wrong-place-when-scrolled-down-page
link = ($scope, $el, $attrs) ->
getUsIndex = (us) =>
return $(us).index(".backlog-table-body .row")
bindOnce $scope, "project", (project) ->
# If the user has not enough permissions we don't enable the sortable
if not (project.my_permissions.indexOf("modify_us") > -1)
return
initIsBacklog = false
filterError = ->
text = $translate.instant("BACKLOG.SORTABLE_FILTER_ERROR")
$tgConfirm.notify("error", text)
$el.sortable({
items: ".us-item-row",
cancel: ".popover"
connectWith: ".sprint"
dropOnEmpty: true
placeholder: "row us-item-row us-item-drag sortable-placeholder"
scroll: true
disableHorizontalScroll: true
# A consequence of length of backlog user story item
# the default tolerance ("intersection") not works properly.
tolerance: "pointer"
# Revert on backlog is disabled bacause it works bad. Something
# on the current taiga backlog structure or style makes jquery ui
# works unexpectly (in some circumstances calculates wrong
# position for revert).
revert: false
start: () ->
$(document.body).addClass("drag-active")
stop: () ->
$(document.body).removeClass("drag-active")
drake = dragula([$el[0], $('.empty-backlog')[0]], {
copySortSource: false,
copy: false,
isContainer: (el) -> return el.classList.contains('sprint-table'),
moves: (item) ->
if !$(item).hasClass('row')
return false
if $el.hasClass("active-filters")
$el.sortable("cancel")
# it doesn't move is the filter is open
parent = $(item).parent()
initIsBacklog = parent.hasClass('backlog-table-body')
if initIsBacklog && $el.hasClass("active-filters")
filterError()
return false
return true
})
$el.on "multiplesortreceive", (event, ui) ->
if $el.hasClass("active-filters")
ui.source.sortable("cancel")
filterError()
drake.on 'drag', (item, container) ->
parent = $(item).parent()
initIsBacklog = parent.hasClass('backlog-table-body')
return
$(document.body).addClass("drag-active")
itemUs = ui.item.scope().us
itemIndex = getUsIndex(ui.item)
isChecked = $(item).find("input[type='checkbox']").is(":checked")
deleteElement(ui.item)
window.dragMultiple.start(item, container)
$scope.$emit("sprint:us:move", [itemUs], itemIndex, null)
ui.item.find('a').removeClass('noclick')
drake.on 'cloned', (item) ->
$(item).addClass('backlog-us-mirror')
$el.on "multiplesortstop", (event, ui) ->
# When parent not exists, do nothing
if $(ui.items[0]).parent().length == 0
return
drake.on 'dragend', (item) ->
$('.doom-line').remove()
if $el.hasClass("active-filters")
return
parent = $(item).parent()
isBacklog = parent.hasClass('backlog-table-body') || parent.hasClass('empty-backlog')
items = _.sortBy ui.items, (item) ->
return $(item).index()
sameContainer = (initIsBacklog == isBacklog)
index = _.min _.map items, (item) ->
return getUsIndex(item)
dragMultipleItems = window.dragMultiple.stop()
us = _.map items, (item) ->
item = $(item)
itemUs = item.scope().us
$(document.body).removeClass("drag-active")
# HACK: setTimeout prevents that firefox click
# event fires just after drag ends
setTimeout ( =>
item.find('a').removeClass('noclick')
), 300
items = $(item).parent().find('.row')
return itemUs
sprint = null
$scope.$emit("sprint:us:move", us, index, null)
firstElement = if dragMultipleItems.length then dragMultipleItems[0] else item
$el.on "sortstart", (event, ui) ->
ui.item.find('a').addClass('noclick')
if isBacklog
index = $(firstElement).index(".backlog-table-body .row")
else
index = $(firstElement).index()
sprint = parent.scope().sprint.id
$scope.$on "$destroy", ->
$el.off()
return {link: link}
BacklogEmptySortableDirective = ($repo, $rs, $rootscope) ->
# Notes about jquery bug:
# http://stackoverflow.com/questions/5791886/jquery-draggable-shows-
# helper-in-wrong-place-when-scrolled-down-page
link = ($scope, $el, $attrs) ->
bindOnce $scope, "project", (project) ->
# If the user has not enough permissions we don't enable the sortable
if project.my_permissions.indexOf("modify_us") > -1
$el.sortable({
items: ".us-item-row",
dropOnEmpty: true
})
$el.on "sortreceive", (event, ui) ->
itemUs = ui.item.scope().us
itemIndex = ui.item.index()
deleteElement(ui.item)
$scope.$emit("sprint:us:move", [itemUs], itemIndex, null)
ui.item.find('a').removeClass('noclick')
$scope.$on "$destroy", ->
$el.off()
return {link: link}
SprintSortableDirective = ($repo, $rs, $rootscope) ->
link = ($scope, $el, $attrs) ->
bindOnce $scope, "project", (project) ->
# If the user has not enough permissions we don't enable the sortable
if project.my_permissions.indexOf("modify_us") > -1
$el.sortable({
scroll: true
dropOnEmpty: true
items: ".sprint-table .milestone-us-item-row"
disableHorizontalScroll: true
connectWith: ".sprint,.backlog-table-body,.empty-backlog"
placeholder: "row us-item-row sortable-placeholder"
forcePlaceholderSize:true
})
$el.on "multiplesortreceive", (event, ui) ->
items = _.sortBy ui.items, (item) ->
return $(item).index()
index = _.min _.map items, (item) ->
return $(item).index()
us = _.map items, (item) ->
item = $(item)
itemUs = item.scope().us
if !sameContainer
if dragMultipleItems.length
usList = _.map dragMultipleItems, (item) ->
return item = $(item).scope().us
else
usList = [$(item).scope().us]
if (dragMultipleItems.length)
_.each dragMultipleItems, (item) ->
deleteElement(item)
else
deleteElement(item)
else
if dragMultipleItems.length
usList = _.map dragMultipleItems, (item) ->
return item = $(item).scope().us
else
usList = _.map items, (item) ->
item = $(item)
itemUs = item.scope().us
return itemUs
return itemUs
$scope.$emit("sprint:us:move", us, index, $scope.sprint.id)
$scope.$emit("sprint:us:move", usList, index, sprint)
$el.on "multiplesortstop", (event, ui) ->
# When parent not exists, do nothing
if ui.item.parent().length == 0
return
scroll = autoScroll([window], {
margin: 20,
pixels: 30,
scrollWhenOutside: true,
autoScroll: () ->
return this.down && drake.dragging;
})
itemUs = ui.item.scope().us
itemIndex = ui.item.index()
# HACK: setTimeout prevents that firefox click
# event fires just after drag ends
setTimeout ( =>
ui.item.find('a').removeClass('noclick')
), 300
$scope.$emit("sprint:us:move", [itemUs], itemIndex, $scope.sprint.id)
$el.on "sortstart", (event, ui) ->
ui.item.find('a').addClass('noclick')
return {link:link}
$scope.$on "$destroy", ->
$el.off()
drake.destroy()
return {link: link}
module.directive("tgBacklogSortable", [
"$tgRepo",
@ -228,17 +158,3 @@ module.directive("tgBacklogSortable", [
"$translate",
BacklogSortableDirective
])
module.directive("tgBacklogEmptySortable", [
"$tgRepo",
"$tgResources",
"$rootScope",
BacklogEmptySortableDirective
])
module.directive("tgSprintSortable", [
"$tgRepo",
"$tgResources",
"$rootScope",
SprintSortableDirective
])

View File

@ -62,7 +62,7 @@ BacklogSprintDirective = ($repo, $rootscope) ->
$el.find(".sprint-table").slideToggle(slideOptions)
$el.on "click", ".sprint-name > .icon-edit", (event) ->
$el.on "click", ".edit-sprint", (event) ->
event.preventDefault()
sprint = $scope.$eval($attrs.tgBacklogSprint)

View File

@ -284,39 +284,52 @@ module.factory("$tgTemplate", ["$templateCache", Template])
## Permission directive, hide elements when necessary
#############################################################################
Capslock = ($translate) ->
link = ($scope, $el, $attrs) ->
open = false
Capslock = () ->
template = """
<tg-svg class="capslock" ng-if="capslockIcon && iscapsLockActivated" svg-icon='icon-capslock' svg-title='COMMON.CAPSLOCK_WARNING'></tg-svg>
"""
return {
template: template
}
warningIcon = "<svg class='icon icon-capslock' title='" + $translate.instant('COMMON.CAPSLOCK_WARNING') + "'><use xlink:href='#icon-capslock'></svg>";
module.directive("tgCapslock", [Capslock])
hideIcon = () ->
$('.icon-capslock').fadeOut () ->
open = false
LightboxClose = () ->
template = """
<a class="close" href="" title="{{'COMMON.CLOSE' | translate}}">
<tg-svg svg-icon="icon-close"></tg-svg>
</a>
"""
$(this).remove()
return {
template: template
}
showIcon = (e) ->
return if open
element = e.currentTarget
$(element).parent().append(warningIcon)
$('.icon-capslock').fadeIn()
module.directive("tgLightboxClose", [LightboxClose])
open = true
Svg = () ->
template = """
<svg class="{{ 'icon ' + svgIcon }}">
<use xlink:href="" ng-attr-xlink:href="{{ '#' + svgIcon }}">
<title ng-if="svgTitle">{{svgTitle}}</title>
<title
ng-if="svgTitleTranslate"
translate="{{svgTitleTranslate}}"
translate-values="{{svgTitleTranslateValues}}"
></title>
</use>
</svg>
"""
$el.on 'blur', (e) ->
hideIcon()
return {
scope: {
svgIcon: "@",
svgTitle: "@",
svgTitleTranslate: "@",
svgTitleTranslateValues: "="
},
template: template
}
$el.on 'keyup.capslock, focus', (e) ->
if $el.val() == $el.val().toLowerCase()
hideIcon(e)
else
showIcon(e)
$scope.$on "$destroy", ->
$el.off('.capslock')
return {link:link}
module.directive("tgCapslock", ["$translate", Capslock])
module.directive("tgSvg", [Svg])

View File

@ -173,14 +173,17 @@ class ConfirmService extends taiga.Service
if icon.type == "img"
detailImage = $('<img>').addClass('lb-icon').attr('src', icon.name)
else if icon.type == "svg"
detailImage = document.createElement("div")
taiga.addClass(detailImage, "icon")
taiga.addClass(detailImage, icon.name)
taiga.addClass(detailImage, "lb-icon")
svgContainer = document.createElementNS("http://www.w3.org/2000/svg", "svg")
useSVG = document.createElementNS('http://www.w3.org/2000/svg', 'use')
useSVG.setAttributeNS('http://www.w3.org/1999/xlink','href', '#' + icon.name)
detailImage = document.createElementNS("http://www.w3.org/2000/svg", "svg")
detailImage.classList.add("icon")
detailImage.classList.add("lb-icon")
detailImage.classList.add(icon.name)
detailImage.appendChild(useSVG)
detailImage.appendChild(svgContainer).appendChild(useSVG)
if detailImage
el.find('section').prepend(detailImage)

View File

@ -117,7 +117,7 @@ CustomAttributesValuesDirective = ($templates, $storage) ->
$ctrl.initialize($attrs.type, value.id)
$ctrl.loadCustomAttributesValues()
$el.on "click", ".custom-fields-header .icon", ->
$el.on "click", ".custom-fields-header .collapse", ->
hash = collapsedHash($attrs.type)
collapsed = not($storage.get(hash) or false)
$storage.set(hash, collapsed)

View File

@ -421,7 +421,7 @@ HistoryDirective = ($log, $loading, $qqueue, $template, $confirm, $translate, $c
# Events
$el.on "click", ".add-comment button.button-green", debounce 2000, (event) ->
$el.on "click", ".add-comment .button-green", debounce 2000, (event) ->
event.preventDefault()
target = angular.element(event.currentTarget)
@ -467,11 +467,11 @@ HistoryDirective = ($log, $loading, $qqueue, $template, $confirm, $translate, $c
$el.on "focus", ".add-comment textarea", (event) ->
$(this).addClass('active')
$el.on "click", ".history-tabs li a", (event) ->
$el.on "click", ".history-tabs a", (event) ->
target = angular.element(event.currentTarget)
$el.find(".history-tabs li a").removeClass("active")
target.addClass("active")
$el.find(".history-tabs li").removeClass("active")
target.parent().addClass("active")
$el.find(".history section").addClass("hidden")
$el.find(".history section.#{target.data('section-class')}").removeClass("hidden")

View File

@ -51,7 +51,12 @@ class LightboxService extends taiga.Service
@animationFrame.add ->
$el.addClass("open")
$el.one "transitionend", =>
$el.find('input,textarea').first().focus()
firstField = $el.find('input,textarea').first()
if firstField.length
$el.find('input,textarea').first().focus()
else if document.activeElement
$(document.activeElement).blur()
@animationFrame.add =>
lightboxContent.show()
@ -79,7 +84,7 @@ class LightboxService extends taiga.Service
if $el.hasClass("remove-on-close")
scope = $el.data("scope")
scope.$destroy()
scope.$destroy() if scope
$el.remove()
closeAll: ->

View File

@ -158,6 +158,10 @@ RelatedTaskStatusDirective = ($repo, $template) ->
$scope.$eval($attrs.onUpdate)
$scope.$emit("related-tasks:status-changed")
$scope.$watch $attrs.tgRelatedTaskStatus, () ->
task = $scope.$eval($attrs.tgRelatedTaskStatus)
updateTaskStatus($el, task, $scope.taskStatusById)
taiga.bindOnce $scope, "project", (project) ->
$el.append(selectionTemplate({ 'statuses': project.task_statuses }))
updateTaskStatus($el, task, $scope.taskStatusById)

View File

@ -108,6 +108,8 @@ LbTagLineDirective = ($rs, $template, $compile) ->
templateTags = $template.get("common/tag/lb-tag-line-tags.html", true)
autocomplete = null
link = ($scope, $el, $attrs, $model) ->
## Render
renderTags = (tags, tagsColors) ->
@ -130,7 +132,7 @@ LbTagLineDirective = ($rs, $template, $compile) ->
resetInput = ->
$el.find("input").val("")
$el.find("input").autocomplete("close")
autocomplete.close()
## Aux methods
addValue = (value) ->
@ -190,22 +192,15 @@ LbTagLineDirective = ($rs, $template, $compile) ->
deleteValue(value)
bindOnce $scope, "project", (project) ->
positioningFunction = (position, elements) ->
menu = elements.element.element
menu.css("width", elements.target.width)
menu.css("top", position.top)
menu.css("left", position.left)
input = $el.find("input")
$el.find("input").autocomplete({
source: _.keys(project.tags_colors)
position: {
my: "left top",
using: positioningFunction
}
select: (event, ui) ->
addValue(ui.item.value)
ui.item.value = ""
})
autocomplete = new Awesomplete(input[0], {
list: _.keys(project.tags_colors)
});
input.on "awesomplete-selectcomplete", () ->
addValue(input.val())
input.val("")
$scope.$watch $attrs.ngModel, (tags) ->
tagsColors = $scope.project?.tags_colors or []
@ -235,6 +230,8 @@ TagLineDirective = ($rootScope, $repo, $rs, $confirm, $qqueue, $template, $compi
templateTags = $template.get("common/tag/tags-line-tags.html", true)
link = ($scope, $el, $attrs, $model) ->
autocomplete = null
isEditable = ->
if $attrs.requiredPerm?
return $scope.project.my_permissions.indexOf($attrs.requiredPerm) != -1
@ -268,7 +265,8 @@ TagLineDirective = ($rootScope, $repo, $rs, $confirm, $qqueue, $template, $compi
hideInput = -> $el.find("input").addClass("hidden").blur()
resetInput = ->
$el.find("input").val("")
$el.find("input").autocomplete("close")
autocomplete.close()
## Aux methods
addValue = $qqueue.bindAdd (value) ->
@ -366,22 +364,15 @@ TagLineDirective = ($rootScope, $repo, $rs, $confirm, $qqueue, $template, $compi
showAddTagButton()
positioningFunction = (position, elements) ->
menu = elements.element.element
menu.css("width", elements.target.width)
menu.css("top", position.top)
menu.css("left", position.left)
input = $el.find("input")
$el.find("input").autocomplete({
source: _.keys(tags_colors)
position: {
my: "left top",
using: positioningFunction
}
select: (event, ui) ->
addValue(ui.item.value)
ui.item.value = ""
})
autocomplete = new Awesomplete(input[0], {
list: _.keys(tags_colors)
});
input.on "awesomplete-selectcomplete", () ->
addValue(input.val())
input.val("")
$scope.$watch $attrs.ngModel, (model) ->
return if not model

View File

@ -584,20 +584,20 @@ IssuesFiltersDirective = ($q, $log, $location, $rs, $confirm, $loading, $templat
unwatchIssues()
# Dom Event Handlers
$el.on "click", ".filters-cats > ul > li > a", (event) ->
$el.on "click", ".filters-cat-single", (event) ->
event.preventDefault()
target = angular.element(event.currentTarget)
tags = $scope.filters[target.data("type")]
renderFilters(_.reject(tags, "selected"))
showFilters(target.attr("title"), target.data("type"))
$el.on "click", ".filters-inner > .filters-step-cat > .breadcrumb > .back", (event) ->
$el.on "click", ".back", (event) ->
event.preventDefault()
showCategories($el)
$el.on "click", ".filters-applied a", (event) ->
$el.on "click", ".filters-applied .remove-filter", (event) ->
event.preventDefault()
target = angular.element(event.currentTarget)
target = angular.element(event.currentTarget).parent()
id = target.data("id") or null
type = target.data("type")
@ -617,7 +617,7 @@ IssuesFiltersDirective = ($q, $log, $location, $rs, $confirm, $loading, $templat
toggleFilterSelection(type, id)
$el.on "click", ".filter-list .single-filter .remove-filter", (event) ->
$el.on "click", ".filter-list .remove-filter", (event) ->
event.preventDefault()
event.stopPropagation()

View File

@ -329,7 +329,7 @@ KanbanArchivedStatusHeaderDirective = ($rootscope, $translate) ->
status = $scope.$eval($attrs.tgKanbanArchivedStatusHeader)
hidden = true
$scope.class = "icon-open-eye"
$scope.class = "icon-watch"
$scope.title = showArchivedText
$el.on "click", (event) ->
@ -337,12 +337,12 @@ KanbanArchivedStatusHeaderDirective = ($rootscope, $translate) ->
$scope.$apply ->
if hidden
$scope.class = "icon-open-eye"
$scope.class = "icon-watch"
$scope.title = showArchivedText
$rootscope.$broadcast("kanban:hide-userstories-for-status", status.id)
else
$scope.class = "icon-closed-eye"
$scope.class = "icon-unwatch"
$scope.title = hideArchivedText
$rootscope.$broadcast("kanban:show-userstories-for-status", status.id)
@ -418,15 +418,13 @@ module.directive("tgKanbanArchivedStatusIntro", ["$translate", KanbanArchivedSta
KanbanUserstoryDirective = ($rootscope, $loading, $rs, $rs2) ->
link = ($scope, $el, $attrs, $model) ->
$el.disableSelection()
$scope.$watch "us", (us) ->
if us.is_blocked and not $el.hasClass("blocked")
$el.addClass("blocked")
else if not us.is_blocked and $el.hasClass("blocked")
$el.removeClass("blocked")
$el.on 'click', '.icon-edit', (event) ->
$el.on 'click', '.edit-us', (event) ->
if $el.find(".icon-edit").hasClass("noclick")
return
@ -498,8 +496,6 @@ module.directive("tgKanbanSquishColumn", ["$tgResources", KanbanSquishColumnDire
KanbanWipLimitDirective = ->
link = ($scope, $el, $attrs) ->
$el.disableSelection()
status = $scope.$eval($attrs.tgKanbanWipLimit)
redrawWipLimit = =>

View File

@ -55,16 +55,23 @@ KanbanSortableDirective = ($repo, $rs, $rootscope) ->
itemEl.off()
itemEl.remove()
tdom.sortable({
handle: ".kanban-task-inner"
dropOnEmpty: true
connectWith: ".kanban-uses-box"
revert: 400
containers = _.map $el.find('.task-column'), (item) ->
return item
drake = dragula(containers, {
copySortSource: false,
copy: false,
mirrorContainer: tdom[0],
moves: (item) ->
return $(item).hasClass('kanban-task')
})
tdom.on "sortstop", (event, ui) ->
parentEl = ui.item.parent()
itemEl = ui.item
drake.on 'drag', (item) ->
oldParentScope = $(item).parent().scope()
drake.on 'dragend', (item) ->
parentEl = $(item).parent()
itemEl = $(item)
itemUs = itemEl.scope().us
itemIndex = itemEl.index()
newParentScope = parentEl.scope()
@ -78,14 +85,17 @@ KanbanSortableDirective = ($repo, $rs, $rootscope) ->
$scope.$apply ->
$rootscope.$broadcast("kanban:us:move", itemUs, itemUs.status, newStatusId, itemIndex)
ui.item.find('a').removeClass('noclick')
scroll = autoScroll(containers, {
margin: 20,
pixels: 30,
scrollWhenOutside: true,
autoScroll: () ->
return this.down && drake.dragging;
})
tdom.on "sortstart", (event, ui) ->
oldParentScope = ui.item.parent().scope()
ui.item.find('a').addClass('noclick')
$scope.$on "$destroy", ->
$el.off()
$scope.$on "$destroy", ->
$el.off()
drake.destroy()
return {link: link}

View File

@ -35,10 +35,6 @@ CreateProject = ($rootscope, $repo, $confirm, $location, $navurls, $rs, $project
$scope.templates = []
currentLoading = null
$auth.refresh()
$scope.canCreatePrivateProjects = currentUserService.canCreatePrivateProjects()
$scope.canCreatePublicProjects = currentUserService.canCreatePublicProjects()
form = $el.find("form").checksley({"onlyOneErrorElement": true})
onSuccessSubmit = (response) ->
@ -88,6 +84,9 @@ CreateProject = ($rootscope, $repo, $confirm, $location, $navurls, $rs, $project
else
$scope.data.creation_template = _.head(_.filter($scope.templates, (x) -> x.slug == "scrum")).id
$scope.canCreatePrivateProjects = currentUserService.canCreatePrivateProjects()
$scope.canCreatePublicProjects = currentUserService.canCreatePublicProjects()
lightboxService.open($el)
submitButton = $el.find(".submit-button")
@ -101,7 +100,8 @@ CreateProject = ($rootscope, $repo, $confirm, $location, $navurls, $rs, $project
$scope.$on "$destroy", ->
$el.off()
openLightbox()
$auth.refresh().then () ->
openLightbox()
directive = {
link: link,

View File

@ -117,16 +117,14 @@ module.directive("tgRelatedTaskRow", ["$tgRepo", "$compile", "$tgConfirm", "$roo
"$tgTemplate", "$translate", RelatedTaskRowDirective])
RelatedTaskCreateFormDirective = ($repo, $compile, $confirm, $tgmodel, $loading, $analytics, $template) ->
template = $template.get("task/related-task-create-form.html", true)
RelatedTaskCreateFormDirective = ($repo, $compile, $confirm, $tgmodel, $loading, $analytics) ->
newTask = {
subject: ""
assigned_to: null
}
link = ($scope, $el, $attrs) ->
createTask = debounce 2000, (task) ->
createTask = (task) ->
task.subject = $el.find('input').val()
task.assigned_to = $scope.newTask.assigned_to
task.status = $scope.newTask.status
@ -152,48 +150,53 @@ RelatedTaskCreateFormDirective = ($repo, $compile, $confirm, $tgmodel, $loading,
close = () ->
$el.off()
$el.html("")
$scope.newRelatedTaskFormOpen = false
$scope.openNewRelatedTask = false
reset = () ->
newTask = {
subject: ""
assigned_to: null
}
newTask["status"] = $scope.project.default_task_status
newTask["project"] = $scope.project.id
newTask["user_story"] = $scope.us.id
$scope.newTask = $tgmodel.make_model("tasks", newTask)
render = ->
$scope.newRelatedTaskFormOpen = true
$el.html($compile(template())($scope))
$el.find('input').focus().select()
$el.addClass('active')
$scope.openNewRelatedTask = true
$el.on "keyup", "input", (event)->
if event.keyCode == 13
createTask(newTask).then ->
render()
reset()
$el.find('input').focus()
else if event.keyCode == 27
$scope.$apply () -> close()
$el.on "click", ".icon-close", (event)->
$scope.$apply () -> close()
$scope.save = () ->
createTask(newTask).then ->
close()
$el.on "click", ".icon-save", (event)->
createTask(newTask).then ->
close()
taiga.bindOnce $scope, "us", (val) ->
newTask["status"] = $scope.project.default_task_status
newTask["project"] = $scope.project.id
newTask["user_story"] = $scope.us.id
$scope.newTask = $tgmodel.make_model("tasks", newTask)
$el.html("")
taiga.bindOnce $scope, "us", reset
$scope.$on "related-tasks:show-form", ->
render()
$scope.$apply(render)
$scope.$on "$destroy", ->
$el.off()
return {link: link}
return {
scope: true,
link: link,
templateUrl: 'task/related-task-create-form.html'
}
module.directive("tgRelatedTaskCreateForm", ["$tgRepo", "$compile", "$tgConfirm", "$tgModel", "$tgLoading",
"$tgAnalytics", "$tgTemplate", RelatedTaskCreateFormDirective])
"$tgAnalytics", RelatedTaskCreateFormDirective])
RelatedTaskCreateButtonDirective = ($repo, $compile, $confirm, $tgmodel, $template) ->
@ -287,6 +290,10 @@ RelatedTaskAssignedToInlineEditionDirective = ($repo, $rootscope, $translate) ->
notAutoSave = $scope.$eval($attrs.notAutoSave)
autoSave = !notAutoSave
$scope.$watch $attrs.tgRelatedTaskAssignedToInlineEdition, () ->
task = $scope.$eval($attrs.tgRelatedTaskAssignedToInlineEdition)
updateRelatedTask(task)
updateRelatedTask(task)
$el.on "click", ".task-assignedto", (event) ->

View File

@ -51,7 +51,9 @@ resourceProvider = ($repo, $http, $urls, $storage) ->
params = {"project": projectId, "milestone": "null"}
params = _.extend({}, params, filters or {})
service.storeQueryParams(projectId, params)
return $repo.queryMany("userstories", params)
return $repo.queryMany("userstories", params, {
enablePagination: true
}, true)
service.listAll = (projectId, filters) ->
params = {"project": projectId}

View File

@ -309,24 +309,22 @@ module.directive("tgTaskboard", ["$rootScope", TaskboardDirective])
TaskboardTaskDirective = ($rootscope, $loading, $rs, $rs2) ->
link = ($scope, $el, $attrs, $model) ->
$el.disableSelection()
$scope.$watch "task", (task) ->
if task.is_blocked and not $el.hasClass("blocked")
$el.addClass("blocked")
else if not task.is_blocked and $el.hasClass("blocked")
$el.removeClass("blocked")
$el.find(".icon-edit").on "click", (event) ->
if $el.find('.icon-edit').hasClass('noclick')
$el.find(".edit-task").on "click", (event) ->
if $el.find('.edit-task').hasClass('noclick')
return
$scope.$apply ->
target = $(event.target)
currentLoading = $loading()
.target(target)
.timeout(200)
.removeClasses("icon-edit")
.start()
task = $scope.task

View File

@ -39,9 +39,9 @@ module = angular.module("taigaBacklog")
TaskboardSortableDirective = ($repo, $rs, $rootscope) ->
link = ($scope, $el, $attrs) ->
bindOnce $scope, "project", (project) ->
bindOnce $scope, "tasks", (xx) ->
# If the user has not enough permissions we don't enable the sortable
if not (project.my_permissions.indexOf("modify_us") > -1)
if not ($scope.project.my_permissions.indexOf("modify_us") > -1)
return
oldParentScope = null
@ -55,16 +55,22 @@ TaskboardSortableDirective = ($repo, $rs, $rootscope) ->
itemEl.off()
itemEl.remove()
tdom.sortable({
handle: ".taskboard-task-inner",
dropOnEmpty: true
connectWith: ".taskboard-tasks-box"
revert: 400
containers = _.map $el.find('.task-column'), (item) ->
return item
drake = dragula(containers, {
copySortSource: false,
copy: false,
mirrorContainer: $el[0],
moves: (item) -> return $(item).hasClass('taskboard-task')
})
tdom.on "sortstop", (event, ui) ->
parentEl = ui.item.parent()
itemEl = ui.item
drake.on 'drag', (item) ->
oldParentScope = $(item).parent().scope()
drake.on 'dragend', (item) ->
parentEl = $(item).parent()
itemEl = $(item)
itemTask = itemEl.scope().task
itemIndex = itemEl.index()
newParentScope = parentEl.scope()
@ -80,14 +86,17 @@ TaskboardSortableDirective = ($repo, $rs, $rootscope) ->
$scope.$apply ->
$rootscope.$broadcast("taskboard:task:move", itemTask, newUsId, newStatusId, itemIndex)
ui.item.find('a').removeClass('noclick')
scroll = autoScroll(containers, {
margin: 20,
pixels: 30,
scrollWhenOutside: true,
autoScroll: () ->
return this.down && drake.dragging;
})
tdom.on "sortstart", (event, ui) ->
oldParentScope = ui.item.parent().scope()
ui.item.find('a').addClass('noclick')
$scope.$on "$destroy", ->
$el.off()
$scope.$on "$destroy", ->
$el.off()
drake.destroy()
return {link: link}

View File

@ -117,6 +117,13 @@ class WikiDetailController extends mixOf(taiga.Controller, taiga.PageMixin)
loadWikiLinks: ->
return @rs.wiki.listLinks(@scope.projectId).then (wikiLinks) =>
@scope.wikiLinks = wikiLinks
for link in @scope.wikiLinks
link.url = @navUrls.resolve("project-wiki-page", {
project: @scope.projectSlug
slug: link.href
})
selectedWikiLink = _.find(wikiLinks, {href: @scope.wikiSlug})
@scope.wikiTitle = selectedWikiLink.title if selectedWikiLink?
@ -258,8 +265,9 @@ EditableWikiContentDirective = ($window, $document, $repo, $confirm, $loading, $
currentLoading.finish()
$el.on "click", "a", (event) ->
target = angular.element(event.target)
target = angular.element(event.currentTarget)
href = target.attr('href')
if href.indexOf("#") == 0
event.preventDefault()
$('body').scrollTop($(href).offset().top)

View File

@ -35,7 +35,8 @@ module = angular.module("taigaWiki")
## Wiki Main Directive
#############################################################################
WikiNavDirective = ($tgrepo, $log, $location, $confirm, $navUrls, $analytics, $loading, $template, $compile, $translate) ->
WikiNavDirective = ($tgrepo, $log, $location, $confirm, $analytics, $loading, $template,
$compile, $translate) ->
template = $template.get("wiki/wiki-nav.html", true)
link = ($scope, $el, $attrs) ->
$ctrl = $el.controller()
@ -59,18 +60,6 @@ WikiNavDirective = ($tgrepo, $log, $location, $confirm, $navUrls, $analytics, $l
$el.off()
$el.html(html)
$el.on "click", ".wiki-link .link-title", (event) ->
event.preventDefault()
target = angular.element(event.currentTarget)
linkId = target.parents('.wiki-link').data('id')
linkSlug = $scope.wikiLinks[linkId].href
$scope.$apply ->
ctx = {
project: $scope.projectSlug
slug: linkSlug
}
$location.path($navUrls.resolve("project-wiki-page", ctx))
$el.on "click", ".add-button", (event) ->
event.preventDefault()
$el.find(".new").removeClass("hidden")
@ -146,5 +135,5 @@ WikiNavDirective = ($tgrepo, $log, $location, $confirm, $navUrls, $analytics, $l
return {link:link}
module.directive("tgWikiNav", ["$tgRepo", "$log", "$tgLocation", "$tgConfirm", "$tgNavUrls",
"$tgAnalytics", "$tgLoading", "$tgTemplate", "$compile", "$translate", WikiNavDirective])
module.directive("tgWikiNav", ["$tgRepo", "$log", "$tgLocation", "$tgConfirm", "$tgAnalytics",
"$tgLoading", "$tgTemplate", "$compile", "$translate", WikiNavDirective])

View File

@ -22,6 +22,12 @@
# File: utils.coffee
###
addClass = (el, className) ->
if (el.classList)
el.classList.add(className)
else
el.className += ' ' + className
nl2br = (str) =>
breakTag = '<br />'
return (str + '').replace(/([^>\r\n]?)(\r\n|\n\r|\r|\n)/g, '$1' + breakTag + '$2')
@ -222,6 +228,7 @@ patch = (oldImmutable, newImmutable) ->
return pathObj
taiga = @.taiga
taiga.addClass = addClass
taiga.nl2br = nl2br
taiga.bindMethods = bindMethods
taiga.bindOnce = bindOnce

573
app/js/dom-autoscroller.js Normal file
View File

@ -0,0 +1,573 @@
// The MIT License (MIT)
// Copyright (c) 2016 Quentin Engles
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
(function() {
// more_events
function MoreEvents(context){
this.listeners = {};
this.__context = context || this;
}
MoreEvents.prototype = {
constructor: MoreEvents,
on: function(event, listener){
this.listeners[event] = this.listeners[event] || [];
this.listeners[event].push(listener);
return this;
},
one: function(event, listener){
function onceListener(){
listener.apply(this, arguments);
this.off(event, onceListener);
return this;
}
return this.on(event, onceListener);
},
emit: function(event){
if(typeof this.listeners[event] === 'undefined' || !this.listeners[event].length)
return this;
var args = Array.prototype.slice.call(arguments, 1),
canRun = this.listeners[event].length;
do{
this.listeners[event][--canRun].apply(this.__context, args);
}while(canRun);
return this;
},
off: function(event, listener){
if(this.listeners[event] === undefined || !this.listeners[event].length)
return this;
this.listeners[event] = this.listeners[event].filter(function(item){
return item !== listener;
});
return this;
},
dispose: function(){
for(var n in this){
this[n] = null;
}
}
};
// pointer_point
var Emitter = MoreEvents;
if(!Date.now){ Date.now = function(){ return new Date().getTime() } }
function LocalDimensions(point, rect){
for(var n in rect)
setProp(this, n, rect[n]);
setProp(this, 'x', point.x - rect.left+1);
setProp(this, 'y', point.y - rect.top+1);
setProp(this, 'north', (((rect.bottom - rect.top) / 2)-this.y));
setProp(this, 'south', ((-(rect.bottom - rect.top) / 2)+this.y));
setProp(this, 'east', (((rect.right - rect.left) / 2)-this.x));
setProp(this, 'west', ((-(rect.right - rect.left) / 2)+this.x));
function setProp(self, name, value){
Object.defineProperty(self, name, {
value: value,
configurable: true,
writable: false
});
}
}
function Point(elements){
var self = this, el = [];
if(typeof elements.length === 'undefined'){
elements = [elements];
}
for(var i=0; i<elements.length; i++){
if(elements[i] !== undefined){
if(typeof elements[i] === 'string'){
try{
el.push(document.querySelector(e));
}catch(err){
throw new Error(e + ' is not a valid selector used by pointer.');
}
}else{
el.push(elements[i]);
}
}
}
var pos = {}, direction = {}, rect, local,
lastmousex=-1, lastmousey=-1, timestamp, mousetravel = 0,
startX=-1, startY=-1, scrolling = false, buf = 10, timeOut = false,
downTime;
var special = {
hold: []
};
this.emitter = new Emitter(this);
this.origin = null;
this.current = null;
this.previous = null;
window.addEventListener('mousedown', onDown, false);
window.addEventListener('mousemove', onMove, false);
window.addEventListener("mouseup", onUp, false);
window.addEventListener('touchstart', onDown, false);
window.addEventListener('touchmove', onMove, false);
window.addEventListener('touchend', onUp, false);
window.addEventListener('scroll', function(e){
scrolling = true;
clearTimeout(timeOut)
timeOut = setTimeout(function(){
scrolling = false;
}, 100)
});
function onDown(e){
downTime = Date.now();
toPoint(e);
self.down = true;
self.up = false;
if(self.current){
self.origin = self.current;
self.emitter.emit('down', self.current, local);
}
startX = self.x;
startY = self.y;
}
function onMove(e){
toPoint(e);
self.emitter.emit('move', self.current, local);
if(self.down && self.current){
self.emitter.emit('stroke', self.current, local);
}
}
function onUp(e){
self.down = false;
self.up = true;
if(self.current){
self.emitter.emit('up', self.current, local);
}
if(e.targetTouches){
//Allow click within buf. A 20x20 square.
if(!(self.y > (startY - buf) && self.y < (startY + buf) &&
self.x > (startX - buf) && self.x < (startX + buf))){
//If there is scrolling there was a touch flick.
if(!scrolling){
//No touch flick so
self.previous = null;
self.origin = null;
e.preventDefault();
return false;
}
}
}
scrolling = false;
self.previous = null;
self.origin = null;
}
function toPoint(event){
var dot, eventDoc, doc, body, pageX, pageY;
var target, newTarget = null, leaving = null;
event = event || window.event; // IE-ism
target = event.target || event.srcElement;
//Supporting touch
//http://www.creativebloq.com/javascript/make-your-site-work-touch-devices-51411644
if(event.targetTouches) {
event.pageX = event.targetTouches[0].clientX;
event.pageY = event.targetTouches[0].clientY;
event.clientX = event.targetTouches[0].clientX;
event.clientY = event.targetTouches[0].clientY;
}else
// If pageX/Y aren't available and clientX/Y are,
// calculate pageX/Y - logic taken from jQuery.
// (This is to support old IE)
if (event.pageX === null && event.clientX !== null) {
eventDoc = (event.target && event.target.ownerDocument) || document;
doc = eventDoc.documentElement;
body = eventDoc.body;
event.pageX = event.clientX +
(doc && doc.scrollLeft || body && body.scrollLeft || 0) -
(doc && doc.clientLeft || body && body.clientLeft || 0);
event.pageY = event.clientY +
(doc && doc.scrollTop || body && body.scrollTop || 0) -
(doc && doc.clientTop || body && body.clientTop || 0 );
}
if(self.x && self.y){
if(event.pageX < self.x)
direction.h = 'left';
else if(event.pageX > self.x)
direction.h = 'right';
if(event.pageY < self.y)
direction.v = 'up';
else if(event.pageY > self.y)
direction.v = 'down';
lastmousex = self.x;
lastmousey = self.y;
}
pos = {};
//Prefer the viewport with clientX, and clientY.
//pageX, and pageY change too often.
pos.x = event.clientX;//event.pageX;
pos.y = event.clientY;//event.pageY;
if(self.current === null || self.outside(self.current)){
for(var i=0; i<el.length; i++){
//console.log('inside el['+i+'] '+self.inside(el[i]));
if(el[i] === target || self.inside(el[i])){
//if(el[i] === target){
newTarget = el[i];
break;
}
}
leaving = self.current;
if(newTarget){
self.previous = self.current;
self.current = newTarget;
}
}
rect = self.current ? getRect(self.current) : null;
local = rect ? new LocalDimensions(self, rect) : null;
if(leaving){
if(!newTarget)
self.current = null;
self.emitter.emit('leave', leaving, local);
}
if(newTarget){
self.emitter.emit('enter', self.current, local);
}
}
//Get speed
//http://stackoverflow.com/questions/6417036/track-mouse-speed-with-js
Object.defineProperty(this, 'speedX', {
get: function(){
var now = Date.now() / 1000;
var dt = now - timestamp;
var dx = self.x - lastmousex;
timestamp = now;
return Math.round(dx / dt);// * 1000);
}
});
Object.defineProperty(this, 'speedY', {
get: function(){
var now = Date.now() / 1000;
var dt = now - timestamp;
var dy = self.y - lastmousey;
timestamp = now;
return Math.round(dy / dt);// * 1000);
}
});
Object.defineProperty(this, 'x', {
get: function(){
return pos.x;
}
});
Object.defineProperty(this, 'y', {
get: function(){
return pos.y;
}
});
Object.defineProperty(this, 'h', {
get: function(){
return direction.h;
}
});
Object.defineProperty(this, 'v', {
get: function(){
return direction.v;
}
});
this.emitter.on('up', function(el, rect){
if(downTime){
for(var i=0; i<special.hold.length; i++){
if(Date.now() > downTime + (special.hold[i].data || 2000)){
special.hold[i].callback.call(this, el, rect);
}
}
}
downTime = 0;
});
function removeSpecial(event, cb){
for(var i=0; i<special[event].length; i++){
if(special[event][i].callback === cb){
special[event].splice(i, 1);
return;
}
}
}
function addSpecial(event, data, cb){
if(typeof cb === 'undefined'){
cb = data;
data = null;
}
special[event].push({
data: data,
callback: cb
})
}
this.on = function(event, cb){
if(special[event]){
addSpecial(event, cb, arguments[2]);
return this;
}
this.emitter.on(event, cb);
return this;
};
this.off = function(event, cb){
if(special[event]){
removeSpecial(event, cb);
return this;
}
this.emitter.off(event, cb);
return this;
};
this.add = function(element){
if(typeof element === 'string'){
try{
el.push(document.querySelector(e));
}catch(err){
throw new Error(e + ' is not a valid selector, and can\'t be used add to pointer.');
}
}else if(!element){
throw new Error(e + ' can not be added to pointer.');
}
el.push(element);
};
this.destroy = function(){
window.removeEventListener('mousedown', onDown, false);
window.removeEventListener('mousemove', onMove, false);
window.removeEventListener('mouseup', onUp, false);
window.removeEventListener('touchstart', onDown, false);
window.removeEventListener('touchmove', onMove, false);
window.removeEventListener('touchend', onUp, false);
el = null;
self = null;
pos = null;
direction = null;
};
}
Point.prototype = {
constructor: Point,
inside: function(el){
if(!el) throw new TypeError('Cannot be inside '+el);
var rect = getRect(el);
return (this.y > rect.top && this.y < rect.bottom &&
this.x > rect.left && this.x < rect.right);
},
outside: function(el){
if(!el) throw new TypeError('Cannot be outside '+el);
return !this.inside(el);
}
};
function elementFromPoint(x, y){
if(document.getElementFromPoint)
return document.getElementFromPoint(x, y);
else
return document.elementFromPoint(x, y);
return null;
}
function safeObject(src){
var obj = {};
for(var n in src)
obj[n] = src[n];
return obj;
}
function getRect(el){
if(el === window){
return {
top: 0,
left: 0,
right: window.innerWidth,
bottom: window.innerHeight,
width: window.innerWidth,
height: window.innerHeight
};
}else{
return el.getBoundingClientRect();
}
}
var pointer = function(element){
return new Point(element);
};
// Autscroller
function AutoScrollerFactory(element, options){
return new AutoScroller(element, options);
}
function AutoScroller(elements, options){
var self = this, pixels = 2;
options = options || {};
this.margin = options.margin || -1;
this.scrolling = false;
this.scrollWhenOutside = options.scrollWhenOutside || false;
this.point = pointer(elements);
if(!isNaN(options.pixels)){
pixels = options.pixels;
}
if(typeof options.autoScroll === 'boolean'){
this.autoScroll = options.autoScroll ? function(){return true;} : function(){return false;};
}else if(typeof options.autoScroll === 'undefined'){
this.autoScroll = function(){return false;};
}else if(typeof options.autoScroll === 'function'){
this.autoScroll = options.autoScroll;
}
this.destroy = function() {
this.point.destroy();
};
Object.defineProperties(this, {
down: {
get: function(){ return self.point.down; }
},
interval: {
get: function(){ return 1/pixels * 1000; }
},
pixels: {
set: function(i){ pixels = i; },
get: function(){ return pixels; }
}
});
this.point.on('move', function(el, rect){
if(!el) return;
if(!self.autoScroll()) return;
if(!self.scrollWhenOutside && this.outside(el)) return;
if(self.point.y < rect.top + self.margin){
autoScrollV(el, -1, rect);
}else if(self.point.y > rect.bottom - self.margin){
autoScrollV(el, 1, rect);
}
if(self.point.x < rect.left + self.margin){
autoScrollH(el, -1, rect);
}else if(self.point.x > rect.right - self.margin){
autoScrollH(el, 1, rect);
}
});
function autoScrollV(el, amount, rect){
//if(!self.down) return;
if(!self.autoScroll()) return;
if(!self.scrollWhenOutside && self.point.outside(el)) return;
if(el === window){
window.scrollTo(el.pageXOffset, el.pageYOffset + amount);
}else{
el.scrollTop = el.scrollTop + amount;
}
setTimeout(function(){
if(self.point.y < rect.top + self.margin){
autoScrollV(el, amount, rect);
}else if(self.point.y > rect.bottom - self.margin){
autoScrollV(el, amount, rect);
}
}, self.interval);
}
function autoScrollH(el, amount, rect){
//if(!self.down) return;
if(!self.autoScroll()) return;
if(!self.scrollWhenOutside && self.point.outside(el)) return;
if(el === window){
window.scrollTo(el.pageXOffset + amount, el.pageYOffset);
}else{
el.scrollLeft = el.scrollLeft + amount;
}
setTimeout(function(){
if(self.point.x < rect.left + self.margin){
autoScrollH(el, amount, rect);
}else if(self.point.x > rect.right - self.margin){
autoScrollH(el, amount, rect);
}
}, self.interval);
}
}
window.autoScroll = AutoScrollerFactory;
}());

View File

@ -0,0 +1,221 @@
(function() {
var multipleSortableClass = 'ui-multisortable-multiple';
var mainClass = 'main-drag-item';
var inProgress = false;
var reset = function(elm) {
$(elm)
.removeAttr('style')
.removeClass('tg-backlog-us-mirror')
.removeClass('backlog-us-mirror')
.data('dragMultipleIndex', null)
.data('dragMultipleActive', false);
};
var sort = function(positions) {
var current = dragMultiple.items.elm;
positions.after.reverse();
$.each(positions.after, function () {
reset(this);
current.after(this);
});
$.each(positions.before, function () {
reset(this);
current.before(this);
});
};
var drag = function() {
var current = dragMultiple.items.elm;
var container = dragMultiple.items.container;
var shadow = dragMultiple.items.shadow;
// following the drag element
var currentLeft = shadow.position().left;
var currentTop = shadow.position().top;
var height = shadow.outerHeight();
_.forEach(dragMultiple.items.draggingItems, function(elm, index) {
var elmIndex = parseInt(elm.data('dragMultipleIndex'), 10);
var top = currentTop + (elmIndex * height);
elm
.css({
top: top,
left: currentLeft
});
});
};
var stop = function() {
inProgress = false;
refreshOriginal();
var current = dragMultiple.items.elm;
var container = dragMultiple.items.container;
$(window).off('mousemove.dragmultiple');
// reset
dragMultiple.items = {};
$('.' + mainClass).removeClass(mainClass);
$('.tg-backlog-us-mirror').remove();
$('.backlog-us-mirror').removeClass('backlog-us-mirror');
$('.tg-backlog-us-dragging')
.removeClass('tg-backlog-us-dragging')
.show();
return $('.' + multipleSortableClass);
};
var refreshOriginal = function() {
var index = parseInt(dragMultiple.items.elm.data('dragMultipleIndex'), 10);
var after = [];
var before = [];
_.forEach(dragMultiple.items.draggedItemsOriginal, function(item) {
if (parseInt($(item).data('dragMultipleIndex'), 10) > index) {
after.push(item);
} else {
before.push(item);
}
});
after.reverse();
_.forEach(after, function(item) {
$(item).insertAfter(dragMultiple.items.elm);
});
_.forEach(before, function(item) {
$(item).insertBefore(dragMultiple.items.elm);
});
};
var isMultiple = function(elm, container) {
var items = $(container).find('.' + multipleSortableClass);
if (!$(elm).hasClass(multipleSortableClass) || !(items.length > 1)) {
return false;
}
return true;
};
var setIndex = function(items) {
var before = [];
var after = [];
var mainFound = false;
_.forEach(items, function(item, index) {
if ($(item).data('dragMultipleIndex') === 0) {
mainFound = true;
return;
}
if (mainFound) {
after.push(item);
} else {
before.push(item);
}
});
before.reverse();
_.forEach(after, function(item, index) {
$(item).data('dragMultipleIndex', index + 1);
});
_.forEach(before, function(item, index) {
$(item).data('dragMultipleIndex', -index - 1);
});
};
var dragMultiple = {};
dragMultiple.prepare = function(elm, container) {
inProgress = true;
var items = $(container).find('.' + multipleSortableClass);
$(elm)
.data('dragmultiple:originalPosition', $(elm).position())
.data('dragMultipleActive', true);
dragMultiple.items = {};
dragMultiple.items.elm = $(elm);
dragMultiple.items.container = $(container);
dragMultiple.items.elm.data('dragMultipleIndex', 0);
setIndex(items);
dragMultiple.items.shadow = $('.gu-mirror');
dragMultiple.items.elm.addClass(mainClass);
items = _.filter(items, function(item) {
return !$(item).hasClass(mainClass);
});
dragMultiple.items.draggedItemsOriginal = items;
var itemsCloned = _.map(items, function (item) {
clone = $(item).clone(true);
clone
.addClass('backlog-us-mirror')
.addClass('tg-backlog-us-mirror')
.data('dragmultiple:originalPosition', $(item).position())
.data('dragMultipleActive', true)
.css({
zIndex: '9999',
opacity: '0.8',
position: 'fixed',
width: dragMultiple.items.elm.outerWidth(),
height: dragMultiple.items.elm.outerHeight()
});
$(item)
.hide()
.addClass('tg-backlog-us-dragging');
return clone;
});
dragMultiple.items.draggingItems = itemsCloned;
$(document.body).append(itemsCloned);
};
dragMultiple.start = function(item, container) {
if (isMultiple(item, container)) {
$(window).on('mousemove.dragmultiple', function() {
if (!inProgress) {
dragMultiple.prepare(item, container);
}
drag();
});
}
};
dragMultiple.stop = function() {
if (inProgress) {
return stop();
} else {
return [];
}
};
window.dragMultiple = dragMultiple;
}());

View File

@ -1,161 +0,0 @@
(function($) {
var multipleSortableClass = 'ui-multisortable-multiple';
var dragStarted = false;
var multiSort = {};
multiSort.isBelow = function(elm, compare) {
var elmOriginalPosition = elm.data('dragmultiple:originalPosition');
var compareOriginalPosition = compare.data('dragmultiple:originalPosition');
return elmOriginalPosition.top > compareOriginalPosition.top;
};
multiSort.reset = function(elm) {
$(elm)
.removeClass("ui-sortable-helper")
.removeAttr('style')
.data('dragMultipleActive', false);
};
multiSort.sort = function(current, positions) {
positions.after.reverse();
$.each(positions.after, function () {
multiSort.reset(this);
current.after(this);
});
$.each(positions.before, function () {
multiSort.reset(this);
current.before(this);
});
};
multiSort.sortPositions = function(elm, current) {
//saved if the elements are after or before the current
var insertAfter = [];
var insertBefore = [];
$(elm).find('.' + multipleSortableClass).each(function () {
var elm = $(this);
if (elm[0] === current[0] || !current.hasClass(multipleSortableClass)) return;
if (multiSort.isBelow(elm, current)) {
insertAfter.push(elm);
} else {
insertBefore.push(elm);
}
});
return {'after': insertAfter, 'before': insertBefore};
};
$.widget( "ui.sortable", $.ui.sortable, {
_mouseStart: function() {
dragStarted = false;
this._superApply( arguments );
},
_createHelper: function () {
var helper = this._superApply( arguments );
if ($(helper).hasClass(multipleSortableClass)) {
$(this.element).find('.' + multipleSortableClass).each(function () {
$(this)
.data('dragmultiple:originalPosition', $(this).position())
.data('dragMultipleActive', true);
});
}
return helper;
},
_mouseStop: function (event, ui) {
var current = this.helper;
var elms = [];
if (current.hasClass(multipleSortableClass)) {
elms = $(this.element).find('.' + multipleSortableClass);
}
if (!elms.length) {
elms = [current];
}
//save the order of the elements relative to the main
var positions = multiSort.sortPositions(this.element, current);
this._superApply( arguments );
if (this.element !== this.currentContainer.element) {
// change to another sortable list
multiSort.sort(current, positions);
$(this.currentContainer.element).trigger('multiplesortreceive', {
'item': current,
'items': elms,
'source': this.element
});
} else if (current.hasClass(multipleSortableClass)) {
// sort in the same list
multiSort.sort(current, positions);
}
$(this.element).trigger('multiplesortstop', {
'item': current,
'items': elms
});
},
_mouseDrag: function(key, value) {
this._super(key, value);
var current = this.helper;
if (!current.hasClass(multipleSortableClass)) return;
// following the drag element
var currentLeft = current.position().left;
var currentTop = current.position().top;
var currentZIndex = current.css('z-index');
var currentPosition = current.css('position');
var positions = multiSort.sortPositions(this.element, current);
positions.before.reverse();
[{'positions': positions.after, type: 'after'},
{'positions': positions.before, type: 'before'}]
.forEach(function (item) {
$.each(item.positions, function (index, elm) {
var top;
if (item.type === 'after') {
top = currentTop + ((index + 1) * current.outerHeight());
} else {
top = currentTop - ((index + 1) * current.outerHeight());
}
elm
.addClass("ui-sortable-helper")
.css({
width: elm.outerWidth(),
height: elm.outerHeight(),
position: currentPosition,
zIndex: currentZIndex,
top: top,
left: currentLeft
});
});
});
// it only refresh position the first time because
// jquery-ui has saved the old positions of the draggable elements
// and with this will remove all elements with dragMultipleActive
if (!dragStarted) {
dragStarted = true;
this.refreshPositions();
}
}
});
}(jQuery))

File diff suppressed because it is too large Load Diff

View File

@ -1,11 +0,0 @@
/*!
* jQuery UI Touch Punch 0.2.3
*
* Copyright 20112014, Dave Furfero
* Dual licensed under the MIT or GPL Version 2 licenses.
*
* Depends:
* jquery.ui.widget.js
* jquery.ui.mouse.js
*/
!function(a){function f(a,b){if(!(a.originalEvent.touches.length>1)){a.preventDefault();var c=a.originalEvent.changedTouches[0],d=document.createEvent("MouseEvents");d.initMouseEvent(b,!0,!0,window,1,c.screenX,c.screenY,c.clientX,c.clientY,!1,!1,!1,!1,0,null),a.target.dispatchEvent(d)}}if(a.support.touch="ontouchend"in document,a.support.touch){var e,b=a.ui.mouse.prototype,c=b._mouseInit,d=b._mouseDestroy;b._touchStart=function(a){var b=this;!e&&b._mouseCapture(a.originalEvent.changedTouches[0])&&(e=!0,b._touchMoved=!1,f(a,"mouseover"),f(a,"mousemove"),f(a,"mousedown"))},b._touchMove=function(a){e&&(this._touchMoved=!0,f(a,"mousemove"))},b._touchEnd=function(a){e&&(f(a,"mouseup"),f(a,"mouseout"),this._touchMoved||f(a,"click"),e=!1)},b._mouseInit=function(){var b=this;b.element.bind({touchstart:a.proxy(b,"_touchStart"),touchmove:a.proxy(b,"_touchMove"),touchend:a.proxy(b,"_touchEnd")}),c.call(b)},b._mouseDestroy=function(){var b=this;b.element.unbind({touchstart:a.proxy(b,"_touchStart"),touchmove:a.proxy(b,"_touchMove"),touchend:a.proxy(b,"_touchEnd")}),d.call(b)}}}(jQuery);

View File

@ -140,7 +140,8 @@
"BLOCKED_NOTE": "Nota de bloqueig",
"IS_BLOCKED": "està bloquejat",
"REF": "Ref",
"VOTES": "Vots"
"VOTES": "Vots",
"SPRINT": "Sprint"
},
"ROLES": {
"ALL": "Tot"
@ -355,7 +356,7 @@
"HOME": {
"PAGE_TITLE": "Home - Taiga",
"PAGE_DESCRIPTION": "La home de Taiga amb els teus projectes principals, totes les històries d'usuari, tasques i incidències que tens assignades i aquelles que estàs Watching",
"EMPTY_WORKING_ON": "<strong>Sembla buit, no?</strong> Comenceu a treballar amb Taiga i voràs ací les históries, tasques e incidències en les que estás treballant.",
"EMPTY_WORKING_ON": "<strong>It feels empty, doesn't it?</strong> Start working with Taiga and you'll see here the stories, tasks and issues you are working on.",
"EMPTY_WATCHING": "<strong>Segueix</strong> históries, tasques e incidéncies en els teus project i rep notificacions quan canvien :)",
"EMPTY_PROJECT_LIST": "No tens cap projecte encara",
"WORKING_ON_SECTION": "En Progrés",
@ -556,9 +557,8 @@
"PAGE_TITLE": "Rols - {{projectName}}",
"WARNING_NO_ROLE": "Ves amb compte, cap rol en el teu projecte pot estimar punts per a les històries d'usuari",
"HELP_ROLE_ENABLED": "Si està activat, els membres assignats a aquest rol podràn estimar els punts d'històries d'usuaris",
"DISABLE_COMPUTABLE_ALERT_TITLE": "Disable estimation for this role",
"DISABLE_COMPUTABLE_ALERT_TITLE": "Are you sure you want to disable this role estimations?",
"DISABLE_COMPUTABLE_ALERT_SUBTITLE": "If you disable estimation permissions for role {{roleName}} all previous estimations made by this role will be removed",
"DISABLE_COMPUTABLE_ALERT_MESSAGE": "<strong>Are you sure you want to disable this role estimations?</strong>",
"COUNT_MEMBERS": "{{ role.members_count }} membres amb aquest rol",
"TITLE_DELETE_ROLE": "Esborrar rol",
"REPLACEMENT_ROLE": "Tots els usuaris amb aquest rol es canviaran a",
@ -699,7 +699,6 @@
"ACCEPT": "Acceptar",
"REJECT": "Reject",
"PROPOSE_OWNERSHIP": "<strong>{{owner}}</strong>, the current owner of the project <strong>{{project}}</strong> has asked that you become the new project owner.",
"ADD_COMMENT_QUESTION": "Would you like to send a question to the project owner?",
"ADD_COMMENT": "Would you like to add a comment for the project owner?",
"UNLIMITED_PROJECTS": "Unlimited",
"OWNER_MESSAGE": {
@ -1413,6 +1412,7 @@
"PLACEHOLDER_PAGE": "Esciu pàgina del Wiki",
"REMOVE": "Esborrar pàgina de Wiki",
"DELETE_LIGHTBOX_TITLE": "Esborrar pàgina de Wiki",
"DELETE_LINK_TITLE": "Delete Wiki link",
"NAVIGATION": {
"SECTION_NAME": "Enllaços",
"ACTION_ADD_LINK": "Afegir link"

View File

@ -140,7 +140,8 @@
"BLOCKED_NOTE": "Blockierungsgrund",
"IS_BLOCKED": "wird blockiert",
"REF": "Ref",
"VOTES": "Stimmen"
"VOTES": "Stimmen",
"SPRINT": "Sprint"
},
"ROLES": {
"ALL": "Alle"
@ -355,7 +356,7 @@
"HOME": {
"PAGE_TITLE": "Home - Taiga",
"PAGE_DESCRIPTION": "Die Taiga Homepage mit Ihren wichtigsten Projekten und all Ihren zugeordneten und beobachteten User-Stories, Aufgaben und Tickets.",
"EMPTY_WORKING_ON": "<strong>Hier siehts ziemlich leer aus, oder?</strong> Beginne deine Arbeit mit Taiga und wir zeigen dir hier die Stories, Tasks und Issues an denen du arbeitest.",
"EMPTY_WORKING_ON": "<strong>It feels empty, doesn't it?</strong> Start working with Taiga and you'll see here the stories, tasks and issues you are working on.",
"EMPTY_WATCHING": "<strong>Folge</strong> User Stories, Tasks, Issues in deinem Projekt und erhalte Benachrichtigungen, wenn sich etwas ändert. :)",
"EMPTY_PROJECT_LIST": "Sie haben noch keine Projekte",
"WORKING_ON_SECTION": "Zuletzt bearbeitet",
@ -556,9 +557,8 @@
"PAGE_TITLE": "Rollen - {{projectName}}",
"WARNING_NO_ROLE": "Beachten Sie, keine Rolle in Ihrem Projekt wird in der Lage sein, die Punktevergabe für User-Stories einzuschätzen.",
"HELP_ROLE_ENABLED": "Wenn Sie dies freischalten, werden Mitglieder, denen diese Rolle zugewiesen ist, in der Lage sein, die Punktevergabe für User-Stories vorzunehmen.",
"DISABLE_COMPUTABLE_ALERT_TITLE": "Deaktiviere Estimatepoints für diese Rolle",
"DISABLE_COMPUTABLE_ALERT_TITLE": "Bist du sicher, dass in dieser Rolle Estimatepoints deaktivieren möchtest?",
"DISABLE_COMPUTABLE_ALERT_SUBTITLE": "Wenn du die Estimatepoints für die Rolle {{roleName}} deaktivierst, werden alle bisherigen gelöscht",
"DISABLE_COMPUTABLE_ALERT_MESSAGE": "<strong>Bist du sicher, dass in dieser Rolle Estimatepoints deaktivieren möchtest?</strong>",
"COUNT_MEMBERS": "{{ role.members_count }} Mitglieder mit dieser Rolle",
"TITLE_DELETE_ROLE": "Rolle löschen",
"REPLACEMENT_ROLE": "Alle Benutzer mit dieser Rolle werden verschoben nach",
@ -699,7 +699,6 @@
"ACCEPT": "Akzeptieren",
"REJECT": "Reject",
"PROPOSE_OWNERSHIP": "<strong>{{owner}}</strong>, the current owner of the project <strong>{{project}}</strong> has asked that you become the new project owner.",
"ADD_COMMENT_QUESTION": "Would you like to send a question to the project owner?",
"ADD_COMMENT": "Would you like to add a comment for the project owner?",
"UNLIMITED_PROJECTS": "Unlimited",
"OWNER_MESSAGE": {
@ -1413,6 +1412,7 @@
"PLACEHOLDER_PAGE": "Schreiben Sie Ihre Wiki Seite",
"REMOVE": "Diese Wiki Seite entfernen",
"DELETE_LIGHTBOX_TITLE": "Wiki Seite löschen",
"DELETE_LINK_TITLE": "Delete Wiki link",
"NAVIGATION": {
"SECTION_NAME": "Links",
"ACTION_ADD_LINK": "Link hinzufügen"

View File

@ -140,7 +140,8 @@
"BLOCKED_NOTE": "blocked note",
"IS_BLOCKED": "is blocked",
"REF": "Ref",
"VOTES": "Votes"
"VOTES": "Votes",
"SPRINT": "Sprint"
},
"ROLES": {
"ALL": "All"
@ -224,6 +225,7 @@
"CODE_BLOCK_SAMPLE_TEXT": "Your text here...",
"PREVIEW_BUTTON": "Preview",
"EDIT_BUTTON": "Edit",
"ATTACH_FILE_HELP": "Attach files by dragging & dropping on the textarea above.",
"MARKDOWN_HELP": "Markdown syntax help"
},
"PERMISIONS_CATEGORIES": {
@ -355,7 +357,7 @@
"HOME": {
"PAGE_TITLE": "Home - Taiga",
"PAGE_DESCRIPTION": "The Taiga home page with your main projects and all your assigned and watched user stories, tasks and issues",
"EMPTY_WORKING_ON": "<strong>It feels empty, doesn't it?</strong> Start working with Taiga and you'll see here the stories, tasks and issues you are workin on.",
"EMPTY_WORKING_ON": "<strong>It feels empty, doesn't it?</strong> Start working with Taiga and you'll see here the stories, tasks and issues you are working on.",
"EMPTY_WATCHING": "<strong>Follow</strong> User Stories, Tasks, Issues in your projects and be notified about its changes :)",
"EMPTY_PROJECT_LIST": "You don't have any projects yet",
"WORKING_ON_SECTION": "Working on",
@ -556,9 +558,8 @@
"PAGE_TITLE": "Roles - {{projectName}}",
"WARNING_NO_ROLE": "Be careful, no role in your project will be able to estimate the point value for user stories",
"HELP_ROLE_ENABLED": "When enabled, members assigned to this role will be able to estimate the point value for user stories",
"DISABLE_COMPUTABLE_ALERT_TITLE": "Disable estimation for this role",
"DISABLE_COMPUTABLE_ALERT_TITLE": "Are you sure you want to disable this role estimations?",
"DISABLE_COMPUTABLE_ALERT_SUBTITLE": "If you disable estimation permissions for role {{roleName}} all previous estimations made by this role will be removed",
"DISABLE_COMPUTABLE_ALERT_MESSAGE": "<strong>Are you sure you want to disable this role estimations?</strong>",
"COUNT_MEMBERS": "{{ role.members_count }} members with this role",
"TITLE_DELETE_ROLE": "Delete Role",
"REPLACEMENT_ROLE": "All the users with this role will be moved to",
@ -699,7 +700,6 @@
"ACCEPT": "Accept",
"REJECT": "Reject",
"PROPOSE_OWNERSHIP": "<strong>{{owner}}</strong>, the current owner of the project <strong>{{project}}</strong> has asked that you become the new project owner.",
"ADD_COMMENT_QUESTION": "Would you like to send a question to the project owner?",
"ADD_COMMENT": "Would you like to add a comment for the project owner?",
"UNLIMITED_PROJECTS": "Unlimited",
"OWNER_MESSAGE": {
@ -1413,6 +1413,7 @@
"PLACEHOLDER_PAGE": "Write your wiki page",
"REMOVE": "Remove this wiki page",
"DELETE_LIGHTBOX_TITLE": "Delete Wiki Page",
"DELETE_LINK_TITLE": "Delete Wiki link",
"NAVIGATION": {
"SECTION_NAME": "Links",
"ACTION_ADD_LINK": "Add link"

View File

@ -140,7 +140,8 @@
"BLOCKED_NOTE": "Motivo del bloqueo",
"IS_BLOCKED": "está bloqueada",
"REF": "Ref",
"VOTES": "Votos"
"VOTES": "Votos",
"SPRINT": "Sprint"
},
"ROLES": {
"ALL": "Todos"
@ -355,7 +356,7 @@
"HOME": {
"PAGE_TITLE": "Inicio - Taiga",
"PAGE_DESCRIPTION": "Página de inicio de Taiga, con tus proyectos principales y tus historias de usuario, tareas y peticiones en progreso asignadas y las que observas.",
"EMPTY_WORKING_ON": "<strong>Parece vacío no?</ strong> Empiece a trabajar con Taiga y verá aquí las historias, las tareas y los incidentes en los que está trabajando.",
"EMPTY_WORKING_ON": "<strong>It feels empty, doesn't it?</strong> Start working with Taiga and you'll see here the stories, tasks and issues you are working on.",
"EMPTY_WATCHING": "<strong>Sigue</strong> Historias de Usuario, Tareas y Peticiones en tus proyectos y se te notificará sobre sus cambios :)",
"EMPTY_PROJECT_LIST": "Todavía no tienes ningún proyecto",
"WORKING_ON_SECTION": "Trabajando en",
@ -556,9 +557,8 @@
"PAGE_TITLE": "Roles - {{projectName}}",
"WARNING_NO_ROLE": "Ojo, ningún rol en tu proyecto podrá estimar historias de usuario",
"HELP_ROLE_ENABLED": "Si lo activas, los miembros que posean este rol serán capaces de estimar las histórias de usuario",
"DISABLE_COMPUTABLE_ALERT_TITLE": "Deshabilitar las estimaciones para este rol",
"DISABLE_COMPUTABLE_ALERT_TITLE": "¿Seguro de que deseas deshabilitar las estimaciones para este rol?",
"DISABLE_COMPUTABLE_ALERT_SUBTITLE": "Si desactivas los permisos de estimación para el rol {{roleName}} todas las estimaciones previas hechas por ese rol se eliminarán",
"DISABLE_COMPUTABLE_ALERT_MESSAGE": "<strong>¿Seguro de que deseas deshabilitar las estimaciones para este rol?</strong>",
"COUNT_MEMBERS": "{{ role.members_count }} miembros con este rol",
"TITLE_DELETE_ROLE": "Borrar Rol",
"REPLACEMENT_ROLE": "Todos los usuarios con este rol serán movidos a",
@ -699,7 +699,6 @@
"ACCEPT": "Aceptar",
"REJECT": "Reject",
"PROPOSE_OWNERSHIP": "<strong>{{owner}}</strong>, the current owner of the project <strong>{{project}}</strong> has asked that you become the new project owner.",
"ADD_COMMENT_QUESTION": "Would you like to send a question to the project owner?",
"ADD_COMMENT": "Would you like to add a comment for the project owner?",
"UNLIMITED_PROJECTS": "Unlimited",
"OWNER_MESSAGE": {
@ -1413,6 +1412,7 @@
"PLACEHOLDER_PAGE": "Escribe el contenido de tu página",
"REMOVE": "Eliminar esta página del wiki",
"DELETE_LIGHTBOX_TITLE": "Eliminar Página del Wiki",
"DELETE_LINK_TITLE": "Delete Wiki link",
"NAVIGATION": {
"SECTION_NAME": "Enlaces",
"ACTION_ADD_LINK": "Añadir enlace"

View File

@ -140,7 +140,8 @@
"BLOCKED_NOTE": "estetty muistiinpano",
"IS_BLOCKED": "on estetty",
"REF": "Ref",
"VOTES": "Ääniä"
"VOTES": "Ääniä",
"SPRINT": "Kierros"
},
"ROLES": {
"ALL": "Kaikki"
@ -355,7 +356,7 @@
"HOME": {
"PAGE_TITLE": "Home - Taiga",
"PAGE_DESCRIPTION": "The Taiga home page with your main projects and all your assigned and watched user stories, tasks and issues",
"EMPTY_WORKING_ON": "<strong>It feels empty, doesn't it?</strong> Start working with Taiga and you'll see here the stories, tasks and issues you are workin on.",
"EMPTY_WORKING_ON": "<strong>It feels empty, doesn't it?</strong> Start working with Taiga and you'll see here the stories, tasks and issues you are working on.",
"EMPTY_WATCHING": "<strong>Follow</strong> User Stories, Tasks, Issues in your projects and be notified about its changes :)",
"EMPTY_PROJECT_LIST": "You don't have any projects yet",
"WORKING_ON_SECTION": "Working on",
@ -556,9 +557,8 @@
"PAGE_TITLE": "Roles - {{projectName}}",
"WARNING_NO_ROLE": "Ole varovainen, yksikään rooli projektissasi ei voi arvioida käyttäjätarinoidesi kokoa",
"HELP_ROLE_ENABLED": "Tämän roolin omaavat jäsenet voivat arvioida käyttäjätarinoiden kokoja",
"DISABLE_COMPUTABLE_ALERT_TITLE": "Disable estimation for this role",
"DISABLE_COMPUTABLE_ALERT_TITLE": "Are you sure you want to disable this role estimations?",
"DISABLE_COMPUTABLE_ALERT_SUBTITLE": "If you disable estimation permissions for role {{roleName}} all previous estimations made by this role will be removed",
"DISABLE_COMPUTABLE_ALERT_MESSAGE": "<strong>Are you sure you want to disable this role estimations?</strong>",
"COUNT_MEMBERS": "{{ role.members_count }} jäsentä joilla tämä rooli",
"TITLE_DELETE_ROLE": "Poista rooli",
"REPLACEMENT_ROLE": "Kaikki käyttäjä joilla on tämä rooli siirretään",
@ -699,7 +699,6 @@
"ACCEPT": "Hyväksy",
"REJECT": "Reject",
"PROPOSE_OWNERSHIP": "<strong>{{owner}}</strong>, the current owner of the project <strong>{{project}}</strong> has asked that you become the new project owner.",
"ADD_COMMENT_QUESTION": "Would you like to send a question to the project owner?",
"ADD_COMMENT": "Would you like to add a comment for the project owner?",
"UNLIMITED_PROJECTS": "Unlimited",
"OWNER_MESSAGE": {
@ -1413,6 +1412,7 @@
"PLACEHOLDER_PAGE": "Kirjoita wiki-sivu",
"REMOVE": "Poista tämä wiki-sivu",
"DELETE_LIGHTBOX_TITLE": "Poista wiki-sivu",
"DELETE_LINK_TITLE": "Delete Wiki link",
"NAVIGATION": {
"SECTION_NAME": "Linkit",
"ACTION_ADD_LINK": "Lisää linkki"

View File

@ -42,7 +42,7 @@
"CLIENT_REQUIREMENT": "Un besoin client est un nouveau besoin qui n'était pas prévu et qu'il est nécessaire d'intégrer au projet",
"TEAM_REQUIREMENT": "Un besoin projet est un besoin qui est nécessaire au projet mais qui ne doit avoir aucun impact pour le client",
"OWNER": "Propriétaire du Projet",
"CAPSLOCK_WARNING": "Be careful! You are using capital letters in an input field that is case sensitive.",
"CAPSLOCK_WARNING": "Attention ! Vous utilisez des majuscules dans un champ qui est sensible à la casse.",
"FORM_ERRORS": {
"DEFAULT_MESSAGE": "Cette valeur semble être invalide.",
"TYPE_EMAIL": "Cette valeur devrait être une adresse courriel valide.",
@ -67,8 +67,8 @@
"MAX_CHECK": "Vous devez sélectionner %s options ou moins.",
"RANGE_CHECK": "Vous devez sélectionner parmi les choix %s et %s.",
"EQUAL_TO": "Cette valeur doit être identique.",
"LINEWIDTH": "One or more lines is perhaps too long. Try to keep under %s characters.",
"PIKADAY": "Invalid date format, please use DD MMM YYYY (like 23 Mar 1984)"
"LINEWIDTH": "Une ou plusieurs lignes est peut-être trop long. Essayez de rester en dessous de %s caractères.",
"PIKADAY": "Format de date non valide, merci d'utiliser JJ MMM AAAA (comme 23 mar 1984)"
},
"PICKERDATE": {
"FORMAT": "DD MMM YYYY",
@ -140,7 +140,8 @@
"BLOCKED_NOTE": "note bloquée",
"IS_BLOCKED": "est bloqué",
"REF": "Réf.",
"VOTES": "Votes"
"VOTES": "Votes",
"SPRINT": "Sprint"
},
"ROLES": {
"ALL": "Tout"
@ -283,7 +284,7 @@
},
"LOGIN_COMMON": {
"HEADER": "J'ai déjà un identifiant Taiga",
"PLACEHOLDER_AUTH_NAME": "Nom d'utilisateur ou adresse courriel (sensible à la casse)",
"PLACEHOLDER_AUTH_NAME": "Nom d'utilisateur ou courriel (sensible à la casse)",
"LINK_FORGOT_PASSWORD": "Mot de passe oublié ?",
"TITLE_LINK_FORGOT_PASSWORD": "Avez-vous oublié votre mot de passe ?",
"ACTION_ENTER": "Entrer",
@ -318,8 +319,8 @@
"PLACEHOLDER_FIELD": "Nom d'utilisateur ou adresse courriel",
"ACTION_RESET_PASSWORD": "Réinitialiser le mot de passe",
"LINK_CANCEL": "Nan, ramenez-moi en arrière. Je crois que je m'en souviens.",
"SUCCESS_TITLE": "Check your inbox!",
"SUCCESS_TEXT": "We sent you an email with the instructions to set a new password",
"SUCCESS_TITLE": "Consultez votre boîte aux lettres !",
"SUCCESS_TEXT": "Nous vous avons envoyé un courriel avec les instructions pour définir un nouveau mot de passe",
"ERROR": "D'après nos Oompa Loompas, vous n'êtes pas encore enregistré."
},
"CHANGE_PASSWORD": {
@ -355,7 +356,7 @@
"HOME": {
"PAGE_TITLE": "Accueil - Taiga",
"PAGE_DESCRIPTION": "La page d'accueil de Taiga sur laquelle apparaissent vos projets principaux et toutes les récits utilisateur, tâches et tickets qui vont sont assignés et surveillés.",
"EMPTY_WORKING_ON": "<strong>C'est un peu vide, n'est-ce pas ?</strong> Commencez à utiliser Taiga et vous verrez ici les récits, tâches et tickets sur lesquels vous travaillez.",
"EMPTY_WORKING_ON": "<strong>It feels empty, doesn't it?</strong> Start working with Taiga and you'll see here the stories, tasks and issues you are working on.",
"EMPTY_WATCHING": "<strong>Suivez</strong> des récits utilisateur, des tâches, des tickets dans vos projets et soyez prévenu des modifications :)",
"EMPTY_PROJECT_LIST": "Vous n'avez aucun projet pour l'instant",
"WORKING_ON_SECTION": "Projets en cours",
@ -434,9 +435,9 @@
"BACKLOG": "Backlog",
"BACKLOG_DESCRIPTION": "Gérez votre récits utilisateur pour garder une vue organisée des travaux à venir et priorisés.",
"NUMBER_SPRINTS": "Nombre prévu de sprints",
"NUMBER_SPRINTS_HELP": "0 for an undetermined number",
"NUMBER_SPRINTS_HELP": "0 pour un nombre indéterminé",
"NUMBER_US_POINTS": "Total prévu de points d'histoire",
"NUMBER_US_POINTS_HELP": "0 for an undetermined number",
"NUMBER_US_POINTS_HELP": "0 pour un nombre indéterminé",
"KANBAN": "Kanban",
"KANBAN_DESCRIPTION": "Organisez votre projet de manière agile avec ce tableau.",
"ISSUES": "Tickets",
@ -474,15 +475,15 @@
"MAX_PRIVATE_PROJECTS_MEMBERS": "The maximum number of members for private projects has been exceeded",
"MAX_PUBLIC_PROJECTS": "Unfortunately, you've reached the maximum number of public projects allowed by your current plan",
"MAX_PUBLIC_PROJECTS_MEMBERS": "The project exceeds your maximum number of members for public projects",
"PROJECT_OWNER": "Project owner",
"REQUEST_OWNERSHIP": "Request ownership",
"REQUEST_OWNERSHIP_CONFIRMATION_TITLE": "Do you want to become the new project owner?",
"REQUEST_OWNERSHIP_DESC": "Request that current project owner {{name}} transfer ownership of this project to you.",
"PROJECT_OWNER": "Propriétaire du projet",
"REQUEST_OWNERSHIP": "Demander la propriété",
"REQUEST_OWNERSHIP_CONFIRMATION_TITLE": "Voulez-vous devenir le nouveau propriétaire du projet ?",
"REQUEST_OWNERSHIP_DESC": "Demander que le propriétaire actuel du projet {{name}} vous transfert la propriété.",
"REQUEST_OWNERSHIP_BUTTON": "Requête",
"REQUEST_OWNERSHIP_SUCCESS": "We'll notify the project owner",
"CHANGE_OWNER": "Change owner",
"CHANGE_OWNER_SUCCESS_TITLE": "Ok, your request has been sent!",
"CHANGE_OWNER_SUCCESS_DESC": "We will notify you by email if the project ownership request is accepted or declined"
"REQUEST_OWNERSHIP_SUCCESS": "Nous allons prévenir le propriétaire du projet",
"CHANGE_OWNER": "Changer le propriétaire",
"CHANGE_OWNER_SUCCESS_TITLE": "Ok, votre demande a été envoyée !",
"CHANGE_OWNER_SUCCESS_DESC": "Nous vous préviendrons par courriel si la demande de propriété du projet est acceptée ou refusée"
},
"REPORTS": {
"TITLE": "Rapports",
@ -556,13 +557,12 @@
"PAGE_TITLE": "Rôles - {{projectName}}",
"WARNING_NO_ROLE": "Attention, aucun rôle dans votre projet ne pourra estimer la valeur du point pour les récits utilisateurs",
"HELP_ROLE_ENABLED": "Si activé, les membres affectés à ce rôle pourront estimer la valeur du point pour les récits utilisateurs",
"DISABLE_COMPUTABLE_ALERT_TITLE": "Désactiver les estimations pour ce rôle",
"DISABLE_COMPUTABLE_ALERT_TITLE": "Êtes-vous sûr de vouloir désactiver les estimations de ce rôle ?",
"DISABLE_COMPUTABLE_ALERT_SUBTITLE": "Si vous désactivez les estimations pour le rôle {{roleName}} toutes les estimations précédentes faites par ce rôle seront supprimées",
"DISABLE_COMPUTABLE_ALERT_MESSAGE": "<strong>Êtes-vous sûr de vouloir désactiver les estimations de ce rôle ?</strong>",
"COUNT_MEMBERS": "{{ role.members_count }} membres avec ce rôle",
"TITLE_DELETE_ROLE": "Supprimer des rôles",
"REPLACEMENT_ROLE": "Tous les utilisateurs avec ce rôle seront déplacés dans",
"WARNING_DELETE_ROLE": "Be careful! All role estimations will be removed",
"WARNING_DELETE_ROLE": "Attention ! Toutes les estimations du rôle vont être supprimées",
"ERROR_DELETE_ALL": "Vous ne pouvez pas supprimer toutes les valeurs",
"EXTERNAL_USER": "Utilisateur externe"
},
@ -692,21 +692,20 @@
"TITLE": "Services"
},
"PROJECT_TRANSFER": {
"DO_YOU_ACCEPT_PROJECT_OWNERNSHIP": "Would you like to become the new project owner?",
"PRIVATE": "Private",
"ACCEPTED_PROJECT_OWNERNSHIP": "Congratulations! You're now the new project owner.",
"REJECTED_PROJECT_OWNERNSHIP": "OK. We'll contact the current project owner",
"DO_YOU_ACCEPT_PROJECT_OWNERNSHIP": "Voudriez-vous devenir le nouveau propriétaire du projet ?",
"PRIVATE": "Privé",
"ACCEPTED_PROJECT_OWNERNSHIP": "Félicitations ! Vous êtes maintenant le nouveau propriétaire du projet.",
"REJECTED_PROJECT_OWNERNSHIP": "OK. Nous allons contacter le propriétaire actuel du projet",
"ACCEPT": "Accepter",
"REJECT": "Reject",
"PROPOSE_OWNERSHIP": "<strong>{{owner}}</strong>, the current owner of the project <strong>{{project}}</strong> has asked that you become the new project owner.",
"ADD_COMMENT_QUESTION": "Would you like to send a question to the project owner?",
"ADD_COMMENT": "Would you like to add a comment for the project owner?",
"UNLIMITED_PROJECTS": "Unlimited",
"REJECT": "Rejeter",
"PROPOSE_OWNERSHIP": "<strong>{{owner}}</strong>, le propriétaire actuel du projet <strong>{{project}}</strong> a demandé à ce que vous soyez le nouveau propriétaire.",
"ADD_COMMENT": "Voulez-vous ajouter un commentaire pour le propriétaire du projet ?",
"UNLIMITED_PROJECTS": "Illimité",
"OWNER_MESSAGE": {
"PRIVATE": "Please remember that you can own up to <strong>{{maxProjects}}</strong> private projects. You currently own <strong>{{currentProjects}}</strong> private projects",
"PUBLIC": "Please remember that you can own up to <strong>{{maxProjects}}</strong> public projects. You currently own <strong>{{currentProjects}}</strong> public projects"
},
"CANT_BE_OWNED": "At the moment you cannot become an owner of a project of this type. If you would like to become the owner of this project, please contact the administrator so they change your account settings to enable project ownership.",
"CANT_BE_OWNED": "Pour le moment, vous ne pouvez devenir propriétaire d'un projet de ce type. Si vous voulez devenir propriétaire de ce projet, merci de contacter l'administrateur afin qu'il puisse modifier les paramètres de votre compte pour autoriser la propriété de projet.",
"CHANGE_MY_PLAN": "Change my plan"
}
},
@ -771,7 +770,7 @@
"BLOCKED_PROJECT": {
"BLOCKED": "Projet bloqué",
"THIS_PROJECT_IS_BLOCKED": "Ce projet est temporairement verrouillé",
"TO_UNBLOCK_CONTACT_THE_ADMIN_STAFF": "In order to unblock your projects, contact the administrator."
"TO_UNBLOCK_CONTACT_THE_ADMIN_STAFF": "Pour débloquer vos projets, merci de contacter l'administrateur."
},
"STATS": {
"PROJECT": "points<br/> projet",
@ -890,7 +889,7 @@
"NEWSLETTER_LABEL_TEXT": "Je ne veux plus recevoir votre bulletin d'information",
"CANCEL": "Retour aux réglages",
"ACCEPT": "Supprimer le compte",
"BLOCK_PROJECT": "Note that all the projects you own projects will be <strong>blocked</strong> after you delete your account. If you do want a project blocked, transfer ownership to another member of each project prior to deleting your account.",
"BLOCK_PROJECT": "Notez que tous les projets dont vous avez la propriété seront <strong>bloqués</strong> après que vous ayez supprimé votre compte. Si vous souhaitez pas qu'un projet soit bloqué, merci d'en transférer la propriété auprès d'un autre membre avant la suppression de votre compte.",
"SUBTITLE": "Sorry to see you go. We'll be here if you should ever consider us again! :("
},
"DELETE_PROJECT": {
@ -952,20 +951,20 @@
"LIMIT_USERS_WARNING_MESSAGE": "Unfortunately, this project can't have more than <strong>{{maxMembers}}</strong> members."
},
"LEAVE_PROJECT_WARNING": {
"TITLE": "Unfortunately, this project can't be left without an owner",
"TITLE": "Malheureusement, ce projet ne peut pas être laissé sans propriétaire",
"CURRENT_USER_OWNER": {
"DESC": "You are the current owner of this project. Before leaving, please transfer ownership to someone else.",
"BUTTON": "Change the project owner"
"DESC": "Vous êtes le propriétaire actuel de ce projet. Avant de partir, merci de transférer la propriété du projet à quelqu'un d'autre.",
"BUTTON": "Changer le propriétaire du projet"
},
"OTHER_USER_OWNER": {
"DESC": "Unfortunately, you can't delete a member who is also the current project owner. First, please assign a new project owner.",
"BUTTON": "Request project owner change"
"DESC": "Malheureusement, vous ne pouvez supprimer un membre s'il est également le propriétaire actuel du projet. Merci de désigner auparavant un nouveau propriétaire.",
"BUTTON": "Demander le changement de propriétaire du projet"
}
},
"CHANGE_OWNER": {
"TITLE": "Who do you want to be the new project owner?",
"ADD_COMMENT": "Add comment",
"BUTTON": "Ask this project member to become the new project owner"
"TITLE": "Qui voulez-vous désigner comme le nouveau propriétaire du projet ?",
"ADD_COMMENT": "Ajouter un commentaire",
"BUTTON": "Demander à ce membre du projet de devenir le nouveau propriétaire"
}
},
"US": {
@ -1395,7 +1394,7 @@
"WIZARD": {
"SECTION_TITLE_CREATE_PROJECT": "Créer un projet",
"CREATE_PROJECT_TEXT": "Tout beau, tout nouveau !",
"CHOOSE_TEMPLATE": "Which template fits your project best?",
"CHOOSE_TEMPLATE": "Quel modèle convient mieux à votre projet ?",
"CHOOSE_TEMPLATE_TITLE": "Plus d'information sur les templates de projets",
"CHOOSE_TEMPLATE_INFO": "Plus d'informations",
"PROJECT_DETAILS": "Détails du projet",
@ -1413,6 +1412,7 @@
"PLACEHOLDER_PAGE": "Ecrivez votre page wiki",
"REMOVE": "Supprimer cette page wiki",
"DELETE_LIGHTBOX_TITLE": "Supprimer la page Wiki",
"DELETE_LINK_TITLE": "Delete Wiki link",
"NAVIGATION": {
"SECTION_NAME": "Liens",
"ACTION_ADD_LINK": "Ajouter un lien"

View File

@ -140,7 +140,8 @@
"BLOCKED_NOTE": "nota bloccata",
"IS_BLOCKED": "è bloccato",
"REF": "Riferimento",
"VOTES": "Voti"
"VOTES": "Voti",
"SPRINT": "Sprint"
},
"ROLES": {
"ALL": "Tutti"
@ -355,7 +356,7 @@
"HOME": {
"PAGE_TITLE": "Home - Taiga",
"PAGE_DESCRIPTION": "La home di Taiga con i tuoi principali progetti e tutte le storie utente, i compiti e problemi assegnati e osservati. ",
"EMPTY_WORKING_ON": "<strong>Dà un po' l'idea di vuoto, no?</strong> Inizia a lavorare con Taiga e qui vedrai le storie, i compiti ed i problemi su cui stai lavorando.",
"EMPTY_WORKING_ON": "<strong>It feels empty, doesn't it?</strong> Start working with Taiga and you'll see here the stories, tasks and issues you are working on.",
"EMPTY_WATCHING": "<strong>Ossserva</strong> Storie Utente, Compiti, Criticità nel progetto e ti verranno notificate le sue modifiche :)",
"EMPTY_PROJECT_LIST": "Per ora non hai nessun progetto",
"WORKING_ON_SECTION": "Sta lavorando su",
@ -556,9 +557,8 @@
"PAGE_TITLE": "Ruoli - {{projectName}}",
"WARNING_NO_ROLE": "Attento, nessun ruolo, all'interno del tuo progetto, potrà stimare i punti valore per le storie utente",
"HELP_ROLE_ENABLED": "Una volta abilitato, chi é associato a questo ruolo sará in grado di stimare il valore dei punti per le storie utente",
"DISABLE_COMPUTABLE_ALERT_TITLE": "Disabilita la stime per questo ruolo",
"DISABLE_COMPUTABLE_ALERT_TITLE": "sei sicuro di voler disabilitare la stime di questo ruolo?",
"DISABLE_COMPUTABLE_ALERT_SUBTITLE": "Se disabiliti i permessi di stime per {{roleName}} tutte le stime precedenti di questo ruolo saranno rimosse",
"DISABLE_COMPUTABLE_ALERT_MESSAGE": "<strong>sei sicuro di voler disabilitare la stime di questo ruolo?</strong>",
"COUNT_MEMBERS": "{{ role.members_count }} membri con questo ruolo",
"TITLE_DELETE_ROLE": "Elimina ruolo",
"REPLACEMENT_ROLE": "Tutti gli utenti con questo ruolo saranno spostati a ",
@ -699,7 +699,6 @@
"ACCEPT": "Accetta",
"REJECT": "Reject",
"PROPOSE_OWNERSHIP": "<strong>{{owner}}</strong>, the current owner of the project <strong>{{project}}</strong> has asked that you become the new project owner.",
"ADD_COMMENT_QUESTION": "Would you like to send a question to the project owner?",
"ADD_COMMENT": "Would you like to add a comment for the project owner?",
"UNLIMITED_PROJECTS": "Unlimited",
"OWNER_MESSAGE": {
@ -1413,6 +1412,7 @@
"PLACEHOLDER_PAGE": "Crea la tua pagina wiki",
"REMOVE": "Rimuovi questa pagina wiki",
"DELETE_LIGHTBOX_TITLE": "Elimina Pagina Wiki",
"DELETE_LINK_TITLE": "Delete Wiki link",
"NAVIGATION": {
"SECTION_NAME": "Link",
"ACTION_ADD_LINK": "Aggiungi link"

View File

@ -140,7 +140,8 @@
"BLOCKED_NOTE": "geblokkeerde notitie",
"IS_BLOCKED": "is geblokkeerd",
"REF": "Ref",
"VOTES": "Stemmen"
"VOTES": "Stemmen",
"SPRINT": "Sprint"
},
"ROLES": {
"ALL": "Alles"
@ -355,7 +356,7 @@
"HOME": {
"PAGE_TITLE": "Home -Taiga",
"PAGE_DESCRIPTION": "De Taiga start pagina met jouw projecten en de aan jou toegewezen en gevolgde user stories, taken en issues",
"EMPTY_WORKING_ON": "<strong>Beetje kaal, vind je niet?</strong> Als je aan de slag gaat met Taiga, zie je hier de stories, taken en issues waar je aan werkt",
"EMPTY_WORKING_ON": "<strong>It feels empty, doesn't it?</strong> Start working with Taiga and you'll see here the stories, tasks and issues you are working on.",
"EMPTY_WATCHING": "<strong>Volg</strong> User Stories, Taken, Issues binnen jouw projecten en ontvang een bericht bij veranderingen :)",
"EMPTY_PROJECT_LIST": "Je hebt nog geen projecten",
"WORKING_ON_SECTION": "Werkt aan",
@ -556,9 +557,8 @@
"PAGE_TITLE": "Rollen - {{projectName}}",
"WARNING_NO_ROLE": "Wees voorzichtig, geen enkele rol in je project zal de puntenwaarde van een user story kunnen estimeren",
"HELP_ROLE_ENABLED": "Als dit actief is, zullen leden met deze rol de punten waarde voor user stories kunnen schatten",
"DISABLE_COMPUTABLE_ALERT_TITLE": "Disable estimation for this role",
"DISABLE_COMPUTABLE_ALERT_TITLE": "Are you sure you want to disable this role estimations?",
"DISABLE_COMPUTABLE_ALERT_SUBTITLE": "If you disable estimation permissions for role {{roleName}} all previous estimations made by this role will be removed",
"DISABLE_COMPUTABLE_ALERT_MESSAGE": "<strong>Are you sure you want to disable this role estimations?</strong>",
"COUNT_MEMBERS": "{{ role.members_count }} leden met deze rol",
"TITLE_DELETE_ROLE": "Verwijder Rol",
"REPLACEMENT_ROLE": "Al de gebruikers met deze rol zullen verplaats worden naar",
@ -699,7 +699,6 @@
"ACCEPT": "Accepteren",
"REJECT": "Reject",
"PROPOSE_OWNERSHIP": "<strong>{{owner}}</strong>, the current owner of the project <strong>{{project}}</strong> has asked that you become the new project owner.",
"ADD_COMMENT_QUESTION": "Would you like to send a question to the project owner?",
"ADD_COMMENT": "Would you like to add a comment for the project owner?",
"UNLIMITED_PROJECTS": "Unlimited",
"OWNER_MESSAGE": {
@ -1413,6 +1412,7 @@
"PLACEHOLDER_PAGE": "Schrijf je wiki pagina",
"REMOVE": "Verwijder deze wiki pagina",
"DELETE_LIGHTBOX_TITLE": "Verwijderd wiki pagina",
"DELETE_LINK_TITLE": "Delete Wiki link",
"NAVIGATION": {
"SECTION_NAME": "Links",
"ACTION_ADD_LINK": "Link toevoegen"

View File

@ -140,7 +140,8 @@
"BLOCKED_NOTE": "zablokowana notka",
"IS_BLOCKED": "zablokowana",
"REF": "Ref",
"VOTES": "Głosy"
"VOTES": "Głosy",
"SPRINT": "Sprint"
},
"ROLES": {
"ALL": "Wszystko"
@ -355,7 +356,7 @@
"HOME": {
"PAGE_TITLE": "Strona główna - Taiga",
"PAGE_DESCRIPTION": "Główna strona Taiga, z Twoimi głównymi projektami i wszystkimi przypisanymi Tobie i obserwowanymi historyjkami użytkownika, zadaniami i zgłoszeniami.",
"EMPTY_WORKING_ON": "<strong>Trochę tu pusto?</strong>Rozpocznij pracę z Taigą, a pojawią się tutaj historie, zadania oraz zgłoszone błędy, nad którymi pracujesz.",
"EMPTY_WORKING_ON": "<strong>It feels empty, doesn't it?</strong> Start working with Taiga and you'll see here the stories, tasks and issues you are working on.",
"EMPTY_WATCHING": "<strong>Follow</strong> User Stories, Tasks, Issues in your projects and be notified about its changes :)",
"EMPTY_PROJECT_LIST": "Nie masz jeszcze żadnych projektów",
"WORKING_ON_SECTION": "Pracujesz nad",
@ -556,9 +557,8 @@
"PAGE_TITLE": "Role - {{projectName}}",
"WARNING_NO_ROLE": "Bez przydzielenia ról w projekcie nie ma możliwości oceniania historyjek użytkownika. Umpa Lumpy nie będą wiedziały komu wolno to zrobić :)",
"HELP_ROLE_ENABLED": "Jeśli aktywne użytkownicy pełniący tę rolę będą mogli szacować wartości historyjek",
"DISABLE_COMPUTABLE_ALERT_TITLE": "Disable estimation for this role",
"DISABLE_COMPUTABLE_ALERT_TITLE": "Are you sure you want to disable this role estimations?",
"DISABLE_COMPUTABLE_ALERT_SUBTITLE": "If you disable estimation permissions for role {{roleName}} all previous estimations made by this role will be removed",
"DISABLE_COMPUTABLE_ALERT_MESSAGE": "<strong>Are you sure you want to disable this role estimations?</strong>",
"COUNT_MEMBERS": "{{ role.members_count }} użytkowników pełniących tę rolę w projekcie",
"TITLE_DELETE_ROLE": "Usuń rolę",
"REPLACEMENT_ROLE": "Wszyscy użytkownicy pełniący tę rolę zostaną przeniesieni do",
@ -699,7 +699,6 @@
"ACCEPT": "Akceptuj",
"REJECT": "Reject",
"PROPOSE_OWNERSHIP": "<strong>{{owner}}</strong>, the current owner of the project <strong>{{project}}</strong> has asked that you become the new project owner.",
"ADD_COMMENT_QUESTION": "Would you like to send a question to the project owner?",
"ADD_COMMENT": "Would you like to add a comment for the project owner?",
"UNLIMITED_PROJECTS": "Unlimited",
"OWNER_MESSAGE": {
@ -1413,6 +1412,7 @@
"PLACEHOLDER_PAGE": "Napisz swoje Wiki",
"REMOVE": "Usuń tą stronę Wiki",
"DELETE_LIGHTBOX_TITLE": "Usuń tą stronę Wiki",
"DELETE_LINK_TITLE": "Delete Wiki link",
"NAVIGATION": {
"SECTION_NAME": "Linki",
"ACTION_ADD_LINK": "Dodaj link"

View File

@ -41,7 +41,7 @@
"IOCAINE_TEXT": "Se sentindo sobrecarregado por uma tarefa? Assegure-se de que os outros saibam disso clicando em Iocaine quando estiver editando a tarefa. É possível se tornar imune a essse veneno mortal (fictício) consumindo pequenas quantidades ao longo do tempo, assim como é possível ficar melhor no que faz, ocasionalmente, por assumir desafios extras!",
"CLIENT_REQUIREMENT": "Client requirement is new requirement that was not previously expected and it is required to be part of the project",
"TEAM_REQUIREMENT": "Team requirement is a requirement that must exist in the project but should have no cost for the client",
"OWNER": "Project Owner",
"OWNER": "Dono do Projeto",
"CAPSLOCK_WARNING": "Be careful! You are using capital letters in an input field that is case sensitive.",
"FORM_ERRORS": {
"DEFAULT_MESSAGE": "Este valor parece ser inválido.",
@ -140,7 +140,8 @@
"BLOCKED_NOTE": "Nota de bloqueio",
"IS_BLOCKED": "está bloqueada",
"REF": "Ref",
"VOTES": "Votos"
"VOTES": "Votos",
"SPRINT": "Sprint"
},
"ROLES": {
"ALL": "Tudo"
@ -318,8 +319,8 @@
"PLACEHOLDER_FIELD": "Nome de usuário ou email",
"ACTION_RESET_PASSWORD": "Resetar Senha",
"LINK_CANCEL": "Nããão, me leve de volta. Acho que me lembrei.",
"SUCCESS_TITLE": "Check your inbox!",
"SUCCESS_TEXT": "We sent you an email with the instructions to set a new password",
"SUCCESS_TITLE": "Verifique sua caixa de entrada!",
"SUCCESS_TEXT": "Nós lhe enviamos um e-mail com instruções para definição de uma nova senha.",
"ERROR": "Segundo nossos Oompa Loompas, você ainda não está inscrito."
},
"CHANGE_PASSWORD": {
@ -355,8 +356,8 @@
"HOME": {
"PAGE_TITLE": "Início - Taiga",
"PAGE_DESCRIPTION": "A página inicial do Taiga com seus principais projetos e todas as estórias atribuídas ou observadas por você, tarefas e problemas",
"EMPTY_WORKING_ON": "<strong>Isso parece vazio não acha?</strong> Comece a trabalhar com Taiga para começar a ver estórias, tarefas e problemas em que está trabalhando.",
"EMPTY_WATCHING": "<strong>Siga</strong> Estórias, Tarefas e Problemas nos seus projetos e seja notificado das mudanças :)",
"EMPTY_WORKING_ON": "<strong>It feels empty, doesn't it?</strong> Start working with Taiga and you'll see here the stories, tasks and issues you are working on.",
"EMPTY_WATCHING": "<strong>Siga</strong> Estórias, Tarefas e Casos nos seus projetos e seja notificado das mudanças :)",
"EMPTY_PROJECT_LIST": "Você ainda não tem projetos",
"WORKING_ON_SECTION": "Trabalhando em",
"WATCHING_SECTION": "Observando",
@ -476,7 +477,7 @@
"MAX_PUBLIC_PROJECTS_MEMBERS": "The project exceeds your maximum number of members for public projects",
"PROJECT_OWNER": "Project owner",
"REQUEST_OWNERSHIP": "Request ownership",
"REQUEST_OWNERSHIP_CONFIRMATION_TITLE": "Do you want to become the new project owner?",
"REQUEST_OWNERSHIP_CONFIRMATION_TITLE": "Gostaria de se tornar o novo dono do projeto?",
"REQUEST_OWNERSHIP_DESC": "Request that current project owner {{name}} transfer ownership of this project to you.",
"REQUEST_OWNERSHIP_BUTTON": "Solicitação",
"REQUEST_OWNERSHIP_SUCCESS": "We'll notify the project owner",
@ -556,9 +557,8 @@
"PAGE_TITLE": "Funções - {{projectName}}",
"WARNING_NO_ROLE": "Seja cuidadoso, nenhuma função em seu projeto será capaz de estimar o valor dos pontos para as user stories",
"HELP_ROLE_ENABLED": "Quando habilitado, membros atribuídos a esta função serão capazes de estimar valores para user stories",
"DISABLE_COMPUTABLE_ALERT_TITLE": "Desativar estimativa para esta permissão",
"DISABLE_COMPUTABLE_ALERT_TITLE": "Você tem certeza que quer desativar esta permissão de estimativas?",
"DISABLE_COMPUTABLE_ALERT_SUBTITLE": "Se você desativar a permissão de estimativas para esta regra {{roleName}} todas estimativas feitas anteriormente por esta regra serão removidas.",
"DISABLE_COMPUTABLE_ALERT_MESSAGE": "<strong>Você tem certeza que quer desativar esta permissão de estimativas?</strong>",
"COUNT_MEMBERS": "{{ role.members_count }} membros com a mesma função",
"TITLE_DELETE_ROLE": "Apagar Função",
"REPLACEMENT_ROLE": "Todos os usuários com essa função serão movidos para",
@ -699,7 +699,6 @@
"ACCEPT": "Aceitar",
"REJECT": "Reject",
"PROPOSE_OWNERSHIP": "<strong>{{owner}}</strong>, the current owner of the project <strong>{{project}}</strong> has asked that you become the new project owner.",
"ADD_COMMENT_QUESTION": "Would you like to send a question to the project owner?",
"ADD_COMMENT": "Would you like to add a comment for the project owner?",
"UNLIMITED_PROJECTS": "Unlimited",
"OWNER_MESSAGE": {
@ -888,8 +887,8 @@
"SECTION_NAME": "Apagar conta no Taiga",
"CONFIRM": "Você tem certeza que quer apagar sua conta Taiga?",
"NEWSLETTER_LABEL_TEXT": "Eu não quero receber mais os informativos",
"CANCEL": "Back to settings",
"ACCEPT": "Delete account",
"CANCEL": "Voltar para configurações",
"ACCEPT": "Remover conta",
"BLOCK_PROJECT": "Note that all the projects you own projects will be <strong>blocked</strong> after you delete your account. If you do want a project blocked, transfer ownership to another member of each project prior to deleting your account.",
"SUBTITLE": "Sorry to see you go. We'll be here if you should ever consider us again! :("
},
@ -1399,8 +1398,8 @@
"CHOOSE_TEMPLATE_TITLE": "More info about project templates",
"CHOOSE_TEMPLATE_INFO": "More info",
"PROJECT_DETAILS": "Project Details",
"PUBLIC_PROJECT": "Public Project",
"PRIVATE_PROJECT": "Private Project",
"PUBLIC_PROJECT": "Projeto Público",
"PRIVATE_PROJECT": "Projeto Privado",
"CREATE_PROJECT": "Criar projeto",
"MAX_PRIVATE_PROJECTS": "You've reached the maximum number of private projects",
"MAX_PUBLIC_PROJECTS": "Unfortunately, you've reached the maximum number of public projects",
@ -1413,6 +1412,7 @@
"PLACEHOLDER_PAGE": "Escreve sua página wiki",
"REMOVE": "Remover essa página wiki",
"DELETE_LIGHTBOX_TITLE": "Apagar página Wiki",
"DELETE_LINK_TITLE": "Delete Wiki link",
"NAVIGATION": {
"SECTION_NAME": "Links",
"ACTION_ADD_LINK": "Adicionar link"

View File

@ -140,7 +140,8 @@
"BLOCKED_NOTE": "Пояснение блокировки",
"IS_BLOCKED": "заблокирован",
"REF": "Ссылка",
"VOTES": "Голоса"
"VOTES": "Голоса",
"SPRINT": "Спринт"
},
"ROLES": {
"ALL": "Все"
@ -355,7 +356,7 @@
"HOME": {
"PAGE_TITLE": "Домашняя страница - Taiga",
"PAGE_DESCRIPTION": "Главная страница Taiga с вашими основными проектами, назначенными и отслеживаемыми ПИ, задачами и запросами",
"EMPTY_WORKING_ON": "<strong>Пустовато, не правда ли?</strong> Начните работать в Taiga - и тут появятся ПИ, задачи и запросы, над которыми вы работаете.",
"EMPTY_WORKING_ON": "<strong>It feels empty, doesn't it?</strong> Start working with Taiga and you'll see here the stories, tasks and issues you are working on.",
"EMPTY_WATCHING": "<strong>Следите</strong> за пользовательскими историями, задачами, запросами в ваших проектах и будьте уведомлены об изменениях :)",
"EMPTY_PROJECT_LIST": "У Вас пока нет проектов",
"WORKING_ON_SECTION": "Работает над",
@ -556,9 +557,8 @@
"PAGE_TITLE": "Роли - {{projectName}}",
"WARNING_NO_ROLE": "Осторожнее: ни с какими ролями на вашем проекте участники не смогут оценить очки для пользовательских историй.",
"HELP_ROLE_ENABLED": "Когда включено, участники, назначенные на эту роль, смогут оценивать очки для пользовательских историй",
"DISABLE_COMPUTABLE_ALERT_TITLE": "Отключить оценку очков для этой роли",
"DISABLE_COMPUTABLE_ALERT_TITLE": "Вы уверены, что хотите отключить оценку очков для этой роли?",
"DISABLE_COMPUTABLE_ALERT_SUBTITLE": "If you disable estimation permissions for role {{roleName}} all previous estimations made by this role will be removed",
"DISABLE_COMPUTABLE_ALERT_MESSAGE": "<strong>Вы уверены, что хотите отключить оценку очков для этой роли?</strong>",
"COUNT_MEMBERS": "{{ role.members_count }} участников с этой ролью",
"TITLE_DELETE_ROLE": "Удалить Роль",
"REPLACEMENT_ROLE": "Все пользователи этой роли будут перемещены в",
@ -699,7 +699,6 @@
"ACCEPT": "Принимаю",
"REJECT": "Reject",
"PROPOSE_OWNERSHIP": "<strong>{{owner}}</strong>, the current owner of the project <strong>{{project}}</strong> has asked that you become the new project owner.",
"ADD_COMMENT_QUESTION": "Would you like to send a question to the project owner?",
"ADD_COMMENT": "Would you like to add a comment for the project owner?",
"UNLIMITED_PROJECTS": "Unlimited",
"OWNER_MESSAGE": {
@ -1413,6 +1412,7 @@
"PLACEHOLDER_PAGE": "Создать вики страницу",
"REMOVE": "Удалить эту вики страницу",
"DELETE_LIGHTBOX_TITLE": "Удалить вики страницу",
"DELETE_LINK_TITLE": "Delete Wiki link",
"NAVIGATION": {
"SECTION_NAME": "Ссылки",
"ACTION_ADD_LINK": "Добавить ссылку"

View File

@ -35,7 +35,7 @@
"ONE_ITEM_LINE": "En post per rad ...",
"NEW_BULK": "Lägg till flera nya",
"RELATED_TASKS": "Besläktade uppgifter",
"LOGOUT": "Logg ut",
"LOGOUT": "Logga ut",
"EXTERNAL_USER": "en extern användare",
"GENERIC_ERROR": "En av våra Oompa Loompier säger {{error}}.",
"IOCAINE_TEXT": "Känner du dig lite bortkommen med en uppgift? Försäkra dig om att andra känner till uppgiften när du klickar på Iocaine-knappen när du ändrar uppgiften. Det är möjligt att bli immun till det här (påhittade) dödliga giftet om du tar små mängder över tid - och du kan även så småningom om bli bättre på vad du gör när du då och då tar på dig större utmaningar!",
@ -140,20 +140,21 @@
"BLOCKED_NOTE": "blockerad notering",
"IS_BLOCKED": "är blockerad",
"REF": "Ref. ",
"VOTES": "Röster"
"VOTES": "Röster",
"SPRINT": "Sprint"
},
"ROLES": {
"ALL": "Alla"
},
"ASSIGNED_TO": {
"NOT_ASSIGNED": "Ej tilldelad",
"ASSIGN": "Assign",
"ASSIGN": "Tilldela",
"DELETE_ASSIGNMENT": "Ta bort tilldelning",
"REMOVE_ASSIGNED": "Ta bort tilldelning",
"TOO_MANY": "... för många användare, fortsätter filtreringen",
"CONFIRM_UNASSIGNED": "Vill du lämna det utan att tilldela det? ",
"TITLE_ACTION_EDIT_ASSIGNMENT": "Redigera tilldelning",
"SELF": "Assign to me"
"SELF": "Tilldela mig"
},
"STATUS": {
"CLOSED": "Stängd",
@ -355,7 +356,7 @@
"HOME": {
"PAGE_TITLE": "Hem - Taiga",
"PAGE_DESCRIPTION": "Taiga hemsida med dina viktigaste projekt, alla dina tilldelade användaruppgifter, uppdrag och frågor",
"EMPTY_WORKING_ON": "<strong>Känns tråkigt utan innehåll, eller hur?`</strong> Börja att arbeta med Taiga och du vill se uppgifter, uppdrag och ärenden du arbetar med. ",
"EMPTY_WORKING_ON": "<strong>It feels empty, doesn't it?</strong> Start working with Taiga and you'll see here the stories, tasks and issues you are working on.",
"EMPTY_WATCHING": "<strong>Follow</strong> User Stories, Tasks, Issues in your projects and be notified about its changes :)",
"EMPTY_PROJECT_LIST": "Du har inte än några projekt",
"WORKING_ON_SECTION": "Arbetar med",
@ -556,9 +557,8 @@
"PAGE_TITLE": "Roller - {{projectName}}",
"WARNING_NO_ROLE": "Var försiktig. Inga roller i ditt projekt kan estimera poängvärden för användarhistorier",
"HELP_ROLE_ENABLED": "När det är aktivt, vill medlemmarna tilldelad den här rollen kunna estimera punktvärlden för användarhistorier",
"DISABLE_COMPUTABLE_ALERT_TITLE": "Avaktivera beräkningar för den här rollen",
"DISABLE_COMPUTABLE_ALERT_TITLE": "ÄR du säker på att du vill avvaktivera den här rollens beräkningar?",
"DISABLE_COMPUTABLE_ALERT_SUBTITLE": "Om du avaktiverar behörigheter för beräkning för rollen {{roleName}} vill alla tidigare beräkningar gjord av den här rollen tas bort. ",
"DISABLE_COMPUTABLE_ALERT_MESSAGE": "<strong>ÄR du säker på att du vill avvaktivera den här rollens beräkningar?</strong>",
"COUNT_MEMBERS": "{{ role.members_count }} medlemmar med den här rollen",
"TITLE_DELETE_ROLE": "Ta bort rollen",
"REPLACEMENT_ROLE": "Alla användarna med den här rollen vill flyttas till",
@ -693,13 +693,12 @@
},
"PROJECT_TRANSFER": {
"DO_YOU_ACCEPT_PROJECT_OWNERNSHIP": "Would you like to become the new project owner?",
"PRIVATE": "Private",
"PRIVATE": "Privat",
"ACCEPTED_PROJECT_OWNERNSHIP": "Congratulations! You're now the new project owner.",
"REJECTED_PROJECT_OWNERNSHIP": "OK. We'll contact the current project owner",
"ACCEPT": "Acceptera",
"REJECT": "Reject",
"PROPOSE_OWNERSHIP": "<strong>{{owner}}</strong>, the current owner of the project <strong>{{project}}</strong> has asked that you become the new project owner.",
"ADD_COMMENT_QUESTION": "Would you like to send a question to the project owner?",
"ADD_COMMENT": "Would you like to add a comment for the project owner?",
"UNLIMITED_PROJECTS": "Unlimited",
"OWNER_MESSAGE": {
@ -795,24 +794,24 @@
"PLACEHOLDER_SEARCH": "Sök i ...",
"ACTION_CREATE_PROJECT": "Skapa projekt",
"ACTION_IMPORT_PROJECT": "Importerar projekt",
"MANAGE_PROJECTS": "Manage projects",
"MANAGE_PROJECTS": "Hantera projekt",
"TITLE_CREATE_PROJECT": "Skapa projekt",
"TITLE_IMPORT_PROJECT": "Importerar projekt",
"TITLE_PRVIOUS_PROJECT": "Visa tidigare projekt",
"TITLE_NEXT_PROJECT": "Visa nästa projekt",
"HELP_TITLE": "Taiga hjälpsida",
"HELP": "Hjälp",
"HOMEPAGE": "Homepage",
"HOMEPAGE": "Webbplats",
"FEEDBACK_TITLE": "Skicka återkoppling",
"FEEDBACK": "Återkokppling",
"FEEDBACK": "Återkoppling",
"NOTIFICATIONS_TITLE": "Ändra inställningar för dina notifieringar",
"NOTIFICATIONS": "Notifieringar",
"ORGANIZATIONS_TITLE": "Ändra dina organisationer",
"ORGANIZATIONS": "Ändra organizationer",
"SETTINGS_TITLE": "Ändra inställningarna",
"SETTINGS": "Inställningar",
"VIEW_PROFILE_TITLE": "Vis profil",
"VIEW_PROFILE": "Vis profil",
"VIEW_PROFILE_TITLE": "Visa profil",
"VIEW_PROFILE": "Visa profil",
"EDIT_PROFILE_TITLE": "Ändra din profil",
"EDIT_PROFILE": "Ändra profil",
"CHANGE_PASSWORD_TITLE": "Byt lösenord",
@ -889,7 +888,7 @@
"CONFIRM": "Är du säker på att du vill radera kontot?",
"NEWSLETTER_LABEL_TEXT": "Jag vill inte motta flera nyhetsbrev",
"CANCEL": "Back to settings",
"ACCEPT": "Delete account",
"ACCEPT": "Ta bort konto",
"BLOCK_PROJECT": "Note that all the projects you own projects will be <strong>blocked</strong> after you delete your account. If you do want a project blocked, transfer ownership to another member of each project prior to deleting your account.",
"SUBTITLE": "Sorry to see you go. We'll be here if you should ever consider us again! :("
},
@ -964,7 +963,7 @@
},
"CHANGE_OWNER": {
"TITLE": "Who do you want to be the new project owner?",
"ADD_COMMENT": "Add comment",
"ADD_COMMENT": "Lägg till kommentar",
"BUTTON": "Ask this project member to become the new project owner"
}
},
@ -1368,7 +1367,7 @@
"USER_PROFILE": "Användarprofil",
"CHANGE_PASSWORD": "Ändra lösenord",
"NOTIFICATIONS": "Notifieringar",
"FEEDBACK": "Återkokppling",
"FEEDBACK": "Återkoppling",
"TITLE_AVATAR": "Inställningar för användare"
}
},
@ -1413,6 +1412,7 @@
"PLACEHOLDER_PAGE": "Skriv din wiki-sida",
"REMOVE": "Ta bort den här wiki-sidan",
"DELETE_LIGHTBOX_TITLE": "Ta bort Wiki-sida",
"DELETE_LINK_TITLE": "Delete Wiki link",
"NAVIGATION": {
"SECTION_NAME": "Länkar",
"ACTION_ADD_LINK": "Lägg till länk"

View File

@ -140,7 +140,8 @@
"BLOCKED_NOTE": "engel notu",
"IS_BLOCKED": "engellendi ",
"REF": "Ref",
"VOTES": "Oylar"
"VOTES": "Oylar",
"SPRINT": "Koşu"
},
"ROLES": {
"ALL": "Hepsi"
@ -355,7 +356,7 @@
"HOME": {
"PAGE_TITLE": "AnaSayfa - Taiga",
"PAGE_DESCRIPTION": "Atanmış ve izlenen kullanıcı hikayeleri, işler ve sorunların yanı sıra ana projeleriniz için Taiga ana sayfanız",
"EMPTY_WORKING_ON": "<strong>Bomboş hissettiriyor degil mi?</strong> Taiga ile çalışmaya başlayın ve burada üzerinde çalıştığınız hikayeleri, işleri ve sorunları göreceksiniz.",
"EMPTY_WORKING_ON": "<strong>It feels empty, doesn't it?</strong> Start working with Taiga and you'll see here the stories, tasks and issues you are working on.",
"EMPTY_WATCHING": "Projelerinizdeki Kullanıcı Hikayelerini, İşleri ve Sorunları <strong>takip edin</strong> ve değişikliklerden haberdar olun :) ",
"EMPTY_PROJECT_LIST": "Henüz bir projeniz yok",
"WORKING_ON_SECTION": "Üzerinde çalışılıyor",
@ -556,9 +557,8 @@
"PAGE_TITLE": "Roller - {{projectName}}",
"WARNING_NO_ROLE": "Dikkat edin, projenizdeki rollerden hiçbiri kullanıcı hikayeleri için puan değeri kestirimi yapma yetkisine sahip değil.",
"HELP_ROLE_ENABLED": "Etkileştirildiğinde, bu role atanan üyeler kullanıcı hikayeleri için puan kestirimi yapabilecek",
"DISABLE_COMPUTABLE_ALERT_TITLE": "Bu rol için kestirimi kapat",
"DISABLE_COMPUTABLE_ALERT_TITLE": "Bu role ait kestirimleri kapatmak istediğinizden emin misiniz?",
"DISABLE_COMPUTABLE_ALERT_SUBTITLE": "{{roleName}} görevi için tahmin izinlerini kaldırırsanız, bu görevdekiler tarafından daha önce yapılmış tüm tahminler silinir",
"DISABLE_COMPUTABLE_ALERT_MESSAGE": "<strong>Bu role ait kestirimleri kapatmak istediğinizden emin misiniz?</strong>",
"COUNT_MEMBERS": "bu roldeki üyelerin sayısı {{ role.members_count }} ",
"TITLE_DELETE_ROLE": "Rol Sil",
"REPLACEMENT_ROLE": "Bu role sahip kullanıcıların taşınacağı",
@ -699,7 +699,6 @@
"ACCEPT": "Kabul et",
"REJECT": "Reject",
"PROPOSE_OWNERSHIP": "<strong>{{owner}}</strong>, the current owner of the project <strong>{{project}}</strong> has asked that you become the new project owner.",
"ADD_COMMENT_QUESTION": "Would you like to send a question to the project owner?",
"ADD_COMMENT": "Would you like to add a comment for the project owner?",
"UNLIMITED_PROJECTS": "Unlimited",
"OWNER_MESSAGE": {
@ -1413,6 +1412,7 @@
"PLACEHOLDER_PAGE": "Wiki sayfanı yaz ",
"REMOVE": "Bu wiki sayfasını sil",
"DELETE_LIGHTBOX_TITLE": "Wiki Sayfası Sil",
"DELETE_LINK_TITLE": "Delete Wiki link",
"NAVIGATION": {
"SECTION_NAME": "Bağlantılar",
"ACTION_ADD_LINK": "Bağlantı ekle"

View File

@ -140,7 +140,8 @@
"BLOCKED_NOTE": "已封鎖之筆記",
"IS_BLOCKED": "封鎖",
"REF": "Ref",
"VOTES": "投票數"
"VOTES": "投票數",
"SPRINT": "衝刺任務"
},
"ROLES": {
"ALL": "所有"
@ -355,7 +356,7 @@
"HOME": {
"PAGE_TITLE": "首頁 - Taiga",
"PAGE_DESCRIPTION": "Taiga 首頁,你的主要專案以及任命,觀看使用者故事,任務與問題。",
"EMPTY_WORKING_ON": "<strong>It feels empty, doesn't it?</strong> Start working with Taiga and you'll see here the stories, tasks and issues you are workin on.",
"EMPTY_WORKING_ON": "<strong>It feels empty, doesn't it?</strong> Start working with Taiga and you'll see here the stories, tasks and issues you are working on.",
"EMPTY_WATCHING": "<strong>Follow</strong> User Stories, Tasks, Issues in your projects and be notified about its changes :)",
"EMPTY_PROJECT_LIST": "你尚無任何專案",
"WORKING_ON_SECTION": "進行中",
@ -556,9 +557,8 @@
"PAGE_TITLE": "角色- {{projectName}}",
"WARNING_NO_ROLE": "注意,你的專案中無角色可以評估使用者故事的點數",
"HELP_ROLE_ENABLED": "當啟動時,被指派此角色的成員將可以評估使用者故事點數",
"DISABLE_COMPUTABLE_ALERT_TITLE": "Disable estimation for this role",
"DISABLE_COMPUTABLE_ALERT_TITLE": "Are you sure you want to disable this role estimations?",
"DISABLE_COMPUTABLE_ALERT_SUBTITLE": "If you disable estimation permissions for role {{roleName}} all previous estimations made by this role will be removed",
"DISABLE_COMPUTABLE_ALERT_MESSAGE": "<strong>Are you sure you want to disable this role estimations?</strong>",
"COUNT_MEMBERS": "{{ role.members_count }} 這類角色的成員",
"TITLE_DELETE_ROLE": "删除角色",
"REPLACEMENT_ROLE": "和此角色有關的使用者都將遭移除 ",
@ -699,7 +699,6 @@
"ACCEPT": "接受",
"REJECT": "Reject",
"PROPOSE_OWNERSHIP": "<strong>{{owner}}</strong>, the current owner of the project <strong>{{project}}</strong> has asked that you become the new project owner.",
"ADD_COMMENT_QUESTION": "Would you like to send a question to the project owner?",
"ADD_COMMENT": "Would you like to add a comment for the project owner?",
"UNLIMITED_PROJECTS": "Unlimited",
"OWNER_MESSAGE": {
@ -1413,6 +1412,7 @@
"PLACEHOLDER_PAGE": "編寫你的維基頁",
"REMOVE": "移除此維基頁 ",
"DELETE_LIGHTBOX_TITLE": "刪除維基頁",
"DELETE_LINK_TITLE": "Delete Wiki link",
"NAVIGATION": {
"SECTION_NAME": "連結",
"ACTION_ADD_LINK": "新增連結"

View File

@ -14,7 +14,7 @@
}
}
.attachment-name {
@extend %light;
@include font-type(light);
@include ellipsis(175px);
display: inline-block;
}

View File

@ -51,10 +51,12 @@
opacity: 0;
}
.editable-settings {
display: block;
opacity: 1;
}
svg {
fill: $gray-light;
pointer-events: none;
}
.icon-edit,
.icon-save {

View File

@ -1,5 +1,20 @@
.attachments {
margin-bottom: 2rem;
margin-bottom: 4rem;
.gu-transit {
background: $whitish;
height: 40px;
* {
display: none;
}
}
.gu-mirror {
opacity: 1;
form {
background: lighten($primary, 60%);
box-shadow: 1px 1px 10px rgba($black, .1);
transition: background .2s ease-in;
}
}
}
.attachments-header {
@ -10,8 +25,8 @@
justify-content: space-between;
min-height: 36px;
.attachments-title {
@extend %medium;
@extend %bold;
@include font-type(bold);
@include font-size(medium);
color: $grayer;
line-height: 36px;
padding: 0 1rem;
@ -55,8 +70,8 @@
}
}
.size-info {
@extend %light;
@extend %small;
@include font-size(small);
@include font-type(light);
color: $gray;
padding-left: 1rem;
}
@ -66,8 +81,8 @@
}
.attachments-empty {
@extend %large;
@extend %bold;
@include font-size(large);
@include font-type(bold);
border: 3px dashed $whitish;
color: $gray-light;
margin-top: .5rem;
@ -76,19 +91,10 @@
}
.single-attachment {
@extend %small;
@include font-size(small);
background: rgba($white, .9);
&.ui-sortable-helper {
background: lighten($primary, 60%);
box-shadow: 1px 1px 10px rgba($black, .1);
transition: background .2s ease-in;
}
&.sortable-placeholder {
background: $whitish;
height: 40px;
}
.attachment-name {
@extend %bold;
@include font-type(bold);
padding-right: 1rem;
svg {
fill: $gray;
@ -103,7 +109,7 @@
}
.more-attachments {
@extend %small;
@include font-size(small);
border-bottom: 1px solid $gray-light;
display: block;
padding: 1rem 0 1rem 1rem;

View File

@ -34,5 +34,4 @@
title="{{'COMMON.DELETE' | translate}}"
ng-click="vm.delete()"
)
svg.icon.icon-trash
use(xlink:href="#icon-trash")
tg-svg(svg-icon="icon-trash")

View File

@ -12,8 +12,7 @@ form.single-attachment(
target="_blank"
download="{{::vm.attachment.getIn(['file', 'name'])}}"
)
svg.icon.icon-attachment
use(xlink:href="#icon-attachment")
tg-svg(svg-icon="icon-attachment")
span {{::vm.attachment.getIn(['file', 'name'])}}
.attachment-comments(ng-if="!vm.attachment.get('editable') && vm.attachment.getIn(['file', 'description'])")
@ -47,44 +46,39 @@ form.single-attachment(
.attachment-settings(ng-if="vm.attachment.get('editable')")
div(tg-loading="vm.attachment.get('loading')")
a.editable-settings(
a.editable-settings.e2e-save(
href=""
title="{{'COMMON.SAVE' | translate}}"
ng-click="vm.save()"
)
svg.drag.icon.icon-save
use(xlink:href="#icon-save")
tg-svg(svg-icon="icon-save")
div
a.editable-settings(
a.editable-settings.e2e-cancel(
href=""
title="{{'COMMON.CANCEL' | translate}}"
ng-click="vm.editMode(false)"
)
svg.drag.icon.icon-close
use(xlink:href="#icon-close")
tg-svg(svg-icon="icon-close")
.attachment-settings(
ng-if="!vm.attachment.get('editable')"
tg-check-permission="modify_{{vm.type}}"
)
a.settings(
a.settings.e2e-edit(
href=""
title="{{'COMMON.EDIT' | translate}}"
ng-click="vm.editMode(true)"
)
svg.drag.icon.icon-edit
use(xlink:href="#icon-edit")
a.settings(
tg-svg.drag(svg-icon="icon-edit")
a.settings.e2e-delete(
href=""
title="{{'COMMON.DELETE' | translate}}"
ng-click="vm.delete()"
)
svg.drag.icon.icon-trash
use(xlink:href="#icon-trash")
tg-svg.drag(svg-icon="icon-trash")
a.settings(
href=""
title="{{'COMMON.DRAG' | translate}}"
)
svg.drag.icon.icon-drag
use(xlink:href="#icon-drag")
tg-svg.drag(svg-icon="icon-drag")

View File

@ -11,24 +11,21 @@ section.attachments(
ng-click="vm.setMode('gallery')"
title="{{ 'ATTACHMENT.GALLERY_VIEW_MODE' | translate }}"
)
svg.icon.icon-gallery
use(xlink:href="#icon-gallery")
tg-svg(svg-icon="icon-gallery")
button.view-list(
ng-class="{'is-active': vm.mode == 'list'}"
ng-if="vm.attachments.size"
ng-click="vm.setMode('list')"
title="{{ 'ATTACHMENT.LIST_VIEW_MODE' | translate }}"
)
svg.icon.icon-list
use(xlink:href="#icon-list")
tg-svg(svg-icon="icon-list")
.add-attach(
tg-check-permission="modify_{{vm.type}}"
title!="{{'ATTACHMENT.ADD' | translate}}"
)
label.add-attachment-button(for="add-attach")
svg.icon.icon-add
use(xlink:href="#icon-add")
tg-svg(svg-icon="icon-add")
input(
id="add-attach",
@ -55,8 +52,7 @@ section.attachments(
.single-attachment(ng-repeat="file in vm.uploadingAttachments()")
.attachment-name
svg.icon.icon-attachment
use(xlink:href="#icon-attachment")
tg-svg(svg-icon="icon-attachment")
span {{file.name}}
.attachment-size
span {{file.size | sizeFormat}}

View File

@ -5,8 +5,7 @@ section.attachments(tg-attachments-drop="vm.addAttachments(files)")
h3.attachments-title #[span.attachments-num {{vm.attachments.size}}] #[span.attachments-text(translate="ATTACHMENT.SECTION_NAME")]
.add-attach(title!="{{'ATTACHMENT.ADD' | translate}}")
label.add-attachment-button(for="add-attach")
svg.icon.icon-add
use(xlink:href="#icon-add")
tg-svg(svg-icon="icon-add")
input(
id="add-attach"
type="file"
@ -19,8 +18,7 @@ section.attachments(tg-attachments-drop="vm.addAttachments(files)")
.attachment-body.attachment-list
.single-attachment(tg-repeat="attachment in vm.attachments track by $index")
.attachment-name
svg.icon.icon-attachment
use(xlink:href="#icon-attachment")
tg-svg(svg-icon="icon-attachment")
span {{attachment.get('name')}}
.attachment-size
span {{attachment.get('size') | sizeFormat}}
@ -31,5 +29,4 @@ section.attachments(tg-attachments-drop="vm.addAttachments(files)")
title="{{'COMMON.DELETE' | translate}}"
ng-click="vm.deleteAttachment(attachment)"
)
svg.icon.icon-trash
use(xlink:href="#icon-trash")
tg-svg(svg-icon="icon-trash")

View File

@ -21,25 +21,34 @@ AttachmentSortableDirective = ($parse) ->
link = (scope, el, attrs) ->
callback = $parse(attrs.tgAttachmentsSortable)
el.sortable({
items: "div[tg-bind-scope]"
handle: ".settings .icon"
containment: ".attachments"
dropOnEmpty: true
helper: 'clone'
scroll: false
tolerance: "pointer"
placeholder: "sortable-placeholder single-attachment"
drake = dragula([el[0]], {
copySortSource: false,
copy: false,
mirrorContainer: el[0],
moves: (item) -> return $(item).is('div[tg-bind-scope]')
})
el.on "sortstop", (event, ui) ->
attachment = ui.item.scope().attachment
newIndex = ui.item.index()
drake.on 'dragend', (item) ->
item = $(item)
attachment = item.scope().attachment
newIndex = item.index()
scope.$apply () ->
callback(scope, {attachment: attachment, index: newIndex})
scope.$on "$destroy", -> el.off()
scroll = autoScroll(window, {
margin: 20,
pixels: 30,
scrollWhenOutside: true,
autoScroll: () ->
return this.down && drake.dragging;
})
scope.$on "$destroy", ->
el.off()
drake.destroy()
return {
link: link

View File

@ -7,7 +7,6 @@
a.close(
ng-click="vm.close()"
href=""
title="{{ COMMON.CLOSE | translate }}"
ng-title="COMMON.CLOSE | translate"
)
svg.icon.icon-close
use(xlink:href="#icon-close")
tg-svg(svg-icon="icon-close")

View File

@ -43,26 +43,27 @@
width: 100%;
}
.title {
@extend %bold;
@extend %larger;
@include font-type(bold);
@include font-size(larger);
color: $tribe-secondary;
margin-bottom: .5rem;
}
.warning {
color: $tribe-secondary;
a {
@extend %bold;
@include font-type(bold);
color: $tribe-secondary;
}
}
.close {
height: 2.5rem;
display: block;
position: absolute;
right: 0;
top: 1rem;
width: 2.5rem;
svg {
@include svg-size(2rem);
fill: lighten($tribe-secondary, 15%);
pointer-events: none;
transition: fill .2s;
&:hover {
fill: $tribe-secondary;

View File

@ -1,105 +1,96 @@
nav.menu(
ng-if="vm.project"
ng-class="{'menu-fixed': vm.fixed}",
)
div(class="menu-container")
ul(class="main-nav")
li(id="nav-search")
)
.menu-container
ul.main-nav
li#nav-search
a(
href=""
ng-click="vm.search()"
ng-class="{active: vm.active == 'search'}"
aria-label="{{'PROJECT.SECTION.SEARCH' | translate}}"
tabindex="1"
)
svg.icon.icon-search
use(xlink:href="#icon-search")
span.helper(translate="PROJECT.SECTION.SEARCH")
)
tg-svg(svg-icon="icon-search")
span.helper(translate="PROJECT.SECTION.SEARCH")
li(id="nav-timeline")
li#nav-timeline
a(
tg-nav="project:project=vm.project.get('slug')"
ng-class="{active: vm.active == 'project-timeline'}"
aria-label="{{'PROJECT.SECTION.TIMELINE' | translate}}"
tabindex="2"
)
svg.icon.icon-timeline
use(xlink:href="#icon-timeline")
tg-svg(svg-icon="icon-timeline")
span.helper(translate="PROJECT.SECTION.TIMELINE")
li(id="nav-backlog", ng-if="vm.menu.get('backlog')")
li#nav-backlog(ng-if="vm.menu.get('backlog')")
a(
tg-nav="project-backlog:project=vm.project.get('slug')"
ng-class="{active: vm.active == 'backlog'}"
aria-label="{{'PROJECT.SECTION.BACKLOG' | translate}}"
tabindex="2"
)
svg.icon.icon-scrum
use(xlink:href="#icon-scrum")
tg-svg(svg-icon="icon-scrum")
span.helper(translate="PROJECT.SECTION.BACKLOG")
li(id="nav-kanban", ng-if="vm.menu.get('kanban')")
li#nav-kanban(ng-if="vm.menu.get('kanban')")
a(
tg-nav="project-kanban:project=vm.project.get('slug')"
ng-class="{active: vm.active == 'kanban'}"
aria-label="{{'PROJECT.SECTION.KANBAN' | translate}}"
tabindex="3"
)
svg.icon.icon-kanban
use(xlink:href="#icon-kanban")
tg-svg(svg-icon="icon-kanban")
span.helper(translate="PROJECT.SECTION.KANBAN")
li(id="nav-issues", ng-if="vm.menu.get('issues')")
li#nav-issues(ng-if="vm.menu.get('issues')")
a(
tg-nav="project-issues:project=vm.project.get('slug')"
ng-class="{active: vm.active == 'issues'}"
aria-label="{{'PROJECT.SECTION.ISSUES' | translate}}"
tabindex="4"
)
svg.icon.icon-issues
use(xlink:href="#icon-issues")
tg-svg(svg-icon="icon-issues")
span.helper(translate="PROJECT.SECTION.ISSUES")
li(id="nav-wiki", ng-if="vm.menu.get('wiki')")
li#nav-wiki(ng-if="vm.menu.get('wiki')")
a(
tg-nav="project-wiki:project=vm.project.get('slug')"
ng-class="{active: vm.active == 'wiki'}"
aria-label="{{'PROJECT.SECTION.WIKI' | translate}}"
tabindex="5"
)
svg.icon.icon-wiki
use(xlink:href="#icon-wiki")
tg-svg(svg-icon="icon-wiki")
span.helper(translate="PROJECT.SECTION.WIKI")
li(id="nav-team")
li#nav-team
a(
tg-nav="project-team:project=vm.project.get('slug')"
ng-class="{active: vm.active == 'team'}"
aria-label="{{'PROJECT.SECTION.TEAM' | translate}}"
tabindex="6"
)
svg.icon.icon-team
use(xlink:href="#icon-team")
tg-svg(svg-icon="icon-team")
span.helper(translate="PROJECT.SECTION.TEAM")
li(id="nav-video", ng-if="vm.project.get('videoconferenceUrl')")
li#nav-video(ng-if="vm.project.get('videoconferenceUrl')")
a(
ng-href="{{vm.project.get('videoconferenceUrl')}}"
target="_blank"
aria-label="{{'PROJECT.SECTION.MEETUP' | translate}}"
tabindex="7"
)
svg.icon.icon-bubble
use(xlink:href="#icon-bubble")
tg-svg(svg-icon="icon-bubble")
span.helper(translate="PROJECT.SECTION.MEETUP")
li(id="nav-admin", ng-if="vm.project.get('i_am_admin')")
li#nav-admin(ng-if="vm.project.get('i_am_admin')")
a(
tg-nav="project-admin-home:project=vm.project.get('slug')"
ng-class="{active: vm.active == 'admin'}"
aria-label="{{'PROJECT.SECTION.ADMIN' | translate}}"
tabindex="8"
)
svg.icon.icon-settings
use(xlink:href="#icon-settings")
tg-svg(svg-icon="icon-settings")
span.helper(translate="PROJECT.SECTION.ADMIN")

View File

@ -9,8 +9,7 @@ a.vote-inner(
ng-mouseleave="vm.showTextWhenMouseIsLeave()"
)
span.track-icon
svg.icon.icon-upvote
use(xlink:href="#icon-upvote")
tg-svg(svg-icon="icon-upvote")
span.track-button-counter(
title="{{ 'COMMON.VOTE_BUTTON.COUNTER_TITLE'|translate:{total:vm.item.total_voters||0}:'messageformat' }}",
tg-loading="vm.loading"
@ -19,8 +18,7 @@ a.vote-inner(
//- Anonymous user button
span.vote-inner(ng-if="::!vm.user")
span.track-icon
svg.icon.icon-upvote
use(xlink:href="#icon-upvote")
tg-svg(svg-icon="icon-watch")
span.track-button-counter(
title="{{ 'COMMON.VOTE_BUTTON.COUNTER_TITLE'|translate:{total:vm.item.total_voters||0}:'messageformat' }}"
) {{ ::vm.item.total_voters }}

View File

@ -14,17 +14,14 @@ div.ticket-watch-inner
ng-mouseleave="vm.showTextWhenMouseIsLeave()"
)
span(ng-if="!vm.item.is_watcher")
svg.icon.icon-watch
use(xlink:href="#icon-watch")
| {{'COMMON.WATCH_BUTTON.WATCH' | translate}}
tg-svg(svg-icon="icon-watch")
span {{'COMMON.WATCH_BUTTON.WATCH' | translate}}
span(ng-if="vm.item.is_watcher && !vm.isMouseOver",)
svg.icon.icon-watch
use(xlink:href="#icon-watch")
| {{'COMMON.WATCH_BUTTON.WATCHING' | translate}}
tg-svg(svg-icon="icon-watch")
span {{'COMMON.WATCH_BUTTON.WATCHING' | translate}}
span(ng-if="vm.item.is_watcher && vm.isMouseOver")
svg.icon.icon-unwatch
use(xlink:href="#icon-unwatch")
| {{'COMMON.WATCH_BUTTON.UNWATCH' | translate}}
tg-svg(svg-icon="icon-unwatch")
span {{'COMMON.WATCH_BUTTON.UNWATCH' | translate}}
a.add-watcher(
href=""

View File

@ -16,8 +16,7 @@ a.track-button.watch-button.watch-container(
ng-mouseleave="vm.showTextWhenMouseIsLeave()"
)
span.track-inner
svg.icon.icon-watch
use(xlink:href="#icon-watch")
tg-svg(svg-icon="icon-watch")
span(
ng-if="!vm.item.is_watcher",
translate="COMMON.WATCH_BUTTON.WATCH"
@ -38,7 +37,6 @@ span.track-button.watch-button.watch-container(
)
span.track-inner
span.track-icon
svg.icon.icon-watch
use(xlink:href="#icon-watch")
tg-svg(svg-icon="icon-watch")
span(translate="COMMON.WATCH_BUTTON.WATCHERS")
+counter

View File

@ -3,8 +3,7 @@
href="#"
ng-click="vm.open()"
) {{vm.currentText()}}
svg.icon.icon-arrow-down
use(xlink:href="#icon-arrow-down")
tg-svg(svg-icon="icon-arrow-down")
ul.filter-list(ng-if="vm.is_open")
li(ng-click="vm.orderBy('week')") {{ 'DISCOVER.FILTERS.WEEK' | translate }}

View File

@ -18,12 +18,11 @@ div.discover-header
placeholder="{{ 'DISCOVER.SEARCH.INPUT_PLACEHOLDER' | translate }}"
ng-model="vm.q"
)
svg.search-button.icon.icon-search(
tg-svg.search-button(
ng-click="vm.submitFilter()"
href="#"
title="{{ 'DISCOVER.SEARCH.ACTION_TITLE' | translate }}"
svg-icon="icon-search"
svg-title-translate="DISCOVER.SEARCH.ACTION_TITLE"
)
use(xlink:href="#icon-search")
fieldset.searchbox-filters(ng-if="vm.filter")
input(

View File

@ -8,12 +8,12 @@
margin: 0 auto;
}
.title {
@extend %xxlarge;
@include font-size(xxlarge);
margin-bottom: 0;
}
.project-number {
@extend %light;
@extend %large;
@include font-type(light);
@include font-size(large);
color: $primary;
}
form {

View File

@ -1,8 +1,7 @@
.discover-results-header
.discover-results-header-inner
.title
svg.icon.icon-search
use(xlink:href="#icon-search")
tg-svg(svg-icon="icon-search")
h2 {{ 'DISCOVER.SEARCH.RESULTS' | translate }}
.filter-discover-search(ng-mouseleave="vm.toggleClose()")
@ -11,16 +10,14 @@
ng-click="vm.openLike()"
ng-class="{active: vm.like_is_open}"
)
svg.icon.icon-like
use(xlink:href="#icon-like")
tg-svg(svg-icon="icon-like")
span {{ 'DISCOVER.MOST_LIKED' | translate }}
a.discover-search-filter(
href="#"
ng-click="vm.openActivity()"
ng-class="{active: vm.activity_is_open}"
)
svg.icon.icon-activity
use(xlink:href="#icon-activity")
tg-svg(svg-icon="icon-activity")
span {{ 'DISCOVER.MOST_ACTIVE' | translate }}
.discover-search-subfilter.most-liked-subfilter(ng-if="vm.like_is_open")

View File

@ -10,8 +10,8 @@
margin-right: .25rem;
}
.title {
@extend %bold;
@extend %larger;
@include font-type(bold);
@include font-size(larger);
text-transform: uppercase;
}
h2 {
@ -57,7 +57,7 @@
animation: dropdownFade .2s;
}
.results {
@extend %small;
@include font-size(small);
color: $red-light;
display: block;
padding: .5rem 1rem;

View File

@ -26,31 +26,28 @@
tg-nav="project:project=project.get('slug')"
title="{{::project.get('name')}}"
) {{::project.get('name')}}
svg.look-for-people.icon.icon-recruit(
tg-svg.look-for-people(
ng-if="project.get('is_looking_for_people')"
svg-icon="icon-recruit"
svg-title="{{ ::project.get('looking_for_people_note') }}"
)
use(xlink:href="#icon-recruit")
title="{{ ::project.get('looking_for_people_note') }}"
p.project-card-description {{ ::project.get('description') | limitTo:100 }}{{ ::project.get('description').length < 100 ? '' : '...'}}
.project-card-statistics
span.statistic(
ng-class="{'active': project.get('is_fan')}"
title="{{ 'PROJECT.FANS_COUNTER_TITLE'|translate:{total:project.get('total_fans')||0}:'messageformat' }}"
)
svg.icon.icon-like
use(xlink:href="#icon-like")
tg-svg(svg-icon="icon-like")
span {{::project.get('total_fans')}}
span.statistic(
ng-class="{'active': project.get('is_watcher')}"
title="{{ 'PROJECT.WATCHERS_COUNTER_TITLE'|translate:{total:project.get('total_watchers')||0}:'messageformat' }}"
)
svg.icon.icon-watch
use(xlink:href="#icon-watch")
tg-svg(svg-icon="icon-watch")
span {{::project.get('total_watchers')}}
span.statistic(
ng-class="{'active': project.get('i_am_member')}"
title="{{ 'PROJECT.MEMBERS_COUNTER_TITLE'|translate:{total:project.get('members').size||0}:'messageformat' }}"
)
svg.icon.icon-team
use(xlink:href="#icon-team")
tg-svg(svg-icon="icon-team")
span.statistics-num {{ ::project.get('members').size }}

View File

@ -3,8 +3,8 @@
.featured-projects {
@include centered;
.title {
@extend %bold;
@extend %larger;
@include font-type(bold);
@include font-size(larger);
color: $grayer;
text-align: center;
}

View File

@ -24,30 +24,29 @@
tg-nav="project:project=project.get('slug')"
title="{{::project.get('name')}}"
) {{::project.get('name')}}
svg.look-for-people.icon.icon-recruit(ng-if="project.get('is_looking_for_people')")
use(xlink:href="#icon-recruit")
title="{{ ::project.get('looking_for_people_note') }}"
tg-svg.look-for-people(
ng-if="project.get('is_looking_for_people')"
svg-icon="icon-recruit"
svg-title="{{ ::project.get('looking_for_people_note') }}"
)
.project-statistics
span.statistic(
ng-class="{'active': project.get('is_fan')}"
title="{{ 'PROJECT.FANS_COUNTER_TITLE'|translate:{total:project.get('total_fans')||0}:'messageformat' }}"
)
svg.icon.icon-like
use(xlink:href="#icon-like")
tg-svg(svg-icon="icon-like")
span {{::project.get('total_fans')}}
span.statistic(
ng-class="{'active': project.get('is_watcher')}"
title="{{ 'PROJECT.WATCHERS_COUNTER_TITLE'|translate:{total:project.get('total_watchers')||0}:'messageformat' }}"
)
svg.icon.icon-watch
use(xlink:href="#icon-watch")
tg-svg(svg-icon="icon-watch")
span {{::project.get('total_watchers')}}
span.statistic(
ng-class="{'active': project.get('i_am_member')}"
title="{{ 'PROJECT.MEMBERS_COUNTER_TITLE'|translate:{total:project.get('members').size||0}:'messageformat' }}"
)
svg.icon.icon-team
use(xlink:href="#icon-team")
tg-svg(svg-icon="icon-team")
span.statistics-num {{ ::project.get('members').size }}
p.project-description {{ ::project.get('description') | limitTo:150 }}{{ ::project.get('description').length < 150 ? '' : '...'}}

View File

@ -49,8 +49,8 @@
}
}
.title {
@extend %bold;
@extend %larger;
@include font-type(bold);
@include font-size(larger);
color: $grayer;
display: inline-block;
margin: 0;
@ -85,7 +85,7 @@
margin: 1rem auto;
}
span {
@extend %light;
@include font-type(light);
color: $gray;
display: block;
}
@ -122,7 +122,7 @@
}
}
li {
@extend %small;
@include font-size(small);
color: $white;
cursor: pointer;
min-width: 8rem;
@ -161,8 +161,8 @@
justify-content: space-between;
}
.project-title {
@extend %large;
@extend %text;
@include font-size(large);
@include font-type(text);
display: inline-block;
margin-bottom: .5rem;
a {
@ -172,13 +172,8 @@
}
}
}
.look-for-people {
@include svg-size();
fill: $gray-light;
margin-left: .5rem;
}
.project-description {
@extend %small;
@include font-size(small);
color: $gray;
margin-bottom: 0;
}
@ -191,12 +186,9 @@
fill: $gray-light;
margin-right: .25rem;
}
.svg-eye-closed {
display: none;
}
}
.statistic {
@extend %small;
@include font-size(small);
color: $gray-light;
display: inline-block;
margin-right: .5rem;

View File

@ -1,8 +1,7 @@
.most-active(ng-if="vm.highlighted.size")
.header
.title-wrapper
svg.icon.icon-activity
use(xlink:href="#icon-activity")
tg-svg(svg-icon="icon-activity")
h1.title {{ 'DISCOVER.MOST_ACTIVE' | translate }}
tg-discover-home-order-by(on-change="vm.orderBy(orderBy)", order-by="vm.currentOrderBy")
@ -15,6 +14,5 @@
.empty-highlighted-project(
ng-if="!vm.highlighted.size"
)
svg.icon.icon-activity
use(xlink:href="#icon-activity")
tg-svg(svg-icon="icon-activity")
span {{ 'DISCOVER.MOST_ACTIVE_EMPTY' | translate }}

View File

@ -1,10 +1,12 @@
.most-liked(ng-if="vm.highlighted.size")
.header
.title-wrapper
svg.icon.icon-like
use(xlink:href="#icon-like")
tg-svg(svg-icon="icon-like")
h1.title {{ 'DISCOVER.MOST_LIKED' | translate }}
tg-discover-home-order-by(on-change="vm.orderBy(orderBy)", order-by="vm.currentOrderBy")
tg-discover-home-order-by(
on-change="vm.orderBy(orderBy)"
order-by="vm.currentOrderBy"
)
tg-highlighted(
loading="vm.loading",
highlighted="vm.highlighted"
@ -14,6 +16,5 @@
.empty-highlighted-project(
ng-if="!vm.highlighted.size"
)
svg.icon.icon-like
use(xlink:href="#icon-like")
tg-svg(svg-icon="icon-like")
span {{ 'DISCOVER.MOST_LIKED_EMPTY' | translate }}

View File

@ -43,9 +43,11 @@ div(tg-discover-search)
tg-nav="project:project=project.get('slug')"
title="{{ ::project.get('name') }}"
) {{project.get('name')}}
svg.look-for-people.icon.icon-recruit(ng-if="project.get('is_looking_for_people')")
use(xlink:href="#icon-recruit")
title="{{ ::project.get('looking_for_people_note') }}"
tg-svg.look-for-people(
ng-if="project.get('is_looking_for_people')"
svg-icon="icon-recruit"
svg-title="{{ ::project.get('looking_for_people_note') }}"
)
p {{ ::project.get('description') | limitTo:300 }}
span(ng-if="::project.get('description').length > 300") ...
.list-itemtype-project-right.project-statistics
@ -53,22 +55,19 @@ div(tg-discover-search)
ng-class="{'active': project.get('is_fan')}"
title="{{ 'PROJECT.FANS_COUNTER_TITLE'|translate:{total:project.get('total_fans')||0}:'messageformat' }}"
)
svg.icon.icon-like
use(xlink:href="#icon-like")
tg-svg(svg-icon="icon-like")
span {{::project.get('total_fans')}}
span.statistic(
ng-class="{'active': project.get('is_watcher')}"
title="{{ 'PROJECT.WATCHERS_COUNTER_TITLE'|translate:{total:project.get('total_watchers')||0}:'messageformat' }}"
)
svg.icon.icon-watch
use(xlink:href="#icon-watch")
tg-svg(svg-icon="icon-watch")
span {{::project.get('total_watchers')}}
span.statistic(
ng-class="{'active': project.get('i_am_member')}"
title="{{ 'PROJECT.MEMBERS_COUNTER_TITLE'|translate:{total:project.get('members').size||0}:'messageformat' }}"
)
svg.icon.icon-team
use(xlink:href="#icon-team")
tg-svg(svg-icon="icon-team")
span.statistics-num {{ ::project.get('members').size }}
a.button-green.more-results(

View File

@ -71,10 +71,6 @@
flex: 1;
vertical-align: middle;
}
.look-for-people {
fill: $gray-light;
margin-left: .5rem;
}
.project-statistics {
display: flex;
flex-basis: 300px;
@ -84,12 +80,9 @@
fill: $gray-light;
margin-right: .2rem;
}
.svg-eye-closed {
display: none;
}
}
.statistic {
@extend %small;
@include font-size(small);
color: $gray-light;
display: inline-block;
margin-right: .5rem;
@ -121,8 +114,8 @@
margin-bottom: 1rem;
}
.title {
@extend %large;
@extend %light;
@include font-size(large);
@include font-type(light);
margin: 0;
text-transform: uppercase;
}

View File

@ -26,10 +26,10 @@
margin: 0;
}
h3 {
@extend %large;
@include font-size(large);
}
a {
@extend %xsmall;
@include font-size(x-small);
display: block;
}
}
@ -47,7 +47,7 @@
}
p {
@extend %xsmall;
@include font-size(x-small);
}
}
.user-card {
@ -67,7 +67,7 @@
display: block;
}
.cancel {
@extend %small;
@include font-size(small);
display: block;
margin-top: .5rem;
text-align: left;

View File

@ -16,18 +16,21 @@ a.list-itemtype-ticket(
div.list-itemtype-ticket-data
p
span.ticket-project {{ ::vm.duty.get('projectName')}}
span.ticket-type {{ ::vm.getDutyType() }}
span.ticket-status(ng-style="{'color': vm.duty.get('status_extra_info').get('color')}") {{ ::vm.duty.get('status_extra_info').get('name') }}
svg.icon.icon-blocked-project(ng-if="vm.duty.get('blockedProject')")
use(xlink:href="#icon-blocked-project")
title(translate="PROJECT.BLOCKED_PROJECT.BLOCKED")
tg-svg(
ng-if="vm.duty.get('blockedProject')",
svg-icon="icon-blocked-project",
svg-title-translate="PROJECT.BLOCKED_PROJECT.BLOCKED"
)
h2
span.ticket-id(tg-bo-ref="duty.get('ref')")
span.ticket-title
span.ticket-title
span.ticket-blocked(
ng-if="::vm.duty.get('is_blocked')"
title="{{::vm.duty.get('blocked_note')}}"
) {{ 'COMMON.BLOCKED' | translate }}
) {{ 'COMMON.BLOCKED' | translate }}
span {{ ::duty.get('subject') }}

View File

@ -11,8 +11,8 @@
display: block;
}
.title-bar {
@extend %light;
@extend %larger;
@include font-type(light);
@include font-size(larger);
align-content: center;
background: $whitish;
display: flex;

View File

@ -11,7 +11,10 @@ section.home-project-list(ng-if="vm.projects.size")
title="{{tag.get('name')}}"
tg-repeat="tag in project.get('colorized_tags') track by tag.get('name')"
)
.project-card-inner(href="#", tg-nav="project:project=project.get('slug')")
.project-card-inner(
href="#"
tg-nav="project:project=project.get('slug')"
)
.project-card-header
a.project-card-logo(
href="#"
@ -22,19 +25,31 @@ section.home-project-list(ng-if="vm.projects.size")
tg-project-logo-small-src="::project"
alt="{{::project.get('name')}}"
)
h2.project-card-name
h3.project-card-name
a.project-title(
href="#"
tg-nav="project:project=project.get('slug')"
title="{{::project.get('name')}}"
) {{::project.get('name')}}
svg.look-for-people.icon.icon-recruit(ng-if="project.get('is_looking_for_people')")
use(xlink:href="#icon-recruit")
title="{{ ::project.get('looking_for_people_note') }}"
svg.icon.icon-blocked-project(ng-if="project.get('blocked_code')")
use(xlink:href="#icon-blocked-project")
title(translate="PROJECT.BLOCKED_PROJECT.BLOCKED")
tg-svg.look-for-people(
ng-if="project.get('is_looking_for_people')"
svg-icon="icon-recruit"
svg-title="{{ ::project.get('looking_for_people_note') }}"
)
tg-svg.owner-badge(
ng-if="project.get('i_am_owner')"
svg-icon="icon-badge"
svg-title="COMMON.OWNER"
)
tg-svg(
ng-if="project.get('blocked_code')"
svg-icon="icon-blocked-project"
svg-title-translate="PROJECT.BLOCKED_PROJECT.BLOCKED"
)
p.project-card-description {{::project.get('description')| limitTo:100 }}
span(ng-if="::project.get('description').length > 100") ...
.project-card-statistics
@ -42,29 +57,25 @@ section.home-project-list(ng-if="vm.projects.size")
ng-class="{'active': project.get('is_fan')}"
title="{{ 'PROJECT.FANS_COUNTER_TITLE'|translate:{total:project.get('total_fans')||0}:'messageformat' }}"
)
svg.icon.icon-like
use(xlink:href="#icon-like")
tg-svg(svg-icon="icon-like")
span {{::project.get('total_fans')}}
span.statistic(
ng-class="{'active': project.get('is_watcher')}"
title="{{ 'PROJECT.WATCHERS_COUNTER_TITLE'|translate:{total:project.get('total_watchers')||0}:'messageformat' }}"
)
svg.icon.icon-watch
use(xlink:href="#icon-watch")
tg-svg(svg-icon="icon-watch")
span {{::project.get('total_watchers')}}
span.statistic(
ng-class="{'active': project.get('i_am_member')}"
title="{{ 'PROJECT.MEMBERS_COUNTER_TITLE'|translate:{total:project.get('members').size||0}:'messageformat' }}"
)
svg.icon.icon-team
use(xlink:href="#icon-team")
tg-svg(svg-icon="icon-team")
span.statistics-num {{ ::project.get('members').size }}
span.statistic(
ng-if="::project.get('is_private')"
title="{{ 'PROJECT.PRIVATE' | translate }}"
)
svg.icon.icon-lock
use(xlink:href="#icon-lock")
tg-svg(svg-icon="icon-lock")
a.see-more-projects-btn.button-gray(
href="#",
@ -75,14 +86,18 @@ section.home-project-list(ng-if="vm.projects.size")
)
section.projects-empty(ng-if="vm.projects != undefined && vm.projects.size === 0")
svg.icon.icon-project
use(xlink:href="#icon-project")
tg-svg(svg-icon="icon-project")
p(translate="HOME.EMPTY_PROJECT_LIST")
a.create-project-button.button-green(href="#", ng-click="vm.newProject()",
title="{{'PROJECT.NAVIGATION.TITLE_CREATE_PROJECT' | translate}}",
translate="PROJECT.NAVIGATION.ACTION_CREATE_PROJECT")
a.create-project-button.button-green(
href="#"
ng-click="vm.newProject()"
title="{{'PROJECT.NAVIGATION.TITLE_CREATE_PROJECT' | translate}}"
translate="PROJECT.NAVIGATION.ACTION_CREATE_PROJECT"
)
span(tg-import-project-button)
a.import-project-button.button-blackish(href="#",
title="{{'PROJECT.NAVIGATION.TITLE_IMPORT_PROJECT' | translate}}",
translate="PROJECT.NAVIGATION.ACTION_IMPORT_PROJECT")
a.import-project-button.button-blackish(
href="#"
title="{{'PROJECT.NAVIGATION.TITLE_IMPORT_PROJECT' | translate}}"
translate="PROJECT.NAVIGATION.ACTION_IMPORT_PROJECT"
)
input.import-file.hidden(type="file")

View File

@ -18,7 +18,6 @@
.tags-container,
.project-card-logo,
.project-card-name a,
.icon-recruit,
.project-card-description,
.project-card-statistics {
opacity: .3;
@ -36,8 +35,8 @@
width: 100%;
}
p {
@extend %small;
@extend %light;
@include font-size(small);
@include font-type(light);
}
.create-project-button {
display: block;

View File

@ -2,7 +2,7 @@
.watching-empty {
margin-bottom: 4rem;
p {
@extend %light;
@include font-type(light);
margin: 2rem 9rem 1rem;
text-align: center;
}

View File

@ -1,11 +1,9 @@
h1
span.green {{"HOME.DASHBOARD" | translate}}
section.working-on-container
header
h1
span.green {{"HOME.DASHBOARD" | translate}}
.title-bar.working-on-title(translate="HOME.WORKING_ON_SECTION")
h1.title-bar.working-on-title(translate="HOME.WORKING_ON_SECTION")
.working-on(ng-if="vm.assignedTo.size")
.duty-single(
@ -17,7 +15,8 @@ section.working-on-container
include empty.jade
section.watching-container
.title-bar.watching-title(translate="HOME.WATCHING_SECTION")
header
h1.title-bar.watching-title(translate="HOME.WATCHING_SECTION")
.watching(ng-if="vm.watching.size")
.duty-single(

View File

@ -1,6 +1,9 @@
a(href="", title="Projects", tg-nav="projects")
svg.icon.icon-project
use(xlink:href="#icon-project")
a(
href=""
title="Projects"
tg-nav="projects"
)
tg-svg(svg-icon="icon-project")
div.navbar-dropdown.dropdown-project-list
ul
@ -11,9 +14,11 @@ div.navbar-dropdown.dropdown-project-list
ng-class="{'blocked-project': project.get('blocked_code')}"
)
span {{::project.get("name")}}
svg.icon.icon-blocked-project(ng-if="project.get('blocked_code')")
use(xlink:href="#icon-blocked-project")
title(translate="PROJECT.BLOCKED_PROJECT.BLOCKED")
tg-svg(
svg-icon="icon-blocked-project"
ng-if="project.get('blocked_code')"
svg-title="PROJECT.BLOCKED_PROJECT.BLOCKED"
)
a.see-more-projects-btn.button-gray(
href="#",
@ -33,6 +38,5 @@ div.navbar-dropdown.dropdown-project-list
href=""
title="{{'PROJECT.NAVIGATION.TITLE_IMPORT_PROJECT' | translate}}"
)
svg.icon.icon-upload
use(xlink:href="#icon-upload")
input.import-file.hidden(type="file")
tg-svg(svg-icon="icon-upload")
input.import-file.hidden(type="file")

View File

@ -30,8 +30,6 @@ div.navbar-dropdown.dropdown-user
ng-class="{active: plugin.slug == currentPlugin.slug}"
)
span.title {{ plugin.name }}
span.new(translate="PROJECT.NAVIGATION.NEW_ITEM")
li
a(
href="#",
@ -54,7 +52,7 @@ div.navbar-dropdown.dropdown-user
translate="PROJECT.NAVIGATION.FEEDBACK")
li
a(
href="https://taiga.io/support/",
href="https://tree.taiga.io/support/",
target="_blank",
title="{{'PROJECT.NAVIGATION.HELP_TITLE' | translate}}",
translate="PROJECT.NAVIGATION.HELP")

View File

@ -16,7 +16,7 @@ nav.navbar(ng-if="vm.isEnabledHeader")
include ../../svg/logo.svg
a(
href="https://taiga.io/support/",
href="https://tree.taiga.io/support/",
target="_blank",
title="{{'PROJECT.NAVIGATION.HELP_TITLE' | translate}}",
translate="PROJECT.NAVIGATION.HELP"
@ -38,21 +38,19 @@ nav.navbar(ng-if="vm.isEnabledHeader")
)
div.nav-right(ng-if="vm.isAuthenticated")
a(tg-nav="home",
ng-class="{active: vm.active}",
title="{{'PROJECT.NAVIGATION.DASHBOARD_TITLE' | translate}}")
svg.icon.icon-dashboard
use(xlink:href="#icon-dashboard")
a(
tg-nav="home"
ng-class="{active: vm.active}"
title="{{'PROJECT.NAVIGATION.DASHBOARD_TITLE' | translate}}"
)
tg-svg(svg-icon="icon-dashboard")
a(
href="#",
tg-nav="discover",
title="{{'PROJECT.NAVIGATION.DISCOVER_TITLE' | translate}}",
)
svg.icon.icon-discover
use(xlink:href="#icon-discover")
tg-svg(svg-icon="icon-discover")
div.topnav-dropdown-wrapper(ng-show="vm.projects.size", tg-dropdown-project-list)
//- div.topnav-dropdown-wrapper(tg-dropdown-organization-list)
div.topnav-dropdown-wrapper(tg-dropdown-user)

View File

@ -136,7 +136,7 @@ $dropdown-width: 350px;
}
}
.new {
@extend %small;
@include font-size(small);
background: $red-light;
float: right;
margin-left: auto;

View File

@ -4,8 +4,7 @@ section.profile-contacts
img(src="/#{v}/svg/spinner-circle.svg", alt="Loading...")
div.empty-tab(ng-if="vm.contacts && !vm.contacts.size")
svg.icon.icon-unwatch
use(xlink:href="#icon-unwatch")
tg-svg(svg-icon="icon-unwatch")
div(ng-if="!vm.isCurrentUser")
p(translate="USER.PROFILE.CONTACTS_EMPTY", translate-values="{username: vm.user.get('full_name_display')}")

View File

@ -18,12 +18,18 @@
tg-nav="project:project=vm.item.get('slug')"
title="{{ ::vm.item.get('name') }}"
) {{ ::vm.item.get('name') }}
svg.icon.icon-lock.private(ng-if="::vm.item.get('project_is_private')")
use(xlink:href="#icon-lock")
title {{'PROJECT.PRIVATE' | translate}}"
svg.icon.icon-blocked-project(ng-if="vm.item.get('project_blocked_code')")
use(xlink:href="#icon-blocked-project")
title(translate="PROJECT.BLOCKED_PROJECT.BLOCKED")
tg-svg(
ng-if="::vm.item.get('is_private')"
svg-icon="icon-lock"
svg-title-translate="PROJECT.PRIVATE"
)
tg-svg(
ng-if="vm.item.get('blocked_code')"
svg-icon="icon-blocked-project"
svg-title-translate="PROJECT.BLOCKED_PROJECT.BLOCKED"
)
p.list-itemtype-project-description {{ ::vm.item.get('description') }}
.list-itemtype-track
@ -31,14 +37,12 @@
ng-class="{'active': vm.item.get('is_fan')}"
title="{{ 'PROJECT.LIKE_BUTTON.COUNTER_TITLE'|translate:{total:vm.item.get(\"total_fans\")||0}:'messageformat' }}"
)
svg.icon.icon-like
use(xlink:href="#icon-like")
tg-svg(svg-icon="icon-like")
span {{ ::vm.item.get('total_fans') }}
span.list-itemtype-track-watchers(
ng-class="{'active': vm.item.get('is_watcher')}"
title="{{ 'PROJECT.WATCH_BUTTON.COUNTER_TITLE'|translate:{total:vm.item.get(\"total_watchers\")||0}:'messageformat' }}"
)
svg.icon.icon-watch
use(xlink:href="#icon-watch")
tg-svg(svg-icon="icon-watch")
span {{ ::vm.item.get('total_watchers') }}

View File

@ -1,4 +1,4 @@
div.list-itemtype-ticket(ng-class="{'blocked-project': vm.item.get('project_blocked_code')}")
.list-itemtype-ticket(ng-class="{'blocked-project': vm.item.get('project_blocked_code')}")
a.list-itemtype-avatar(
href=""
ng-if="::vm.item.get('assigned_to')"
@ -20,7 +20,7 @@ div.list-itemtype-ticket(ng-class="{'blocked-project': vm.item.get('project_bloc
alt="{{ 'COMMON.ASSIGNED_TO.NOT_ASSIGNED'|translate }}"
)
div.list-itemtype-ticket-data
.list-itemtype-ticket-data
p
span.ticket-project
| {{:: vm.item.get('project_name') }}
@ -36,11 +36,12 @@ div.list-itemtype-ticket(ng-class="{'blocked-project': vm.item.get('project_bloc
ng-if="::vm.item.get('type') === 'issue'"
translate="COMMON.ISSUE"
)
span.ticket-status(ng-style="::{'color': vm.item.get('status_color')}")
| {{:: vm.item.get('status') }}
svg.icon.icon-blocked-project(ng-if="vm.item.get('project_blocked_code')")
use(xlink:href="#icon-blocked-project")
title(translate="PROJECT.BLOCKED_PROJECT.BLOCKED")
span.ticket-status(ng-style="::{'color': vm.item.get('status_color')}") {{:: vm.item.get('status') }}
tg-svg(
ng-if="vm.item.get('project_blocked_code')"
svg-icon="icon-blocked-project"
svgTitleTranslate: "PROJECT.BLOCKED_PROJECT.BLOCKED"
)
h2
span.ticket-id(tg-bo-ref="vm.item.get('ref')")
a.ticket-title(
@ -67,14 +68,12 @@ div.list-itemtype-ticket(ng-class="{'blocked-project': vm.item.get('project_bloc
ng-class="{'active': vm.item.get('is_voter')}",
title="{{ 'COMMON.VOTE_BUTTON.COUNTER_TITLE'|translate:{total:vm.item.get(\"total_voters\")||0}:'messageformat' }}"
)
svg.icon.icon-upvote
use(xlink:href="#icon-upvote")
tg-svg(svg-icon="icon-upvote")
span {{ ::vm.item.get('total_voters') }}
span.list-itemtype-track-watchers(
ng-class="{'active': vm.item.get('is_watcher')}"
title="{{ 'COMMON.WATCH_BUTTON.COUNTER_TITLE'|translate:{total:vm.item.get(\"total_watchers\")||0}:'messageformat' }}"
)
svg.icon.icon-watch
use(xlink:href="#icon-watch")
tg-svg(svg-icon="icon-watch")
span {{ ::vm.item.get('total_watchers') }}

View File

@ -1,8 +1,7 @@
section.profile-favs
div.profile-filter
div.searchbox(ng-if="::vm.enableFilterByTextQuery")
svg.icon.icon-search
use(xlink:href="#icon-search")
tg-svg(svg-icon="icon-search")
input(
type="text"
ng-model="vm.q"

View File

@ -20,10 +20,10 @@
class ProfileHints
HINTS: [
{ #hint1
url: "https://taiga.io/support/import-export-projects/"
url: "https://tree.taiga.io/support/admin/import-export-projects/"
},
{ #hint2
url: "https://taiga.io/support/custom-fields/"
url: "https://tree.taiga.io/support/admin/custom-fields/"
},
{ #hint3
},

View File

@ -1,6 +1,5 @@
h4
svg.icon.icon-question
use(xlink:href="#icon-question")
tg-svg(svg-icon="icon-question")
span(translate="HINTS.SECTION_NAME")
p {{::vm.hint.title}}

View File

@ -4,8 +4,7 @@ section.profile-projects
img(src="/#{v}/svg/spinner-circle.svg", alt="Loading...")
.empty-tab(ng-if="vm.projects && !vm.projects.size")
svg.icon.icon-unwatch
use(xlink:href="#icon-unwatch")
tg-svg(svg-icon="icon-unwatch")
p(
translate="USER.PROFILE.PROJECTS_EMPTY"
@ -33,9 +32,12 @@ section.profile-projects
tg-nav="project:project=project.get('slug')"
title="{{ ::project.get('name') }}"
) {{::project.get('name')}}
svg.icon.icon-blocked-project(ng-if="project.get('blocked_code')")
use(xlink:href="#icon-blocked-project")
title(translate="PROJECT.BLOCKED_PROJECT.BLOCKED")
tg-svg(
ng-if="project.get('blocked_code')",
svg-icon="icon-blocked-project"
svg-title-translate="PROJECT.BLOCKED_PROJECT.BLOCKED"
)
p.project-description {{ ::project.get('description') | limitTo:300 }}
.list-itemtype-project-right
@ -45,16 +47,14 @@ section.profile-projects
ng-class="{'active': project.get('is_fan')}"
title="{{ 'PROJECT.LIKE_BUTTON.COUNTER_TITLE'|translate:{total:project.get(\"total_fans\")||0}:'messageformat' }}"
)
svg.icon.icon-like
use(xlink:href="#icon-like")
tg-svg(svg-icon="icon-like")
span {{ ::project.get('total_fans') }}
span.list-itemtype-track-watchers(
ng-class="{'active': project.get('is_watcher')}"
title="{{ 'PROJECT.WATCH_BUTTON.COUNTER_TITLE'|translate:{total:project.get(\"total_watchers\")||0}:'messageformat' }}"
)
svg.icon.icon-watch
use(xlink:href="#icon-watch")
tg-svg(svg-icon="icon-watch")
span {{ ::project.get('total_watchers') }}
.list-itemtype-project-members

View File

@ -28,7 +28,6 @@ ProfileTabDirective = () ->
scope.tab.title = title
scope.tab.icon = attrs.tabIcon
scope.tab.iconName = '#' + attrs.tabIcon
scope.tab.active = !!attrs.tabActive
if scope.$eval(attrs.tabDisabled) != true

View File

@ -7,8 +7,7 @@ div
ng-click="vm.toggleTab(tab)"
ng-class="{active: tab.active}"
)
svg.icon(ng-class="::tab.icon")
use(xlink:href="{{::tab.iconName}}")
tg-svg(svg-icon="{{::tab.icon}}")
span {{::tab.name}}
ng-transclude

View File

@ -27,7 +27,7 @@
margin: 10% auto;
width: 3rem;
img {
@extend %loading-spinner;
@include loading-spinner;
max-height: 3rem;
max-width: 3rem;
}

View File

@ -22,8 +22,8 @@
width: 100%;
}
.profile-edition {
@extend %large;
@extend %light;
@include font-size(large);
@include font-type(light);
background: rgba($black, .4);
bottom: 0;
color: $white;
@ -64,8 +64,8 @@
}
}
h1 {
@extend %bold;
@extend %xlarge;
@include font-type(bold);
@include font-size(xlarge);
line-height: 1.2;
margin-bottom: .25rem;
text-transform: none;
@ -75,15 +75,15 @@
word-wrap: break-word;
}
h2 {
@extend %light;
@extend %larger;
@include font-type(light);
@include font-size(larger);
color: $gray;
line-height: 1.2;
margin-bottom: 1rem;
}
.username {
@extend %light;
@extend %large;
@include font-type(light);
@include font-size(large);
color: $gray-light;
margin-bottom: 1rem;
}
@ -112,43 +112,20 @@
text-align: center;
}
.stat-number {
@extend %xlarge;
@extend %bold;
@include font-size(xlarge);
@include font-type(bold);
display: block;
line-height: 1;
}
.stat-name {
@extend %title;
@extend %small;
@include font-type(text);
@include font-size(small);
display: block;
}
}
.profile-organizations {
border-bottom: 1px solid $whitish;
border-top: 1px solid $whitish;
margin-bottom: 1rem;
padding: 1rem 0;
h3 {
@extend %bold;
margin-bottom: .5rem;
}
.profile-organizations-wrapper {
display: flex;
justify-content: space-between;
}
.organization {
background: $gray-light;
border-radius: 5px;
height: 45px;
margin-right: .2rem;
width: 45px;
}
}
.profile-quote {
@extend %light;
@extend %large;
@include font-type(light);
@include font-size(large);
background: url('../images/quote.png') no-repeat top left;
line-height: 1.4;
padding: .5rem;

View File

@ -20,63 +20,3 @@
}
}
}
.profile-contact-single {
border-bottom: 1px solid $whitish;
display: flex;
flex-wrap: wrap;
padding: .8rem 1rem;
.profile-contact-picture {
flex-grow: 0;
margin-right: 1rem;
max-width: 54px;
img {
border-radius: .2rem;
width: 100%;
}
}
.profile-contact-data {
flex: 1;
h1 {
@extend %text;
@extend %large;
align-items: center;
display: flex;
line-height: 1.6;
margin-bottom: 0;
text-transform: none;
span {
@extend %text;
@extend %small;
background: $whitish;
color: $gray;
margin-left: 1rem;
padding: .1rem .3rem;
}
}
p {
color: $gray;
margin-bottom: 0;
}
.extra-info {
@extend %light;
color: $gray;
}
.position {
margin-right: .3rem;
}
}
.profile-project-stats {
display: flex;
flex-grow: 0;
margin-left: auto;
width: 100px;
div {
color: $gray-light;
margin-right: .5rem;
.icon {
margin-right: .2rem;
vertical-align: center;
}
}
}
}

View File

@ -1,6 +1,6 @@
.profile-sidebar {
h4 {
@extend %bold;
@include font-type(bold);
background: $whitish;
color: $gray;
margin-bottom: .5rem;
@ -13,7 +13,7 @@
}
}
p {
@extend %small;
@include font-size(small);
color: $gray-light;
}
a {

Some files were not shown because too many files have changed in this diff Show More