Merge pull request #15 from taigaio/attachments-component

Attachments as components
stable
David Barragán Merino 2014-09-12 03:09:14 +02:00
commit 2a46431b3f
18 changed files with 273 additions and 287 deletions

View File

@ -21,9 +21,6 @@
taiga = @.taiga taiga = @.taiga
trim = @.taiga.trim
typeIsArray = @.taiga.typeIsArray
module = angular.module("taigaCommon", []) module = angular.module("taigaCommon", [])
############################################################################# #############################################################################
@ -31,19 +28,15 @@ module = angular.module("taigaCommon", [])
############################################################################# #############################################################################
CheckPermissionDirective = -> CheckPermissionDirective = ->
showElementIfPermission = (element, permission, project) -> render = ($el, project, permission) ->
element.show() if project.my_permissions.indexOf(permission) > -1 $el.show() if project.my_permissions.indexOf(permission) > -1
link = ($scope, $el, $attrs) -> link = ($scope, $el, $attrs) ->
$el.hide() $el.hide()
permission = $attrs.tgCheckPermission permission = $attrs.tgCheckPermission
#Sometimes this directive from a self included html template $scope.$watch "project", (project) ->
if $scope.project? render($el, project, permission) if project?
showElementIfPermission($el, permission, $scope.project)
$scope.$on "project:loaded", (ctx, project) ->
showElementIfPermission($el, permission, project)
$scope.$on "$destroy", -> $scope.$on "$destroy", ->
$el.off() $el.off()

View File

