bootstrap 5.1.3 → 5.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +24 -4
  3. data/assets/javascripts/bootstrap/alert.js +11 -146
  4. data/assets/javascripts/bootstrap/base-component.js +37 -120
  5. data/assets/javascripts/bootstrap/button.js +10 -74
  6. data/assets/javascripts/bootstrap/carousel.js +213 -485
  7. data/assets/javascripts/bootstrap/collapse.js +65 -249
  8. data/assets/javascripts/bootstrap/dom/data.js +3 -5
  9. data/assets/javascripts/bootstrap/dom/event-handler.js +94 -132
  10. data/assets/javascripts/bootstrap/dom/manipulator.js +23 -27
  11. data/assets/javascripts/bootstrap/dom/selector-engine.js +16 -58
  12. data/assets/javascripts/bootstrap/dropdown.js +103 -317
  13. data/assets/javascripts/bootstrap/modal.js +107 -749
  14. data/assets/javascripts/bootstrap/offcanvas.js +90 -659
  15. data/assets/javascripts/bootstrap/popover.js +36 -118
  16. data/assets/javascripts/bootstrap/scrollspy.js +183 -262
  17. data/assets/javascripts/bootstrap/tab.js +215 -214
  18. data/assets/javascripts/bootstrap/toast.js +36 -218
  19. data/assets/javascripts/bootstrap/tooltip.js +280 -629
  20. data/assets/javascripts/bootstrap/util/backdrop.js +165 -0
  21. data/assets/javascripts/bootstrap/util/component-functions.js +46 -0
  22. data/assets/javascripts/bootstrap/util/config.js +79 -0
  23. data/assets/javascripts/bootstrap/util/focustrap.js +129 -0
  24. data/assets/javascripts/bootstrap/util/index.js +350 -0
  25. data/assets/javascripts/bootstrap/util/sanitizer.js +122 -0
  26. data/assets/javascripts/bootstrap/util/scrollbar.js +138 -0
  27. data/assets/javascripts/bootstrap/util/swipe.js +155 -0
  28. data/assets/javascripts/bootstrap/util/template-factory.js +177 -0
  29. data/assets/javascripts/bootstrap-global-this-define.js +1 -1
  30. data/assets/javascripts/bootstrap-sprockets.js +17 -8
  31. data/assets/javascripts/bootstrap.js +2093 -1881
  32. data/assets/javascripts/bootstrap.min.js +3 -3
  33. data/assets/stylesheets/_bootstrap-grid.scss +3 -6
  34. data/assets/stylesheets/_bootstrap-reboot.scss +3 -7
  35. data/assets/stylesheets/_bootstrap.scss +4 -6
  36. data/assets/stylesheets/bootstrap/_accordion.scss +56 -25
  37. data/assets/stylesheets/bootstrap/_alert.scss +18 -4
  38. data/assets/stylesheets/bootstrap/_badge.scss +14 -5
  39. data/assets/stylesheets/bootstrap/_breadcrumb.scss +22 -10
  40. data/assets/stylesheets/bootstrap/_button-group.scss +4 -1
  41. data/assets/stylesheets/bootstrap/_buttons.scss +125 -29
  42. data/assets/stylesheets/bootstrap/_card.scss +55 -37
  43. data/assets/stylesheets/bootstrap/_close.scss +1 -1
  44. data/assets/stylesheets/bootstrap/_containers.scss +1 -1
  45. data/assets/stylesheets/bootstrap/_dropdown.scss +85 -76
  46. data/assets/stylesheets/bootstrap/_functions.scss +8 -8
  47. data/assets/stylesheets/bootstrap/_grid.scss +3 -3
  48. data/assets/stylesheets/bootstrap/_helpers.scss +1 -0
  49. data/assets/stylesheets/bootstrap/_list-group.scss +48 -30
  50. data/assets/stylesheets/bootstrap/_maps.scss +54 -0
  51. data/assets/stylesheets/bootstrap/_modal.scss +71 -43
  52. data/assets/stylesheets/bootstrap/_nav.scss +53 -20
  53. data/assets/stylesheets/bootstrap/_navbar.scss +93 -150
  54. data/assets/stylesheets/bootstrap/_offcanvas.scss +120 -59
  55. data/assets/stylesheets/bootstrap/_pagination.scss +66 -21
  56. data/assets/stylesheets/bootstrap/_placeholders.scss +1 -1
  57. data/assets/stylesheets/bootstrap/_popover.scss +90 -52
  58. data/assets/stylesheets/bootstrap/_progress.scss +20 -9
  59. data/assets/stylesheets/bootstrap/_reboot.scss +25 -40
  60. data/assets/stylesheets/bootstrap/_root.scss +40 -21
  61. data/assets/stylesheets/bootstrap/_spinners.scss +38 -22
  62. data/assets/stylesheets/bootstrap/_tables.scss +32 -23
  63. data/assets/stylesheets/bootstrap/_toasts.scss +38 -16
  64. data/assets/stylesheets/bootstrap/_tooltip.scss +61 -56
  65. data/assets/stylesheets/bootstrap/_type.scss +2 -0
  66. data/assets/stylesheets/bootstrap/_utilities.scss +43 -26
  67. data/assets/stylesheets/bootstrap/_variables.scss +128 -135
  68. data/assets/stylesheets/bootstrap/bootstrap-utilities.scss +3 -6
  69. data/assets/stylesheets/bootstrap/forms/_floating-labels.scss +15 -3
  70. data/assets/stylesheets/bootstrap/forms/_form-check.scss +28 -5
  71. data/assets/stylesheets/bootstrap/forms/_form-control.scss +12 -37
  72. data/assets/stylesheets/bootstrap/forms/_form-select.scss +0 -1
  73. data/assets/stylesheets/bootstrap/forms/_input-group.scss +19 -8
  74. data/assets/stylesheets/bootstrap/helpers/_color-bg.scss +10 -0
  75. data/assets/stylesheets/bootstrap/helpers/_colored-links.scss +2 -2
  76. data/assets/stylesheets/bootstrap/helpers/_position.scss +7 -1
  77. data/assets/stylesheets/bootstrap/helpers/_ratio.scss +2 -2
  78. data/assets/stylesheets/bootstrap/helpers/_vr.scss +1 -1
  79. data/assets/stylesheets/bootstrap/mixins/_alert.scss +7 -3
  80. data/assets/stylesheets/bootstrap/mixins/_banner.scss +9 -0
  81. data/assets/stylesheets/bootstrap/mixins/_breakpoints.scss +8 -8
  82. data/assets/stylesheets/bootstrap/mixins/_buttons.scss +32 -95
  83. data/assets/stylesheets/bootstrap/mixins/_container.scss +4 -2
  84. data/assets/stylesheets/bootstrap/mixins/_forms.scss +18 -10
  85. data/assets/stylesheets/bootstrap/mixins/_gradients.scss +1 -1
  86. data/assets/stylesheets/bootstrap/mixins/_grid.scss +12 -12
  87. data/assets/stylesheets/bootstrap/mixins/_pagination.scss +4 -25
  88. data/assets/stylesheets/bootstrap/mixins/_reset-text.scss +1 -1
  89. data/assets/stylesheets/bootstrap/mixins/_table-variants.scss +12 -9
  90. data/assets/stylesheets/bootstrap/mixins/_utilities.scss +13 -5
  91. data/bootstrap.gemspec +1 -1
  92. data/lib/bootstrap/version.rb +2 -2
  93. data/tasks/updater/js.rb +10 -5
  94. data/tasks/updater.rb +2 -2
  95. metadata +16 -4
