mirror of
https://github.com/twbs/bootstrap.git
synced 2025-01-17 09:52:29 +01:00
Merge branch 'v4-dev' into patch-5
This commit is contained in:
commit
0b06ad69d2
3
.gitignore
vendored
3
.gitignore
vendored
@ -44,8 +44,9 @@ scss-lint-report.xml
|
||||
# grunt-contrib-sass cache
|
||||
.sass-cache
|
||||
|
||||
# Jekyll metadata
|
||||
# Jekyll metadata and extra config file for `github` script
|
||||
docs/.jekyll-metadata
|
||||
twbsconfig.yml
|
||||
|
||||
# Folders to ignore
|
||||
bower_components
|
||||
|
@ -9,7 +9,7 @@ module.exports = (ctx) => ({
|
||||
browsers: [
|
||||
//
|
||||
// Official browser support policy:
|
||||
// https://v4-alpha.getbootstrap.com/getting-started/browsers-devices/#supported-browsers
|
||||
// https://getbootstrap.com/docs/4.0/getting-started/browsers-devices/#supported-browsers
|
||||
//
|
||||
'Chrome >= 45', // Exact version number here is kinda arbitrary
|
||||
'Firefox ESR',
|
||||
|
@ -216,7 +216,7 @@ $('#myCollapsible').collapse({
|
||||
|
||||
#### `.collapse('toggle')`
|
||||
|
||||
Toggles a collapsible element to shown or hidden. **Returns to the caller before the collapsible element has actually been shown or hidden (i.e. before the `shown.bs.collapse` or `hidden.bs.collapse` event occurs).
|
||||
Toggles a collapsible element to shown or hidden. **Returns to the caller before the collapsible element has actually been shown or hidden** (i.e. before the `shown.bs.collapse` or `hidden.bs.collapse` event occurs).
|
||||
|
||||
#### `.collapse('show')`
|
||||
|
||||
|
@ -56,7 +56,7 @@ Be sure to **not use the standard `.btn` classes here**.
|
||||
|
||||
{% example html %}
|
||||
<div class="list-group">
|
||||
<a href="#" class="list-group-item active">
|
||||
<a href="#" class="list-group-item list-group-item-action active">
|
||||
Cras justo odio
|
||||
</a>
|
||||
<a href="#" class="list-group-item list-group-item-action">Dapibus ac facilisis in</a>
|
||||
|
@ -68,6 +68,7 @@ const Modal = (($) => {
|
||||
DATA_TOGGLE : '[data-toggle="modal"]',
|
||||
DATA_DISMISS : '[data-dismiss="modal"]',
|
||||
FIXED_CONTENT : '.fixed-top, .fixed-bottom, .is-fixed, .sticky-top',
|
||||
STICKY_CONTENT : '.sticky-top',
|
||||
NAVBAR_TOGGLER : '.navbar-toggler'
|
||||
}
|
||||
|
||||
@ -441,6 +442,13 @@ const Modal = (($) => {
|
||||
$(element).data('padding-right', actualPadding).css('padding-right', `${parseFloat(calculatedPadding) + this._scrollbarWidth}px`)
|
||||
})
|
||||
|
||||
// Adjust sticky content margin
|
||||
$(Selector.STICKY_CONTENT).each((index, element) => {
|
||||
const actualMargin = $(element)[0].style.marginRight
|
||||
const calculatedMargin = $(element).css('margin-right')
|
||||
$(element).data('margin-right', actualMargin).css('margin-right', `${parseFloat(calculatedMargin) - this._scrollbarWidth}px`)
|
||||
})
|
||||
|
||||
// Adjust navbar-toggler margin
|
||||
$(Selector.NAVBAR_TOGGLER).each((index, element) => {
|
||||
const actualMargin = $(element)[0].style.marginRight
|
||||
@ -464,8 +472,8 @@ const Modal = (($) => {
|
||||
}
|
||||
})
|
||||
|
||||
// Restore navbar-toggler margin
|
||||
$(Selector.NAVBAR_TOGGLER).each((index, element) => {
|
||||
// Restore sticky content and navbar-toggler margin
|
||||
$(`${Selector.STICKY_CONTENT}, ${Selector.NAVBAR_TOGGLER}`).each((index, element) => {
|
||||
const margin = $(element).data('margin-right')
|
||||
if (typeof margin !== 'undefined') {
|
||||
$(element).css('margin-right', margin).removeData('margin-right')
|
||||
|
@ -117,7 +117,7 @@ const Util = (($) => {
|
||||
}
|
||||
|
||||
try {
|
||||
const $selector = $(selector)
|
||||
const $selector = $(document).find(selector)
|
||||
return $selector.length > 0 ? selector : null
|
||||
} catch (error) {
|
||||
return null
|
||||
|
@ -433,6 +433,48 @@ $(function () {
|
||||
.bootstrapModal('show')
|
||||
})
|
||||
|
||||
QUnit.test('should adjust the inline margin of sticky elements when opening and restore when closing', function (assert) {
|
||||
assert.expect(2)
|
||||
var done = assert.async()
|
||||
var $element = $('<div class="sticky-top"></div>').appendTo('#qunit-fixture')
|
||||
var originalPadding = $element.css('margin-right')
|
||||
|
||||
$('<div id="modal-test"/>')
|
||||
.on('hidden.bs.modal', function () {
|
||||
var currentPadding = $element.css('margin-right')
|
||||
assert.strictEqual(currentPadding, originalPadding, 'sticky element margin should be reset after closing')
|
||||
$element.remove()
|
||||
done()
|
||||
})
|
||||
.on('shown.bs.modal', function () {
|
||||
var expectedPadding = parseFloat(originalPadding) - $(this).getScrollbarWidth() + 'px'
|
||||
var currentPadding = $element.css('margin-right')
|
||||
assert.strictEqual(currentPadding, expectedPadding, 'sticky element margin should be adjusted while opening')
|
||||
$(this).bootstrapModal('hide')
|
||||
})
|
||||
.bootstrapModal('show')
|
||||
})
|
||||
|
||||
QUnit.test('should store the original margin of sticky elements in data-margin-right before showing', function (assert) {
|
||||
assert.expect(2)
|
||||
var done = assert.async()
|
||||
var $element = $('<div class="sticky-top"></div>').appendTo('#qunit-fixture')
|
||||
var originalPadding = '0px'
|
||||
$element.css('margin-right', originalPadding)
|
||||
|
||||
$('<div id="modal-test"/>')
|
||||
.on('hidden.bs.modal', function () {
|
||||
assert.strictEqual(typeof $element.data('margin-right'), 'undefined', 'data-margin-right should be cleared after closing')
|
||||
$element.remove()
|
||||
done()
|
||||
})
|
||||
.on('shown.bs.modal', function () {
|
||||
assert.strictEqual($element.data('margin-right'), originalPadding, 'original sticky element margin should be stored in data-margin-right')
|
||||
$(this).bootstrapModal('hide')
|
||||
})
|
||||
.bootstrapModal('show')
|
||||
})
|
||||
|
||||
QUnit.test('should adjust the inline margin of the navbar-toggler when opening and restore when closing', function (assert) {
|
||||
assert.expect(2)
|
||||
var done = assert.async()
|
||||
@ -555,4 +597,40 @@ $(function () {
|
||||
})
|
||||
.trigger('click')
|
||||
})
|
||||
|
||||
QUnit.test('should not parse target as html', function (assert) {
|
||||
assert.expect(1)
|
||||
var done = assert.async()
|
||||
|
||||
var $toggleBtn = $('<button data-toggle="modal" data-target="<div id="modal-test"><div class="contents"<div<div id="close" data-dismiss="modal"/></div></div>"/>')
|
||||
.appendTo('#qunit-fixture')
|
||||
|
||||
$toggleBtn.trigger('click')
|
||||
setTimeout(function () {
|
||||
assert.strictEqual($('#modal-test').length, 0, 'target has not been parsed and added to the document')
|
||||
done()
|
||||
}, 1)
|
||||
})
|
||||
|
||||
QUnit.test('should not execute js from target', function (assert) {
|
||||
assert.expect(0)
|
||||
var done = assert.async()
|
||||
|
||||
// This toggle button contains XSS payload in its data-target
|
||||
// Note: it uses the onerror handler of an img element to execute the js, because a simple script element does not work here
|
||||
// a script element works in manual tests though, so here it is likely blocked by the qunit framework
|
||||
var $toggleBtn = $('<button data-toggle="modal" data-target="<div><image src="missing.png" onerror="$('#qunit-fixture button.control').trigger('click')"></div>"/>')
|
||||
.appendTo('#qunit-fixture')
|
||||
// The XSS payload above does not have a closure over this function and cannot access the assert object directly
|
||||
// However, it can send a click event to the following control button, which will then fail the assert
|
||||
$('<button>')
|
||||
.addClass('control')
|
||||
.on('click', function () {
|
||||
assert.notOk(true, 'XSS payload is not executed as js')
|
||||
})
|
||||
.appendTo('#qunit-fixture')
|
||||
|
||||
$toggleBtn.trigger('click')
|
||||
setTimeout(done, 500)
|
||||
})
|
||||
})
|
||||
|
@ -167,6 +167,10 @@
|
||||
<div class="bg-dark text-white p-2" id="tall" style="display: none;">
|
||||
Tall body content to force the page to have a scrollbar.
|
||||
</div>
|
||||
|
||||
<button type="button" class="btn btn-secondary btn-lg" data-toggle="modal" data-target="<div class="modal fade the-bad" tabindex="-1" role="dialog"><div class="modal-dialog" role="document"><div class="modal-content"><div class="modal-header"><button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button><h4 class="modal-title">The Bad Modal</h4></div><div class="modal-body">This modal's HTTML source code is declared inline, inside the data-target attribute of it's show-button</div></div></div></div>">
|
||||
Modal with an XSS inside the data-target
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<script src="../../../assets/js/vendor/jquery-slim.min.js"></script>
|
||||
|
@ -28,10 +28,10 @@
|
||||
"css-prefix-docs": "postcss --config build/postcss.config.js --no-map --replace assets/css/docs.min.css",
|
||||
"css-minify": "cleancss --level 1 --source-map --source-map-inline-sources --output dist/css/bootstrap.min.css dist/css/bootstrap.css && cleancss --level 1 --source-map --source-map-inline-sources --output dist/css/bootstrap-grid.min.css dist/css/bootstrap-grid.css && cleancss --level 1 --source-map --source-map-inline-sources --output dist/css/bootstrap-reboot.min.css dist/css/bootstrap-reboot.css",
|
||||
"css-minify-docs": "cleancss --level 1 --source-map --source-map-inline-sources --output assets/css/docs.min.css assets/css/docs.min.css",
|
||||
"js": "npm-run-all js-lint js-compile js-minify",
|
||||
"js": "npm-run-all js-lint* js-compile js-minify",
|
||||
"js-docs": "npm-run-all js-lint-docs js-minify-docs",
|
||||
"js-lint": "eslint js/ && eslint --config js/tests/.eslintrc.json --env node build/ Gruntfile.js",
|
||||
"js-lint-docs": "eslint --config js/tests/.eslintrc.json assets/js/",
|
||||
"js-lint-docs": "eslint --config js/tests/.eslintrc.json assets/js/ sw.js",
|
||||
"js-compile": "npm-run-all --parallel js-compile-*",
|
||||
"js-compile-bundle": "shx cat js/src/util.js js/src/alert.js js/src/button.js js/src/carousel.js js/src/collapse.js js/src/dropdown.js js/src/modal.js js/src/scrollspy.js js/src/tab.js js/src/tooltip.js js/src/popover.js | shx sed \"s/^(import|export).*//\" | babel --filename js/src/bootstrap.js | node build/stamp.js > dist/js/bootstrap.js",
|
||||
"js-compile-plugins": "babel js/src/ --out-dir js/dist/ --source-maps",
|
||||
@ -43,7 +43,7 @@
|
||||
"docs-lint": "htmllint --rc build/.htmllintrc _gh_pages/*.html _gh_pages/**/*.html js/tests/visual/*.html",
|
||||
"docs-compile": "bundle exec jekyll build",
|
||||
"docs-serve": "bundle exec jekyll serve",
|
||||
"docs-github": "shx echo 'github: true' > $npm_config_tmp/twbsconfig.yml && npm run docs-compile -- --config _config.yml,$npm_config_tmp/twbsconfig.yml && shx rm $npm_config_tmp/twbsconfig.yml",
|
||||
"docs-github": "shx echo \"github: true\" > twbsconfig.yml && npm run docs-compile -- --config _config.yml,twbsconfig.yml && shx rm ./twbsconfig.yml",
|
||||
"docs-upload-preview": "build/upload-preview.sh",
|
||||
"maintenance-dependencies": "ncu -a -x jquery && npm update && bundle update && shx echo 'Manually update assets/js/vendor/*, js/tests/vendor/*, bower.json and .travis.yml'",
|
||||
"release-version": "node build/change-version.js",
|
||||
|
Loading…
x
Reference in New Issue
Block a user