Skip to content

Commit

Permalink
Ability to add custom class in tooltip/popover (#32217)
Browse files Browse the repository at this point in the history
Porting of #31834 to main.

Co-authored-by: XhmikosR <xhmikosr@gmail.com>
  • Loading branch information
rohit2sharma95 and XhmikosR committed Nov 25, 2020
1 parent d61f506 commit c348ad4
Show file tree
Hide file tree
Showing 6 changed files with 97 additions and 1 deletion.
2 changes: 1 addition & 1 deletion .bundlewatch.config.json
Expand Up @@ -38,7 +38,7 @@
},
{
"path": "./dist/js/bootstrap.bundle.min.js",
"maxSize": "22 kB"
"maxSize": "22.25 kB"
},
{
"path": "./dist/js/bootstrap.esm.js",
Expand Down
7 changes: 7 additions & 0 deletions js/src/tooltip.js
Expand Up @@ -54,6 +54,7 @@ const DefaultType = {
container: '(string|element|boolean)',
fallbackPlacement: '(string|array)',
boundary: '(string|element)',
customClass: '(string|function)',
sanitize: 'boolean',
sanitizeFn: '(null|function)',
allowList: 'object',
Expand Down Expand Up @@ -83,6 +84,7 @@ const Default = {
container: false,
fallbackPlacement: 'flip',
boundary: 'scrollParent',
customClass: '',
sanitize: true,
sanitizeFn: null,
allowList: DefaultAllowlist,
Expand Down Expand Up @@ -296,6 +298,11 @@ class Tooltip {

tip.classList.add(CLASS_NAME_SHOW)

const customClass = typeof this.config.customClass === 'function' ? this.config.customClass() : this.config.customClass
if (customClass) {
tip.classList.add(...customClass.split(' '))
}

// If this is a touch-enabled device we add extra
// empty mouseover listeners to the body's immediate children;
// only needed because of broken event delegation on iOS
Expand Down
16 changes: 16 additions & 0 deletions js/tests/unit/popover.spec.js
Expand Up @@ -116,6 +116,22 @@ describe('Popover', () => {

popover.show()
})

it('should show a popover with provided custom class', done => {
fixtureEl.innerHTML = '<a href="#" title="Popover" data-bs-content="https://twitter.com/getbootstrap" data-bs-custom-class="custom-class">BS twitter</a>'

const popoverEl = fixtureEl.querySelector('a')
const popover = new Popover(popoverEl)

popoverEl.addEventListener('shown.bs.popover', () => {
const tip = document.querySelector('.popover')
expect(tip).toBeDefined()
expect(tip.classList.contains('custom-class')).toBeTrue()
done()
})

popover.show()
})
})

describe('hide', () => {
Expand Down
55 changes: 55 additions & 0 deletions js/tests/unit/tooltip.spec.js
Expand Up @@ -632,6 +632,61 @@ describe('Tooltip', () => {

tooltipEl.dispatchEvent(createEvent('mouseover'))
})

it('should show a tooltip with custom class provided in data attributes', done => {
fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip" data-bs-custom-class="custom-class">'

const tooltipEl = fixtureEl.querySelector('a')
const tooltip = new Tooltip(tooltipEl)

tooltipEl.addEventListener('shown.bs.tooltip', () => {
const tip = document.querySelector('.tooltip')
expect(tip).toBeDefined()
expect(tip.classList.contains('custom-class')).toBeTrue()
done()
})

tooltip.show()
})

it('should show a tooltip with custom class provided as a string in config', done => {
fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip">'

const tooltipEl = fixtureEl.querySelector('a')
const tooltip = new Tooltip(tooltipEl, {
customClass: 'custom-class custom-class-2'
})

tooltipEl.addEventListener('shown.bs.tooltip', () => {
const tip = document.querySelector('.tooltip')
expect(tip).toBeDefined()
expect(tip.classList.contains('custom-class')).toBeTrue()
expect(tip.classList.contains('custom-class-2')).toBeTrue()
done()
})

tooltip.show()
})

it('should show a tooltip with custom class provided as a function in config', done => {
fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip">'

const spy = jasmine.createSpy('customClass').and.returnValue('custom-class')
const tooltipEl = fixtureEl.querySelector('a')
const tooltip = new Tooltip(tooltipEl, {
customClass: spy
})

tooltipEl.addEventListener('shown.bs.tooltip', () => {
const tip = document.querySelector('.tooltip')
expect(tip).toBeDefined()
expect(spy).toHaveBeenCalled()
expect(tip.classList.contains('custom-class')).toBeTrue()
done()
})

tooltip.show()
})
})

describe('hide', () => {
Expand Down
9 changes: 9 additions & 0 deletions site/content/docs/5.0/components/popovers.md
Expand Up @@ -262,6 +262,15 @@ Note that for security reasons the `sanitize`, `sanitizeFn`, and `allowList` opt
<td><code>'scrollParent'</code></td>
<td>Overflow constraint boundary of the popover. Accepts the values of <code>'viewport'</code>, <code>'window'</code>, <code>'scrollParent'</code>, or an HTMLElement reference (JavaScript only). For more information refer to Popper's <a href="https://popper.js.org/docs/v1/#modifiers..preventOverflow.boundariesElement">preventOverflow docs</a>.</td>
</tr>
<tr>
<td><code>customClass</code></td>
<td>string | function</td>
<td><code>''</code></td>
<td>
<p>Add classes to the popover when it is shown. Note that these classes will be added in addition to any classes specified in the template. To add multiple classes, separate them with spaces: <code>'class-1 class-2'</code>.</p>
<p>You can also pass a function that should return a single string containing additional class names.</p>
</td>
</tr>
<tr>
<td><code>sanitize</code></td>
<td>boolean</td>
Expand Down
9 changes: 9 additions & 0 deletions site/content/docs/5.0/components/tooltips.md
Expand Up @@ -271,6 +271,15 @@ Note that for security reasons the `sanitize`, `sanitizeFn`, and `allowList` opt
<td><code>'scrollParent'</code></td>
<td>Overflow constraint boundary of the tooltip. Accepts the values of <code>'viewport'</code>, <code>'window'</code>, <code>'scrollParent'</code>, or an HTMLElement reference (JavaScript only). For more information refer to Popper's <a href="https://popper.js.org/docs/v1/#modifiers..preventOverflow.boundariesElement">preventOverflow docs</a>.</td>
</tr>
<tr>
<td><code>customClass</code></td>
<td>string | function</td>
<td><code>''</code></td>
<td>
<p>Add classes to the tooltip when it is shown. Note that these classes will be added in addition to any classes specified in the template. To add multiple classes, separate them with spaces: <code>'class-1 class-2'</code>.</p>
<p>You can also pass a function that should return a single string containing additional class names.</p>
</td>
</tr>
<tr>
<td><code>sanitize</code></td>
<td>boolean</td>
Expand Down

0 comments on commit c348ad4

Please sign in to comment.