labels_select.js.coffee 12.6 KB
Newer Older
1 2
class @LabelsSelect
  constructor: ->
A
Alfredo Sumaran 已提交
3 4
    _this = @

5
    $('.js-label-select').each (i, dropdown) ->
P
Phil Hughes 已提交
6 7 8
      $dropdown = $(dropdown)
      projectId = $dropdown.data('project-id')
      labelUrl = $dropdown.data('labels')
9
      issueUpdateURL = $dropdown.data('issueUpdate')
P
Phil Hughes 已提交
10
      selectedLabel = $dropdown.data('selected')
J
Jacob Schatz 已提交
11
      if selectedLabel? and not $dropdown.hasClass 'js-multiselect'
12
        selectedLabel = selectedLabel.split(',')
A
Alfredo Sumaran 已提交
13 14
      newLabelField = $('#new_label_name')
      newColorField = $('#new_label_color')
P
Phil Hughes 已提交
15 16
      showNo = $dropdown.data('show-no')
      showAny = $dropdown.data('show-any')
17
      defaultLabel = $dropdown.data('default-label')
18
      abilityName = $dropdown.data('ability-name')
19 20
      $selectbox = $dropdown.closest('.selectbox')
      $block = $selectbox.closest('.block')
21
      $form = $dropdown.closest('form')
22
      $sidebarCollapsedValue = $block.find('.sidebar-collapsed-icon span')
23
      $value = $block.find('.value')
A
Alfredo Sumaran 已提交
24 25 26
      $newLabelError = $('.js-label-error')
      $colorPreview = $('.js-dropdown-label-color-preview')
      $newLabelCreateButton = $('.js-new-label-btn')
A
Alfredo Sumaran 已提交
27 28

      $newLabelError.hide()
29
      $loading = $block.find('.block-loading').fadeOut()
P
Phil Hughes 已提交
30

31 32
      issueURLSplit = issueUpdateURL.split('/') if issueUpdateURL?
      if issueUpdateURL
33
        labelHTMLTemplate = _.template(
34
            '<% _.each(labels, function(label){ %>
35
            <a href="<%= ["",issueURLSplit[1], issueURLSplit[2],""].join("/") %>issues?label_name[]=<%= _.escape(label.title) %>">
36
            <span class="label has-tooltip color-label" title="<%= _.escape(label.description) %>" style="background-color: <%= label.color %>; color: <%= label.text_color %>;">
37
            <%= _.escape(label.title) %>
38 39 40
            </span>
            </a>
            <% }); %>'
41
        )
42
        labelNoneHTMLTemplate = '<span class="no-value">None</span>'
43

A
Alfredo Sumaran 已提交
44
      if newLabelField.length
A
Alfredo Sumaran 已提交
45 46

        # Suggested colors in the dropdown to chose from pre-chosen colors
47
        $('.suggest-colors-dropdown a').on "click", (e) ->
P
Phil Hughes 已提交
48 49
          e.preventDefault()
          e.stopPropagation()
50 51 52 53
          newColorField
            .val($(this).data('color'))
            .trigger('change')
          $colorPreview
P
Phil Hughes 已提交
54
            .css 'background-color', $(this).data('color')
55
            .parent()
P
Phil Hughes 已提交
56 57
            .addClass 'is-active'

58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
        # 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()

74 75 76
        $('.js-cancel-label-btn').on 'click', (e) ->
          e.preventDefault()
          e.stopPropagation()
77
          resetForm()
78 79
          $('.dropdown-menu-back', $dropdown.parent()).trigger 'click'

80 81 82
        # Listen for change and keyup events on label and color field
        # This allows us to enable the button when ready
        enableLabelCreateButton = ->
P
Phil Hughes 已提交
83
          if newLabelField.val() isnt '' and newColorField.val() isnt ''
84
            $newLabelError.hide()
85 86 87 88
            $newLabelCreateButton.enable()
          else
            $newLabelCreateButton.disable()

A
Alfredo Sumaran 已提交
89 90 91 92 93 94 95 96 97
        saveLabel = ->
          # Create new label with API
          Api.newLabel projectId, {
            name: newLabelField.val()
            color: newColorField.val()
          }, (label) ->
            $newLabelCreateButton.enable()

            if label.message?
98 99 100
              errors = _.map label.message, (value, key) ->
                "#{key} #{value[0]}"

