Completed
Push — master ( 36261e...adbdec )
by
unknown
14s queued 12s
created

resources/bootstrap/js/collapse.js   F

Complexity

Total Complexity 77
Complexity/F 2.48

Size

Lines of Code 391
Function Count 31

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 228
dl 0
loc 391
rs 2.24
c 0
b 0
f 0
wmc 77
mnd 46
bc 46
fnc 31
bpm 1.4838
cpm 2.4838
noi 9

17 Functions

Rating   Name   Duplication   Size   Complexity  
B collapse.js ➔ _interopDefaultLegacy 0 1 7
A collapse.js ➔ _defineProperties 0 9 3
A collapse.js ➔ _createClass 0 8 3
A collapse.js ➔ toggle 0 7 2
A collapse.js ➔ setTransitioning 0 3 1
B collapse.js ➔ _extends 0 16 6
B collapse.js ➔ hide 0 48 8
A collapse.js ➔ _getConfig 0 7 1
B collapse.js ➔ Collapse 0 31 8
A collapse.js ➔ _addAriaAndCollapsedClass 0 7 2
A collapse.js ➔ get 0 3 1
A collapse.js ➔ _getParent 0 22 4
A collapse.js ➔ dispose 0 8 1
D collapse.js ➔ show 0 73 13
B collapse.js ➔ _jQueryInterface 0 25 7
A collapse.js ➔ _getTargetFromElement 0 4 2
A collapse.js ➔ _getDimension 0 4 2

How to fix   Complexity   

Complexity

Complex classes like resources/bootstrap/js/collapse.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
/*!
2
  * Bootstrap collapse.js v4.6.1 (https://getbootstrap.com/)
3
  * Copyright 2011-2021 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
4
  * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
5
  */
