Completed
Push — master ( 32a55c )
by Gray
12:22 queued 51s
created

public/js/autocomplete.js   F

Complexity

Total Complexity 107
Complexity/F 4.12

Size

Lines of Code 439
Function Count 26

Duplication

Duplicated Lines 425
Ratio 96.81 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 107
eloc 276
c 1
b 0
f 0
dl 425
loc 439
rs 2
cc 0
nc 0
mnd 7
bc 67
fnc 26
bpm 2.5769
cpm 4.1153
noi 3

5 Functions

Rating   Name   Duplication   Size   Complexity  
A autocomplete.js ➔ __webpack_require__ 22 22 2
B autocomplete.js ➔ ?!? 0 6 1
A __webpack_require__.d 9 9 2
A __webpack_require__.o 1 1 1
A __webpack_require__.n 7 7 3

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complexity

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like public/js/autocomplete.js 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 View Code Duplication
/******/ (function(modules) { // webpackBootstrap
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
2
/******/ 	// The module cache
3
/******/ 	var installedModules = {};
4
/******/
5
/******/ 	// The require function
6
/******/ 	function __webpack_require__(moduleId) {
7
/******/
8
/******/ 		// Check if module is in cache
9
/******/ 		if(installedModules[moduleId]) {
10
/******/ 			return installedModules[moduleId].exports;
11
/******/ 		}
12
/******/ 		// Create a new module (and put it into the cache)
13
/******/ 		var module = installedModules[moduleId] = {
14
/******/ 			i: moduleId,
15
/******/ 			l: false,
16
/******/ 			exports: {}
17
/******/ 		};
18
/******/
19
/******/ 		// Execute the module function
20
/******/ 		modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
21
/******/
22
/******/ 		// Flag the module as loaded
23
/******/ 		module.l = true;
24
/******/
25
/******/ 		// Return the exports of the module
26
/******/ 		return module.exports;
27
/******/ 	}
28
/******/
29
/******/
30
/******/ 	// expose the modules object (__webpack_modules__)
31
/******/ 	__webpack_require__.m = modules;
32
/******/
33
/******/ 	// expose the module cache
34
/******/ 	__webpack_require__.c = installedModules;
35
/******/
36
/******/ 	// define getter function for harmony exports
37
/******/ 	__webpack_require__.d = function(exports, name, getter) {
38
/******/ 		if(!__webpack_require__.o(exports, name)) {
39
/******/ 			Object.defineProperty(exports, name, {
40
/******/ 				configurable: false,
41
/******/ 				enumerable: true,
42
/******/ 				get: getter
43
/******/ 			});
44
/******/ 		}
45
/******/ 	};
46
/******/
47
/******/ 	// getDefaultExport function for compatibility with non-harmony modules
48
/******/ 	__webpack_require__.n = function(module) {
49
/******/ 		var getter = module && module.__esModule ?
50
/******/ 			function getDefault() { return module['default']; } :
51
/******/ 			function getModuleExports() { return module; };
52
/******/ 		__webpack_require__.d(getter, 'a', getter);
53
/******/ 		return getter;
54
/******/ 	};
55
/******/
56
/******/ 	// Object.prototype.hasOwnProperty.call
57
/******/ 	__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
58
/******/
59
/******/ 	// __webpack_public_path__
60
/******/ 	__webpack_require__.p = "/";
61
/******/
62
/******/ 	// Load entry module and return exports
63
/******/ 	return __webpack_require__(__webpack_require__.s = 3);
64
/******/ })
65
/************************************************************************/
66
/******/ ([
67
/* 0 */,
0 ignored issues
show
Bug introduced by
The variable seems to be never declared. If this is a global, consider adding a /** global: */ 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...
68
/* 1 */,
69
/* 2 */,
70
/* 3 */
71
/***/ (function(module, exports, __webpack_require__) {
72
73
module.exports = __webpack_require__(4);
74
75
76
/***/ }),
77
/* 4 */
78 View Code Duplication
/***/ (function(module, exports) {
0 ignored issues
show
Unused Code introduced by
The parameter exports 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 module 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...
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
79
80
$(document).ready(function () {
81
82
    /*
83
     * jQuery accessible and keyboard-enhanced autocomplete list
84
     * @version v1.6.0
85
     * Website: https://a11y.nicolas-hoffmann.net/autocomplet-list/
86
     * License MIT: https://github.com/nico3333fr/jquery-accessible-autocomplete-list-aria/blob/master/LICENSE
87
     */
88
    // loading combobox ------------------------------------------------------------------------------------------------------------
89
    // init
90
    var $js_combobox = $('.js-combobox'),
91
        $body = $('body'),
92
93
    // default_text_help = 'Use tabulation (or down) key to access and browse suggestions after input. Confirm your choice with enter key, or esc key to close suggestions box.',
94
    default_text_help = '',
95
        default_class_for_invisible_text = 'invisible',
96
        suggestion_single = 'There is ',
97
        suggestion_plural = 'There are ',
98
        suggestion_word = 'suggestion',
99
        suggestion_word_plural = 'suggestions',
100
        button_clear_title = 'clear this field',
101
        button_clear_text = 'X',
102
        case_sensitive = 'no',
103
        min_length = 0,
104
        limit_number_suggestions = 666,
105
        search_option = 'beginning',
106
        // or 'containing'
107
    see_more_text = 'See more results…',
108
        tablo_suggestions = [];
109
110
    function do_see_more_option() {
111
        var $output_content = $('#js-codeit');
112
        $output_content.html('You have to code a function or a redirection to display more results ;)');
113
    }
114
115
    if ($js_combobox.length) {
116
        // if there are at least one :)
117
118
        // init
119
        $js_combobox.each(function (index_combo) {
120
            var $this = $(this),
121
                $this_id = $this.attr('id'),
122
                $label_this = $('label[for="' + $this_id + '"]'),
123
                index_lisible = index_combo + 1,
124
                options = $this.data(),
125
                $combobox_prefix_class = typeof options.comboboxPrefixClass !== 'undefined' ? options.comboboxPrefixClass + '-' : '',
126
                $combobox_help_text = typeof options.comboboxHelpText !== 'undefined' ? options.comboboxHelpText : default_text_help,
127
                $list_suggestions = $('#' + $this.attr('list')),
128
                $combobox_button_title = typeof options.comboboxButtonTitle !== 'undefined' ? options.comboboxButtonTitle : button_clear_title,
129
                $combobox_button_text = typeof options.comboboxButtonText !== 'undefined' ? options.comboboxButtonText : button_clear_text,
130
                $combobox_case_sensitive = typeof options.comboboxCaseSensitive !== 'undefined' ? options.comboboxCaseSensitive : case_sensitive,
131
                tablo_temp_suggestions = [];
132
133
            // input
134
            $this.attr({
135
                'data-number': index_lisible,
136
                'autocorrect': 'off',
137
                'autocapitalize': 'off',
138
                'spellcheck': 'false',
139
                'autocomplete': 'off',
140
                'aria-describedby': $combobox_prefix_class + 'help-text' + index_lisible,
141
                'aria-autocomplete': 'list',
142
                'data-lastval': '',
143
                'aria-owns': $combobox_prefix_class + 'suggest_' + index_lisible
144
            });
145
            // stock into tables
146
            $list_suggestions.find('option').each(function (index_option, index_element) {
147
                tablo_temp_suggestions.push(index_element.value);
148
            });
149
            if ($combobox_case_sensitive === 'no') {
150
                // order case tablo_temp_suggestions
151
                tablo_suggestions[index_lisible] = tablo_temp_suggestions.sort(function (a, b) {
152
                    a = a.toLowerCase();
153
                    b = b.toLowerCase();
154
                    if (a == b) {
155
                        return 0;
156
                    }
157
                    if (a > b) {
158
                        return 1;
159
                    }
160
                    return -1;
161
                });
162
            } else {
163
                tablo_suggestions[index_lisible] = tablo_temp_suggestions.sort();
164
            }
165
166
            // wrap into a container
167
            $this.wrap('<div class="' + $combobox_prefix_class + 'container js-container" data-combobox-prefix-class="' + $combobox_prefix_class + '"></div>');
168
169
            var $combobox_container = $this.parent();
170
171
            // custom datalist/listbox linked to input
172
            $combobox_container.append('<div id="' + $combobox_prefix_class + 'suggest_' + index_lisible + '" class="js-suggest ' + $combobox_prefix_class + 'suggestions"><div role="listbox"></div></div>');
173
            $list_suggestions.remove();
174
175
            // status zone
176
            // $combobox_container.prepend('<div id="' + $combobox_prefix_class + 'suggestion-text' + index_lisible + '" class="js-suggestion-text ' + $combobox_prefix_class + 'suggestion-text ' + default_class_for_invisible_text + '" aria-live="assertive"></div>');
177
178
            // help text
179
            $combobox_container.prepend('<span id="' + $combobox_prefix_class + 'help-text' + index_lisible + '" class="' + $combobox_prefix_class + 'help-text ' + default_class_for_invisible_text + '">' + $combobox_help_text + '</span>');
180
181
            // label id
182
            $label_this.attr('id', 'label-id-' + $this_id);
183
184
            // button clear
185
            $this.after('<button class="js-clear-button ' + $combobox_prefix_class + 'clear-button" aria-label="' + $combobox_button_title + '" title="' + $combobox_button_title + '" aria-describedby="label-id-' + $this_id + '" type="button">' + $combobox_button_text + '</button>');
186
        });
187
188
        // listeners
189
        // keydown on field
190
        $body.on('keyup', '.js-combobox', function (event) {
191
            var $this = $(this),
192
                options_combo = $this.data(),
193
                $container = $this.parent(),
194
                $form = $container.parents('form'),
195
                options = $container.data(),
196
                $combobox_prefix_class = typeof options.comboboxPrefixClass !== 'undefined' ? options.comboboxPrefixClass : '',
197
                // no "-"" because already generated
198
            $suggestions = $container.find('.js-suggest div'),
199
200
            //$suggestion_list = $suggestions.find('.js-suggestion'),
201
            $suggestions_text = $container.find('.js-suggestion-text'),
202
                $combobox_suggestion_single = typeof options_combo.suggestionSingle !== 'undefined' ? options_combo.suggestionSingle : suggestion_single,
203
                $combobox_suggestion_plural = typeof options_combo.suggestionPlural !== 'undefined' ? options_combo.suggestionPlural : suggestion_plural,
204
                $combobox_suggestion_word = typeof options_combo.suggestionWord !== 'undefined' ? options_combo.suggestionWord : suggestion_word,
205
                $combobox_suggestion_word_plural = typeof options_combo.suggestionWord !== 'undefined' ? options_combo.suggestionWordPlural : suggestion_word_plural,
206
                combobox_min_length = typeof options_combo.comboboxMinLength !== 'undefined' ? Math.abs(options_combo.comboboxMinLength) : min_length,
207
                $combobox_case_sensitive = typeof options_combo.comboboxCaseSensitive !== 'undefined' ? options_combo.comboboxCaseSensitive : case_sensitive,
208
                combobox_limit_number_suggestions = typeof options_combo.comboboxLimitNumberSuggestions !== 'undefined' ? Math.abs(options_combo.comboboxLimitNumberSuggestions) : limit_number_suggestions,
209
                $combobox_search_option = typeof options_combo.comboboxSearchOption !== 'undefined' ? options_combo.comboboxSearchOption : search_option,
210
                $combobox_see_more_text = typeof options_combo.comboboxSeeMoreText !== 'undefined' ? options_combo.comboboxSeeMoreText : see_more_text,
211
                index_table = $this.attr('data-number'),
212
                value_to_search = $this.val(),
213
                text_number_suggestions = '';
214
215
            if (event.keyCode === 13) {
216
                $form.submit();
217
            } else {
218
219
                if (event.keyCode !== 27) {
220
                    // No Escape
221
222
                    $this.attr('data-lastval', value_to_search);
223
                    // search for text suggestion in the array tablo_suggestions[index_table]
224
                    var size_tablo = tablo_suggestions[index_table].length,
225
                        i = 0,
226
                        counter = 0;
227
228
                    $suggestions.empty();
229
230
                    if (value_to_search != '' && value_to_search.length >= combobox_min_length) {
231
                        while (i < size_tablo) {
232
                            if (counter < combobox_limit_number_suggestions) {
233
                                if ($combobox_search_option === 'containing' && ($combobox_case_sensitive === 'yes' && tablo_suggestions[index_table][i].indexOf(value_to_search) >= 0 || $combobox_case_sensitive === 'no' && tablo_suggestions[index_table][i].toUpperCase().indexOf(value_to_search.toUpperCase()) >= 0) || $combobox_search_option === 'beginning' && ($combobox_case_sensitive === 'yes' && tablo_suggestions[index_table][i].substring(0, value_to_search.length) === value_to_search || $combobox_case_sensitive === 'no' && tablo_suggestions[index_table][i].substring(0, value_to_search.length).toUpperCase() === value_to_search.toUpperCase())) {
234
                                    $suggestions.append('<div id="suggestion-' + index_table + '-' + counter + '" class="js-suggestion ' + $combobox_prefix_class + 'suggestion" tabindex="-1" role="option">' + tablo_suggestions[index_table][i] + '</div>');
235
                                    counter++;
236
                                }
237
                            }
238
                            i++;
239
                        }
240
                        if (counter >= combobox_limit_number_suggestions) {
241
                            $suggestions.append('<div id="suggestion-' + index_table + '-' + counter + '" class="js-suggestion js-seemore ' + $combobox_prefix_class + 'suggestion" tabindex="-1" role="option">' + $combobox_see_more_text + '</div>');
242
                            counter++;
243
                        }
244
                        // update number of suggestions
245
                        if (counter > 1) {
246
                            text_number_suggestions = $combobox_suggestion_plural + counter + ' ' + $combobox_suggestion_word_plural + '.';
247
                        }
248
                        if (counter === 1) {
249
                            text_number_suggestions = $combobox_suggestion_single + counter + ' ' + $combobox_suggestion_word + '.';
250
                        }
251
                        if (counter === 0) {
252
                            text_number_suggestions = $combobox_suggestion_single + counter + ' ' + $combobox_suggestion_word + '.';
253
                        }
254
                        if (counter >= 0) {
255
                            var text_number_suggestions_default = $suggestions_text.text();
256
                            if (text_number_suggestions != text_number_suggestions_default) {
257
                                // @Goestu trick to make it work on all AT
258
                                var suggestions_to_add = $("<p>").text(text_number_suggestions);
259
                                $suggestions_text.attr('aria-live', 'polite');
260
                                $suggestions_text.empty();
261
                                $suggestions_text.append(suggestions_to_add);
262
                            }
263
                        }
264
                    }
265
                }
266
            }
267
        }).on('click', function (event) {
268
            var $target = $(event.target),
269
                $suggestions_text = $('.js-suggestion-text:not(:empty)'),
270
                // if a suggestion text is not empty => suggestion opened somewhere
271
            $container = $suggestions_text.parents('.js-container'),
272
                $input_text = $container.find('.js-combobox'),
273
                $suggestions = $container.find('.js-suggest div');
274
275
            // if click outside => close opened suggestions 
276
            if (!$target.is('.js-suggestion') && !$target.is('.js-combobox') && $suggestions_text.length) {
277
                $input_text.val($input_text.attr('data-lastval'));
278
                $suggestions.empty();
279
                $suggestions_text.empty();
280
            }
281
        })
282
        // tab + down management for autocomplete (when list of suggestion)
283
        .on('keydown', '.js-combobox', function (event) {
284
            var $this = $(this),
285
                $container = $this.parent(),
286
                $input_text = $container.find('.js-combobox'),
287
                $suggestions = $container.find('.js-suggest div'),
288
                $suggestion_list = $suggestions.find('.js-suggestion'),
289
                $suggestions_text = $container.find('.js-suggestion-text'),
290
                $autorise_tab_options = typeof $this.attr('data-combobox-notab-options') !== 'undefined' ? false : true,
291
                $first_suggestion = $suggestion_list.first();
292
293
            if (!event.shiftKey && event.keyCode == 9 && $autorise_tab_options || event.keyCode == 40) {
294
                // tab (if authorised) or bottom
295
                // See if there are suggestions, and yes => focus on first one
296
                if ($suggestion_list.length) {
297
                    $input_text.val($first_suggestion.html());
298
                    $suggestion_list.first().focus();
299
                    event.preventDefault();
300
                }
301
            }
302
            if (event.keyCode == 27 || $autorise_tab_options === false && event.keyCode == 9) {
303
                // esc or (tab/shift tab + notab option) = close
304
                $input_text.val($input_text.attr('data-lastval'));
305
                $suggestions.empty();
306
                $suggestions_text.empty();
307
                if (event.keyCode == 27) {
308
                    // Esc prevented only, tab can go :)
309
                    event.preventDefault();
310
                    setTimeout(function () {
311
                        $input_text.focus();
312
                    }, 300); // timeout to avoid problem in suggestions display
313
                }
314
            }
315
        })
316
        // tab + down management in list of suggestions
317
        .on('keydown', '.js-suggestion', function (event) {
318
            var $this = $(this),
319
                $container = $this.parents('.js-container'),
320
                $input_text = $container.find('.js-combobox'),
321
                $autorise_tab_options = typeof $input_text.attr('data-combobox-notab-options') !== 'undefined' ? false : true,
322
                $suggestions = $container.find('.js-suggest div'),
323
                $suggestions_text = $container.find('.js-suggestion-text'),
324
                $next_suggestion = $this.next(),
325
                $previous_suggestion = $this.prev();
326
327
            if (event.keyCode == 27 || $autorise_tab_options === false && event.keyCode == 9) {
328
                // esc or (tab/shift tab + notab option) = close
329
                if (event.keyCode == 27) {
330
                    // Esc prevented only, tab can go :)
331
                    $input_text.val($input_text.attr('data-lastval'));
332
                    $suggestions.empty();
333
                    $suggestions_text.empty();
334
                    setTimeout(function () {
335
                        $input_text.focus();
336
                    }, 300); // timeout to avoid problem in suggestions display
337
                    event.preventDefault();
338
                }
339
                if ($autorise_tab_options === false && event.keyCode == 9) {
340
                    $suggestions.empty();
341
                    $suggestions_text.empty();
342
                    $input_text.focus();
343
                }
344
            }
345
            if (event.keyCode == 13 || event.keyCode == 32) {
346
                // Enter or space
347
                if ($this.hasClass('js-seemore')) {
348
                    $input_text.val($input_text.attr('data-lastval'));
349
                    $suggestions.empty();
350
                    $suggestions_text.empty();
351
                    setTimeout(function () {
352
                        $input_text.focus();
353
                    }, 300); // timeout to avoid problem in suggestions display
354
                    // go define the function you need when we click the see_more option
355
                    setTimeout(function () {
356
                        do_see_more_option();
357
                    }, 301); // timeout to avoid problem in suggestions display
358
                    event.preventDefault();
359
                } else {
360
                    $input_text.val($this.html());
361
                    $input_text.attr('data-lastval', $this.html());
362
                    $suggestions.empty();
363
                    $suggestions_text.empty();
364
                    setTimeout(function () {
365
                        $input_text.focus();
366
                    }, 300); // timeout to avoid problem in suggestions display
367
                    event.preventDefault();
368
                }
369
            }
370
            if (!event.shiftKey && event.keyCode == 9 && $autorise_tab_options || event.keyCode == 40) {
371
                // tab (if authorised) or bottom
372
                if ($next_suggestion.length) {
373
                    $input_text.val($next_suggestion.html());
374
                    $next_suggestion.focus();
375
                } else {
376
                    $input_text.val($input_text.attr('data-lastval'));
377
                    if (!event.shiftKey && event.keyCode == 9) {
378
                        // tab closes the list
379
                        var e = jQuery.Event("keydown");
380
                        e.which = 27; // # Some key code value
381
                        e.keyCode = 27;
382
                        $this.trigger(e);
383
                    } else {
384
                        setTimeout(function () {
385
                            $input_text.focus();
386
                        }, 300);
387
                    } // timeout to avoid problem in suggestions display
388
                }
389
                event.preventDefault();
390
            }
391
392
            if (event.shiftKey && event.keyCode == 9 && $autorise_tab_options || event.keyCode == 38) {
393
                // top or Maj+tab (if authorised)
394
                if ($previous_suggestion.length) {
395
                    $input_text.val($previous_suggestion.html());
396
                    $previous_suggestion.focus();
397
                } else {
398
                    $input_text.val($input_text.attr('data-lastval')).focus();
399
                }
400
                event.preventDefault();
401
            }
402
        })
403
        // clear button
404
        .on('click', '.js-clear-button', function () {
405
            var $this = $(this),
406
                $container = $this.parent(),
407
                $input_text = $container.find('.js-combobox'),
408
                $suggestions = $container.find('.js-suggest div'),
409
                $suggestions_text = $container.find('.js-suggestion-text');
410
411
            $suggestions.empty();
412
            $suggestions_text.empty();
413
            $input_text.val('');
414
            $input_text.attr('data-lastval', '');
415
        }).on('click', '.js-suggestion', function () {
416
            var $this = $(this),
417
                value = $this.html(),
418
                $container = $this.parents('.js-container'),
419
                $input_text = $container.find('.js-combobox'),
420
                $suggestions = $container.find('.js-suggest div'),
421
                $suggestions_text = $container.find('.js-suggestion-text');
422
423
            if ($this.hasClass('js-seemore')) {
424
                $suggestions.empty();
425
                $suggestions_text.empty();
426
                $input_text.focus();
427
                // go define the function you need when we click the see_more option
428
                do_see_more_option();
429
            } else {
430
                $input_text.val(value).focus();
431
                $suggestions.empty();
432
                $suggestions_text.empty();
433
            }
434
        });
435
    }
436
});
437
438
/***/ })
439
/******/ ]);