A
Alfredo Sumaran 已提交
101
              $newLabelError
102
                .html errors.join("<br/>")
A
Alfredo Sumaran 已提交
103 104 105 106
                .show()
            else
              $('.dropdown-menu-back', $dropdown.parent()).trigger 'click'

107 108 109 110 111 112 113 114 115 116
        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()
A
Alfredo Sumaran 已提交
117
            saveLabel()
118

119 120 121 122 123 124 125 126 127 128 129 130 131
      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()
J
Jacob Schatz 已提交
132
        $dropdown.trigger('loading.gl.dropdown')
133 134
        $.ajax(
          type: 'PUT'
135
          url: issueUpdateURL
A
Alfredo Sumaran 已提交
136
          dataType: 'JSON'
137 138 139
          data: data
        ).done (data) ->
          $loading.fadeOut()
J
Jacob Schatz 已提交
140
          $dropdown.trigger('loaded.gl.dropdown')
141
          $selectbox.hide()
J
Jacob Schatz 已提交
142
          data.issueURLSplit = issueURLSplit
143 144
          labelCount = 0
          if data.labels.length
145
            template = labelHTMLTemplate(data)
146 147
            labelCount = data.labels.length
          else
148
            template = labelNoneHTMLTemplate
149 150 151 152 153
          $value
            .removeAttr('style')
            .html(template)
          $sidebarCollapsedValue.text(labelCount)

154 155
          $('.has-tooltip', $value).tooltip(container: 'body')

156 157 158 159
          $value
            .find('a')
            .each((i) ->
              setTimeout(=>
160
                gl.animate.animate($(@), 'pulse')
161 162 163 164
              ,200 * i
              )
            )

165