6
(function (global, factory) {
7
  typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('jquery'), require('./util.js')) :
8
  typeof define === 'function' && define.amd ? define(['jquery', './util'], factory) :
0 ignored issues
show
Bug introduced by
The variable define seems to be never declared. If this is a global, consider adding a /** global: define */ 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...
9
  (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Collapse = factory(global.jQuery, global.Util));
0 ignored issues
show
Bug introduced by
The variable globalThis seems to be never declared. If this is a global, consider adding a /** global: globalThis */ 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...
Best Practice introduced by
If you intend to check if the variable self is declared in the current environment, consider using typeof self === "undefined" instead. This is safe if the variable is not actually declared.
Loading history...
Comprehensibility introduced by
Usage of the sequence operator is discouraged, since it may lead to obfuscated code.

The sequence or comma operator allows the inclusion of multiple expressions where only is permitted. The result of the sequence is the value of the last expression.

This operator is most often used in for statements.

Used in another places it can make code hard to read, especially when people do not realize it even exists as a seperate operator.

This check looks for usage of the sequence operator in locations where it is not necessary and could be replaced by a series of expressions or statements.

var a,b,c;

a = 1, b = 1,  c= 3;

could just as well be written as:

var a,b,c;

a = 1;
b = 1;
c = 3;

To learn more about the sequence operator, please refer to the MDN.

Loading history...
10
})(this, (function ($, Util) { 'use strict';
11
12
  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
13
14
  var $__default = /*#__PURE__*/_interopDefaultLegacy($);
15
  var Util__default = /*#__PURE__*/_interopDefaultLegacy(Util);
16
17
  function _defineProperties(target, props) {
18
    for (var i = 0; i < props.length; i++) {
19
      var descriptor = props[i];
20
      descriptor.enumerable = descriptor.enumerable || false;
21
      descriptor.configurable = true;
22
      if ("value" in descriptor) descriptor.writable = true;
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...
23
      Object.defineProperty(target, descriptor.key, descriptor);
24
    }
25
  }
26
27
  function _createClass(Constructor, protoProps, staticProps) {
28
    if (protoProps) _defineProperties(Constructor.prototype, protoProps);
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...
29
    if (staticProps) _defineProperties(Constructor, staticProps);
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...
30
    return Constructor;
31
  }
32
33
  function _extends() {
34
    _extends = Object.assign || function (target) {
35
      for (var i = 1; i < arguments.length; i++) {
36
        var source = arguments[i];
37
0 ignored issues
show
Comprehensibility introduced by
It seems like you are trying to overwrite a function name here. _extends is already defined in line 36 as a function. While this will work, it can be very confusing.
Loading history...
38
        for (var key in source) {
39
          if (Object.prototype.hasOwnProperty.call(source, key)) {
40
            target[key] = source[key];
41
          }
0 ignored issues
show
Complexity introduced by
A for in loop automatically includes the property of any prototype object, consider checking the key using hasOwnProperty.

When iterating over the keys of an object, this includes not only the keys of the object, but also keys contained in the prototype of that object. It is generally a best practice to check for these keys specifically:

var someObject;
for (var key in someObject) {
    if ( ! someObject.hasOwnProperty(key)) {
        continue; // Skip keys from the prototype.
    }

    doSomethingWith(key);
}
Loading history...
42
        }
43
      }
44
45
      return target;
46
    };
47
48
    return _extends.apply(this, arguments);
49
  }
50
51
  /**
52
   * Constants
53
   */
54
55
  var NAME = 'collapse';
56
  var VERSION = '4.6.1';
57
  var DATA_KEY = 'bs.collapse';
58
  var EVENT_KEY = "." + DATA_KEY;
59
  var DATA_API_KEY = '.data-api';
60
  var JQUERY_NO_CONFLICT = $__default["default"].fn[NAME];
61
  var CLASS_NAME_SHOW = 'show';
62
  var CLASS_NAME_COLLAPSE = 'collapse';
63
  var CLASS_NAME_COLLAPSING = 'collapsing';
64
  var CLASS_NAME_COLLAPSED = 'collapsed';
65
  var DIMENSION_WIDTH = 'width';
66
  var DIMENSION_HEIGHT = 'height';
67
  var EVENT_SHOW = "show" + EVENT_KEY;
68
  var EVENT_SHOWN = "shown" + EVENT_KEY;
69
  var EVENT_HIDE = "hide" + EVENT_KEY;
70
  var EVENT_HIDDEN = "hidden" + EVENT_KEY;
71
  var EVENT_CLICK_DATA_API = "click" + EVENT_KEY + DATA_API_KEY;
72
  var SELECTOR_ACTIVES = '.show, .collapsing';
73
  var SELECTOR_DATA_TOGGLE = '[data-toggle="collapse"]';
74
  var Default = {
75
    toggle: true,
76
    parent: ''
77
  };
78
  var DefaultType = {
79
    toggle: 'boolean',
80
    parent: '(string|element)'
81
  };
82
  /**
83
   * Class definition
84
   */
85
86
  var Collapse = /*#__PURE__*/function () {
87
    function Collapse(element, config) {
88
      this._isTransitioning = false;
89
      this._element = element;
90
      this._config = this._getConfig(config);
91
      this._triggerArray = [].slice.call(document.querySelectorAll("[data-toggle=\"collapse\"][href=\"#" + element.id + "\"]," + ("[data-toggle=\"collapse\"][data-target=\"#" + element.id + "\"]")));
92
      var toggleList = [].slice.call(document.querySelectorAll(SELECTOR_DATA_TOGGLE));
93
94
      for (var i = 0, len = toggleList.length; i < len; i++) {
95
        var elem = toggleList[i];
96
        var selector = Util__default["default"].getSelectorFromElement(elem);
97
        var filterElement = [].slice.call(document.querySelectorAll(selector)).filter(function (foundElem) {
98
          return foundElem === element;
99
        });
100
101
        if (selector !== null && filterElement.length > 0) {
102
          this._selector = selector;
103
104
          this._triggerArray.push(elem);
105
        }
106
      }
107
108
      this._parent = this._config.parent ? this._getParent() : null;
109
110
      if (!this._config.parent) {
111
        this._addAriaAndCollapsedClass(this._element, this._triggerArray);
112
      }
113
114
      if (this._config.toggle) {
115
        this.toggle();
116
      }
117
    } // Getters
118
119
120
    var _proto = Collapse.prototype;
121
122
    // Public
123
    _proto.toggle = function toggle() {
124
      if ($__default["default"](this._element).hasClass(CLASS_NAME_SHOW)) {
125
        this.hide();
126
      } else {
127
        this.show();
128
      }
129
    };
130
131
    _proto.show = function show() {
132
      var _this = this;
133
134
      if (this._isTransitioning || $__default["default"](this._element).hasClass(CLASS_NAME_SHOW)) {
135
        return;
136
      }
137
138
      var actives;
139
      var activesData;
140
141
      if (this._parent) {
142
        actives = [].slice.call(this._parent.querySelectorAll(SELECTOR_ACTIVES)).filter(function (elem) {
143
          if (typeof _this._config.parent === 'string') {
144
            return elem.getAttribute('data-parent') === _this._config.parent;
145
          }
146
147
          return elem.classList.contains(CLASS_NAME_COLLAPSE);
148
        });
149
150
        if (actives.length === 0) {
151
          actives = null;
152
        }
153
      }
154
155
      if (actives) {
156
        activesData = $__default["default"](actives).not(this._selector).data(DATA_KEY);
157
158
        if (activesData && activesData._isTransitioning) {
159
          return;
160
        }
161
      }
162
163
      var startEvent = $__default["default"].Event(EVENT_SHOW);
164
      $__default["default"](this._element).trigger(startEvent);
165
166
      if (startEvent.isDefaultPrevented()) {
167
        return;
168
      }
169
170
      if (actives) {
171
        Collapse._jQueryInterface.call($__default["default"](actives).not(this._selector), 'hide');
172
173
        if (!activesData) {
174
          $__default["default"](actives).data(DATA_KEY, null);
175
        }
176
      }
177
178
      var dimension = this._getDimension();
179
180
      $__default["default"](this._element).removeClass(CLASS_NAME_COLLAPSE).addClass(CLASS_NAME_COLLAPSING);
181
      this._element.style[dimension] = 0;
182
183
      if (this._triggerArray.length) {
184
        $__default["default"](this._triggerArray).removeClass(CLASS_NAME_COLLAPSED).attr('aria-expanded', true);
185
      }
186
187
      this.setTransitioning(true);
188
189
      var complete = function complete() {
190
        $__default["default"](_this._element).removeClass(CLASS_NAME_COLLAPSING).addClass(CLASS_NAME_COLLAPSE + " " + CLASS_NAME_SHOW);
191
        _this._element.style[dimension] = '';
192
193
        _this.setTransitioning(false);
194
195
        $__default["default"](_this._element).trigger(EVENT_SHOWN);
196
      };
197
198
      var capitalizedDimension = dimension[0].toUpperCase() + dimension.slice(1);
199
      var scrollSize = "scroll" + capitalizedDimension;
200
      var transitionDuration = Util__default["default"].getTransitionDurationFromElement(this._element);
201
      $__default["default"](this._element).one(Util__default["default"].TRANSITION_END, complete).emulateTransitionEnd(transitionDuration);
202
      this._element.style[dimension] = this._element[scrollSize] + "px";
203
    };
204
205
    _proto.hide = function hide() {
206
      var _this2 = this;
207
208
      if (this._isTransitioning || !$__default["default"](this._element).hasClass(CLASS_NAME_SHOW)) {
209
        return;
210
      }
211
212
      var startEvent = $__default["default"].Event(EVENT_HIDE);
213
      $__default["default"](this._element).trigger(startEvent);
214
215
      if (startEvent.isDefaultPrevented()) {
216
        return;
217
      }
218
219
      var dimension = this._getDimension();
220
221
      this._element.style[dimension] = this._element.getBoundingClientRect()[dimension] + "px";
222
      Util__default["default"].reflow(this._element);
223
      $__default["default"](this._element).addClass(CLASS_NAME_COLLAPSING).removeClass(CLASS_NAME_COLLAPSE + " " + CLASS_NAME_SHOW);
224
      var triggerArrayLength = this._triggerArray.length;
225
226
      if (triggerArrayLength > 0) {
227
        for (var i = 0; i < triggerArrayLength; i++) {
228
          var trigger = this._triggerArray[i];
229
          var selector = Util__default["default"].getSelectorFromElement(trigger);
230
231
          if (selector !== null) {
232
            var $elem = $__default["default"]([].slice.call(document.querySelectorAll(selector)));
233
234
            if (!$elem.hasClass(CLASS_NAME_SHOW)) {
235
              $__default["default"](trigger).addClass(CLASS_NAME_COLLAPSED).attr('aria-expanded', false);
236
            }
237
          }
238
        }
239
      }
240
241
      this.setTransitioning(true);
242
243
      var complete = function complete() {
244
        _this2.setTransitioning(false);
245
246
        $__default["default"](_this2._element).removeClass(CLASS_NAME_COLLAPSING).addClass(CLASS_NAME_COLLAPSE).trigger(EVENT_HIDDEN);
247
      };
248
249
      this._element.style[dimension] = '';
250
      var transitionDuration = Util__default["default"].getTransitionDurationFromElement(this._element);
251
      $__default["default"](this._element).one(Util__default["default"].TRANSITION_END, complete).emulateTransitionEnd(transitionDuration);
252
    };
253
254
    _proto.setTransitioning = function setTransitioning(isTransitioning) {
255
      this._isTransitioning = isTransitioning;
256
    };
257
258
    _proto.dispose = function dispose() {
259
      $__default["default"].removeData(this._element, DATA_KEY);
260
      this._config = null;
261
      this._parent = null;
262
      this._element = null;
263
      this._triggerArray = null;
264
      this._isTransitioning = null;
265
    } // Private
266
    ;
267
268
    _proto._getConfig = function _getConfig(config) {
269
      config = _extends({}, Default, config);
270
      config.toggle = Boolean(config.toggle); // Coerce string values
271
272
      Util__default["default"].typeCheckConfig(NAME, config, DefaultType);
273
      return config;
274
    };
275
276
    _proto._getDimension = function _getDimension() {
277
      var hasWidth = $__default["default"](this._element).hasClass(DIMENSION_WIDTH);
278
      return hasWidth ? DIMENSION_WIDTH : DIMENSION_HEIGHT;
279
    };
280
281
    _proto._getParent = function _getParent() {
282
      var _this3 = this;
283
284
      var parent;
285
286
      if (Util__default["default"].isElement(this._config.parent)) {
287
        parent = this._config.parent; // It's a jQuery object
288
289
        if (typeof this._config.parent.jquery !== 'undefined') {
290
          parent = this._config.parent[0];
291
        }
292
      } else {
293
        parent = document.querySelector(this._config.parent);
294
      }
295
296
      var selector = "[data-toggle=\"collapse\"][data-parent=\"" + this._config.parent + "\"]";
297
      var children = [].slice.call(parent.querySelectorAll(selector));
298
      $__default["default"](children).each(function (i, element) {
299
        _this3._addAriaAndCollapsedClass(Collapse._getTargetFromElement(element), [element]);
300
      });
301
      return parent;
302
    };
303
304
    _proto._addAriaAndCollapsedClass = function _addAriaAndCollapsedClass(element, triggerArray) {
305
      var isOpen = $__default["default"](element).hasClass(CLASS_NAME_SHOW);
306
307
      if (triggerArray.length) {
308
        $__default["default"](triggerArray).toggleClass(CLASS_NAME_COLLAPSED, !isOpen).attr('aria-expanded', isOpen);
309
      }
310
    } // Static
311
    ;
312
313
    Collapse._getTargetFromElement = function _getTargetFromElement(element) {
314
      var selector = Util__default["default"].getSelectorFromElement(element);
315
      return selector ? document.querySelector(selector) : null;
316
    };
317
318
    Collapse._jQueryInterface = function _jQueryInterface(config) {
319
      return this.each(function () {
320
        var $element = $__default["default"](this);
321
        var data = $element.data(DATA_KEY);
322
323
        var _config = _extends({}, Default, $element.data(), typeof config === 'object' && config ? config : {});
324
325
        if (!data && _config.toggle && typeof config === 'string' && /show|hide/.test(config)) {
326
          _config.toggle = false;
327
        }
328
329
        if (!data) {
330
          data = new Collapse(this, _config);
331
          $element.data(DATA_KEY, data);
332
        }
333
334
        if (typeof config === 'string') {
335
          if (typeof data[config] === 'undefined') {
336
            throw new TypeError("No method named \"" + config + "\"");
337
          }
338
339
          data[config]();
340
        }
341
      });
342
    };
343
344
    _createClass(Collapse, null, [{
345
      key: "VERSION",
346
      get: function get() {
347
        return VERSION;
348
      }
349
    }, {
350
      key: "Default",
351
      get: function get() {
352
        return Default;
353
      }
354
    }]);
355
356
    return Collapse;
357
  }();
358
  /**
359
   * Data API implementation
360
   */
361
362
363
  $__default["default"](document).on(EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {
364
    // preventDefault only for <a> elements (which change the URL) not inside the collapsible element
365
    if (event.currentTarget.tagName === 'A') {
366
      event.preventDefault();
367
    }
368
369
    var $trigger = $__default["default"](this);
370
    var selector = Util__default["default"].getSelectorFromElement(this);
371
    var selectors = [].slice.call(document.querySelectorAll(selector));
372
    $__default["default"](selectors).each(function () {
373
      var $target = $__default["default"](this);
374
      var data = $target.data(DATA_KEY);
375
      var config = data ? 'toggle' : $trigger.data();
376
377
      Collapse._jQueryInterface.call($target, config);
378
    });
379
  });
380
  /**
381
   * jQuery
382
   */
383
384
  $__default["default"].fn[NAME] = Collapse._jQueryInterface;
385
  $__default["default"].fn[NAME].Constructor = Collapse;
386
387
  $__default["default"].fn[NAME].noConflict = function () {
388
    $__default["default"].fn[NAME] = JQUERY_NO_CONFLICT;
389
    return Collapse._jQueryInterface;
390
  };
391
392
  return Collapse;
393
394
}));
395
//# sourceMappingURL=collapse.js.map
396