Skip to content

Commit

Permalink
Merge branch 'v4-dev' into patch-5
Browse files Browse the repository at this point in the history
  • Loading branch information
Johann-S committed Aug 29, 2017
2 parents 0fdbaaf + 1ea63d1 commit 0b06ad6
Show file tree
Hide file tree
Showing 9 changed files with 101 additions and 10 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion build/postcss.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down
2 changes: 1 addition & 1 deletion docs/4.0/components/collapse.md
Original file line number Diff line number Diff line change
Expand Up @@ -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')`

Expand Down
2 changes: 1 addition & 1 deletion docs/4.0/components/list-group.md
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down
12 changes: 10 additions & 2 deletions js/src/modal.js
Original file line number Diff line number Diff line change
Expand Up @@ -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'
}

Expand Down Expand Up @@ -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
Expand All @@ -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')
Expand Down
2 changes: 1 addition & 1 deletion js/src/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
78 changes: 78 additions & 0 deletions js/tests/unit/modal.js
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down Expand Up @@ -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)
})
})
4 changes: 4 additions & 0 deletions js/tests/visual/modal.html
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,10 @@ <h4 class="modal-title" id="firefoxModalLabel">Firefox Bug Test</h4>
<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>
Expand Down
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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",
Expand Down

0 comments on commit 0b06ad6

Please sign in to comment.