BigW Consortium Gitlab

gfm_auto_complete.js.coffee 5.88 KB
Newer Older
1
# Creates the variables for setting up GFM auto-completion
2

Riyad Preukschas committed
3
window.GitLab ?= {}
4
GitLab.GfmAutoComplete =
5
  dataLoading: false
6
  dataLoaded: false
7

8
  dataSource: ''
9

10
  # Emoji
11
  Emoji:
12
    template: '<li>${name} <img alt="${name}" height="20" src="${path}" width="20" /></li>'
13

14
  # Team Members
15
  Members:
16
    template: '<li>${username} <small>${title}</small></li>'
17

18
  Labels:
19
    template: '<li><span class="dropdown-label-box" style="background: ${color}"></span> ${title}</li>'
20

21
  # Issues and MergeRequests
22
  Issues:
23
    template: '<li><small>${id}</small> ${title}</li>'
24

25 26 27 28
  # Milestones
  Milestones:
    template: '<li>${title}</li>'

29 30 31 32 33 34 35 36 37 38 39 40 41
  Loading:
    template: '<li><i class="fa fa-refresh fa-spin"></i> Loading...</li>'

  DefaultOptions:
    sorter: (query, items, searchKey) ->
      return items if items[0].name? and items[0].name is 'loading'

      $.fn.atwho.default.callbacks.sorter(query, items, searchKey)
    filter: (query, data, searchKey) ->
      return data if data[0] is 'loading'

      $.fn.atwho.default.callbacks.filter(query, data, searchKey)
    beforeInsert: (value) ->
42
      if not GitLab.GfmAutoComplete.dataLoaded
43 44 45 46
        @at
      else
        value

47
  # Add GFM auto-completion to all input fields, that accept GFM input.
48 49 50 51 52 53 54 55 56 57 58 59
  setup: (wrap) ->
    @input = $('.js-gfm-input')

    # destroy previous instances
    @destroyAtWho()

    # set up instances
    @setupAtWho()

    if @dataSource
      if !@dataLoading
        @dataLoading = true
60

61 62 63 64 65 66 67 68 69 70 71 72 73 74
        # We should wait until initializations are done
        # and only trigger the last .setup since
        # The previous .dataSource belongs to the previous issuable
        # and the last one will have the **proper** .dataSource property
        # TODO: Make this a singleton and turn off events when moving to another page
        setTimeout( =>
          fetch = @fetchData(@dataSource)
          fetch.done (data) =>
            @dataLoading = false
            @loadData(data)
        , 1000)


  setupAtWho: ->
75
    # Emoji
76
    @input.atwho
77
      at: ':'
78 79 80 81 82
      displayTpl: (value) =>
        if value.path?
          @Emoji.template
        else
          @Loading.template
83
      insertTpl: ':${name}:'
84 85 86 87 88
      data: ['loading']
      callbacks:
        sorter: @DefaultOptions.sorter
        filter: @DefaultOptions.filter
        beforeInsert: @DefaultOptions.beforeInsert
89 90

    # Team Members
91
    @input.atwho
92
      at: '@'
93 94 95 96 97
      displayTpl: (value) =>
        if value.username?
          @Members.template
        else
          @Loading.template
98 99
      insertTpl: '${atwho-at}${username}'
      searchKey: 'search'
100
      data: ['loading']
101
      callbacks:
102 103 104
        sorter: @DefaultOptions.sorter
        filter: @DefaultOptions.filter
        beforeInsert: @DefaultOptions.beforeInsert
105
        beforeSave: (members) ->
106
          $.map members, (m) ->
107 108
            return m if not m.username?

109 110 111 112 113 114
            title = m.name
            title += " (#{m.count})" if m.count

            username: m.username
            title:    sanitize(title)
            search:   sanitize("#{m.username} #{m.name}")
115

116
    @input.atwho
117 118
      at: '#'
      alias: 'issues'
119
      searchKey: 'search'
120 121 122 123 124 125
      displayTpl:  (value) =>
        if value.title?
          @Issues.template
        else
          @Loading.template
      data: ['loading']
126
      insertTpl: '${atwho-at}${id}'
127
      callbacks:
128 129 130
        sorter: @DefaultOptions.sorter
        filter: @DefaultOptions.filter
        beforeInsert: @DefaultOptions.beforeInsert
131
        beforeSave: (issues) ->
132
          $.map issues, (i) ->
133 134
            return i if not i.title?

135 136 137
            id:     i.iid
            title:  sanitize(i.title)
            search: "#{i.iid} #{i.title}"
138

139 140 141 142
    @input.atwho
      at: '%'
      alias: 'milestones'
      searchKey: 'search'
143 144 145 146 147
      displayTpl:  (value) =>
        if value.title?
          @Milestones.template
        else
          @Loading.template
148
      insertTpl: '${atwho-at}"${title}"'
149
      data: ['loading']
150 151 152
      callbacks:
        beforeSave: (milestones) ->
          $.map milestones, (m) ->
153 154
            return m if not m.title?

155 156 157 158
            id:     m.iid
            title:  sanitize(m.title)
            search: "#{m.title}"

159
    @input.atwho
160 161
      at: '!'
      alias: 'mergerequests'
162
      searchKey: 'search'
163 164 165 166 167 168
      displayTpl:  (value) =>
        if value.title?
          @Issues.template
        else
          @Loading.template
      data: ['loading']
169
      insertTpl: '${atwho-at}${id}'
170
      callbacks:
171 172 173
        sorter: @DefaultOptions.sorter
        filter: @DefaultOptions.filter
        beforeInsert: @DefaultOptions.beforeInsert
174
        beforeSave: (merges) ->
175
          $.map merges, (m) ->
176 177
            return m if not m.title?

178 179 180
            id:     m.iid
            title:  sanitize(m.title)
            search: "#{m.iid} #{m.title}"
181

182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200
    @input.atwho
      at: '~'
      alias: 'labels'
      searchKey: 'search'
      displayTpl: @Labels.template
      insertTpl: '${atwho-at}${title}'
      callbacks:
        beforeSave: (merges) ->
          sanitizeLabelTitle = (title)->
            if /\w+\s+\w+/g.test(title)
              "\"#{sanitize(title)}\""
            else
              sanitize(title)

          $.map merges, (m) ->
            title: sanitizeLabelTitle(m.title)
            color: m.color
            search: "#{m.title}"

201 202 203 204 205 206 207
  destroyAtWho: ->
    @input.atwho('destroy')

  fetchData: (dataSource) ->
    $.getJSON(dataSource)

  loadData: (data) ->
208 209
    @dataLoaded = true

210 211 212 213
    # load members
    @input.atwho 'load', '@', data.members
    # load issues
    @input.atwho 'load', 'issues', data.issues
214 215
    # load milestones
    @input.atwho 'load', 'milestones', data.milestones
216 217 218 219
    # load merge requests
    @input.atwho 'load', 'mergerequests', data.mergerequests
    # load emojis
    @input.atwho 'load', ':', data.emojis
220 221
    # load labels
    @input.atwho 'load', '~', data.labels
222 223 224 225

    # This trigger at.js again
    # otherwise we would be stuck with loading until the user types
    $(':focus').trigger('keyup')