### # Copyright (C) 2014 Andrey Antukh # Copyright (C) 2014 Jesús Espino Garcia # Copyright (C) 2014 David Barragán Merino # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as # published by the Free Software Foundation, either version 3 of the # License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . # # File: modules/common/attachments.coffee ### taiga = @.taiga sizeFormat = @.taiga.sizeFormat module = angular.module("taigaCommon") ############################################################################# ## Attachments Directive ############################################################################# AttachmentsDirective = ($repo, $rs, $confirm) -> link = ($scope, $el, $attrs, $model) -> $ctrl = $el.controller() $scope.uploadingFiles = [] ########### ## Drag & drop ########### tdom = $el.find("div.attachment-body.sortable") tdom.sortable({ items: "div.single-attachment" handle: "a.settings.icon.icon-drag-v" dropOnEmpty: true revert: 400 axis: "y" placeholder: "sortable-placeholder single-attachment" }) tdom.on "sortstop", (event, ui) -> attachment = ui.item.scope().attach newIndex = ui.item.index() index = $scope.attachments.indexOf(attachment) return if index == newIndex # Move attachment to newIndex and recalculate order $scope.attachments.splice(index, 1) $scope.attachments.splice(newIndex, 0, attachment) _.forEach $scope.attachments, (attach, idx) -> attach.order = idx+1 # Save or revert changes $repo.saveAll($scope.attachments).then null, -> _.forEach $scope.attachments, attach -> attach.revert() _.sorBy($scope.attachments, 'order') ########### ## Total attachments counter ########### $scope.$watch "attachmentsCount", (count) -> $el.find("span.attachments-num").html(count) ########### ## Show/Hide deprecated attachments ########### $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() target = angular.element(event.currentTarget) $scope.showDeprecatedAttachments = not $scope.showDeprecatedAttachments if $scope.showDeprecatedAttachments target.find("span.text").html("- hide deprecated attachments") # TODO: i18n .prop("title", "hide deprecated attachments") # TODO: i18n $el.find("div.single-attachment.deprecated").removeClass("hidden") else target.find("span.text").html("+ show deprecated attachments") # TODO: i18n .prop("title", "show deprecated attachments") # TODO: i18n $el.find("div.single-attachment.deprecated").addClass("hidden") ########### ## Add Attachments ########### $el.on "click", "a.add-attach", -> event.preventDefault() angular.element("input.add-attach").trigger("click") $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", -> $el.off() return { link: link, require: "ngModel" } module.directive("tgAttachments", ["$tgRepo", "$tgResources", "$tgConfirm", AttachmentsDirective]) ############################################################################# ## Attachment Directive ############################################################################# AttachmentDirective = ($log, $repo, $confirm) -> singleAttachment = _.template("""
<%- size %>
<% if (isDeprecated){ %> (deprecated) <% } %> <%- description %>
<% if (modifyPermission) {%>
<% } %> """) #TODO: i18n singleAttachmentEditable = _.template("""
<%- size %>
checked<% } %> />
""") # TODO: i18n link = ($scope, $el, $attrs) -> $ctrl = $el.controller() render = (attachment, isEditable=false) -> modifyPermission = $scope.project.my_permissions.indexOf("modify_#{$attrs.permissionSuffix}") > -1 ctx = { id: attachment.id name: attachment.name url: attachment.url size: sizeFormat(attachment.size) description: attachment.description isDeprecated: attachment.is_deprecated modifyPermission: modifyPermission } if isEditable html = singleAttachmentEditable(ctx) else html = singleAttachment(ctx) $el.html(html) if attachment.is_deprecated $el.addClass("deprecated") if $scope.showDeprecatedAttachments $el.removeClass("hidden") else $el.addClass("hidden") else $el.removeClass("deprecated") $el.removeClass("hidden") ########### ## Initialize ########### if not $attrs.tgAttachment? return $log.error "AttachmentDirective the directive need an attachment" attachment = $scope.$eval($attrs.tgAttachment) render(attachment, attachment.isCreatedRightNow) delete attachment.isCreatedRightNow ########### ## Actions (on view mode) ########### $el.on "click", "a.settings.icon-edit", (event) -> event.preventDefault() render(attachment, true) $el.on "click", "a.settings.icon-delete", (event) -> event.preventDefault() 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", -> $el.off() return {link: link} module.directive("tgAttachment", ["$log", "$tgRepo", "$tgConfirm", AttachmentDirective])