@ -21,22 +21,189 @@
taiga = @.taiga taiga = @.taiga
sizeFormat = @.taiga.sizeFormat sizeFormat = @.taiga.sizeFormat
bindOnce = @.taiga.bindOnce
module = angular.module("taigaCommon") module = angular.module("taigaCommon")
############################################################################# class AttachmentsController extends taiga.Controller
## Attachments Directive @.$inject = ["$scope", "$rootScope", "$tgRepo", "$tgResources", "$tgConfirm", "$q"]
#############################################################################
AttachmentsDirective = ($repo, $rs, $confirm) -> constructor: (@scope, @rootscope, @repo, @rs, @confirm, @q) ->
link = ($scope, $el, $attrs, $model) -> _.bindAll(@)
$ctrl = $el.controller() @.type = null
$scope.uploadingFiles = [] @.objectId = null
@.uploadingAttachments = []
@.attachments = []
@.attachmentsCount = 0
@.deprecatedAttachmentsCount = 0
@.showDeprecated = false
initialize: (type, objectId) ->
@.type = type
@.objectId = objectId
loadAttachments: ->
urlname = "attachments/#{@.type}"
id = @.objectId
return @rs.attachments.list(urlname, id).then (attachments) =>
@.attachments = _.sortBy(attachments, "order")
@.updateCounters()
return attachments
updateCounters: ->
@.attachmentsCount = @.attachments.length
@.deprecatedAttachmentsCount = _.filter(@.attachments, {is_deprecated: true}).length
_createAttachment: (attachment) ->
projectId = @scope.projectId
urlName = "attachments/#{@.type}"
promise = @rs.attachments.create(urlName, projectId, @.objectId, attachment)
promise = promise.then (data) =>
data.isCreatedRightNow = true
index = @.uploadingAttachments.indexOf(attachment)
@.uploadingAttachments.splice(index, 1)
@.attachments.push(data)
@rootscope.$broadcast("attachment:create")
promise = promise.then null, (data) ->
index = @.uploadingAttachments.indexOf(attachment)
@.uploadingAttachments.splice(index, 1)
@confirm.notify("error", null, "We have not been able to upload '#{attachment.name}'.")
return @q.reject(data)
return promise
# Create attachments in bulk
createAttachments: (attachments) ->
promises = _.map(attachments, (x) => @._createAttachment(x))
return @q.all.apply(null, promises).then =>
@.updateCounters()
# Add uploading attachment tracking.
addUploadingAttachments: (attachments) ->
@.uploadingAttachments = _.union(@.uploadingAttachments, attachments)
# Change order of attachment in a ordered list.
# This function is mainly executed after sortable ends.
reorderAttachment: (attachment, newIndex) ->
oldIndex = @.attachments.indexOf(attachment)
return if oldIndex == newIndex
@.attachments.splice(oldIndex, 1)
@.attachments.splice(newIndex, 0, attachment)
_.each(@.attachments, (x,i) -> x.order = i+1)
# Persist one concrete attachment.
# This function is mainly used when user clicks
# to save button for save one unique attachment.
updateAttachment: (attachment) ->
onSuccess = =>
@.updateCounters()
@rootscope.$broadcast("attachment:edit")
onError = =>
@confirm.notify("error")
return @q.reject()
return @repo.save(attachment).then(onSuccess, onError)
# Persist all pending modifications on attachments.
# This function is used mainly for persist the order
# after sorting.
saveAttachments: ->
return @repo.saveAll(@.attachments).then null, =>
for item in @.attachments
item.revert()
@.attachments = _.sorBy(@.attachments, "order")
# Remove one concrete attachment.
removeAttachment: (attachment) ->
title = "Delete attachment" #TODO: i18in
subtitle = "the attachment '#{attachment.name}'" #TODO: i18in
onSuccess = =>
index = @.attachments.indexOf(attachment)
@.attachments.splice(index, 1)
@.updateCounters()
@rootscope.$broadcast("attachment:delete")
onError = =>
@confirm.notify("error", null, "We have not been able to delete #{subtitle}.")
return @q.reject()
return @confirm.ask(title, subtitle).then =>
return @repo.remove(attachment).then(onSuccess, onError)
# Function used in template for filter visible attachments
filterAttachments: (item) ->
if @.showDeprecated
return true
return not item.is_deprecated
AttachmentsDirective = ($confirm) ->
template = _.template("""
<section class="attachments">
<div class="attachments-header">
<h3 class="attachments-title">
<span class="icon icon-attachments"></span>
<span class="attachments-num" tg-bind-html="ctrl.attachmentsCount"></span>
<span class="attachments-text">attachments</span>
<div tg-check-permission="modify_<%- type %>"
title="Add new attachment" class="button button-gray add-attach">
<span>+new file</span>
<input type="file" multiple="multiple"/>
</div>
</h3>
</div>
<div class="attachment-body sortable">
<div ng-repeat="attach in ctrl.attachments|filter:ctrl.filterAttachments track by attach.id"
tg-attachment="attach"
class="single-attachment">
</div>
<div ng-repeat="file in ctrl.uploadingAttachments" class="single-attachment">
<div class="attachment-name">
<a href="" tg-bo-title="file.name" tg-bo-bind="file.name"></a>
</div>
<div class="attachment-size">
<span tg-bo-bind="file.size" class="attachment-size"></span>
</div>
<div class="attachment-comments">
<span ng-bind="file.progressMessage"></span>
<div ng-style="{'width': file.progressPercent}" class="percentage"></div>
</div>
</div>
<a href="" title="show deprecated atachments" class="more-attachments"
ng-if="ctrl.deprecatedAttachmentsCount > 0">
<span class="text" data-type="show">+ show deprecated atachments</span>
<span class="text hidden" data-type="hide">- hide deprecated atachments</span>
<span class="more-attachments-num">
({{ctrl.deprecatedAttachmentsCount }} deprecated)
</span>
</a>
</div>
</section>""")
link = ($scope, $el, $attrs, $ctrls) ->
$ctrl = $ctrls[0]
$model = $ctrls[1]
bindOnce $scope, $attrs.ngModel, (value) ->
$ctrl.initialize($attrs.type, value.id)
$ctrl.loadAttachments()
## Drag & drop
tdom = $el.find("div.attachment-body.sortable") tdom = $el.find("div.attachment-body.sortable")
tdom.sortable({ tdom.sortable({
items: "div.single-attachment" items: "div.single-attachment"
handle: "a.settings.icon.icon-drag-v" handle: "a.settings.icon.icon-drag-v"
@ -49,101 +216,58 @@ AttachmentsDirective = ($repo, $rs, $confirm) ->
tdom.on "sortstop", (event, ui) -> tdom.on "sortstop", (event, ui) ->
attachment = ui.item.scope().attach attachment = ui.item.scope().attach
newIndex = ui.item.index() newIndex = ui.item.index()
index = $scope.attachments.indexOf(attachment)
return if index == newIndex $ctrl.reorderAttachment(attachment, newIndex)
$ctrl.saveAttachments()
# Move attachment to newIndex and recalculate order $el.on "click", "a.add-attach", (event) ->
$scope.attachments.splice(index, 1) event.preventDefault()
$scope.attachments.splice(newIndex, 0, attachment) $el.find("input.add-attach").trigger("click")
_.forEach $scope.attachments, (attach, idx) ->
attach.order = idx+1
# Save or revert changes $el.on "change", "input.add-attach", (event) ->
$repo.saveAll($scope.attachments).then null, -> files = _.toArray(event.target.files)
_.forEach $scope.attachments, attach -> return if files.length < 1
attach.revert()
_.sorBy($scope.attachments, 'order')
## Total attachments counter $scope.$apply ->
$scope.$watch "attachmentsCount", (count) -> $ctrl.addUploadingAttachments(files)
$el.find("span.attachments-num").html(count) $ctrl.createAttachments(files)
## Show/Hide deprecated attachments $el.on "click", ".more-attachments", (event) ->
$scope.showDeprecatedAttachments = false
$scope.$watch "deprecatedAttachmentsCount", (deprecatedAttachmentsCount) ->
$el.find("span.more-attachments-num").html("(#{deprecatedAttachmentsCount} deprecated)") # TODO: i18n
if deprecatedAttachmentsCount
$el.find("a.more-attachments").removeClass("hidden")
else
$el.find("a.more-attachments").addClass("hidden")
$el.on "click", "a.more-attachments", ->
event.preventDefault() event.preventDefault()
target = angular.element(event.currentTarget) target = angular.element(event.currentTarget)
$scope.showDeprecatedAttachments = not $scope.showDeprecatedAttachments $scope.$apply ->
$ctrl.showDeprecated = not $ctrl.showDeprecated
if $scope.showDeprecatedAttachments target.find("span.text").addClass("hidden")
target.find("span.text").html("- hide deprecated attachments") # TODO: i18n if $ctrl.showDeprecated
.prop("title", "hide deprecated attachments") # TODO: i18n target.find("span[data-type=hide]").removeClass("hidden")
$el.find("div.single-attachment.deprecated").removeClass("hidden") target.find("more-attachments-num").addClass("hidden")
else else
target.find("span.text").html("+ show deprecated attachments") # TODO: i18n target.find("span[data-type=show]").removeClass("hidden")
.prop("title", "show deprecated attachments") # TODO: i18n target.find("more-attachments-num").removeClass("hidden")
$el.find("div.single-attachment.deprecated").addClass("hidden")
$el.on "change", "input.add-attach", ->
files = _.map(event.target.files, (x) -> x)
return if files.length < 1
# Add files to uploadingFiles array
$scope.$apply =>
if not $scope.uploadingFiles or $scope.uploadingFiles.length == 0
$scope.uploadingFiles = files
else
$scope.uploadingFiles = scope.uploadingFiles.concat(files)
# Upload new files
urlName = $ctrl.attachmentsUrlName
projectId = $scope.projectId
objectId = $model.$modelValue.id
_.forEach files, (file) ->
promise = $rs.attachments.create(urlName, projectId, objectId, file)
promise.then (data) ->
data.isCreatedRightNow = true
index = $scope.uploadingFiles.indexOf(file)
$scope.uploadingFiles.splice(index, 1)
$ctrl.onCreateAttachment(data)
promise.then null, (data) ->
index = $scope.uploadingFiles.indexOf(file)
$scope.uploadingFiles.splice(index, 1)
$confirm.notify("error", null, "We have not been able to upload '#{file.name}'.") #TODO: i18in
## On destroy
$scope.$on "$destroy", -> $scope.$on "$destroy", ->
$el.off() $el.off()
templateFn = ($el, $attrs) ->
return template({type: $attrs.type})
return { return {
link: link, require: ["tgAttachments", "ngModel"]
require: "ngModel" controller: AttachmentsController
controllerAs: "ctrl"
restrict: "AE"
scope: true
link: link
template: templateFn
} }
module.directive("tgAttachments", ["$tgRepo", "$tgResources", "$tgConfirm", AttachmentsDirective]) module.directive("tgAttachments", ["$tgConfirm", AttachmentsDirective])
############################################################################# AttachmentDirective = ->
## Attachment Directive template = _.template("""
#############################################################################
AttachmentDirective = ($log, $repo, $confirm) ->
singleAttachment = _.template("""
<div class="attachment-name"> <div class="attachment-name">
<a href="<%- url %>" title="<%- name %>" target="_blank"> <a href="<%- url %>" title="<%- name %>" target="_blank">
<span class="icon icon-documents"></span> <span class="icon icon-documents"></span>
@ -164,9 +288,9 @@ AttachmentDirective = ($log, $repo, $confirm) ->
<a class="settings icon icon-drag-v" href="" title=""Drag"></a> <a class="settings icon icon-drag-v" href="" title=""Drag"></a>
</div> </div>
<% } %> <% } %>
""") #TODO: i18n """)
singleAttachmentEditable = _.template(""" templateEdit = _.template("""
<div class="attachment-name"> <div class="attachment-name">
<span class="icon.icon-document"></span> <span class="icon.icon-document"></span>
<a href="<%- url %>" title="<%- name %>" target="_blank"><%- name %></a> <a href="<%- url %>" title="<%- name %>" target="_blank"><%- name %></a>
@ -188,13 +312,13 @@ AttachmentDirective = ($log, $repo, $confirm) ->
<a class="editable-settings icon icon-floppy" href="" title="Save"></a> <a class="editable-settings icon icon-floppy" href="" title="Save"></a>
<a class="editable-settings icon icon-delete" href="" title="Cancel"></a> <a class="editable-settings icon icon-delete" href="" title="Cancel"></a>
</div> </div>
""") # TODO: i18n """)
link = ($scope, $el, $attrs) -> link = ($scope, $el, $attrs, $ctrl) ->
$ctrl = $el.controller() render = (attachment, edit=false) ->
permissions = $scope.project.my_permissions
modifyPermission = permissions.indexOf("modify_#{$ctrl.type}") > -1
render = (attachment, isEditable=false) ->
modifyPermission = $scope.project.my_permissions.indexOf("modify_#{$attrs.permissionSuffix}") > -1
ctx = { ctx = {
id: attachment.id id: attachment.id
name: attachment.name name: attachment.name
@ -205,30 +329,29 @@ AttachmentDirective = ($log, $repo, $confirm) ->
modifyPermission: modifyPermission modifyPermission: modifyPermission
} }
if isEditable if edit
html = singleAttachmentEditable(ctx) html = templateEdit(ctx)
else else
html = singleAttachment(ctx) html = template(ctx)
$el.html(html) $el.html(html)
if attachment.is_deprecated if attachment.is_deprecated
$el.addClass("deprecated") $el.addClass("deprecated")
if $scope.showDeprecatedAttachments
$el.removeClass("hidden")
else
$el.addClass("hidden")
else
$el.removeClass("deprecated")
$el.removeClass("hidden")
## Initialize ## Actions (on edit mode)
if not $attrs.tgAttachment? $el.on "click", "a.editable-settings.icon-floppy", (event) ->
return $log.error "AttachmentDirective the directive need an attachment" event.preventDefault()
attachment = $scope.$eval($attrs.tgAttachment) attachment.description = $el.find("input[name='description']").val()
render(attachment, attachment.isCreatedRightNow) attachment.is_deprecated = $el.find("input[name='is-deprecated']").prop("checked")
delete attachment.isCreatedRightNow
$scope.$apply ->
$ctrl.updateAttachment(attachment).then ->
render(attachment)
$el.on "click", "a.editable-settings.icon-delete", (event) ->
event.preventDefault()
render(attachment, false)
## Actions (on view mode) ## Actions (on view mode)
$el.on "click", "a.settings.icon-edit", (event) -> $el.on "click", "a.settings.icon-edit", (event) ->
@ -237,49 +360,20 @@ AttachmentDirective = ($log, $repo, $confirm) ->
$el.on "click", "a.settings.icon-delete", (event) -> $el.on "click", "a.settings.icon-delete", (event) ->
event.preventDefault() event.preventDefault()
$scope.$apply ->
$ctrl.removeAttachment(attachment)
title = "Delete attachment" #TODO: i18in
subtitle = "the attachment '#{attachment.name}'" #TODO: i18in
onSuccess = ->
$ctrl.onDeleteAttachment(attachment)
onError = ->
$confirm.notify("error", null, "We have not been able to delete #{subtitle}.") #TODO: i18in
$confirm.ask(title, subtitle).then ->
$repo.remove(attachment).then(onSuccess, onError)
## Actions (on edit mode)
$el.on "click", "a.editable-settings.icon-floppy", (event) ->
event.preventDefault()
newDescription = $el.find("input[name='description']").val()
newIsDeprecated = $el.find("input[name='is-deprecated']").prop("checked")
if newDescription != attachment.description
attachment.description = newDescription
if newIsDeprecated != attachment.is_deprecated
attachment.is_deprecated = newIsDeprecated
onSuccess = ->
$ctrl.onEditAttachment(attachment)
render(attachment)
onError = ->
$confirm.notify("error")
$repo.save(attachment).then(onSuccess, onError)
$el.on "click", "a.editable-settings.icon-delete", (event) ->
event.preventDefault()
render(attachment)
## On destroy
$scope.$on "$destroy", -> $scope.$on "$destroy", ->
$el.off() $el.off()
return {link: link} # Bootstrap
attachment = $scope.$eval($attrs.tgAttachment)
render(attachment, attachment.isCreatedRightNow)
module.directive("tgAttachment", ["$log", "$tgRepo", "$tgConfirm", return {
AttachmentDirective]) link: link
require: "^tgAttachments"
restrict: "AE"
}
module.directive("tgAttachment", AttachmentDirective)

View File

@ -102,44 +102,3 @@ class FiltersMixin
location.search(name, value) location.search(name, value)
taiga.FiltersMixin = FiltersMixin taiga.FiltersMixin = FiltersMixin
#############################################################################
## Attachments Mixin
#############################################################################
# This mixin requires @rs ($tgResources), @scope and @log ($tgLog)
# The mixin required @..attachmentsUrlName (p.e. 'issues/attachments',see resources.coffee)
class AttachmentsMixin
loadAttachments: (objectId) ->
if not @.attachmentsUrlName
return @log.error "AttachmentsMixin: @.attachmentsUrlName is required"
@scope.attachmentsCount = 0
@scope.deprecatedAttachmentsCount = 0
return @rs.attachments.list(@.attachmentsUrlName, objectId).then (attachments) =>
@scope.attachments = _.sortBy(attachments, "order")
@.updateAttachmentsCounters()
return attachments
updateAttachmentsCounters: ->
@scope.attachmentsCount = @scope.attachments.length
@scope.deprecatedAttachmentsCount = _.filter(@scope.attachments, is_deprecated: true).length
onCreateAttachment: (attachment) ->
@scope.attachments[@scope.attachments.length] = attachment
@.updateAttachmentsCounters()
@scope.$emit("attachment:create")
onEditAttachment: (attachment) ->
@.updateAttachmentsCounters()
@scope.$emit("attachment:edit")
onDeleteAttachment: (attachment) ->
index = @scope.attachments.indexOf(attachment)
@scope.attachments.splice(index, 1)
@.updateAttachmentsCounters()
@scope.$emit("attachment:delete")
taiga.AttachmentsMixin = AttachmentsMixin

View File

@ -33,7 +33,7 @@ module = angular.module("taigaIssues")
## Issue Detail Controller ## Issue Detail Controller
############################################################################# #############################################################################
class IssueDetailController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.AttachmentsMixin) class IssueDetailController extends mixOf(taiga.Controller, taiga.PageMixin)
@.$inject = [ @.$inject = [
"$scope", "$scope",
"$rootScope", "$rootScope",
@ -49,8 +49,6 @@ class IssueDetailController extends mixOf(taiga.Controller, taiga.PageMixin, tai
] ]
constructor: (@scope, @rootscope, @repo, @confirm, @rs, @params, @q, @location, @log, @appTitle, @navUrls) -> constructor: (@scope, @rootscope, @repo, @confirm, @rs, @params, @q, @location, @log, @appTitle, @navUrls) ->
@.attachmentsUrlName = "issues/attachments"
@scope.issueRef = @params.issueref @scope.issueRef = @params.issueref
@scope.sectionName = "Issue Details" @scope.sectionName = "Issue Details"
@ -118,8 +116,7 @@ class IssueDetailController extends mixOf(taiga.Controller, taiga.PageMixin, tai
return promise.then(=> @.loadProject()) return promise.then(=> @.loadProject())
.then(=> @.loadUsersAndRoles()) .then(=> @.loadUsersAndRoles())
.then(=> @q.all([@.loadIssue(), .then(=> @.loadIssue())
@.loadAttachments(@scope.issueId)]))
block: -> block: ->
@rootscope.$broadcast("block", @scope.issue) @rootscope.$broadcast("block", @scope.issue)

View File

@ -88,10 +88,10 @@ urls = {
"history/wiki": "/api/v1/history/wiki" "history/wiki": "/api/v1/history/wiki"
# Attachments # Attachments
"userstories/attachments": "/api/v1/userstories/attachments" "attachments/us": "/api/v1/userstories/attachments"
"issues/attachments": "/api/v1/issues/attachments" "attachments/issue": "/api/v1/issues/attachments"
"tasks/attachments": "/api/v1/tasks/attachments" "attachments/task": "/api/v1/tasks/attachments"
"wiki/attachments": "/api/v1/wiki/attachments" "attachments/wiki_page": "/api/v1/wiki/attachments"
} }
# Initialize api urls service # Initialize api urls service

View File

@ -30,7 +30,7 @@ module = angular.module("taigaTasks")
## Task Detail Controller ## Task Detail Controller
############################################################################# #############################################################################
class TaskDetailController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.AttachmentsMixin) class TaskDetailController extends mixOf(taiga.Controller, taiga.PageMixin)
@.$inject = [ @.$inject = [
"$scope", "$scope",
"$rootScope", "$rootScope",
@ -46,8 +46,6 @@ class TaskDetailController extends mixOf(taiga.Controller, taiga.PageMixin, taig
] ]
constructor: (@scope, @rootscope, @repo, @confirm, @rs, @params, @q, @location, @log, @appTitle, @navUrls) -> constructor: (@scope, @rootscope, @repo, @confirm, @rs, @params, @q, @location, @log, @appTitle, @navUrls) ->
@.attachmentsUrlName = "tasks/attachments"
@scope.taskRef = @params.taskref @scope.taskRef = @params.taskref
@scope.sectionName = "Task Details" @scope.sectionName = "Task Details"
@ -110,7 +108,6 @@ class TaskDetailController extends mixOf(taiga.Controller, taiga.PageMixin, taig
return promise.then(=> @.loadProject()) return promise.then(=> @.loadProject())
.then(=> @.loadUsersAndRoles()) .then(=> @.loadUsersAndRoles())
.then(=> @.loadTask()) .then(=> @.loadTask())
.then(=> @.loadAttachments(@scope.taskId))
block: -> block: ->
@rootscope.$broadcast("block", @scope.task) @rootscope.$broadcast("block", @scope.task)

View File

@ -31,7 +31,7 @@ module = angular.module("taigaUserStories")
## User story Detail Controller ## User story Detail Controller
############################################################################# #############################################################################
class UserStoryDetailController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.AttachmentsMixin) class UserStoryDetailController extends mixOf(taiga.Controller, taiga.PageMixin)
@.$inject = [ @.$inject = [
"$scope", "$scope",
"$rootScope", "$rootScope",
@ -47,7 +47,6 @@ class UserStoryDetailController extends mixOf(taiga.Controller, taiga.PageMixin,
] ]
constructor: (@scope, @rootscope, @repo, @confirm, @rs, @params, @q, @location, @log, @appTitle, @navUrls) -> constructor: (@scope, @rootscope, @repo, @confirm, @rs, @params, @q, @location, @log, @appTitle, @navUrls) ->
@.attachmentsUrlName = "userstories/attachments"
@scope.issueRef = @params.issueref @scope.issueRef = @params.issueref
@scope.sectionName = "User Story Details" @scope.sectionName = "User Story Details"
@ -114,8 +113,7 @@ class UserStoryDetailController extends mixOf(taiga.Controller, taiga.PageMixin,
return promise.then(=> @.loadProject()) return promise.then(=> @.loadProject())
.then(=> @.loadUsersAndRoles()) .then(=> @.loadUsersAndRoles())
.then(=> @q.all([@.loadUs(), .then(=> @.loadUs())
@.loadAttachments(@scope.usId)]))
block: -> block: ->
@rootscope.$broadcast("block", @scope.us) @rootscope.$broadcast("block", @scope.us)

View File

@ -32,7 +32,7 @@ module = angular.module("taigaWiki")
## Wiki Detail Controller ## Wiki Detail Controller
############################################################################# #############################################################################
class WikiDetailController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.AttachmentsMixin) class WikiDetailController extends mixOf(taiga.Controller, taiga.PageMixin)
@.$inject = [ @.$inject = [
"$scope", "$scope",
"$rootScope", "$rootScope",
@ -50,7 +50,6 @@ class WikiDetailController extends mixOf(taiga.Controller, taiga.PageMixin, taig
constructor: (@scope, @rootscope, @repo, @confirm, @rs, @params, @q, @location, @filter, @log, @appTitle, constructor: (@scope, @rootscope, @repo, @confirm, @rs, @params, @q, @location, @filter, @log, @appTitle,
@navUrls) -> @navUrls) ->
@.attachmentsUrlName = "wiki/attachments"
@scope.projectSlug = @params.pslug @scope.projectSlug = @params.pslug
@scope.wikiSlug = @params.slug @scope.wikiSlug = @params.slug
@scope.sectionName = "Wiki" @scope.sectionName = "Wiki"
@ -116,8 +115,7 @@ class WikiDetailController extends mixOf(taiga.Controller, taiga.PageMixin, taig
return promise.then(=> @.loadProject()) return promise.then(=> @.loadProject())
.then(=> @.loadUsersAndRoles()) .then(=> @.loadUsersAndRoles())
.then(=> @q.all([@.loadWikiLinks(), .then(=> @q.all([@.loadWikiLinks(),
@.loadWiki(), @.loadWiki()]))
@.loadAttachments(@scope.wikiId)]))
edit: -> edit: ->
ctx = { ctx = {

View File

@ -28,10 +28,7 @@ block content
section.us-content section.us-content
textarea(placeholder="Write a description of your issue", ng-model="issue.description", tg-markitup) textarea(placeholder="Write a description of your issue", ng-model="issue.description", tg-markitup)
- var attachModel = "issue" tg-attachments(ng-model="issue", type="issue")
- var permissionSuffix = "issue"
include views/modules/attachments
tg-history(ng-model="issue", type="issue", mode="edit") tg-history(ng-model="issue", type="issue", mode="edit")
sidebar.menu-secondary.sidebar sidebar.menu-secondary.sidebar

View File

@ -28,10 +28,7 @@ block content
section.us-content.wysiwyg(tg-bind-html="issue.description_html") section.us-content.wysiwyg(tg-bind-html="issue.description_html")
- var attachModel = "issue" tg-attachments(ng-model="issue", type="issue")
- var permissionSuffix = "issue"
include views/modules/attachments
tg-history(ng-model="issue", type="issue") tg-history(ng-model="issue", type="issue")
sidebar.menu-secondary.sidebar sidebar.menu-secondary.sidebar

View File

@ -28,10 +28,7 @@ block content
section.us-content section.us-content
textarea(placeholder="Write a description of your task", ng-model="task.description", tg-markitup) textarea(placeholder="Write a description of your task", ng-model="task.description", tg-markitup)
- var attachModel = "task" tg-attachments(ng-model="task", type="task")
- var permissionSuffix = "task"
include views/modules/attachments
tg-history(ng-model="task", type="task", mode="edit") tg-history(ng-model="task", type="task", mode="edit")
sidebar.menu-secondary.sidebar sidebar.menu-secondary.sidebar

View File

@ -28,10 +28,7 @@ block content
section.us-content.wysiwyg(tg-bind-html="task.description_html") section.us-content.wysiwyg(tg-bind-html="task.description_html")
- var attachModel = "task" tg-attachments(ng-model="task", type="task")
- var permissionSuffix = "task"
include views/modules/attachments
tg-history(ng-model="task", type="task") tg-history(ng-model="task", type="task")
sidebar.menu-secondary.sidebar sidebar.menu-secondary.sidebar

View File

@ -28,10 +28,7 @@ block content
section.us-content section.us-content
textarea(placeholder="Write a description of your user story", ng-model="us.description", tg-markitup) textarea(placeholder="Write a description of your user story", ng-model="us.description", tg-markitup)
- var attachModel = "us" tg-attachments(ng-model="us", type="us")
- var permissionSuffix = "us"
include views/modules/attachments
tg-history(ng-model="us", type="us", mode="edit") tg-history(ng-model="us", type="us", mode="edit")
sidebar.menu-secondary.sidebar sidebar.menu-secondary.sidebar

View File

@ -32,10 +32,7 @@ block content
include views/modules/related-tasks include views/modules/related-tasks
- var attachModel = "us" tg-attachments(ng-model="us", type="us")
- var permissionSuffix = "us"
include views/modules/attachments
tg-history(ng-model="us", type="us") tg-history(ng-model="us", type="us")
sidebar.menu-secondary.sidebar sidebar.menu-secondary.sidebar

View File

@ -1,31 +0,0 @@
//- NOTE: You must to define 'var attachModel' 'var permissionSuffix' with the object model
//- that have attachments
section.attachments(tg-attachments, ng-model=attachModel, ng-if="#{attachModel}.id")
div.attachments-header
h3.attachments-title
span.icon.icon-attachments
span.attachments-num 0
span.attachments-text attachments
div.button.button-gray.add-attach(tg-check-permission="modify_"+permissionSuffix, title="Add new attachment")
span +new file
input.add-attach(type="file", multiple="multiple")
div.attachment-body.sortable
div.hidden.single-attachment(ng-repeat="attach in attachments",
tg-attachment="attach", permission-suffix=permissionSuffix)
//- See modules/common/attachments.coffee - AttachmentDirective
div.single-attachment(ng-repeat="file in uploadingFiles")
div.attachment-name
a(href="", tg-bo-title="file.name", tg-bo-bind="file.name")
div.attachment-size
span.attachment-size(tg-bo-bind="file.size")
div.attachment-comments
span(ng-bind="file.progressMessage")
div.percentage(ng-style="{'width': file.progressPercent}")
a.hidden.more-attachments(href="", title="show deprecated atachments")
span.text + show deprecated atachments
span.more-attachments-num (0 deprecated)

View File

@ -21,6 +21,4 @@ block content
section.wysiwyg section.wysiwyg
textarea(placeholder="Write a your wiki page", ng-model="wiki.content", tg-markitup) textarea(placeholder="Write a your wiki page", ng-model="wiki.content", tg-markitup)
- var attachModel = "wiki" tg-attachments(ng-model="wiki", type="wiki_page")
- var permissionSuffix = "wiki_page"
include views/modules/attachments

View File

@ -25,6 +25,4 @@ block content
section.wiki-content.wysiwyg(tg-bind-html="wiki.html") section.wiki-content.wysiwyg(tg-bind-html="wiki.html")
- var attachModel = "wiki" tg-attachments(ng-model="wiki", type="wiki_page")
- var permissionSuffix = "wiki_page"
include views/modules/attachments

View File

@ -159,16 +159,19 @@
} }
.add-attach { .add-attach {
overflow: hidden;
position: relative; position: relative;
cursor: pointer;
input { input {
cursor: pointer; cursor: pointer;
height: 100%; font-size: 99px;
height: 120%;
left: 0; left: 0;
opacity: 0; opacity: 0;
position: absolute; position: absolute;
top: 0; top: -5px;
width: 100%; width: 100%;
z-index: 9999; z-index: 9999;
} }
} }