aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohann-S <[email protected]>2017-08-29 21:32:52 +0200
committerGitHub <[email protected]>2017-08-29 21:32:52 +0200
commit0b06ad69d2c3428b052ca228c0b12b45ab36ec55 (patch)
treecfce8034c7a9a8819fe625867415c1c9e5f08586
parent0fdbaaf8853b266f75777cf84295b1bfdedd8a8a (diff)
parent1ea63d131279884ab3729111f22b455205eed6e7 (diff)
downloadbootstrap-0b06ad69d2c3428b052ca228c0b12b45ab36ec55.tar.xz
bootstrap-0b06ad69d2c3428b052ca228c0b12b45ab36ec55.zip
Merge branch 'v4-dev' into patch-5
-rw-r--r--.gitignore3
-rw-r--r--build/postcss.config.js2
-rw-r--r--docs/4.0/components/collapse.md2
-rw-r--r--docs/4.0/components/list-group.md2
-rw-r--r--js/src/modal.js12
-rw-r--r--js/src/util.js2
-rw-r--r--js/tests/unit/modal.js78
-rw-r--r--js/tests/visual/modal.html4
-rw-r--r--package.json6
9 files changed, 101 insertions, 10 deletions
diff --git a/.gitignore b/.gitignore
index 1e00d3dd4..b78c3a0fb 100644
--- a/.gitignore
+++ b/.gitignore
@@ -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
diff --git a/build/postcss.config.js b/build/postcss.config.js
index aef4679fa..cadd98d03 100644
--- a/build/postcss.config.js
+++ b/build/postcss.config.js
@@ -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',
diff --git a/docs/4.0/components/collapse.md b/docs/4.0/components/collapse.md
index c77d436fb..9e889efb2 100644
--- a/docs/4.0/components/collapse.md
+++ b/docs/4.0/components/collapse.md
@@ -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')`
diff --git a/docs/4.0/components/list-group.md b/docs/4.0/components/list-group.md
index 8dc25a0dc..5fad36d5a 100644
--- a/docs/4.0/components/list-group.md
+++ b/docs/4.0/components/list-group.md
@@ -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>
diff --git a/js/src/modal.js b/js/src/modal.js
index d21a137fb..ab73230c8 100644
--- a/js/src/modal.js
+++ b/js/src/modal.js
@@ -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')
diff --git a/js/src/util.js b/js/src/util.js
index 69fb8283c..cd3f1fb6a 100644
--- a/js/src/util.js
+++ b/js/src/util.js
@@ -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
diff --git a/js/tests/unit/modal.js b/js/tests/unit/modal.js
index 09c352443..5b265df15 100644
--- a/js/tests/unit/modal.js
+++ b/js/tests/unit/modal.js
@@ -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="&lt;div id=&quot;modal-test&quot;&gt;&lt;div class=&quot;contents&quot;&lt;div&lt;div id=&quot;close&quot; data-dismiss=&quot;modal&quot;/&gt;&lt;/div&gt;&lt;/div&gt;"/>')
+ .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="&lt;div&gt;&lt;image src=&quot;missing.png&quot; onerror=&quot;$(&apos;#qunit-fixture button.control&apos;).trigger(&apos;click&apos;)&quot;&gt;&lt;/div&gt;"/>')
+ .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)
+ })
})
diff --git a/js/tests/visual/modal.html b/js/tests/visual/modal.html
index c9a950b8c..da9bbf93a 100644
--- a/js/tests/visual/modal.html
+++ b/js/tests/visual/modal.html
@@ -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="&#x3C;div class=&#x22;modal fade the-bad&#x22; tabindex=&#x22;-1&#x22; role=&#x22;dialog&#x22;&#x3E;&#x3C;div class=&#x22;modal-dialog&#x22; role=&#x22;document&#x22;&#x3E;&#x3C;div class=&#x22;modal-content&#x22;&#x3E;&#x3C;div class=&#x22;modal-header&#x22;&#x3E;&#x3C;button type=&#x22;button&#x22; class=&#x22;close&#x22; data-dismiss=&#x22;modal&#x22; aria-label=&#x22;Close&#x22;&#x3E;&#x3C;span aria-hidden=&#x22;true&#x22;&#x3E;&#x26;times;&#x3C;/span&#x3E;&#x3C;/button&#x3E;&#x3C;h4 class=&#x22;modal-title&#x22;&#x3E;The Bad Modal&#x3C;/h4&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;modal-body&#x22;&#x3E;This modal&#x27;s HTTML source code is declared inline, inside the data-target attribute of it&#x27;s show-button&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;">
+ Modal with an XSS inside the data-target
+ </button>
</div>
<script src="../../../assets/js/vendor/jquery-slim.min.js"></script>
diff --git a/package.json b/package.json
index 92ec1b3aa..640099946 100644
--- a/package.json
+++ b/package.json
@@ -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",