diff --git a/.gitignore b/.gitignore index d60e71a5fda5edebe58f2fa8895ca89d0e6550d9..042d47047f9c64d2492259e0544f18738df62073 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,11 @@ # Ignore docs files _gh_pages _site + +# Ignore ruby files .ruby-version -Gemfile.lock +.bundle +vendor/cache # Numerous always-ignore extensions *.diff @@ -41,6 +44,9 @@ validation-status.json # SCSS-Lint scss-lint-report.xml +# grunt-contrib-sass cache +.sass-cache + # Folders to ignore bower_components node_modules diff --git a/.travis.yml b/.travis.yml index 5899bbf0f72fb82551539e1c93b599410b31b59b..bb85115f6136c0b4bab5049c801c0ca82156117c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,15 +15,12 @@ before_install: install: - npm install -g grunt-cli - ./test-infra/s3_cache.py download npm-modules - - if [ "$TWBS_TEST" = validate-html ] && [ $TWBS_DO_VALIDATOR -ne 0 ]; then ./test-infra/s3_cache.py download rubygems; fi + - if [ -n "$BUNDLE_GEMFILE" ]; then ./test-infra/s3_cache.py download rubygems; fi after_script: - if [ "$TRAVIS_REPO_SLUG" != twbs-savage/bootstrap ] && [ "$TWBS_TEST" = core ]; then ./test-infra/s3_cache.py upload npm-modules; fi - - if [ "$TRAVIS_REPO_SLUG" != twbs-savage/bootstrap ] && [ "$TWBS_TEST" = validate-html ] && [ $TWBS_DO_VALIDATOR -ne 0 ]; then ./test-infra/s3_cache.py upload rubygems; fi + - if [ "$TRAVIS_REPO_SLUG" != twbs-savage/bootstrap ] && [ -n "$BUNDLE_GEMFILE" ]; then ./test-infra/s3_cache.py upload rubygems; fi env: global: - - JEKYLL_VERSION="2.5.1" - - ROUGE_VERSION="1.7.2" - - SCSS_LINT_VERSION="0.30.0" - SAUCE_USERNAME="bootstrap" - secure: "pJkBwnuae9dKU5tEcCqccfS1QQw7/meEcfz63fM7ba7QJNjoA6BaXj08L5Z3Vb5vBmVPwBawxo5Hp0jC0r/Z/O0hGnAmz/Cz09L+cy7dSAZ9x4hvZePSja/UAusaB5ogMoO8l2b773MzgQeSmrLbExr9BWLeqEfjC2hFgdgHLaQ=" - secure: "gqjqISbxBJK6byFbsmr1AyP1qoWH+rap06A2gI7v72+Tn2PU2nYkIMUkCvhZw6K889jv+LhQ/ybcBxDOXHpNCExCnSgB4dcnmYp+9oeNZb37jSP0rQ+Ib4OTLjzc3/FawE/fUq5kukZTC7porzc/k0qJNLAZRx3YLALmK1GIdUY=" @@ -35,8 +32,9 @@ env: - secure: "PabpUdG2dE40hHUkMCdxk1e9Ak3BOo0h7Y5/uekosLKOz5N60Xmn/ooyrSkvicLthXO4cfONFhO3/xSVRKQOxlUw4on5i0VuNK+QSqxJk0IDaRSZnTCcC8J7083K0YL+FvMdGQwcYwMY9LiwS8aS014IRkSQjsa+mjo3owP+dOU=" - secure: "G4/f4PVyVi9o6UbZMqw9YFmDu7cHqe9iymiXYd1RcnPXwhWAePX12m0PWMhUj5itJ180PTEddVip8PNOgBdqyrDxEPKkcgAW2EElVAPIKJXVfvDW64UjQ0H7NS7XvF7iLQUJp/XfmR7NJ7tT393AQdh8SGmuQpJhgYbwIWbES/k=" matrix: - - TWBS_TEST=core - - TWBS_TEST=validate-html + - TWBS_TEST=core TWBS_SASS=libsass BUNDLE_GEMFILE=test-infra/gemfiles/core.gemfile + - TWBS_TEST=core TWBS_SASS=sass BUNDLE_GEMFILE=test-infra/gemfiles/core.gemfile + - TWBS_TEST=validate-html BUNDLE_GEMFILE=Gemfile - TWBS_TEST=sauce-js-unit matrix: fast_finish: true diff --git a/Gemfile b/Gemfile index eb9646efef1108f495a604b3f9d27ee3b7220eec..23068bdfebf5d68492430c4c51b007cf015821b8 100644 --- a/Gemfile +++ b/Gemfile @@ -1,6 +1,11 @@ +# Ruby Gems for building and testing Bootstrap +# Run `grunt update-gemfile-lock` to update to the latest compatible versions + source 'https://rubygems.org' -group :development do +group :development, :test do gem 'jekyll', '~> 2.5.2' gem 'rouge', '~> 1.7.4' + gem 'sass', '~> 3.4.9' + gem 'scss-lint', '~> 0.31' end diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000000000000000000000000000000000000..725379399c4294e5a28f0636810e66a9fb6327e6 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,78 @@ +GEM + remote: https://rubygems.org/ + specs: + blankslate (2.1.2.4) + celluloid (0.16.0) + timers (~> 4.0.0) + classifier-reborn (2.0.2) + fast-stemmer (~> 1.0) + coffee-script (2.3.0) + coffee-script-source + execjs + coffee-script-source (1.8.0) + colorator (0.1) + execjs (2.2.2) + fast-stemmer (1.0.2) + ffi (1.9.6) + hitimes (1.2.2) + jekyll (2.5.2) + classifier-reborn (~> 2.0) + colorator (~> 0.1) + jekyll-coffeescript (~> 1.0) + jekyll-gist (~> 1.0) + jekyll-paginate (~> 1.0) + jekyll-sass-converter (~> 1.0) + jekyll-watch (~> 1.1) + kramdown (~> 1.3) + liquid (~> 2.6.1) + mercenary (~> 0.3.3) + pygments.rb (~> 0.6.0) + redcarpet (~> 3.1) + safe_yaml (~> 1.0) + toml (~> 0.1.0) + jekyll-coffeescript (1.0.1) + coffee-script (~> 2.2) + jekyll-gist (1.1.0) + jekyll-paginate (1.1.0) + jekyll-sass-converter (1.3.0) + sass (~> 3.2) + jekyll-watch (1.2.0) + listen (~> 2.7) + kramdown (1.5.0) + liquid (2.6.1) + listen (2.8.4) + celluloid (>= 0.15.2) + rb-fsevent (>= 0.9.3) + rb-inotify (>= 0.9) + mercenary (0.3.5) + parslet (1.5.0) + blankslate (~> 2.0) + posix-spawn (0.3.9) + pygments.rb (0.6.0) + posix-spawn (~> 0.3.6) + yajl-ruby (~> 1.1.0) + rainbow (2.0.0) + rb-fsevent (0.9.4) + rb-inotify (0.9.5) + ffi (>= 0.5.0) + redcarpet (3.2.2) + rouge (1.7.4) + safe_yaml (1.0.4) + sass (3.4.9) + scss-lint (0.31.0) + rainbow (~> 2.0) + sass (~> 3.4.1) + timers (4.0.1) + hitimes + toml (0.1.2) + parslet (~> 1.5.0) + yajl-ruby (1.1.0) + +PLATFORMS + ruby + +DEPENDENCIES + jekyll (~> 2.5.2) + rouge (~> 1.7.4) + sass (~> 3.4.9) + scss-lint (~> 0.31) diff --git a/Gruntfile.js b/Gruntfile.js index d09e6f5606ee0cf6f4eec70e8df06ef0db0d8cf4..582f4ac30840d5649c14682371e87844e74e840d 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -17,6 +17,7 @@ module.exports = function (grunt) { var fs = require('fs'); var path = require('path'); + var glob = require('glob'); var npmShrinkwrap = require('npm-shrinkwrap'); var generateCommonJSModule = require('./grunt/bs-commonjs-generator.js'); @@ -144,25 +145,6 @@ module.exports = function (grunt) { files: 'js/tests/index.html' }, - sass: { - options: { - includePaths: ['scss'], - precision: 6, - sourceComments: false, - sourceMap: true - }, - core: { - files: { - 'dist/css/<%= pkg.name %>.css': 'scss/<%= pkg.name %>.scss' - } - }, - docs: { - files: { - 'docs/assets/css/docs.min.css': 'docs/assets/scss/docs.scss' - } - } - }, - scsslint: { scss: ['scss/*.scss', '!scss/_normalize.scss'], options: { @@ -342,13 +324,23 @@ module.exports = function (grunt) { exec: { npmUpdate: { command: 'npm update' + }, + bundleUpdate: { + command: function () { + // Update dev gems and all the test gemsets + return 'bundle update && ' + glob.sync('test-infra/gemfiles/*.gemfile').map(function (gemfile) { + return 'BUNDLE_GEMFILE=' + gemfile + ' bundle update'; + }).join(' && '); + } } } }); // These plugins provide necessary tasks. - require('load-grunt-tasks')(grunt, { scope: 'devDependencies' }); + require('load-grunt-tasks')(grunt, { scope: 'devDependencies', + // Exclude Sass compilers. We choose the one to load later on. + pattern: ['grunt-*', '!grunt-sass', '!grunt-contrib-sass'] }); require('time-grunt')(grunt); // Docs HTML validation task @@ -366,7 +358,8 @@ module.exports = function (grunt) { // Skip core tests if running a different subset of the test suite if (runSubset('core') && // Skip core tests if this is a Savage build - process.env.TRAVIS_REPO_SLUG !== 'twbs-savage/bootstrap') { testSubtasks = testSubtasks.concat(['dist-css', 'dist-js', 'test-scss', 'test-js', 'docs']); + process.env.TRAVIS_REPO_SLUG !== 'twbs-savage/bootstrap') { + testSubtasks = testSubtasks.concat(['dist-css', 'dist-js', 'test-scss', 'test-js', 'docs']); } // Skip HTML validation if running a different subset of the test suite if (runSubset('validate-html') && @@ -392,7 +385,12 @@ module.exports = function (grunt) { grunt.registerTask('test-scss', ['scsslint:scss']); // CSS distribution task. + // Supported Compilers: sass (Ruby) and libsass. + (function (sassCompilerName) { + require('./grunt/bs-sass-compile/' + sassCompilerName + '.js')(grunt); + })(process.env.TWBS_SASS || 'libsass'); grunt.registerTask('sass-compile', ['sass:core', 'sass:docs']); + grunt.registerTask('dist-css', ['sass-compile', 'autoprefixer:core', 'usebanner', 'csscomb:dist', 'cssmin:core', 'cssmin:docs']); // Full distribution task. @@ -435,4 +433,7 @@ module.exports = function (grunt) { done(); }); }); + // Task for updating the cached RubyGem packages used by the Travis build (which are controlled by test-infra/Gemfile.lock). + // This task should be run and the updated file should be committed whenever Bootstrap's RubyGem dependencies change. + grunt.registerTask('update-gemfile-lock', ['exec:bundleUpdate']); }; diff --git a/dist/css/bootstrap.css b/dist/css/bootstrap.css index fbb56e094661ba02ca9c1b9c68e7b6a661783ac7..5045aa462c996a121bd187e75ac36af68bae19e2 100644 --- a/dist/css/bootstrap.css +++ b/dist/css/bootstrap.css @@ -447,7 +447,7 @@ ul ul, ul ol, ol ul, ol ol { margin-bottom: 0; } -.list-unstyled, .nav { +.list-unstyled, .list-inline, .nav { padding-left: 0; list-style: none; } @@ -607,7 +607,7 @@ pre code { } @media (min-width: 34em) { .container { - max-width: 34em; + max-width: 34rem; } } @media (min-width: 48em) { @@ -620,6 +620,11 @@ pre code { max-width: 60rem; } } +@media (min-width: 75em) { + .container { + max-width: 72.25rem; + } +} .container-fluid { padding-right: .75rem; @@ -647,7 +652,7 @@ pre code { clear: both; } -.col-xs-1, .col-sm-1, .col-md-1, .col-lg-1, .col-xl-1, .col-xs-2, .col-sm-2, .col-md-2, .col-lg-2, .col-xl-2, .col-xs-3, .col-sm-3, .col-md-3, .col-lg-3, .col-xl-3, .col-xs-4, .col-sm-4, .col-md-4, .col-lg-4, .col-xl-4, .col-xs-5, .col-sm-5, .col-md-5, .col-lg-5, .col-xl-5, .col-xs-6, .col-sm-6, .col-md-6, .col-lg-6, .col-xl-6, .col-xs-7, .col-sm-7, .col-md-7, .col-lg-7, .col-xl-7, .col-xs-8, .col-sm-8, .col-md-8, .col-lg-8, .col-xl-8, .col-xs-9, .col-sm-9, .col-md-9, .col-lg-9, .col-xl-9, .col-xs-10, .col-sm-10, .col-md-10, .col-lg-10, .col-xl-10, .col-xs-11, .col-sm-11, .col-md-11, .col-lg-11, .col-xl-11, .col-xs-12, .col-sm-12, .col-md-12, .col-lg-12, .col-xl-12 { +.col-xs-1, .col-xs-2, .col-xs-3, .col-xs-4, .col-xs-5, .col-xs-6, .col-xs-7, .col-xs-8, .col-xs-9, .col-xs-10, .col-xs-11, .col-xs-12, .col-sm-1, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-10, .col-sm-11, .col-sm-12, .col-md-1, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-10, .col-md-11, .col-md-12, .col-lg-1, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-lg-10, .col-lg-11, .col-lg-12, .col-xl-1, .col-xl-2, .col-xl-3, .col-xl-4, .col-xl-5, .col-xl-6, .col-xl-7, .col-xl-8, .col-xl-9, .col-xl-10, .col-xl-11, .col-xl-12 { position: relative; min-height: 1px; padding-right: .75rem; @@ -1492,7 +1497,7 @@ pre code { } } -@media (min-width: 62em) { +@media (min-width: 75em) { .col-xl-1, .col-xl-2, .col-xl-3, .col-xl-4, .col-xl-5, .col-xl-6, .col-xl-7, .col-xl-8, .col-xl-9, .col-xl-10, .col-xl-11, .col-xl-12 { float: left; } @@ -2725,7 +2730,7 @@ input[type="submit"].btn-block, input[type="reset"].btn-block, input[type="butto z-index: 990; } -.pull-right > .dropdown-menu, .navbar-right > .dropdown-menu { +.pull-right > .dropdown-menu { right: 0; left: auto; } @@ -3485,7 +3490,12 @@ input[type="submit"].btn-block, input[type="reset"].btn-block, input[type="butto } @media (min-width: 34em) { + .navbar-left { + float: left !important; + } + .navbar-right { + float: right !important; margin-right: -1rem; } .navbar-right ~ .navbar-right { @@ -3990,7 +4000,7 @@ a.label:hover, a.label:focus { .badge:empty { display: none; } -.badge.pull-left, .badge.navbar-left, .badge.pull-right, .badge.navbar-right { +.badge.pull-left, .badge.pull-right { top: .2em; } .list-group-item.active > .badge, .nav-pills > .active > a > .badge { @@ -4322,11 +4332,11 @@ a.badge:hover, a.badge:focus { display: block; } -.media-right, .media > .pull-right, .media > .navbar-right { +.media-right, .media > .pull-right { padding-left: 10px; } -.media-left, .media > .pull-left, .media > .navbar-left { +.media-left, .media > .pull-left { padding-right: 10px; } @@ -4705,19 +4715,23 @@ a.list-group-item-state.active, a.list-group-item-state.active:hover, a.list-gro .tooltip.in { opacity: .9; } -.tooltip.top { + +.tooltip-top { padding: 5px 0; margin-top: -3px; } -.tooltip.right { + +.tooltip-right { padding: 0 5px; margin-left: 3px; } -.tooltip.bottom { + +.tooltip-bottom { padding: 5px 0; margin-top: 3px; } -.tooltip.left { + +.tooltip-left { padding: 0 5px; margin-left: -3px; } @@ -4740,62 +4754,37 @@ a.list-group-item-state.active, a.list-group-item-state.active:hover, a.list-gro border-style: solid; } -.tooltip.top .tooltip-arrow { +.tooltip-top .tooltip-arrow { bottom: 0; left: 50%; margin-left: -5px; border-width: 5px 5px 0; border-top-color: #000; } -.tooltip.top-left .tooltip-arrow { - right: 5px; - bottom: 0; - margin-bottom: -5px; - border-width: 5px 5px 0; - border-top-color: #000; -} -.tooltip.top-right .tooltip-arrow { - bottom: 0; - left: 5px; - margin-bottom: -5px; - border-width: 5px 5px 0; - border-top-color: #000; -} -.tooltip.right .tooltip-arrow { + +.tooltip-right .tooltip-arrow { top: 50%; left: 0; margin-top: -5px; border-width: 5px 5px 5px 0; border-right-color: #000; } -.tooltip.left .tooltip-arrow { + +.tooltip-left .tooltip-arrow { top: 50%; right: 0; margin-top: -5px; border-width: 5px 0 5px 5px; border-left-color: #000; } -.tooltip.bottom .tooltip-arrow { + +.tooltip-bottom .tooltip-arrow { top: 0; left: 50%; margin-left: -5px; border-width: 0 5px 5px; border-bottom-color: #000; } -.tooltip.bottom-left .tooltip-arrow { - top: 0; - right: 5px; - margin-top: -5px; - border-width: 0 5px 5px; - border-bottom-color: #000; -} -.tooltip.bottom-right .tooltip-arrow { - top: 0; - left: 5px; - margin-top: -5px; - border-width: 0 5px 5px; - border-bottom-color: #000; -} .popover { position: absolute; @@ -4819,16 +4808,20 @@ a.list-group-item-state.active, a.list-group-item-state.active:hover, a.list-gro -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, .2); box-shadow: 0 5px 10px rgba(0, 0, 0, .2); } -.popover.top { + +.popover-top { margin-top: -10px; } -.popover.right { + +.popover-right { margin-left: 10px; } -.popover.bottom { + +.popover-bottom { margin-top: 10px; } -.popover.left { + +.popover-left { margin-left: -10px; } @@ -4845,7 +4838,7 @@ a.list-group-item-state.active, a.list-group-item-state.active:hover, a.list-gro padding: 9px 14px; } -.popover > .arrow, .popover > .arrow:after { +.popover-arrow, .popover-arrow:after { position: absolute; display: block; width: 0; @@ -4854,65 +4847,68 @@ a.list-group-item-state.active, a.list-group-item-state.active:hover, a.list-gro border-style: solid; } -.popover > .arrow { +.popover-arrow { border-width: 11px; } -.popover > .arrow:after { +.popover-arrow:after { content: ""; border-width: 10px; } -.popover.top > .arrow { +.popover-top > .popover-arrow { bottom: -11px; left: 50%; margin-left: -11px; border-top-color: rgba(0, 0, 0, .25); border-bottom-width: 0; } -.popover.top > .arrow:after { +.popover-top > .popover-arrow:after { bottom: 1px; margin-left: -10px; content: ""; border-top-color: #fff; border-bottom-width: 0; } -.popover.right > .arrow { + +.popover-right > .popover-arrow { top: 50%; left: -11px; margin-top: -11px; border-right-color: rgba(0, 0, 0, .25); border-left-width: 0; } -.popover.right > .arrow:after { +.popover-right > .popover-arrow:after { bottom: -10px; left: 1px; content: ""; border-right-color: #fff; border-left-width: 0; } -.popover.bottom > .arrow { + +.popover-bottom > .popover-arrow { top: -11px; left: 50%; margin-left: -11px; border-top-width: 0; border-bottom-color: rgba(0, 0, 0, .25); } -.popover.bottom > .arrow:after { +.popover-bottom > .popover-arrow:after { top: 1px; margin-left: -10px; content: ""; border-top-width: 0; border-bottom-color: #fff; } -.popover.left > .arrow { + +.popover-left > .popover-arrow { top: 50%; right: -11px; margin-top: -11px; border-right-width: 0; border-left-color: rgba(0, 0, 0, .25); } -.popover.left > .arrow:after { +.popover-left > .popover-arrow:after { right: 1px; bottom: -10px; content: ""; @@ -5139,11 +5135,11 @@ a.list-group-item-state.active, a.list-group-item-state.active:hover, a.list-gro margin-left: auto; } -.pull-right, .navbar-right { +.pull-right { float: right !important; } -.pull-left, .navbar-left { +.pull-left { float: left !important; } diff --git a/docs/_includes/js/popovers.html b/docs/_includes/js/popovers.html index ab33baccbdb537b8441dabfb0465913954d094cc..4557a44a4293c5fd3e2d4b65122f7af65a061105 100644 --- a/docs/_includes/js/popovers.html +++ b/docs/_includes/js/popovers.html @@ -39,24 +39,24 @@ $(function () { <h3>Static popover</h3> <p>Four options are available: top, right, bottom, and left aligned.</p> <div class="bs-example bs-example-popover"> - <div class="popover top"> - <div class="arrow"></div> + <div class="popover popover-top"> + <div class="popover-arrow"></div> <h3 class="popover-title">Popover top</h3> <div class="popover-content"> <p>Sed posuere consectetur est at lobortis. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum.</p> </div> </div> - <div class="popover right"> - <div class="arrow"></div> + <div class="popover popover-right"> + <div class="popover-arrow"></div> <h3 class="popover-title">Popover right</h3> <div class="popover-content"> <p>Sed posuere consectetur est at lobortis. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum.</p> </div> </div> - <div class="popover bottom"> - <div class="arrow"></div> + <div class="popover popover-bottom"> + <div class="popover-arrow"></div> <h3 class="popover-title">Popover bottom</h3> <div class="popover-content"> @@ -64,8 +64,8 @@ $(function () { </div> </div> - <div class="popover left"> - <div class="arrow"></div> + <div class="popover popover-left"> + <div class="popover-arrow"></div> <h3 class="popover-title">Popover left</h3> <div class="popover-content"> <p>Sed posuere consectetur est at lobortis. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum.</p> @@ -207,12 +207,12 @@ sagittis lacus vel augue laoreet rutrum faucibus."> <tr> <td>template</td> <td>string</td> - <td><code>'<div class="popover" role="tooltip"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'</code></td> + <td><code>'<div class="popover" role="tooltip"><div class="popover-arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'</code></td> <td> <p>Base HTML to use when creating the popover.</p> <p>The popover's <code>title</code> will be injected into the <code>.popover-title</code>.</p> <p>The popover's <code>content</code> will be injected into the <code>.popover-content</code>.</p> - <p><code>.arrow</code> will become the popover's arrow.</p> + <p><code>.popover-arrow</code> will become the popover's arrow.</p> <p>The outermost wrapper element should have the <code>.popover</code> class.</p> </td> </tr> diff --git a/docs/_includes/js/tooltips.html b/docs/_includes/js/tooltips.html index ae553e0df0ff20f718a7db4abc0fcc259ba115b9..b8293c9f5d3756182c7ee758bbba7ae1199d278e 100644 --- a/docs/_includes/js/tooltips.html +++ b/docs/_includes/js/tooltips.html @@ -12,25 +12,25 @@ <h3>Static tooltip</h3> <p>Four options are available: top, right, bottom, and left aligned.</p> <div class="bs-example bs-example-tooltip"> - <div class="tooltip left" role="tooltip"> + <div class="tooltip tooltip-left" role="tooltip"> <div class="tooltip-arrow"></div> <div class="tooltip-inner"> Tooltip on the left </div> </div> - <div class="tooltip top" role="tooltip"> + <div class="tooltip tooltip-top" role="tooltip"> <div class="tooltip-arrow"></div> <div class="tooltip-inner"> Tooltip on the top </div> </div> - <div class="tooltip bottom" role="tooltip"> + <div class="tooltip tooltip-bottom" role="tooltip"> <div class="tooltip-arrow"></div> <div class="tooltip-inner"> Tooltip on the bottom </div> </div> - <div class="tooltip right" role="tooltip"> + <div class="tooltip tooltip-right" role="tooltip"> <div class="tooltip-arrow"></div> <div class="tooltip-inner"> Tooltip on the right diff --git a/docs/assets/js/src/application.js b/docs/assets/js/src/application.js index 9c1ec22c47cbc3f0489f0082a69c8f0c1cd59102..8dfb826519b213b455d0b6ed4b54a83fe36957ef 100644 --- a/docs/assets/js/src/application.js +++ b/docs/assets/js/src/application.js @@ -10,6 +10,7 @@ */ /* global ZeroClipboard */ +/* global SimpleJekyllSearch */ !function ($) { 'use strict'; diff --git a/docs/components/card.md b/docs/components/card.md index 237588c55eab3d30cd927d843933625465523bbb..7e7b4d8ee4ccac4e638276a230ce2edc208acb03 100644 --- a/docs/components/card.md +++ b/docs/components/card.md @@ -21,7 +21,7 @@ Cards require very little markup, but do require some additional classes to give ### Text alignment -You can quickly change the text alignment of any card—in it's entirety or specific parts—with our [text align classes](). +You can quickly change the text alignment of any card—in its entirety or specific parts—with our [text align classes](). {% example html %} <div class="card"> diff --git a/docs/content/tables.md b/docs/content/tables.md index 23e25a2158c11ebd345b35b1333053d7c03b49ec..e4f69b06824e9f16ffa2ccf0548c8b30833e2166 100644 --- a/docs/content/tables.md +++ b/docs/content/tables.md @@ -3,7 +3,7 @@ layout: page title: Tables --- -Due to the widespread use of tables across plugins like calendars and date pickers, we've designed our tables to be **opt-in**. Just add the base class `.table` to any `<table>`. +Due to the widespread use of tables across third-party widgets like calendars and date pickers, we've designed our tables to be **opt-in**. Just add the base class `.table` to any `<table>`. ## Basic example diff --git a/docs/examples/album/index.html b/docs/examples/album/index.html index 6a3c085a8821478e40507a623dcc128552be9496..ac456377b0f367f8e9040bee8ada09f18aea8538 100644 --- a/docs/examples/album/index.html +++ b/docs/examples/album/index.html @@ -50,7 +50,7 @@ <section class="jumbotron text-center"> <div class="container"> <h1 class="jumbotron-heading">Album example</h1> - <p class="lead text-muted">Something short and leading about the collection below—it's contents, the creator, etc. Make it short and sweet, but not too short so folks don't simply skip over it entirely.</p> + <p class="lead text-muted">Something short and leading about the collection below—its contents, the creator, etc. Make it short and sweet, but not too short so folks don't simply skip over it entirely.</p> <p> <a href="#" class="btn btn-primary">Main call to action</a> <a href="#" class="btn btn-secondary">Secondary action</a> diff --git a/docs/examples/navbar-top/index.html b/docs/examples/navbar-top/index.html index 334b8430ae82fd04f3c5709e1dc1d1f69fdc635c..f54f5eafd07435fc87e4e4426df56efd7df0a2e7 100644 --- a/docs/examples/navbar-top/index.html +++ b/docs/examples/navbar-top/index.html @@ -37,7 +37,7 @@ <div class="container"> <div class="jumbotron"> <h1>Navbar example</h1> - <p class="lead">This example is a quick exercise to illustrate how the top-aligned navbar works. As you scroll, this navbar remains in it's original position and moves with the rest of the page.</p> + <p class="lead">This example is a quick exercise to illustrate how the top-aligned navbar works. As you scroll, this navbar remains in its original position and moves with the rest of the page.</p> <a class="btn btn-lg btn-primary" href="../../components/#navbar" role="button">View navbar docs »</a> </div> </div> diff --git a/docs/examples/navbar/index.html b/docs/examples/navbar/index.html index d6084e663ed95859b01f7720afca0f9706191efd..fde91fa8fa844cc895c20485cd8be53ba7cb5ab3 100644 --- a/docs/examples/navbar/index.html +++ b/docs/examples/navbar/index.html @@ -39,7 +39,7 @@ <!-- Main component for a primary marketing message or call to action --> <div class="jumbotron"> <h1>Navbar example</h1> - <p>This example is a quick exercise to illustrate how the default navbar works. It's placed within a <code>.container</code> to limit it's width and will scroll with the rest of the page's content.</p> + <p>This example is a quick exercise to illustrate how the default navbar works. It's placed within a <code>.container</code> to limit its width and will scroll with the rest of the page's content.</p> <p> <a class="btn btn-lg btn-primary" href="../../components/#navbar" role="button">View navbar docs »</a> </p> diff --git a/docs/getting-started/compiling.md b/docs/getting-started/compiling.md index 7a12becf757d93e664f7986209fe34d0e61078f0..38aa249d55ec90edb5b8ab0af4883171d4126e6c 100644 --- a/docs/getting-started/compiling.md +++ b/docs/getting-started/compiling.md @@ -13,11 +13,15 @@ From the command line: 1. Install `grunt-cli` globally with `npm install -g grunt-cli`. 2. Navigate to the root `/bootstrap` directory, then run `npm install`. npm will look at [package.json](https://github.com/twbs/bootstrap/blob/master/package.json) and automatically install the necessary local dependencies listed there. +3. [Install Ruby][install-ruby], install [Bundler][gembundler] with `gem install bundler`, and finally run `bundle`. This will install all Ruby dependencies, such as Jekyll and Sass linter. When completed, you'll be able to run the various Grunt commands provided from the command line. **Unfamiliar with npm? Don't have node installed?** That's a-okay. npm stands for [node packaged modules](http://npmjs.org/) and is a way to manage development dependencies through node.js. [Download and install node.js](http://nodejs.org/download/) before proceeding. +[install-ruby]: https://www.ruby-lang.org/en/documentation/installation/ +[gembundler]: http://bundler.io/ + ### Available Grunt commands #### Build - `grunt` @@ -35,6 +39,20 @@ Builds and tests CSS, JavaScript, and other assets which are used when running t #### Watch - `grunt watch` This is a convenience method for watching just Sass files and automatically building them whenever you save. +### Use another Sass compiler +Bootstrap is compiled with [libsass][libsass] by default. +Use another compiler by setting the `TWBS_SASS` environment variable to: + +* `sass` to use [Ruby Sass][ruby-sass] via [grunt-contrib-sass][grunt-contrib-sass]. +* `libsass` (default) to use [libsass][libsass] via [grunt-sass][grunt-sass]. + +For example, run `TWBS_SASS=sass grunt` to test and build Bootstrap with Ruby Sass. + +[ruby-sass]: https://github.com/sass/sass +[grunt-contrib-sass]: https://github.com/gruntjs/grunt-contrib-sass +[libsass]: https://github.com/sass/libsass +[grunt-sass]: https://github.com/sindresorhus/grunt-sass + ### Troubleshooting dependencies Should you encounter problems with installing dependencies or running Grunt commands, uninstall all previous dependency versions (global and local). Then, rerun `npm install`. diff --git a/docs/getting-started/quick-start.md b/docs/getting-started/quick-start.md index 6b1e682207ba3f79d1d33bf8a254dd297a2826fb..8e2f6814d8790cde3ac1d1fbf03372e3247d4ce5 100644 --- a/docs/getting-started/quick-start.md +++ b/docs/getting-started/quick-start.md @@ -22,7 +22,7 @@ Then, add the Bootstrap JavaScript—and jQuery—near the end of your pages. It Be sure to have your pages set up with the latest design and development standards. That means: * Using an HTML5 doctype -* Forcing Internet Explorer to use it's latest rendering mode ([read more]()) +* Forcing Internet Explorer to use its latest rendering mode ([read more]()) * And, utilizing the viewport meta tag. Put it all together and your pages should look like this: diff --git a/docs/getting-started/third-party-support.md b/docs/getting-started/third-party-support.md index c469b644e73a0f2cd4ed9ade2c3edc915886ff2d..ea22cf589fb212869f62733c7e35f543ab02e100 100644 --- a/docs/getting-started/third-party-support.md +++ b/docs/getting-started/third-party-support.md @@ -16,7 +16,7 @@ Depending on the context, you may override as-needed (Option 1) or reset the box * * Reset individual elements or override regions to avoid conflicts due to * global box model settings of Bootstrap. Two options, individual overrides and - * region resets, are available as plain CSS and uncompiled Less formats. + * region resets, are available as plain CSS and uncompiled Sass formats. */ /* Option 1A: Override a single element's box model via CSS */ @@ -26,7 +26,7 @@ Depending on the context, you may override as-needed (Option 1) or reset the box box-sizing: content-box; } -/* Option 1B: Override a single element's box model by using a Bootstrap Less mixin */ +/* Option 1B: Override a single element's box model by using a Bootstrap Sass mixin */ .element { .box-sizing(content-box); } @@ -41,7 +41,7 @@ Depending on the context, you may override as-needed (Option 1) or reset the box box-sizing: content-box; } -/* Option 2B: Reset an entire region with a custom Less mixin */ +/* Option 2B: Reset an entire region with a custom Sass mixin */ .reset-box-sizing { &, *, diff --git a/docs/index.html b/docs/index.html index 2ebeb3ff90065ea5c5e3ade84310ad0be18d143a..d0ae59d72dab6cb6e8b0e85d261ebbd44e362450 100644 --- a/docs/index.html +++ b/docs/index.html @@ -25,9 +25,9 @@ title: Bootstrap · The world's most popular mobile-first and responsive f <div class="row"> <div class="col-sm-4"> - <img src="assets/img/sass-less.png" alt="Sass and Less support" class="img-responsive"> + <img src="assets/img/sass-less.png" alt="Sass support" class="img-responsive"> <h3>Preprocessors</h3> - <p>Bootstrap ships with vanilla CSS, but its source code utilizes the two most popular CSS preprocessors, <a href="../css/#less">Less</a> and <a href="../css/#sass">Sass</a>. Quickly get started with precompiled CSS or build on the source.</p> + <p>Bootstrap ships with vanilla CSS, but its source code utilizes <a href="../css/#sass">Sass</a>, a popular CSS preprocessor. Quickly get started with precompiled CSS or build on the source.</p> </div> <div class="col-sm-4"> <img src="assets/img/devices.png" alt="Responsive across devices" class="img-responsive"> diff --git a/docs/javascript/alerts.md b/docs/javascript/alerts.md index bbe2eeab426eab6b700582a4bfdc8c28759779ca..8d3df5d2f8881cee473688dedf8b13cbc9a94607 100644 --- a/docs/javascript/alerts.md +++ b/docs/javascript/alerts.md @@ -22,7 +22,7 @@ When using a `.close` button, it must be the first child of the `.alert-dismissi {% example html %} <div class="alert alert-danger alert-dismissible fade in" role="alert"> <button type="button" class="close" data-dismiss="alert"><span aria-hidden="true">×</span><span class="sr-only">Close</span></button> - <h4>Oh snap! You got an error!</h4> + <h4 class="alert-heading">Oh snap! You got an error!</h4> <p>Change this and that and try again. Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Cras mattis consectetur purus sit amet fermentum.</p> <p> <button type="button" class="btn btn-danger">Take this action</button> diff --git a/docs/javascript/carousel.md b/docs/javascript/carousel.md index dac8d00d1ead8c583e8040d5c970bfe5d56feb05..d69725a594ea76511cf0b0375b553cec19274a14 100644 --- a/docs/javascript/carousel.md +++ b/docs/javascript/carousel.md @@ -37,8 +37,8 @@ A slideshow component for cycling through elements—images or slides of text— {% endexample %} <div class="bs-callout bs-callout-warning" id="callout-carousel-transitions"> - <h4>Transition animations not supported in Internet Explorer 8 & 9</h4> - <p>Bootstrap exclusively uses CSS3 for its animations, but Internet Explorer 8 & 9 don't support the necessary CSS properties. Thus, there are no slide transition animations when using these browsers. We have intentionally decided not to include jQuery-based fallbacks for the transitions.</p> + <h4>Transition animations not supported in Internet Explorer 9</h4> + <p>Bootstrap exclusively uses CSS3 for its animations, but Internet Explorer 9 doesn't support the necessary CSS properties. Thus, there are no slide transition animations when using that browser. We have intentionally decided not to include jQuery-based fallbacks for the transitions.</p> </div> <div class="bs-callout bs-callout-warning" id="callout-carousel-active"> diff --git a/docs/javascript/overview.md b/docs/javascript/overview.md index 8d22d402026bdbdf00940887f274e9082369c71e..631ea519c55084461a841ed2568a99a6332f4c57 100644 --- a/docs/javascript/overview.md +++ b/docs/javascript/overview.md @@ -81,8 +81,6 @@ $.fn.bootstrapBtn = bootstrapButton // give $().bootstrapBtn the Boot Bootstrap provides custom events for most plugins' unique actions. Generally, these come in an infinitive and past participle form - where the infinitive (ex. `show`) is triggered at the start of an event, and its past participle form (ex. `shown`) is triggered on the completion of an action. -As of 3.0.0, all Bootstrap events are namespaced. - All infinitive events provide `preventDefault` functionality. This provides the ability to stop the execution of an action before it starts. {% highlight js %} diff --git a/docs/javascript/popovers.md b/docs/javascript/popovers.md index 0844621ba306aab53b5beb32e71e8ca9b165e54a..28cafb1b0855f11592345c98363cd659b59c5ba7 100644 --- a/docs/javascript/popovers.md +++ b/docs/javascript/popovers.md @@ -43,24 +43,24 @@ $(function () { Four options are available: top, right, bottom, and left aligned. <div class="bs-example bs-example-popover"> - <div class="popover top"> - <div class="arrow"></div> + <div class="popover popover-top"> + <div class="popover-arrow"></div> <h3 class="popover-title">Popover top</h3> <div class="popover-content"> <p>Sed posuere consectetur est at lobortis. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum.</p> </div> </div> - <div class="popover right"> - <div class="arrow"></div> + <div class="popover popover-right"> + <div class="popover-arrow"></div> <h3 class="popover-title">Popover right</h3> <div class="popover-content"> <p>Sed posuere consectetur est at lobortis. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum.</p> </div> </div> - <div class="popover bottom"> - <div class="arrow"></div> + <div class="popover popover-bottom"> + <div class="popover-arrow"></div> <h3 class="popover-title">Popover bottom</h3> <div class="popover-content"> @@ -68,8 +68,8 @@ Four options are available: top, right, bottom, and left aligned. </div> </div> - <div class="popover left"> - <div class="arrow"></div> + <div class="popover popover-left"> + <div class="popover-arrow"></div> <h3 class="popover-title">Popover left</h3> <div class="popover-content"> <p>Sed posuere consectetur est at lobortis. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum.</p> @@ -222,12 +222,12 @@ Options can be passed via data attributes or JavaScript. For data attributes, ap <tr> <td>template</td> <td>string</td> - <td><code>'<div class="popover" role="tooltip"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'</code></td> + <td><code>'<div class="popover" role="tooltip"><div class="popover-arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'</code></td> <td> <p>Base HTML to use when creating the popover.</p> <p>The popover's <code>title</code> will be injected into the <code>.popover-title</code>.</p> <p>The popover's <code>content</code> will be injected into the <code>.popover-content</code>.</p> - <p><code>.arrow</code> will become the popover's arrow.</p> + <p><code>.popover-arrow</code> will become the popover's arrow.</p> <p>The outermost wrapper element should have the <code>.popover</code> class.</p> </td> </tr> diff --git a/grunt/bs-sass-compile/libsass.js b/grunt/bs-sass-compile/libsass.js new file mode 100644 index 0000000000000000000000000000000000000000..e3d13a989ffc243134c69f1a2c390653c0751344 --- /dev/null +++ b/grunt/bs-sass-compile/libsass.js @@ -0,0 +1,26 @@ +// Compile Bootstrap with [libsass][1] using [grunt-sass][2] +// [1]: https://github.com/sass/libsass +// [2]: https://github.com/sindresorhus/grunt-sass +module.exports = function configureLibsass(grunt) { + grunt.config.merge({ + sass: { + options: { + includePaths: ['scss'], + precision: 6, + sourceComments: false, + sourceMap: true + }, + core: { + files: { + 'dist/css/<%= pkg.name %>.css': 'scss/<%= pkg.name %>.scss' + } + }, + docs: { + files: { + 'docs/assets/css/docs.min.css': 'docs/assets/scss/docs.scss' + } + } + } + }); + grunt.loadNpmTasks('grunt-sass'); +}; diff --git a/grunt/bs-sass-compile/sass.js b/grunt/bs-sass-compile/sass.js new file mode 100644 index 0000000000000000000000000000000000000000..d7743515d80fd3aaf775611d2e6ccd9828bdfc5f --- /dev/null +++ b/grunt/bs-sass-compile/sass.js @@ -0,0 +1,30 @@ +// Compile Bootstrap with [Ruby Sass][1] using [grunt-contrib-sass][2] +// [1]: https://github.com/sass/sass +// [2]: https://github.com/gruntjs/grunt-contrib-sass +module.exports = function configureRubySass(grunt) { + var options = { + loadPath: ['scss'], + precision: 6, + sourcemap: 'auto', + style: 'expanded', + trace: true, + bundleExec: true + }; + grunt.config.merge({ + sass: { + core: { + options: options, + files: { + 'dist/css/<%= pkg.name %>.css': 'scss/<%= pkg.name %>.scss' + } + }, + docs: { + options: options, + files: { + 'docs/assets/css/docs.min.css': 'docs/assets/scss/docs.scss' + } + } + } + }); + grunt.loadNpmTasks('grunt-contrib-sass'); +}; diff --git a/js/.jscsrc b/js/.jscsrc index 9612c1683328ccfb22758050fb48d6871d7a81b6..ac1d73f55e4128a5728f338b020efb075ae73e30 100644 --- a/js/.jscsrc +++ b/js/.jscsrc @@ -22,6 +22,7 @@ "requireSpaceAfterKeywords": ["if", "else", "for", "while", "do", "switch", "return", "try", "catch"], "requireSpaceAfterLineComment": true, "requireSpaceBeforeBinaryOperators": ["+", "-", "/", "*", "=", "==", "===", "!=", "!==", ">", "<", ">=", "<="], + "requireSpaceBetweenArguments": true, "requireSpacesInAnonymousFunctionExpression": { "beforeOpeningCurlyBrace": true, "beforeOpeningRoundBrace": true }, "requireSpacesInConditionalExpression": true, "requireSpacesInFunctionDeclaration": { "beforeOpeningCurlyBrace": true }, diff --git a/js/popover.js b/js/popover.js index db272bdee412f9a98ef803c476c6671bf31e86c0..085584fe8744846c8c7283844ec40edeedd5a94e 100644 --- a/js/popover.js +++ b/js/popover.js @@ -25,7 +25,7 @@ placement: 'right', trigger: 'click', content: '', - template: '<div class="popover" role="tooltip"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>' + template: '<div class="popover" role="tooltip"><div class="popover-arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>' }) @@ -50,7 +50,7 @@ this.options.html ? (typeof content == 'string' ? 'html' : 'append') : 'text' ](content) - $tip.removeClass('fade top bottom left right in') + $tip.removeClass('fade popover-top popover-bottom popover-left popover-right in') // IE8 doesn't accept hiding via the `:empty` pseudo selector, we have to do // this manually by checking the contents. @@ -72,7 +72,7 @@ } Popover.prototype.arrow = function () { - return (this.$arrow = this.$arrow || this.tip().find('.arrow')) + return (this.$arrow = this.$arrow || this.tip().find('.popover-arrow')) } Popover.prototype.tip = function () { diff --git a/js/tests/unit/popover.js b/js/tests/unit/popover.js index 466ebace26d5141298886eeb41e20285c69ff6ca..8f59d3483acc9b155b196d3ba1b3090502039967 100644 --- a/js/tests/unit/popover.js +++ b/js/tests/unit/popover.js @@ -141,7 +141,7 @@ $(function () { .bootstrapPopover({ title: 'Test', content: 'Test', - template: '<div class="popover foobar"><div class="arrow"></div><div class="inner"><h3 class="title"/><div class="content"><p/></div></div></div>' + template: '<div class="popover foobar"><div class="popover-arrow"></div><div class="inner"><h3 class="title"/><div class="content"><p/></div></div></div>' }) $popover.bootstrapPopover('show') diff --git a/js/tests/unit/tooltip.js b/js/tests/unit/tooltip.js index eb578c22af3565f7f72efcf89078585670580268..6232ccdcb3beec50548766fc8581cd91f3b06810 100644 --- a/js/tests/unit/tooltip.js +++ b/js/tests/unit/tooltip.js @@ -85,7 +85,7 @@ $(function () { .bootstrapTooltip({ placement: 'bottom' }) $tooltip.bootstrapTooltip('show') - ok($('.tooltip').is('.fade.bottom.in'), 'has correct classes applied') + ok($('.tooltip').is('.fade.tooltip-bottom.in'), 'has correct classes applied') $tooltip.bootstrapTooltip('hide') equal($('.tooltip').length, 0, 'tooltip removed') @@ -300,8 +300,8 @@ $(function () { test('should add position class before positioning so that position-specific styles are taken into account', function () { var styles = '<style>' - + '.tooltip.right { white-space: nowrap; }' - + '.tooltip.right .tooltip-inner { max-width: none; }' + + '.tooltip.tooltip-right { white-space: nowrap; }' + + '.tooltip.tooltip-right .tooltip-inner { max-width: none; }' + '</style>' var $styles = $(styles).appendTo('head') @@ -384,7 +384,7 @@ $(function () { .bootstrapTooltip({ placement: 'auto' }) $topTooltip.bootstrapTooltip('show') - ok($('.tooltip').is('.bottom'), 'top positioned tooltip is dynamically positioned to bottom') + ok($('.tooltip').is('.tooltip-bottom'), 'top positioned tooltip is dynamically positioned to bottom') $topTooltip.bootstrapTooltip('hide') equal($('.tooltip').length, 0, 'top positioned tooltip removed from dom') @@ -394,7 +394,7 @@ $(function () { .bootstrapTooltip({ placement: 'right auto' }) $rightTooltip.bootstrapTooltip('show') - ok($('.tooltip').is('.left'), 'right positioned tooltip is dynamically positioned left') + ok($('.tooltip').is('.tooltip-left'), 'right positioned tooltip is dynamically positioned left') $rightTooltip.bootstrapTooltip('hide') equal($('.tooltip').length, 0, 'right positioned tooltip removed from dom') @@ -404,7 +404,7 @@ $(function () { .bootstrapTooltip({ placement: 'auto left' }) $leftTooltip.bootstrapTooltip('show') - ok($('.tooltip').is('.right'), 'left positioned tooltip is dynamically positioned right') + ok($('.tooltip').is('.tooltip-right'), 'left positioned tooltip is dynamically positioned right') $leftTooltip.bootstrapTooltip('hide') equal($('.tooltip').length, 0, 'left positioned tooltip removed from dom') @@ -430,7 +430,7 @@ $(function () { }) $target.bootstrapTooltip('show') - ok($('.tooltip').is('.top'), 'top positioned tooltip is dynamically positioned to top') + ok($('.tooltip').is('.tooltip-top'), 'top positioned tooltip is dynamically positioned to top') $target.bootstrapTooltip('hide') equal($('.tooltip').length, 0, 'tooltip removed from dom') @@ -455,7 +455,7 @@ $(function () { }) $target.bootstrapTooltip('show') - ok($('.tooltip').is('.bottom'), 'top positioned tooltip is dynamically positioned to bottom') + ok($('.tooltip').is('.tooltip-bottom'), 'top positioned tooltip is dynamically positioned to bottom') $target.bootstrapTooltip('hide') equal($('.tooltip').length, 0, 'tooltip removed from dom') @@ -481,7 +481,7 @@ $(function () { $('#scrollable-div').scrollTop(100) $target.bootstrapTooltip('show') - ok($('.tooltip').is('.fade.top.in'), 'has correct classes applied') + ok($('.tooltip').is('.fade.tooltip-top.in'), 'has correct classes applied') $target.bootstrapTooltip('hide') equal($('.tooltip').length, 0, 'tooltip removed from dom') @@ -507,7 +507,7 @@ $(function () { $('#scrollable-div').scrollTop(200) $target.bootstrapTooltip('show') - ok($('.tooltip').is('.fade.bottom.in'), 'has correct classes applied') + ok($('.tooltip').is('.fade.tooltip-bottom.in'), 'has correct classes applied') $target.bootstrapTooltip('hide') equal($('.tooltip').length, 0, 'tooltip removed from dom') @@ -537,7 +537,7 @@ $(function () { $('#scrollable-div').scrollTop(200) $target.bootstrapTooltip('show') - ok($('.tooltip').is('.fade.bottom.in'), 'has correct classes applied') + ok($('.tooltip').is('.fade.tooltip-bottom.in'), 'has correct classes applied') $target.bootstrapTooltip('hide') equal($('.tooltip').length, 0, 'tooltip removed from dom') @@ -563,7 +563,7 @@ $(function () { $('#scrollable-div').scrollTop(400) $target.bootstrapTooltip('show') - ok($('.tooltip').is('.fade.top.in'), 'has correct classes applied') + ok($('.tooltip').is('.fade.tooltip-top.in'), 'has correct classes applied') $target.bootstrapTooltip('hide') equal($('.tooltip').length, 0, 'tooltip removed from dom') diff --git a/js/tooltip.js b/js/tooltip.js index bd376f77279be72aebc6685783a697ac033cd46b..9d3074cc048591f0b6992317919866d7a846cfa2 100644 --- a/js/tooltip.js +++ b/js/tooltip.js @@ -177,7 +177,7 @@ $tip .detach() .css({ top: 0, left: 0, display: 'block' }) - .addClass(placement) + .addClass(this.type + '-' + placement) .data('bs.' + this.type, this) this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element) @@ -187,7 +187,7 @@ var actualHeight = $tip[0].offsetHeight if (autoPlace) { - var orgPlacement = placement + var origPlacement = placement var $container = this.options.container ? $(this.options.container) : this.$element.parent() var containerDim = this.getPosition($container) @@ -198,8 +198,8 @@ placement $tip - .removeClass(orgPlacement) - .addClass(placement) + .removeClass(this.type + '-' + origPlacement) + .addClass(this.type + '-' + placement) } var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight) @@ -283,7 +283,7 @@ var title = this.getTitle() $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title) - $tip.removeClass('fade in top bottom left right') + $tip.removeClass('fade in tooltip-top tooltip-bottom tooltip-left tooltip-right') } Tooltip.prototype.hide = function (callback) { diff --git a/package.json b/package.json index 049eec9999b43cbf8a4fee808db6f9b02f92728b..ef03659e8d27f618bca96bd9629daaf6cd76cef7 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ }, "devDependencies": { "btoa": "~1.1.2", - "glob": "~4.2.1", + "glob": "~4.3.1", "grunt": "~0.4.5", "grunt-autoprefixer": "~2.0.0", "grunt-banner": "~0.2.3", @@ -42,23 +42,24 @@ "grunt-contrib-copy": "~0.7.0", "grunt-contrib-csslint": "~0.3.1", "grunt-contrib-cssmin": "~0.10.0", - "grunt-contrib-jade": "~0.13.0", + "grunt-contrib-jade": "~0.14.0", "grunt-contrib-jshint": "~0.10.0", "grunt-contrib-qunit": "~0.5.2", - "grunt-contrib-uglify": "~0.6.0", + "grunt-contrib-sass": "^0.8.1", + "grunt-contrib-uglify": "~0.7.0", "grunt-contrib-watch": "~0.6.1", "grunt-csscomb": "~3.0.0", "grunt-exec": "~0.4.6", "grunt-html-validation": "~0.1.18", "grunt-jekyll": "~0.4.2", - "grunt-jscs": "~1.0.0", + "grunt-jscs": "~1.1.0", "grunt-sass": "~0.17.0", - "grunt-saucelabs": "~8.3.3", + "grunt-saucelabs": "~8.4.0", "grunt-scss-lint": "^0.3.4", "grunt-sed": "~0.1.1", - "load-grunt-tasks": "~1.0.0", - "npm-shrinkwrap": "5.0.0", - "remarkable": "~1.4.2", + "load-grunt-tasks": "~2.0.0", + "npm-shrinkwrap": "^200.0.0", + "remarkable": "~1.6.0", "time-grunt": "~1.0.0" }, "engines": { diff --git a/scss/_alert.scss b/scss/_alert.scss index 685ca314b115565537513d615a18ad30ee249af4..8ec7d066283b222c5aead2ee80b11a668ea48751 100644 --- a/scss/_alert.scss +++ b/scss/_alert.scss @@ -12,17 +12,6 @@ border: 1px solid transparent; @include border-radius($alert-border-radius); - // Headings for larger alerts - h4 { - margin-top: 0; - // Specified for the h4 to prevent conflicts of changing $headings-color - color: inherit; - } - // Provide class for links that match alerts - .alert-link { - font-weight: $alert-link-font-weight; - } - // Improve alignment and spacing of inner content > p, > ul { @@ -33,6 +22,18 @@ } } +// Headings for larger alerts +.alert-heading { + margin-top: 0; + // Specified to prevent conflicts of changing $headings-color + color: inherit; +} + +// Provide class for links that match alerts +.alert-link { + font-weight: $alert-link-font-weight; +} + // Dismissible alerts // // Expand the right padding and account for the close button's positioning. diff --git a/scss/_forms.scss b/scss/_forms.scss index 67a4f8020372c9057b49556849dbab77a6a1c406..2d9867d32bd3dc920d7f7845594208232d2449e3 100644 --- a/scss/_forms.scss +++ b/scss/_forms.scss @@ -540,14 +540,14 @@ input[type="checkbox"] { // Quick utility class for applying `.input-lg` and `.input-sm` styles to the // inputs and labels within a `.form-group`. .form-group-lg { - @media (min-width: $screen-sm-min) { + @include media-sm { .control-label { padding-top: $padding-lg-vertical; } } } .form-group-sm { - @media (min-width: $screen-sm-min) { + @include media-sm { .control-label { padding-top: ($padding-sm-vertical + .1); } diff --git a/scss/_grid.scss b/scss/_grid.scss index 6374d77def3e5ef5fc41f1438eb25490227a8b1f..1129cff6d024a926c36ff3179dd5a517c9f7b954 100644 --- a/scss/_grid.scss +++ b/scss/_grid.scss @@ -10,14 +10,11 @@ .container { @include make-container(); - @media (min-width: $screen-sm-min) { - max-width: $container-sm; - } - @media (min-width: $screen-md-min) { - max-width: $container-md; - } - @media (min-width: $screen-lg-min) { - max-width: $container-lg; + // For each breakpoint, define the maximum width of the container in a media query + @each $breakpoint, $container-max-width in $container-max-widths { + @include media-breakpoint-min($breakpoint) { + max-width: $container-max-width; + } } } @@ -47,47 +44,3 @@ @include make-grid-columns(); - -// Extra small grid -// -// Columns, offsets, pushes, and pulls for extra small devices like -// smartphones. - -@include make-grid(xs); - - -// Small grid -// -// Columns, offsets, pushes, and pulls for the small device range, from phones -// to tablets. - -@include media-sm { - @include make-grid(sm); -} - - -// Medium grid -// -// Columns, offsets, pushes, and pulls for the desktop device range. - -@include media-md { - @include make-grid(md); -} - - -// Large grid -// -// Columns, offsets, pushes, and pulls for the large desktop device range. - -@include media-lg { - @include make-grid(lg); -} - - -// Large grid -// -// Columns, offsets, pushes, and pulls for the large desktop device range. - -@include media-lg { - @include make-grid(xl); -} diff --git a/scss/_mixins.scss b/scss/_mixins.scss index d9f0e7a4b3d322894e24ab85d8d4b59d4d9a5a2e..801b5c7e992a937fffded5688f330bb8d543b3a9 100644 --- a/scss/_mixins.scss +++ b/scss/_mixins.scss @@ -24,6 +24,7 @@ } // Utilities +@import "mixins/breakpoints"; @import "mixins/media-queries"; @import "mixins/hide-text"; @import "mixins/image"; @@ -57,3 +58,4 @@ // @import "mixins/navbar-align"; @import "mixins/grid-framework"; @import "mixins/grid"; +@import "mixins/pulls"; diff --git a/scss/_modal.scss b/scss/_modal.scss index 8fb7d201ddb5120b3079a10ec013aa90d0004b88..2566c3ef2de23824f71fcd38713f17208c3737dd 100644 --- a/scss/_modal.scss +++ b/scss/_modal.scss @@ -126,7 +126,7 @@ } // Scale up the modal -@media (min-width: $screen-sm-min) { +@include media-sm { // Automatically set modal's width for larger viewports .modal-dialog { width: $modal-md; @@ -140,6 +140,6 @@ .modal-sm { width: $modal-sm; } } -@media (min-width: $screen-md-min) { +@include media-md { .modal-lg { width: $modal-lg; } } diff --git a/scss/_navbar.scss b/scss/_navbar.scss index d4dcb673f08f9e7c8aa44c47ed66fc6ae9a62aec..b163dad9cd9499e3b9e9a2522a0347133dfaa289 100644 --- a/scss/_navbar.scss +++ b/scss/_navbar.scss @@ -199,10 +199,10 @@ @include media-sm { .navbar-left { - @extend .pull-left; + @include pull-left(); } .navbar-right { - @extend .pull-right; + @include pull-right(); margin-right: -$navbar-padding-horizontal; ~ .navbar-right { diff --git a/scss/_popover.scss b/scss/_popover.scss index 63928a4fce009ff7d72a72f9d7f2915f0d86a578..a614518c7f7efa7c46fa7f893629d2c162e33a65 100644 --- a/scss/_popover.scss +++ b/scss/_popover.scss @@ -24,14 +24,14 @@ border: 1px solid $popover-border-color; @include border-radius($border-radius-lg); @include box-shadow(0 5px 10px rgba(0,0,0,.2)); - - // Offset the popover to account for the popover arrow - &.top { margin-top: -$popover-arrow-width; } - &.right { margin-left: $popover-arrow-width; } - &.bottom { margin-top: $popover-arrow-width; } - &.left { margin-left: -$popover-arrow-width; } } +// Offset the popover to account for the popover arrow +.popover-top { margin-top: -$popover-arrow-width; } +.popover-right { margin-left: $popover-arrow-width; } +.popover-bottom { margin-top: $popover-arrow-width; } +.popover-left { margin-left: -$popover-arrow-width; } + .popover-title { padding: 8px 14px; margin: 0; // reset heading margin @@ -47,9 +47,9 @@ // Arrows // -// .arrow is outer, .arrow:after is inner +// .popover-arrow is outer, .popover-arrow:after is inner -.popover > .arrow { +.popover-arrow { &, &:after { position: absolute; @@ -60,70 +60,68 @@ border-style: solid; } } -.popover > .arrow { +.popover-arrow { border-width: $popover-arrow-outer-width; } -.popover > .arrow:after { +.popover-arrow:after { content: ""; border-width: $popover-arrow-width; } -.popover { - &.top > .arrow { - bottom: -$popover-arrow-outer-width; - left: 50%; - margin-left: -$popover-arrow-outer-width; - border-top-color: $popover-arrow-outer-color; +.popover-top > .popover-arrow { + bottom: -$popover-arrow-outer-width; + left: 50%; + margin-left: -$popover-arrow-outer-width; + border-top-color: $popover-arrow-outer-color; + border-bottom-width: 0; + &:after { + bottom: 1px; + margin-left: -$popover-arrow-width; + content: ""; + border-top-color: $popover-arrow-color; border-bottom-width: 0; - &:after { - bottom: 1px; - margin-left: -$popover-arrow-width; - content: ""; - border-top-color: $popover-arrow-color; - border-bottom-width: 0; - } } - &.right > .arrow { - top: 50%; - left: -$popover-arrow-outer-width; - margin-top: -$popover-arrow-outer-width; - border-right-color: $popover-arrow-outer-color; +} +.popover-right > .popover-arrow { + top: 50%; + left: -$popover-arrow-outer-width; + margin-top: -$popover-arrow-outer-width; + border-right-color: $popover-arrow-outer-color; + border-left-width: 0; + &:after { + bottom: -$popover-arrow-width; + left: 1px; + content: ""; + border-right-color: $popover-arrow-color; border-left-width: 0; - &:after { - bottom: -$popover-arrow-width; - left: 1px; - content: ""; - border-right-color: $popover-arrow-color; - border-left-width: 0; - } } - &.bottom > .arrow { - top: -$popover-arrow-outer-width; - left: 50%; - margin-left: -$popover-arrow-outer-width; +} +.popover-bottom > .popover-arrow { + top: -$popover-arrow-outer-width; + left: 50%; + margin-left: -$popover-arrow-outer-width; + border-top-width: 0; + border-bottom-color: $popover-arrow-outer-color; + &:after { + top: 1px; + margin-left: -$popover-arrow-width; + content: ""; border-top-width: 0; - border-bottom-color: $popover-arrow-outer-color; - &:after { - top: 1px; - margin-left: -$popover-arrow-width; - content: ""; - border-top-width: 0; - border-bottom-color: $popover-arrow-color; - } + border-bottom-color: $popover-arrow-color; } +} - &.left > .arrow { - top: 50%; - right: -$popover-arrow-outer-width; - margin-top: -$popover-arrow-outer-width; +.popover-left > .popover-arrow { + top: 50%; + right: -$popover-arrow-outer-width; + margin-top: -$popover-arrow-outer-width; + border-right-width: 0; + border-left-color: $popover-arrow-outer-color; + &:after { + right: 1px; + bottom: -$popover-arrow-width; + content: ""; border-right-width: 0; - border-left-color: $popover-arrow-outer-color; - &:after { - right: 1px; - bottom: -$popover-arrow-width; - content: ""; - border-right-width: 0; - border-left-color: $popover-arrow-color; - } + border-left-color: $popover-arrow-color; } } diff --git a/scss/_tooltip.scss b/scss/_tooltip.scss index 033c19f3b0243dd011929c9b38b8606d468cd376..49af2b28815cc6e5bc27844799fa19e6358a9bf6 100644 --- a/scss/_tooltip.scss +++ b/scss/_tooltip.scss @@ -17,26 +17,23 @@ opacity: 0; &.in { opacity: $tooltip-opacity; } +} - &.top { - padding: $tooltip-arrow-width 0; - margin-top: -3px; - } - - &.right { - padding: 0 $tooltip-arrow-width; - margin-left: 3px; - } - - &.bottom { - padding: $tooltip-arrow-width 0; - margin-top: 3px; - } - - &.left { - padding: 0 $tooltip-arrow-width; - margin-left: -3px; - } +.tooltip-top { + padding: $tooltip-arrow-width 0; + margin-top: -3px; +} +.tooltip-right { + padding: 0 $tooltip-arrow-width; + margin-left: 3px; +} +.tooltip-bottom { + padding: $tooltip-arrow-width 0; + margin-top: 3px; +} +.tooltip-left { + padding: 0 $tooltip-arrow-width; + margin-left: -3px; } // Wrapper for the tooltip content @@ -58,62 +55,31 @@ border-color: transparent; border-style: solid; } -// Note: Deprecated .top-left, .top-right, .bottom-left, and .bottom-right as of v3.3.1 -.tooltip { - &.top .tooltip-arrow { - bottom: 0; - left: 50%; - margin-left: -$tooltip-arrow-width; - border-width: $tooltip-arrow-width $tooltip-arrow-width 0; - border-top-color: $tooltip-arrow-color; - } - &.top-left .tooltip-arrow { - right: $tooltip-arrow-width; - bottom: 0; - margin-bottom: -$tooltip-arrow-width; - border-width: $tooltip-arrow-width $tooltip-arrow-width 0; - border-top-color: $tooltip-arrow-color; - } - &.top-right .tooltip-arrow { - bottom: 0; - left: $tooltip-arrow-width; - margin-bottom: -$tooltip-arrow-width; - border-width: $tooltip-arrow-width $tooltip-arrow-width 0; - border-top-color: $tooltip-arrow-color; - } - &.right .tooltip-arrow { - top: 50%; - left: 0; - margin-top: -$tooltip-arrow-width; - border-width: $tooltip-arrow-width $tooltip-arrow-width $tooltip-arrow-width 0; - border-right-color: $tooltip-arrow-color; - } - &.left .tooltip-arrow { - top: 50%; - right: 0; - margin-top: -$tooltip-arrow-width; - border-width: $tooltip-arrow-width 0 $tooltip-arrow-width $tooltip-arrow-width; - border-left-color: $tooltip-arrow-color; - } - &.bottom .tooltip-arrow { - top: 0; - left: 50%; - margin-left: -$tooltip-arrow-width; - border-width: 0 $tooltip-arrow-width $tooltip-arrow-width; - border-bottom-color: $tooltip-arrow-color; - } - &.bottom-left .tooltip-arrow { - top: 0; - right: $tooltip-arrow-width; - margin-top: -$tooltip-arrow-width; - border-width: 0 $tooltip-arrow-width $tooltip-arrow-width; - border-bottom-color: $tooltip-arrow-color; - } - &.bottom-right .tooltip-arrow { - top: 0; - left: $tooltip-arrow-width; - margin-top: -$tooltip-arrow-width; - border-width: 0 $tooltip-arrow-width $tooltip-arrow-width; - border-bottom-color: $tooltip-arrow-color; - } +.tooltip-top .tooltip-arrow { + bottom: 0; + left: 50%; + margin-left: -$tooltip-arrow-width; + border-width: $tooltip-arrow-width $tooltip-arrow-width 0; + border-top-color: $tooltip-arrow-color; +} +.tooltip-right .tooltip-arrow { + top: 50%; + left: 0; + margin-top: -$tooltip-arrow-width; + border-width: $tooltip-arrow-width $tooltip-arrow-width $tooltip-arrow-width 0; + border-right-color: $tooltip-arrow-color; +} +.tooltip-left .tooltip-arrow { + top: 50%; + right: 0; + margin-top: -$tooltip-arrow-width; + border-width: $tooltip-arrow-width 0 $tooltip-arrow-width $tooltip-arrow-width; + border-left-color: $tooltip-arrow-color; +} +.tooltip-bottom .tooltip-arrow { + top: 0; + left: 50%; + margin-left: -$tooltip-arrow-width; + border-width: 0 $tooltip-arrow-width $tooltip-arrow-width; + border-bottom-color: $tooltip-arrow-color; } diff --git a/scss/_type.scss b/scss/_type.scss index 395417324500149ff16b7866a1ef2e0cca9cb3f0..5bbbf5873e2f2f5302558aef1b2b05a03973b60c 100644 --- a/scss/_type.scss +++ b/scss/_type.scss @@ -116,7 +116,7 @@ ol { // Inline turns list items into inline-block .list-inline { - @extend list-unstyled(); + @extend .list-unstyled; margin-left: -5px; > li { diff --git a/scss/_utilities.scss b/scss/_utilities.scss index aeffdcd78167caff6d20ac4788efe233097de015..5e297fc75eb0f28f18515be5c3d0a76ca0e6fac4 100644 --- a/scss/_utilities.scss +++ b/scss/_utilities.scss @@ -10,11 +10,12 @@ .center-block { @include center-block(); } + .pull-right { - float: right !important; + @include pull-right(); } .pull-left { - float: left !important; + @include pull-left(); } diff --git a/scss/_variables.scss b/scss/_variables.scss index 24271131431d2e6432cf874da6bccbfbebdb3ca4..4b515d3a4c1bf6fb5dbe2947b015054337903f2f 100644 --- a/scss/_variables.scss +++ b/scss/_variables.scss @@ -272,29 +272,22 @@ $zindex-modal: 1040 !default; // //## Define the minimum and maximum dimensions at which your layout will change, adapting to different screen sizes. -// Extra large screen / wide desktop -$screen-xl-min: 75em !default; - -// Large screen / desktop -$screen-lg-max: ($screen-xl-min - .1) !default; -$screen-lg-min: 62em !default; - -// Medium screen / tablet -$screen-md-max: ($screen-lg-min - .1) !default; -$screen-md-min: 48em !default; - -// Small screen / phone -$screen-sm-max: ($screen-md-min - .1) !default; -$screen-sm-min: 34em !default; - -// Extra small screen / phone -$screen-xs-max: ($screen-sm-min - .1) !default; - - //== Grid system // //## Define your custom responsive grid. -$grid-breakpoints: (xs sm md lg xl); +$grid-breakpoints: ( + // Extra small screen / phone + xs: 0, + // Small screen / phone + sm: 34em, + // Medium screen / tablet + md: 48em, + // Large screen / desktop + lg: 62em, + // Extra large screen / wide desktop + xl: 75em +) !default; + //** Number of columns in the grid. $grid-columns: 12 !default; //** Padding between columns. Gets divided in half for the left and right. @@ -305,17 +298,12 @@ $grid-gutter-width: 1.5rem !default; // //## Define the maximum width of `.container` for different screen sizes. -//** For `$screen-xs-min` and up. -$container-sm: 34em !default; // 480 - -//** For `$screen-sm-min` and up. -$container-md: 45rem !default; // 720 - -//** For `$screen-md-min` and up. -$container-lg: 60rem !default; // 960 - -//** For `$screen-lg-min` and up. -$container-xl: 72.25rem !default; // 1140 +$container-max-widths: ( + sm: 34rem, // 480 + md: 45rem, // 720 + lg: 60rem, // 960 + xl: 72.25rem // 1140 +) !default; //== Navbar diff --git a/scss/mixins/_breakpoints.scss b/scss/mixins/_breakpoints.scss new file mode 100644 index 0000000000000000000000000000000000000000..71a15cd0430a21def001094952151d7574c2501b --- /dev/null +++ b/scss/mixins/_breakpoints.scss @@ -0,0 +1,85 @@ +// Breakpoint viewport sizes and media queries. +// +// Breakpoints are defined as a map of (name: minimum width), order from small to large: +// +// (xs: 0, sm: 34rem, md: 45rem) +// +// The map defined in the `$grid-breakpoints` global variable is used as the `$breakpoints` argument by default. + +// Name of the next breakpoint, or null for the last breakpoint. +// +// >> breakpoint-next(sm) +// md +// >> breakpoint-next(sm, $breakpoints: (xs: 0, sm: 34rem, md: 45rem)) +// md +// >> breakpoint-next(sm, $breakpoint-names: (xs sm md)) +// md +@function breakpoint-next($name, $breakpoints: $grid-breakpoints, $breakpoint-names: map-keys($breakpoints)) { + $n: index($breakpoint-names, $name); + @return if($n < length($breakpoint-names), nth($breakpoint-names, $n + 1), null); +} + +// Minimum breakpoint width. Null for the smallest (first) breakpoint. +// +// >> breakpoint-min(sm, (xs: 0, sm: 34rem, md: 45rem)) +// 34rem +@function breakpoint-min($name, $breakpoints: $grid-breakpoints) { + $min: map-get($breakpoints, $name); + @return if($min != 0, $min, null); +} + +// Maximum breakpoint width. Null for the largest (last) breakpoint. +// The maximum value is calculated as the minimum of the next one less 0.1. +// +// >> breakpoint-max(sm, (xs: 0, sm: 34rem, md: 45rem)) +// 44.9rem +@function breakpoint-max($name, $breakpoints: $grid-breakpoints) { + $next: breakpoint-next($name, $breakpoints); + @return if($next, breakpoint-min($next, $breakpoints) - 0.1, null); +} + +// Media of at least the minimum breakpoint width. No query for the smallest breakpoint. +@mixin media-breakpoint-min($name, $breakpoints: $grid-breakpoints) { + $min: breakpoint-min($name, $breakpoints); + @if $min { + @media (min-width: $min) { + @content; + } + } @else { + @content; + } +} + +// Media of at most the maximum breakpoint width. No query for the largest breakpoint. +@mixin media-breakpoint-max($name, $breakpoints: $grid-breakpoints) { + $max: breakpoint-max($name, $breakpoints); + @if $max { + @media (max-width: $max) { + @content; + } + } @else { + @content; + } +} + +// Media between the breakpoint's minimum and maximum widths. +// No minimum for the smallest breakpoint, and no maximum for the largest one. +@mixin media-breakpoint-only($name, $breakpoints: $grid-breakpoints) { + // Nested media query combination does not work in libsass yet + // https://github.com/sass/libsass/issues/185 + // Work around until the issue is resolved: + $min: breakpoint-min($name, $breakpoints); + $max: breakpoint-max($name, $breakpoints); + @if $min and $max { + @media (min-width: $min) and (max-width: $max) { + @content; + } + } @else { + // One of min or max is a no-op, so this branch is not affected by libsass#185 + @include media-breakpoint-min($name, $breakpoints) { + @include media-breakpoint-max($name, $breakpoints) { + @content; + } + } + } +} diff --git a/scss/mixins/_grid-framework.scss b/scss/mixins/_grid-framework.scss index 3eecbae8b27788c6edcc8c640757ac9d5b7c1409..0d346db57d81c987cb334869b581f61dc5d0db95 100644 --- a/scss/mixins/_grid-framework.scss +++ b/scss/mixins/_grid-framework.scss @@ -3,69 +3,40 @@ // Used only by Bootstrap to generate the correct number of grid classes given // any value of `$grid-columns`. -// Common properties for all breakpoints -@mixin make-grid-columns($columns: $grid-columns, $breakpoints: $grid-breakpoints) { +@mixin make-grid-columns($columns: $grid-columns, $gutter: $grid-gutter-width, $breakpoints: $grid-breakpoints) { + // Common properties for all breakpoints %grid-column { position: relative; // Prevent columns from collapsing when empty min-height: 1px; // Inner gutter via padding - padding-left: ($grid-gutter-width / 2); - padding-right: ($grid-gutter-width / 2); + padding-left: ($gutter / 2); + padding-right: ($gutter / 2); } - @for $i from 1 through $columns { - @each $breakpoint in $breakpoints { + @each $breakpoint in map-keys($breakpoints) { + @for $i from 1 through $columns { .col-#{$breakpoint}-#{$i} { @extend %grid-column; } } - } -} - -// Breakpoint-specific properties -@mixin make-grid($breakpoint, $columns: $grid-columns) { - // Work around cross-media @extend (https://github.com/sass/sass/issues/1050) - %grid-column-float-#{$breakpoint} { - float: left; - } - @for $i from 1 through $columns { - .col-#{$breakpoint}-#{$i} { - @extend %grid-column-float-#{$breakpoint}; - @include grid-column-width($i, $columns); - } - } - @each $modifier in (pull, push, offset) { - @for $i from 0 through $columns { - .col-#{$breakpoint}-#{$modifier}-#{$i} { - @include grid-column-modifier($modifier, $i, $columns) + @include media-breakpoint-min($breakpoint) { + // Work around cross-media @extend (https://github.com/sass/sass/issues/1050) + %grid-column-float-#{$breakpoint} { + float: left; + } + @for $i from 1 through $columns { + .col-#{$breakpoint}-#{$i} { + @extend %grid-column-float-#{$breakpoint}; + @include make-col-span($i, $columns); + } + } + @each $modifier in (pull, push, offset) { + @for $i from 0 through $columns { + .col-#{$breakpoint}-#{$modifier}-#{$i} { + @include make-col-modifier($modifier, $i, $columns) + } + } } } } } - -@mixin grid-column-width($index, $columns) { - width: percentage($index / $columns); -} - -@mixin grid-column-push($index, $columns) { - left: if($index > 0, percentage($index / $columns), auto); -} - -@mixin grid-column-pull($index, $columns) { - right: if($index > 0, percentage($index / $columns), auto); -} - -@mixin grid-column-offset($index, $columns) { - margin-left: percentage($index / $columns); -} - -// Work around the lack of dynamic mixin @include support (https://github.com/sass/sass/issues/626) -@mixin grid-column-modifier($type, $index, $columns) { - @if $type == push { - @include grid-column-push($index, $columns); - } @else if $type == pull { - @include grid-column-pull($index, $columns); - } @else if $type == offset { - @include grid-column-offset($index, $columns); - } -} diff --git a/scss/mixins/_grid.scss b/scss/mixins/_grid.scss index aceaeeb4c469bfdca7b54b5fd5e16fe399acd78c..29af269aacdd22f2d9cae0a0335edc0fe48ec7c0 100644 --- a/scss/mixins/_grid.scss +++ b/scss/mixins/_grid.scss @@ -24,18 +24,29 @@ padding-right: ($gutter / 2); } -@mixin make-col-span($columns) { - width: percentage(($columns / $grid-columns)); +@mixin make-col-span($size, $columns: $grid-columns) { + width: percentage($size / $columns); } -@mixin make-col-offset($columns) { - margin-left: percentage(($columns / $grid-columns)); +@mixin make-col-offset($size, $columns: $grid-columns) { + margin-left: percentage($size / $columns); } -@mixin make-col-push($columns) { - left: percentage(($columns / $grid-columns)); +@mixin make-col-push($size, $columns: $grid-columns) { + left: if($size > 0, percentage($size / $columns), auto); } -@mixin make-col-pull($columns) { - right: percentage(($columns / $grid-columns)); +@mixin make-col-pull($size, $columns: $grid-columns) { + right: if($size > 0, percentage($size / $columns), auto); +} + +@mixin make-col-modifier($type, $size, $columns) { + // Work around the lack of dynamic mixin @include support (https://github.com/sass/sass/issues/626) + @if $type == push { + @include make-col-push($size, $columns); + } @else if $type == pull { + @include make-col-pull($size, $columns); + } @else if $type == offset { + @include make-col-offset($size, $columns); + } } diff --git a/scss/mixins/_media-queries.scss b/scss/mixins/_media-queries.scss index b4e16ed888fee19a949c9a45b80bb89c7e3f67cd..28130d2e7ea25f4b98ef5541a3a2da771be2729e 100644 --- a/scss/mixins/_media-queries.scss +++ b/scss/mixins/_media-queries.scss @@ -1,25 +1,25 @@ -// Media query mixins +// Media query mixins for default breakpoints @mixin media-xs() { - @media (max-width: $screen-xs-max) { @content } + @include media-breakpoint-max(xs) { @content } } @mixin media-sm() { - @media (min-width: $screen-sm-min) { @content } + @include media-breakpoint-min(sm) { @content } } @mixin media-sm-max() { - @media (min-width: $screen-sm-min) and (max-width: $screen-sm-max) { @content } + @include media-breakpoint-only(sm) { @content } } @mixin media-md() { - @media (min-width: $screen-md-min) { @content } + @include media-breakpoint-min(md) { @content } } @mixin media-md-max() { - @media (min-width: $screen-md-min) and (max-width: $screen-md-max) { @content } + @include media-breakpoint-only(md) { @content } } @mixin media-lg() { - @media (min-width: $screen-lg-min) { @content } + @include media-breakpoint-min(lg) { @content } } diff --git a/scss/mixins/_pulls.scss b/scss/mixins/_pulls.scss new file mode 100644 index 0000000000000000000000000000000000000000..6bdff025d43cf858086b0eefb99f8febce118c8e --- /dev/null +++ b/scss/mixins/_pulls.scss @@ -0,0 +1,6 @@ +@mixin pull-left { + float: left !important; +} +@mixin pull-right { + float: right !important; +} diff --git a/test-infra/S3Cachefile.json b/test-infra/S3Cachefile.json index 04d809246774818776aac7687b3e2435574d9d62..90eae796dc7edc75d6ad20b67709b8c3d7b4d020 100644 --- a/test-infra/S3Cachefile.json +++ b/test-infra/S3Cachefile.json @@ -5,8 +5,8 @@ "generate": "./uncached-npm-install.sh" }, "rubygems": { - "key": "../pseudo_Gemfile.lock", - "cache": "$GEMDIR", - "generate": "gem install -N scss-lint -v $SCSS_LINT_VERSION && gem install -N jekyll -v $JEKYLL_VERSION && gem install -N rouge -v $ROUGE_VERSION" + "key": "$BUNDLE_GEMFILE", + "cache": "../vendor/cache", + "generate": "cd .. ; bundle install --path=\"`pwd`/vendor/cache\"" } } diff --git a/test-infra/gemfiles/core.gemfile b/test-infra/gemfiles/core.gemfile new file mode 100644 index 0000000000000000000000000000000000000000..6a837269193ac9be705cafe9f383523dc991cb36 --- /dev/null +++ b/test-infra/gemfiles/core.gemfile @@ -0,0 +1,7 @@ +# Ruby Gems for the 'core' set of tests +# Run `grunt update-gemfile-lock` to update to the latest compatible versions + +source 'https://rubygems.org' + +gem 'sass', '~> 3.4.9' +gem 'scss-lint', '~> 0.31' diff --git a/test-infra/gemfiles/core.gemfile.lock b/test-infra/gemfiles/core.gemfile.lock new file mode 100644 index 0000000000000000000000000000000000000000..03580d83bb17bd933efabcdabad6341dd24cfda4 --- /dev/null +++ b/test-infra/gemfiles/core.gemfile.lock @@ -0,0 +1,15 @@ +GEM + remote: https://rubygems.org/ + specs: + rainbow (2.0.0) + sass (3.4.9) + scss-lint (0.31.0) + rainbow (~> 2.0) + sass (~> 3.4.1) + +PLATFORMS + ruby + +DEPENDENCIES + sass (~> 3.4.9) + scss-lint (~> 0.31)