diff --git a/app/coffee/modules/admin/project-values.coffee b/app/coffee/modules/admin/project-values.coffee index cd0e6d0d..25c9098a 100644 --- a/app/coffee/modules/admin/project-values.coffee +++ b/app/coffee/modules/admin/project-values.coffee @@ -374,6 +374,27 @@ module.directive("tgColorSelection", ColorSelectionDirective) ## Custom Attributes Controller ############################################################################# +# Custom attributes types (see taiga-back/taiga/projects/custom_attributes/choices.py) +TEXT_TYPE = "text" +MULTILINE_TYPE = "multiline" +DATE_TYPE = "date" + + +TYPE_CHOICES = [ + { + key: TEXT_TYPE, + name: "ADMIN.CUSTOM_FIELDS.FIELD_TYPE_TEXT" + }, + { + key: MULTILINE_TYPE, + name: "ADMIN.CUSTOM_FIELDS.FIELD_TYPE_MULTI" + }, + { + key: DATE_TYPE, + name: "ADMIN.CUSTOM_FIELDS.FIELD_TYPE_DATE" + } +] + class ProjectCustomAttributesController extends mixOf(taiga.Controller, taiga.PageMixin) @.$inject = [ "$scope", @@ -390,6 +411,8 @@ class ProjectCustomAttributesController extends mixOf(taiga.Controller, taiga.Pa constructor: (@scope, @rootscope, @repo, @rs, @params, @q, @location, @navUrls, @appMetaService, @translate) -> + @scope.TYPE_CHOICES = TYPE_CHOICES + @scope.project = {} @rootscope.$on "project:loaded", => diff --git a/app/coffee/modules/common/custom-field-values.coffee b/app/coffee/modules/common/custom-field-values.coffee index 477ab050..1d8e1efe 100644 --- a/app/coffee/modules/common/custom-field-values.coffee +++ b/app/coffee/modules/common/custom-field-values.coffee @@ -27,6 +27,28 @@ generateHash = taiga.generateHash module = angular.module("taigaCommon") +# Custom attributes types (see taiga-back/taiga/projects/custom_attributes/choices.py) +TEXT_TYPE = "text" +MULTILINE_TYPE = "multiline" +DATE_TYPE = "date" + + +TYPE_CHOICES = [ + { + key: TEXT_TYPE, + name: "ADMIN.CUSTOM_FIELDS.FIELD_TYPE_TEXT" + }, + { + key: MULTILINE_TYPE, + name: "ADMIN.CUSTOM_FIELDS.FIELD_TYPE_MULTI" + }, + { + key: DATE_TYPE, + name: "ADMIN.CUSTOM_FIELDS.FIELD_TYPE_DATE" + } +] + + class CustomAttributesValuesController extends taiga.Controller @.$inject = ["$scope", "$rootScope", "$tgRepo", "$tgResources", "$tgConfirm", "$q"] @@ -118,7 +140,8 @@ CustomAttributesValuesDirective = ($templates, $storage) -> template: templateFn } -module.directive("tgCustomAttributesValues", ["$tgTemplate", "$tgStorage", "$translate", CustomAttributesValuesDirective]) +module.directive("tgCustomAttributesValues", ["$tgTemplate", "$tgStorage", "$translate", + CustomAttributesValuesDirective]) CustomAttributeValueDirective = ($template, $selectedText, $compile, $translate, datePickerConfigService) -> @@ -130,7 +153,6 @@ CustomAttributeValueDirective = ($template, $selectedText, $compile, $translate, render = (attributeValue, edit=false) -> value = attributeValue.value - innerText = attributeValue.value editable = isEditable() ctx = { id: attributeValue.id @@ -138,7 +160,7 @@ CustomAttributeValueDirective = ($template, $selectedText, $compile, $translate, description: attributeValue.description value: value isEditable: editable - field_type: attributeValue.field_type + type: attributeValue.type } if editable and (edit or not value) @@ -150,18 +172,17 @@ CustomAttributeValueDirective = ($template, $selectedText, $compile, $translate, $el.html(html) - if attributeValue.field_type == "DATE" + if attributeValue.type == DATE_TYPE datePickerConfig = datePickerConfigService.get() _.merge(datePickerConfig, { - field: $el.find('input')[0] + field: $el.find("input[name=value]")[0] onSelect: (date) => selectedDate = date onOpen: => $el.picker.setDate(selectedDate) if selectedDate? }) - selectedDate = null $el.picker = new Pikaday(datePickerConfig) isEditable = -> @@ -170,28 +191,32 @@ CustomAttributeValueDirective = ($template, $selectedText, $compile, $translate, return permissions.indexOf(requiredEditionPerm) > -1 saveAttributeValue = -> - attributeValue.value = $el.find("input, textarea").val() - - if attributeValue.field_type == "DATE" - if attributeValue.value - return if moment(attributeValue.value).isValid() != true + attributeValue.value = $el.find("input[name=value], textarea[name='value']").val() + if attributeValue.type is DATE_TYPE + if moment(attributeValue.value, prettyDate).isValid() attributeValue.value = moment(attributeValue.value, prettyDate).format("YYYY-MM-DD") + else + attributeValue.reset() + return $scope.$apply -> $ctrl.updateAttributeValue(attributeValue).then -> - if attributeValue.field_type == "DATE" and attributeValue.value + if attributeValue.type is "DATE_TYPE" and attributeValue.value attributeValue.value = moment(attributeValue.value, "YYYY-MM-DD").format(prettyDate) render(attributeValue, false) - $el.on "keyup", "input[name=description], textarea[name='description']", (event) -> - if event.keyCode == 13 and event.currentTarget.type != "textarea" - submit(event) - else if event.keyCode == 27 - return if attributeValue.field_type == "DATE" and moment(attributeValue.value).isValid() != true + submit = debounce 2000, (event) => + event.preventDefault() + saveAttributeValue() - render(attributeValue, false) + # Bootstrap + attributeValue = $scope.$eval($attrs.tgCustomAttributeValue) + if attributeValue.type is DATE_TYPE and attributeValue.value + attributeValue.value = moment(attributeValue.value, "YYYY-MM-DD").format(prettyDate) + + render(attributeValue) ## Actions (on view mode) $el.on "click", ".custom-field-value.read-mode", -> @@ -206,28 +231,24 @@ CustomAttributeValueDirective = ($template, $selectedText, $compile, $translate, $el.find("input[name='description'], textarea[name='description']").focus().select() ## Actions (on edit mode) - submit = debounce 2000, (event) => - event.preventDefault() - saveAttributeValue() + $el.on "keyup", "input[name=value], textarea[name='value']", (event) -> + if event.keyCode is 13 and event.currentTarget.type isnt "textarea" + submit(event) + else if event.keyCode == 27 + render(attributeValue, false) $el.on "submit", "form", submit + $el.on "click", "a.icon-floppy", submit $scope.$on "$destroy", -> $el.off() - # Bootstrap - attributeValue = $scope.$eval($attrs.tgCustomAttributeValue) - - if attributeValue.field_type == "DATE" and attributeValue.value - attributeValue.value = moment(attributeValue.value, "YYYY-MM-DD").format(prettyDate) - - render(attributeValue) - return { link: link require: "^tgCustomAttributesValues" restrict: "AE" } -module.directive("tgCustomAttributeValue", ["$tgTemplate", "$selectedText", "$compile", "$translate", "tgDatePickerConfigService", CustomAttributeValueDirective]) +module.directive("tgCustomAttributeValue", ["$tgTemplate", "$selectedText", "$compile", "$translate", + "tgDatePickerConfigService", CustomAttributeValueDirective]) diff --git a/app/partials/custom-attributes/custom-attribute-value-edit.jade b/app/partials/custom-attributes/custom-attribute-value-edit.jade index 5ac1edbd..f6869cba 100644 --- a/app/partials/custom-attributes/custom-attribute-value-edit.jade +++ b/app/partials/custom-attributes/custom-attribute-value-edit.jade @@ -1,6 +1,6 @@ form.custom-field-single.editable div.custom-field-data - label.custom-field-name(for="custom-field-description") + label.custom-field-name(for="custom-field-value") <%- name %> <% if (description){ %> span.custom-field-description @@ -8,22 +8,15 @@ form.custom-field-single.editable <% } %> div.custom-field-value - - <% if (field_type=="MULTI") { %> - textarea#custom-field-description(name="description") - <%- value %> - <% } %> - - <% if (field_type=="TEXT") { %> - input#custom-field-description(name="description", type="text", value!="<%- value %>") - <% } %> - - <% if (field_type=="DATE" && value!="") { %> - input#custom-field-description(name="description", type="text", value!="<%- moment(value).format('DD MMM YYYY') %>") - <% } %> - - <% if (field_type=="DATE" && value=="") { %> - input#custom-field-description(name="description", type="text", value!="") + //- See TYPE_CHOICES in app/coffee/modules/common/custom-field-values.coffee + <% if (type=="text") { %> + input#custom-field-value(name="value", type="text", value!="<%- value %>") + <% } else if (type=="multiline") { %> + textarea#custom-field-value(name="value") <%- value %> + <% } else if (type=="date") { %> + input#custom-field-value(name="value", type="text", value!="<%- value %>") + <% } else { %> + input#custom-field-value(name="value", type="text", value!="<%- value %>") <% } %> div.custom-field-options diff --git a/app/partials/includes/modules/admin/admin-custom-attributes.jade b/app/partials/includes/modules/admin/admin-custom-attributes.jade index b26cf9f8..8d2ef76f 100644 --- a/app/partials/includes/modules/admin/admin-custom-attributes.jade +++ b/app/partials/includes/modules/admin/admin-custom-attributes.jade @@ -1,7 +1,10 @@ section.custom-fields-table.basic-table div.project-values-title h2 {{ customFieldSectionTitle | translate }} - a.button.button-gray.show-add-new.js-add-custom-field-button(href="", title="{{ customFieldButtonTitle | translate }}") + a.button.button-gray.show-add-new.js-add-custom-field-button( + href="" + title="{{ customFieldButtonTitle | translate }}" + ) span(translate="ADMIN.CUSTOM_ATTRIBUTES.ADD") div.table-header @@ -24,40 +27,84 @@ section.custom-fields-table.basic-table span {{ attr.name }} div.custom-description span {{ attr.description }} - div.custom-field-type - span(translate="ADMIN.CUSTOM_FIELDS.FIELD_TYPE_{{ attr.field_type }}") + div.custom-field-type(ng-switch on="attr.type") + //- See TYPE_CHOICES in app/coffee/modules/admin/project-values.coffee + span(ng-switch-default, translate="ADMIN.CUSTOM_FIELDS.FIELD_TYPE_TEXT") + span(ng-switch-when="multiline", translate="ADMIN.CUSTOM_FIELDS.FIELD_TYPE_MULTI") + span(ng-switch-when="date", translate="ADMIN.CUSTOM_FIELDS.FIELD_TYPE_DATE") div.custom-options div.custom-options-wrapper - a.js-edit-custom-field-button.icon.icon-edit(href="", title="{{'ADMIN.CUSTOM_ATTRIBUTES.EDIT' | translate}}") - a.js-delete-custom-field-button.icon.icon-delete(href="", title="{{'ADMIN.CUSTOM_ATTRIBUTES.DELETE' | translate}}") + a.js-edit-custom-field-button.icon.icon-edit( + href="" + title="{{'ADMIN.CUSTOM_ATTRIBUTES.EDIT' | translate}}" + ) + a.js-delete-custom-field-button.icon.icon-delete( + href="" + title="{{'ADMIN.CUSTOM_ATTRIBUTES.DELETE' | translate}}" + ) div.row.single-custom-field.js-edit-custom-field.hidden fieldset.custom-name - input(type="text", name="name", placeholder="{{'ADMIN.CUSTOM_ATTRIBUTES.SET_FIELD_NAME' | translate}}", - ng-model="attr.name", data-required="true" data-maxlength="64") + input( + type="text" + name="name" + placeholder="{{'ADMIN.CUSTOM_ATTRIBUTES.SET_FIELD_NAME' | translate}}" + ng-model="attr.name" + data-required="true" + data-maxlength="64" + ) fieldset.custom-description - input(type="text", name="description", placeholder="{{'ADMIN.CUSTOM_ATTRIBUTES.SET_FIELD_DESCRIPTION' | translate}}", - ng-model="attr.description") + input( + type="text" + name="description" + placeholder="{{'ADMIN.CUSTOM_ATTRIBUTES.SET_FIELD_DESCRIPTION' | translate}}" + ng-model="attr.description" + ) fieldset.custom-field-type - select(ng-model="attr.field_type", - ng-options="e.id as e.name | translate for e in [{'id':'TEXT', 'name': 'ADMIN.CUSTOM_FIELDS.FIELD_TYPE_TEXT'},{'id':'MULTI', 'name': 'ADMIN.CUSTOM_FIELDS.FIELD_TYPE_MULTI'},{'id':'DATE', 'name': 'ADMIN.CUSTOM_FIELDS.FIELD_TYPE_DATE'}]") + select( + ng-model="attr.type" + ng-options="type.key as type.name | translate for type in TYPE_CHOICES" + ) fieldset.custom-options div.custom-options-wrapper - a.js-update-custom-field-button.icon.icon-floppy(href="", title="{{'ADMIN.CUSTOM_ATTRIBUTES.ACTION_UPDATE' | translate}}") - a.js-cancel-edit-custom-field-button.icon.icon-delete(href="", title="{{'ADMIN.CUSTOM_ATTRIBUTES.ACTION_CANCEL_EDITION' | translate}}") + a.js-update-custom-field-button.icon.icon-floppy( + href="" + title="{{'ADMIN.CUSTOM_ATTRIBUTES.ACTION_UPDATE' | translate}}" + ) + a.js-cancel-edit-custom-field-button.icon.icon-delete( + href="" + title="{{'ADMIN.CUSTOM_ATTRIBUTES.ACTION_CANCEL_EDITION' | translate}}" + ) form.row.single-custom-field.js-new-custom-field.hidden fieldset.custom-name - input(type="text", name="name", placeholder="{{'ADMIN.CUSTOM_ATTRIBUTES.SET_FIELD_NAME' | translate}}", - ng-model="newAttr.name", data-required="true", data-maxlength="64") + input( + type="text" + name="name" + placeholder="{{'ADMIN.CUSTOM_ATTRIBUTES.SET_FIELD_NAME' | translate}}" + ng-model="newAttr.name" + data-required="true" + data-maxlength="64" + ) fieldset.custom-description - input(type="text", name="description", placeholder="{{'ADMIN.CUSTOM_ATTRIBUTES.SET_FIELD_DESCRIPTION' | translate}}", - ng-model="newAttr.description") + input( + type="text" + name="description" + placeholder="{{'ADMIN.CUSTOM_ATTRIBUTES.SET_FIELD_DESCRIPTION' | translate}}" + ng-model="newAttr.description" + ) fieldset.custom-field-type - select(ng-model="newAttr.field_type", - ng-options="e.id as e.name | translate for e in [{'id':'TEXT', 'name': 'ADMIN.CUSTOM_FIELDS.FIELD_TYPE_TEXT'},{'id':'MULTI', 'name': 'ADMIN.CUSTOM_FIELDS.FIELD_TYPE_MULTI'},{'id':'DATE', 'name': 'ADMIN.CUSTOM_FIELDS.FIELD_TYPE_DATE'}]") - + select( + ng-model="newAttr.type" + ng-options="type.key as type.name for type in TYPE_CHOICES" + ) fieldset.custom-options div.custom-options-wrapper - a.js-create-custom-field-button.icon.icon-floppy(href="", title="{{'ADMIN.CUSTOM_ATTRIBUTES.SAVE_TITLE' | translate}}") - a.js-cancel-new-custom-field-button.icon.icon-delete(href="", title="{{'ADMIN.CUSTOM_ATTRIBUTES.CANCEL_TITLE' | translate}}") + a.js-create-custom-field-button.icon.icon-floppy( + href="" + title="{{'ADMIN.CUSTOM_ATTRIBUTES.SAVE_TITLE' | translate}}" + ) + a.js-cancel-new-custom-field-button.icon.icon-delete( + href="" + title="{{'ADMIN.CUSTOM_ATTRIBUTES.CANCEL_TITLE' | translate}}" + )