class @LabelsSelect constructor: -> _this = @ $('.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){ %> issues?label_name[]=<%= _.escape(label.title) %>"> <%= _.escape(label.title) %> <% }); %>' ) labelNoneHTMLTemplate = 'None' 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? errors = _.map label.message, (value, key) -> "#{key} #{value[0]}" $newLabelError .html errors.join("
") .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, instance) -> $li = $('
  • ') $a = $('') selectedClass = [] removesAll = label.id is 0 or not label.id? if $dropdown.hasClass('js-filter-bulk-update') indeterminate = instance.indeterminateIds active = instance.activeIds if indeterminate.indexOf(label.id) isnt -1 selectedClass.push 'is-indeterminate' if active.indexOf(label.id) isnt -1 # Remove is-indeterminate class if the item will be marked as active i = selectedClass.indexOf 'is-indeterminate' selectedClass.splice i, 1 unless i is -1 selectedClass.push 'is-active' # Add input manually instance.addInput @fieldName, label.id 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 = "" else colorEl = '' # We need to identify which items are actually labels if label.id selectedClass.push('label-item') $a.attr('data-label-id', label.id) $a.addClass(selectedClass.join(' ')) .html("#{colorEl} #{_.escape(label.title)}") # Return generated html $li.html($a).prop('outerHTML') persistWhenHide: $dropdown.data('persistWhenHide') search: fields: ['title'] selectable: true filterable: 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 if not $dropdown.hasClass 'js-filter-bulk-update' saveLabelData() if $dropdown.hasClass('js-filter-bulk-update') # If we are persisting state we need the classes if not @options.persistWhenHide $dropdown.parent().find('.is-active, .is-indeterminate').removeClass() multiSelect: $dropdown.hasClass 'js-multiselect' clicked: (label) -> if $dropdown.hasClass('js-filter-bulk-update') return 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() setIndeterminateIds: -> if @dropdown.find('.dropdown-menu-toggle').hasClass('js-filter-bulk-update') @indeterminateIds = _this.getIndeterminateIds() setActiveIds: -> if @dropdown.find('.dropdown-menu-toggle').hasClass('js-filter-bulk-update') @activeIds = _this.getActiveIds() ) @bindEvents() bindEvents: -> $('body').on 'change', '.selected_issue', @onSelectCheckboxIssue onSelectCheckboxIssue: -> return if $('.selected_issue:checked').length # Remove inputs $('.issues_bulk_update .labels-filter input[type="hidden"]').remove() # Also restore button text $('.issues_bulk_update .labels-filter .dropdown-toggle-text').text('Label') getIndeterminateIds: -> label_ids = [] $('.selected_issue:checked').each (i, el) -> issue_id = $(el).data('id') label_ids.push $("#issue_#{issue_id}").data('labels') _.flatten(label_ids) getActiveIds: -> label_ids = [] $('.selected_issue:checked').each (i, el) -> issue_id = $(el).data('id') label_ids.push $("#issue_#{issue_id}").data('labels') _.intersection.apply _, label_ids