'vendor'
])
const INCLUDED_EXTENSIONS = new Set([
- // This extension whitelist is how we avoid modifying binary files
+ // This extension allowlist is how we avoid modifying binary files
'',
'.css',
'.html',
typeCheckConfig
} from './util/index'
import {
- DefaultWhitelist,
+ DefaultAllowlist,
sanitizeHtml
} from './util/sanitizer'
import Data from './dom/data'
const EVENT_KEY = `.${DATA_KEY}`
const CLASS_PREFIX = 'bs-tooltip'
const BSCLS_PREFIX_REGEX = new RegExp(`(^|\\s)${CLASS_PREFIX}\\S+`, 'g')
-const DISALLOWED_ATTRIBUTES = ['sanitize', 'whiteList', 'sanitizeFn']
+const DISALLOWED_ATTRIBUTES = ['sanitize', 'allowList', 'sanitizeFn']
const DefaultType = {
animation: 'boolean',
boundary: '(string|element)',
sanitize: 'boolean',
sanitizeFn: '(null|function)',
- whiteList: 'object',
+ allowList: 'object',
popperConfig: '(null|object)'
}
boundary: 'scrollParent',
sanitize: true,
sanitizeFn: null,
- whiteList: DefaultWhitelist,
+ allowList: DefaultAllowlist,
popperConfig: null
}
if (this.config.html) {
if (this.config.sanitize) {
- content = sanitizeHtml(content, this.config.whiteList, this.config.sanitizeFn)
+ content = sanitizeHtml(content, this.config.allowList, this.config.sanitizeFn)
}
element.innerHTML = content
typeCheckConfig(NAME, config, this.constructor.DefaultType)
if (config.sanitize) {
- config.template = sanitizeHtml(config.template, config.whiteList, config.sanitizeFn)
+ config.template = sanitizeHtml(config.template, config.allowList, config.sanitizeFn)
}
return config
return false
}
-export const DefaultWhitelist = {
+export const DefaultAllowlist = {
// Global attributes allowed on any supplied element below.
'*': ['class', 'dir', 'id', 'lang', 'role', ARIA_ATTRIBUTE_PATTERN],
a: ['target', 'href', 'title', 'rel'],
ul: []
}
-export function sanitizeHtml(unsafeHtml, whiteList, sanitizeFn) {
+export function sanitizeHtml(unsafeHtml, allowList, sanitizeFn) {
if (!unsafeHtml.length) {
return unsafeHtml
}
const domParser = new window.DOMParser()
const createdDocument = domParser.parseFromString(unsafeHtml, 'text/html')
- const whitelistKeys = Object.keys(whiteList)
+ const allowlistKeys = Object.keys(allowList)
const elements = [].concat(...createdDocument.body.querySelectorAll('*'))
for (let i = 0, len = elements.length; i < len; i++) {
const el = elements[i]
const elName = el.nodeName.toLowerCase()
- if (whitelistKeys.indexOf(elName) === -1) {
+ if (allowlistKeys.indexOf(elName) === -1) {
el.parentNode.removeChild(el)
continue
}
const attributeList = [].concat(...el.attributes)
- const whitelistedAttributes = [].concat(whiteList['*'] || [], whiteList[elName] || [])
+ const allowedAttributes = [].concat(allowList['*'] || [], allowList[elName] || [])
attributeList.forEach(attr => {
- if (!allowedAttribute(attr, whitelistedAttributes)) {
+ if (!allowedAttribute(attr, allowedAttributes)) {
el.removeAttribute(attr.nodeName)
}
})
-import { DefaultWhitelist, sanitizeHtml } from '../../../src/util/sanitizer'
+import { DefaultAllowlist, sanitizeHtml } from '../../../src/util/sanitizer'
describe('Sanitizer', () => {
describe('sanitizeHtml', () => {
it('should return the same on empty string', () => {
const empty = ''
- const result = sanitizeHtml(empty, DefaultWhitelist, null)
+ const result = sanitizeHtml(empty, DefaultAllowlist, null)
expect(result).toEqual(empty)
})
'</div>'
].join('')
- const result = sanitizeHtml(template, DefaultWhitelist, null)
+ const result = sanitizeHtml(template, DefaultAllowlist, null)
expect(result.indexOf('script') === -1).toEqual(true)
})
'</div>'
].join('')
- const result = sanitizeHtml(template, DefaultWhitelist, null)
+ const result = sanitizeHtml(template, DefaultAllowlist, null)
expect(result.indexOf('aria-pressed') !== -1).toEqual(true)
expect(result.indexOf('class="test"') !== -1).toEqual(true)
})
- it('should remove not whitelist tags', () => {
+ it('should remove tags not in allowlist', () => {
const template = [
'<div>',
' <script>alert(7)</script>',
'</div>'
].join('')
- const result = sanitizeHtml(template, DefaultWhitelist, null)
+ const result = sanitizeHtml(template, DefaultAllowlist, null)
expect(result.indexOf('<script>') === -1).toEqual(true)
})
spyOn(DOMParser.prototype, 'parseFromString')
- const result = sanitizeHtml(template, DefaultWhitelist, mySanitize)
+ const result = sanitizeHtml(template, DefaultAllowlist, mySanitize)
expect(result).toEqual(template)
expect(DOMParser.prototype.parseFromString).not.toHaveBeenCalled()
While you can insert rich, structured HTML in popovers with the `html` option, we strongly recommend that you avoid adding an excessive amount of content. The way popovers currently work is that, once displayed, their content is tied to the trigger element with the `aria-describedby` attribute. As a result, the entirety of the popover's content will be announced to assistive technology users as one long, uninterrupted stream.
-Additionally, while it is possible to also include interactive controls (such as form elements or links) in your popover (by adding these elements to the `whiteList` or allowed attributes and tags), be aware that currently the popover does not manage keyboard focus order. When a keyboard user opens a popover, focus remains on the triggering element, and as the popover usually does not immediately follow the trigger in the document's structure, there is no guarantee that moving forward/pressing <kbd>TAB</kbd> will move a keyboard user into the popover itself. In short, simply adding interactive controls to a popover is likely to make these controls unreachable/unusable for keyboard users and users of assistive technologies, or at the very least make for an illogical overall focus order. In these cases, consider using a modal dialog instead.
+Additionally, while it is possible to also include interactive controls (such as form elements or links) in your popover (by adding these elements to the `allowList` of allowed attributes and tags), be aware that currently the popover does not manage keyboard focus order. When a keyboard user opens a popover, focus remains on the triggering element, and as the popover usually does not immediately follow the trigger in the document's structure, there is no guarantee that moving forward/pressing <kbd>TAB</kbd> will move a keyboard user into the popover itself. In short, simply adding interactive controls to a popover is likely to make these controls unreachable/unusable for keyboard users and users of assistive technologies, or at the very least make for an illogical overall focus order. In these cases, consider using a modal dialog instead.
{{< /callout >}}
### Options
Options can be passed via data attributes or JavaScript. For data attributes, append the option name to `data-`, as in `data-animation=""`.
{{< callout warning >}}
-Note that for security reasons the `sanitize`, `sanitizeFn` and `whiteList` options cannot be supplied using data attributes.
+Note that for security reasons the `sanitize`, `sanitizeFn`, and `allowList` options cannot be supplied using data attributes.
{{< /callout >}}
<table class="table">
<td>Enable or disable the sanitization. If activated <code>'template'</code>, <code>'content'</code> and <code>'title'</code> options will be sanitized.</td>
</tr>
<tr>
- <td>whiteList</td>
+ <td>allowList</td>
<td>object</td>
<td><a href="{{< docsref "/getting-started/javascript#sanitizer" >}}">Default value</a></td>
<td>Object which contains allowed attributes and tags</td>
Options can be passed via data attributes or JavaScript. For data attributes, append the option name to `data-`, as in `data-animation=""`.
{{< callout warning >}}
-Note that for security reasons the `sanitize`, `sanitizeFn` and `whiteList` options cannot be supplied using data attributes.
+Note that for security reasons the `sanitize`, `sanitizeFn`, and `allowList` options cannot be supplied using data attributes.
{{< /callout >}}
<table class="table">
<td>Enable or disable the sanitization. If activated <code>'template'</code> and <code>'title'</code> options will be sanitized.</td>
</tr>
<tr>
- <td>whiteList</td>
+ <td>allowList</td>
<td>object</td>
<td><a href="{{< docsref "/getting-started/javascript#sanitizer" >}}">Default value</a></td>
<td>Object which contains allowed attributes and tags</td>
Tooltips and Popovers use our built-in sanitizer to sanitize options which accept HTML.
-The default `whiteList` value is the following:
+The default `allowList` value is the following:
{{< highlight js >}}
var ARIA_ATTRIBUTE_PATTERN = /^aria-[\w-]*$/i
-var DefaultWhitelist = {
+var DefaultAllowlist = {
// Global attributes allowed on any supplied element below.
'*': ['class', 'dir', 'id', 'lang', 'role', ARIA_ATTRIBUTE_PATTERN],
a: ['target', 'href', 'title', 'rel'],
}
{{< /highlight >}}
-If you want to add new values to this default `whiteList` you can do the following:
+If you want to add new values to this default `allowList` you can do the following:
{{< highlight js >}}
-var myDefaultWhiteList = bootstrap.Tooltip.Default.whiteList
+var myDefaultAllowList = bootstrap.Tooltip.Default.allowList
// To allow table elements
-myDefaultWhiteList.table = []
+myDefaultAllowList.table = []
// To allow td elements and data-option attributes on td elements
-myDefaultWhiteList.td = ['data-option']
+myDefaultAllowList.td = ['data-option']
// You can push your custom regex to validate your attributes.
// Be careful about your regular expressions being too lax
var myCustomRegex = /^data-my-app-[\w-]+/
-myDefaultWhiteList['*'].push(myCustomRegex)
+myDefaultAllowList['*'].push(myCustomRegex)
{{< /highlight >}}
If you want to bypass our sanitizer because you prefer to use a dedicated library, for example [DOMPurify](https://www.npmjs.com/package/dompurify), you should do the following:
### Popovers
- Renamed `.arrow` to `.popover-arrow`
+- Renamed `whiteList` option to `allowList`
### Tooltips
- Renamed `.arrow` to `.tooltip-arrow`
+- Renamed `whiteList` option to `allowList`
## Accessibility