From 335593fc2d9c799d6ae753159b677f73f5c1144a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Garc=C3=ADa?= Date: Tue, 23 Oct 2018 13:48:10 +0200 Subject: [PATCH] Added custom fields dropdown, checkbox and number --- .../modules/admin/project-values.coffee | 244 +++++++++++++----- .../modules/common/custom-field-values.coffee | 38 ++- app/locales/taiga/locale-en.json | 5 +- .../custom-attribute-value-edit.jade | 18 ++ .../custom-attribute-value.jade | 7 + .../admin/admin-custom-attributes-extra.jade | 33 +++ .../admin-custom-attributes-new-extra.jade | 29 +++ .../admin/admin-custom-attributes.jade | 171 +++++++----- .../admin/admin-custom-attributes.scss | 48 +++- 9 files changed, 449 insertions(+), 144 deletions(-) create mode 100644 app/partials/includes/modules/admin/admin-custom-attributes-extra.jade create mode 100644 app/partials/includes/modules/admin/admin-custom-attributes-new-extra.jade diff --git a/app/coffee/modules/admin/project-values.coffee b/app/coffee/modules/admin/project-values.coffee index ba4d2275..12b0db43 100644 --- a/app/coffee/modules/admin/project-values.coffee +++ b/app/coffee/modules/admin/project-values.coffee @@ -544,6 +544,9 @@ MULTILINE_TYPE = "multiline" RICHTEXT_TYPE = "richtext" DATE_TYPE = "date" URL_TYPE = "url" +DROPDOWN_TYPE = "dropdown" +CHECKBOX_TYPE = "checkbox" +NUMBER_TYPE = "number" TYPE_CHOICES = [ @@ -566,6 +569,18 @@ TYPE_CHOICES = [ { key: URL_TYPE, name: "ADMIN.CUSTOM_FIELDS.FIELD_TYPE_URL" + }, + { + key: DROPDOWN_TYPE, + name: "ADMIN.CUSTOM_FIELDS.FIELD_TYPE_DROPDOWN" + }, + { + key: CHECKBOX_TYPE, + name: "ADMIN.CUSTOM_FIELDS.FIELD_TYPE_CHECKBOX" + }, + { + key: NUMBER_TYPE, + name: "ADMIN.CUSTOM_FIELDS.FIELD_TYPE_NUMBER" } ] @@ -605,11 +620,19 @@ class ProjectCustomAttributesController extends mixOf(taiga.Controller, taiga.Pa ######################### # Custom Attribute ######################### + _parseAttributesExtra: () -> + @scope.customAttributes = _.map(@scope.customAttributes, (x) => @._parseAttributeExtra(x)) + + _parseAttributeExtra: (attr) -> + if (attr.type == 'dropdown' && !attr.extra) + attr.extra = [''] + return attr loadCustomAttributes: => return @rs.customAttributes[@scope.type].list(@scope.projectId).then (customAttributes) => @scope.customAttributes = customAttributes @scope.maxOrder = _.maxBy(customAttributes, "order")?.order + @._parseAttributesExtra() return customAttributes createCustomAttribute: (attrValues) => @@ -647,23 +670,63 @@ ProjectCustomAttributesDirective = ($log, $confirm, animationFrame, $translate) $scope.$on "$destroy", -> $el.off() + $scope.isExtraVisible = {} + + _manageFormEvent = (event, callback) -> + event.preventDefault() + formEl = angular.element(event.currentTarget).closest("form") + callback(formEl) + ################################## # Drag & Drop ################################## - sortableEl = $el.find(".js-sortable") - drake = dragula([sortableEl[0]], { - direction: 'vertical', - copySortSource: false, - copy: false, - mirrorContainer: sortableEl[0], - moves: (item) -> return $(item).is('div[tg-bind-scope]') - }) - drake.on 'dragend', (item) -> - itemEl = $(item) - itemAttr = itemEl.scope().attr - itemIndex = itemEl.index() - $ctrl.moveCustomAttributes(itemAttr, itemIndex) + initDraggable = -> + sortableEl = $el.find(".js-sortable") + drake = dragula([sortableEl[0]], { + direction: 'vertical', + copySortSource: false, + copy: false, + mirrorContainer: sortableEl[0], + moves: (item, source, handle) -> + childItem = $(handle).closest('.js-child-sortable') + if childItem[0] + return false + return $(item).is('div[tg-bind-scope]') + }) + + drake.on 'dragend', (item) -> + itemEl = $(item) + itemAttr = itemEl.scope().attr + itemIndex = itemEl.index() + $ctrl.moveCustomAttributes(itemAttr, itemIndex) + + sortableChildren = $el.find(".js-child-sortable") + for el in sortableChildren + drake[el] = dragula([el], { + direction: 'vertical', + copySortSource: false, + copy: false, + mirrorContainer: el, + moves: (item) -> return $(item).is('div[tg-bind-scope]') + }) + + drake[el].on 'dragend', (item) -> + itemEl = $(item) + attrExtra = itemEl.scope().attr.extra + + sourceIndex = itemEl.scope().$index + targetIndex = itemEl.index() + + value = attrExtra[sourceIndex] + + attrExtra.splice(sourceIndex, 1) + attrExtra.splice(targetIndex, 0, value) + + itemEl.scope().attr.setAttr('extra', attrExtra) + $ctrl.saveCustomAttribute(itemEl.scope().attr).then -> + $confirm.notify("success") + ################################## # New custom attribute @@ -695,13 +758,13 @@ ProjectCustomAttributesDirective = ($log, $confirm, animationFrame, $translate) form = formEl.checksley() return if not form.validate() - onSucces = => + onSucces = -> $ctrl.loadCustomAttributes() hideCreateForm() resetNewAttr() $confirm.notify("success") - onError = (data) => + onError = (data) -> form.setErrors(data) attr = $scope.newAttr @@ -714,6 +777,22 @@ ProjectCustomAttributesDirective = ($log, $confirm, animationFrame, $translate) hideCreateForm() resetNewAttr() + initAttrType = (formEl) -> + attr = if formEl.scope().newAttr then formEl.scope().newAttr else formEl.scope().attr + + if attr.type isnt "dropdown" + return + + if attr.extra?.length + return + + attr.extra = [''] + if attr.id + showEditForm(formEl) + else + showExtra(-1) + formEl.scope().$apply() + $scope.$watch "customAttributes", (customAttributes) -> return if not customAttributes @@ -725,17 +804,16 @@ ProjectCustomAttributesDirective = ($log, $confirm, animationFrame, $translate) hideCreateForm() showAddButton() showCancelButton() + initDraggable() + + $el.on "change", ".custom-field-type select", (event) -> + _manageFormEvent(event, initAttrType) $el.on "click", ".js-add-custom-field-button", (event) -> - event.preventDefault() - showCreateForm() + _manageFormEvent(event, showCreateForm) $el.on "click", ".js-create-custom-field-button", debounce 2000, (event) -> - event.preventDefault() - target = angular.element(event.currentTarget) - formEl = target.closest("form") - - create(formEl) + _manageFormEvent(event, create) $el.on "click", ".js-cancel-new-custom-field-button", (event) -> event.preventDefault() @@ -743,9 +821,7 @@ ProjectCustomAttributesDirective = ($log, $confirm, animationFrame, $translate) $el.on "keyup", ".js-new-custom-field input", (event) -> if event.keyCode == 13 # Enter - target = angular.element(event.currentTarget) - formEl = target.closest("form") - create(formEl) + _manageFormEvent(event, create) else if event.keyCode == 27 # Esc cancelCreate() @@ -757,64 +833,56 @@ ProjectCustomAttributesDirective = ($log, $confirm, animationFrame, $translate) formEl.find(".js-view-custom-field").addClass("hidden") formEl.find(".js-edit-custom-field").removeClass("hidden") formEl.find(".js-edit-custom-field input:visible").first().focus().select() - - hideEditForm = (formEl) -> - formEl.find(".js-edit-custom-field").addClass("hidden") - formEl.find(".js-view-custom-field").removeClass("hidden") - - revertChangesInCustomAttribute = (formEl) -> - $scope.$apply -> - formEl.scope().attr.revert() + formEl.find(".js-view-custom-field-extra").addClass("hidden") + formEl.find(".js-edit-custom-field-extra").removeClass("hidden") + formEl.find(".custom-extra-actions").removeClass("hidden") + showExtra(formEl.scope().attr.id) + $scope.$apply() update = (formEl) -> form = formEl.checksley() return if not form.validate() - - onSucces = => + onSucces = -> $ctrl.loadCustomAttributes() hideEditForm(formEl) $confirm.notify("success") - onError = (data) => + onError = (data) -> form.setErrors(data) attr = formEl.scope().attr + attr.setAttr('extra', attr.extra) $ctrl.saveCustomAttribute(attr).then(onSucces, onError) cancelUpdate = (formEl) -> hideEditForm(formEl) revertChangesInCustomAttribute(formEl) + hideEditForm = (formEl) -> + formEl.find(".js-edit-custom-field").addClass("hidden") + formEl.find(".js-view-custom-field").removeClass("hidden") + formEl.find(".js-edit-custom-field-extra").addClass("hidden") + formEl.find(".js-view-custom-field-extra").removeClass("hidden") + formEl.find(".custom-extra-actions").addClass("hidden") + + revertChangesInCustomAttribute = (formEl) -> + $scope.$apply -> + formEl.scope().attr.revert() + $el.on "click", ".js-edit-custom-field-button", (event) -> - event.preventDefault() - target = angular.element(event.currentTarget) - formEl = target.closest("form") + _manageFormEvent(event, showEditForm) - showEditForm(formEl) - - $el.on "click", ".js-update-custom-field-button", debounce 2000, (event) -> - event.preventDefault() - target = angular.element(event.currentTarget) - formEl = target.closest("form") - - update(formEl) + $el.on "click", ".js-update-custom-field-button", debounce 1000, (event) -> + _manageFormEvent(event, update) $el.on "click", ".js-cancel-edit-custom-field-button", (event) -> - event.preventDefault() - target = angular.element(event.currentTarget) - formEl = target.closest("form") - - cancelUpdate(formEl) + _manageFormEvent(event, cancelUpdate) $el.on "keyup", ".js-edit-custom-field input", (event) -> if event.keyCode == 13 # Enter - target = angular.element(event.currentTarget) - formEl = target.closest("form") - update(formEl) + _manageFormEvent(event, update) else if event.keyCode == 27 # Esc - target = angular.element(event.currentTarget) - formEl = target.closest("form") - cancelUpdate(formEl) + _manageFormEvent(event, cancelUpdate) ################################## # Delete custom attribute @@ -837,16 +905,66 @@ ProjectCustomAttributesDirective = ($log, $confirm, animationFrame, $translate) $ctrl.deleteCustomAttribute(attr).then(onSucces, onError) $el.on "click", ".js-delete-custom-field-button", debounce 2000, (event) -> - event.preventDefault() - target = angular.element(event.currentTarget) - formEl = target.closest("form") + _manageFormEvent(event, deleteCustomAttribute) - deleteCustomAttribute(formEl) + ################################## + # Custom attribute extra + ################################## + + $scope.toggleExtraVisible = (index) -> + if not $scope.isExtraVisible[index] + showExtra(index) + else + hideExtra(index) + + showExtra = (index) -> + $scope.isExtraVisible[index] = true + + hideExtra = (index) -> + $scope.isExtraVisible[index] = false + + _manageExtraFormEvent = (event, callback) -> + event.preventDefault() + formEl = angular.element(event.currentTarget).closest("form") + formExtraEl = angular.element(event.currentTarget).closest(".js-form") + callback(formEl, formExtraEl) + + addExtraOption = (formEl, formExtraEl) -> + formScope = formEl.scope() + attrExtra = if formScope.newAttr then formScope.newAttr.extra else formScope.attr.extra + attrExtra.push("") + formScope.$apply() + + formEl.find(".js-edit-custom-field-extra").last().removeClass("hidden") + formEl.find(".js-view-custom-field-extra").last().addClass("hidden") + + removeExtraOption = (formEl, formExtraEl) -> + attrExtra = formEl.scope().attr.extra + attrExtra.splice(formExtraEl.scope().$index, 1) + formExtraEl.scope().$apply() + + $el.on "keyup", ".js-edit-custom-field-extra input", (event) -> + if event.keyCode == 13 # Enter + _manageFormEvent(event, update) + else if event.keyCode == 27 # Esc + _manageFormEvent(event, cancelUpdate) + + $el.on "keyup", ".js-new-custom-field-extra input", (event) -> + if event.keyCode == 13 # Enter + _manageFormEvent(event, create) + else if event.keyCode == 27 # Esc + cancelCreate() + + $el.on "click", ".js-add-option-custom-field-extra-button", debounce 500, (event) -> + _manageExtraFormEvent(event, addExtraOption) + + $el.on "click", ".js-delete-custom-field-extra-button", debounce 500, (event) -> + _manageExtraFormEvent(event, removeExtraOption) return {link: link} module.directive("tgProjectCustomAttributes", ["$log", "$tgConfirm", "animationFrame", "$translate", - ProjectCustomAttributesDirective]) +ProjectCustomAttributesDirective]) ############################################################################# diff --git a/app/coffee/modules/common/custom-field-values.coffee b/app/coffee/modules/common/custom-field-values.coffee index 9593f42f..c0c48bd8 100644 --- a/app/coffee/modules/common/custom-field-values.coffee +++ b/app/coffee/modules/common/custom-field-values.coffee @@ -31,6 +31,9 @@ RICHTEXT_TYPE = "url" MULTILINE_TYPE = "multiline" DATE_TYPE = "date" URL_TYPE = "url" +DROPDOWN_TYPE = "dropdown" +CHECKBOX_TYPE = "checkbox" +NUMBER_TYPE = "number" TYPE_CHOICES = [ @@ -53,6 +56,18 @@ TYPE_CHOICES = [ { key: RICHTEXT_TYPE, name: "ADMIN.CUSTOM_FIELDS.FIELD_TYPE_RICHTEXT" + }, + { + key: DROPDOWN_TYPE, + name: "ADMIN.CUSTOM_FIELDS.FIELD_TYPE_DROPDOWN" + }, + { + key: CHECKBOX_TYPE, + name: "ADMIN.CUSTOM_FIELDS.FIELD_TYPE_CHECKBOX" + }, + { + key: NUMBER_TYPE, + name: "ADMIN.CUSTOM_FIELDS.FIELD_TYPE_NUMBER" } ] @@ -155,8 +170,11 @@ CustomAttributeValueDirective = ($template, $selectedText, $compile, $translate, render = (attributeValue, edit=false) -> if attributeValue.type is DATE_TYPE and attributeValue.value value = moment(attributeValue.value, "YYYY-MM-DD").format(prettyDate) + if attributeValue.type is NUMBER_TYPE and attributeValue.value + value = parseFloat(attributeValue.value) else value = attributeValue.value + editable = isEditable() ctx = { @@ -164,12 +182,14 @@ CustomAttributeValueDirective = ($template, $selectedText, $compile, $translate, name: attributeValue.name description: attributeValue.description value: value - isEditable: editable type: attributeValue.type + isEditable: editable } scope = $scope.$new() scope.attributeHtml = wysiwygService.getHTML(value) + scope.extra = attributeValue.extra + scope.model = value if editable and (edit or not value) html = templateEdit(ctx) @@ -214,11 +234,19 @@ CustomAttributeValueDirective = ($template, $selectedText, $compile, $translate, form = $el.find("form").checksley() return if not form.validate() - input = $el.find("input[name=value], textarea[name='value']") - attributeValue.value = input.val() - if attributeValue.type is DATE_TYPE - if moment(attributeValue.value, prettyDate).isValid() + if attributeValue.type is DROPDOWN_TYPE + formControl = $el.find("select[name='value']") + attributeValue.value = formControl.val() + else if attributeValue.type is CHECKBOX_TYPE + formControl = $el.find("input[name=value]") + attributeValue.value = formControl[0].checked + else + formControl = $el.find("input[name=value], textarea[name='value']") + attributeValue.value = formControl.val() + if attributeValue.type is DATE_TYPE and moment(attributeValue.value, prettyDate).isValid() attributeValue.value = moment(attributeValue.value, prettyDate).format("YYYY-MM-DD") + if attributeValue.type is NUMBER_TYPE + attributeValue.value = parseFloat(attributeValue.value) $scope.$apply -> $ctrl.updateAttributeValue(attributeValue).then -> diff --git a/app/locales/taiga/locale-en.json b/app/locales/taiga/locale-en.json index be4f58dd..986b4d68 100644 --- a/app/locales/taiga/locale-en.json +++ b/app/locales/taiga/locale-en.json @@ -571,7 +571,10 @@ "FIELD_TYPE_RICHTEXT": "Rich text", "FIELD_TYPE_MULTI": "Multi-line", "FIELD_TYPE_DATE": "Date", - "FIELD_TYPE_URL": "Url" + "FIELD_TYPE_URL": "Url", + "FIELD_TYPE_DROPDOWN": "Dropdown", + "FIELD_TYPE_CHECKBOX": "Checkbox", + "FIELD_TYPE_NUMBER": "Number" }, "PROJECT_VALUES": { "PAGE_TITLE": "{{sectionName}} - Project values - {{projectName}}", diff --git a/app/partials/custom-attributes/custom-attribute-value-edit.jade b/app/partials/custom-attributes/custom-attribute-value-edit.jade index 3e2a1a60..ce11b449 100644 --- a/app/partials/custom-attributes/custom-attribute-value-edit.jade +++ b/app/partials/custom-attributes/custom-attribute-value-edit.jade @@ -19,6 +19,24 @@ form.custom-field-single.editable input#custom-field-value(name="value", type="text", data-pikaday, value!="<%- value %>") <% } else if (type=="url") { %> input#custom-field-value(name="value", type="url", value!="<%- value %>") + <% } else if (type=="dropdown") { %> + select#custom-field-value( + name="value" + ng-model="model" + ) + option(ng-repeat="option in extra", value="{{ option }}") {{ option }} + <% } else if (type=="number") { %> + input#custom-field-value(name="value", type="number", value!="<%- value %>") + <% } else if (type=="checkbox") { %> + div.check + input( + name="value" + type="checkbox", + ng-checked="model" + ) + div + span.check-text.check-yes(translate="COMMON.YES") + span.check-text.check-no(translate="COMMON.NO") <% } else { %> input#custom-field-value(name="value", type="text", value!="<%- value %>") <% } %> diff --git a/app/partials/custom-attributes/custom-attribute-value.jade b/app/partials/custom-attributes/custom-attribute-value.jade index 66dc21d4..634d3c50 100644 --- a/app/partials/custom-attributes/custom-attribute-value.jade +++ b/app/partials/custom-attributes/custom-attribute-value.jade @@ -15,6 +15,13 @@ <% } else if (type=="richtext") { %> .custom-field-value.js-value-view-mode.wysiwyg div(ng-bind-html="attributeHtml") + <% } else if (type=="checkbox") { %> + .custom-field-value.js-value-view-mode + <% if (value) { %> + span {{ 'COMMON.YES' | translate }} + <% } else { %> + span {{ 'COMMON.NO' | translate }} + <% } %> <% } else { %> .custom-field-value.js-value-view-mode span diff --git a/app/partials/includes/modules/admin/admin-custom-attributes-extra.jade b/app/partials/includes/modules/admin/admin-custom-attributes-extra.jade new file mode 100644 index 00000000..25ab7162 --- /dev/null +++ b/app/partials/includes/modules/admin/admin-custom-attributes-extra.jade @@ -0,0 +1,33 @@ +.js-child-sortable(data-id="{{ attr.id }}") + .js-form( + ng-repeat="option in attr.extra track by $index" + tg-bind-scope + ) + div.row.js-view-custom-field-extra + tg-svg.e2e-drag(svg-icon="icon-drag") + div.custom-extra-attr-wrapper + span {{ option }} + + div.row.js-edit-custom-field-extra.hidden + div.custom-extra-attr-wrapper + input( + type="text" + name="name" + ng-model="attr.extra[$index]" + data-required="true" + data-maxlength="64" + ) + .custom-options + .custom-options-wrapper + a.js-delete-custom-field-extra-button( + href="" + tabindex="-1" + title="{{'ADMIN.CUSTOM_ATTRIBUTES.DELETE' | translate}}" + ng-if="attr.extra.length > 1" + ) + tg-svg(svg-icon="icon-trash") + +div.custom-extra-actions.hidden + a.js-add-option-custom-field-extra-button(href="") + tg-svg(svg-icon="icon-add") + span Add option diff --git a/app/partials/includes/modules/admin/admin-custom-attributes-new-extra.jade b/app/partials/includes/modules/admin/admin-custom-attributes-new-extra.jade new file mode 100644 index 00000000..a5482f1f --- /dev/null +++ b/app/partials/includes/modules/admin/admin-custom-attributes-new-extra.jade @@ -0,0 +1,29 @@ + +.js-child-sortable(data-id="-1") + .js-form( + ng-repeat="option in newAttr.extra track by $index" + tg-bind-scope + ) + div.row.js-new-custom-field-extra + div.custom-extra-attr-wrapper + input( + type="text" + name="name" + ng-model="newAttr.extra[$index]" + data-required="true" + data-maxlength="64" + ) + .custom-options + .custom-options-wrapper + a.js-delete-custom-field-extra-button( + href="" + tabindex="-1" + title="{{'ADMIN.CUSTOM_ATTRIBUTES.DELETE' | translate}}" + ng-if="newAttr.extra.length > 1" + ) + tg-svg(svg-icon="icon-trash") + +div.custom-extra-actions + a.js-add-option-custom-field-extra-button(href="") + tg-svg(svg-icon="icon-add") + span Add option diff --git a/app/partials/includes/modules/admin/admin-custom-attributes.jade b/app/partials/includes/modules/admin/admin-custom-attributes.jade index b2e97952..eff698f5 100644 --- a/app/partials/includes/modules/admin/admin-custom-attributes.jade +++ b/app/partials/includes/modules/admin/admin-custom-attributes.jade @@ -23,7 +23,21 @@ section.custom-fields-table.basic-table form.js-form(tg-bind-scope) div.row.single-custom-field.js-view-custom-field tg-svg.e2e-drag(svg-icon="icon-drag") - div.custom-name {{ attr.name }} + div.custom-name + span {{ attr.name }} + a( + href="" + ng-click="toggleExtraVisible(attr.id)" + ng-if="attr.type == 'dropdown'" + ) + tg-svg( + ng-if="!isExtraVisible[attr.id]" + svg-icon="icon-arrow-right" + ) + tg-svg( + ng-if="isExtraVisible[attr.id]" + svg-icon="icon-arrow-down" + ) div.custom-description {{ attr.description }} div.custom-field-type(ng-switch on="attr.type") span( @@ -46,6 +60,18 @@ section.custom-fields-table.basic-table ng-switch-when="url" translate="ADMIN.CUSTOM_FIELDS.FIELD_TYPE_URL" ) + span( + ng-switch-when="dropdown" + translate="ADMIN.CUSTOM_FIELDS.FIELD_TYPE_DROPDOWN" + ) + span( + ng-switch-when="checkbox" + translate="ADMIN.CUSTOM_FIELDS.FIELD_TYPE_CHECKBOX" + ) + span( + ng-switch-when="number" + translate="ADMIN.CUSTOM_FIELDS.FIELD_TYPE_NUMBER" + ) .custom-options .custom-options-wrapper a.js-edit-custom-field-button( @@ -59,77 +85,84 @@ section.custom-fields-table.basic-table title="{{'ADMIN.CUSTOM_ATTRIBUTES.DELETE' | translate}}" ) tg-svg(svg-icon="icon-trash") - - 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" - ) - fieldset.custom-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.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( - href="", - title="{{'ADMIN.CUSTOM_ATTRIBUTES.ACTION_UPDATE' | translate}}" + .js-edit-custom-field.hidden + div.row.single-custom-field + 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" ) - tg-svg(svg-icon="icon-save") - - a.js-cancel-edit-custom-field-button( - href="", - title="{{'ADMIN.CUSTOM_ATTRIBUTES.ACTION_CANCEL_EDITION' | translate}}" + fieldset.custom-description + input( + type="text" + name="description" + placeholder="{{'ADMIN.CUSTOM_ATTRIBUTES.SET_FIELD_DESCRIPTION' | translate}}" + ng-model="attr.description" ) - tg-svg(svg-icon="icon-close") + fieldset.custom-field-type + 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( + href="", + title="{{'ADMIN.CUSTOM_ATTRIBUTES.ACTION_UPDATE' | translate}}" + ) + tg-svg(svg-icon="icon-save") - 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" - ) - fieldset.custom-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.type" - ng-options="type.key as type.name|translate for type in TYPE_CHOICES" - ) - option(value="", translate="ADMIN.CUSTOM_ATTRIBUTES.FIELD_TYPE_DEFAULT") + a.js-cancel-edit-custom-field-button( + href="", + title="{{'ADMIN.CUSTOM_ATTRIBUTES.ACTION_CANCEL_EDITION' | translate}}" + ) + tg-svg(svg-icon="icon-close") - fieldset.custom-options - div.custom-options-wrapper - a.js-create-custom-field-button( - href="", - title="{{'ADMIN.CUSTOM_ATTRIBUTES.SAVE_TITLE' | translate}}" + div.custom-field-extra(ng-show="attr.type == 'dropdown' && isExtraVisible[attr.id]") + include admin-custom-attributes-extra + + form(tg-bind-scope) + div.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" ) - tg-svg(svg-icon="icon-save") - - a.js-cancel-new-custom-field-button( - href="", - title="{{'ADMIN.CUSTOM_ATTRIBUTES.CANCEL_TITLE' | translate}}" + fieldset.custom-description + input( + type="text" + name="description" + placeholder="{{'ADMIN.CUSTOM_ATTRIBUTES.SET_FIELD_DESCRIPTION' | translate}}" + ng-model="newAttr.description" ) - tg-svg(svg-icon="icon-close") + fieldset.custom-field-type + select( + ng-model="newAttr.type" + ng-options="type.key as type.name|translate for type in TYPE_CHOICES" + ) + option(value="", translate="ADMIN.CUSTOM_ATTRIBUTES.FIELD_TYPE_DEFAULT") + + fieldset.custom-options + div.custom-options-wrapper + a.js-create-custom-field-button( + href="", + title="{{'ADMIN.CUSTOM_ATTRIBUTES.SAVE_TITLE' | translate}}" + ) + tg-svg(svg-icon="icon-save") + + a.js-cancel-new-custom-field-button( + href="", + title="{{'ADMIN.CUSTOM_ATTRIBUTES.CANCEL_TITLE' | translate}}" + ) + tg-svg(svg-icon="icon-close") + + div.custom-field-extra(ng-show="newAttr.type == 'dropdown' && isExtraVisible[-1]") + include admin-custom-attributes-new-extra \ No newline at end of file diff --git a/app/styles/modules/admin/admin-custom-attributes.scss b/app/styles/modules/admin/admin-custom-attributes.scss index 6d97314a..c0634399 100644 --- a/app/styles/modules/admin/admin-custom-attributes.scss +++ b/app/styles/modules/admin/admin-custom-attributes.scss @@ -7,7 +7,6 @@ margin-bottom: 2em; .row { border-bottom: 0; - padding: .5rem 0; } .table-header { @include font-type(bold); @@ -34,14 +33,17 @@ cursor: default; } } - .custom-description { - color: $gray-light; - } } .single-custom-field { border-bottom: 1px solid $whitish; color: $gray; } + .js-view-custom-field { + padding: .75rem 0; + .custom-extra-attr-wrapper { + margin-left: 1em; + } + } .icon-drag { fill: $gray-light; opacity: 0; @@ -55,6 +57,13 @@ .custom-name { flex-basis: 25%; flex-shrink: 0; + a { + padding: .5em; + } + svg { + height: 12px; + width: 12px; + } } .custom-description { @include ellipsis(100%); @@ -62,7 +71,7 @@ flex-grow: 8; } .custom-field-type { - flex-basis: 10%; + flex-basis: 12%; flex-grow: 0; flex-shrink: 0; } @@ -95,7 +104,34 @@ display: inline-block; } } - form { + .custom-field-extra { + align-items: center; + border-bottom: 1px solid $whitish; + color: $gray-light; + font-size: .95em; + padding: .25em 1.5em; + } + .js-view-custom-field-extra { + padding: .5em; + } + .js-edit-custom-field { + margin-left: .4rem; + } + .custom-extra-attr-wrapper { + flex-grow: 1; + } + .custom-extra-actions { + padding: .5em; + a { + color: $primary; + } + svg { + height: 10px; + margin-right: .25em; + width: 10px; + } + } + .js-form { .custom-options-wrapper { opacity: 1; }