diff --git a/.travis.yml b/.travis.yml index 7ccf23744c..be63538028 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,10 +1,28 @@ language: node_js node_js: - 0.10 -before_script: - - gem install jekyll - - npm install -g grunt-cli +before_install: + - time sudo pip install --use-mirrors -r test-infra/requirements.txt + - rvm use 1.9.3 --fuzzy + - if [ "$TWBS_TEST" = validate-html ]; then echo "ruby=$(basename $(rvm gemdir)) jekyll=$JEKYLL_VERSION" > pseudo_Gemfile.lock; fi +install: + - time npm install -g grunt-cli + - time ./test-infra/s3_cache.py download 'node.js packages' package.json ./node_modules || time npm install + - if [ "$TWBS_TEST" = validate-html ]; then time ./test-infra/s3_cache.py download rubygems pseudo_Gemfile.lock $(rvm gemdir) || gem install -N jekyll -v $JEKYLL_VERSION; fi +after_script: + - if [ "$TWBS_TEST" = core ]; then time ./test-infra/s3_cache.py upload 'node.js packages' package.json ./node_modules; fi + - if [ "$TWBS_TEST" = validate-html ]; then time ./test-infra/s3_cache.py upload rubygems pseudo_Gemfile.lock $(rvm gemdir); fi env: global: - - SAUCE_USERNAME: bootstrap - - secure: "pJkBwnuae9dKU5tEcCqccfS1QQw7/meEcfz63fM7ba7QJNjoA6BaXj08L5Z3Vb5vBmVPwBawxo5Hp0jC0r/Z/O0hGnAmz/Cz09L+cy7dSAZ9x4hvZePSja/UAusaB5ogMoO8l2b773MzgQeSmrLbExr9BWLeqEfjC2hFgdgHLaQ=" + - JEKYLL_VERSION: 1.4.1 + - SAUCE_USERNAME: bootstrap + - secure: "pJkBwnuae9dKU5tEcCqccfS1QQw7/meEcfz63fM7ba7QJNjoA6BaXj08L5Z3Vb5vBmVPwBawxo5Hp0jC0r/Z/O0hGnAmz/Cz09L+cy7dSAZ9x4hvZePSja/UAusaB5ogMoO8l2b773MzgQeSmrLbExr9BWLeqEfjC2hFgdgHLaQ=" + - secure: "gqjqISbxBJK6byFbsmr1AyP1qoWH+rap06A2gI7v72+Tn2PU2nYkIMUkCvhZw6K889jv+LhQ/ybcBxDOXHpNCExCnSgB4dcnmYp+9oeNZb37jSP0rQ+Ib4OTLjzc3/FawE/fUq5kukZTC7porzc/k0qJNLAZRx3YLALmK1GIdUY=" + - secure: "Gghh/e3Gsbj1+4RR9Lh2aR/xJl35HWiHqlPIeSUqE9D7uDCVTAwNce/dGL3Ew7uJPfJ6Pgr70wD3zgu3stw0Zmzayax0hiDtGwcQCxVIER08wqGANK9C2Q7PYJkNTNtiTo6ehKWbdV4Z+/U+TEYyQfpQTDbAFYk/vVpsdjp0Lmc=" + - secure: "RTbRdx4G/2OTLfrZtP1VbRljxEmd6A1F3GqXboeQTldsnAlwpsES65es5CE3ub/rmixLApOY9ot7OPmNixFgC2Y8xOsV7lNCC62QVpmqQEDyGFFQKb3yO6/dmwQxdsCqGfzf9Np6Wh5V22QFvr50ZLKLd7Uhd9oXMDIk/z1MJ3o=" + matrix: + - TWBS_TEST=core + - TWBS_TEST=validate-html + - TWBS_TEST=sauce-js-unit +matrix: + fast_finish: true diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 708ace7ec9..21062d9f1b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -37,12 +37,15 @@ We only accept issues that are bug reports or feature requests. Bugs must be iso ### CSS -- Adhere to the [RECESS CSS property order](http://markdotto.com/2011/11/29/css-property-order/) +- Adhere to the [CSS property order](http://markdotto.com/2011/11/29/css-property-order/) - Multiple-line approach (one property and value per line) - Always a space after a property's colon (e.g., `display: block;` and not `display:block;`) - End all lines with a semi-colon - For multiple, comma-separated selectors, place each selector on its own line - Attribute selectors, like `input[type="text"]` should always wrap the attribute's value in double quotes, for consistency and safety (see this [blog post on unquoted attribute values](http://mathiasbynens.be/notes/unquoted-attribute-values) that can lead to XSS attacks). +- Attribute selectors should only be used where absolutely necessary (e.g., form controls) and should be avoided on custom components for performance and explicitness. +- Series of classes for a component should include a base class (e.g., `.component`) and use the base class as a prefix for modifier and sub-components (e.g., `.component-lg`). +- Avoid inheritance and over nesting—use single, explicit classes whenever possible. ### JS diff --git a/Gruntfile.js b/Gruntfile.js index efe5918fb1..ab4b56cd26 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -6,7 +6,9 @@ module.exports = function (grunt) { // Force use of Unix newlines grunt.util.linefeed = '\n'; - RegExp.quote = require('regexp-quote') + RegExp.quote = function (string) { + return string.replace(/[-\\^$*+?.()|[\]{}]/g, '\\$&') + } var btoa = require('btoa') // Project configuration. grunt.initConfig({ @@ -113,6 +115,7 @@ module.exports = function (grunt) { less: { compileCore: { options: { + strictMath: true, sourceMap: true, outputSourceFiles: true, sourceMapURL: '<%= pkg.name %>.css.map', @@ -124,6 +127,7 @@ module.exports = function (grunt) { }, compileTheme: { options: { + strictMath: true, sourceMap: true, outputSourceFiles: true, sourceMapURL: '<%= pkg.name %>-theme.css.map', @@ -204,6 +208,9 @@ module.exports = function (grunt) { validation: { options: { + charset: 'utf-8', + doctype: 'HTML5', + failHard: true, reset: true, relaxerror: [ 'Bad value X-UA-Compatible for attribute http-equiv on element meta.', @@ -247,90 +254,7 @@ module.exports = function (grunt) { build: process.env.TRAVIS_JOB_ID, concurrency: 3, urls: ['http://127.0.0.1:3000/js/tests/index.html'], - browsers: [ - // See https://saucelabs.com/docs/platforms/webdriver - { - browserName: 'safari', - version: '6', - platform: 'OS X 10.8' - }, - { - browserName: 'chrome', - version: '28', - platform: 'OS X 10.6' - }, - /* FIXME: currently fails 1 tooltip test - { - browserName: 'firefox', - version: '25', - platform: 'OS X 10.6' - },*/ - // Mac Opera not currently supported by Sauce Labs - /* FIXME: currently fails 1 tooltip test - { - browserName: 'internet explorer', - version: '11', - platform: 'Windows 8.1' - },*/ - /* - { - browserName: 'internet explorer', - version: '10', - platform: 'Windows 8' - }, - { - browserName: 'internet explorer', - version: '9', - platform: 'Windows 7' - }, - { - browserName: 'internet explorer', - version: '8', - platform: 'Windows 7' - }, - {// unofficial - browserName: 'internet explorer', - version: '7', - platform: 'Windows XP' - }, - */ - { - browserName: 'chrome', - version: '31', - platform: 'Windows 8.1' - }, - { - browserName: 'firefox', - version: '25', - platform: 'Windows 8.1' - }, - // Win Opera 15+ not currently supported by Sauce Labs - { - browserName: 'iphone', - version: '6.1', - platform: 'OS X 10.8' - }, - // iOS Chrome not currently supported by Sauce Labs - // Linux (unofficial) - { - browserName: 'chrome', - version: '30', - platform: 'Linux' - }, - { - browserName: 'firefox', - version: '25', - platform: 'Linux' - } - // Android Chrome not currently supported by Sauce Labs - /* Android Browser (super-unofficial) - { - browserName: 'android', - version: '4.0', - platform: 'Linux' - } - */ - ], + browsers: grunt.file.readYAML('sauce_browsers.yml') } } } @@ -338,31 +262,25 @@ module.exports = function (grunt) { // These plugins provide necessary tasks. - grunt.loadNpmTasks('grunt-banner'); - grunt.loadNpmTasks('grunt-contrib-clean'); - grunt.loadNpmTasks('grunt-contrib-concat'); - grunt.loadNpmTasks('grunt-contrib-connect'); - grunt.loadNpmTasks('grunt-contrib-copy'); - grunt.loadNpmTasks('grunt-contrib-csslint'); - grunt.loadNpmTasks('grunt-contrib-jshint'); - grunt.loadNpmTasks('grunt-contrib-less'); - grunt.loadNpmTasks('grunt-contrib-qunit'); - grunt.loadNpmTasks('grunt-contrib-uglify'); - grunt.loadNpmTasks('grunt-contrib-watch'); - grunt.loadNpmTasks('grunt-csscomb'); - grunt.loadNpmTasks('grunt-html-validation'); - grunt.loadNpmTasks('grunt-jekyll'); - grunt.loadNpmTasks('grunt-jscs-checker'); - grunt.loadNpmTasks('grunt-saucelabs'); - grunt.loadNpmTasks('grunt-sed'); + require('load-grunt-tasks')(grunt, {scope: 'devDependencies'}); // Docs HTML validation task grunt.registerTask('validate-html', ['jekyll', 'validation']); // Test task. - var testSubtasks = ['dist-css', 'jshint', 'jscs', 'qunit', 'validate-html']; + var testSubtasks = []; + // Skip core tests if running a different subset of the test suite + if (!process.env.TWBS_TEST || process.env.TWBS_TEST === 'core') { + testSubtasks = testSubtasks.concat(['dist-css', 'jshint', 'jscs', 'qunit']); + } + // Skip HTML validation if running a different subset of the test suite + if (!process.env.TWBS_TEST || process.env.TWBS_TEST === 'validate-html') { + testSubtasks.push('validate-html'); + } // Only run Sauce Labs tests if there's a Sauce access key - if (typeof process.env.SAUCE_ACCESS_KEY !== 'undefined') { + if (typeof process.env.SAUCE_ACCESS_KEY !== 'undefined' + // Skip Sauce if running a different subset of the test suite + && (!process.env.TWBS_TEST || process.env.TWBS_TEST === 'sauce-js-unit')) { testSubtasks.push('connect'); testSubtasks.push('saucelabs-qunit'); } diff --git a/README.md b/README.md index 8bfcc7e55e..7d342d7a70 100644 --- a/README.md +++ b/README.md @@ -57,8 +57,9 @@ Bootstrap's documentation, included in this repo in the root directory, is built ### Running documentation locally 1. If necessary, [install Jekyll](http://jekyllrb.com/docs/installation) (requires v1.x). + - **Windows users:** read [this unofficial guide](https://github.com/juthilo/run-jekyll-on-windows/) to get Jekyll up and running without problems. 2. From the root `/bootstrap` directory, run `jekyll serve` in the command line. - - **Windows users:** run `chcp 65001` first to change the command prompt's character encoding ([code page](http://en.wikipedia.org/wiki/Windows_code_page)) to UTF-8 so Jekyll runs without errors. + - **Windows users:** For Ruby 2.0.0 run `chcp 65001` first to change the command prompt's character encoding ([code page](http://en.wikipedia.org/wiki/Windows_code_page)) to UTF-8 so Jekyll runs without errors. For Ruby 1.9.3 you can alternatively do `SET LANG=en_EN.UTF-8`. In addition, ensure you have Python installed and added in your `PATH` or the build will fail due to our Pygments dependency. 3. Open in your browser, and voilà. Learn more about using Jekyll by reading its [documentation](http://jekyllrb.com/docs/home/). diff --git a/_includes/nav-css.html b/_includes/nav-css.html index 0228932dd3..55d46d8b59 100644 --- a/_includes/nav-css.html +++ b/_includes/nav-css.html @@ -66,7 +66,9 @@
  • Horizontal form
  • Supported controls
  • Static control
  • -
  • Control states
  • +
  • Focus state
  • +
  • Disabled state
  • +
  • Validation states
  • Control sizing
  • Help text
  • @@ -87,6 +89,8 @@
  • Helper classes
  • +
  • + Using LESS + +
  • diff --git a/_includes/nav-getting-started.html b/_includes/nav-getting-started.html index ce7a718d66..96e175dd2d 100644 --- a/_includes/nav-getting-started.html +++ b/_includes/nav-getting-started.html @@ -32,7 +32,19 @@
  • - Browser support + Browser and device support +
  • Third party support diff --git a/_includes/nav-javascript.html b/_includes/nav-javascript.html index e97027096c..aeeafe2641 100644 --- a/_includes/nav-javascript.html +++ b/_includes/nav-javascript.html @@ -13,6 +13,7 @@ Modal
  • diff --git a/bower.json b/bower.json index 313ff697f2..f1680ac615 100644 --- a/bower.json +++ b/bower.json @@ -14,7 +14,6 @@ "_*", "docs-assets", "examples", - "/fonts", "js/tests", "CNAME", "CONTRIBUTING.md", diff --git a/components.html b/components.html index 8377b81238..cdea79edce 100644 --- a/components.html +++ b/components.html @@ -902,9 +902,13 @@ base_url: "../" {% endhighlight %} -

    Add .pull-right to a .dropdown-menu to right align the dropdown menu.

    +

    Add .dropdown-menu-right to a .dropdown-menu to right align the dropdown menu.

    +
    +

    Deprecated .pull-right alignment

    +

    As of v3.1, we've deprecated .pull-right on dropdown menus. To right-align a menu, use .dropdown-menu-right. Right-aligned nav components in the navbar use a mixin version of this class to automatically align the menu. To override it, use .dropdown-menu-left.

    +
    {% highlight html %} -