P
Phil Hughes 已提交
166
      $dropdown.glDropdown(
P
Phil Hughes 已提交
167
        data: (term, callback) ->
168 169 170
          $.ajax(
            url: labelUrl
          ).done (data) ->
171 172 173 174 175 176 177 178 179 180 181 182 183 184 185
            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()

186 187 188 189 190 191 192 193 194 195 196 197 198 199 200
            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'
201

202
            callback data
203

A
Alfredo Sumaran 已提交
204
        renderRow: (label, instance) ->
A
Alfredo Sumaran 已提交
205 206 207
          $li = $('<li>')
          $a  = $('<a href="#">')

A
Alfredo Sumaran 已提交
208
          selectedClass = []
209
          removesAll = label.id is 0 or not label.id?
210

A
Alfredo Sumaran 已提交
211
          if $dropdown.hasClass('js-filter-bulk-update')
A
typo  
Alfredo Sumaran 已提交
212
            indeterminate = instance.indeterminateIds
213 214
            active = instance.activeIds

A
typo  
Alfredo Sumaran 已提交
215
            if indeterminate.indexOf(label.id) isnt -1
216
              selectedClass.push 'is-indeterminate'
A
Alfredo Sumaran 已提交
217

218 219 220 221 222 223 224 225 226 227
            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

228
          if $form.find("input[type='hidden']\
229
            [name='#{$dropdown.data('fieldName')}']\
230
            [value='#{this.id(label)}']").length
231 232 233 234
            selectedClass.push 'is-active'

          if $dropdown.hasClass('js-multiselect') and removesAll
            selectedClass.push 'dropdown-clear-active'
P
Phil Hughes 已提交
235

236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256
          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 = ''
P
Phil Hughes 已提交
257

A
Alfredo Sumaran 已提交
258 259
          # We need to identify which items are actually labels
          if label.id
A
Alfredo Sumaran 已提交
260 261
            selectedClass.push('label-item')
            $a.attr('data-label-id', label.id)
A
Alfredo Sumaran 已提交
262

A
Alfredo Sumaran 已提交
263 264
          $a.addClass(selectedClass.join(' '))
            .html("#{colorEl} #{_.escape(label.title)}")
A
Alfredo Sumaran 已提交
265

A
Alfredo Sumaran 已提交
266 267
          # Return generated html
          $li.html($a).prop('outerHTML')
A
Alfredo Sumaran 已提交
268
        persistWhenHide: $dropdown.data('persistWhenHide')
269
        search:
270
          fields: ['title']
271
        selectable: true
272
        filterable: true
273 274 275
        toggleLabel: (selected, el) ->
          selected_labels = $('.js-label-select').siblings('.dropdown-menu-labels').find('.is-active')

276
          if selected and selected.title?
A
Arinde Eniola 已提交
277
            if selected_labels.length > 1
278 279 280 281 282 283 284 285
              "#{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()
286 287
          else
            defaultLabel
P
Phil Hughes 已提交
288
        fieldName: $dropdown.data('field-name')
289
        id: (label) ->
290
          if $dropdown.hasClass("js-filter-submit") and not label.isAny?
P
Phil Hughes 已提交
291
            _.escape label.title
292 293 294 295
          else
            label.id

        hidden: ->
J
Jacob Schatz 已提交
296 297
          page = $('body').data 'page'
          isIssueIndex = page is 'projects:issues:index'
A
Arinde Eniola 已提交
298
          isMRIndex = page is 'projects:merge_requests:index'
299

300
          $selectbox.hide()
301 302
          # display:block overrides the hide-collapse rule
          $value.removeAttr('style')
303
          if $dropdown.hasClass 'js-multiselect'
J
Jacob Schatz 已提交
304
            if $dropdown.hasClass('js-filter-submit') and (isIssueIndex or isMRIndex)
305 306
              selectedLabels = $dropdown
                .closest('form')
A
Arinde Eniola 已提交
307
                .find("input:hidden[name='#{$dropdown.data('fieldName')}']")
P
Phil Hughes 已提交
308
              Issuable.filterResults $dropdown.closest('form')
J
Jacob Schatz 已提交
309 310 311
            else if $dropdown.hasClass('js-filter-submit')
              $dropdown.closest('form').submit()
            else
312 313 314 315
              if not $dropdown.hasClass 'js-filter-bulk-update'
                saveLabelData()

          if $dropdown.hasClass('js-filter-bulk-update')
A
Alfredo Sumaran 已提交
316 317 318
            # If we are persisting state we need the classes
            if not @options.persistWhenHide
              $dropdown.parent().find('.is-active, .is-indeterminate').removeClass()
319

J
Jacob Schatz 已提交
320
        multiSelect: $dropdown.hasClass 'js-multiselect'
P
Phil Hughes 已提交
321
        clicked: (label) ->
322 323 324
          if $dropdown.hasClass('js-filter-bulk-update')
            return

P
Phil Hughes 已提交
325 326
          page = $('body').data 'page'
          isIssueIndex = page is 'projects:issues:index'
A
Arinde Eniola 已提交
327
          isMRIndex = page is 'projects:merge_requests:index'
P
Phil Hughes 已提交
328
          if $dropdown.hasClass('js-filter-submit') and (isIssueIndex or isMRIndex)
329 330
            if not $dropdown.hasClass 'js-multiselect'
              selectedLabel = label.title
P
Phil Hughes 已提交
331
              Issuable.filterResults $dropdown.closest('form')
P
Phil Hughes 已提交
332 333
          else if $dropdown.hasClass 'js-filter-submit'
            $dropdown.closest('form').submit()
334
          else
335 336 337 338
            if $dropdown.hasClass 'js-multiselect'
              return
            else
              saveLabelData()
A
Alfredo Sumaran 已提交
339

A
typo  
Alfredo Sumaran 已提交
340
        setIndeterminateIds: ->
A
Alfredo Sumaran 已提交
341
          if @dropdown.find('.dropdown-menu-toggle').hasClass('js-filter-bulk-update')
A
typo  
Alfredo Sumaran 已提交
342
            @indeterminateIds = _this.getIndeterminateIds()
343 344 345 346

        setActiveIds: ->
          if @dropdown.find('.dropdown-menu-toggle').hasClass('js-filter-bulk-update')
            @activeIds = _this.getActiveIds()
347
      )
A
Alfredo Sumaran 已提交
348

349 350 351 352 353 354 355 356 357 358 359 360 361 362
    @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')

A
typo  
Alfredo Sumaran 已提交
363
  getIndeterminateIds: ->
A
Alfredo Sumaran 已提交
364 365 366 367 368 369 370
    label_ids = []

    $('.selected_issue:checked').each (i, el) ->
      issue_id = $(el).data('id')
      label_ids.push $("#issue_#{issue_id}").data('labels')

    _.flatten(label_ids)
371 372 373 374 375 376 377 378 379

  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