302 lines
10 KiB
CoffeeScript
302 lines
10 KiB
CoffeeScript
|
class @LabelsSelect
|
||
|
constructor: ->
|
||
|
$('.js-label-select').each (i, dropdown) ->
|
||
|
$dropdown = $(dropdown)
|
||
|
projectId = $dropdown.data('project-id')
|
||
|
labelUrl = $dropdown.data('labels')
|
||
|
issueUpdateURL = $dropdown.data('issueUpdate')
|
||
|
selectedLabel = $dropdown.data('selected')
|
||
|
if selectedLabel? and not $dropdown.hasClass 'js-multiselect'
|
||
|
selectedLabel = selectedLabel.split(',')
|
||
|
newLabelField = $('#new_label_name')
|
||
|
newColorField = $('#new_label_color')
|
||
|
showNo = $dropdown.data('show-no')
|
||
|
showAny = $dropdown.data('show-any')
|
||
|
defaultLabel = $dropdown.data('default-label')
|
||
|
abilityName = $dropdown.data('ability-name')
|
||
|
$selectbox = $dropdown.closest('.selectbox')
|
||
|
$block = $selectbox.closest('.block')
|
||
|
$form = $dropdown.closest('form')
|
||
|
$sidebarCollapsedValue = $block.find('.sidebar-collapsed-icon span')
|
||
|
$value = $block.find('.value')
|
||
|
$newLabelError = $('.js-label-error')
|
||
|
$colorPreview = $('.js-dropdown-label-color-preview')
|
||
|
$newLabelCreateButton = $('.js-new-label-btn')
|
||
|
|
||
|
$newLabelError.hide()
|
||
|
$loading = $block.find('.block-loading').fadeOut()
|
||
|
|
||
|
issueURLSplit = issueUpdateURL.split('/') if issueUpdateURL?
|
||
|
if issueUpdateURL
|
||
|
labelHTMLTemplate = _.template(
|
||
|
'<% _.each(labels, function(label){ %>
|
||
|
<a href="<%= ["",issueURLSplit[1], issueURLSplit[2],""].join("/") %>issues?label_name[]=<%= _.escape(label.title) %>">
|
||
|
<span class="label has-tooltip color-label" title="<%= _.escape(label.description) %>" style="background-color: <%= label.color %>; color: <%= label.text_color %>;">
|
||
|
<%= _.escape(label.title) %>
|
||
|
</span>
|
||
|
</a>
|
||
|
<% }); %>'
|
||
|
)
|
||
|
labelNoneHTMLTemplate = _.template('<div class="light">None</div>')
|
||
|
|
||
|
if newLabelField.length
|
||
|
|
||
|
# Suggested colors in the dropdown to chose from pre-chosen colors
|
||
|
$('.suggest-colors-dropdown a').on "click", (e) ->
|
||
|
e.preventDefault()
|
||
|
e.stopPropagation()
|
||
|
newColorField
|
||
|
.val($(this).data('color'))
|
||
|
.trigger('change')
|
||
|
$colorPreview
|
||
|
.css 'background-color', $(this).data('color')
|
||
|
.parent()
|
||
|
.addClass 'is-active'
|
||
|
|
||
|
# Cancel button takes back to first page
|
||
|
resetForm = ->
|
||
|
newLabelField
|
||
|
.val ''
|
||
|
.trigger 'change'
|
||
|
newColorField
|
||
|
.val ''
|
||
|
.trigger 'change'
|
||
|
$colorPreview
|
||
|
.css 'background-color', ''
|
||
|
.parent()
|
||
|
.removeClass 'is-active'
|
||
|
|
||
|
$('.dropdown-menu-back').on 'click', ->
|
||
|
resetForm()
|
||
|
|
||
|
$('.js-cancel-label-btn').on 'click', (e) ->
|
||
|
e.preventDefault()
|
||
|
e.stopPropagation()
|
||
|
resetForm()
|
||
|
$('.dropdown-menu-back', $dropdown.parent()).trigger 'click'
|
||
|
|
||
|
# Listen for change and keyup events on label and color field
|
||
|
# This allows us to enable the button when ready
|
||
|
enableLabelCreateButton = ->
|
||
|
if newLabelField.val() isnt '' and newColorField.val() isnt ''
|
||
|
$newLabelError.hide()
|
||
|
$newLabelCreateButton.enable()
|
||
|
else
|
||
|
$newLabelCreateButton.disable()
|
||
|
|
||
|
saveLabel = ->
|
||
|
# Create new label with API
|
||
|
Api.newLabel projectId, {
|
||
|
name: newLabelField.val()
|
||
|
color: newColorField.val()
|
||
|
}, (label) ->
|
||
|
$newLabelCreateButton.enable()
|
||
|
|
||
|
if label.message?
|
||
|
$newLabelError
|
||
|
.text label.message
|
||
|
.show()
|
||
|
else
|
||
|
$('.dropdown-menu-back', $dropdown.parent()).trigger 'click'
|
||
|
|
||
|
newLabelField.on 'keyup change', enableLabelCreateButton
|
||
|
|
||
|
newColorField.on 'keyup change', enableLabelCreateButton
|
||
|
|
||
|
# Send the API call to create the label
|
||
|
$newLabelCreateButton
|
||
|
.disable()
|
||
|
.on 'click', (e) ->
|
||
|
e.preventDefault()
|
||
|
e.stopPropagation()
|
||
|
saveLabel()
|
||
|
|
||
|
saveLabelData = ->
|
||
|
selected = $dropdown
|
||
|
.closest('.selectbox')
|
||
|
.find("input[name='#{$dropdown.data('field-name')}']")
|
||
|
.map(->
|
||
|
@value
|
||
|
).get()
|
||
|
data = {}
|
||
|
data[abilityName] = {}
|
||
|
data[abilityName].label_ids = selected
|
||
|
if not selected.length
|
||
|
data[abilityName].label_ids = ['']
|
||
|
$loading.fadeIn()
|
||
|
$dropdown.trigger('loading.gl.dropdown')
|
||
|
$.ajax(
|
||
|
type: 'PUT'
|
||
|
url: issueUpdateURL
|
||
|
dataType: 'JSON'
|
||
|
data: data
|
||
|
).done (data) ->
|
||
|
$loading.fadeOut()
|
||
|
$dropdown.trigger('loaded.gl.dropdown')
|
||
|
$selectbox.hide()
|
||
|
data.issueURLSplit = issueURLSplit
|
||
|
labelCount = 0
|
||
|
if data.labels.length
|
||
|
template = labelHTMLTemplate(data)
|
||
|
labelCount = data.labels.length
|
||
|
else
|
||
|
template = labelNoneHTMLTemplate()
|
||
|
$value
|
||
|
.removeAttr('style')
|
||
|
.html(template)
|
||
|
$sidebarCollapsedValue.text(labelCount)
|
||
|
|
||
|
$('.has-tooltip', $value).tooltip(container: 'body')
|
||
|
|
||
|
$value
|
||
|
.find('a')
|
||
|
.each((i) ->
|
||
|
setTimeout(=>
|
||
|
gl.animate.animate($(@), 'pulse')
|
||
|
,200 * i
|
||
|
)
|
||
|
)
|
||
|
|
||
|
|
||
|
$dropdown.glDropdown(
|
||
|
data: (term, callback) ->
|
||
|
$.ajax(
|
||
|
url: labelUrl
|
||
|
).done (data) ->
|
||
|
data = _.chain data
|
||
|
.groupBy (label) ->
|
||
|
label.title
|
||
|
.map (label) ->
|
||
|
color = _.map label, (dup) ->
|
||
|
dup.color
|
||
|
|
||
|
return {
|
||
|
id: label[0].id
|
||
|
title: label[0].title
|
||
|
color: color
|
||
|
duplicate: color.length > 1
|
||
|
}
|
||
|
.value()
|
||
|
|
||
|
if $dropdown.hasClass 'js-extra-options'
|
||
|
if showNo
|
||
|
data.unshift(
|
||
|
id: 0
|
||
|
title: 'No Label'
|
||
|
)
|
||
|
|
||
|
if showAny
|
||
|
data.unshift(
|
||
|
isAny: true
|
||
|
title: 'Any Label'
|
||
|
)
|
||
|
|
||
|
if data.length > 2
|
||
|
data.splice 2, 0, 'divider'
|
||
|
|
||
|
callback data
|
||
|
|
||
|
renderRow: (label) ->
|
||
|
removesAll = label.id is 0 or not label.id?
|
||
|
|
||
|
selectedClass = []
|
||
|
if $form.find("input[type='hidden']\
|
||
|
[name='#{$dropdown.data('fieldName')}']\
|
||
|
[value='#{this.id(label)}']").length
|
||
|
selectedClass.push 'is-active'
|
||
|
|
||
|
if $dropdown.hasClass('js-multiselect') and removesAll
|
||
|
selectedClass.push 'dropdown-clear-active'
|
||
|
|
||
|
if label.duplicate
|
||
|
spacing = 100 / label.color.length
|
||
|
|
||
|
# Reduce the colors to 4
|
||
|
label.color = label.color.filter (color, i) ->
|
||
|
i < 4
|
||
|
|
||
|
color = _.map(label.color, (color, i) ->
|
||
|
percentFirst = Math.floor(spacing * i)
|
||
|
percentSecond = Math.floor(spacing * (i + 1))
|
||
|
"#{color} #{percentFirst}%,#{color} #{percentSecond}% "
|
||
|
).join(',')
|
||
|
color = "linear-gradient(#{color})"
|
||
|
else
|
||
|
if label.color?
|
||
|
color = label.color[0]
|
||
|
|
||
|
if color
|
||
|
colorEl = "<span class='dropdown-label-box' style='background: #{color}'></span>"
|
||
|
else
|
||
|
colorEl = ''
|
||
|
|
||
|
"<li>
|
||
|
<a href='#' class='#{selectedClass.join(' ')}'>
|
||
|
#{colorEl}
|
||
|
#{_.escape(label.title)}
|
||
|
</a>
|
||
|
</li>"
|
||
|
filterable: true
|
||
|
search:
|
||
|
fields: ['title']
|
||
|
selectable: true
|
||
|
|
||
|
toggleLabel: (selected, el) ->
|
||
|
selected_labels = $('.js-label-select').siblings('.dropdown-menu-labels').find('.is-active')
|
||
|
|
||
|
if selected and selected.title?
|
||
|
if selected_labels.length > 1
|
||
|
"#{selected.title} +#{selected_labels.length - 1} more"
|
||
|
else
|
||
|
selected.title
|
||
|
else if not selected and selected_labels.length isnt 0
|
||
|
if selected_labels.length > 1
|
||
|
"#{$(selected_labels[0]).text()} +#{selected_labels.length - 1} more"
|
||
|
else if selected_labels.length is 1
|
||
|
$(selected_labels).text()
|
||
|
else
|
||
|
defaultLabel
|
||
|
fieldName: $dropdown.data('field-name')
|
||
|
id: (label) ->
|
||
|
if $dropdown.hasClass("js-filter-submit") and not label.isAny?
|
||
|
_.escape label.title
|
||
|
else
|
||
|
label.id
|
||
|
|
||
|
hidden: ->
|
||
|
page = $('body').data 'page'
|
||
|
isIssueIndex = page is 'projects:issues:index'
|
||
|
isMRIndex = page is 'projects:merge_requests:index'
|
||
|
|
||
|
$selectbox.hide()
|
||
|
# display:block overrides the hide-collapse rule
|
||
|
$value.removeAttr('style')
|
||
|
if $dropdown.hasClass 'js-multiselect'
|
||
|
if $dropdown.hasClass('js-filter-submit') and (isIssueIndex or isMRIndex)
|
||
|
selectedLabels = $dropdown
|
||
|
.closest('form')
|
||
|
.find("input:hidden[name='#{$dropdown.data('fieldName')}']")
|
||
|
Issuable.filterResults $dropdown.closest('form')
|
||
|
else if $dropdown.hasClass('js-filter-submit')
|
||
|
$dropdown.closest('form').submit()
|
||
|
else
|
||
|
saveLabelData()
|
||
|
|
||
|
multiSelect: $dropdown.hasClass 'js-multiselect'
|
||
|
clicked: (label) ->
|
||
|
page = $('body').data 'page'
|
||
|
isIssueIndex = page is 'projects:issues:index'
|
||
|
isMRIndex = page is 'projects:merge_requests:index'
|
||
|
if $dropdown.hasClass('js-filter-submit') and (isIssueIndex or isMRIndex)
|
||
|
if not $dropdown.hasClass 'js-multiselect'
|
||
|
selectedLabel = label.title
|
||
|
Issuable.filterResults $dropdown.closest('form')
|
||
|
else if $dropdown.hasClass 'js-filter-submit'
|
||
|
$dropdown.closest('form').submit()
|
||
|
else
|
||
|
if $dropdown.hasClass 'js-multiselect'
|
||
|
return
|
||
|
else
|
||
|
saveLabelData()
|
||
|
)
|