Added custom fields dropdown, checkbox and number
parent
09fd3a9d72
commit
335593fc2d
|
@ -544,6 +544,9 @@ MULTILINE_TYPE = "multiline"
|
||||||
RICHTEXT_TYPE = "richtext"
|
RICHTEXT_TYPE = "richtext"
|
||||||
DATE_TYPE = "date"
|
DATE_TYPE = "date"
|
||||||
URL_TYPE = "url"
|
URL_TYPE = "url"
|
||||||
|
DROPDOWN_TYPE = "dropdown"
|
||||||
|
CHECKBOX_TYPE = "checkbox"
|
||||||
|
NUMBER_TYPE = "number"
|
||||||
|
|
||||||
|
|
||||||
TYPE_CHOICES = [
|
TYPE_CHOICES = [
|
||||||
|
@ -566,6 +569,18 @@ TYPE_CHOICES = [
|
||||||
{
|
{
|
||||||
key: URL_TYPE,
|
key: URL_TYPE,
|
||||||
name: "ADMIN.CUSTOM_FIELDS.FIELD_TYPE_URL"
|
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
|
# Custom Attribute
|
||||||
#########################
|
#########################
|
||||||
|
_parseAttributesExtra: () ->
|
||||||
|
@scope.customAttributes = _.map(@scope.customAttributes, (x) => @._parseAttributeExtra(x))
|
||||||
|
|
||||||
|
_parseAttributeExtra: (attr) ->
|
||||||
|
if (attr.type == 'dropdown' && !attr.extra)
|
||||||
|
attr.extra = ['']
|
||||||
|
return attr
|
||||||
|
|
||||||
loadCustomAttributes: =>
|
loadCustomAttributes: =>
|
||||||
return @rs.customAttributes[@scope.type].list(@scope.projectId).then (customAttributes) =>
|
return @rs.customAttributes[@scope.type].list(@scope.projectId).then (customAttributes) =>
|
||||||
@scope.customAttributes = customAttributes
|
@scope.customAttributes = customAttributes
|
||||||
@scope.maxOrder = _.maxBy(customAttributes, "order")?.order
|
@scope.maxOrder = _.maxBy(customAttributes, "order")?.order
|
||||||
|
@._parseAttributesExtra()
|
||||||
return customAttributes
|
return customAttributes
|
||||||
|
|
||||||
createCustomAttribute: (attrValues) =>
|
createCustomAttribute: (attrValues) =>
|
||||||
|
@ -647,23 +670,63 @@ ProjectCustomAttributesDirective = ($log, $confirm, animationFrame, $translate)
|
||||||
$scope.$on "$destroy", ->
|
$scope.$on "$destroy", ->
|
||||||
$el.off()
|
$el.off()
|
||||||
|
|
||||||
|
$scope.isExtraVisible = {}
|
||||||
|
|
||||||
|
_manageFormEvent = (event, callback) ->
|
||||||
|
event.preventDefault()
|
||||||
|
formEl = angular.element(event.currentTarget).closest("form")
|
||||||
|
callback(formEl)
|
||||||
|
|
||||||
##################################
|
##################################
|
||||||
# Drag & Drop
|
# 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) ->
|
initDraggable = ->
|
||||||
itemEl = $(item)
|
sortableEl = $el.find(".js-sortable")
|
||||||
itemAttr = itemEl.scope().attr
|
drake = dragula([sortableEl[0]], {
|
||||||
itemIndex = itemEl.index()
|
direction: 'vertical',
|
||||||
$ctrl.moveCustomAttributes(itemAttr, itemIndex)
|
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
|
# New custom attribute
|
||||||
|
@ -695,13 +758,13 @@ ProjectCustomAttributesDirective = ($log, $confirm, animationFrame, $translate)
|
||||||
form = formEl.checksley()
|
form = formEl.checksley()
|
||||||
return if not form.validate()
|
return if not form.validate()
|
||||||
|
|
||||||
onSucces = =>
|
onSucces = ->
|
||||||
$ctrl.loadCustomAttributes()
|
$ctrl.loadCustomAttributes()
|
||||||
hideCreateForm()
|
hideCreateForm()
|
||||||
resetNewAttr()
|
resetNewAttr()
|
||||||
$confirm.notify("success")
|
$confirm.notify("success")
|
||||||
|
|
||||||
onError = (data) =>
|
onError = (data) ->
|
||||||
form.setErrors(data)
|
form.setErrors(data)
|
||||||
|
|
||||||
attr = $scope.newAttr
|
attr = $scope.newAttr
|
||||||
|
@ -714,6 +777,22 @@ ProjectCustomAttributesDirective = ($log, $confirm, animationFrame, $translate)
|
||||||
hideCreateForm()
|
hideCreateForm()
|
||||||
resetNewAttr()
|
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) ->
|
$scope.$watch "customAttributes", (customAttributes) ->
|
||||||
return if not customAttributes
|
return if not customAttributes
|
||||||
|
|
||||||
|
@ -725,17 +804,16 @@ ProjectCustomAttributesDirective = ($log, $confirm, animationFrame, $translate)
|
||||||
hideCreateForm()
|
hideCreateForm()
|
||||||
showAddButton()
|
showAddButton()
|
||||||
showCancelButton()
|
showCancelButton()
|
||||||
|
initDraggable()
|
||||||
|
|
||||||
|
$el.on "change", ".custom-field-type select", (event) ->
|
||||||
|
_manageFormEvent(event, initAttrType)
|
||||||
|
|
||||||
$el.on "click", ".js-add-custom-field-button", (event) ->
|
$el.on "click", ".js-add-custom-field-button", (event) ->
|
||||||
event.preventDefault()
|
_manageFormEvent(event, showCreateForm)
|
||||||
showCreateForm()
|
|
||||||
|
|
||||||
$el.on "click", ".js-create-custom-field-button", debounce 2000, (event) ->
|
$el.on "click", ".js-create-custom-field-button", debounce 2000, (event) ->
|
||||||
event.preventDefault()
|
_manageFormEvent(event, create)
|
||||||
target = angular.element(event.currentTarget)
|
|
||||||
formEl = target.closest("form")
|
|
||||||
|
|
||||||
create(formEl)
|
|
||||||
|
|
||||||
$el.on "click", ".js-cancel-new-custom-field-button", (event) ->
|
$el.on "click", ".js-cancel-new-custom-field-button", (event) ->
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
|
@ -743,9 +821,7 @@ ProjectCustomAttributesDirective = ($log, $confirm, animationFrame, $translate)
|
||||||
|
|
||||||
$el.on "keyup", ".js-new-custom-field input", (event) ->
|
$el.on "keyup", ".js-new-custom-field input", (event) ->
|
||||||
if event.keyCode == 13 # Enter
|
if event.keyCode == 13 # Enter
|
||||||
target = angular.element(event.currentTarget)
|
_manageFormEvent(event, create)
|
||||||
formEl = target.closest("form")
|
|
||||||
create(formEl)
|
|
||||||
else if event.keyCode == 27 # Esc
|
else if event.keyCode == 27 # Esc
|
||||||
cancelCreate()
|
cancelCreate()
|
||||||
|
|
||||||
|
@ -757,64 +833,56 @@ ProjectCustomAttributesDirective = ($log, $confirm, animationFrame, $translate)
|
||||||
formEl.find(".js-view-custom-field").addClass("hidden")
|
formEl.find(".js-view-custom-field").addClass("hidden")
|
||||||
formEl.find(".js-edit-custom-field").removeClass("hidden")
|
formEl.find(".js-edit-custom-field").removeClass("hidden")
|
||||||
formEl.find(".js-edit-custom-field input:visible").first().focus().select()
|
formEl.find(".js-edit-custom-field input:visible").first().focus().select()
|
||||||
|
formEl.find(".js-view-custom-field-extra").addClass("hidden")
|
||||||
hideEditForm = (formEl) ->
|
formEl.find(".js-edit-custom-field-extra").removeClass("hidden")
|
||||||
formEl.find(".js-edit-custom-field").addClass("hidden")
|
formEl.find(".custom-extra-actions").removeClass("hidden")
|
||||||
formEl.find(".js-view-custom-field").removeClass("hidden")
|
showExtra(formEl.scope().attr.id)
|
||||||
|
$scope.$apply()
|
||||||
revertChangesInCustomAttribute = (formEl) ->
|
|
||||||
$scope.$apply ->
|
|
||||||
formEl.scope().attr.revert()
|
|
||||||
|
|
||||||
update = (formEl) ->
|
update = (formEl) ->
|
||||||
form = formEl.checksley()
|
form = formEl.checksley()
|
||||||
return if not form.validate()
|
return if not form.validate()
|
||||||
|
onSucces = ->
|
||||||
onSucces = =>
|
|
||||||
$ctrl.loadCustomAttributes()
|
$ctrl.loadCustomAttributes()
|
||||||
hideEditForm(formEl)
|
hideEditForm(formEl)
|
||||||
$confirm.notify("success")
|
$confirm.notify("success")
|
||||||
|
|
||||||
onError = (data) =>
|
onError = (data) ->
|
||||||
form.setErrors(data)
|
form.setErrors(data)
|
||||||
|
|
||||||
attr = formEl.scope().attr
|
attr = formEl.scope().attr
|
||||||
|
attr.setAttr('extra', attr.extra)
|
||||||
$ctrl.saveCustomAttribute(attr).then(onSucces, onError)
|
$ctrl.saveCustomAttribute(attr).then(onSucces, onError)
|
||||||
|
|
||||||
cancelUpdate = (formEl) ->
|
cancelUpdate = (formEl) ->
|
||||||
hideEditForm(formEl)
|
hideEditForm(formEl)
|
||||||
revertChangesInCustomAttribute(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) ->
|
$el.on "click", ".js-edit-custom-field-button", (event) ->
|
||||||
event.preventDefault()
|
_manageFormEvent(event, showEditForm)
|
||||||
target = angular.element(event.currentTarget)
|
|
||||||
formEl = target.closest("form")
|
|
||||||
|
|
||||||
showEditForm(formEl)
|
$el.on "click", ".js-update-custom-field-button", debounce 1000, (event) ->
|
||||||
|
_manageFormEvent(event, update)
|
||||||
$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-cancel-edit-custom-field-button", (event) ->
|
$el.on "click", ".js-cancel-edit-custom-field-button", (event) ->
|
||||||
event.preventDefault()
|
_manageFormEvent(event, cancelUpdate)
|
||||||
target = angular.element(event.currentTarget)
|
|
||||||
formEl = target.closest("form")
|
|
||||||
|
|
||||||
cancelUpdate(formEl)
|
|
||||||
|
|
||||||
$el.on "keyup", ".js-edit-custom-field input", (event) ->
|
$el.on "keyup", ".js-edit-custom-field input", (event) ->
|
||||||
if event.keyCode == 13 # Enter
|
if event.keyCode == 13 # Enter
|
||||||
target = angular.element(event.currentTarget)
|
_manageFormEvent(event, update)
|
||||||
formEl = target.closest("form")
|
|
||||||
update(formEl)
|
|
||||||
else if event.keyCode == 27 # Esc
|
else if event.keyCode == 27 # Esc
|
||||||
target = angular.element(event.currentTarget)
|
_manageFormEvent(event, cancelUpdate)
|
||||||
formEl = target.closest("form")
|
|
||||||
cancelUpdate(formEl)
|
|
||||||
|
|
||||||
##################################
|
##################################
|
||||||
# Delete custom attribute
|
# Delete custom attribute
|
||||||
|
@ -837,16 +905,66 @@ ProjectCustomAttributesDirective = ($log, $confirm, animationFrame, $translate)
|
||||||
$ctrl.deleteCustomAttribute(attr).then(onSucces, onError)
|
$ctrl.deleteCustomAttribute(attr).then(onSucces, onError)
|
||||||
|
|
||||||
$el.on "click", ".js-delete-custom-field-button", debounce 2000, (event) ->
|
$el.on "click", ".js-delete-custom-field-button", debounce 2000, (event) ->
|
||||||
event.preventDefault()
|
_manageFormEvent(event, deleteCustomAttribute)
|
||||||
target = angular.element(event.currentTarget)
|
|
||||||
formEl = target.closest("form")
|
|
||||||
|
|
||||||
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}
|
return {link: link}
|
||||||
|
|
||||||
module.directive("tgProjectCustomAttributes", ["$log", "$tgConfirm", "animationFrame", "$translate",
|
module.directive("tgProjectCustomAttributes", ["$log", "$tgConfirm", "animationFrame", "$translate",
|
||||||
ProjectCustomAttributesDirective])
|
ProjectCustomAttributesDirective])
|
||||||
|
|
||||||
|
|
||||||
#############################################################################
|
#############################################################################
|
||||||
|
|
|
@ -31,6 +31,9 @@ RICHTEXT_TYPE = "url"
|
||||||
MULTILINE_TYPE = "multiline"
|
MULTILINE_TYPE = "multiline"
|
||||||
DATE_TYPE = "date"
|
DATE_TYPE = "date"
|
||||||
URL_TYPE = "url"
|
URL_TYPE = "url"
|
||||||
|
DROPDOWN_TYPE = "dropdown"
|
||||||
|
CHECKBOX_TYPE = "checkbox"
|
||||||
|
NUMBER_TYPE = "number"
|
||||||
|
|
||||||
|
|
||||||
TYPE_CHOICES = [
|
TYPE_CHOICES = [
|
||||||
|
@ -53,6 +56,18 @@ TYPE_CHOICES = [
|
||||||
{
|
{
|
||||||
key: RICHTEXT_TYPE,
|
key: RICHTEXT_TYPE,
|
||||||
name: "ADMIN.CUSTOM_FIELDS.FIELD_TYPE_RICHTEXT"
|
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) ->
|
render = (attributeValue, edit=false) ->
|
||||||
if attributeValue.type is DATE_TYPE and attributeValue.value
|
if attributeValue.type is DATE_TYPE and attributeValue.value
|
||||||
value = moment(attributeValue.value, "YYYY-MM-DD").format(prettyDate)
|
value = moment(attributeValue.value, "YYYY-MM-DD").format(prettyDate)
|
||||||
|
if attributeValue.type is NUMBER_TYPE and attributeValue.value
|
||||||
|
value = parseFloat(attributeValue.value)
|
||||||
else
|
else
|
||||||
value = attributeValue.value
|
value = attributeValue.value
|
||||||
|
|
||||||
editable = isEditable()
|
editable = isEditable()
|
||||||
|
|
||||||
ctx = {
|
ctx = {
|
||||||
|
@ -164,12 +182,14 @@ CustomAttributeValueDirective = ($template, $selectedText, $compile, $translate,
|
||||||
name: attributeValue.name
|
name: attributeValue.name
|
||||||
description: attributeValue.description
|
description: attributeValue.description
|
||||||
value: value
|
value: value
|
||||||
isEditable: editable
|
|
||||||
type: attributeValue.type
|
type: attributeValue.type
|
||||||
|
isEditable: editable
|
||||||
}
|
}
|
||||||
|
|
||||||
scope = $scope.$new()
|
scope = $scope.$new()
|
||||||
scope.attributeHtml = wysiwygService.getHTML(value)
|
scope.attributeHtml = wysiwygService.getHTML(value)
|
||||||
|
scope.extra = attributeValue.extra
|
||||||
|
scope.model = value
|
||||||
|
|
||||||
if editable and (edit or not value)
|
if editable and (edit or not value)
|
||||||
html = templateEdit(ctx)
|
html = templateEdit(ctx)
|
||||||
|
@ -214,11 +234,19 @@ CustomAttributeValueDirective = ($template, $selectedText, $compile, $translate,
|
||||||
form = $el.find("form").checksley()
|
form = $el.find("form").checksley()
|
||||||
return if not form.validate()
|
return if not form.validate()
|
||||||
|
|
||||||
input = $el.find("input[name=value], textarea[name='value']")
|
if attributeValue.type is DROPDOWN_TYPE
|
||||||
attributeValue.value = input.val()
|
formControl = $el.find("select[name='value']")
|
||||||
if attributeValue.type is DATE_TYPE
|
attributeValue.value = formControl.val()
|
||||||
if moment(attributeValue.value, prettyDate).isValid()
|
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")
|
attributeValue.value = moment(attributeValue.value, prettyDate).format("YYYY-MM-DD")
|
||||||
|
if attributeValue.type is NUMBER_TYPE
|
||||||
|
attributeValue.value = parseFloat(attributeValue.value)
|
||||||
|
|
||||||
$scope.$apply ->
|
$scope.$apply ->
|
||||||
$ctrl.updateAttributeValue(attributeValue).then ->
|
$ctrl.updateAttributeValue(attributeValue).then ->
|
||||||
|
|
|
@ -571,7 +571,10 @@
|
||||||
"FIELD_TYPE_RICHTEXT": "Rich text",
|
"FIELD_TYPE_RICHTEXT": "Rich text",
|
||||||
"FIELD_TYPE_MULTI": "Multi-line",
|
"FIELD_TYPE_MULTI": "Multi-line",
|
||||||
"FIELD_TYPE_DATE": "Date",
|
"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": {
|
"PROJECT_VALUES": {
|
||||||
"PAGE_TITLE": "{{sectionName}} - Project values - {{projectName}}",
|
"PAGE_TITLE": "{{sectionName}} - Project values - {{projectName}}",
|
||||||
|
|
|
@ -19,6 +19,24 @@ form.custom-field-single.editable
|
||||||
input#custom-field-value(name="value", type="text", data-pikaday, value!="<%- value %>")
|
input#custom-field-value(name="value", type="text", data-pikaday, value!="<%- value %>")
|
||||||
<% } else if (type=="url") { %>
|
<% } else if (type=="url") { %>
|
||||||
input#custom-field-value(name="value", type="url", value!="<%- value %>")
|
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 { %>
|
<% } else { %>
|
||||||
input#custom-field-value(name="value", type="text", value!="<%- value %>")
|
input#custom-field-value(name="value", type="text", value!="<%- value %>")
|
||||||
<% } %>
|
<% } %>
|
||||||
|
|
|
@ -15,6 +15,13 @@
|
||||||
<% } else if (type=="richtext") { %>
|
<% } else if (type=="richtext") { %>
|
||||||
.custom-field-value.js-value-view-mode.wysiwyg
|
.custom-field-value.js-value-view-mode.wysiwyg
|
||||||
div(ng-bind-html="attributeHtml")
|
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 { %>
|
<% } else { %>
|
||||||
.custom-field-value.js-value-view-mode
|
.custom-field-value.js-value-view-mode
|
||||||
span
|
span
|
||||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -23,7 +23,21 @@ section.custom-fields-table.basic-table
|
||||||
form.js-form(tg-bind-scope)
|
form.js-form(tg-bind-scope)
|
||||||
div.row.single-custom-field.js-view-custom-field
|
div.row.single-custom-field.js-view-custom-field
|
||||||
tg-svg.e2e-drag(svg-icon="icon-drag")
|
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-description {{ attr.description }}
|
||||||
div.custom-field-type(ng-switch on="attr.type")
|
div.custom-field-type(ng-switch on="attr.type")
|
||||||
span(
|
span(
|
||||||
|
@ -46,6 +60,18 @@ section.custom-fields-table.basic-table
|
||||||
ng-switch-when="url"
|
ng-switch-when="url"
|
||||||
translate="ADMIN.CUSTOM_FIELDS.FIELD_TYPE_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
|
||||||
.custom-options-wrapper
|
.custom-options-wrapper
|
||||||
a.js-edit-custom-field-button(
|
a.js-edit-custom-field-button(
|
||||||
|
@ -59,77 +85,84 @@ section.custom-fields-table.basic-table
|
||||||
title="{{'ADMIN.CUSTOM_ATTRIBUTES.DELETE' | translate}}"
|
title="{{'ADMIN.CUSTOM_ATTRIBUTES.DELETE' | translate}}"
|
||||||
)
|
)
|
||||||
tg-svg(svg-icon="icon-trash")
|
tg-svg(svg-icon="icon-trash")
|
||||||
|
.js-edit-custom-field.hidden
|
||||||
div.row.single-custom-field.js-edit-custom-field.hidden
|
div.row.single-custom-field
|
||||||
fieldset.custom-name
|
fieldset.custom-name
|
||||||
input(
|
input(
|
||||||
type="text"
|
type="text"
|
||||||
name="name"
|
name="name"
|
||||||
placeholder="{{'ADMIN.CUSTOM_ATTRIBUTES.SET_FIELD_NAME' | translate}}"
|
placeholder="{{'ADMIN.CUSTOM_ATTRIBUTES.SET_FIELD_NAME' | translate}}"
|
||||||
ng-model="attr.name"
|
ng-model="attr.name"
|
||||||
data-required="true"
|
data-required="true"
|
||||||
data-maxlength="64"
|
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}}"
|
|
||||||
)
|
)
|
||||||
tg-svg(svg-icon="icon-save")
|
fieldset.custom-description
|
||||||
|
input(
|
||||||
a.js-cancel-edit-custom-field-button(
|
type="text"
|
||||||
href="",
|
name="description"
|
||||||
title="{{'ADMIN.CUSTOM_ATTRIBUTES.ACTION_CANCEL_EDITION' | translate}}"
|
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
|
a.js-cancel-edit-custom-field-button(
|
||||||
fieldset.custom-name
|
href="",
|
||||||
input(
|
title="{{'ADMIN.CUSTOM_ATTRIBUTES.ACTION_CANCEL_EDITION' | translate}}"
|
||||||
type="text"
|
)
|
||||||
name="name"
|
tg-svg(svg-icon="icon-close")
|
||||||
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")
|
|
||||||
|
|
||||||
fieldset.custom-options
|
div.custom-field-extra(ng-show="attr.type == 'dropdown' && isExtraVisible[attr.id]")
|
||||||
div.custom-options-wrapper
|
include admin-custom-attributes-extra
|
||||||
a.js-create-custom-field-button(
|
|
||||||
href="",
|
form(tg-bind-scope)
|
||||||
title="{{'ADMIN.CUSTOM_ATTRIBUTES.SAVE_TITLE' | translate}}"
|
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")
|
fieldset.custom-description
|
||||||
|
input(
|
||||||
a.js-cancel-new-custom-field-button(
|
type="text"
|
||||||
href="",
|
name="description"
|
||||||
title="{{'ADMIN.CUSTOM_ATTRIBUTES.CANCEL_TITLE' | translate}}"
|
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
|
|
@ -7,7 +7,6 @@
|
||||||
margin-bottom: 2em;
|
margin-bottom: 2em;
|
||||||
.row {
|
.row {
|
||||||
border-bottom: 0;
|
border-bottom: 0;
|
||||||
padding: .5rem 0;
|
|
||||||
}
|
}
|
||||||
.table-header {
|
.table-header {
|
||||||
@include font-type(bold);
|
@include font-type(bold);
|
||||||
|
@ -34,14 +33,17 @@
|
||||||
cursor: default;
|
cursor: default;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.custom-description {
|
|
||||||
color: $gray-light;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.single-custom-field {
|
.single-custom-field {
|
||||||
border-bottom: 1px solid $whitish;
|
border-bottom: 1px solid $whitish;
|
||||||
color: $gray;
|
color: $gray;
|
||||||
}
|
}
|
||||||
|
.js-view-custom-field {
|
||||||
|
padding: .75rem 0;
|
||||||
|
.custom-extra-attr-wrapper {
|
||||||
|
margin-left: 1em;
|
||||||
|
}
|
||||||
|
}
|
||||||
.icon-drag {
|
.icon-drag {
|
||||||
fill: $gray-light;
|
fill: $gray-light;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
|
@ -55,6 +57,13 @@
|
||||||
.custom-name {
|
.custom-name {
|
||||||
flex-basis: 25%;
|
flex-basis: 25%;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
|
a {
|
||||||
|
padding: .5em;
|
||||||
|
}
|
||||||
|
svg {
|
||||||
|
height: 12px;
|
||||||
|
width: 12px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.custom-description {
|
.custom-description {
|
||||||
@include ellipsis(100%);
|
@include ellipsis(100%);
|
||||||
|
@ -62,7 +71,7 @@
|
||||||
flex-grow: 8;
|
flex-grow: 8;
|
||||||
}
|
}
|
||||||
.custom-field-type {
|
.custom-field-type {
|
||||||
flex-basis: 10%;
|
flex-basis: 12%;
|
||||||
flex-grow: 0;
|
flex-grow: 0;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
@ -95,7 +104,34 @@
|
||||||
display: inline-block;
|
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 {
|
.custom-options-wrapper {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue