labels_select.js.coffee 13.3 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
      $dropdown = $(dropdown)
P
Phil Hughes 已提交
7
      $toggleText = $dropdown.find('.dropdown-toggle-text')
P
Phil Hughes 已提交
8 9
      projectId = $dropdown.data('project-id')
      labelUrl = $dropdown.data('labels')
10
      issueUpdateURL = $dropdown.data('issueUpdate')
P
Phil Hughes 已提交
11
      selectedLabel = $dropdown.data('selected')
J
Jacob Schatz 已提交
12
      if selectedLabel? and not $dropdown.hasClass 'js-multiselect'
13
        selectedLabel = selectedLabel.split(',')
A
Alfredo Sumaran 已提交
14 15
      newLabelField = $('#new_label_name')
      newColorField = $('#new_label_color')
P
Phil Hughes 已提交
16 17
      showNo = $dropdown.data('show-no')
      showAny = $dropdown.data('show-any')
18
      defaultLabel = $dropdown.data('default-label')
19
      abilityName = $dropdown.data('ability-name')
20 21
      $selectbox = $dropdown.closest('.selectbox')
      $block = $selectbox.closest('.block')
22
      $form = $dropdown.closest('form')
23
      $sidebarCollapsedValue = $block.find('.sidebar-collapsed-icon span')
24
      $value = $block.find('.value')
A
Alfredo Sumaran 已提交
25 26 27
      $newLabelError = $('.js-label-error')
      $colorPreview = $('.js-dropdown-label-color-preview')
      $newLabelCreateButton = $('.js-new-label-btn')
28 29 30
      fieldName = $dropdown.data('field-name')
      useId = $dropdown.hasClass('js-issuable-form-dropdown') or $dropdown.hasClass('js-filter-bulk-update')
      propertyName = if useId then "id" else "title"
31

A
Alfredo Sumaran 已提交
32
      $newLabelError.hide()
33
      $loading = $block.find('.block-loading').fadeOut()
P
Phil Hughes 已提交
34

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

A
Alfredo Sumaran 已提交
48
      if newLabelField.length
A
Alfredo Sumaran 已提交
49 50

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

62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
        # 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()

78 79 80
        $('.js-cancel-label-btn').on 'click', (e) ->
          e.preventDefault()
          e.stopPropagation()
81
          resetForm()
82 83
          $('.dropdown-menu-back', $dropdown.parent()).trigger 'click'

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

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

            if label.message?
102 103 104
              errors = _.map label.message, (value, key) ->
                "#{key} #{value[0]}"

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

111 112 113 114 115 116 117 118 119 120
        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 已提交
121
            saveLabel()
122

123 124 125
      saveLabelData = ->
        selected = $dropdown
          .closest('.selectbox')
126
          .find("input[name='#{fieldName}']")
127 128 129 130 131 132 133 134 135
          .map(->
            @value
          ).get()
        data = {}
        data[abilityName] = {}
        data[abilityName].label_ids = selected
        if not selected.length
          data[abilityName].label_ids = ['']
        $loading.fadeIn()
J
Jacob Schatz 已提交
136
        $dropdown.trigger('loading.gl.dropdown')
137 138
        $.ajax(
          type: 'PUT'
139
          url: issueUpdateURL
A
Alfredo Sumaran 已提交
140
          dataType: 'JSON'
141 142 143
          data: data
        ).done (data) ->
          $loading.fadeOut()
J
Jacob Schatz 已提交
144
          $dropdown.trigger('loaded.gl.dropdown')
145
          $selectbox.hide()
J
Jacob Schatz 已提交
146
          data.issueURLSplit = issueURLSplit
147 148
          labelCount = 0
          if data.labels.length
149
            template = labelHTMLTemplate(data)
150 151
            labelCount = data.labels.length
          else
152
            template = labelNoneHTMLTemplate
153 154 155 156 157
          $value
            .removeAttr('style')
            .html(template)
          $sidebarCollapsedValue.text(labelCount)

158 159
          $('.has-tooltip', $value).tooltip(container: 'body')

160 161 162 163
          $value
            .find('a')
            .each((i) ->
              setTimeout(=>
164
                gl.animate.animate($(@), 'pulse')
165 166 167 168
              ,200 * i
              )
            )

169

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

190
            if $dropdown.hasClass 'js-extra-options'
191
              extraData = []
192
              if showAny
193
                extraData.push(
194 195 196 197
                  isAny: true
                  title: 'Any Label'
                )

198 199 200 201 202 203 204 205 206
              if showNo
                extraData.push(
                  id: 0
                  title: 'No Label'
                )

              if extraData.length
                extraData.push 'divider'
                data = extraData.concat(data)
207

208
            callback data
209

A
Alfredo Sumaran 已提交
210
        renderRow: (label, instance) ->
A
Alfredo Sumaran 已提交
211 212 213
          $li = $('<li>')
          $a  = $('<a href="#">')

A
Alfredo Sumaran 已提交
214
          selectedClass = []
215
          removesAll = label.id is 0 or not label.id?
216

A
Alfredo Sumaran 已提交
217
          if $dropdown.hasClass('js-filter-bulk-update')
A
typo  
Alfredo Sumaran 已提交
218
            indeterminate = instance.indeterminateIds
219 220
            active = instance.activeIds

A
typo  
Alfredo Sumaran 已提交
221
            if indeterminate.indexOf(label.id) isnt -1
222
              selectedClass.push 'is-indeterminate'
A
Alfredo Sumaran 已提交
223

224 225 226 227 228 229 230 231 232 233
            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

234
          if $form.find("input[type='hidden']\
235
            [name='#{$dropdown.data('fieldName')}']\
236
            [value='#{this.id(label)}']").length
237 238 239 240
            selectedClass.push 'is-active'

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

242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262
          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 已提交
263

A
Alfredo Sumaran 已提交
264 265
          # We need to identify which items are actually labels
          if label.id
A
Alfredo Sumaran 已提交
266 267
            selectedClass.push('label-item')
            $a.attr('data-label-id', label.id)
A
Alfredo Sumaran 已提交
268

A
Alfredo Sumaran 已提交
269
          $a.addClass(selectedClass.join(' '))
270
            .html("#{colorEl} #{label.title}")
A
Alfredo Sumaran 已提交
271

A
Alfredo Sumaran 已提交
272 273
          # Return generated html
          $li.html($a).prop('outerHTML')
A
Alfredo Sumaran 已提交
274
        persistWhenHide: $dropdown.data('persistWhenHide')
275
        search:
276
          fields: ['title']
277
        selectable: true
278
        filterable: true
279 280 281
        toggleLabel: (selected, el, glDropdown) ->
          if glDropdown?
            selectedIds = $("input[name='#{fieldName}']").map(-> $(this).val()).get()
P
Phil Hughes 已提交
282

283 284
            selected = _.filter glDropdown.fullData, (label) ->
              selectedIds.indexOf("#{label[propertyName]}") >= 0 if label[propertyName]?
285

286 287 288 289
            if selected.length is 1
              selected[0].title
            else if selected.length > 1
              "#{selected[0].title} +#{selected.length - 1} more"
290
            else
291
              defaultLabel
P
Phil Hughes 已提交
292
        defaultLabel: defaultLabel
293
        fieldName: fieldName
294
        id: (label) ->
295 296 297 298 299 300
          if $dropdown.hasClass('js-issuable-form-dropdown')
            if label.id is 0
              return
            else
              return label.id

301
          if $dropdown.hasClass("js-filter-submit") and not label.isAny?
302
            label.title
303 304 305 306
          else
            label.id

        hidden: ->
J
Jacob Schatz 已提交
307 308
          page = $('body').data 'page'
          isIssueIndex = page is 'projects:issues:index'
A
Arinde Eniola 已提交
309
          isMRIndex = page is 'projects:merge_requests:index'
310

311
          $selectbox.hide()
312 313
          # display:block overrides the hide-collapse rule
          $value.removeAttr('style')
314 315 316

          return if $dropdown.hasClass('js-issuable-form-dropdown')

317
          if $dropdown.hasClass 'js-multiselect'
J
Jacob Schatz 已提交
318
            if $dropdown.hasClass('js-filter-submit') and (isIssueIndex or isMRIndex)
319 320
              selectedLabels = $dropdown
                .closest('form')
A
Arinde Eniola 已提交
321
                .find("input:hidden[name='#{$dropdown.data('fieldName')}']")
P
Phil Hughes 已提交
322
              Issuable.filterResults $dropdown.closest('form')
J
Jacob Schatz 已提交
323 324 325
            else if $dropdown.hasClass('js-filter-submit')
              $dropdown.closest('form').submit()
            else
326 327 328 329
              if not $dropdown.hasClass 'js-filter-bulk-update'
                saveLabelData()

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

J
Jacob Schatz 已提交
334
        multiSelect: $dropdown.hasClass 'js-multiselect'
P
Phil Hughes 已提交
335
        clicked: (label) ->
336 337
          _this.enableBulkLabelDropdown()

338
          if $dropdown.hasClass('js-filter-bulk-update') or $dropdown.hasClass('js-issuable-form-dropdown')
339 340
            return

P
Phil Hughes 已提交
341 342
          page = $('body').data 'page'
          isIssueIndex = page is 'projects:issues:index'
A
Arinde Eniola 已提交
343
          isMRIndex = page is 'projects:merge_requests:index'
P
Phil Hughes 已提交
344
          if $dropdown.hasClass('js-filter-submit') and (isIssueIndex or isMRIndex)
345 346
            if not $dropdown.hasClass 'js-multiselect'
              selectedLabel = label.title
P
Phil Hughes 已提交
347
              Issuable.filterResults $dropdown.closest('form')
P
Phil Hughes 已提交
348 349
          else if $dropdown.hasClass 'js-filter-submit'
            $dropdown.closest('form').submit()
350
          else
351 352 353 354
            if $dropdown.hasClass 'js-multiselect'
              return
            else
              saveLabelData()
A
Alfredo Sumaran 已提交
355

A
typo  
Alfredo Sumaran 已提交
356
        setIndeterminateIds: ->
A
Alfredo Sumaran 已提交
357
          if @dropdown.find('.dropdown-menu-toggle').hasClass('js-filter-bulk-update')
A
typo  
Alfredo Sumaran 已提交
358
            @indeterminateIds = _this.getIndeterminateIds()
359 360 361 362

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

365 366 367 368 369 370 371 372 373 374 375 376 377 378
    @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 已提交
379
  getIndeterminateIds: ->
A
Alfredo Sumaran 已提交
380 381 382 383 384 385 386
    label_ids = []

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

    _.flatten(label_ids)
387 388 389 390 391 392 393 394 395

  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
396 397 398 399

  enableBulkLabelDropdown: ->
    if $('.selected_issue:checked').length
      issuableBulkActions = $('.bulk-update').data('bulkActions')
400
      issuableBulkActions.willUpdateLabels = true