Completed
Push — master ( 9c8f6b...5df6dd )
by Jonathan
08:43
created

datatable.js ➔ launchSearch   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 14
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 9
nc 4
nop 2
dl 0
loc 14
rs 9.95
c 0
b 0
f 0

1 Function

Rating   Name   Duplication   Size   Complexity  
A datatable.js ➔ ... ➔ ??? 0 4 1
1
import 'datatables.net-bs';
2
import 'datatables.net-buttons-bs';
3
import 'datatables.net-buttons/js/buttons.colVis';
4
// import 'datatables.net-colreorder';
5
import 'datatables.net-fixedcolumns';
6
import 'datatables.net-responsive-bs';
7
import 'datatables.net-select';
8
import { sprintf } from 'sprintf-js'
9
import { Link } from './link'
10
11
export class Datatable {
12
    /**
13
     * Init Datatable configuration
14
     * @param {Element} element
15
     */
16
    init(element) {
17
        let linkManager = new Link(false)
18
19
        this.table = $(element).DataTable({
20
            dom: 'Brtp',
21
            autoWidth: false, // Else the width is not refreshed on window resize
22
            responsive: true,
23
            colReorder: false,
24
            serverSide: true,
25
            ajax: {
26
                url: this.url,
27
                type: "POST"
28
            },
29
            pageLength: this.getInitialPageLength(),
30
            order: this.getInitialOrder(),
31
            columnDefs: this.getDatatableColumnDefs(element),
32
            createdRow: (row, data, index) => {
0 ignored issues
show
Unused Code introduced by
The parameter index is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
33
                // Go to detail view when you click on a row
34
                $('td:gt(0):lt(-1)', row).click(() => {
35
                    document.location.href = sprintf(this.rowUrl, data.id);
36
                })
37
38
                // Init click listener on delete button
39
                linkManager.initClickListener(row)
40
41
                // Init click listener on the row if a callback is defined
42
                if (typeof this.rowClickCallback !== 'undefined') {
43
                    $(row).on('click', (event) => {
44
                        this.rowClickCallback(event, this.table, data)
45
                    })
46
                }
47
            },
48
            buttons: [
49
                {
50
                    extend: 'colvis',
51
                    columns: ':gt(0):lt(-1)'
52
                }
53
            ],
54
            language: {
55
                paginate: {
56
                    previous: '<',
57
                    next: '>'
58
                },
59
                buttons: {
60
                    colvis: uctrans('button.columns')
61
                }
62
            },
63
            aoSearchCols: this.getInitialSearch(),
64
65
        });
66
67
        // Config buttons
68
        this.configButtons()
69
70
        // Init search
71
        this.initDatatableColumnSearch()
72
    }
73
74
    /**
75
     * Make datatable columns from filter.
76
     * @param {Element} element
77
     * @return {array}
78
     */
79
    getDatatableColumnDefs(element) {
80
        let selector = new UccelloUitypeSelector.UitypeSelector() // UccelloUitypeSelector is replaced automaticaly by webpack. See webpack.mix.js
0 ignored issues
show
Bug introduced by
The variable UccelloUitypeSelector seems to be never declared. If this is a global, consider adding a /** global: UccelloUitypeSelector */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
81
82
        let datatableColumns = [];
83
84
        // Add first column
85
        datatableColumns.push({
86
            targets: 0,
87
            data: null,
88
            defaultContent: '',
89
            orderable: false,
90
            searchable: false
91
        })
92
93
        // Add all filter columns
94
        for (let i in this.columns) {
95
            let column = this.columns[i]
96
            datatableColumns.push({
97
                targets: parseInt(i) + 1, // Force integer
98
                data: column.name,
99
                orderable: true,
100
                createdCell: (td, cellData, rowData, row, col) => {
101
                    selector.get(column.uitype).createdCell(column, td, cellData, rowData, row, col)
102
                },
103
                visible: column.visible
104
            })
105
        }
106
107
        // Add last column (action buttons)
108
        datatableColumns.push({
109
            targets: this.columns.length + 1,
110
            data: null,
111
            defaultContent: '',
112
            orderable: false,
113
            searchable: false,
114
            createdCell: this.getActionsColumnCreatedCell(element)
115
        })
116
117
        return datatableColumns;
118
    }
119
120
    /**
121
     * Initialize initial columns search, according to selected filter conditions
122
     * @return {array}
123
     */
124
    getInitialSearch() {
125
        let search = []
126
127
        if (this.selectedFilter && this.selectedFilter.conditions && this.selectedFilter.conditions.search) {
128
            // First column
129
            search.push(null)
130
131
            for (let i in this.columns) {
132
                let value = null
0 ignored issues
show
Unused Code introduced by
The assignment to value seems to be never used. If you intend to free memory here, this is not necessary since the variable leaves the scope anyway.
Loading history...
133
134
                let column =  this.columns[i]
135
                value = typeof this.selectedFilter.conditions.search[column.name] !== 'undefined' ? this.selectedFilter.conditions.search[column.name] : null
136
137
                if (value) {
138
                    search.push({sSearch: value})
139
                } else {
140
                    search.push(null)
141
                }
142
            }
143
144
            // Last column
145
            search.push(null)
146
        }
147
148
        return search
149
    }
150
151
    /**
152
     * Get initial order
153
     * @return {array}
154
     */
155
    getInitialOrder() {
156
        let order = [[1, 'asc']] // Default
157
        if (this.selectedFilter && this.selectedFilter.data && this.selectedFilter.data.order) {
158
            order = this.selectedFilter.data.order
159
        }
160
161
        return order
162
    }
163
164
    /**
165
     * Get initial page length
166
     * @return {integer}
167
     */
168
    getInitialPageLength() {
169
        let length = 15 // Default
170
        if (this.selectedFilter && this.selectedFilter.data && this.selectedFilter.data.length) {
171
            length = this.selectedFilter.data.length
172
        }
173
174
        return length
175
    }
176
177
    /**
178
     * Make datatable action column.
179
     * @param {Element} element
180
     */
181
    getActionsColumnCreatedCell(element) {
182
        return (td, cellData, rowData, row, col) => {
0 ignored issues
show
Unused Code introduced by
The parameter row is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
Unused Code introduced by
The parameter col is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
183
            var dataTableContainer = $(element).parents('.dataTable-container:first');
184
185
            // Copy buttons from template
186
            let editButton = $(".template .edit-btn", dataTableContainer).clone().tooltip().appendTo($(td))
187
            let deleteButton = $(".template .delete-btn", dataTableContainer).clone().tooltip().appendTo($(td))
188
189
            // Config edit link url
190
            if (editButton.attr('href')) {
191
                let editLink = editButton.attr('href').replace('RECORD_ID', rowData.id)
192
                editButton.attr('href', editLink)
193
            }
194
195
            // Config delete link url
196
            if (deleteButton.attr('href')) {
197
                let deleteLink = deleteButton.attr('href').replace('RECORD_ID', rowData.id)
198
199
                // if relation_id is defined, replace RELATION_ID
200
                if (rowData.relation_id) {
201
                    deleteLink = deleteLink.replace('RELATION_ID', rowData.relation_id)
202
                }
203
204
                deleteButton.attr('href', deleteLink)
205
            }
206
        }
207
    }
208
209
    /**
210
     * Config buttons to display them correctly
211
     */
212
    configButtons() {
213
        let table = this.table
214
215
        // Get buttons container
216
        let buttonsContainer = table.buttons().container()
217
218
        // Retrieve container
219
        let dataTableContainer = buttonsContainer.parents('.dataTable-container:first');
220
221
        // Remove old buttons if datatable was initialized before (e.g. in related list selection modal)
222
        $('.action-buttons .buttons-colvis', dataTableContainer).remove()
223
224
        // Display mini buttons (related lists)
225
        if (dataTableContainer.data('button-size') === 'mini') {
226
227
            $('button', buttonsContainer).each((index, element) => {
228
                // Get content and use it as a title
229
                let title = $('span', element).html()
230
231
                // Add icon and effect
232
                $(element)
233
                    .addClass('btn-circle waves-effect waves-circle waves-float bg-primary')
234
                    .removeClass('btn-default')
235
                    .html('<i class="material-icons">view_column</i>')
236
                    .attr('title', title)
237
                    .tooltip({
238
                        placement: 'top'
239
                    })
240
241
                // Move button
242
                $(element).prependTo($('.action-buttons', dataTableContainer))
243
            })
244
        }
245
        // Display classic buttons (list)
246
        else {
247
            // Move buttons
248
            buttonsContainer.appendTo($('.action-buttons', dataTableContainer));
249
250
            $('button', buttonsContainer).each((index, element) => {
251
                // Replace <span>...</span> by its content
252
                $(element).html($('span', element).html())
253
254
                // Add icon and effect
255
                $(element).addClass('icon-right waves-effect bg-primary')
256
                $(element).removeClass('btn-default')
257
                $(element).append('<i class="material-icons">keyboard_arrow_down</i>')
258
            })
259
260
            // Move to the right
261
            $('.action-buttons .btn-group', dataTableContainer).addClass('pull-right')
262
        }
263
264
        // Change records number
265
        $('ul#items-number a').on('click', (event) => {
266
            let recordsNumber = $(event.target).data('number')
267
            $('strong.records-number').text(recordsNumber)
268
            table.page.len(recordsNumber).draw()
269
        })
270
271
        $(".dataTables_paginate", dataTableContainer).appendTo($('.paginator', dataTableContainer))
272
    }
273
274
    /**
275
     * Config column search.
276
     */
277
    initDatatableColumnSearch()
278
    {
279
        let table = this.table
280
        this.timer = 0
281
        let that = this
282
283
        // Config each column
284
        table.columns().every(function (index) {
285
            let column = table.column(index)
286
287
            // Event listener to launch search
288
            $('input', this.header()).on('keyup apply.daterangepicker cancel.daterangepicker', function() {
289
                that.launchSearch(column, $(this).val())
290
            })
291
292
            $('select', this.header()).on('change', function() {
293
                that.launchSearch(column, $(this).val())
294
            })
295
        })
296
297
        // Add clear search button listener
298
        this.addClearSearchButtonListener()
299
    }
300
301
    /**
302
     * Launch search
303
     * @param {Object} column
304
     * @param {String} q
305
     */
306
    launchSearch(column, q)
307
    {
308
        if (q !== '') {
309
            $('.clear-search').show()
310
        }
311
312
        if (column.search() !== q) {
313
            clearTimeout(this.timer)
314
            this.timer = setTimeout(() => {
315
                column.search(q)
316
                this.table.draw()
317
            }, 500)
318
        }
319
    }
320
321
    /**
322
     * Clear datatable search
323
     */
324
    addClearSearchButtonListener()
325
    {
326
        let table = this.table
327
328
        $('.actions-column .clear-search').on('click', (event) => {
329
            // Clear all search fields
330
            $('.dataTable thead select').selectpicker('deselectAll')
331
            $('.dataTable thead input').val('')
332
333
            // Update columns
334
            table.columns().every(function (index) {
335
                let column = table.column(index)
336
                column.search('')
337
            })
338
339
            // Disable clear search button
340
            $(event.currentTarget).hide()
341
342
            // Update data
343
            table.draw()
344
        })
345
    }
346
}