mirror of
https://github.com/twbs/bootstrap.git
synced 2025-02-19 16:54:24 +01:00
Add sanitize template option for tooltip/popover plugins.
This commit is contained in:
parent
bf2515ae68
commit
7bc4d2e0bc
127
js/src/tools/sanitizer.js
Normal file
127
js/src/tools/sanitizer.js
Normal file
@ -0,0 +1,127 @@
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Bootstrap (v4.3.0): tools/sanitizer.js
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
||||
* --------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
const uriAttrs = [
|
||||
'background',
|
||||
'cite',
|
||||
'href',
|
||||
'itemtype',
|
||||
'longdesc',
|
||||
'poster',
|
||||
'src',
|
||||
'xlink:href'
|
||||
]
|
||||
|
||||
const ARIA_ATTRIBUTE_PATTERN = /^aria-[\w-]*$/i
|
||||
|
||||
export const DefaultWhitelist = {
|
||||
// Global attributes allowed on any supplied element below.
|
||||
'*': ['class', 'dir', 'id', 'lang', 'role', ARIA_ATTRIBUTE_PATTERN],
|
||||
a: ['target', 'href', 'title', 'rel'],
|
||||
area: [],
|
||||
b: [],
|
||||
br: [],
|
||||
col: [],
|
||||
code: [],
|
||||
div: [],
|
||||
em: [],
|
||||
hr: [],
|
||||
h1: [],
|
||||
h2: [],
|
||||
h3: [],
|
||||
h4: [],
|
||||
h5: [],
|
||||
h6: [],
|
||||
i: [],
|
||||
img: ['src', 'alt', 'title', 'width', 'height'],
|
||||
li: [],
|
||||
ol: [],
|
||||
p: [],
|
||||
pre: [],
|
||||
s: [],
|
||||
small: [],
|
||||
span: [],
|
||||
sub: [],
|
||||
sup: [],
|
||||
strong: [],
|
||||
u: [],
|
||||
ul: []
|
||||
}
|
||||
|
||||
/**
|
||||
* A pattern that recognizes a commonly useful subset of URLs that are safe.
|
||||
*
|
||||
* Shoutout to Angular 7 https://github.com/angular/angular/blob/7.2.4/packages/core/src/sanitization/url_sanitizer.ts
|
||||
*/
|
||||
const SAFE_URL_PATTERN = /^(?:(?:https?|mailto|ftp|tel|file):|[^&:/?#]*(?:[/?#]|$))/gi
|
||||
|
||||
/**
|
||||
* A pattern that matches safe data URLs. Only matches image, video and audio types.
|
||||
*
|
||||
* Shoutout to Angular 7 https://github.com/angular/angular/blob/7.2.4/packages/core/src/sanitization/url_sanitizer.ts
|
||||
*/
|
||||
const DATA_URL_PATTERN = /^data:(?:image\/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|video\/(?:mpeg|mp4|ogg|webm)|audio\/(?:mp3|oga|ogg|opus));base64,[a-z0-9+/]+=*$/i
|
||||
|
||||
function allowedAttribute(attr, allowedAttributeList) {
|
||||
const attrName = attr.nodeName.toLowerCase()
|
||||
|
||||
if (allowedAttributeList.indexOf(attrName) !== -1) {
|
||||
if (uriAttrs.indexOf(attrName) !== -1) {
|
||||
return Boolean(attr.nodeValue.match(SAFE_URL_PATTERN) || attr.nodeValue.match(DATA_URL_PATTERN))
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
const regExp = allowedAttributeList.filter((attrRegex) => attrRegex instanceof RegExp)
|
||||
|
||||
// Check if a regular expression validates the attribute.
|
||||
for (let i = 0, l = regExp.length; i < l; i++) {
|
||||
if (attrName.match(regExp[i])) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
export function sanitizeHtml(unsafeHtml, whiteList, sanitizeFn) {
|
||||
if (unsafeHtml.length === 0) {
|
||||
return unsafeHtml
|
||||
}
|
||||
|
||||
if (sanitizeFn && typeof sanitizeFn === 'function') {
|
||||
return sanitizeFn(unsafeHtml)
|
||||
}
|
||||
|
||||
const domParser = new window.DOMParser()
|
||||
const createdDocument = domParser.parseFromString(unsafeHtml, 'text/html')
|
||||
const whitelistKeys = Object.keys(whiteList)
|
||||
const elements = [].slice.call(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(el.nodeName.toLowerCase()) === -1) {
|
||||
el.parentNode.removeChild(el)
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
const attributeList = [].slice.call(el.attributes)
|
||||
const whitelistedAttributes = [].concat(whiteList['*'] || [], whiteList[elName] || [])
|
||||
|
||||
attributeList.forEach((attr) => {
|
||||
if (!allowedAttribute(attr, whitelistedAttributes)) {
|
||||
el.removeAttribute(attr.nodeName)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return createdDocument.body.innerHTML
|
||||
}
|
@ -5,6 +5,10 @@
|
||||
* --------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
import {
|
||||
DefaultWhitelist,
|
||||
sanitizeHtml
|
||||
} from './tools/sanitizer'
|
||||
import $ from 'jquery'
|
||||
import Popper from 'popper.js'
|
||||
import Util from './util'
|
||||
@ -15,13 +19,14 @@ import Util from './util'
|
||||
* ------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
const NAME = 'tooltip'
|
||||
const VERSION = '4.3.0'
|
||||
const DATA_KEY = 'bs.tooltip'
|
||||
const EVENT_KEY = `.${DATA_KEY}`
|
||||
const JQUERY_NO_CONFLICT = $.fn[NAME]
|
||||
const CLASS_PREFIX = 'bs-tooltip'
|
||||
const BSCLS_PREFIX_REGEX = new RegExp(`(^|\\s)${CLASS_PREFIX}\\S+`, 'g')
|
||||
const NAME = 'tooltip'
|
||||
const VERSION = '4.3.0'
|
||||
const DATA_KEY = 'bs.tooltip'
|
||||
const EVENT_KEY = `.${DATA_KEY}`
|
||||
const JQUERY_NO_CONFLICT = $.fn[NAME]
|
||||
const CLASS_PREFIX = 'bs-tooltip'
|
||||
const BSCLS_PREFIX_REGEX = new RegExp(`(^|\\s)${CLASS_PREFIX}\\S+`, 'g')
|
||||
const DISALLOWED_ATTRIBUTES = ['sanitize', 'whiteList', 'sanitizeFn']
|
||||
|
||||
const DefaultType = {
|
||||
animation : 'boolean',
|
||||
@ -35,7 +40,10 @@ const DefaultType = {
|
||||
offset : '(number|string|function)',
|
||||
container : '(string|element|boolean)',
|
||||
fallbackPlacement : '(string|array)',
|
||||
boundary : '(string|element)'
|
||||
boundary : '(string|element)',
|
||||
sanitize : 'boolean',
|
||||
sanitizeFn : '(null|function)',
|
||||
whiteList : 'object'
|
||||
}
|
||||
|
||||
const AttachmentMap = {
|
||||
@ -60,7 +68,10 @@ const Default = {
|
||||
offset : 0,
|
||||
container : false,
|
||||
fallbackPlacement : 'flip',
|
||||
boundary : 'scrollParent'
|
||||
boundary : 'scrollParent',
|
||||
sanitize : true,
|
||||
sanitizeFn : null,
|
||||
whiteList : DefaultWhitelist
|
||||
}
|
||||
|
||||
const HoverState = {
|
||||
@ -419,18 +430,27 @@ class Tooltip {
|
||||
}
|
||||
|
||||
setElementContent($element, content) {
|
||||
const html = this.config.html
|
||||
if (typeof content === 'object' && (content.nodeType || content.jquery)) {
|
||||
// Content is a DOM node or a jQuery
|
||||
if (html) {
|
||||
if (this.config.html) {
|
||||
if (!$(content).parent().is($element)) {
|
||||
$element.empty().append(content)
|
||||
}
|
||||
} else {
|
||||
$element.text($(content).text())
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if (this.config.html) {
|
||||
if (this.config.sanitize) {
|
||||
content = sanitizeHtml(content, this.config.whiteList, this.config.sanitizeFn)
|
||||
}
|
||||
|
||||
$element.html(content)
|
||||
} else {
|
||||
$element[html ? 'html' : 'text'](content)
|
||||
$element.text(content)
|
||||
}
|
||||
}
|
||||
|
||||
@ -636,9 +656,18 @@ class Tooltip {
|
||||
}
|
||||
|
||||
_getConfig(config) {
|
||||
const dataAttributes = $(this.element).data()
|
||||
|
||||
Object.keys(dataAttributes)
|
||||
.forEach((dataAttr) => {
|
||||
if (DISALLOWED_ATTRIBUTES.indexOf(dataAttr) !== -1) {
|
||||
delete dataAttributes[dataAttr]
|
||||
}
|
||||
})
|
||||
|
||||
config = {
|
||||
...this.constructor.Default,
|
||||
...$(this.element).data(),
|
||||
...dataAttributes,
|
||||
...typeof config === 'object' && config ? config : {}
|
||||
}
|
||||
|
||||
@ -663,6 +692,10 @@ class Tooltip {
|
||||
this.constructor.DefaultType
|
||||
)
|
||||
|
||||
if (config.sanitize) {
|
||||
config.template = sanitizeHtml(config.template, config.whiteList, config.sanitizeFn)
|
||||
}
|
||||
|
||||
return config
|
||||
}
|
||||
|
||||
|
@ -1106,4 +1106,164 @@ $(function () {
|
||||
assert.strictEqual(offset.offset, myOffset)
|
||||
assert.ok(typeof offset.fn === 'undefined')
|
||||
})
|
||||
|
||||
QUnit.test('should disable sanitizer', function (assert) {
|
||||
assert.expect(1)
|
||||
|
||||
var $trigger = $('<a href="#" rel="tooltip" data-trigger="click" title="Another tooltip"/>')
|
||||
.appendTo('#qunit-fixture')
|
||||
.bootstrapTooltip({
|
||||
sanitize: false
|
||||
})
|
||||
|
||||
var tooltip = $trigger.data('bs.tooltip')
|
||||
assert.strictEqual(tooltip.config.sanitize, false)
|
||||
})
|
||||
|
||||
QUnit.test('should sanitize template by removing disallowed tags', function (assert) {
|
||||
assert.expect(1)
|
||||
|
||||
var $trigger = $('<a href="#" rel="tooltip" data-trigger="click" title="Another tooltip"/>')
|
||||
.appendTo('#qunit-fixture')
|
||||
.bootstrapTooltip({
|
||||
template: [
|
||||
'<div>',
|
||||
' <script>console.log("oups script inserted")</script>',
|
||||
' <span>Some content</span>',
|
||||
'</div>'
|
||||
].join('')
|
||||
})
|
||||
|
||||
var tooltip = $trigger.data('bs.tooltip')
|
||||
assert.strictEqual(tooltip.config.template.indexOf('script'), -1)
|
||||
})
|
||||
|
||||
QUnit.test('should sanitize template by removing disallowed attributes', function (assert) {
|
||||
assert.expect(1)
|
||||
|
||||
var $trigger = $('<a href="#" rel="tooltip" data-trigger="click" title="Another tooltip"/>')
|
||||
.appendTo('#qunit-fixture')
|
||||
.bootstrapTooltip({
|
||||
template: [
|
||||
'<div>',
|
||||
' <img src="x" onError="alert(\'test\')">Some content</img>',
|
||||
'</div>'
|
||||
].join('')
|
||||
})
|
||||
|
||||
var tooltip = $trigger.data('bs.tooltip')
|
||||
assert.strictEqual(tooltip.config.template.indexOf('onError'), -1)
|
||||
})
|
||||
|
||||
QUnit.test('should sanitize template by removing tags with XSS', function (assert) {
|
||||
assert.expect(1)
|
||||
|
||||
var $trigger = $('<a href="#" rel="tooltip" data-trigger="click" title="Another tooltip"/>')
|
||||
.appendTo('#qunit-fixture')
|
||||
.bootstrapTooltip({
|
||||
template: [
|
||||
'<div>',
|
||||
' <a href="javascript:alert(7)">Click me</a>',
|
||||
' <span>Some content</span>',
|
||||
'</div>'
|
||||
].join('')
|
||||
})
|
||||
|
||||
var tooltip = $trigger.data('bs.tooltip')
|
||||
assert.strictEqual(tooltip.config.template.indexOf('script'), -1)
|
||||
})
|
||||
|
||||
QUnit.test('should allow custom sanitization rules', function (assert) {
|
||||
assert.expect(2)
|
||||
|
||||
var $trigger = $('<a href="#" rel="tooltip" data-trigger="click" title="Another tooltip"/>')
|
||||
.appendTo('#qunit-fixture')
|
||||
.bootstrapTooltip({
|
||||
template: [
|
||||
'<a href="javascript:alert(7)">Click me</a>',
|
||||
'<span>Some content</span>'
|
||||
].join(''),
|
||||
whiteList: {
|
||||
span: null
|
||||
}
|
||||
})
|
||||
|
||||
var tooltip = $trigger.data('bs.tooltip')
|
||||
|
||||
assert.strictEqual(tooltip.config.template.indexOf('<a'), -1)
|
||||
assert.ok(tooltip.config.template.indexOf('span') !== -1)
|
||||
})
|
||||
|
||||
QUnit.test('should allow passing a custom function for sanitization', function (assert) {
|
||||
assert.expect(1)
|
||||
|
||||
var $trigger = $('<a href="#" rel="tooltip" data-trigger="click" title="Another tooltip"/>')
|
||||
.appendTo('#qunit-fixture')
|
||||
.bootstrapTooltip({
|
||||
template: [
|
||||
'<span>Some content</span>'
|
||||
].join(''),
|
||||
sanitizeFn: function (input) {
|
||||
return input
|
||||
}
|
||||
})
|
||||
|
||||
var tooltip = $trigger.data('bs.tooltip')
|
||||
|
||||
assert.ok(tooltip.config.template.indexOf('span') !== -1)
|
||||
})
|
||||
|
||||
QUnit.test('should allow passing aria attributes', function (assert) {
|
||||
assert.expect(1)
|
||||
|
||||
var $trigger = $('<a href="#" rel="tooltip" data-trigger="click" title="Another tooltip"/>')
|
||||
.appendTo('#qunit-fixture')
|
||||
.bootstrapTooltip({
|
||||
template: [
|
||||
'<span aria-pressed="true">Some content</span>'
|
||||
].join('')
|
||||
})
|
||||
|
||||
var tooltip = $trigger.data('bs.tooltip')
|
||||
|
||||
assert.ok(tooltip.config.template.indexOf('aria-pressed') !== -1)
|
||||
})
|
||||
|
||||
QUnit.test('should not sanitize element content', function (assert) {
|
||||
assert.expect(1)
|
||||
|
||||
var $element = $('<div />').appendTo('#qunit-fixture')
|
||||
var content = '<script>var test = 1;</script>'
|
||||
|
||||
var $trigger = $('<a href="#" rel="tooltip" data-trigger="click" title="Another tooltip"/>')
|
||||
.appendTo('#qunit-fixture')
|
||||
.bootstrapTooltip({
|
||||
template: [
|
||||
'<span aria-pressed="true">Some content</span>'
|
||||
].join(''),
|
||||
html: true,
|
||||
sanitize: false
|
||||
})
|
||||
|
||||
var tooltip = $trigger.data('bs.tooltip')
|
||||
tooltip.setElementContent($element, content)
|
||||
|
||||
assert.strictEqual($element[0].innerHTML, content)
|
||||
})
|
||||
|
||||
QUnit.test('should not take into account sanitize in data attributes', function (assert) {
|
||||
assert.expect(1)
|
||||
|
||||
var $trigger = $('<a href="#" rel="tooltip" data-sanitize="false" data-trigger="click" title="Another tooltip"/>')
|
||||
.appendTo('#qunit-fixture')
|
||||
.bootstrapTooltip({
|
||||
template: [
|
||||
'<span aria-pressed="true">Some content</span>'
|
||||
].join('')
|
||||
})
|
||||
|
||||
var tooltip = $trigger.data('bs.tooltip')
|
||||
|
||||
assert.strictEqual(tooltip.config.sanitize, true)
|
||||
})
|
||||
})
|
||||
|
@ -182,19 +182,19 @@
|
||||
},
|
||||
{
|
||||
"path": "./dist/js/bootstrap.bundle.js",
|
||||
"maxSize": "45 kB"
|
||||
"maxSize": "47 kB"
|
||||
},
|
||||
{
|
||||
"path": "./dist/js/bootstrap.bundle.min.js",
|
||||
"maxSize": "21.25 kB"
|
||||
"maxSize": "22 kB"
|
||||
},
|
||||
{
|
||||
"path": "./dist/js/bootstrap.js",
|
||||
"maxSize": "23 kB"
|
||||
"maxSize": "25 kB"
|
||||
},
|
||||
{
|
||||
"path": "./dist/js/bootstrap.min.js",
|
||||
"maxSize": "14.5 kB"
|
||||
"maxSize": "15.5 kB"
|
||||
}
|
||||
],
|
||||
"jspm": {
|
||||
|
@ -140,6 +140,11 @@ Enable popovers via JavaScript:
|
||||
|
||||
Options can be passed via data attributes or JavaScript. For data attributes, append the option name to `data-`, as in `data-animation=""`.
|
||||
|
||||
{% capture callout %}
|
||||
Note that for security reasons the `sanitize`, `sanitizeFn` and `whiteList` options cannot be supplied using data attributes.
|
||||
{% endcapture %}
|
||||
{% include callout.html content=callout type="warning" %}
|
||||
|
||||
<table class="table table-bordered table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
@ -250,6 +255,24 @@ Options can be passed via data attributes or JavaScript. For data attributes, ap
|
||||
<td>'scrollParent'</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.js's <a href="https://popper.js.org/popper-documentation.html#modifiers..preventOverflow.boundariesElement">preventOverflow docs</a>.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>sanitize</td>
|
||||
<td>boolean</td>
|
||||
<td>true</td>
|
||||
<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>object</td>
|
||||
<td><a href="{{ site.baseurl }}/docs/{{ site.docs_version }}/getting-started/javascript/#sanitizer">Default value</a></td>
|
||||
<td>Object which contains allowed attributes and tags</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>sanitizeFn</td>
|
||||
<td>null | function</td>
|
||||
<td>null</td>
|
||||
<td>Here you can supply your own sanitize function. This can be useful if you prefer to use a dedicated library to perform sanitization.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
@ -143,6 +143,11 @@ Elements with the `disabled` attribute aren't interactive, meaning users cannot
|
||||
|
||||
Options can be passed via data attributes or JavaScript. For data attributes, append the option name to `data-`, as in `data-animation=""`.
|
||||
|
||||
{% capture callout %}
|
||||
Note that for security reasons the `sanitize`, `sanitizeFn` and `whiteList` options cannot be supplied using data attributes.
|
||||
{% endcapture %}
|
||||
{% include callout.html content=callout type="warning" %}
|
||||
|
||||
<table class="table table-bordered table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
@ -255,6 +260,24 @@ Options can be passed via data attributes or JavaScript. For data attributes, ap
|
||||
<td>'scrollParent'</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.js's <a href="https://popper.js.org/popper-documentation.html#modifiers..preventOverflow.boundariesElement">preventOverflow docs</a>.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>sanitize</td>
|
||||
<td>boolean</td>
|
||||
<td>true</td>
|
||||
<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>object</td>
|
||||
<td><a href="{{ site.baseurl }}/docs/{{ site.docs_version }}/getting-started/javascript/#sanitizer">Default value</a></td>
|
||||
<td>Object which contains allowed attributes and tags</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>sanitizeFn</td>
|
||||
<td>null | function</td>
|
||||
<td>null</td>
|
||||
<td>Here you can supply your own sanitize function. This can be useful if you prefer to use a dedicated library to perform sanitization.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
@ -139,3 +139,73 @@ Bootstrap's plugins don't fall back particularly gracefully when JavaScript is d
|
||||
All Bootstrap's JavaScript files depend on `util.js` and it has to be included alongside the other JavaScript files. If you're using the compiled (or minified) `bootstrap.js`, there is no need to include this—it's already there.
|
||||
|
||||
`util.js` includes utility functions and a basic helper for `transitionEnd` events as well as a CSS transition emulator. It's used by the other plugins to check for CSS transition support and to catch hanging transitions.
|
||||
|
||||
## Sanitizer
|
||||
|
||||
Tooltips and Popovers use our built-in sanitizer to sanitize options which accept HTML.
|
||||
|
||||
The default `whiteList` value is the following:
|
||||
|
||||
{% highlight js %}
|
||||
var ARIA_ATTRIBUTE_PATTERN = /^aria-[\w-]*$/i
|
||||
var DefaultWhitelist = {
|
||||
// Global attributes allowed on any supplied element below.
|
||||
'*': ['class', 'dir', 'id', 'lang', 'role', ARIA_ATTRIBUTE_PATTERN],
|
||||
a: ['target', 'href', 'title', 'rel'],
|
||||
area: [],
|
||||
b: [],
|
||||
br: [],
|
||||
col: [],
|
||||
code: [],
|
||||
div: [],
|
||||
em: [],
|
||||
hr: [],
|
||||
h1: [],
|
||||
h2: [],
|
||||
h3: [],
|
||||
h4: [],
|
||||
h5: [],
|
||||
h6: [],
|
||||
i: [],
|
||||
img: ['src', 'alt', 'title', 'width', 'height'],
|
||||
li: [],
|
||||
ol: [],
|
||||
p: [],
|
||||
pre: [],
|
||||
s: [],
|
||||
small: [],
|
||||
span: [],
|
||||
sub: [],
|
||||
sup: [],
|
||||
strong: [],
|
||||
u: [],
|
||||
ul: []
|
||||
}
|
||||
{% endhighlight %}
|
||||
|
||||
If you want to add new values to this default `whiteList` you can do the following:
|
||||
|
||||
{% highlight js %}
|
||||
var myDefaultWhiteList = $.fn.tooltip.Constructor.Default.whiteList
|
||||
|
||||
// To allow table elements
|
||||
myDefaultWhiteList.table = []
|
||||
|
||||
// To allow td elements and data-option attributes on td elements
|
||||
myDefaultWhiteList.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)
|
||||
{% endhighlight %}
|
||||
|
||||
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:
|
||||
|
||||
{% highlight js %}
|
||||
$('#yourTooltip').tooltip({
|
||||
sanitizeFn: function (content) {
|
||||
return DOMPurify.sanitize(content)
|
||||
}
|
||||
})
|
||||
{% endhighlight %}
|
||||
|
Loading…
x
Reference in New Issue
Block a user