usersList._add   F
last analyzed

Complexity

Conditions 14
Paths 7

Size

Total Lines 133

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 14
c 1
b 0
f 1
nc 7
nop 0
dl 0
loc 133
rs 2.52

1 Function

Rating   Name   Duplication   Size   Complexity  
B 0 63 4

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Complexity

Complex classes like usersList._add often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
/*global document, confirm, $ */
2
3
import Nanoajax from 'nanoajax'
4
import qs from 'qs'
5
6
var usersList = {
7
  init: function() {
8
    var scope = document.querySelector('.user-list')
9
    if (scope != null) {
10
      this._ajax = Nanoajax.ajax
11
12
      this._scope = scope
13
      this._table = this._scope.querySelector('#filtered-list tbody')
14
      this._alert = document.querySelector('.alert')
15
      this._handleActivate = this._activate.bind(this)
16
      this._handleDeactivate = this._deactivate.bind(this)
17
      this._handleRemove = this._remove.bind(this)
18
      this._handleEdit = this._edit.bind(this)
19
      this._handleUpdate = this._update.bind(this)
20
      this._handleCloseUpdate = this._closeUpdate.bind(this)
21
      this._handleAdd = this._add.bind(this)
22
23
      this._bindEvents()
24
    }
25
26
    if (document.querySelectorAll('#filtered-list').length > 0) {
27
      var orderables = document.querySelectorAll('#filtered-list thead th')
28
      var columns = []
29
      Array.prototype.forEach.call(orderables, orderable => {
30
        var order = orderable.getAttribute('data-orderable')
31
        if (order != null) {
32
          columns.push({orderable: order == 'true' ? true : false})
33
        } else {
34
          columns.push(null)
35
        }
36
      })
37
      this.table = $('#filtered-list').DataTable({
38
        paging: false,
39
        info: false,
40
        columns: columns
41
      })
42
    }
43
44
    if (document.querySelectorAll('#filtered-list-url').length > 0) {
45
      this._handleFormUserRoleSubmit = this._formUserRoleSubmit.bind(this)
46
47
      this._formUserRole = document.querySelector('[data-user-role]')
48
      this._formUserRoleSave = document.querySelector('[data-save-user-role]')
49
50
      if (
51
        typeof this._formUserRole !== 'undefined' &&
52
        this._formUserRole !== null
53
      ) {
54
        this._formUserRole.addEventListener(
55
          'submit',
56
          this._handleFormUserRoleSubmit
57
        )
58
      }
59
    }
60
  },
61
  _bindEvents: function() {
62
    this._activateBtn = this._scope.querySelectorAll('[data-activate]')
63
    this._deactivateBtn = this._scope.querySelectorAll('[data-deactivate]')
64
    this._removeBtn = this._scope.querySelectorAll('[data-remove]')
65
    this._editBtn = this._scope.querySelectorAll('[data-edit]')
66
    this._updateBtn = this._scope.querySelectorAll('[data-update]')
67
    this._addBtn = this._scope.querySelector('[data-add-user]')
68
69
    Array.prototype.forEach.call(this._activateBtn, btn => {
70
      btn.removeEventListener('click', this._handleActivate)
71
      btn.addEventListener('click', this._handleActivate)
72
    })
73
74
    Array.prototype.forEach.call(this._deactivateBtn, btn => {
75
      btn.removeEventListener('click', this._handleDeactivate)
76
      btn.addEventListener('click', this._handleDeactivate)
77
    })
78
79
    Array.prototype.forEach.call(this._removeBtn, btn => {
80
      btn.removeEventListener('click', this._handleRemove)
81
      btn.addEventListener('click', this._handleRemove)
82
    })
83
84
    Array.prototype.forEach.call(this._editBtn, btn => {
85
      btn.removeEventListener('click', this._handleEdit, true)
86
      btn.addEventListener('click', this._handleEdit, true)
87
    })
88
89
    Array.prototype.forEach.call(this._updateBtn, btn => {
90
      btn.removeEventListener('click', this._handleUpdate, true)
91
      btn.addEventListener('click', this._handleUpdate, true)
92
    })
93
94
    if (typeof this._addBtn !== 'undefined' && this._addBtn !== null) {
95
      this._addBtn.addEventListener('click', this._handleAdd)
96
    }
97
  },
98
  _formUserRoleSubmit: function(e) {
99
    e.preventDefault()
100
101
    var inputs = this._formUserRole.querySelectorAll('input[type=checkbox]')
102
    var data = {}
103
    Array.prototype.forEach.call(inputs, input => {
104
      if (!input.disabled) {
105
        var name = input.getAttribute('name')
106
        if (data[name] == null) {
107
          data[name] = []
108
        }
109
        if (input.checked) {
110
          data[name].push(input.getAttribute('value'))
111
        }
112
      }
113
    })
114
115
    var toSave = qs.stringify(data)
116
117
    this._ajax(
118
      {
119
        url: '/abe/list-url/save',
120
        body: toSave,
121
        method: 'post'
122
      },
123
      () => {}
124
    )
125
  },
126
  _activate: function(e) {
127
    var target = e.currentTarget
128
    var id = target.getAttribute('data-user-id')
129
130
    var toSave = qs.stringify({
131
      id: id
132
    })
133
134
    this._ajax(
135
      {
136
        url: '/abe/users/activate',
137
        body: toSave,
138
        method: 'post'
139
      },
140
      () => {
141
        var childGlyph = target.querySelector('.glyphicon')
142
        childGlyph.classList.remove('glyphicon-eye-open', 'text-info')
143
        childGlyph.classList.add('glyphicon-eye-close', 'text-danger')
144
        target.classList.remove('glyphicon-eye-close', 'text-danger')
145
        target.classList.add('glyphicon-eye-open', 'text-info')
146
        target.removeEventListener('click', this._handleActivate)
147
        target.addEventListener('click', this._handleDeactivate)
148
      }
149
    )
150
  },
151
  _deactivate: function(e) {
152
    var target = e.currentTarget
153
    var id = target.getAttribute('data-user-id')
154
155
    var toSave = qs.stringify({
156
      id: id
157
    })
158
159
    this._ajax(
160
      {
161
        url: '/abe/users/deactivate',
162
        body: toSave,
163
        method: 'post'
164
      },
165
      () => {
166
        var childGlyph = target.querySelector('.glyphicon')
167
        childGlyph.classList.remove('glyphicon-eye-close', 'text-danger')
168
        childGlyph.classList.add('glyphicon-eye-open', 'text-info')
169
        target.classList.remove('glyphicon-eye-open', 'text-info')
170
        target.classList.add('glyphicon-eye-close', 'text-danger')
171
        target.removeEventListener('click', this._handleDeactivate)
172
        target.addEventListener('click', this._handleActivate)
173
      }
174
    )
175
  },
176
  _edit: function(e) {
177
    var parent = e.currentTarget.parentNode.parentNode
178
    e.currentTarget.removeEventListener('click', this._handleEdit, true)
179
180
    parent.classList.add('editing')
181
    var closeUpdateBtn = parent.querySelector('[data-close-update]')
182
    closeUpdateBtn.removeEventListener('click', this._handleCloseUpdate)
183
    closeUpdateBtn.addEventListener('click', this._handleCloseUpdate)
184
  },
185
  _closeFormUpdate(target) {
186
    var parent = target.parentNode.parentNode.parentNode
187
    var edit = parent.querySelector('[data-edit]')
188
    parent.classList.remove('editing')
189
    edit.addEventListener('click', this._handleEdit, true)
190
    target.removeEventListener('click', this._handleCloseUpdate)
191
  },
192
  _closeUpdate: function(e) {
193
    this._closeFormUpdate(e.currentTarget)
194
  },
195
  _update: function(e) {
196
    var parent = e.currentTarget.parentNode.parentNode.parentNode
197
    var target = e.currentTarget
198
    var data = {
199
      id: target.getAttribute('data-user-id')
200
    }
201
202
    var inputs = parent.querySelectorAll('.form-control')
203
    var msg = ''
204
    var hasError = false
205
    Array.prototype.forEach.call(
206
      inputs,
207
      function(input) {
208
        data[input.name] = input.value
209
210
        if (input.name === 'email' && !this._validateEmail(input.value)) {
211
          hasError = true
212
          input.parentNode.classList.add('has-error')
213
          this._alert.classList.remove('hidden')
214
          msg += 'email is invalid<br />'
215
          return
0 ignored issues
show
Unused Code introduced by
This return has no effect and can be removed.
Loading history...
216
        } else if (input.value.trim() === '') {
217
          hasError = true
218
          input.parentNode.classList.add('has-error')
219
          this._alert.classList.remove('hidden')
220
          msg += input.name + ' is invalid<br />'
221
          return
0 ignored issues
show
Unused Code introduced by
This return has no effect and can be removed.
Loading history...
222
        } else {
223
          input.parentNode.classList.remove('has-error')
224
        }
225
      }.bind(this)
226
    )
227
228
    if (hasError) {
229
      this._alert.innerHTML = msg
230
      return
231
    } else {
232
      this._alert.classList.add('hidden')
233
      this._alert.innerHTML = ''
234
    }
235
    var toSave = qs.stringify(data)
236
237
    this._ajax(
238
      {
239
        url: '/abe/users/update',
240
        body: toSave,
241
        method: 'post'
242
      },
243
      (code, responseText) => {
244
        var response = JSON.parse(responseText)
245
        if (response.success === 1) {
246
          Array.prototype.forEach.call(inputs, function(input) {
247
            input.parentNode.parentNode.querySelector('.value').innerHTML =
248
              input.value
249
          })
250
          this._closeFormUpdate(target)
251
        } else {
252
          this._alert.classList.remove('hidden')
253
          this._alert.innerHTML = response.message
254
        }
255
      }
256
    )
257
  },
258
  _remove: function(e) {
259
    var confirmDelete = confirm(e.currentTarget.getAttribute('data-text'))
260
    if (!confirmDelete) return
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
261
262
    var target = e.currentTarget
263
    var id = target.getAttribute('data-user-id')
264
    var toSave = qs.stringify({
265
      id: id
266
    })
267
268
    this._ajax(
269
      {
270
        url: '/abe/users/remove',
271
        body: toSave,
272
        method: 'post'
273
      },
274
      () => {
275
        target.parentNode.parentNode.remove()
276
      }
277
    )
278
  },
279
  _validateEmail: function(email) {
280
    var re = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
281
    return re.test(email)
282
  },
283
  _add: function() {
284
    this._alert.classList.add('hidden')
285
    var username = document.querySelector('[data-add-user-username]')
286
    if (
287
      typeof username.value === 'undefined' ||
288
      username.value === null ||
289
      username.value === ''
290
    ) {
291
      username.parentNode.classList.add('has-error')
292
      return
293
    }
294
    username.parentNode.classList.remove('has-error')
295
296
    var name = document.querySelector('[data-add-user-name]')
297
    if (
298
      typeof name.value === 'undefined' ||
299
      name.value === null ||
300
      name.value === ''
301
    ) {
302
      name.parentNode.classList.add('has-error')
303
      return
304
    }
305
    name.parentNode.classList.remove('has-error')
306
307
    var email = document.querySelector('[data-add-user-email]')
308
    if (
309
      typeof email.value === 'undefined' ||
310
      email.value === null ||
311
      email.value === ''
312
    ) {
313
      email.parentNode.classList.add('has-error')
314
      return
315
    }
316
    if (!this._validateEmail(email.value)) {
317
      email.parentNode.classList.add('has-error')
318
      this._alert.classList.remove('hidden')
319
      this._alert.innerHTML = 'email is invalid'
320
      return
321
    }
322
    email.parentNode.classList.remove('has-error')
323
324
    var password = document.querySelector('[data-add-user-password]')
325
    if (
326
      typeof password.value === 'undefined' ||
327
      password.value === null ||
328
      password.value === ''
329
    ) {
330
      password.parentNode.classList.add('has-error')
331
      return
332
    }
333
334
    password.parentNode.classList.remove('has-error')
335
336
    var role = document.querySelector('[data-add-user-role]')
337
    var toSave = qs.stringify({
338
      username: username.value,
339
      name: name.value,
340
      email: email.value,
341
      password: password.value,
342
      role: role.value
343
    })
344
345
    this._ajax(
346
      {
347
        url: '/abe/users/add',
348
        body: toSave,
349
        method: 'post'
350
      },
351
      (code, responseText) => {
352
        var data = JSON.parse(responseText)
353
        if (data.success === 1) {
354
          var tr = document.createElement('tr')
355
          var oldTr = document.querySelector('[data-user-base]')
356
          if (typeof oldTr !== 'undefined' && oldTr !== null) {
357
            tr.innerHTML = oldTr.innerHTML
358
359
            var tdUsername = tr.querySelector('.td-username')
360
            tdUsername.querySelector('.value').innerHTML = data.user.username
361
            tdUsername.querySelector('input').value = data.user.username
362
363
            var tdName = tr.querySelector('.td-name')
364
            tdName.querySelector('.value').innerHTML = data.user.name
365
            tdName.querySelector('input').value = data.user.name
366
367
            var tdEmail = tr.querySelector('.td-email')
368
            tdEmail.querySelector('.value').innerHTML = data.user.email
369
            tdEmail.querySelector('input').value = data.user.email
370
371
            var tdRole = tr.querySelector('.td-role')
372
            tdRole.querySelector('.value').innerHTML = data.user.role.name
373
            var tdRoleOptions = tdRole.querySelectorAll('select option')
374
            Array.prototype.forEach.call(tdRoleOptions, function(option) {
375
              if (option.value === data.user.role.name) {
376
                option.selected = 'selected'
377
              }
378
            })
379
380
            var tdActive = tr.querySelector('.td-active')
381
            var glypEyeClose = tdActive.querySelector('.glyphicon-eye-close')
382
            glypEyeClose.addEventListener('click', this._handleActivate, true)
383
            glypEyeClose.setAttribute('data-user-id', data.user.id)
384
385
            var tdActions = tr.querySelector('.td-actions')
386
            var glypEdit = tdActions.querySelector('.glyphicon-pencil')
387
            glypEdit.addEventListener('click', this._handleEdit, true)
388
            glypEdit.setAttribute('data-user-id', data.user.id)
389
390
            var glypOk = tdActions.querySelector('.glyphicon-ok')
391
            glypOk.addEventListener('click', this._handleUpdate, true)
392
            glypOk.setAttribute('data-user-id', data.user.id)
393
394
            var glypCloseUpdate = tdActions.querySelector('.glyphicon-remove')
395
            glypCloseUpdate.setAttribute('data-user-id', data.user.id)
396
            // glypCloseUpdate.addEventListener('click', this._handleCloseUpdate, true)
397
398
            var glypRemove = tdActions.querySelector('.glyphicon-trash')
399
            glypRemove.setAttribute('data-user-id', data.user.id)
400
            glypRemove.addEventListener('click', this._handleRemove, true)
401
          }
402
403
          this._table.appendChild(tr)
404
405
          username.value = ''
406
          name.value = ''
407
          email.value = ''
408
          password.value = ''
409
        } else {
410
          this._alert.classList.remove('hidden')
411
          this._alert.innerHTML = data.message
412
        }
413
      }
414
    )
415
  }
416
}
417
418
export default usersList
419
420
// var userListEle = document.querySelector('.user-list');
421
// if(typeof userListEle !== 'undefined' && userListEle !== null) {
422
//   usersList.init(userListEle)
423
// }
424