diff options
| author | Johann-S <[email protected]> | 2017-08-29 21:32:52 +0200 |
|---|---|---|
| committer | GitHub <[email protected]> | 2017-08-29 21:32:52 +0200 |
| commit | 0b06ad69d2c3428b052ca228c0b12b45ab36ec55 (patch) | |
| tree | cfce8034c7a9a8819fe625867415c1c9e5f08586 | |
| parent | 0fdbaaf8853b266f75777cf84295b1bfdedd8a8a (diff) | |
| parent | 1ea63d131279884ab3729111f22b455205eed6e7 (diff) | |
| download | bootstrap-0b06ad69d2c3428b052ca228c0b12b45ab36ec55.tar.xz bootstrap-0b06ad69d2c3428b052ca228c0b12b45ab36ec55.zip | |
Merge branch 'v4-dev' into patch-5
| -rw-r--r-- | .gitignore | 3 | ||||
| -rw-r--r-- | build/postcss.config.js | 2 | ||||
| -rw-r--r-- | docs/4.0/components/collapse.md | 2 | ||||
| -rw-r--r-- | docs/4.0/components/list-group.md | 2 | ||||
| -rw-r--r-- | js/src/modal.js | 12 | ||||
| -rw-r--r-- | js/src/util.js | 2 | ||||
| -rw-r--r-- | js/tests/unit/modal.js | 78 | ||||
| -rw-r--r-- | js/tests/visual/modal.html | 4 | ||||
| -rw-r--r-- | package.json | 6 |
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="<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) + }) }) 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="<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> 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", |