@@ -1,19 +1,19 @@
1
1
  /*!
2
- * Bootstrap tooltip.js v5.1.3 (https://getbootstrap.com/)
3
- * Copyright 2011-2021 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
2
+ * Bootstrap tooltip.js v5.2.2 (https://getbootstrap.com/)
3
+ * Copyright 2011-2022 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
4
4
  * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
5
5
  */
6
6
  (function (global, factory) {
7
- typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('@popperjs/core'), require('./dom/data.js'), require('./dom/event-handler.js'), require('./dom/manipulator.js'), require('./dom/selector-engine.js'), require('./base-component.js')) :
8
- typeof define === 'function' && define.amd ? define(['@popperjs/core', './dom/data', './dom/event-handler', './dom/manipulator', './dom/selector-engine', './base-component'], factory) :
9
- (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Tooltip = factory(global.Popper, global.Data, global.EventHandler, global.Manipulator, global.SelectorEngine, global.Base));
10
- })(this, (function (Popper, Data, EventHandler, Manipulator, SelectorEngine, BaseComponent) { 'use strict';
7
+ typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('@popperjs/core'), require('./util/index'), require('./util/sanitizer'), require('./dom/event-handler'), require('./dom/manipulator'), require('./base-component'), require('./util/template-factory')) :
8
+ typeof define === 'function' && define.amd ? define(['@popperjs/core', './util/index', './util/sanitizer', './dom/event-handler', './dom/manipulator', './base-component', './util/template-factory'], factory) :
9
+ (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Tooltip = factory(global["@popperjs/core"], global.Index, global.Sanitizer, global.EventHandler, global.Manipulator, global.BaseComponent, global.TemplateFactory));
10
+ })(this, (function (Popper, index, sanitizer, EventHandler, Manipulator, BaseComponent, TemplateFactory) { 'use strict';
11
11
 
12
12
  const _interopDefaultLegacy = e => e && typeof e === 'object' && 'default' in e ? e : { default: e };
13
13
 
14
14
  function _interopNamespace(e) {
15
15
  if (e && e.__esModule) return e;
16
- const n = Object.create(null);
16
+ const n = Object.create(null, { [Symbol.toStringTag]: { value: 'Module' } });
17
17
  if (e) {
18
18
  for (const k in e) {
19
19
  if (k !== 'default') {
@@ -30,356 +30,90 @@
30
30
  }
31
31
 
32
32
  const Popper__namespace = /*#__PURE__*/_interopNamespace(Popper);
33
- const Data__default = /*#__PURE__*/_interopDefaultLegacy(Data);
34
33
  const EventHandler__default = /*#__PURE__*/_interopDefaultLegacy(EventHandler);
35
34
  const Manipulator__default = /*#__PURE__*/_interopDefaultLegacy(Manipulator);
36
- const SelectorEngine__default = /*#__PURE__*/_interopDefaultLegacy(SelectorEngine);
37
35
  const BaseComponent__default = /*#__PURE__*/_interopDefaultLegacy(BaseComponent);
36
+ const TemplateFactory__default = /*#__PURE__*/_interopDefaultLegacy(TemplateFactory);
38
37
 
39
38
  /**
40
39
  * --------------------------------------------------------------------------
41
- * Bootstrap (v5.1.3): util/index.js
40
+ * Bootstrap (v5.2.2): tooltip.js
42
41
  * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
43
42
  * --------------------------------------------------------------------------
44
43
  */
45
- const MAX_UID = 1000000;
46
-
47
- const toType = obj => {
48
- if (obj === null || obj === undefined) {
49
- return `${obj}`;
50
- }
51
-
52
- return {}.toString.call(obj).match(/\s([a-z]+)/i)[1].toLowerCase();
53
- };
54
44
  /**
55
- * --------------------------------------------------------------------------
56
- * Public Util Api
57
- * --------------------------------------------------------------------------
58
- */
59
-
60
-
61
- const getUID = prefix => {
62
- do {
63
- prefix += Math.floor(Math.random() * MAX_UID);
64
- } while (document.getElementById(prefix));
65
-
66
- return prefix;
67
- };
68
-
69
- const isElement = obj => {
70
- if (!obj || typeof obj !== 'object') {
71
- return false;
72
- }
73
-
74
- if (typeof obj.jquery !== 'undefined') {
75
- obj = obj[0];
76
- }
77
-
78
- return typeof obj.nodeType !== 'undefined';
79
- };
80
-
81
- const getElement = obj => {
82
- if (isElement(obj)) {
83
- // it's a jQuery object or a node element
84
- return obj.jquery ? obj[0] : obj;
85
- }
86
-
87
- if (typeof obj === 'string' && obj.length > 0) {
88
- return document.querySelector(obj);
89
- }
90
-
91
- return null;
92
- };
93
-
94
- const typeCheckConfig = (componentName, config, configTypes) => {
95
- Object.keys(configTypes).forEach(property => {
96
- const expectedTypes = configTypes[property];
97
- const value = config[property];
98
- const valueType = value && isElement(value) ? 'element' : toType(value);
99
-
100
- if (!new RegExp(expectedTypes).test(valueType)) {
101
- throw new TypeError(`${componentName.toUpperCase()}: Option "${property}" provided type "${valueType}" but expected type "${expectedTypes}".`);
102
- }
103
- });
104
- };
105
-
106
- const findShadowRoot = element => {
107
- if (!document.documentElement.attachShadow) {
108
- return null;
109
- } // Can find the shadow root otherwise it'll return the document
110
-
111
-
112
- if (typeof element.getRootNode === 'function') {
113
- const root = element.getRootNode();
114
- return root instanceof ShadowRoot ? root : null;
115
- }
116
-
117
- if (element instanceof ShadowRoot) {
118
- return element;
119
- } // when we don't find a shadow root
120
-
121
-
122
- if (!element.parentNode) {
123
- return null;
124
- }
125
-
126
- return findShadowRoot(element.parentNode);
127
- };
128
-
129
- const noop = () => {};
130
-
131
- const getjQuery = () => {
132
- const {
133
- jQuery
134
- } = window;
135
-
136
- if (jQuery && !document.body.hasAttribute('data-bs-no-jquery')) {
137
- return jQuery;
138
- }
139
-
140
- return null;
141
- };
142
-
143
- const DOMContentLoadedCallbacks = [];
144
-
145
- const onDOMContentLoaded = callback => {
146
- if (document.readyState === 'loading') {
147
- // add listener on the first call when the document is in loading state
148
- if (!DOMContentLoadedCallbacks.length) {
149
- document.addEventListener('DOMContentLoaded', () => {
150
- DOMContentLoadedCallbacks.forEach(callback => callback());
151
- });
152
- }
153
-
154
- DOMContentLoadedCallbacks.push(callback);
155
- } else {
156
- callback();
157
- }
158
- };
159
-
160
- const isRTL = () => document.documentElement.dir === 'rtl';
161
-
162
- const defineJQueryPlugin = plugin => {
163
- onDOMContentLoaded(() => {
164
- const $ = getjQuery();
165
- /* istanbul ignore if */
166
-
167
- if ($) {
168
- const name = plugin.NAME;
169
- const JQUERY_NO_CONFLICT = $.fn[name];
170
- $.fn[name] = plugin.jQueryInterface;
171
- $.fn[name].Constructor = plugin;
172
-
173
- $.fn[name].noConflict = () => {
174
- $.fn[name] = JQUERY_NO_CONFLICT;
175
- return plugin.jQueryInterface;
176
- };
177
- }
178
- });
179
- };
180
-
181
- /**
182
- * --------------------------------------------------------------------------
183
- * Bootstrap (v5.1.3): util/sanitizer.js
184
- * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
185
- * --------------------------------------------------------------------------
186
- */
187
- const uriAttributes = new Set(['background', 'cite', 'href', 'itemtype', 'longdesc', 'poster', 'src', 'xlink:href']);
188
- const ARIA_ATTRIBUTE_PATTERN = /^aria-[\w-]*$/i;
189
- /**
190
- * A pattern that recognizes a commonly useful subset of URLs that are safe.
191
- *
192
- * Shoutout to Angular https://github.com/angular/angular/blob/12.2.x/packages/core/src/sanitization/url_sanitizer.ts
193
- */
194
-
195
- const SAFE_URL_PATTERN = /^(?:(?:https?|mailto|ftp|tel|file|sms):|[^#&/:?]*(?:[#/?]|$))/i;
196
- /**
197
- * A pattern that matches safe data URLs. Only matches image, video and audio types.
198
- *
199
- * Shoutout to Angular https://github.com/angular/angular/blob/12.2.x/packages/core/src/sanitization/url_sanitizer.ts
200
- */
201
-
202
- const DATA_URL_PATTERN = /^data:(?:image\/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|video\/(?:mpeg|mp4|ogg|webm)|audio\/(?:mp3|oga|ogg|opus));base64,[\d+/a-z]+=*$/i;
203
-
204
- const allowedAttribute = (attribute, allowedAttributeList) => {
205
- const attributeName = attribute.nodeName.toLowerCase();
206
-
207
- if (allowedAttributeList.includes(attributeName)) {
208
- if (uriAttributes.has(attributeName)) {
209
- return Boolean(SAFE_URL_PATTERN.test(attribute.nodeValue) || DATA_URL_PATTERN.test(attribute.nodeValue));
210
- }
211
-
212
- return true;
213
- }
214
-
215
- const regExp = allowedAttributeList.filter(attributeRegex => attributeRegex instanceof RegExp); // Check if a regular expression validates the attribute.
216
-
217
- for (let i = 0, len = regExp.length; i < len; i++) {
218
- if (regExp[i].test(attributeName)) {
219
- return true;
220
- }
221
- }
222
-
223
- return false;
224
- };
225
-
226
- const DefaultAllowlist = {
227
- // Global attributes allowed on any supplied element below.
228
- '*': ['class', 'dir', 'id', 'lang', 'role', ARIA_ATTRIBUTE_PATTERN],
229
- a: ['target', 'href', 'title', 'rel'],
230
- area: [],
231
- b: [],
232
- br: [],
233
- col: [],
234
- code: [],
235
- div: [],
236
- em: [],
237
- hr: [],
238
- h1: [],
239
- h2: [],
240
- h3: [],
241
- h4: [],
242
- h5: [],
243
- h6: [],
244
- i: [],
245
- img: ['src', 'srcset', 'alt', 'title', 'width', 'height'],
246
- li: [],
247
- ol: [],
248
- p: [],
249
- pre: [],
250
- s: [],
251
- small: [],
252
- span: [],
253
- sub: [],
254
- sup: [],
255
- strong: [],
256
- u: [],
257
- ul: []
258
- };
259
- function sanitizeHtml(unsafeHtml, allowList, sanitizeFn) {
260
- if (!unsafeHtml.length) {
261
- return unsafeHtml;
262
- }
263
-
264
- if (sanitizeFn && typeof sanitizeFn === 'function') {
265
- return sanitizeFn(unsafeHtml);
266
- }
267
-
268
- const domParser = new window.DOMParser();
269
- const createdDocument = domParser.parseFromString(unsafeHtml, 'text/html');
270
- const elements = [].concat(...createdDocument.body.querySelectorAll('*'));
271
-
272
- for (let i = 0, len = elements.length; i < len; i++) {
273
- const element = elements[i];
274
- const elementName = element.nodeName.toLowerCase();
275
-
276
- if (!Object.keys(allowList).includes(elementName)) {
277
- element.remove();
278
- continue;
279
- }
280
-
281
- const attributeList = [].concat(...element.attributes);
282
- const allowedAttributes = [].concat(allowList['*'] || [], allowList[elementName] || []);
283
- attributeList.forEach(attribute => {
284
- if (!allowedAttribute(attribute, allowedAttributes)) {
285
- element.removeAttribute(attribute.nodeName);
286
- }
287
- });
288
- }
289
-
290
- return createdDocument.body.innerHTML;
291
- }
292
-
293
- /**
294
- * --------------------------------------------------------------------------
295
- * Bootstrap (v5.1.3): tooltip.js
296
- * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
297
- * --------------------------------------------------------------------------
298
- */
299
- /**
300
- * ------------------------------------------------------------------------
301
45
  * Constants
302
- * ------------------------------------------------------------------------
303
46
  */
304
47
 
305
48
  const NAME = 'tooltip';
306
- const DATA_KEY = 'bs.tooltip';
307
- const EVENT_KEY = `.${DATA_KEY}`;
308
- const CLASS_PREFIX = 'bs-tooltip';
309
49
  const DISALLOWED_ATTRIBUTES = new Set(['sanitize', 'allowList', 'sanitizeFn']);
310
- const DefaultType = {
311
- animation: 'boolean',
312
- template: 'string',
313
- title: '(string|element|function)',
314
- trigger: 'string',
315
- delay: '(number|object)',
316
- html: 'boolean',
317
- selector: '(string|boolean)',
318
- placement: '(string|function)',
319
- offset: '(array|string|function)',
320
- container: '(string|element|boolean)',
321
- fallbackPlacements: 'array',
322
- boundary: '(string|element)',
323
- customClass: '(string|function)',
324
- sanitize: 'boolean',
325
- sanitizeFn: '(null|function)',
326
- allowList: 'object',
327
- popperConfig: '(null|object|function)'
328
- };
50
+ const CLASS_NAME_FADE = 'fade';
51
+ const CLASS_NAME_MODAL = 'modal';
52
+ const CLASS_NAME_SHOW = 'show';
53
+ const SELECTOR_TOOLTIP_INNER = '.tooltip-inner';
54
+ const SELECTOR_MODAL = `.${CLASS_NAME_MODAL}`;
55
+ const EVENT_MODAL_HIDE = 'hide.bs.modal';
56
+ const TRIGGER_HOVER = 'hover';
57
+ const TRIGGER_FOCUS = 'focus';
58
+ const TRIGGER_CLICK = 'click';
59
+ const TRIGGER_MANUAL = 'manual';
60
+ const EVENT_HIDE = 'hide';
61
+ const EVENT_HIDDEN = 'hidden';
62
+ const EVENT_SHOW = 'show';
63
+ const EVENT_SHOWN = 'shown';
64
+ const EVENT_INSERTED = 'inserted';
65
+ const EVENT_CLICK = 'click';
66
+ const EVENT_FOCUSIN = 'focusin';
67
+ const EVENT_FOCUSOUT = 'focusout';
68
+ const EVENT_MOUSEENTER = 'mouseenter';
69
+ const EVENT_MOUSELEAVE = 'mouseleave';
329
70
  const AttachmentMap = {
330
71
  AUTO: 'auto',
331
72
  TOP: 'top',
332
- RIGHT: isRTL() ? 'left' : 'right',
73
+ RIGHT: index.isRTL() ? 'left' : 'right',
333
74
  BOTTOM: 'bottom',
334
- LEFT: isRTL() ? 'right' : 'left'
75
+ LEFT: index.isRTL() ? 'right' : 'left'
335
76
  };
336
77
  const Default = {
78
+ allowList: sanitizer.DefaultAllowlist,
337
79
  animation: true,
338
- template: '<div class="tooltip" role="tooltip">' + '<div class="tooltip-arrow"></div>' + '<div class="tooltip-inner"></div>' + '</div>',
339
- trigger: 'hover focus',
340
- title: '',
80
+ boundary: 'clippingParents',
81
+ container: false,
82
+ customClass: '',
341
83
  delay: 0,
84
+ fallbackPlacements: ['top', 'right', 'bottom', 'left'],
342
85
  html: false,
343
- selector: false,
344
- placement: 'top',
345
86
  offset: [0, 0],
346
- container: false,
347
- fallbackPlacements: ['top', 'right', 'bottom', 'left'],
348
- boundary: 'clippingParents',
349
- customClass: '',
87
+ placement: 'top',
88
+ popperConfig: null,
350
89
  sanitize: true,
351
90
  sanitizeFn: null,
352
- allowList: DefaultAllowlist,
353
- popperConfig: null
91
+ selector: false,
92
+ template: '<div class="tooltip" role="tooltip">' + '<div class="tooltip-arrow"></div>' + '<div class="tooltip-inner"></div>' + '</div>',
93
+ title: '',
94
+ trigger: 'hover focus'
354
95
  };
355
- const Event = {
356
- HIDE: `hide${EVENT_KEY}`,
357
- HIDDEN: `hidden${EVENT_KEY}`,
358
- SHOW: `show${EVENT_KEY}`,
359
- SHOWN: `shown${EVENT_KEY}`,
360
- INSERTED: `inserted${EVENT_KEY}`,
361
- CLICK: `click${EVENT_KEY}`,
362
- FOCUSIN: `focusin${EVENT_KEY}`,
363
- FOCUSOUT: `focusout${EVENT_KEY}`,
364
- MOUSEENTER: `mouseenter${EVENT_KEY}`,
365
- MOUSELEAVE: `mouseleave${EVENT_KEY}`
96
+ const DefaultType = {
97
+ allowList: 'object',
98
+ animation: 'boolean',
99
+ boundary: '(string|element)',
100
+ container: '(string|element|boolean)',
101
+ customClass: '(string|function)',
102
+ delay: '(number|object)',
103
+ fallbackPlacements: 'array',
104
+ html: 'boolean',
105
+ offset: '(array|string|function)',
106
+ placement: '(string|function)',
107
+ popperConfig: '(null|object|function)',
108
+ sanitize: 'boolean',
109
+ sanitizeFn: '(null|function)',
110
+ selector: '(string|boolean)',
111
+ template: 'string',
112
+ title: '(string|element|function)',
113
+ trigger: 'string'
366
114
  };
367
- const CLASS_NAME_FADE = 'fade';
368
- const CLASS_NAME_MODAL = 'modal';
369
- const CLASS_NAME_SHOW = 'show';
370
- const HOVER_STATE_SHOW = 'show';
371
- const HOVER_STATE_OUT = 'out';
372
- const SELECTOR_TOOLTIP_INNER = '.tooltip-inner';
373
- const SELECTOR_MODAL = `.${CLASS_NAME_MODAL}`;
374
- const EVENT_MODAL_HIDE = 'hide.bs.modal';
375
- const TRIGGER_HOVER = 'hover';
376
- const TRIGGER_FOCUS = 'focus';
377
- const TRIGGER_CLICK = 'click';
378
- const TRIGGER_MANUAL = 'manual';
379
115
  /**
380
- * ------------------------------------------------------------------------
381
- * Class Definition
382
- * ------------------------------------------------------------------------
116
+ * Class definition
383
117
  */
384
118
 
385
119
  class Tooltip extends BaseComponent__default.default {
@@ -388,18 +122,23 @@
388
122
  throw new TypeError('Bootstrap\'s tooltips require Popper (https://popper.js.org)');
389
123
  }
390
124
 
391
- super(element); // private
125
+ super(element, config); // Private
392
126
 
393
127
  this._isEnabled = true;
394
128
  this._timeout = 0;
395
- this._hoverState = '';
129
+ this._isHovered = null;
396
130
  this._activeTrigger = {};
397
- this._popper = null; // Protected
131
+ this._popper = null;
132
+ this._templateFactory = null;
133
+ this._newContent = null; // Protected
398
134
 
399
- this._config = this._getConfig(config);
400
135
  this.tip = null;
401
136
 
402
137
  this._setListeners();
138
+
139
+ if (!this._config.selector) {
140
+ this._fixTitle();
141
+ }
403
142
  } // Getters
404
143
 
405
144
 
@@ -407,16 +146,12 @@
407
146
  return Default;
408
147
  }
409
148
 
410
- static get NAME() {
411
- return NAME;
412
- }
413
-
414
- static get Event() {
415
- return Event;
416
- }
417
-
418
149
  static get DefaultType() {
419
150
  return DefaultType;
151
+ }
152
+
153
+ static get NAME() {
154
+ return NAME;
420
155
  } // Public
421
156
 
422
157
 
@@ -432,30 +167,20 @@
432
167
  this._isEnabled = !this._isEnabled;
433
168
  }
434
169
 
435
- toggle(event) {
170
+ toggle() {
436
171
  if (!this._isEnabled) {
437
172
  return;
438
173
  }
439
174
 
440
- if (event) {
441
- const context = this._initializeOnDelegatedTarget(event);
442
-
443
- context._activeTrigger.click = !context._activeTrigger.click;
175
+ this._activeTrigger.click = !this._activeTrigger.click;
444
176
 
445
- if (context._isWithActiveTrigger()) {
446
- context._enter(null, context);
447
- } else {
448
- context._leave(null, context);
449
- }
450
- } else {
451
- if (this.getTipElement().classList.contains(CLASS_NAME_SHOW)) {
452
- this._leave(null, this);
177
+ if (this._isShown()) {
178
+ this._leave();
453
179
 
454
- return;
455
- }
456
-
457
- this._enter(null, this);
180
+ return;
458
181
  }
182
+
183
+ this._enter();
459
184
  }
460
185
 
461
186
  dispose() {
@@ -466,6 +191,10 @@
466
191
  this.tip.remove();
467
192
  }
468
193
 
194
+ if (this._element.getAttribute('data-bs-original-title')) {
195
+ this._element.setAttribute('title', this._element.getAttribute('data-bs-original-title'));
196
+ }
197
+
469
198
  this._disposePopper();
470
199
 
471
200
  super.dispose();
@@ -476,233 +205,206 @@
476
205
  throw new Error('Please use show on visible elements');
477
206
  }
478
207
 
479
- if (!(this.isWithContent() && this._isEnabled)) {
208
+ if (!(this._isWithContent() && this._isEnabled)) {
480
209
  return;
481
210
  }
482
211
 
483
- const showEvent = EventHandler__default.default.trigger(this._element, this.constructor.Event.SHOW);
484
- const shadowRoot = findShadowRoot(this._element);
485
- const isInTheDom = shadowRoot === null ? this._element.ownerDocument.documentElement.contains(this._element) : shadowRoot.contains(this._element);
212
+ const showEvent = EventHandler__default.default.trigger(this._element, this.constructor.eventName(EVENT_SHOW));
213
+ const shadowRoot = index.findShadowRoot(this._element);
214
+
215
+ const isInTheDom = (shadowRoot || this._element.ownerDocument.documentElement).contains(this._element);
486
216
 
487
217
  if (showEvent.defaultPrevented || !isInTheDom) {
488
218
  return;
489
- } // A trick to recreate a tooltip in case a new title is given by using the NOT documented `data-bs-original-title`
490
- // This will be removed later in favor of a `setContent` method
219
+ } // todo v6 remove this OR make it optional
491
220
 
492
221
 
493
- if (this.constructor.NAME === 'tooltip' && this.tip && this.getTitle() !== this.tip.querySelector(SELECTOR_TOOLTIP_INNER).innerHTML) {
494
- this._disposePopper();
495
-
222
+ if (this.tip) {
496
223
  this.tip.remove();
497
224
  this.tip = null;
498
225
  }
499
226
 
500
- const tip = this.getTipElement();
501
- const tipId = getUID(this.constructor.NAME);
502
- tip.setAttribute('id', tipId);
227
+ const tip = this._getTipElement();
503
228
 
504
- this._element.setAttribute('aria-describedby', tipId);
505
-
506
- if (this._config.animation) {
507
- tip.classList.add(CLASS_NAME_FADE);
508
- }
509
-
510
- const placement = typeof this._config.placement === 'function' ? this._config.placement.call(this, tip, this._element) : this._config.placement;
511
-
512
- const attachment = this._getAttachment(placement);
513
-
514
- this._addAttachmentClass(attachment);
229
+ this._element.setAttribute('aria-describedby', tip.getAttribute('id'));
515
230
 
516
231
  const {
517
232
  container
518
233
  } = this._config;
519
- Data__default.default.set(tip, this.constructor.DATA_KEY, this);
520
234
 
521
235
  if (!this._element.ownerDocument.documentElement.contains(this.tip)) {
522
236
  container.append(tip);
523
- EventHandler__default.default.trigger(this._element, this.constructor.Event.INSERTED);
237
+ EventHandler__default.default.trigger(this._element, this.constructor.eventName(EVENT_INSERTED));
524
238
  }
525
239
 
526
240
  if (this._popper) {
527
241
  this._popper.update();
528
242
  } else {
529
- this._popper = Popper__namespace.createPopper(this._element, tip, this._getPopperConfig(attachment));
243
+ this._popper = this._createPopper(tip);
530
244
  }
531
245
 
532
- tip.classList.add(CLASS_NAME_SHOW);
533
-
534
- const customClass = this._resolvePossibleFunction(this._config.customClass);
535
-
536
- if (customClass) {
537
- tip.classList.add(...customClass.split(' '));
538
- } // If this is a touch-enabled device we add extra
246
+ tip.classList.add(CLASS_NAME_SHOW); // If this is a touch-enabled device we add extra
539
247
  // empty mouseover listeners to the body's immediate children;
540
248
  // only needed because of broken event delegation on iOS
541
249
  // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html
542
250
 
543
-
544
251
  if ('ontouchstart' in document.documentElement) {
545
- [].concat(...document.body.children).forEach(element => {
546
- EventHandler__default.default.on(element, 'mouseover', noop);
547
- });
252
+ for (const element of [].concat(...document.body.children)) {
253
+ EventHandler__default.default.on(element, 'mouseover', index.noop);
254
+ }
548
255
  }
549
256
 
550
257
  const complete = () => {
551
- const prevHoverState = this._hoverState;
552
- this._hoverState = null;
553
- EventHandler__default.default.trigger(this._element, this.constructor.Event.SHOWN);
258
+ EventHandler__default.default.trigger(this._element, this.constructor.eventName(EVENT_SHOWN));
554
259
 
555
- if (prevHoverState === HOVER_STATE_OUT) {
556
- this._leave(null, this);
260
+ if (this._isHovered === false) {
261
+ this._leave();
557
262
  }
558
- };
559
263
 
560
- const isAnimated = this.tip.classList.contains(CLASS_NAME_FADE);
264
+ this._isHovered = false;
265
+ };
561
266
 
562
- this._queueCallback(complete, this.tip, isAnimated);
267
+ this._queueCallback(complete, this.tip, this._isAnimated());
563
268
  }
564
269
 
565
270
  hide() {
566
- if (!this._popper) {
271
+ if (!this._isShown()) {
567
272
  return;
568
273
  }
569
274
 
570
- const tip = this.getTipElement();
571
-
572
- const complete = () => {
573
- if (this._isWithActiveTrigger()) {
574
- return;
575
- }
576
-
577
- if (this._hoverState !== HOVER_STATE_SHOW) {
578
- tip.remove();
579
- }
580
-
581
- this._cleanTipClass();
582
-
583
- this._element.removeAttribute('aria-describedby');
584
-
585
- EventHandler__default.default.trigger(this._element, this.constructor.Event.HIDDEN);
586
-
587
- this._disposePopper();
588
- };
589
-
590
- const hideEvent = EventHandler__default.default.trigger(this._element, this.constructor.Event.HIDE);
275
+ const hideEvent = EventHandler__default.default.trigger(this._element, this.constructor.eventName(EVENT_HIDE));
591
276
 
592
277
  if (hideEvent.defaultPrevented) {
593
278
  return;
594
279
  }
595
280
 
281
+ const tip = this._getTipElement();
282
+
596
283
  tip.classList.remove(CLASS_NAME_SHOW); // If this is a touch-enabled device we remove the extra
597
284
  // empty mouseover listeners we added for iOS support
598
285
 
599
286
  if ('ontouchstart' in document.documentElement) {
600
- [].concat(...document.body.children).forEach(element => EventHandler__default.default.off(element, 'mouseover', noop));
287
+ for (const element of [].concat(...document.body.children)) {
288
+ EventHandler__default.default.off(element, 'mouseover', index.noop);
289
+ }
601
290
  }
602
291
 
603
292
  this._activeTrigger[TRIGGER_CLICK] = false;
604
293
  this._activeTrigger[TRIGGER_FOCUS] = false;
605
294
  this._activeTrigger[TRIGGER_HOVER] = false;
606
- const isAnimated = this.tip.classList.contains(CLASS_NAME_FADE);
295
+ this._isHovered = null; // it is a trick to support manual triggering
296
+
297
+ const complete = () => {
298
+ if (this._isWithActiveTrigger()) {
299
+ return;
300
+ }
301
+
302
+ if (!this._isHovered) {
303
+ tip.remove();
304
+ }
607
305
 
608
- this._queueCallback(complete, this.tip, isAnimated);
306
+ this._element.removeAttribute('aria-describedby');
307
+
308
+ EventHandler__default.default.trigger(this._element, this.constructor.eventName(EVENT_HIDDEN));
309
+
310
+ this._disposePopper();
311
+ };
609
312
 
610
- this._hoverState = '';
313
+ this._queueCallback(complete, this.tip, this._isAnimated());
611
314
  }
612
315
 
613
316
  update() {
614
- if (this._popper !== null) {
317
+ if (this._popper) {
615
318
  this._popper.update();
616
319
  }
617
320
  } // Protected
618
321
 
619
322
 
620
- isWithContent() {
621
- return Boolean(this.getTitle());
323
+ _isWithContent() {
324
+ return Boolean(this._getTitle());
622
325
  }
623
326
 
624
- getTipElement() {
625
- if (this.tip) {
626
- return this.tip;
327
+ _getTipElement() {
328
+ if (!this.tip) {
329
+ this.tip = this._createTipElement(this._newContent || this._getContentForTemplate());
627
330
  }
628
331
 
629
- const element = document.createElement('div');
630
- element.innerHTML = this._config.template;
631
- const tip = element.children[0];
632
- this.setContent(tip);
633
- tip.classList.remove(CLASS_NAME_FADE, CLASS_NAME_SHOW);
634
- this.tip = tip;
635
332
  return this.tip;
636
333
  }
637
334
 
638
- setContent(tip) {
639
- this._sanitizeAndSetContent(tip, this.getTitle(), SELECTOR_TOOLTIP_INNER);
640
- }
335
+ _createTipElement(content) {
336
+ const tip = this._getTemplateFactory(content).toHtml(); // todo: remove this check on v6
641
337
 
642
- _sanitizeAndSetContent(template, content, selector) {
643
- const templateElement = SelectorEngine__default.default.findOne(selector, template);
644
338
 
645
- if (!content && templateElement) {
646
- templateElement.remove();
647
- return;
648
- } // we use append for html objects to maintain js events
339
+ if (!tip) {
340
+ return null;
341
+ }
649
342
 
343
+ tip.classList.remove(CLASS_NAME_FADE, CLASS_NAME_SHOW); // todo: on v6 the following can be achieved with CSS only
650
344
 
651
- this.setElementContent(templateElement, content);
652
- }
345
+ tip.classList.add(`bs-${this.constructor.NAME}-auto`);
346
+ const tipId = index.getUID(this.constructor.NAME).toString();
347
+ tip.setAttribute('id', tipId);
653
348
 
654
- setElementContent(element, content) {
655
- if (element === null) {
656
- return;
349
+ if (this._isAnimated()) {
350
+ tip.classList.add(CLASS_NAME_FADE);
657
351
  }
658
352
 
659
- if (isElement(content)) {
660
- content = getElement(content); // content is a DOM node or a jQuery
353
+ return tip;
354
+ }
661
355
 
662
- if (this._config.html) {
663
- if (content.parentNode !== element) {
664
- element.innerHTML = '';
665
- element.append(content);
666
- }
667
- } else {
668
- element.textContent = content.textContent;
669
- }
356
+ setContent(content) {
357
+ this._newContent = content;
670
358
 
671
- return;
672
- }
359
+ if (this._isShown()) {
360
+ this._disposePopper();
673
361
 
674
- if (this._config.html) {
675
- if (this._config.sanitize) {
676
- content = sanitizeHtml(content, this._config.allowList, this._config.sanitizeFn);
677
- }
362
+ this.show();
363
+ }
364
+ }
678
365
 
679
- element.innerHTML = content;
366
+ _getTemplateFactory(content) {
367
+ if (this._templateFactory) {
368
+ this._templateFactory.changeContent(content);
680
369
  } else {
681
- element.textContent = content;
370
+ this._templateFactory = new TemplateFactory__default.default({ ...this._config,
371
+ // the `content` var has to be after `this._config`
372
+ // to override config.content in case of popover
373
+ content,
374
+ extraClass: this._resolvePossibleFunction(this._config.customClass)
375
+ });
682
376
  }
683
- }
684
377
 
685
- getTitle() {
686
- const title = this._element.getAttribute('data-bs-original-title') || this._config.title;
378
+ return this._templateFactory;
379
+ }
687
380
 
688
- return this._resolvePossibleFunction(title);
381
+ _getContentForTemplate() {
382
+ return {
383
+ [SELECTOR_TOOLTIP_INNER]: this._getTitle()
384
+ };
689
385
  }
690
386
 
691
- updateAttachment(attachment) {
692
- if (attachment === 'right') {
693
- return 'end';
694
- }
387
+ _getTitle() {
388
+ return this._resolvePossibleFunction(this._config.title) || this._element.getAttribute('data-bs-original-title');
389
+ } // Private
695
390
 
696
- if (attachment === 'left') {
697
- return 'start';
698
- }
699
391
 
700
- return attachment;
701
- } // Private
392
+ _initializeOnDelegatedTarget(event) {
393
+ return this.constructor.getOrCreateInstance(event.delegateTarget, this._getDelegateConfig());
394
+ }
702
395
 
396
+ _isAnimated() {
397
+ return this._config.animation || this.tip && this.tip.classList.contains(CLASS_NAME_FADE);
398
+ }
703
399
 
704
- _initializeOnDelegatedTarget(event, context) {
705
- return context || this.constructor.getOrCreateInstance(event.delegateTarget, this._getDelegateConfig());
400
+ _isShown() {
401
+ return this.tip && this.tip.classList.contains(CLASS_NAME_SHOW);
402
+ }
403
+
404
+ _createPopper(tip) {
405
+ const placement = typeof this._config.placement === 'function' ? this._config.placement.call(this, tip, this._element) : this._config.placement;
406
+ const attachment = AttachmentMap[placement.toUpperCase()];
407
+ return Popper__namespace.createPopper(this._element, tip, this._getPopperConfig(attachment));
706
408
  }
707
409
 
708
410
  _getOffset() {
@@ -711,7 +413,7 @@
711
413
  } = this._config;
712
414
 
713
415
  if (typeof offset === 'string') {
714
- return offset.split(',').map(val => Number.parseInt(val, 10));
416
+ return offset.split(',').map(value => Number.parseInt(value, 10));
715
417
  }
716
418
 
717
419
  if (typeof offset === 'function') {
@@ -721,8 +423,8 @@
721
423
  return offset;
722
424
  }
723
425
 
724
- _resolvePossibleFunction(content) {
725
- return typeof content === 'function' ? content.call(this._element) : content;
426
+ _resolvePossibleFunction(arg) {
427
+ return typeof arg === 'function' ? arg.call(this._element) : arg;
726
428
  }
727
429
 
728
430
  _getPopperConfig(attachment) {
@@ -749,43 +451,50 @@
749
451
  element: `.${this.constructor.NAME}-arrow`
750
452
  }
751
453
  }, {
752
- name: 'onChange',
454
+ name: 'preSetPlacement',
753
455
  enabled: true,
754
- phase: 'afterWrite',
755
- fn: data => this._handlePopperPlacementChange(data)
756
- }],
757
- onFirstUpdate: data => {
758
- if (data.options.placement !== data.placement) {
759
- this._handlePopperPlacementChange(data);
456
+ phase: 'beforeMain',
457
+ fn: data => {
458
+ // Pre-set Popper's placement attribute in order to read the arrow sizes properly.
459
+ // Otherwise, Popper mixes up the width and height dimensions since the initial arrow style is for top placement
460
+ this._getTipElement().setAttribute('data-popper-placement', data.state.placement);
760
461
  }
761
- }
462
+ }]
762
463
  };
763
464
  return { ...defaultBsPopperConfig,
764
465
  ...(typeof this._config.popperConfig === 'function' ? this._config.popperConfig(defaultBsPopperConfig) : this._config.popperConfig)
765
466
  };
766
467
  }
767
468
 
768
- _addAttachmentClass(attachment) {
769
- this.getTipElement().classList.add(`${this._getBasicClassPrefix()}-${this.updateAttachment(attachment)}`);
770
- }
771
-
772
- _getAttachment(placement) {
773
- return AttachmentMap[placement.toUpperCase()];
774
- }
775
-
776
469
  _setListeners() {
777
470
  const triggers = this._config.trigger.split(' ');
778
471
 
779
- triggers.forEach(trigger => {
472
+ for (const trigger of triggers) {
780
473
  if (trigger === 'click') {
781
- EventHandler__default.default.on(this._element, this.constructor.Event.CLICK, this._config.selector, event => this.toggle(event));
474
+ EventHandler__default.default.on(this._element, this.constructor.eventName(EVENT_CLICK), this._config.selector, event => {
475
+ const context = this._initializeOnDelegatedTarget(event);
476
+
477
+ context.toggle();
478
+ });
782
479
  } else if (trigger !== TRIGGER_MANUAL) {
783
- const eventIn = trigger === TRIGGER_HOVER ? this.constructor.Event.MOUSEENTER : this.constructor.Event.FOCUSIN;
784
- const eventOut = trigger === TRIGGER_HOVER ? this.constructor.Event.MOUSELEAVE : this.constructor.Event.FOCUSOUT;
785
- EventHandler__default.default.on(this._element, eventIn, this._config.selector, event => this._enter(event));
786
- EventHandler__default.default.on(this._element, eventOut, this._config.selector, event => this._leave(event));
480
+ const eventIn = trigger === TRIGGER_HOVER ? this.constructor.eventName(EVENT_MOUSEENTER) : this.constructor.eventName(EVENT_FOCUSIN);
481
+ const eventOut = trigger === TRIGGER_HOVER ? this.constructor.eventName(EVENT_MOUSELEAVE) : this.constructor.eventName(EVENT_FOCUSOUT);
482
+ EventHandler__default.default.on(this._element, eventIn, this._config.selector, event => {
483
+ const context = this._initializeOnDelegatedTarget(event);
484
+
485
+ context._activeTrigger[event.type === 'focusin' ? TRIGGER_FOCUS : TRIGGER_HOVER] = true;
486
+
487
+ context._enter();
488
+ });
489
+ EventHandler__default.default.on(this._element, eventOut, this._config.selector, event => {
490
+ const context = this._initializeOnDelegatedTarget(event);
491
+
492
+ context._activeTrigger[event.type === 'focusout' ? TRIGGER_FOCUS : TRIGGER_HOVER] = context._element.contains(event.relatedTarget);
493
+
494
+ context._leave();
495
+ });
787
496
  }
788
- });
497
+ }
789
498
 
790
499
  this._hideModalHandler = () => {
791
500
  if (this._element) {
@@ -794,108 +503,85 @@
794
503
  };
795
504
 
796
505
  EventHandler__default.default.on(this._element.closest(SELECTOR_MODAL), EVENT_MODAL_HIDE, this._hideModalHandler);
797
-
798
- if (this._config.selector) {
799
- this._config = { ...this._config,
800
- trigger: 'manual',
801
- selector: ''
802
- };
803
- } else {
804
- this._fixTitle();
805
- }
806
506
  }
807
507
 
808
508
  _fixTitle() {
809
509
  const title = this._element.getAttribute('title');
810
510
 
811
- const originalTitleType = typeof this._element.getAttribute('data-bs-original-title');
812
-
813
- if (title || originalTitleType !== 'string') {
814
- this._element.setAttribute('data-bs-original-title', title || '');
815
-
816
- if (title && !this._element.getAttribute('aria-label') && !this._element.textContent) {
817
- this._element.setAttribute('aria-label', title);
818
- }
819
-
820
- this._element.setAttribute('title', '');
511
+ if (!title) {
512
+ return;
821
513
  }
822
- }
823
-
824
- _enter(event, context) {
825
- context = this._initializeOnDelegatedTarget(event, context);
826
514
 
827
- if (event) {
828
- context._activeTrigger[event.type === 'focusin' ? TRIGGER_FOCUS : TRIGGER_HOVER] = true;
515
+ if (!this._element.getAttribute('aria-label') && !this._element.textContent.trim()) {
516
+ this._element.setAttribute('aria-label', title);
829
517
  }
830
518
 
831
- if (context.getTipElement().classList.contains(CLASS_NAME_SHOW) || context._hoverState === HOVER_STATE_SHOW) {
832
- context._hoverState = HOVER_STATE_SHOW;
833
- return;
834
- }
519
+ this._element.setAttribute('data-bs-original-title', title); // DO NOT USE IT. Is only for backwards compatibility
835
520
 
836
- clearTimeout(context._timeout);
837
- context._hoverState = HOVER_STATE_SHOW;
838
521
 
839
- if (!context._config.delay || !context._config.delay.show) {
840
- context.show();
522
+ this._element.removeAttribute('title');
523
+ }
524
+
525
+ _enter() {
526
+ if (this._isShown() || this._isHovered) {
527
+ this._isHovered = true;
841
528
  return;
842
529
  }
843
530
 
844
- context._timeout = setTimeout(() => {
845
- if (context._hoverState === HOVER_STATE_SHOW) {
846
- context.show();
531
+ this._isHovered = true;
532
+
533
+ this._setTimeout(() => {
534
+ if (this._isHovered) {
535
+ this.show();
847
536
  }
848
- }, context._config.delay.show);
537
+ }, this._config.delay.show);
849
538
  }
850
539
 
851
- _leave(event, context) {
852
- context = this._initializeOnDelegatedTarget(event, context);
853
-
854
- if (event) {
855
- context._activeTrigger[event.type === 'focusout' ? TRIGGER_FOCUS : TRIGGER_HOVER] = context._element.contains(event.relatedTarget);
856
- }
857
-
858
- if (context._isWithActiveTrigger()) {
540
+ _leave() {
541
+ if (this._isWithActiveTrigger()) {
859
542
  return;
860
543
  }
861
544
 
862
- clearTimeout(context._timeout);
863
- context._hoverState = HOVER_STATE_OUT;
545
+ this._isHovered = false;
864
546
 
865
- if (!context._config.delay || !context._config.delay.hide) {
866
- context.hide();
867
- return;
868
- }
869
-
870
- context._timeout = setTimeout(() => {
871
- if (context._hoverState === HOVER_STATE_OUT) {
872
- context.hide();
547
+ this._setTimeout(() => {
548
+ if (!this._isHovered) {
549
+ this.hide();
873
550
  }
874
- }, context._config.delay.hide);
551
+ }, this._config.delay.hide);
875
552
  }
876
553
 
877
- _isWithActiveTrigger() {
878
- for (const trigger in this._activeTrigger) {
879
- if (this._activeTrigger[trigger]) {
880
- return true;
881
- }
882
- }
554
+ _setTimeout(handler, timeout) {
555
+ clearTimeout(this._timeout);
556
+ this._timeout = setTimeout(handler, timeout);
557
+ }
883
558
 
884
- return false;
559
+ _isWithActiveTrigger() {
560
+ return Object.values(this._activeTrigger).includes(true);
885
561
  }
886
562
 
887
563
  _getConfig(config) {
888
564
  const dataAttributes = Manipulator__default.default.getDataAttributes(this._element);
889
- Object.keys(dataAttributes).forEach(dataAttr => {
890
- if (DISALLOWED_ATTRIBUTES.has(dataAttr)) {
891
- delete dataAttributes[dataAttr];
565
+
566
+ for (const dataAttribute of Object.keys(dataAttributes)) {
567
+ if (DISALLOWED_ATTRIBUTES.has(dataAttribute)) {
568
+ delete dataAttributes[dataAttribute];
892
569
  }
893
- });
894
- config = { ...this.constructor.Default,
895
- ...dataAttributes,
570
+ }
571
+
572
+ config = { ...dataAttributes,
896
573
  ...(typeof config === 'object' && config ? config : {})
897
574
  };
898
- config.container = config.container === false ? document.body : getElement(config.container);
575
+ config = this._mergeConfigObj(config);
576
+ config = this._configAfterMerge(config);
577
+
578
+ this._typeCheckConfig(config);
579
+
580
+ return config;
581
+ }
582
+
583
+ _configAfterMerge(config) {
584
+ config.container = config.container === false ? document.body : index.getElement(config.container);
899
585
 
900
586
  if (typeof config.delay === 'number') {
901
587
  config.delay = {
@@ -912,12 +598,6 @@
912
598
  config.content = config.content.toString();
913
599
  }
914
600
 
915
- typeCheckConfig(NAME, config, this.constructor.DefaultType);
916
-
917
- if (config.sanitize) {
918
- config.template = sanitizeHtml(config.template, config.allowList, config.sanitizeFn);
919
- }
920
-
921
601
  return config;
922
602
  }
923
603
 
@@ -928,44 +608,16 @@
928
608
  if (this.constructor.Default[key] !== this._config[key]) {
929
609
  config[key] = this._config[key];
930
610
  }
931
- } // In the future can be replaced with:
611
+ }
612
+
613
+ config.selector = false;
614
+ config.trigger = 'manual'; // In the future can be replaced with:
932
615
  // const keysWithDifferentValues = Object.entries(this._config).filter(entry => this.constructor.Default[entry[0]] !== this._config[entry[0]])
933
616
  // `Object.fromEntries(keysWithDifferentValues)`
934
617
 
935
-
936
618
  return config;
937
619
  }
938
620
 
939
- _cleanTipClass() {
940
- const tip = this.getTipElement();
941
- const basicClassPrefixRegex = new RegExp(`(^|\\s)${this._getBasicClassPrefix()}\\S+`, 'g');
942
- const tabClass = tip.getAttribute('class').match(basicClassPrefixRegex);
943
-
944
- if (tabClass !== null && tabClass.length > 0) {
945
- tabClass.map(token => token.trim()).forEach(tClass => tip.classList.remove(tClass));
946
- }
947
- }
948
-
949
- _getBasicClassPrefix() {
950
- return CLASS_PREFIX;
951
- }
952
-
953
- _handlePopperPlacementChange(popperData) {
954
- const {
955
- state
956
- } = popperData;
957
-
958
- if (!state) {
959
- return;
960
- }
961
-
962
- this.tip = state.elements.popper;
963
-
964
- this._cleanTipClass();
965
-
966
- this._addAttachmentClass(this._getAttachment(state.placement));
967
- }
968
-
969
621
  _disposePopper() {
970
622
  if (this._popper) {
971
623
  this._popper.destroy();
@@ -979,26 +631,25 @@
979
631
  return this.each(function () {
980
632
  const data = Tooltip.getOrCreateInstance(this, config);
981
633
 
982
- if (typeof config === 'string') {
983
- if (typeof data[config] === 'undefined') {
984
- throw new TypeError(`No method named "${config}"`);
985
- }
634
+ if (typeof config !== 'string') {
635
+ return;
636
+ }
986
637
 
987
- data[config]();
638
+ if (typeof data[config] === 'undefined') {
639
+ throw new TypeError(`No method named "${config}"`);
988
640
  }
641
+
642
+ data[config]();
989
643
  });
990
644
  }
991
645
 
992
646
  }
993
647
  /**
994
- * ------------------------------------------------------------------------
995
648
  * jQuery
996
- * ------------------------------------------------------------------------
997
- * add .Tooltip to jQuery only if jQuery is present
998
649
  */
999
650
 
1000
651
 
1001
- defineJQueryPlugin(Tooltip);
652
+ index.defineJQueryPlugin(Tooltip);
1002
653
 
1003
654
  return Tooltip;
1004
655