modified .gitignore

This commit is contained in:
TLRZ Seyfferth
2017-09-13 10:20:31 +02:00
parent e1db4792aa
commit cf899d0675
411 changed files with 23733 additions and 67956 deletions
-5
View File
@@ -1,5 +0,0 @@
Bootstrap uses [GitHub's Releases feature](https://github.com/blog/1547-release-your-software) for its changelogs.
See [the Releases section of our GitHub project](https://github.com/twbs/bootstrap/releases) for changelogs for each release version of Bootstrap.
Release announcement posts on [the official Bootstrap blog](https://blog.getbootstrap.com) contain summaries of the most noteworthy changes made in each release.
+3 -329
View File
@@ -9,194 +9,8 @@
module.exports = function (grunt) {
'use strict'
// Force use of Unix newlines
grunt.util.linefeed = '\n'
RegExp.quote = function (string) {
return string.replace(/[-\\^$*+?.()|[\]{}]/g, '\\$&')
}
var path = require('path')
var isTravis = require('is-travis')
var configBridge = grunt.file.readJSON('./grunt/configBridge.json', { encoding: 'utf8' })
Object.keys(configBridge.paths).forEach(function (key) {
configBridge.paths[key].forEach(function (val, i, arr) {
arr[i] = path.join('./docs', val)
})
})
// Project configuration.
grunt.initConfig({
// Metadata.
pkg: grunt.file.readJSON('package.json'),
banner: '/*!\n' +
' * Bootstrap v<%= pkg.version %> (<%= pkg.homepage %>)\n' +
' * Copyright 2011-<%= grunt.template.today("yyyy") %> <%= pkg.author %>\n' +
' * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n' +
' */\n',
jqueryCheck: 'if (typeof jQuery === \'undefined\') {\n' +
' throw new Error(\'Bootstrap\\\'s JavaScript requires jQuery. jQuery must be included before Bootstrap\\\'s JavaScript.\')\n' +
'}\n',
jqueryVersionCheck: '+function ($) {\n' +
' var version = $.fn.jquery.split(\' \')[0].split(\'.\')\n' +
' if ((version[0] < 2 && version[1] < 9) || (version[0] == 1 && version[1] == 9 && version[2] < 1) || (version[0] >= 4)) {\n' +
' throw new Error(\'Bootstrap\\\'s JavaScript requires at least jQuery v1.9.1 but less than v4.0.0\')\n' +
' }\n' +
'}(jQuery);\n\n',
// Task configuration.
clean: {
dist: 'dist',
docs: 'docs/dist'
},
// JS build configuration
babel: {
dev: {
options: {
sourceMap: true
},
files: {
'js/dist/util.js' : 'js/src/util.js',
'js/dist/alert.js' : 'js/src/alert.js',
'js/dist/button.js' : 'js/src/button.js',
'js/dist/carousel.js' : 'js/src/carousel.js',
'js/dist/collapse.js' : 'js/src/collapse.js',
'js/dist/dropdown.js' : 'js/src/dropdown.js',
'js/dist/modal.js' : 'js/src/modal.js',
'js/dist/scrollspy.js' : 'js/src/scrollspy.js',
'js/dist/tab.js' : 'js/src/tab.js',
'js/dist/tooltip.js' : 'js/src/tooltip.js',
'js/dist/popover.js' : 'js/src/popover.js'
}
},
dist: {
options: {
extends: '../../js/.babelrc'
},
files: {
'<%= concat.bootstrap.dest %>' : '<%= concat.bootstrap.dest %>'
}
}
},
stamp: {
options: {
banner: '<%= banner %>\n<%= jqueryCheck %>\n<%= jqueryVersionCheck %>\n+function () {\n',
footer: '\n}();'
},
bootstrap: {
files: {
src: '<%= concat.bootstrap.dest %>'
}
}
},
concat: {
options: {
// Custom function to remove all export and import statements
process: function (src) {
return src.replace(/^(export|import).*/gm, '')
}
},
bootstrap: {
src: [
'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'
],
dest: 'dist/js/<%= pkg.name %>.js'
}
},
qunit: {
options: {
inject: 'js/tests/unit/phantom.js'
},
files: 'js/tests/index.html'
},
// CSS build configuration
copy: {
docs: {
expand: true,
cwd: 'dist/',
src: [
'**/*'
],
dest: 'docs/dist/'
}
},
connect: {
server: {
options: {
port: 3000,
base: '.'
}
}
},
jekyll: {
options: {
bundleExec: true,
config: '_config.yml',
incremental: false
},
docs: {},
github: {
options: {
raw: 'github: true'
}
}
},
htmllint: {
options: {
ignore: [
'Attribute “autocomplete” is only allowed when the input type is “color”, “date”, “datetime”, “datetime-local”, “email”, “hidden”, “month”, “number”, “password”, “range”, “search”, “tel”, “text”, “time”, “url”, or “week”.',
'Attribute “autocomplete” not allowed on element “button” at this point.',
'Consider using the “h1” element as a top-level heading only (all “h1” elements are treated as top-level headings by many screen readers and other tools).',
'Element “div” not allowed as child of element “progress” in this context. (Suppressing further errors from this subtree.)',
'Element “img” is missing required attribute “src”.',
'The “color” input type is not supported in all browsers. Please be sure to test, and consider using a polyfill.',
'The “date” input type is not supported in all browsers. Please be sure to test, and consider using a polyfill.',
'The “datetime” input type is not supported in all browsers. Please be sure to test, and consider using a polyfill.',
'The “datetime-local” input type is not supported in all browsers. Please be sure to test, and consider using a polyfill.',
'The “month” input type is not supported in all browsers. Please be sure to test, and consider using a polyfill.',
'The “time” input type is not supported in all browsers. Please be sure to test, and consider using a polyfill.',
'The “week” input type is not supported in all browsers. Please be sure to test, and consider using a polyfill.'
]
},
src: ['_gh_pages/**/*.html', 'js/tests/visual/*.html']
},
watch: {
src: {
files: '<%= concat.bootstrap.src %>',
tasks: ['babel:dev']
},
sass: {
files: 'scss/**/*.scss',
tasks: ['dist-css', 'docs']
},
docs: {
files: 'docs/assets/scss/**/*.scss',
tasks: ['dist-css', 'docs']
}
},
'saucelabs-qunit': {
all: {
options: {
@@ -204,152 +18,12 @@ module.exports = function (grunt) {
concurrency: 10,
maxRetries: 3,
maxPollRetries: 4,
urls: ['http://127.0.0.1:3000/js/tests/index.html?hidepassed'],
browsers: grunt.file.readYAML('grunt/sauce_browsers.yml')
urls: ['http://localhost:3000/js/tests/index.html?hidepassed'],
browsers: grunt.file.readYAML('build/sauce_browsers.yml')
}
}
},
exec: {
'clean-css': {
command: 'npm run clean-css'
},
'clean-css-docs': {
command: 'npm run clean-css-docs'
},
postcss: {
command: 'npm run postcss'
},
'postcss-docs': {
command: 'npm run postcss-docs'
},
htmlhint: {
command: 'npm run htmlhint'
},
sass: {
command: 'npm run sass'
},
'sass-docs': {
command: 'npm run sass-docs'
},
'scss-lint': {
command: 'npm run scss-lint'
},
'scss-lint-docs': {
command: 'npm run scss-lint-docs'
},
uglify: {
command: 'npm run uglify'
},
'uglify-docs': {
command: 'npm run uglify-docs'
}
},
buildcontrol: {
options: {
dir: '_gh_pages',
commit: true,
push: true,
message: 'Built %sourceName% from commit %sourceCommit% on branch %sourceBranch%'
},
pages: {
options: {
remote: 'git@github.com:twbs/derpstrap.git',
branch: 'gh-pages'
}
}
},
compress: {
main: {
options: {
archive: 'bootstrap-<%= pkg.version %>-dist.zip',
mode: 'zip',
level: 9,
pretty: true
},
files: [
{
expand: true,
cwd: 'dist/',
src: ['**'],
dest: 'bootstrap-<%= pkg.version %>-dist'
}
]
}
}
})
// These plugins provide necessary tasks.
require('load-grunt-tasks')(grunt)
require('time-grunt')(grunt)
// Docs HTML validation task
grunt.registerTask('validate-html', ['jekyll:docs', 'htmllint', 'exec:htmlhint'])
var runSubset = function (subset) {
return !process.env.TWBS_TEST || process.env.TWBS_TEST === subset
}
var isUndefOrNonZero = function (val) {
return val === undefined || val !== '0'
}
// Test task.
var testSubtasks = []
// 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', 'qunit', 'docs'])
}
// Skip HTML validation if running a different subset of the test suite
if (runSubset('validate-html') &&
isTravis &&
// Skip HTML5 validator when [skip validator] is in the commit message
isUndefOrNonZero(process.env.TWBS_DO_VALIDATOR)) {
testSubtasks.push('validate-html')
}
// Only run Sauce Labs tests if there's a Sauce access key
if (typeof process.env.SAUCE_ACCESS_KEY !== 'undefined' &&
// Skip Sauce if running a different subset of the test suite
runSubset('sauce-js-unit')) {
testSubtasks = testSubtasks.concat(['dist', 'docs-css', 'docs-js', 'clean:docs', 'copy:docs'])
// Skip Sauce on Travis when [skip sauce] is in the commit message
if (isUndefOrNonZero(process.env.TWBS_DO_SAUCE)) {
testSubtasks.push('connect')
testSubtasks.push('saucelabs-qunit')
}
}
grunt.registerTask('test', testSubtasks)
// JS distribution task.
grunt.registerTask('dist-js', ['babel:dev', 'concat', 'babel:dist', 'stamp', 'exec:uglify'])
grunt.registerTask('test-scss', ['exec:scss-lint'])
// CSS distribution task.
grunt.registerTask('sass-compile', ['exec:sass', 'exec:sass-docs'])
grunt.registerTask('dist-css', ['sass-compile', 'exec:postcss', 'exec:clean-css', 'exec:clean-css-docs'])
// Full distribution task.
grunt.registerTask('dist', ['clean:dist', 'dist-css', 'dist-js'])
// Default task.
grunt.registerTask('default', ['clean:dist', 'test'])
// Docs task.
grunt.registerTask('docs-css', ['exec:clean-css-docs', 'exec:postcss-docs'])
grunt.registerTask('lint-docs-css', ['exec:scss-lint-docs'])
grunt.registerTask('docs-js', ['exec:uglify-docs'])
grunt.registerTask('docs', ['lint-docs-css', 'docs-css', 'docs-js', 'clean:docs', 'copy:docs'])
grunt.registerTask('docs-github', ['jekyll:github'])
grunt.registerTask('prep-release', ['dist', 'docs', 'docs-github', 'compress'])
// Publish to GitHub
grunt.registerTask('publish', ['buildcontrol:pages'])
grunt.loadNpmTasks('grunt-saucelabs')
}
+47 -23
View File
@@ -1,24 +1,31 @@
# [Bootstrap](https://getbootstrap.com)
<p align="center">
<a href="https://v4-alpha.getbootstrap.com">
<img src="http://v4-alpha.getbootstrap.com/assets/brand/bootstrap-solid.svg" width=72 height=72>
</a>
[![Slack](https://bootstrap-slack.herokuapp.com/badge.svg)](https://bootstrap-slack.herokuapp.com)
![Bower version](https://img.shields.io/bower/v/bootstrap.svg)
[![npm version](https://img.shields.io/npm/v/bootstrap.svg)](https://www.npmjs.com/package/bootstrap)
[![Gem version](https://img.shields.io/gem/v/bootstrap.svg)](https://rubygems.org/gems/bootstrap)
[![Build Status](https://img.shields.io/travis/twbs/bootstrap/master.svg)](https://travis-ci.org/twbs/bootstrap)
[![devDependency Status](https://img.shields.io/david/dev/twbs/bootstrap.svg)](https://david-dm.org/twbs/bootstrap?type=dev)
[![Meteor Atmosphere](https://img.shields.io/badge/meteor-twbs%3Abootstrap-blue.svg)](https://atmospherejs.com/twbs/bootstrap)
[![Packagist Prerelease](https://img.shields.io/packagist/vpre/twbs/bootstrap.svg)](https://packagist.org/packages/twbs/bootstrap)
[![NuGet](https://img.shields.io/nuget/vpre/bootstrap.svg)](https://www.nuget.org/packages/bootstrap/4.0.0-alpha5)
<h3 align="center">Bootstrap</h3>
[![Selenium Test Status](https://saucelabs.com/browser-matrix/bootstrap.svg)](https://saucelabs.com/u/bootstrap)
<p align="center">
Sleek, intuitive, and powerful front-end framework for faster and easier web development.
<br>
<a href="https://v4-alpha.getbootstrap.com"><strong>Explore Bootstrap docs &raquo;</strong></a>
<br>
<br>
<a href="https://themes.getbootstrap.com">Bootstrap Themes</a>
&middot;
<a href="https://jobs.getbootstrap.com">Job Board</a>
&middot;
<a href="https://blog.getbootstrap.com">Blog</a>
</p>
</p>
Bootstrap is a sleek, intuitive, and powerful front-end framework for faster and easier web development, created by [Mark Otto](https://twitter.com/mdo) and [Jacob Thornton](https://twitter.com/fat), and maintained by the [core team](https://github.com/orgs/twbs/people) with the massive support and involvement of the community.
To get started, check out <https://getbootstrap.com>!
<br>
## Table of contents
- [Quick start](#quick-start)
- [Status](#status)
- [What's included](#whats-included)
- [Bugs and feature requests](#bugs-and-feature-requests)
- [Documentation](#documentation)
- [Contributing](#contributing)
@@ -31,17 +38,32 @@ To get started, check out <https://getbootstrap.com>!
Several quick start options are available:
- [Download the latest release.](https://github.com/twbs/bootstrap/archive/v4.0.0-alpha.6.zip)
- [Download the latest release.](https://github.com/twbs/bootstrap/archive/v4.0.0-beta.zip)
- Clone the repo: `git clone https://github.com/twbs/bootstrap.git`
- Install with [npm](https://www.npmjs.com): `npm install bootstrap@4.0.0-alpha.6`
- Install with [yarn](https://github.com/yarnpkg/yarn): `yarn add bootstrap@4.0.0-alpha.6`
- Install with [Composer](https://getcomposer.org): `composer require twbs/bootstrap:4.0.0-alpha.6`
- Install with [Bower](https://bower.io): `bower install bootstrap#v4.0.0-alpha.6`
- Install with [npm](https://www.npmjs.com): `npm install bootstrap@4.0.0-beta`
- Install with [yarn](https://github.com/yarnpkg/yarn): `yarn add bootstrap@4.0.0-beta`
- Install with [Composer](https://getcomposer.org): `composer require twbs/bootstrap:4.0.0-beta`
- Install with [Bower](https://bower.io): `bower install bootstrap#v4.0.0-beta`
- Install with [NuGet](https://www.nuget.org): CSS: `Install-Package bootstrap -Pre` Sass: `Install-Package bootstrap.sass -Pre` (`-Pre` is only required until Bootstrap v4 has a stable release).
Read the [Getting started page](https://getbootstrap.com/getting-started/) for information on the framework contents, templates and examples, and more.
### What's included
## Status
[![Slack](https://bootstrap-slack.herokuapp.com/badge.svg)](https://bootstrap-slack.herokuapp.com)
[![Bower](https://img.shields.io/bower/v/bootstrap.svg)](https://bower.io/search/?q=bootstrap)
[![npm version](https://img.shields.io/npm/v/bootstrap.svg)](https://www.npmjs.com/package/bootstrap)
[![Gem version](https://img.shields.io/gem/v/bootstrap.svg)](https://rubygems.org/gems/bootstrap)
[![Build Status](https://img.shields.io/travis/twbs/bootstrap/v4-dev.svg)](https://travis-ci.org/twbs/bootstrap)
[![dependencies Status](https://david-dm.org/twbs/bootstrap/status.svg)](https://david-dm.org/twbs/bootstrap)
[![devDependency Status](https://img.shields.io/david/dev/twbs/bootstrap.svg)](https://david-dm.org/twbs/bootstrap?type=dev)
[![Meteor Atmosphere](https://img.shields.io/badge/meteor-twbs%3Abootstrap-blue.svg)](https://atmospherejs.com/twbs/bootstrap)
[![Packagist Prerelease](https://img.shields.io/packagist/vpre/twbs/bootstrap.svg)](https://packagist.org/packages/twbs/bootstrap)
[![NuGet](https://img.shields.io/nuget/vpre/bootstrap.svg)](https://www.nuget.org/packages/bootstrap/absoluteLatest)
[![Selenium Test Status](https://saucelabs.com/browser-matrix/bootstrap.svg)](https://saucelabs.com/u/bootstrap)
## What's included
Within the download you'll find the following directories and files, logically grouping common assets and providing both compiled and minified variations. You'll see something like this:
@@ -57,7 +79,7 @@ bootstrap/
└── bootstrap.min.js
```
We provide compiled CSS and JS (`bootstrap.*`), as well as compiled and minified CSS and JS (`bootstrap.min.*`). CSS [source maps](https://developer.chrome.com/devtools/docs/css-preprocessors) (`bootstrap.*.map`) are available for use with certain browsers' developer tools.
We provide compiled CSS and JS (`bootstrap.*`), as well as compiled and minified CSS and JS (`bootstrap.min.*`). CSS [source maps](https://developers.google.com/web/tools/chrome-devtools/debug/readability/source-maps) (`bootstrap.*.map`) are available for use with certain browsers' developer tools.
## Bugs and feature requests
@@ -69,10 +91,12 @@ Have a bug or a feature request? Please first read the [issue guidelines](https:
Bootstrap's documentation, included in this repo in the root directory, is built with [Jekyll](https://jekyllrb.com) and publicly hosted on GitHub Pages at <https://getbootstrap.com>. The docs may also be run locally.
Documentation search is powered by [Algolia's DocSearch](https://community.algolia.com/docsearch/). Working on our search? Be sure to set `debug: true` in the `_scripts.html` include.
### Running documentation locally
1. Run through the [tooling setup](https://github.com/twbs/bootstrap/blob/v4-dev/docs/getting-started/build-tools.md#tooling-setup) to install Jekyll (the site builder) and other Ruby dependencies with `bundle install`.
2. Run `grunt` (or a specific set of Grunt tasks) to rebuild distributed CSS and JavaScript files, as well as our docs assets.
1. Run through the [tooling setup](https://github.com/twbs/bootstrap/blob/v4-dev/docs/4.0/getting-started/build-tools.md#tooling-setup) to install Jekyll (the site builder) and other Ruby dependencies with `bundle install`.
2. Run `npm run test` (or a specific NPM script) to rebuild distributed CSS and JavaScript files, as well as our docs assets.
3. From the root `/bootstrap` directory, run `bundle exec jekyll serve` in the command line.
4. Open <http://localhost:9001> in your browser, and voilà.
+949 -935
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+134 -263
View File
@@ -1,274 +1,34 @@
/*! normalize.css v5.0.0 | MIT License | github.com/necolas/normalize.css */
html {
box-sizing: border-box;
font-family: sans-serif;
line-height: 1.15;
-ms-text-size-adjust: 100%;
-webkit-text-size-adjust: 100%;
}
body {
margin: 0;
}
article,
aside,
footer,
header,
nav,
section {
display: block;
}
h1 {
font-size: 2em;
margin: 0.67em 0;
}
figcaption,
figure,
main {
display: block;
}
figure {
margin: 1em 40px;
}
hr {
-webkit-box-sizing: content-box;
box-sizing: content-box;
height: 0;
overflow: visible;
}
pre {
font-family: monospace, monospace;
font-size: 1em;
}
a {
background-color: transparent;
-webkit-text-decoration-skip: objects;
}
a:active,
a:hover {
outline-width: 0;
}
abbr[title] {
border-bottom: none;
text-decoration: underline;
text-decoration: underline dotted;
}
b,
strong {
font-weight: inherit;
}
b,
strong {
font-weight: bolder;
}
code,
kbd,
samp {
font-family: monospace, monospace;
font-size: 1em;
}
dfn {
font-style: italic;
}
mark {
background-color: #ff0;
color: #000;
}
small {
font-size: 80%;
}
sub,
sup {
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: baseline;
}
sub {
bottom: -0.25em;
}
sup {
top: -0.5em;
}
audio,
video {
display: inline-block;
}
audio:not([controls]) {
display: none;
height: 0;
}
img {
border-style: none;
}
svg:not(:root) {
overflow: hidden;
}
button,
input,
optgroup,
select,
textarea {
font-family: sans-serif;
font-size: 100%;
line-height: 1.15;
margin: 0;
}
button,
input {
overflow: visible;
}
button,
select {
text-transform: none;
}
button,
html [type="button"],
[type="reset"],
[type="submit"] {
-webkit-appearance: button;
}
button::-moz-focus-inner,
[type="button"]::-moz-focus-inner,
[type="reset"]::-moz-focus-inner,
[type="submit"]::-moz-focus-inner {
border-style: none;
padding: 0;
}
button:-moz-focusring,
[type="button"]:-moz-focusring,
[type="reset"]:-moz-focusring,
[type="submit"]:-moz-focusring {
outline: 1px dotted ButtonText;
}
fieldset {
border: 1px solid #c0c0c0;
margin: 0 2px;
padding: 0.35em 0.625em 0.75em;
}
legend {
-webkit-box-sizing: border-box;
box-sizing: border-box;
color: inherit;
display: table;
max-width: 100%;
padding: 0;
white-space: normal;
}
progress {
display: inline-block;
vertical-align: baseline;
}
textarea {
overflow: auto;
}
[type="checkbox"],
[type="radio"] {
-webkit-box-sizing: border-box;
box-sizing: border-box;
padding: 0;
}
[type="number"]::-webkit-inner-spin-button,
[type="number"]::-webkit-outer-spin-button {
height: auto;
}
[type="search"] {
-webkit-appearance: textfield;
outline-offset: -2px;
}
[type="search"]::-webkit-search-cancel-button,
[type="search"]::-webkit-search-decoration {
-webkit-appearance: none;
}
::-webkit-file-upload-button {
-webkit-appearance: button;
font: inherit;
}
details,
menu {
display: block;
}
summary {
display: list-item;
}
canvas {
display: inline-block;
}
template {
display: none;
}
[hidden] {
display: none;
}
html {
-webkit-box-sizing: border-box;
box-sizing: border-box;
-ms-text-size-adjust: 100%;
-ms-overflow-style: scrollbar;
-webkit-tap-highlight-color: transparent;
}
*,
*::before,
*::after {
-webkit-box-sizing: inherit;
box-sizing: inherit;
box-sizing: inherit;
}
@-ms-viewport {
width: device-width;
}
html {
-ms-overflow-style: scrollbar;
-webkit-tap-highlight-color: transparent;
article, aside, dialog, figcaption, figure, footer, header, hgroup, main, nav, section {
display: block;
}
body {
font-family: -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
font-size: 1rem;
font-weight: normal;
line-height: 1.5;
color: #292b2c;
color: #212529;
background-color: #fff;
}
@@ -276,6 +36,12 @@ body {
outline: none !important;
}
hr {
box-sizing: content-box;
height: 0;
overflow: visible;
}
h1, h2, h3, h4, h5, h6 {
margin-top: 0;
margin-bottom: .5rem;
@@ -288,7 +54,11 @@ p {
abbr[title],
abbr[data-original-title] {
text-decoration: underline;
-webkit-text-decoration: underline dotted;
text-decoration: underline dotted;
cursor: help;
border-bottom: 0;
}
address {
@@ -324,13 +94,44 @@ blockquote {
margin: 0 0 1rem;
}
a {
color: #0275d8;
text-decoration: none;
dfn {
font-style: italic;
}
a:focus, a:hover {
color: #014c8c;
b,
strong {
font-weight: bolder;
}
small {
font-size: 80%;
}
sub,
sup {
position: relative;
font-size: 75%;
line-height: 0;
vertical-align: baseline;
}
sub {
bottom: -.25em;
}
sup {
top: -.5em;
}
a {
color: #007bff;
text-decoration: none;
background-color: transparent;
-webkit-text-decoration-skip: objects;
}
a:hover {
color: #0056b3;
text-decoration: underline;
}
@@ -348,6 +149,14 @@ a:not([href]):not([tabindex]):focus {
outline: 0;
}
pre,
code,
kbd,
samp {
font-family: monospace, monospace;
font-size: 1em;
}
pre {
margin-top: 0;
margin-bottom: 1rem;
@@ -360,10 +169,11 @@ figure {
img {
vertical-align: middle;
border-style: none;
}
[role="button"] {
cursor: pointer;
svg:not(:root) {
overflow: hidden;
}
a,
@@ -381,13 +191,12 @@ textarea {
table {
border-collapse: collapse;
background-color: transparent;
}
caption {
padding-top: 0.75rem;
padding-bottom: 0.75rem;
color: #636c72;
color: #868e96;
text-align: left;
caption-side: bottom;
}
@@ -409,13 +218,43 @@ button:focus {
input,
button,
select,
optgroup,
textarea {
margin: 0;
font-family: inherit;
font-size: inherit;
line-height: inherit;
}
input[type="radio"]:disabled,
input[type="checkbox"]:disabled {
cursor: not-allowed;
button,
input {
overflow: visible;
}
button,
select {
text-transform: none;
}
button,
html [type="button"],
[type="reset"],
[type="submit"] {
-webkit-appearance: button;
}
button::-moz-focus-inner,
[type="button"]::-moz-focus-inner,
[type="reset"]::-moz-focus-inner,
[type="submit"]::-moz-focus-inner {
padding: 0;
border-style: none;
}
input[type="radio"],
input[type="checkbox"] {
box-sizing: border-box;
padding: 0;
}
input[type="date"],
@@ -426,6 +265,7 @@ input[type="month"] {
}
textarea {
overflow: auto;
resize: vertical;
}
@@ -439,20 +279,51 @@ fieldset {
legend {
display: block;
width: 100%;
max-width: 100%;
padding: 0;
margin-bottom: .5rem;
font-size: 1.5rem;
line-height: inherit;
color: inherit;
white-space: normal;
}
input[type="search"] {
progress {
vertical-align: baseline;
}
[type="number"]::-webkit-inner-spin-button,
[type="number"]::-webkit-outer-spin-button {
height: auto;
}
[type="search"] {
outline-offset: -2px;
-webkit-appearance: none;
}
[type="search"]::-webkit-search-cancel-button,
[type="search"]::-webkit-search-decoration {
-webkit-appearance: none;
}
::-webkit-file-upload-button {
font: inherit;
-webkit-appearance: button;
}
output {
display: inline-block;
}
summary {
display: list-item;
}
template {
display: none;
}
[hidden] {
display: none !important;
}
File diff suppressed because one or more lines are too long
+2 -1
View File
@@ -1 +1,2 @@
/*! normalize.css v5.0.0 | MIT License | github.com/necolas/normalize.css */html{font-family:sans-serif;line-height:1.15;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,footer,header,nav,section{display:block}h1{font-size:2em;margin:.67em 0}figcaption,figure,main{display:block}figure{margin:1em 40px}hr{-webkit-box-sizing:content-box;box-sizing:content-box;height:0;overflow:visible}pre{font-family:monospace,monospace;font-size:1em}a{background-color:transparent;-webkit-text-decoration-skip:objects}a:active,a:hover{outline-width:0}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:inherit}b,strong{font-weight:bolder}code,kbd,samp{font-family:monospace,monospace;font-size:1em}dfn{font-style:italic}mark{background-color:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}audio,video{display:inline-block}audio:not([controls]){display:none;height:0}img{border-style:none}svg:not(:root){overflow:hidden}button,input,optgroup,select,textarea{font-family:sans-serif;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{-webkit-box-sizing:border-box;box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{display:inline-block;vertical-align:baseline}textarea{overflow:auto}[type=checkbox],[type=radio]{-webkit-box-sizing:border-box;box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}details,menu{display:block}summary{display:list-item}canvas{display:inline-block}template{display:none}[hidden]{display:none}html{-webkit-box-sizing:border-box;box-sizing:border-box}*,::after,::before{-webkit-box-sizing:inherit;box-sizing:inherit}@-ms-viewport{width:device-width}html{-ms-overflow-style:scrollbar;-webkit-tap-highlight-color:transparent}body{font-family:-apple-system,system-ui,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;font-size:1rem;font-weight:400;line-height:1.5;color:#292b2c;background-color:#fff}[tabindex="-1"]:focus{outline:0!important}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem}p{margin-top:0;margin-bottom:1rem}abbr[data-original-title],abbr[title]{cursor:help}address{margin-bottom:1rem;font-style:normal;line-height:inherit}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}a{color:#0275d8;text-decoration:none}a:focus,a:hover{color:#014c8c;text-decoration:underline}a:not([href]):not([tabindex]){color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus,a:not([href]):not([tabindex]):hover{color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus{outline:0}pre{margin-top:0;margin-bottom:1rem;overflow:auto}figure{margin:0 0 1rem}img{vertical-align:middle}[role=button]{cursor:pointer}[role=button],a,area,button,input,label,select,summary,textarea{-ms-touch-action:manipulation;touch-action:manipulation}table{border-collapse:collapse;background-color:transparent}caption{padding-top:.75rem;padding-bottom:.75rem;color:#636c72;text-align:left;caption-side:bottom}th{text-align:left}label{display:inline-block;margin-bottom:.5rem}button:focus{outline:1px dotted;outline:5px auto -webkit-focus-ring-color}button,input,select,textarea{line-height:inherit}input[type=checkbox]:disabled,input[type=radio]:disabled{cursor:not-allowed}input[type=date],input[type=time],input[type=datetime-local],input[type=month]{-webkit-appearance:listbox}textarea{resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:.5rem;font-size:1.5rem;line-height:inherit}input[type=search]{-webkit-appearance:none}output{display:inline-block}[hidden]{display:none!important}/*# sourceMappingURL=bootstrap-reboot.min.css.map */
html{box-sizing:border-box;font-family:sans-serif;line-height:1.15;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;-ms-overflow-style:scrollbar;-webkit-tap-highlight-color:transparent}*,::after,::before{box-sizing:inherit}@-ms-viewport{width:device-width}article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;font-size:1rem;font-weight:400;line-height:1.5;color:#212529;background-color:#fff}[tabindex="-1"]:focus{outline:0!important}hr{box-sizing:content-box;height:0;overflow:visible}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem}p{margin-top:0;margin-bottom:1rem}abbr[data-original-title],abbr[title]{text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;border-bottom:0}address{margin-bottom:1rem;font-style:normal;line-height:inherit}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}dfn{font-style:italic}b,strong{font-weight:bolder}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#007bff;text-decoration:none;background-color:transparent;-webkit-text-decoration-skip:objects}a:hover{color:#0056b3;text-decoration:underline}a:not([href]):not([tabindex]){color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus,a:not([href]):not([tabindex]):hover{color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus{outline:0}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}pre{margin-top:0;margin-bottom:1rem;overflow:auto}figure{margin:0 0 1rem}img{vertical-align:middle;border-style:none}svg:not(:root){overflow:hidden}[role=button],a,area,button,input,label,select,summary,textarea{-ms-touch-action:manipulation;touch-action:manipulation}table{border-collapse:collapse}caption{padding-top:.75rem;padding-bottom:.75rem;color:#868e96;text-align:left;caption-side:bottom}th{text-align:left}label{display:inline-block;margin-bottom:.5rem}button:focus{outline:1px dotted;outline:5px auto -webkit-focus-ring-color}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,input{overflow:visible}button,select{text-transform:none}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{padding:0;border-style:none}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=date],input[type=datetime-local],input[type=month],input[type=time]{-webkit-appearance:listbox}textarea{overflow:auto;resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;max-width:100%;padding:0;margin-bottom:.5rem;font-size:1.5rem;line-height:inherit;color:inherit;white-space:normal}progress{vertical-align:baseline}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:none}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}summary{display:list-item}template{display:none}[hidden]{display:none!important}
/*# sourceMappingURL=bootstrap-reboot.min.css.map */
File diff suppressed because one or more lines are too long
+2419 -3554
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
File diff suppressed because one or more lines are too long
+3 -2
View File
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+667 -371
View File
File diff suppressed because it is too large Load Diff
+2 -3
View File
File diff suppressed because one or more lines are too long
-110
View File
@@ -1,110 +0,0 @@
#!/usr/bin/env node
'use strict'
/*!
* Script to update version number references in the project.
* Copyright 2017 The Bootstrap Authors
* Copyright 2017 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
*/
/* global Set */
var fs = require('fs')
var path = require('path')
var sh = require('shelljs')
sh.config.fatal = true
var sed = sh.sed
// Blame TC39... https://github.com/benjamingr/RegExp.escape/issues/37
RegExp.quote = function (string) {
return string.replace(/[-\\^$*+?.()|[\]{}]/g, '\\$&')
}
RegExp.quoteReplacement = function (string) {
return string.replace(/[$]/g, '$$')
}
var DRY_RUN = false
function walkAsync(directory, excludedDirectories, fileCallback, errback) {
if (excludedDirectories.has(path.parse(directory).base)) {
return
}
fs.readdir(directory, function (err, names) {
if (err) {
errback(err)
return
}
names.forEach(function (name) {
var filepath = path.join(directory, name)
fs.lstat(filepath, function (err, stats) {
if (err) {
process.nextTick(errback, err)
return
}
if (stats.isSymbolicLink()) {
return
}
else if (stats.isDirectory()) {
process.nextTick(walkAsync, filepath, excludedDirectories, fileCallback, errback)
}
else if (stats.isFile()) {
process.nextTick(fileCallback, filepath)
}
})
})
})
}
function replaceRecursively(directory, excludedDirectories, allowedExtensions, original, replacement) {
original = new RegExp(RegExp.quote(original), 'g')
replacement = RegExp.quoteReplacement(replacement)
var updateFile = !DRY_RUN ? function (filepath) {
if (allowedExtensions.has(path.parse(filepath).ext)) {
sed('-i', original, replacement, filepath)
}
} : function (filepath) {
if (allowedExtensions.has(path.parse(filepath).ext)) {
console.log('FILE: ' + filepath)
}
else {
console.log('EXCLUDED:' + filepath)
}
}
walkAsync(directory, excludedDirectories, updateFile, function (err) {
console.error('ERROR while traversing directory!:')
console.error(err)
process.exit(1)
})
}
function main(args) {
if (args.length !== 2) {
console.error('USAGE: change-version old_version new_version')
console.error('Got arguments:', args)
process.exit(1)
}
var oldVersion = args[0]
var newVersion = args[1]
var EXCLUDED_DIRS = new Set([
'.git',
'node_modules',
'vendor'
])
var INCLUDED_EXTENSIONS = new Set([
// This extension whitelist is how we avoid modifying binary files
'',
'.css',
'.html',
'.js',
'.json',
'.md',
'.scss',
'.txt',
'.yml'
])
replaceRecursively('.', EXCLUDED_DIRS, INCLUDED_EXTENSIONS, oldVersion, newVersion)
}
main(process.argv.slice(2))
-10
View File
@@ -1,10 +0,0 @@
{
"paths": {
"docsJs": [
"assets/js/vendor/anchor.min.js",
"assets/js/vendor/clipboard.min.js",
"assets/js/vendor/holder.min.js",
"assets/js/src/application.js"
]
}
}
BIN
View File
Binary file not shown.
-3864
View File
File diff suppressed because it is too large Load Diff
-42
View File
@@ -1,42 +0,0 @@
module.exports = {
use: [
'postcss-flexbugs-fixes',
'autoprefixer'
],
map: {
inline: false,
annotation: true,
sourcesContent: true
},
autoprefixer: {
browsers: [
//
// Official browser support policy:
// https://v4-alpha.getbootstrap.com/getting-started/browsers-devices/#supported-browsers
//
'Chrome >= 35', // Exact version number here is kinda arbitrary
// Rather than using Autoprefixer's native "Firefox ESR" version specifier string,
// we deliberately hardcode the number. This is to avoid unwittingly severely breaking the previous ESR in the event that:
// (a) we happen to ship a new Bootstrap release soon after the release of a new ESR,
// such that folks haven't yet had a reasonable amount of time to upgrade; and
// (b) the new ESR has unprefixed CSS properties/values whose absence would severely break webpages
// (e.g. `box-sizing`, as opposed to `background: linear-gradient(...)`).
// Since they've been unprefixed, Autoprefixer will stop prefixing them,
// thus causing them to not work in the previous ESR (where the prefixes were required).
'Firefox >= 38', // Current Firefox Extended Support Release (ESR); https://www.mozilla.org/en-US/firefox/organizations/faq/
// Note: Edge versions in Autoprefixer & Can I Use refer to the EdgeHTML rendering engine version,
// NOT the Edge app version shown in Edge's "About" screen.
// For example, at the time of writing, Edge 20 on an up-to-date system uses EdgeHTML 12.
// See also https://github.com/Fyrd/caniuse/issues/1928
'Edge >= 12',
'Explorer >= 10',
// Out of leniency, we prefix these 1 version further back than the official policy.
'iOS >= 8',
'Safari >= 8',
// The following remain NOT officially supported, but we're lenient and include their prefixes to avoid severely breaking in them.
'Android 2.3',
'Android >= 4',
'Opera >= 12'
]
}
}
-84
View File
@@ -1,84 +0,0 @@
[
# Docs: https://wiki.saucelabs.com/display/DOCS/Platform+Configurator
{
browserName: "safari",
platform: "OS X 10.11"
},
{
browserName: "chrome",
platform: "OS X 10.11",
version: "latest"
},
{
browserName: "firefox",
platform: "OS X 10.11",
version: "latest"
},
# Mac Opera not currently supported by Sauce Labs
{
browserName: "MicrosoftEdge",
platform: "Windows 10",
version: "latest"
},
{
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: "chrome",
platform: "Windows 10",
version: "latest"
},
{
browserName: "firefox",
platform: "Windows 10",
version: "latest"
},
# Win Opera 15+ not currently supported by Sauce Labs
{
browserName: "Safari",
deviceName: "iPhone Simulator",
platformVersion: "9.3",
platformName: "iOS"
},
# iOS Chrome not currently supported by Sauce Labs
# Linux (unofficial)
{
browserName: "chrome",
platform: "Linux",
version: "latest"
},
{
browserName: "firefox",
platform: "Linux",
version: "latest"
},
# Android
{
platform: "Linux",
browserName: "android",
deviceName: "Android Emulator",
version: "latest",
deviceType: "phone"
}
]
-28
View File
@@ -1,28 +0,0 @@
#!/bin/bash
# Upload built docs to preview.twbsapps.com
if [ "$TRAVIS_REPO_SLUG" != twbs-savage/bootstrap ]; then exit 0; fi
# Add build metadata to version
sed -i "/^current_version:/ s/\$/+pr.${TRAVIS_COMMIT}/" _config.yml
# Fix URLs since the site's root is now a subdirectory
echo "baseurl: /c/${TRAVIS_COMMIT}" >> _config.yml
bundle exec jekyll build --destination "$TRAVIS_COMMIT"
# Install gcloud & gsutil
GSUTIL_VERSION=$(gsutil version | cut -d ' ' -f 3)
if [ ! -d "${HOME}/google-cloud-sdk" ] || [ "${GSUTIL_VERSION}" != '4.19' ]; then
rm -rf "${HOME}/google-cloud-sdk" # Kill Travis' outdated non-updateable preinstalled version
echo 'Installing google-cloud-sdk...'
export CLOUDSDK_CORE_DISABLE_PROMPTS=1
time (curl -S -s https://sdk.cloud.google.com | bash &>/dev/null)
echo 'Done.'
fi
source "${HOME}/google-cloud-sdk/path.bash.inc"
openssl aes-256-cbc -K $encrypted_2b749c8e6327_key -iv $encrypted_2b749c8e6327_iv -in grunt/gcp-key.json.enc -out grunt/gcp-key.json -d
gcloud auth activate-service-account "$GCP_SERVICE_ACCOUNT" --key-file grunt/gcp-key.json &> /dev/null || (echo 'GCP login failed!'; exit 1)
echo "Uploading to http://preview.twbsapps.com/c/${TRAVIS_COMMIT} ..."
time gsutil -q -m cp -z html,css,js,svg -r "./${TRAVIS_COMMIT}" gs://preview.twbsapps.com/c/
echo 'Done.'
+10 -10
View File
@@ -4,7 +4,7 @@ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Cons
/**
* --------------------------------------------------------------------------
* Bootstrap (v4.0.0-alpha.6): alert.js
* Bootstrap (v4.0.0-beta): alert.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* --------------------------------------------------------------------------
*/
@@ -18,7 +18,7 @@ var Alert = function ($) {
*/
var NAME = 'alert';
var VERSION = '4.0.0-alpha.6';
var VERSION = '4.0.0-beta';
var DATA_KEY = 'bs.alert';
var EVENT_KEY = '.' + DATA_KEY;
var DATA_API_KEY = '.data-api';
@@ -39,14 +39,14 @@ var Alert = function ($) {
ALERT: 'alert',
FADE: 'fade',
SHOW: 'show'
/**
* ------------------------------------------------------------------------
* Class Definition
* ------------------------------------------------------------------------
*/
};
/**
* ------------------------------------------------------------------------
* Class Definition
* ------------------------------------------------------------------------
*/
var Alert = function () {
function Alert(element) {
_classCallCheck(this, Alert);
@@ -180,4 +180,4 @@ var Alert = function ($) {
return Alert;
}(jQuery);
//# sourceMappingURL=alert.js.map
//# sourceMappingURL=alert.js.map
+18 -11
View File
@@ -4,7 +4,7 @@ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Cons
/**
* --------------------------------------------------------------------------
* Bootstrap (v4.0.0-alpha.6): button.js
* Bootstrap (v4.0.0-beta): button.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* --------------------------------------------------------------------------
*/
@@ -18,7 +18,7 @@ var Button = function ($) {
*/
var NAME = 'button';
var VERSION = '4.0.0-alpha.6';
var VERSION = '4.0.0-beta';
var DATA_KEY = 'bs.button';
var EVENT_KEY = '.' + DATA_KEY;
var DATA_API_KEY = '.data-api';
@@ -41,14 +41,14 @@ var Button = function ($) {
var Event = {
CLICK_DATA_API: 'click' + EVENT_KEY + DATA_API_KEY,
FOCUS_BLUR_DATA_API: 'focus' + EVENT_KEY + DATA_API_KEY + ' ' + ('blur' + EVENT_KEY + DATA_API_KEY)
/**
* ------------------------------------------------------------------------
* Class Definition
* ------------------------------------------------------------------------
*/
};
/**
* ------------------------------------------------------------------------
* Class Definition
* ------------------------------------------------------------------------
*/
var Button = function () {
function Button(element) {
_classCallCheck(this, Button);
@@ -62,6 +62,7 @@ var Button = function ($) {
Button.prototype.toggle = function toggle() {
var triggerChangeEvent = true;
var addAriaPressed = true;
var rootElement = $(this._element).closest(Selector.DATA_TOGGLE)[0];
if (rootElement) {
@@ -81,15 +82,21 @@ var Button = function ($) {
}
if (triggerChangeEvent) {
if (input.hasAttribute('disabled') || rootElement.hasAttribute('disabled') || input.classList.contains('disabled') || rootElement.classList.contains('disabled')) {
return;
}
input.checked = !$(this._element).hasClass(ClassName.ACTIVE);
$(input).trigger('change');
}
input.focus();
addAriaPressed = false;
}
}
this._element.setAttribute('aria-pressed', !$(this._element).hasClass(ClassName.ACTIVE));
if (addAriaPressed) {
this._element.setAttribute('aria-pressed', !$(this._element).hasClass(ClassName.ACTIVE));
}
if (triggerChangeEvent) {
$(this._element).toggleClass(ClassName.ACTIVE);
@@ -164,4 +171,4 @@ var Button = function ($) {
return Button;
}(jQuery);
//# sourceMappingURL=button.js.map
//# sourceMappingURL=button.js.map
+50 -23
View File
@@ -6,7 +6,7 @@ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Cons
/**
* --------------------------------------------------------------------------
* Bootstrap (v4.0.0-alpha.6): carousel.js
* Bootstrap (v4.0.0-beta): carousel.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* --------------------------------------------------------------------------
*/
@@ -20,7 +20,7 @@ var Carousel = function ($) {
*/
var NAME = 'carousel';
var VERSION = '4.0.0-alpha.6';
var VERSION = '4.0.0-beta';
var DATA_KEY = 'bs.carousel';
var EVENT_KEY = '.' + DATA_KEY;
var DATA_API_KEY = '.data-api';
@@ -28,6 +28,7 @@ var Carousel = function ($) {
var TRANSITION_DURATION = 600;
var ARROW_LEFT_KEYCODE = 37; // KeyboardEvent.which value for left arrow key
var ARROW_RIGHT_KEYCODE = 39; // KeyboardEvent.which value for right arrow key
var TOUCHEVENT_COMPAT_WAIT = 500; // Time for mouse compat events to fire after touch
var Default = {
interval: 5000,
@@ -58,6 +59,7 @@ var Carousel = function ($) {
KEYDOWN: 'keydown' + EVENT_KEY,
MOUSEENTER: 'mouseenter' + EVENT_KEY,
MOUSELEAVE: 'mouseleave' + EVENT_KEY,
TOUCHEND: 'touchend' + EVENT_KEY,
LOAD_DATA_API: 'load' + EVENT_KEY + DATA_API_KEY,
CLICK_DATA_API: 'click' + EVENT_KEY + DATA_API_KEY
};
@@ -81,14 +83,14 @@ var Carousel = function ($) {
INDICATORS: '.carousel-indicators',
DATA_SLIDE: '[data-slide], [data-slide-to]',
DATA_RIDE: '[data-ride="carousel"]'
/**
* ------------------------------------------------------------------------
* Class Definition
* ------------------------------------------------------------------------
*/
};
/**
* ------------------------------------------------------------------------
* Class Definition
* ------------------------------------------------------------------------
*/
var Carousel = function () {
function Carousel(element, config) {
_classCallCheck(this, Carousel);
@@ -100,6 +102,8 @@ var Carousel = function ($) {
this._isPaused = false;
this._isSliding = false;
this.touchTimeout = null;
this._config = this._getConfig(config);
this._element = $(element)[0];
this._indicatorsElement = $(this._element).find(Selector.INDICATORS)[0];
@@ -112,10 +116,9 @@ var Carousel = function ($) {
// public
Carousel.prototype.next = function next() {
if (this._isSliding) {
throw new Error('Carousel is sliding');
if (!this._isSliding) {
this._slide(Direction.NEXT);
}
this._slide(Direction.NEXT);
};
Carousel.prototype.nextWhenVisible = function nextWhenVisible() {
@@ -126,10 +129,9 @@ var Carousel = function ($) {
};
Carousel.prototype.prev = function prev() {
if (this._isSliding) {
throw new Error('Carousel is sliding');
if (!this._isSliding) {
this._slide(Direction.PREV);
}
this._slide(Direction.PREVIOUS);
};
Carousel.prototype.pause = function pause(event) {
@@ -185,7 +187,7 @@ var Carousel = function ($) {
return;
}
var direction = index > activeIndex ? Direction.NEXT : Direction.PREVIOUS;
var direction = index > activeIndex ? Direction.NEXT : Direction.PREV;
this._slide(direction, this._items[index]);
};
@@ -221,12 +223,30 @@ var Carousel = function ($) {
});
}
if (this._config.pause === 'hover' && !('ontouchstart' in document.documentElement)) {
if (this._config.pause === 'hover') {
$(this._element).on(Event.MOUSEENTER, function (event) {
return _this2.pause(event);
}).on(Event.MOUSELEAVE, function (event) {
return _this2.cycle(event);
});
if ('ontouchstart' in document.documentElement) {
// if it's a touch-enabled device, mouseenter/leave are fired as
// part of the mouse compatibility events on first tap - the carousel
// would stop cycling until user tapped out of it;
// here, we listen for touchend, explicitly pause the carousel
// (as if it's the second time we tap on it, mouseenter compat event
// is NOT fired) and after a timeout (to allow for mouse compatibility
// events to fire) we explicitly restart cycling
$(this._element).on(Event.TOUCHEND, function () {
_this2.pause();
if (_this2.touchTimeout) {
clearTimeout(_this2.touchTimeout);
}
_this2.touchTimeout = setTimeout(function (event) {
return _this2.cycle(event);
}, TOUCHEVENT_COMPAT_WAIT + _this2._config.interval);
});
}
}
};
@@ -256,7 +276,7 @@ var Carousel = function ($) {
Carousel.prototype._getItemByDirection = function _getItemByDirection(direction, activeElement) {
var isNextDirection = direction === Direction.NEXT;
var isPrevDirection = direction === Direction.PREVIOUS;
var isPrevDirection = direction === Direction.PREV;
var activeIndex = this._getItemIndex(activeElement);
var lastItemIndex = this._items.length - 1;
var isGoingToWrap = isPrevDirection && activeIndex === 0 || isNextDirection && activeIndex === lastItemIndex;
@@ -265,16 +285,20 @@ var Carousel = function ($) {
return activeElement;
}
var delta = direction === Direction.PREVIOUS ? -1 : 1;
var delta = direction === Direction.PREV ? -1 : 1;
var itemIndex = (activeIndex + delta) % this._items.length;
return itemIndex === -1 ? this._items[this._items.length - 1] : this._items[itemIndex];
};
Carousel.prototype._triggerSlideEvent = function _triggerSlideEvent(relatedTarget, eventDirectionName) {
var targetIndex = this._getItemIndex(relatedTarget);
var fromIndex = this._getItemIndex($(this._element).find(Selector.ACTIVE_ITEM)[0]);
var slideEvent = $.Event(Event.SLIDE, {
relatedTarget: relatedTarget,
direction: eventDirectionName
direction: eventDirectionName,
from: fromIndex,
to: targetIndex
});
$(this._element).trigger(slideEvent);
@@ -298,8 +322,9 @@ var Carousel = function ($) {
var _this3 = this;
var activeElement = $(this._element).find(Selector.ACTIVE_ITEM)[0];
var activeElementIndex = this._getItemIndex(activeElement);
var nextElement = element || activeElement && this._getItemByDirection(direction, activeElement);
var nextElementIndex = this._getItemIndex(nextElement);
var isCycling = Boolean(this._interval);
var directionalClassName = void 0;
@@ -341,7 +366,9 @@ var Carousel = function ($) {
var slidEvent = $.Event(Event.SLID, {
relatedTarget: nextElement,
direction: eventDirectionName
direction: eventDirectionName,
from: activeElementIndex,
to: nextElementIndex
});
if (Util.supportsTransitionEnd() && $(this._element).hasClass(ClassName.SLIDE)) {
@@ -483,4 +510,4 @@ var Carousel = function ($) {
return Carousel;
}(jQuery);
//# sourceMappingURL=carousel.js.map
//# sourceMappingURL=carousel.js.map
+44 -35
View File
@@ -6,7 +6,7 @@ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Cons
/**
* --------------------------------------------------------------------------
* Bootstrap (v4.0.0-alpha.6): collapse.js
* Bootstrap (v4.0.0-beta): collapse.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* --------------------------------------------------------------------------
*/
@@ -20,7 +20,7 @@ var Collapse = function ($) {
*/
var NAME = 'collapse';
var VERSION = '4.0.0-alpha.6';
var VERSION = '4.0.0-beta';
var DATA_KEY = 'bs.collapse';
var EVENT_KEY = '.' + DATA_KEY;
var DATA_API_KEY = '.data-api';
@@ -58,16 +58,16 @@ var Collapse = function ($) {
};
var Selector = {
ACTIVES: '.card > .show, .card > .collapsing',
ACTIVES: '.show, .collapsing',
DATA_TOGGLE: '[data-toggle="collapse"]'
/**
* ------------------------------------------------------------------------
* Class Definition
* ------------------------------------------------------------------------
*/
};
/**
* ------------------------------------------------------------------------
* Class Definition
* ------------------------------------------------------------------------
*/
var Collapse = function () {
function Collapse(element, config) {
_classCallCheck(this, Collapse);
@@ -76,6 +76,14 @@ var Collapse = function ($) {
this._element = element;
this._config = this._getConfig(config);
this._triggerArray = $.makeArray($('[data-toggle="collapse"][href="#' + element.id + '"],' + ('[data-toggle="collapse"][data-target="#' + element.id + '"]')));
var tabToggles = $(Selector.DATA_TOGGLE);
for (var i = 0; i < tabToggles.length; i++) {
var elem = tabToggles[i];
var selector = Util.getSelectorFromElement(elem);
if (selector !== null && $(selector).filter(element).length > 0) {
this._triggerArray.push(elem);
}
}
this._parent = this._config.parent ? this._getParent() : null;
@@ -103,11 +111,7 @@ var Collapse = function ($) {
Collapse.prototype.show = function show() {
var _this = this;
if (this._isTransitioning) {
throw new Error('Collapse is transitioning');
}
if ($(this._element).hasClass(ClassName.SHOW)) {
if (this._isTransitioning || $(this._element).hasClass(ClassName.SHOW)) {
return;
}
@@ -115,7 +119,7 @@ var Collapse = function ($) {
var activesData = void 0;
if (this._parent) {
actives = $.makeArray($(this._parent).find(Selector.ACTIVES));
actives = $.makeArray($(this._parent).children().children(Selector.ACTIVES));
if (!actives.length) {
actives = null;
}
@@ -146,7 +150,6 @@ var Collapse = function ($) {
$(this._element).removeClass(ClassName.COLLAPSE).addClass(ClassName.COLLAPSING);
this._element.style[dimension] = 0;
this._element.setAttribute('aria-expanded', true);
if (this._triggerArray.length) {
$(this._triggerArray).removeClass(ClassName.COLLAPSED).attr('aria-expanded', true);
@@ -180,11 +183,7 @@ var Collapse = function ($) {
Collapse.prototype.hide = function hide() {
var _this2 = this;
if (this._isTransitioning) {
throw new Error('Collapse is transitioning');
}
if (!$(this._element).hasClass(ClassName.SHOW)) {
if (this._isTransitioning || !$(this._element).hasClass(ClassName.SHOW)) {
return;
}
@@ -195,18 +194,24 @@ var Collapse = function ($) {
}
var dimension = this._getDimension();
var offsetDimension = dimension === Dimension.WIDTH ? 'offsetWidth' : 'offsetHeight';
this._element.style[dimension] = this._element[offsetDimension] + 'px';
this._element.style[dimension] = this._element.getBoundingClientRect()[dimension] + 'px';
Util.reflow(this._element);
$(this._element).addClass(ClassName.COLLAPSING).removeClass(ClassName.COLLAPSE).removeClass(ClassName.SHOW);
this._element.setAttribute('aria-expanded', false);
if (this._triggerArray.length) {
$(this._triggerArray).addClass(ClassName.COLLAPSED).attr('aria-expanded', false);
for (var i = 0; i < this._triggerArray.length; i++) {
var trigger = this._triggerArray[i];
var selector = Util.getSelectorFromElement(trigger);
if (selector !== null) {
var $elem = $(selector);
if (!$elem.hasClass(ClassName.SHOW)) {
$(trigger).addClass(ClassName.COLLAPSED).attr('aria-expanded', false);
}
}
}
}
this.setTransitioning(true);
@@ -270,7 +275,6 @@ var Collapse = function ($) {
Collapse.prototype._addAriaAndCollapsedClass = function _addAriaAndCollapsedClass(element, triggerArray) {
if (element) {
var isOpen = $(element).hasClass(ClassName.SHOW);
element.setAttribute('aria-expanded', isOpen);
if (triggerArray.length) {
$(triggerArray).toggleClass(ClassName.COLLAPSED, !isOpen).attr('aria-expanded', isOpen);
@@ -331,13 +335,18 @@ var Collapse = function ($) {
*/
$(document).on(Event.CLICK_DATA_API, Selector.DATA_TOGGLE, function (event) {
event.preventDefault();
if (!/input|textarea/i.test(event.target.tagName)) {
event.preventDefault();
}
var target = Collapse._getTargetFromElement(this);
var data = $(target).data(DATA_KEY);
var config = data ? 'toggle' : $(this).data();
Collapse._jQueryInterface.call($(target), config);
var $trigger = $(this);
var selector = Util.getSelectorFromElement(this);
$(selector).each(function () {
var $target = $(this);
var data = $target.data(DATA_KEY);
var config = data ? 'toggle' : $trigger.data();
Collapse._jQueryInterface.call($target, config);
});
});
/**
@@ -355,4 +364,4 @@ var Collapse = function ($) {
return Collapse;
}(jQuery);
//# sourceMappingURL=collapse.js.map
//# sourceMappingURL=collapse.js.map
+197 -53
View File
@@ -1,16 +1,26 @@
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
/**
* --------------------------------------------------------------------------
* Bootstrap (v4.0.0-alpha.6): dropdown.js
* Bootstrap (v4.0.0-beta): dropdown.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* --------------------------------------------------------------------------
*/
var Dropdown = function ($) {
/**
* Check for Popper dependency
* Popper - https://popper.js.org
*/
if (typeof Popper === 'undefined') {
throw new Error('Bootstrap dropdown require Popper.js (https://popper.js.org)');
}
/**
* ------------------------------------------------------------------------
* Constants
@@ -18,15 +28,18 @@ var Dropdown = function ($) {
*/
var NAME = 'dropdown';
var VERSION = '4.0.0-alpha.6';
var VERSION = '4.0.0-beta';
var DATA_KEY = 'bs.dropdown';
var EVENT_KEY = '.' + DATA_KEY;
var DATA_API_KEY = '.data-api';
var JQUERY_NO_CONFLICT = $.fn[NAME];
var ESCAPE_KEYCODE = 27; // KeyboardEvent.which value for Escape (Esc) key
var SPACE_KEYCODE = 32; // KeyboardEvent.which value for space key
var TAB_KEYCODE = 9; // KeyboardEvent.which value for tab key
var ARROW_UP_KEYCODE = 38; // KeyboardEvent.which value for up arrow key
var ARROW_DOWN_KEYCODE = 40; // KeyboardEvent.which value for down arrow key
var RIGHT_MOUSE_BUTTON_WHICH = 3; // MouseEvent.which value for the right button (assuming a right-handed mouse)
var REGEXP_KEYDOWN = new RegExp(ARROW_UP_KEYCODE + '|' + ARROW_DOWN_KEYCODE + '|' + ESCAPE_KEYCODE);
var Event = {
HIDE: 'hide' + EVENT_KEY,
@@ -35,37 +48,60 @@ var Dropdown = function ($) {
SHOWN: 'shown' + EVENT_KEY,
CLICK: 'click' + EVENT_KEY,
CLICK_DATA_API: 'click' + EVENT_KEY + DATA_API_KEY,
FOCUSIN_DATA_API: 'focusin' + EVENT_KEY + DATA_API_KEY,
KEYDOWN_DATA_API: 'keydown' + EVENT_KEY + DATA_API_KEY
KEYDOWN_DATA_API: 'keydown' + EVENT_KEY + DATA_API_KEY,
KEYUP_DATA_API: 'keyup' + EVENT_KEY + DATA_API_KEY
};
var ClassName = {
BACKDROP: 'dropdown-backdrop',
DISABLED: 'disabled',
SHOW: 'show'
SHOW: 'show',
DROPUP: 'dropup',
MENURIGHT: 'dropdown-menu-right',
MENULEFT: 'dropdown-menu-left'
};
var Selector = {
BACKDROP: '.dropdown-backdrop',
DATA_TOGGLE: '[data-toggle="dropdown"]',
FORM_CHILD: '.dropdown form',
ROLE_MENU: '[role="menu"]',
ROLE_LISTBOX: '[role="listbox"]',
MENU: '.dropdown-menu',
NAVBAR_NAV: '.navbar-nav',
VISIBLE_ITEMS: '[role="menu"] li:not(.disabled) a, ' + '[role="listbox"] li:not(.disabled) a'
VISIBLE_ITEMS: '.dropdown-menu .dropdown-item:not(.disabled)'
};
/**
* ------------------------------------------------------------------------
* Class Definition
* ------------------------------------------------------------------------
*/
var AttachmentMap = {
TOP: 'top-start',
TOPEND: 'top-end',
BOTTOM: 'bottom-start',
BOTTOMEND: 'bottom-end'
};
var Default = {
placement: AttachmentMap.BOTTOM,
offset: 0,
flip: true
};
var DefaultType = {
placement: 'string',
offset: '(number|string)',
flip: 'boolean'
/**
* ------------------------------------------------------------------------
* Class Definition
* ------------------------------------------------------------------------
*/
};
var Dropdown = function () {
function Dropdown(element) {
function Dropdown(element, config) {
_classCallCheck(this, Dropdown);
this._element = element;
this._popper = null;
this._config = this._getConfig(config);
this._menu = this._getMenuElement();
this._inNavbar = this._detectNavbar();
this._addEventListeners();
}
@@ -75,58 +111,144 @@ var Dropdown = function ($) {
// public
Dropdown.prototype.toggle = function toggle() {
if (this.disabled || $(this).hasClass(ClassName.DISABLED)) {
return false;
if (this._element.disabled || $(this._element).hasClass(ClassName.DISABLED)) {
return;
}
var parent = Dropdown._getParentFromElement(this);
var isActive = $(parent).hasClass(ClassName.SHOW);
var parent = Dropdown._getParentFromElement(this._element);
var isActive = $(this._menu).hasClass(ClassName.SHOW);
Dropdown._clearMenus();
if (isActive) {
return false;
}
if ('ontouchstart' in document.documentElement && !$(parent).closest(Selector.NAVBAR_NAV).length) {
// if mobile we use a backdrop because click events don't delegate
var dropdown = document.createElement('div');
dropdown.className = ClassName.BACKDROP;
$(dropdown).insertBefore(this);
$(dropdown).on('click', Dropdown._clearMenus);
return;
}
var relatedTarget = {
relatedTarget: this
relatedTarget: this._element
};
var showEvent = $.Event(Event.SHOW, relatedTarget);
$(parent).trigger(showEvent);
if (showEvent.isDefaultPrevented()) {
return false;
return;
}
this.focus();
this.setAttribute('aria-expanded', true);
var element = this._element;
// for dropup with alignment we use the parent as popper container
if ($(parent).hasClass(ClassName.DROPUP)) {
if ($(this._menu).hasClass(ClassName.MENULEFT) || $(this._menu).hasClass(ClassName.MENURIGHT)) {
element = parent;
}
}
this._popper = new Popper(element, this._menu, this._getPopperConfig());
$(parent).toggleClass(ClassName.SHOW);
$(parent).trigger($.Event(Event.SHOWN, relatedTarget));
// if this is a touch-enabled device we add extra
// empty mouseover listeners to the body's immediate children;
// only needed because of broken event delegation on iOS
// https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html
if ('ontouchstart' in document.documentElement && !$(parent).closest(Selector.NAVBAR_NAV).length) {
$('body').children().on('mouseover', null, $.noop);
}
return false;
this._element.focus();
this._element.setAttribute('aria-expanded', true);
$(this._menu).toggleClass(ClassName.SHOW);
$(parent).toggleClass(ClassName.SHOW).trigger($.Event(Event.SHOWN, relatedTarget));
};
Dropdown.prototype.dispose = function dispose() {
$.removeData(this._element, DATA_KEY);
$(this._element).off(EVENT_KEY);
this._element = null;
this._menu = null;
if (this._popper !== null) {
this._popper.destroy();
}
this._popper = null;
};
Dropdown.prototype.update = function update() {
this._inNavbar = this._detectNavbar();
if (this._popper !== null) {
this._popper.scheduleUpdate();
}
};
// private
Dropdown.prototype._addEventListeners = function _addEventListeners() {
$(this._element).on(Event.CLICK, this.toggle);
var _this = this;
$(this._element).on(Event.CLICK, function (event) {
event.preventDefault();
event.stopPropagation();
_this.toggle();
});
};
Dropdown.prototype._getConfig = function _getConfig(config) {
var elementData = $(this._element).data();
if (elementData.placement !== undefined) {
elementData.placement = AttachmentMap[elementData.placement.toUpperCase()];
}
config = $.extend({}, this.constructor.Default, $(this._element).data(), config);
Util.typeCheckConfig(NAME, config, this.constructor.DefaultType);
return config;
};
Dropdown.prototype._getMenuElement = function _getMenuElement() {
if (!this._menu) {
var parent = Dropdown._getParentFromElement(this._element);
this._menu = $(parent).find(Selector.MENU)[0];
}
return this._menu;
};
Dropdown.prototype._getPlacement = function _getPlacement() {
var $parentDropdown = $(this._element).parent();
var placement = this._config.placement;
// Handle dropup
if ($parentDropdown.hasClass(ClassName.DROPUP) || this._config.placement === AttachmentMap.TOP) {
placement = AttachmentMap.TOP;
if ($(this._menu).hasClass(ClassName.MENURIGHT)) {
placement = AttachmentMap.TOPEND;
}
} else if ($(this._menu).hasClass(ClassName.MENURIGHT)) {
placement = AttachmentMap.BOTTOMEND;
}
return placement;
};
Dropdown.prototype._detectNavbar = function _detectNavbar() {
return $(this._element).closest('.navbar').length > 0;
};
Dropdown.prototype._getPopperConfig = function _getPopperConfig() {
var popperConfig = {
placement: this._getPlacement(),
modifiers: {
offset: {
offset: this._config.offset
},
flip: {
enabled: this._config.flip
}
}
// Disable Popper.js for Dropdown in Navbar
};if (this._inNavbar) {
popperConfig.modifiers.applyStyle = {
enabled: !this._inNavbar
};
}
return popperConfig;
};
// static
@@ -134,9 +256,10 @@ var Dropdown = function ($) {
Dropdown._jQueryInterface = function _jQueryInterface(config) {
return this.each(function () {
var data = $(this).data(DATA_KEY);
var _config = (typeof config === 'undefined' ? 'undefined' : _typeof(config)) === 'object' ? config : null;
if (!data) {
data = new Dropdown(this);
data = new Dropdown(this, _config);
$(this).data(DATA_KEY, data);
}
@@ -144,34 +267,34 @@ var Dropdown = function ($) {
if (data[config] === undefined) {
throw new Error('No method named "' + config + '"');
}
data[config].call(this);
data[config]();
}
});
};
Dropdown._clearMenus = function _clearMenus(event) {
if (event && event.which === RIGHT_MOUSE_BUTTON_WHICH) {
if (event && (event.which === RIGHT_MOUSE_BUTTON_WHICH || event.type === 'keyup' && event.which !== TAB_KEYCODE)) {
return;
}
var backdrop = $(Selector.BACKDROP)[0];
if (backdrop) {
backdrop.parentNode.removeChild(backdrop);
}
var toggles = $.makeArray($(Selector.DATA_TOGGLE));
for (var i = 0; i < toggles.length; i++) {
var parent = Dropdown._getParentFromElement(toggles[i]);
var context = $(toggles[i]).data(DATA_KEY);
var relatedTarget = {
relatedTarget: toggles[i]
};
if (!context) {
continue;
}
var dropdownMenu = context._menu;
if (!$(parent).hasClass(ClassName.SHOW)) {
continue;
}
if (event && (event.type === 'click' && /input|textarea/i.test(event.target.tagName) || event.type === 'focusin') && $.contains(parent, event.target)) {
if (event && (event.type === 'click' && /input|textarea/i.test(event.target.tagName) || event.type === 'keyup' && event.which === TAB_KEYCODE) && $.contains(parent, event.target)) {
continue;
}
@@ -181,8 +304,15 @@ var Dropdown = function ($) {
continue;
}
// if this is a touch-enabled device we remove the extra
// empty mouseover listeners we added for iOS support
if ('ontouchstart' in document.documentElement) {
$('body').children().off('mouseover', null, $.noop);
}
toggles[i].setAttribute('aria-expanded', 'false');
$(dropdownMenu).removeClass(ClassName.SHOW);
$(parent).removeClass(ClassName.SHOW).trigger($.Event(Event.HIDDEN, relatedTarget));
}
};
@@ -199,7 +329,7 @@ var Dropdown = function ($) {
};
Dropdown._dataApiKeydownHandler = function _dataApiKeydownHandler(event) {
if (!/(38|40|27|32)/.test(event.which) || /input|textarea/i.test(event.target.tagName)) {
if (!REGEXP_KEYDOWN.test(event.which) || /button/i.test(event.target.tagName) && event.which === SPACE_KEYCODE || /input|textarea/i.test(event.target.tagName)) {
return;
}
@@ -213,7 +343,7 @@ var Dropdown = function ($) {
var parent = Dropdown._getParentFromElement(this);
var isActive = $(parent).hasClass(ClassName.SHOW);
if (!isActive && event.which !== ESCAPE_KEYCODE || isActive && event.which === ESCAPE_KEYCODE) {
if (!isActive && (event.which !== ESCAPE_KEYCODE || event.which !== SPACE_KEYCODE) || isActive && (event.which === ESCAPE_KEYCODE || event.which === SPACE_KEYCODE)) {
if (event.which === ESCAPE_KEYCODE) {
var toggle = $(parent).find(Selector.DATA_TOGGLE)[0];
@@ -254,6 +384,16 @@ var Dropdown = function ($) {
get: function get() {
return VERSION;
}
}, {
key: 'Default',
get: function get() {
return Default;
}
}, {
key: 'DefaultType',
get: function get() {
return DefaultType;
}
}]);
return Dropdown;
@@ -265,7 +405,11 @@ var Dropdown = function ($) {
* ------------------------------------------------------------------------
*/
$(document).on(Event.KEYDOWN_DATA_API, Selector.DATA_TOGGLE, Dropdown._dataApiKeydownHandler).on(Event.KEYDOWN_DATA_API, Selector.ROLE_MENU, Dropdown._dataApiKeydownHandler).on(Event.KEYDOWN_DATA_API, Selector.ROLE_LISTBOX, Dropdown._dataApiKeydownHandler).on(Event.CLICK_DATA_API + ' ' + Event.FOCUSIN_DATA_API, Dropdown._clearMenus).on(Event.CLICK_DATA_API, Selector.DATA_TOGGLE, Dropdown.prototype.toggle).on(Event.CLICK_DATA_API, Selector.FORM_CHILD, function (e) {
$(document).on(Event.KEYDOWN_DATA_API, Selector.DATA_TOGGLE, Dropdown._dataApiKeydownHandler).on(Event.KEYDOWN_DATA_API, Selector.MENU, Dropdown._dataApiKeydownHandler).on(Event.CLICK_DATA_API + ' ' + Event.KEYUP_DATA_API, Dropdown._clearMenus).on(Event.CLICK_DATA_API, Selector.DATA_TOGGLE, function (event) {
event.preventDefault();
event.stopPropagation();
Dropdown._jQueryInterface.call($(this), 'toggle');
}).on(Event.CLICK_DATA_API, Selector.FORM_CHILD, function (e) {
e.stopPropagation();
});
@@ -283,5 +427,5 @@ var Dropdown = function ($) {
};
return Dropdown;
}(jQuery);
//# sourceMappingURL=dropdown.js.map
}(jQuery); /* global Popper */
//# sourceMappingURL=dropdown.js.map
+73 -31
View File
@@ -6,7 +6,7 @@ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Cons
/**
* --------------------------------------------------------------------------
* Bootstrap (v4.0.0-alpha.6): modal.js
* Bootstrap (v4.0.0-beta): modal.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* --------------------------------------------------------------------------
*/
@@ -20,7 +20,7 @@ var Modal = function ($) {
*/
var NAME = 'modal';
var VERSION = '4.0.0-alpha.6';
var VERSION = '4.0.0-beta';
var DATA_KEY = 'bs.modal';
var EVENT_KEY = '.' + DATA_KEY;
var DATA_API_KEY = '.data-api';
@@ -69,15 +69,16 @@ var Modal = function ($) {
DIALOG: '.modal-dialog',
DATA_TOGGLE: '[data-toggle="modal"]',
DATA_DISMISS: '[data-dismiss="modal"]',
FIXED_CONTENT: '.fixed-top, .fixed-bottom, .is-fixed, .sticky-top'
FIXED_CONTENT: '.fixed-top, .fixed-bottom, .is-fixed, .sticky-top',
NAVBAR_TOGGLER: '.navbar-toggler'
/**
* ------------------------------------------------------------------------
* Class Definition
* ------------------------------------------------------------------------
*/
};
/**
* ------------------------------------------------------------------------
* Class Definition
* ------------------------------------------------------------------------
*/
var Modal = function () {
function Modal(element, config) {
_classCallCheck(this, Modal);
@@ -89,7 +90,6 @@ var Modal = function ($) {
this._isShown = false;
this._isBodyOverflowing = false;
this._ignoreBackdropClick = false;
this._isTransitioning = false;
this._originalBodyPadding = 0;
this._scrollbarWidth = 0;
}
@@ -106,12 +106,13 @@ var Modal = function ($) {
var _this = this;
if (this._isTransitioning) {
throw new Error('Modal is transitioning');
return;
}
if (Util.supportsTransitionEnd() && $(this._element).hasClass(ClassName.FADE)) {
this._isTransitioning = true;
}
var showEvent = $.Event(Event.SHOW, {
relatedTarget: relatedTarget
});
@@ -156,16 +157,18 @@ var Modal = function ($) {
event.preventDefault();
}
if (this._isTransitioning) {
throw new Error('Modal is transitioning');
if (this._isTransitioning || !this._isShown) {
return;
}
var transition = Util.supportsTransitionEnd() && $(this._element).hasClass(ClassName.FADE);
if (transition) {
this._isTransitioning = true;
}
var hideEvent = $.Event(Event.HIDE);
$(this._element).trigger(hideEvent);
if (!this._isShown || hideEvent.isDefaultPrevented()) {
@@ -185,6 +188,7 @@ var Modal = function ($) {
$(this._dialog).off(Event.MOUSEDOWN_DISMISS);
if (transition) {
$(this._element).one(Util.TRANSITION_END, function (event) {
return _this2._hideModal(event);
}).emulateTransitionEnd(TRANSITION_DURATION);
@@ -205,10 +209,13 @@ var Modal = function ($) {
this._isShown = null;
this._isBodyOverflowing = null;
this._ignoreBackdropClick = null;
this._originalBodyPadding = null;
this._scrollbarWidth = null;
};
Modal.prototype.handleUpdate = function handleUpdate() {
this._adjustDialog();
};
// private
Modal.prototype._getConfig = function _getConfig(config) {
@@ -277,6 +284,7 @@ var Modal = function ($) {
if (this._isShown && this._config.keyboard) {
$(this._element).on(Event.KEYDOWN_DISMISS, function (event) {
if (event.which === ESCAPE_KEYCODE) {
event.preventDefault();
_this5.hide();
}
});
@@ -290,7 +298,7 @@ var Modal = function ($) {
if (this._isShown) {
$(window).on(Event.RESIZE, function (event) {
return _this6._handleUpdate(event);
return _this6.handleUpdate(event);
});
} else {
$(window).off(Event.RESIZE);
@@ -301,7 +309,7 @@ var Modal = function ($) {
var _this7 = this;
this._element.style.display = 'none';
this._element.setAttribute('aria-hidden', 'true');
this._element.setAttribute('aria-hidden', true);
this._isTransitioning = false;
this._showBackdrop(function () {
$(document.body).removeClass(ClassName.OPEN);
@@ -391,10 +399,6 @@ var Modal = function ($) {
// todo (fat): these should probably be refactored out of modal.js
// ----------------------------------------------------------------------
Modal.prototype._handleUpdate = function _handleUpdate() {
this._adjustDialog();
};
Modal.prototype._adjustDialog = function _adjustDialog() {
var isModalOverflowing = this._element.scrollHeight > document.documentElement.clientHeight;
@@ -418,17 +422,55 @@ var Modal = function ($) {
};
Modal.prototype._setScrollbar = function _setScrollbar() {
var bodyPadding = parseInt($(Selector.FIXED_CONTENT).css('padding-right') || 0, 10);
this._originalBodyPadding = document.body.style.paddingRight || '';
var _this9 = this;
if (this._isBodyOverflowing) {
document.body.style.paddingRight = bodyPadding + this._scrollbarWidth + 'px';
// Note: DOMNode.style.paddingRight returns the actual value or '' if not set
// while $(DOMNode).css('padding-right') returns the calculated value or 0 if not set
// Adjust fixed content padding
$(Selector.FIXED_CONTENT).each(function (index, element) {
var actualPadding = $(element)[0].style.paddingRight;
var calculatedPadding = $(element).css('padding-right');
$(element).data('padding-right', actualPadding).css('padding-right', parseFloat(calculatedPadding) + _this9._scrollbarWidth + 'px');
});
// Adjust navbar-toggler margin
$(Selector.NAVBAR_TOGGLER).each(function (index, element) {
var actualMargin = $(element)[0].style.marginRight;
var calculatedMargin = $(element).css('margin-right');
$(element).data('margin-right', actualMargin).css('margin-right', parseFloat(calculatedMargin) + _this9._scrollbarWidth + 'px');
});
// Adjust body padding
var actualPadding = document.body.style.paddingRight;
var calculatedPadding = $('body').css('padding-right');
$('body').data('padding-right', actualPadding).css('padding-right', parseFloat(calculatedPadding) + this._scrollbarWidth + 'px');
}
};
Modal.prototype._resetScrollbar = function _resetScrollbar() {
document.body.style.paddingRight = this._originalBodyPadding;
// Restore fixed content padding
$(Selector.FIXED_CONTENT).each(function (index, element) {
var padding = $(element).data('padding-right');
if (typeof padding !== 'undefined') {
$(element).css('padding-right', padding).removeData('padding-right');
}
});
// Restore navbar-toggler margin
$(Selector.NAVBAR_TOGGLER).each(function (index, element) {
var margin = $(element).data('margin-right');
if (typeof margin !== 'undefined') {
$(element).css('margin-right', margin).removeData('margin-right');
}
});
// Restore body padding
var padding = $('body').data('padding-right');
if (typeof padding !== 'undefined') {
$('body').css('padding-right', padding).removeData('padding-right');
}
};
Modal.prototype._getScrollbarWidth = function _getScrollbarWidth() {
@@ -436,7 +478,7 @@ var Modal = function ($) {
var scrollDiv = document.createElement('div');
scrollDiv.className = ClassName.SCROLLBAR_MEASURER;
document.body.appendChild(scrollDiv);
var scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth;
var scrollbarWidth = scrollDiv.getBoundingClientRect().width - scrollDiv.clientWidth;
document.body.removeChild(scrollDiv);
return scrollbarWidth;
};
@@ -486,7 +528,7 @@ var Modal = function ($) {
*/
$(document).on(Event.CLICK_DATA_API, Selector.DATA_TOGGLE, function (event) {
var _this9 = this;
var _this10 = this;
var target = void 0;
var selector = Util.getSelectorFromElement(this);
@@ -508,8 +550,8 @@ var Modal = function ($) {
}
$target.one(Event.HIDDEN, function () {
if ($(_this9).is(':visible')) {
_this9.focus();
if ($(_this10).is(':visible')) {
_this10.focus();
}
});
});
@@ -532,4 +574,4 @@ var Modal = function ($) {
return Modal;
}(jQuery);
//# sourceMappingURL=modal.js.map
//# sourceMappingURL=modal.js.map
+27 -15
View File
@@ -10,7 +10,7 @@ function _inherits(subClass, superClass) { if (typeof superClass !== "function"
/**
* --------------------------------------------------------------------------
* Bootstrap (v4.0.0-alpha.6): popover.js
* Bootstrap (v4.0.0-beta): popover.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* --------------------------------------------------------------------------
*/
@@ -24,16 +24,18 @@ var Popover = function ($) {
*/
var NAME = 'popover';
var VERSION = '4.0.0-alpha.6';
var VERSION = '4.0.0-beta';
var DATA_KEY = 'bs.popover';
var EVENT_KEY = '.' + DATA_KEY;
var JQUERY_NO_CONFLICT = $.fn[NAME];
var CLASS_PREFIX = 'bs-popover';
var BSCLS_PREFIX_REGEX = new RegExp('(^|\\s)' + CLASS_PREFIX + '\\S+', 'g');
var Default = $.extend({}, Tooltip.Default, {
placement: 'right',
trigger: 'click',
content: '',
template: '<div class="popover" role="tooltip">' + '<h3 class="popover-title"></h3>' + '<div class="popover-content"></div></div>'
template: '<div class="popover" role="tooltip">' + '<div class="arrow"></div>' + '<h3 class="popover-header"></h3>' + '<div class="popover-body"></div></div>'
});
var DefaultType = $.extend({}, Tooltip.DefaultType, {
@@ -46,8 +48,8 @@ var Popover = function ($) {
};
var Selector = {
TITLE: '.popover-title',
CONTENT: '.popover-content'
TITLE: '.popover-header',
CONTENT: '.popover-body'
};
var Event = {
@@ -61,14 +63,14 @@ var Popover = function ($) {
FOCUSOUT: 'focusout' + EVENT_KEY,
MOUSEENTER: 'mouseenter' + EVENT_KEY,
MOUSELEAVE: 'mouseleave' + EVENT_KEY
/**
* ------------------------------------------------------------------------
* Class Definition
* ------------------------------------------------------------------------
*/
};
/**
* ------------------------------------------------------------------------
* Class Definition
* ------------------------------------------------------------------------
*/
var Popover = function (_Tooltip) {
_inherits(Popover, _Tooltip);
@@ -84,6 +86,10 @@ var Popover = function ($) {
return this.getTitle() || this._getContent();
};
Popover.prototype.addAttachmentClass = function addAttachmentClass(attachment) {
$(this.getTipElement()).addClass(CLASS_PREFIX + '-' + attachment);
};
Popover.prototype.getTipElement = function getTipElement() {
return this.tip = this.tip || $(this.config.template)[0];
};
@@ -96,8 +102,6 @@ var Popover = function ($) {
this.setElementContent($tip.find(Selector.CONTENT), this._getContent());
$tip.removeClass(ClassName.FADE + ' ' + ClassName.SHOW);
this.cleanupTether();
};
// private
@@ -106,6 +110,14 @@ var Popover = function ($) {
return this.element.getAttribute('data-content') || (typeof this.config.content === 'function' ? this.config.content.call(this.element) : this.config.content);
};
Popover.prototype._cleanTipClass = function _cleanTipClass() {
var $tip = $(this.getTipElement());
var tabClass = $tip.attr('class').match(BSCLS_PREFIX_REGEX);
if (tabClass !== null && tabClass.length > 0) {
$tip.removeClass(tabClass.join(''));
}
};
// static
Popover._jQueryInterface = function _jQueryInterface(config) {
@@ -190,4 +202,4 @@ var Popover = function ($) {
return Popover;
}(jQuery);
//# sourceMappingURL=popover.js.map
//# sourceMappingURL=popover.js.map
+25 -23
View File
@@ -6,7 +6,7 @@ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Cons
/**
* --------------------------------------------------------------------------
* Bootstrap (v4.0.0-alpha.6): scrollspy.js
* Bootstrap (v4.0.0-beta): scrollspy.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* --------------------------------------------------------------------------
*/
@@ -20,7 +20,7 @@ var ScrollSpy = function ($) {
*/
var NAME = 'scrollspy';
var VERSION = '4.0.0-alpha.6';
var VERSION = '4.0.0-beta';
var DATA_KEY = 'bs.scrollspy';
var EVENT_KEY = '.' + DATA_KEY;
var DATA_API_KEY = '.data-api';
@@ -47,18 +47,15 @@ var ScrollSpy = function ($) {
var ClassName = {
DROPDOWN_ITEM: 'dropdown-item',
DROPDOWN_MENU: 'dropdown-menu',
NAV_LINK: 'nav-link',
NAV: 'nav',
ACTIVE: 'active'
};
var Selector = {
DATA_SPY: '[data-spy="scroll"]',
ACTIVE: '.active',
LIST_ITEM: '.list-item',
LI: 'li',
LI_DROPDOWN: 'li.dropdown',
NAV_LIST_GROUP: '.nav, .list-group',
NAV_LINKS: '.nav-link',
LIST_ITEMS: '.list-group-item',
DROPDOWN: '.dropdown',
DROPDOWN_ITEMS: '.dropdown-item',
DROPDOWN_TOGGLE: '.dropdown-toggle'
@@ -67,14 +64,14 @@ var ScrollSpy = function ($) {
var OffsetMethod = {
OFFSET: 'offset',
POSITION: 'position'
/**
* ------------------------------------------------------------------------
* Class Definition
* ------------------------------------------------------------------------
*/
};
/**
* ------------------------------------------------------------------------
* Class Definition
* ------------------------------------------------------------------------
*/
var ScrollSpy = function () {
function ScrollSpy(element, config) {
var _this = this;
@@ -84,7 +81,7 @@ var ScrollSpy = function ($) {
this._element = element;
this._scrollElement = element.tagName === 'BODY' ? window : element;
this._config = this._getConfig(config);
this._selector = this._config.target + ' ' + Selector.NAV_LINKS + ',' + (this._config.target + ' ' + Selector.DROPDOWN_ITEMS);
this._selector = this._config.target + ' ' + Selector.NAV_LINKS + ',' + (this._config.target + ' ' + Selector.LIST_ITEMS + ',') + (this._config.target + ' ' + Selector.DROPDOWN_ITEMS);
this._offsets = [];
this._targets = [];
this._activeTarget = null;
@@ -126,9 +123,12 @@ var ScrollSpy = function ($) {
target = $(targetSelector)[0];
}
if (target && (target.offsetWidth || target.offsetHeight)) {
// todo (fat): remove sketch reliance on jQuery position/offset
return [$(target)[offsetMethod]().top + offsetBase, targetSelector];
if (target) {
var targetBCR = target.getBoundingClientRect();
if (targetBCR.width || targetBCR.height) {
// todo (fat): remove sketch reliance on jQuery position/offset
return [$(target)[offsetMethod]().top + offsetBase, targetSelector];
}
}
return null;
}).filter(function (item) {
@@ -183,7 +183,7 @@ var ScrollSpy = function ($) {
};
ScrollSpy.prototype._getOffsetHeight = function _getOffsetHeight() {
return this._scrollElement === window ? window.innerHeight : this._scrollElement.offsetHeight;
return this._scrollElement === window ? window.innerHeight : this._scrollElement.getBoundingClientRect().height;
};
ScrollSpy.prototype._process = function _process() {
@@ -235,9 +235,11 @@ var ScrollSpy = function ($) {
$link.closest(Selector.DROPDOWN).find(Selector.DROPDOWN_TOGGLE).addClass(ClassName.ACTIVE);
$link.addClass(ClassName.ACTIVE);
} else {
// todo (fat) this is kinda sus...
// recursively add actives to tested nav-links
$link.parents(Selector.LI).find('> ' + Selector.NAV_LINKS).addClass(ClassName.ACTIVE);
// Set triggered link as active
$link.addClass(ClassName.ACTIVE);
// Set triggered links parents as active
// With both <ul> and <nav> markup a parent is the previous sibling of any nav ancestor
$link.parents(Selector.NAV_LIST_GROUP).prev(Selector.NAV_LINKS + ', ' + Selector.LIST_ITEMS).addClass(ClassName.ACTIVE);
}
$(this._scrollElement).trigger(Event.ACTIVATE, {
@@ -315,4 +317,4 @@ var ScrollSpy = function ($) {
return ScrollSpy;
}(jQuery);
//# sourceMappingURL=scrollspy.js.map
//# sourceMappingURL=scrollspy.js.map
+16 -20
View File
@@ -4,7 +4,7 @@ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Cons
/**
* --------------------------------------------------------------------------
* Bootstrap (v4.0.0-alpha.6): tab.js
* Bootstrap (v4.0.0-beta): tab.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* --------------------------------------------------------------------------
*/
@@ -18,7 +18,7 @@ var Tab = function ($) {
*/
var NAME = 'tab';
var VERSION = '4.0.0-alpha.6';
var VERSION = '4.0.0-beta';
var DATA_KEY = 'bs.tab';
var EVENT_KEY = '.' + DATA_KEY;
var DATA_API_KEY = '.data-api';
@@ -42,24 +42,20 @@ var Tab = function ($) {
};
var Selector = {
A: 'a',
LI: 'li',
DROPDOWN: '.dropdown',
LIST: 'ul:not(.dropdown-menu), ol:not(.dropdown-menu), nav:not(.dropdown-menu)',
FADE_CHILD: '> .nav-item .fade, > .fade',
NAV_LIST_GROUP: '.nav, .list-group',
ACTIVE: '.active',
ACTIVE_CHILD: '> .nav-item > .active, > .active',
DATA_TOGGLE: '[data-toggle="tab"], [data-toggle="pill"]',
DATA_TOGGLE: '[data-toggle="tab"], [data-toggle="pill"], [data-toggle="list"]',
DROPDOWN_TOGGLE: '.dropdown-toggle',
DROPDOWN_ACTIVE_CHILD: '> .dropdown-menu .active'
/**
* ------------------------------------------------------------------------
* Class Definition
* ------------------------------------------------------------------------
*/
};
/**
* ------------------------------------------------------------------------
* Class Definition
* ------------------------------------------------------------------------
*/
var Tab = function () {
function Tab(element) {
_classCallCheck(this, Tab);
@@ -80,7 +76,7 @@ var Tab = function ($) {
var target = void 0;
var previous = void 0;
var listElement = $(this._element).closest(Selector.LIST)[0];
var listElement = $(this._element).closest(Selector.NAV_LIST_GROUP)[0];
var selector = Util.getSelectorFromElement(this._element);
if (listElement) {
@@ -133,7 +129,7 @@ var Tab = function ($) {
};
Tab.prototype.dispose = function dispose() {
$.removeClass(this._element, DATA_KEY);
$.removeData(this._element, DATA_KEY);
this._element = null;
};
@@ -142,8 +138,8 @@ var Tab = function ($) {
Tab.prototype._activate = function _activate(element, container, callback) {
var _this2 = this;
var active = $(container).find(Selector.ACTIVE_CHILD)[0];
var isTransitioning = callback && Util.supportsTransitionEnd() && (active && $(active).hasClass(ClassName.FADE) || Boolean($(container).find(Selector.FADE_CHILD)[0]));
var active = $(container).find(Selector.ACTIVE)[0];
var isTransitioning = callback && Util.supportsTransitionEnd() && active && $(active).hasClass(ClassName.FADE);
var complete = function complete() {
return _this2._transitionComplete(element, active, isTransitioning, callback);
@@ -255,4 +251,4 @@ var Tab = function ($) {
return Tab;
}(jQuery);
//# sourceMappingURL=tab.js.map
//# sourceMappingURL=tab.js.map
+141 -85
View File
@@ -6,7 +6,7 @@ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Cons
/**
* --------------------------------------------------------------------------
* Bootstrap (v4.0.0-alpha.6): tooltip.js
* Bootstrap (v4.0.0-beta): tooltip.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* --------------------------------------------------------------------------
*/
@@ -14,11 +14,11 @@ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Cons
var Tooltip = function ($) {
/**
* Check for Tether dependency
* Tether - http://tether.io/
* Check for Popper dependency
* Popper - https://popper.js.org
*/
if (typeof Tether === 'undefined') {
throw new Error('Bootstrap tooltips require Tether (http://tether.io/)');
if (typeof Popper === 'undefined') {
throw new Error('Bootstrap tooltips require Popper.js (https://popper.js.org)');
}
/**
@@ -28,26 +28,13 @@ var Tooltip = function ($) {
*/
var NAME = 'tooltip';
var VERSION = '4.0.0-alpha.6';
var VERSION = '4.0.0-beta';
var DATA_KEY = 'bs.tooltip';
var EVENT_KEY = '.' + DATA_KEY;
var JQUERY_NO_CONFLICT = $.fn[NAME];
var TRANSITION_DURATION = 150;
var CLASS_PREFIX = 'bs-tether';
var Default = {
animation: true,
template: '<div class="tooltip" role="tooltip">' + '<div class="tooltip-inner"></div></div>',
trigger: 'hover focus',
title: '',
delay: 0,
html: false,
selector: false,
placement: 'top',
offset: '0 0',
constraints: [],
container: false
};
var CLASS_PREFIX = 'bs-tooltip';
var BSCLS_PREFIX_REGEX = new RegExp('(^|\\s)' + CLASS_PREFIX + '\\S+', 'g');
var DefaultType = {
animation: 'boolean',
@@ -58,16 +45,31 @@ var Tooltip = function ($) {
html: 'boolean',
selector: '(string|boolean)',
placement: '(string|function)',
offset: 'string',
constraints: 'array',
container: '(string|element|boolean)'
offset: '(number|string)',
container: '(string|element|boolean)',
fallbackPlacement: '(string|array)'
};
var AttachmentMap = {
TOP: 'bottom center',
RIGHT: 'middle left',
BOTTOM: 'top center',
LEFT: 'middle right'
AUTO: 'auto',
TOP: 'top',
RIGHT: 'right',
BOTTOM: 'bottom',
LEFT: 'left'
};
var Default = {
animation: true,
template: '<div class="tooltip" role="tooltip">' + '<div class="arrow"></div>' + '<div class="tooltip-inner"></div></div>',
trigger: 'hover focus',
title: '',
delay: 0,
html: false,
selector: false,
placement: 'top',
offset: 0,
container: false,
fallbackPlacement: 'flip'
};
var HoverState = {
@@ -95,12 +97,8 @@ var Tooltip = function ($) {
var Selector = {
TOOLTIP: '.tooltip',
TOOLTIP_INNER: '.tooltip-inner'
};
var TetherClass = {
element: false,
enabled: false
TOOLTIP_INNER: '.tooltip-inner',
ARROW: '.arrow'
};
var Trigger = {
@@ -108,14 +106,14 @@ var Tooltip = function ($) {
FOCUS: 'focus',
CLICK: 'click',
MANUAL: 'manual'
/**
* ------------------------------------------------------------------------
* Class Definition
* ------------------------------------------------------------------------
*/
};
/**
* ------------------------------------------------------------------------
* Class Definition
* ------------------------------------------------------------------------
*/
var Tooltip = function () {
function Tooltip(element, config) {
_classCallCheck(this, Tooltip);
@@ -125,8 +123,7 @@ var Tooltip = function ($) {
this._timeout = 0;
this._hoverState = '';
this._activeTrigger = {};
this._isTransitioning = false;
this._tether = null;
this._popper = null;
// protected
this.element = element;
@@ -183,8 +180,6 @@ var Tooltip = function ($) {
Tooltip.prototype.dispose = function dispose() {
clearTimeout(this._timeout);
this.cleanupTether();
$.removeData(this.element, this.constructor.DATA_KEY);
$(this.element).off(this.constructor.EVENT_KEY);
@@ -198,7 +193,10 @@ var Tooltip = function ($) {
this._timeout = null;
this._hoverState = null;
this._activeTrigger = null;
this._tether = null;
if (this._popper !== null) {
this._popper.destroy();
}
this._popper = null;
this.element = null;
this.config = null;
@@ -214,9 +212,6 @@ var Tooltip = function ($) {
var showEvent = $.Event(this.constructor.Event.SHOW);
if (this.isWithContent() && this._isEnabled) {
if (this._isTransitioning) {
throw new Error('Tooltip is transitioning');
}
$(this.element).trigger(showEvent);
var isInTheDom = $.contains(this.element.ownerDocument.documentElement, this.element);
@@ -240,33 +235,57 @@ var Tooltip = function ($) {
var placement = typeof this.config.placement === 'function' ? this.config.placement.call(this, tip, this.element) : this.config.placement;
var attachment = this._getAttachment(placement);
this.addAttachmentClass(attachment);
var container = this.config.container === false ? document.body : $(this.config.container);
$(tip).data(this.constructor.DATA_KEY, this).appendTo(container);
$(tip).data(this.constructor.DATA_KEY, this);
if (!$.contains(this.element.ownerDocument.documentElement, this.tip)) {
$(tip).appendTo(container);
}
$(this.element).trigger(this.constructor.Event.INSERTED);
this._tether = new Tether({
attachment: attachment,
element: tip,
target: this.element,
classes: TetherClass,
classPrefix: CLASS_PREFIX,
offset: this.config.offset,
constraints: this.config.constraints,
addTargetClasses: false
this._popper = new Popper(this.element, tip, {
placement: attachment,
modifiers: {
offset: {
offset: this.config.offset
},
flip: {
behavior: this.config.fallbackPlacement
},
arrow: {
element: Selector.ARROW
}
},
onCreate: function onCreate(data) {
if (data.originalPlacement !== data.placement) {
_this._handlePopperPlacementChange(data);
}
},
onUpdate: function onUpdate(data) {
_this._handlePopperPlacementChange(data);
}
});
Util.reflow(tip);
this._tether.position();
$(tip).addClass(ClassName.SHOW);
// if this is a touch-enabled device we add extra
// empty mouseover listeners to the body's immediate children;
// only needed because of broken event delegation on iOS
// https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html
if ('ontouchstart' in document.documentElement) {
$('body').children().on('mouseover', null, $.noop);
}
var complete = function complete() {
if (_this.config.animation) {
_this._fixTransition();
}
var prevHoverState = _this._hoverState;
_this._hoverState = null;
_this._isTransitioning = false;
$(_this.element).trigger(_this.constructor.Event.SHOWN);
@@ -276,12 +295,10 @@ var Tooltip = function ($) {
};
if (Util.supportsTransitionEnd() && $(this.tip).hasClass(ClassName.FADE)) {
this._isTransitioning = true;
$(this.tip).one(Util.TRANSITION_END, complete).emulateTransitionEnd(Tooltip._TRANSITION_DURATION);
return;
} else {
complete();
}
complete();
}
};
@@ -290,18 +307,17 @@ var Tooltip = function ($) {
var tip = this.getTipElement();
var hideEvent = $.Event(this.constructor.Event.HIDE);
if (this._isTransitioning) {
throw new Error('Tooltip is transitioning');
}
var complete = function complete() {
if (_this2._hoverState !== HoverState.SHOW && tip.parentNode) {
tip.parentNode.removeChild(tip);
}
_this2._cleanTipClass();
_this2.element.removeAttribute('aria-describedby');
$(_this2.element).trigger(_this2.constructor.Event.HIDDEN);
_this2._isTransitioning = false;
_this2.cleanupTether();
if (_this2._popper !== null) {
_this2._popper.destroy();
}
if (callback) {
callback();
@@ -316,12 +332,18 @@ var Tooltip = function ($) {
$(tip).removeClass(ClassName.SHOW);
// if this is a touch-enabled device we remove the extra
// empty mouseover listeners we added for iOS support
if ('ontouchstart' in document.documentElement) {
$('body').children().off('mouseover', null, $.noop);
}
this._activeTrigger[Trigger.CLICK] = false;
this._activeTrigger[Trigger.FOCUS] = false;
this._activeTrigger[Trigger.HOVER] = false;
if (Util.supportsTransitionEnd() && $(this.tip).hasClass(ClassName.FADE)) {
this._isTransitioning = true;
$(tip).one(Util.TRANSITION_END, complete).emulateTransitionEnd(TRANSITION_DURATION);
} else {
complete();
@@ -330,24 +352,30 @@ var Tooltip = function ($) {
this._hoverState = '';
};
Tooltip.prototype.update = function update() {
if (this._popper !== null) {
this._popper.scheduleUpdate();
}
};
// protected
Tooltip.prototype.isWithContent = function isWithContent() {
return Boolean(this.getTitle());
};
Tooltip.prototype.addAttachmentClass = function addAttachmentClass(attachment) {
$(this.getTipElement()).addClass(CLASS_PREFIX + '-' + attachment);
};
Tooltip.prototype.getTipElement = function getTipElement() {
return this.tip = this.tip || $(this.config.template)[0];
};
Tooltip.prototype.setContent = function setContent() {
var $tip = $(this.getTipElement());
this.setElementContent($tip.find(Selector.TOOLTIP_INNER), this.getTitle());
$tip.removeClass(ClassName.FADE + ' ' + ClassName.SHOW);
this.cleanupTether();
};
Tooltip.prototype.setElementContent = function setElementContent($element, content) {
@@ -376,12 +404,6 @@ var Tooltip = function ($) {
return title;
};
Tooltip.prototype.cleanupTether = function cleanupTether() {
if (this._tether) {
this._tether.destroy();
}
};
// private
Tooltip.prototype._getAttachment = function _getAttachment(placement) {
@@ -521,6 +543,14 @@ var Tooltip = function ($) {
};
}
if (config.title && typeof config.title === 'number') {
config.title = config.title.toString();
}
if (config.content && typeof config.content === 'number') {
config.content = config.content.toString();
}
Util.typeCheckConfig(NAME, config, this.constructor.DefaultType);
return config;
@@ -540,6 +570,32 @@ var Tooltip = function ($) {
return config;
};
Tooltip.prototype._cleanTipClass = function _cleanTipClass() {
var $tip = $(this.getTipElement());
var tabClass = $tip.attr('class').match(BSCLS_PREFIX_REGEX);
if (tabClass !== null && tabClass.length > 0) {
$tip.removeClass(tabClass.join(''));
}
};
Tooltip.prototype._handlePopperPlacementChange = function _handlePopperPlacementChange(data) {
this._cleanTipClass();
this.addAttachmentClass(this._getAttachment(data.placement));
};
Tooltip.prototype._fixTransition = function _fixTransition() {
var tip = this.getTipElement();
var initConfigAnimation = this.config.animation;
if (tip.getAttribute('x-placement') !== null) {
return;
}
$(tip).removeClass(ClassName.FADE);
this.config.animation = false;
this.hide();
this.show();
this.config.animation = initConfigAnimation;
};
// static
Tooltip._jQueryInterface = function _jQueryInterface(config) {
@@ -619,5 +675,5 @@ var Tooltip = function ($) {
};
return Tooltip;
}(jQuery); /* global Tether */
//# sourceMappingURL=tooltip.js.map
}(jQuery); /* global Popper */
//# sourceMappingURL=tooltip.js.map
+11 -9
View File
@@ -1,6 +1,6 @@
/**
* --------------------------------------------------------------------------
* Bootstrap (v4.0.0-alpha.6): util.js
* Bootstrap (v4.0.0-beta): util.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* --------------------------------------------------------------------------
*/
@@ -22,10 +22,9 @@ var Util = function ($) {
MozTransition: 'transitionend',
OTransition: 'oTransitionEnd otransitionend',
transition: 'transitionend'
};
// shoutout AngusCroll (https://goo.gl/pxwQGp)
function toType(obj) {
// shoutout AngusCroll (https://goo.gl/pxwQGp)
};function toType(obj) {
return {}.toString.call(obj).match(/\s([a-zA-Z]+)/)[1].toLowerCase();
}
@@ -111,13 +110,16 @@ var Util = function ($) {
},
getSelectorFromElement: function getSelectorFromElement(element) {
var selector = element.getAttribute('data-target');
if (!selector) {
if (!selector || selector === '#') {
selector = element.getAttribute('href') || '';
selector = /^#[a-z]/i.test(selector) ? selector : null;
}
return selector;
try {
var $selector = $(selector);
return $selector.length > 0 ? selector : null;
} catch (error) {
return null;
}
},
reflow: function reflow(element) {
return element.offsetHeight;
@@ -147,4 +149,4 @@ var Util = function ($) {
return Util;
}(jQuery);
//# sourceMappingURL=util.js.map
//# sourceMappingURL=util.js.map
+2 -2
View File
@@ -3,7 +3,7 @@ import Util from './util'
/**
* --------------------------------------------------------------------------
* Bootstrap (v4.0.0-alpha.6): alert.js
* Bootstrap (v4.0.0-beta): alert.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* --------------------------------------------------------------------------
*/
@@ -18,7 +18,7 @@ const Alert = (($) => {
*/
const NAME = 'alert'
const VERSION = '4.0.0-alpha.6'
const VERSION = '4.0.0-beta'
const DATA_KEY = 'bs.alert'
const EVENT_KEY = `.${DATA_KEY}`
const DATA_API_KEY = '.data-api'
+14 -4
View File
@@ -1,6 +1,6 @@
/**
* --------------------------------------------------------------------------
* Bootstrap (v4.0.0-alpha.6): button.js
* Bootstrap (v4.0.0-beta): button.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* --------------------------------------------------------------------------
*/
@@ -15,7 +15,7 @@ const Button = (($) => {
*/
const NAME = 'button'
const VERSION = '4.0.0-alpha.6'
const VERSION = '4.0.0-beta'
const DATA_KEY = 'bs.button'
const EVENT_KEY = `.${DATA_KEY}`
const DATA_API_KEY = '.data-api'
@@ -66,6 +66,7 @@ const Button = (($) => {
toggle() {
let triggerChangeEvent = true
let addAriaPressed = true
const rootElement = $(this._element).closest(
Selector.DATA_TOGGLE
)[0]
@@ -89,17 +90,26 @@ const Button = (($) => {
}
if (triggerChangeEvent) {
if (input.hasAttribute('disabled') ||
rootElement.hasAttribute('disabled') ||
input.classList.contains('disabled') ||
rootElement.classList.contains('disabled')) {
return
}
input.checked = !$(this._element).hasClass(ClassName.ACTIVE)
$(input).trigger('change')
}
input.focus()
addAriaPressed = false
}
}
this._element.setAttribute('aria-pressed',
!$(this._element).hasClass(ClassName.ACTIVE))
if (addAriaPressed) {
this._element.setAttribute('aria-pressed',
!$(this._element).hasClass(ClassName.ACTIVE))
}
if (triggerChangeEvent) {
$(this._element).toggleClass(ClassName.ACTIVE)
+48 -24
View File
@@ -3,7 +3,7 @@ import Util from './util'
/**
* --------------------------------------------------------------------------
* Bootstrap (v4.0.0-alpha.6): carousel.js
* Bootstrap (v4.0.0-beta): carousel.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* --------------------------------------------------------------------------
*/
@@ -17,15 +17,16 @@ const Carousel = (($) => {
* ------------------------------------------------------------------------
*/
const NAME = 'carousel'
const VERSION = '4.0.0-alpha.6'
const DATA_KEY = 'bs.carousel'
const EVENT_KEY = `.${DATA_KEY}`
const DATA_API_KEY = '.data-api'
const JQUERY_NO_CONFLICT = $.fn[NAME]
const TRANSITION_DURATION = 600
const ARROW_LEFT_KEYCODE = 37 // KeyboardEvent.which value for left arrow key
const ARROW_RIGHT_KEYCODE = 39 // KeyboardEvent.which value for right arrow key
const NAME = 'carousel'
const VERSION = '4.0.0-beta'
const DATA_KEY = 'bs.carousel'
const EVENT_KEY = `.${DATA_KEY}`
const DATA_API_KEY = '.data-api'
const JQUERY_NO_CONFLICT = $.fn[NAME]
const TRANSITION_DURATION = 600
const ARROW_LEFT_KEYCODE = 37 // KeyboardEvent.which value for left arrow key
const ARROW_RIGHT_KEYCODE = 39 // KeyboardEvent.which value for right arrow key
const TOUCHEVENT_COMPAT_WAIT = 500 // Time for mouse compat events to fire after touch
const Default = {
interval : 5000,
@@ -56,6 +57,7 @@ const Carousel = (($) => {
KEYDOWN : `keydown${EVENT_KEY}`,
MOUSEENTER : `mouseenter${EVENT_KEY}`,
MOUSELEAVE : `mouseleave${EVENT_KEY}`,
TOUCHEND : `touchend${EVENT_KEY}`,
LOAD_DATA_API : `load${EVENT_KEY}${DATA_API_KEY}`,
CLICK_DATA_API : `click${EVENT_KEY}${DATA_API_KEY}`
}
@@ -98,6 +100,8 @@ const Carousel = (($) => {
this._isPaused = false
this._isSliding = false
this.touchTimeout = null
this._config = this._getConfig(config)
this._element = $(element)[0]
this._indicatorsElement = $(this._element).find(Selector.INDICATORS)[0]
@@ -120,10 +124,9 @@ const Carousel = (($) => {
// public
next() {
if (this._isSliding) {
throw new Error('Carousel is sliding')
if (!this._isSliding) {
this._slide(Direction.NEXT)
}
this._slide(Direction.NEXT)
}
nextWhenVisible() {
@@ -134,10 +137,9 @@ const Carousel = (($) => {
}
prev() {
if (this._isSliding) {
throw new Error('Carousel is sliding')
if (!this._isSliding) {
this._slide(Direction.PREV)
}
this._slide(Direction.PREVIOUS)
}
pause(event) {
@@ -195,7 +197,7 @@ const Carousel = (($) => {
const direction = index > activeIndex ?
Direction.NEXT :
Direction.PREVIOUS
Direction.PREV
this._slide(direction, this._items[index])
}
@@ -229,11 +231,26 @@ const Carousel = (($) => {
.on(Event.KEYDOWN, (event) => this._keydown(event))
}
if (this._config.pause === 'hover' &&
!('ontouchstart' in document.documentElement)) {
if (this._config.pause === 'hover') {
$(this._element)
.on(Event.MOUSEENTER, (event) => this.pause(event))
.on(Event.MOUSELEAVE, (event) => this.cycle(event))
if ('ontouchstart' in document.documentElement) {
// if it's a touch-enabled device, mouseenter/leave are fired as
// part of the mouse compatibility events on first tap - the carousel
// would stop cycling until user tapped out of it;
// here, we listen for touchend, explicitly pause the carousel
// (as if it's the second time we tap on it, mouseenter compat event
// is NOT fired) and after a timeout (to allow for mouse compatibility
// events to fire) we explicitly restart cycling
$(this._element).on(Event.TOUCHEND, () => {
this.pause()
if (this.touchTimeout) {
clearTimeout(this.touchTimeout)
}
this.touchTimeout = setTimeout((event) => this.cycle(event), TOUCHEVENT_COMPAT_WAIT + this._config.interval)
})
}
}
}
@@ -263,7 +280,7 @@ const Carousel = (($) => {
_getItemByDirection(direction, activeElement) {
const isNextDirection = direction === Direction.NEXT
const isPrevDirection = direction === Direction.PREVIOUS
const isPrevDirection = direction === Direction.PREV
const activeIndex = this._getItemIndex(activeElement)
const lastItemIndex = this._items.length - 1
const isGoingToWrap = isPrevDirection && activeIndex === 0 ||
@@ -273,7 +290,7 @@ const Carousel = (($) => {
return activeElement
}
const delta = direction === Direction.PREVIOUS ? -1 : 1
const delta = direction === Direction.PREV ? -1 : 1
const itemIndex = (activeIndex + delta) % this._items.length
return itemIndex === -1 ?
@@ -282,9 +299,13 @@ const Carousel = (($) => {
_triggerSlideEvent(relatedTarget, eventDirectionName) {
const targetIndex = this._getItemIndex(relatedTarget)
const fromIndex = this._getItemIndex($(this._element).find(Selector.ACTIVE_ITEM)[0])
const slideEvent = $.Event(Event.SLIDE, {
relatedTarget,
direction: eventDirectionName
direction: eventDirectionName,
from: fromIndex,
to: targetIndex
})
$(this._element).trigger(slideEvent)
@@ -310,9 +331,10 @@ const Carousel = (($) => {
_slide(direction, element) {
const activeElement = $(this._element).find(Selector.ACTIVE_ITEM)[0]
const activeElementIndex = this._getItemIndex(activeElement)
const nextElement = element || activeElement &&
this._getItemByDirection(direction, activeElement)
const nextElementIndex = this._getItemIndex(nextElement)
const isCycling = Boolean(this._interval)
let directionalClassName
@@ -354,7 +376,9 @@ const Carousel = (($) => {
const slidEvent = $.Event(Event.SLID, {
relatedTarget: nextElement,
direction: eventDirectionName
direction: eventDirectionName,
from: activeElementIndex,
to: nextElementIndex
})
if (Util.supportsTransitionEnd() &&
+39 -30
View File
@@ -3,7 +3,7 @@ import Util from './util'
/**
* --------------------------------------------------------------------------
* Bootstrap (v4.0.0-alpha.6): collapse.js
* Bootstrap (v4.0.0-beta): collapse.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* --------------------------------------------------------------------------
*/
@@ -18,7 +18,7 @@ const Collapse = (($) => {
*/
const NAME = 'collapse'
const VERSION = '4.0.0-alpha.6'
const VERSION = '4.0.0-beta'
const DATA_KEY = 'bs.collapse'
const EVENT_KEY = `.${DATA_KEY}`
const DATA_API_KEY = '.data-api'
@@ -56,7 +56,7 @@ const Collapse = (($) => {
}
const Selector = {
ACTIVES : '.card > .show, .card > .collapsing',
ACTIVES : '.show, .collapsing',
DATA_TOGGLE : '[data-toggle="collapse"]'
}
@@ -77,6 +77,14 @@ const Collapse = (($) => {
`[data-toggle="collapse"][href="#${element.id}"],` +
`[data-toggle="collapse"][data-target="#${element.id}"]`
))
const tabToggles = $(Selector.DATA_TOGGLE)
for (let i = 0; i < tabToggles.length; i++) {
const elem = tabToggles[i]
const selector = Util.getSelectorFromElement(elem)
if (selector !== null && $(selector).filter(element).length > 0) {
this._triggerArray.push(elem)
}
}
this._parent = this._config.parent ? this._getParent() : null
@@ -112,11 +120,8 @@ const Collapse = (($) => {
}
show() {
if (this._isTransitioning) {
throw new Error('Collapse is transitioning')
}
if ($(this._element).hasClass(ClassName.SHOW)) {
if (this._isTransitioning ||
$(this._element).hasClass(ClassName.SHOW)) {
return
}
@@ -124,7 +129,7 @@ const Collapse = (($) => {
let activesData
if (this._parent) {
actives = $.makeArray($(this._parent).find(Selector.ACTIVES))
actives = $.makeArray($(this._parent).children().children(Selector.ACTIVES))
if (!actives.length) {
actives = null
}
@@ -157,7 +162,6 @@ const Collapse = (($) => {
.addClass(ClassName.COLLAPSING)
this._element.style[dimension] = 0
this._element.setAttribute('aria-expanded', true)
if (this._triggerArray.length) {
$(this._triggerArray)
@@ -196,11 +200,8 @@ const Collapse = (($) => {
}
hide() {
if (this._isTransitioning) {
throw new Error('Collapse is transitioning')
}
if (!$(this._element).hasClass(ClassName.SHOW)) {
if (this._isTransitioning ||
!$(this._element).hasClass(ClassName.SHOW)) {
return
}
@@ -211,10 +212,8 @@ const Collapse = (($) => {
}
const dimension = this._getDimension()
const offsetDimension = dimension === Dimension.WIDTH ?
'offsetWidth' : 'offsetHeight'
this._element.style[dimension] = `${this._element[offsetDimension]}px`
this._element.style[dimension] = `${this._element.getBoundingClientRect()[dimension]}px`
Util.reflow(this._element)
@@ -223,12 +222,18 @@ const Collapse = (($) => {
.removeClass(ClassName.COLLAPSE)
.removeClass(ClassName.SHOW)
this._element.setAttribute('aria-expanded', false)
if (this._triggerArray.length) {
$(this._triggerArray)
.addClass(ClassName.COLLAPSED)
.attr('aria-expanded', false)
for (let i = 0; i < this._triggerArray.length; i++) {
const trigger = this._triggerArray[i]
const selector = Util.getSelectorFromElement(trigger)
if (selector !== null) {
const $elem = $(selector)
if (!$elem.hasClass(ClassName.SHOW)) {
$(trigger).addClass(ClassName.COLLAPSED)
.attr('aria-expanded', false)
}
}
}
}
this.setTransitioning(true)
@@ -300,7 +305,6 @@ const Collapse = (($) => {
_addAriaAndCollapsedClass(element, triggerArray) {
if (element) {
const isOpen = $(element).hasClass(ClassName.SHOW)
element.setAttribute('aria-expanded', isOpen)
if (triggerArray.length) {
$(triggerArray)
@@ -357,13 +361,18 @@ const Collapse = (($) => {
*/
$(document).on(Event.CLICK_DATA_API, Selector.DATA_TOGGLE, function (event) {
event.preventDefault()
if (!/input|textarea/i.test(event.target.tagName)) {
event.preventDefault()
}
const target = Collapse._getTargetFromElement(this)
const data = $(target).data(DATA_KEY)
const config = data ? 'toggle' : $(this).data()
Collapse._jQueryInterface.call($(target), config)
const $trigger = $(this)
const selector = Util.getSelectorFromElement(this)
$(selector).each(function () {
const $target = $(this)
const data = $target.data(DATA_KEY)
const config = data ? 'toggle' : $trigger.data()
Collapse._jQueryInterface.call($target, config)
})
})
+202 -55
View File
@@ -1,15 +1,24 @@
/* global Popper */
import Util from './util'
/**
* --------------------------------------------------------------------------
* Bootstrap (v4.0.0-alpha.6): dropdown.js
* Bootstrap (v4.0.0-beta): dropdown.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* --------------------------------------------------------------------------
*/
const Dropdown = (($) => {
/**
* Check for Popper dependency
* Popper - https://popper.js.org
*/
if (typeof Popper === 'undefined') {
throw new Error('Bootstrap dropdown require Popper.js (https://popper.js.org)')
}
/**
* ------------------------------------------------------------------------
@@ -18,15 +27,18 @@ const Dropdown = (($) => {
*/
const NAME = 'dropdown'
const VERSION = '4.0.0-alpha.6'
const VERSION = '4.0.0-beta'
const DATA_KEY = 'bs.dropdown'
const EVENT_KEY = `.${DATA_KEY}`
const DATA_API_KEY = '.data-api'
const JQUERY_NO_CONFLICT = $.fn[NAME]
const ESCAPE_KEYCODE = 27 // KeyboardEvent.which value for Escape (Esc) key
const SPACE_KEYCODE = 32 // KeyboardEvent.which value for space key
const TAB_KEYCODE = 9 // KeyboardEvent.which value for tab key
const ARROW_UP_KEYCODE = 38 // KeyboardEvent.which value for up arrow key
const ARROW_DOWN_KEYCODE = 40 // KeyboardEvent.which value for down arrow key
const RIGHT_MOUSE_BUTTON_WHICH = 3 // MouseEvent.which value for the right button (assuming a right-handed mouse)
const REGEXP_KEYDOWN = new RegExp(`${ARROW_UP_KEYCODE}|${ARROW_DOWN_KEYCODE}|${ESCAPE_KEYCODE}`)
const Event = {
HIDE : `hide${EVENT_KEY}`,
@@ -35,25 +47,43 @@ const Dropdown = (($) => {
SHOWN : `shown${EVENT_KEY}`,
CLICK : `click${EVENT_KEY}`,
CLICK_DATA_API : `click${EVENT_KEY}${DATA_API_KEY}`,
FOCUSIN_DATA_API : `focusin${EVENT_KEY}${DATA_API_KEY}`,
KEYDOWN_DATA_API : `keydown${EVENT_KEY}${DATA_API_KEY}`
KEYDOWN_DATA_API : `keydown${EVENT_KEY}${DATA_API_KEY}`,
KEYUP_DATA_API : `keyup${EVENT_KEY}${DATA_API_KEY}`
}
const ClassName = {
BACKDROP : 'dropdown-backdrop',
DISABLED : 'disabled',
SHOW : 'show'
DISABLED : 'disabled',
SHOW : 'show',
DROPUP : 'dropup',
MENURIGHT : 'dropdown-menu-right',
MENULEFT : 'dropdown-menu-left'
}
const Selector = {
BACKDROP : '.dropdown-backdrop',
DATA_TOGGLE : '[data-toggle="dropdown"]',
FORM_CHILD : '.dropdown form',
ROLE_MENU : '[role="menu"]',
ROLE_LISTBOX : '[role="listbox"]',
MENU : '.dropdown-menu',
NAVBAR_NAV : '.navbar-nav',
VISIBLE_ITEMS : '[role="menu"] li:not(.disabled) a, '
+ '[role="listbox"] li:not(.disabled) a'
VISIBLE_ITEMS : '.dropdown-menu .dropdown-item:not(.disabled)'
}
const AttachmentMap = {
TOP : 'top-start',
TOPEND : 'top-end',
BOTTOM : 'bottom-start',
BOTTOMEND : 'bottom-end'
}
const Default = {
placement : AttachmentMap.BOTTOM,
offset : 0,
flip : true
}
const DefaultType = {
placement : 'string',
offset : '(number|string)',
flip : 'boolean'
}
@@ -65,8 +95,12 @@ const Dropdown = (($) => {
class Dropdown {
constructor(element) {
this._element = element
constructor(element, config) {
this._element = element
this._popper = null
this._config = this._getConfig(config)
this._menu = this._getMenuElement()
this._inNavbar = this._detectNavbar()
this._addEventListeners()
}
@@ -78,75 +112,177 @@ const Dropdown = (($) => {
return VERSION
}
static get Default() {
return Default
}
static get DefaultType() {
return DefaultType
}
// public
toggle() {
if (this.disabled || $(this).hasClass(ClassName.DISABLED)) {
return false
if (this._element.disabled || $(this._element).hasClass(ClassName.DISABLED)) {
return
}
const parent = Dropdown._getParentFromElement(this)
const isActive = $(parent).hasClass(ClassName.SHOW)
const parent = Dropdown._getParentFromElement(this._element)
const isActive = $(this._menu).hasClass(ClassName.SHOW)
Dropdown._clearMenus()
if (isActive) {
return false
}
if ('ontouchstart' in document.documentElement &&
!$(parent).closest(Selector.NAVBAR_NAV).length) {
// if mobile we use a backdrop because click events don't delegate
const dropdown = document.createElement('div')
dropdown.className = ClassName.BACKDROP
$(dropdown).insertBefore(this)
$(dropdown).on('click', Dropdown._clearMenus)
return
}
const relatedTarget = {
relatedTarget : this
relatedTarget : this._element
}
const showEvent = $.Event(Event.SHOW, relatedTarget)
const showEvent = $.Event(Event.SHOW, relatedTarget)
$(parent).trigger(showEvent)
if (showEvent.isDefaultPrevented()) {
return false
return
}
this.focus()
this.setAttribute('aria-expanded', true)
let element = this._element
// for dropup with alignment we use the parent as popper container
if ($(parent).hasClass(ClassName.DROPUP)) {
if ($(this._menu).hasClass(ClassName.MENULEFT) || $(this._menu).hasClass(ClassName.MENURIGHT)) {
element = parent
}
}
this._popper = new Popper(element, this._menu, this._getPopperConfig())
$(parent).toggleClass(ClassName.SHOW)
$(parent).trigger($.Event(Event.SHOWN, relatedTarget))
// if this is a touch-enabled device we add extra
// empty mouseover listeners to the body's immediate children;
// only needed because of broken event delegation on iOS
// https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html
if ('ontouchstart' in document.documentElement &&
!$(parent).closest(Selector.NAVBAR_NAV).length) {
$('body').children().on('mouseover', null, $.noop)
}
return false
this._element.focus()
this._element.setAttribute('aria-expanded', true)
$(this._menu).toggleClass(ClassName.SHOW)
$(parent)
.toggleClass(ClassName.SHOW)
.trigger($.Event(Event.SHOWN, relatedTarget))
}
dispose() {
$.removeData(this._element, DATA_KEY)
$(this._element).off(EVENT_KEY)
this._element = null
this._menu = null
if (this._popper !== null) {
this._popper.destroy()
}
this._popper = null
}
update() {
this._inNavbar = this._detectNavbar()
if (this._popper !== null) {
this._popper.scheduleUpdate()
}
}
// private
_addEventListeners() {
$(this._element).on(Event.CLICK, this.toggle)
$(this._element).on(Event.CLICK, (event) => {
event.preventDefault()
event.stopPropagation()
this.toggle()
})
}
_getConfig(config) {
const elementData = $(this._element).data()
if (elementData.placement !== undefined) {
elementData.placement = AttachmentMap[elementData.placement.toUpperCase()]
}
config = $.extend(
{},
this.constructor.Default,
$(this._element).data(),
config
)
Util.typeCheckConfig(
NAME,
config,
this.constructor.DefaultType
)
return config
}
_getMenuElement() {
if (!this._menu) {
const parent = Dropdown._getParentFromElement(this._element)
this._menu = $(parent).find(Selector.MENU)[0]
}
return this._menu
}
_getPlacement() {
const $parentDropdown = $(this._element).parent()
let placement = this._config.placement
// Handle dropup
if ($parentDropdown.hasClass(ClassName.DROPUP) || this._config.placement === AttachmentMap.TOP) {
placement = AttachmentMap.TOP
if ($(this._menu).hasClass(ClassName.MENURIGHT)) {
placement = AttachmentMap.TOPEND
}
} else if ($(this._menu).hasClass(ClassName.MENURIGHT)) {
placement = AttachmentMap.BOTTOMEND
}
return placement
}
_detectNavbar() {
return $(this._element).closest('.navbar').length > 0
}
_getPopperConfig() {
const popperConfig = {
placement : this._getPlacement(),
modifiers : {
offset : {
offset : this._config.offset
},
flip : {
enabled : this._config.flip
}
}
}
// Disable Popper.js for Dropdown in Navbar
if (this._inNavbar) {
popperConfig.modifiers.applyStyle = {
enabled: !this._inNavbar
}
}
return popperConfig
}
// static
static _jQueryInterface(config) {
return this.each(function () {
let data = $(this).data(DATA_KEY)
const _config = typeof config === 'object' ? config : null
if (!data) {
data = new Dropdown(this)
data = new Dropdown(this, _config)
$(this).data(DATA_KEY, data)
}
@@ -154,35 +290,36 @@ const Dropdown = (($) => {
if (data[config] === undefined) {
throw new Error(`No method named "${config}"`)
}
data[config].call(this)
data[config]()
}
})
}
static _clearMenus(event) {
if (event && event.which === RIGHT_MOUSE_BUTTON_WHICH) {
if (event && (event.which === RIGHT_MOUSE_BUTTON_WHICH ||
event.type === 'keyup' && event.which !== TAB_KEYCODE)) {
return
}
const backdrop = $(Selector.BACKDROP)[0]
if (backdrop) {
backdrop.parentNode.removeChild(backdrop)
}
const toggles = $.makeArray($(Selector.DATA_TOGGLE))
for (let i = 0; i < toggles.length; i++) {
const parent = Dropdown._getParentFromElement(toggles[i])
const context = $(toggles[i]).data(DATA_KEY)
const relatedTarget = {
relatedTarget : toggles[i]
}
if (!context) {
continue
}
const dropdownMenu = context._menu
if (!$(parent).hasClass(ClassName.SHOW)) {
continue
}
if (event && (event.type === 'click' &&
/input|textarea/i.test(event.target.tagName) || event.type === 'focusin')
/input|textarea/i.test(event.target.tagName) || event.type === 'keyup' && event.which === TAB_KEYCODE)
&& $.contains(parent, event.target)) {
continue
}
@@ -193,8 +330,15 @@ const Dropdown = (($) => {
continue
}
// if this is a touch-enabled device we remove the extra
// empty mouseover listeners we added for iOS support
if ('ontouchstart' in document.documentElement) {
$('body').children().off('mouseover', null, $.noop)
}
toggles[i].setAttribute('aria-expanded', 'false')
$(dropdownMenu).removeClass(ClassName.SHOW)
$(parent)
.removeClass(ClassName.SHOW)
.trigger($.Event(Event.HIDDEN, relatedTarget))
@@ -213,7 +357,7 @@ const Dropdown = (($) => {
}
static _dataApiKeydownHandler(event) {
if (!/(38|40|27|32)/.test(event.which) ||
if (!REGEXP_KEYDOWN.test(event.which) || /button/i.test(event.target.tagName) && event.which === SPACE_KEYCODE ||
/input|textarea/i.test(event.target.tagName)) {
return
}
@@ -228,8 +372,8 @@ const Dropdown = (($) => {
const parent = Dropdown._getParentFromElement(this)
const isActive = $(parent).hasClass(ClassName.SHOW)
if (!isActive && event.which !== ESCAPE_KEYCODE ||
isActive && event.which === ESCAPE_KEYCODE) {
if (!isActive && (event.which !== ESCAPE_KEYCODE || event.which !== SPACE_KEYCODE) ||
isActive && (event.which === ESCAPE_KEYCODE || event.which === SPACE_KEYCODE)) {
if (event.which === ESCAPE_KEYCODE) {
const toggle = $(parent).find(Selector.DATA_TOGGLE)[0]
@@ -274,10 +418,13 @@ const Dropdown = (($) => {
$(document)
.on(Event.KEYDOWN_DATA_API, Selector.DATA_TOGGLE, Dropdown._dataApiKeydownHandler)
.on(Event.KEYDOWN_DATA_API, Selector.ROLE_MENU, Dropdown._dataApiKeydownHandler)
.on(Event.KEYDOWN_DATA_API, Selector.ROLE_LISTBOX, Dropdown._dataApiKeydownHandler)
.on(`${Event.CLICK_DATA_API} ${Event.FOCUSIN_DATA_API}`, Dropdown._clearMenus)
.on(Event.CLICK_DATA_API, Selector.DATA_TOGGLE, Dropdown.prototype.toggle)
.on(Event.KEYDOWN_DATA_API, Selector.MENU, Dropdown._dataApiKeydownHandler)
.on(`${Event.CLICK_DATA_API} ${Event.KEYUP_DATA_API}`, Dropdown._clearMenus)
.on(Event.CLICK_DATA_API, Selector.DATA_TOGGLE, function (event) {
event.preventDefault()
event.stopPropagation()
Dropdown._jQueryInterface.call($(this), 'toggle')
})
.on(Event.CLICK_DATA_API, Selector.FORM_CHILD, (e) => {
e.stopPropagation()
})
+62 -29
View File
@@ -3,7 +3,7 @@ import Util from './util'
/**
* --------------------------------------------------------------------------
* Bootstrap (v4.0.0-alpha.6): modal.js
* Bootstrap (v4.0.0-beta): modal.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* --------------------------------------------------------------------------
*/
@@ -18,7 +18,7 @@ const Modal = (($) => {
*/
const NAME = 'modal'
const VERSION = '4.0.0-alpha.6'
const VERSION = '4.0.0-beta'
const DATA_KEY = 'bs.modal'
const EVENT_KEY = `.${DATA_KEY}`
const DATA_API_KEY = '.data-api'
@@ -67,7 +67,8 @@ const Modal = (($) => {
DIALOG : '.modal-dialog',
DATA_TOGGLE : '[data-toggle="modal"]',
DATA_DISMISS : '[data-dismiss="modal"]',
FIXED_CONTENT : '.fixed-top, .fixed-bottom, .is-fixed, .sticky-top'
FIXED_CONTENT : '.fixed-top, .fixed-bottom, .is-fixed, .sticky-top',
NAVBAR_TOGGLER : '.navbar-toggler'
}
@@ -87,7 +88,6 @@ const Modal = (($) => {
this._isShown = false
this._isBodyOverflowing = false
this._ignoreBackdropClick = false
this._isTransitioning = false
this._originalBodyPadding = 0
this._scrollbarWidth = 0
}
@@ -112,13 +112,13 @@ const Modal = (($) => {
show(relatedTarget) {
if (this._isTransitioning) {
throw new Error('Modal is transitioning')
return
}
if (Util.supportsTransitionEnd() &&
$(this._element).hasClass(ClassName.FADE)) {
if (Util.supportsTransitionEnd() && $(this._element).hasClass(ClassName.FADE)) {
this._isTransitioning = true
}
const showEvent = $.Event(Event.SHOW, {
relatedTarget
})
@@ -161,17 +161,18 @@ const Modal = (($) => {
event.preventDefault()
}
if (this._isTransitioning) {
throw new Error('Modal is transitioning')
if (this._isTransitioning || !this._isShown) {
return
}
const transition = Util.supportsTransitionEnd() &&
$(this._element).hasClass(ClassName.FADE)
const transition = Util.supportsTransitionEnd() && $(this._element).hasClass(ClassName.FADE)
if (transition) {
this._isTransitioning = true
}
const hideEvent = $.Event(Event.HIDE)
$(this._element).trigger(hideEvent)
if (!this._isShown || hideEvent.isDefaultPrevented()) {
@@ -191,6 +192,7 @@ const Modal = (($) => {
$(this._dialog).off(Event.MOUSEDOWN_DISMISS)
if (transition) {
$(this._element)
.one(Util.TRANSITION_END, (event) => this._hideModal(event))
.emulateTransitionEnd(TRANSITION_DURATION)
@@ -211,10 +213,12 @@ const Modal = (($) => {
this._isShown = null
this._isBodyOverflowing = null
this._ignoreBackdropClick = null
this._originalBodyPadding = null
this._scrollbarWidth = null
}
handleUpdate() {
this._adjustDialog()
}
// private
@@ -285,6 +289,7 @@ const Modal = (($) => {
if (this._isShown && this._config.keyboard) {
$(this._element).on(Event.KEYDOWN_DISMISS, (event) => {
if (event.which === ESCAPE_KEYCODE) {
event.preventDefault()
this.hide()
}
})
@@ -296,7 +301,7 @@ const Modal = (($) => {
_setResizeEvent() {
if (this._isShown) {
$(window).on(Event.RESIZE, (event) => this._handleUpdate(event))
$(window).on(Event.RESIZE, (event) => this.handleUpdate(event))
} else {
$(window).off(Event.RESIZE)
}
@@ -304,7 +309,7 @@ const Modal = (($) => {
_hideModal() {
this._element.style.display = 'none'
this._element.setAttribute('aria-hidden', 'true')
this._element.setAttribute('aria-hidden', true)
this._isTransitioning = false
this._showBackdrop(() => {
$(document.body).removeClass(ClassName.OPEN)
@@ -401,10 +406,6 @@ const Modal = (($) => {
// todo (fat): these should probably be refactored out of modal.js
// ----------------------------------------------------------------------
_handleUpdate() {
this._adjustDialog()
}
_adjustDialog() {
const isModalOverflowing =
this._element.scrollHeight > document.documentElement.clientHeight
@@ -429,28 +430,60 @@ const Modal = (($) => {
}
_setScrollbar() {
const bodyPadding = parseInt(
$(Selector.FIXED_CONTENT).css('padding-right') || 0,
10
)
this._originalBodyPadding = document.body.style.paddingRight || ''
if (this._isBodyOverflowing) {
document.body.style.paddingRight =
`${bodyPadding + this._scrollbarWidth}px`
// Note: DOMNode.style.paddingRight returns the actual value or '' if not set
// while $(DOMNode).css('padding-right') returns the calculated value or 0 if not set
// Adjust fixed content padding
$(Selector.FIXED_CONTENT).each((index, element) => {
const actualPadding = $(element)[0].style.paddingRight
const calculatedPadding = $(element).css('padding-right')
$(element).data('padding-right', actualPadding).css('padding-right', `${parseFloat(calculatedPadding) + this._scrollbarWidth}px`)
})
// Adjust navbar-toggler margin
$(Selector.NAVBAR_TOGGLER).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 body padding
const actualPadding = document.body.style.paddingRight
const calculatedPadding = $('body').css('padding-right')
$('body').data('padding-right', actualPadding).css('padding-right', `${parseFloat(calculatedPadding) + this._scrollbarWidth}px`)
}
}
_resetScrollbar() {
document.body.style.paddingRight = this._originalBodyPadding
// Restore fixed content padding
$(Selector.FIXED_CONTENT).each((index, element) => {
const padding = $(element).data('padding-right')
if (typeof padding !== 'undefined') {
$(element).css('padding-right', padding).removeData('padding-right')
}
})
// Restore navbar-toggler margin
$(Selector.NAVBAR_TOGGLER).each((index, element) => {
const margin = $(element).data('margin-right')
if (typeof margin !== 'undefined') {
$(element).css('margin-right', margin).removeData('margin-right')
}
})
// Restore body padding
const padding = $('body').data('padding-right')
if (typeof padding !== 'undefined') {
$('body').css('padding-right', padding).removeData('padding-right')
}
}
_getScrollbarWidth() { // thx d.walsh
const scrollDiv = document.createElement('div')
scrollDiv.className = ClassName.SCROLLBAR_MEASURER
document.body.appendChild(scrollDiv)
const scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth
const scrollbarWidth = scrollDiv.getBoundingClientRect().width - scrollDiv.clientWidth
document.body.removeChild(scrollDiv)
return scrollbarWidth
}
+21 -8
View File
@@ -3,7 +3,7 @@ import Tooltip from './tooltip'
/**
* --------------------------------------------------------------------------
* Bootstrap (v4.0.0-alpha.6): popover.js
* Bootstrap (v4.0.0-beta): popover.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* --------------------------------------------------------------------------
*/
@@ -18,18 +18,21 @@ const Popover = (($) => {
*/
const NAME = 'popover'
const VERSION = '4.0.0-alpha.6'
const VERSION = '4.0.0-beta'
const DATA_KEY = 'bs.popover'
const EVENT_KEY = `.${DATA_KEY}`
const JQUERY_NO_CONFLICT = $.fn[NAME]
const CLASS_PREFIX = 'bs-popover'
const BSCLS_PREFIX_REGEX = new RegExp(`(^|\\s)${CLASS_PREFIX}\\S+`, 'g')
const Default = $.extend({}, Tooltip.Default, {
placement : 'right',
trigger : 'click',
content : '',
template : '<div class="popover" role="tooltip">'
+ '<h3 class="popover-title"></h3>'
+ '<div class="popover-content"></div></div>'
+ '<div class="arrow"></div>'
+ '<h3 class="popover-header"></h3>'
+ '<div class="popover-body"></div></div>'
})
const DefaultType = $.extend({}, Tooltip.DefaultType, {
@@ -42,8 +45,8 @@ const Popover = (($) => {
}
const Selector = {
TITLE : '.popover-title',
CONTENT : '.popover-content'
TITLE : '.popover-header',
CONTENT : '.popover-body'
}
const Event = {
@@ -106,6 +109,10 @@ const Popover = (($) => {
return this.getTitle() || this._getContent()
}
addAttachmentClass(attachment) {
$(this.getTipElement()).addClass(`${CLASS_PREFIX}-${attachment}`)
}
getTipElement() {
return this.tip = this.tip || $(this.config.template)[0]
}
@@ -118,8 +125,6 @@ const Popover = (($) => {
this.setElementContent($tip.find(Selector.CONTENT), this._getContent())
$tip.removeClass(`${ClassName.FADE} ${ClassName.SHOW}`)
this.cleanupTether()
}
// private
@@ -131,6 +136,14 @@ const Popover = (($) => {
this.config.content)
}
_cleanTipClass() {
const $tip = $(this.getTipElement())
const tabClass = $tip.attr('class').match(BSCLS_PREFIX_REGEX)
if (tabClass !== null && tabClass.length > 0) {
$tip.removeClass(tabClass.join(''))
}
}
// static
+20 -17
View File
@@ -3,7 +3,7 @@ import Util from './util'
/**
* --------------------------------------------------------------------------
* Bootstrap (v4.0.0-alpha.6): scrollspy.js
* Bootstrap (v4.0.0-beta): scrollspy.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* --------------------------------------------------------------------------
*/
@@ -18,7 +18,7 @@ const ScrollSpy = (($) => {
*/
const NAME = 'scrollspy'
const VERSION = '4.0.0-alpha.6'
const VERSION = '4.0.0-beta'
const DATA_KEY = 'bs.scrollspy'
const EVENT_KEY = `.${DATA_KEY}`
const DATA_API_KEY = '.data-api'
@@ -45,18 +45,15 @@ const ScrollSpy = (($) => {
const ClassName = {
DROPDOWN_ITEM : 'dropdown-item',
DROPDOWN_MENU : 'dropdown-menu',
NAV_LINK : 'nav-link',
NAV : 'nav',
ACTIVE : 'active'
}
const Selector = {
DATA_SPY : '[data-spy="scroll"]',
ACTIVE : '.active',
LIST_ITEM : '.list-item',
LI : 'li',
LI_DROPDOWN : 'li.dropdown',
NAV_LIST_GROUP : '.nav, .list-group',
NAV_LINKS : '.nav-link',
LIST_ITEMS : '.list-group-item',
DROPDOWN : '.dropdown',
DROPDOWN_ITEMS : '.dropdown-item',
DROPDOWN_TOGGLE : '.dropdown-toggle'
@@ -81,6 +78,7 @@ const ScrollSpy = (($) => {
this._scrollElement = element.tagName === 'BODY' ? window : element
this._config = this._getConfig(config)
this._selector = `${this._config.target} ${Selector.NAV_LINKS},`
+ `${this._config.target} ${Selector.LIST_ITEMS},`
+ `${this._config.target} ${Selector.DROPDOWN_ITEMS}`
this._offsets = []
this._targets = []
@@ -133,12 +131,15 @@ const ScrollSpy = (($) => {
target = $(targetSelector)[0]
}
if (target && (target.offsetWidth || target.offsetHeight)) {
// todo (fat): remove sketch reliance on jQuery position/offset
return [
$(target)[offsetMethod]().top + offsetBase,
targetSelector
]
if (target) {
const targetBCR = target.getBoundingClientRect()
if (targetBCR.width || targetBCR.height) {
// todo (fat): remove sketch reliance on jQuery position/offset
return [
$(target)[offsetMethod]().top + offsetBase,
targetSelector
]
}
}
return null
})
@@ -198,7 +199,7 @@ const ScrollSpy = (($) => {
_getOffsetHeight() {
return this._scrollElement === window ?
window.innerHeight : this._scrollElement.offsetHeight
window.innerHeight : this._scrollElement.getBoundingClientRect().height
}
_process() {
@@ -256,9 +257,11 @@ const ScrollSpy = (($) => {
$link.closest(Selector.DROPDOWN).find(Selector.DROPDOWN_TOGGLE).addClass(ClassName.ACTIVE)
$link.addClass(ClassName.ACTIVE)
} else {
// todo (fat) this is kinda sus...
// recursively add actives to tested nav-links
$link.parents(Selector.LI).find(`> ${Selector.NAV_LINKS}`).addClass(ClassName.ACTIVE)
// Set triggered link as active
$link.addClass(ClassName.ACTIVE)
// Set triggered links parents as active
// With both <ul> and <nav> markup a parent is the previous sibling of any nav ancestor
$link.parents(Selector.NAV_LIST_GROUP).prev(`${Selector.NAV_LINKS}, ${Selector.LIST_ITEMS}`).addClass(ClassName.ACTIVE)
}
$(this._scrollElement).trigger(Event.ACTIVATE, {
+8 -13
View File
@@ -3,7 +3,7 @@ import Util from './util'
/**
* --------------------------------------------------------------------------
* Bootstrap (v4.0.0-alpha.6): tab.js
* Bootstrap (v4.0.0-beta): tab.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* --------------------------------------------------------------------------
*/
@@ -18,7 +18,7 @@ const Tab = (($) => {
*/
const NAME = 'tab'
const VERSION = '4.0.0-alpha.6'
const VERSION = '4.0.0-beta'
const DATA_KEY = 'bs.tab'
const EVENT_KEY = `.${DATA_KEY}`
const DATA_API_KEY = '.data-api'
@@ -42,14 +42,10 @@ const Tab = (($) => {
}
const Selector = {
A : 'a',
LI : 'li',
DROPDOWN : '.dropdown',
LIST : 'ul:not(.dropdown-menu), ol:not(.dropdown-menu), nav:not(.dropdown-menu)',
FADE_CHILD : '> .nav-item .fade, > .fade',
NAV_LIST_GROUP : '.nav, .list-group',
ACTIVE : '.active',
ACTIVE_CHILD : '> .nav-item > .active, > .active',
DATA_TOGGLE : '[data-toggle="tab"], [data-toggle="pill"]',
DATA_TOGGLE : '[data-toggle="tab"], [data-toggle="pill"], [data-toggle="list"]',
DROPDOWN_TOGGLE : '.dropdown-toggle',
DROPDOWN_ACTIVE_CHILD : '> .dropdown-menu .active'
}
@@ -87,7 +83,7 @@ const Tab = (($) => {
let target
let previous
const listElement = $(this._element).closest(Selector.LIST)[0]
const listElement = $(this._element).closest(Selector.NAV_LIST_GROUP)[0]
const selector = Util.getSelectorFromElement(this._element)
if (listElement) {
@@ -144,7 +140,7 @@ const Tab = (($) => {
}
dispose() {
$.removeClass(this._element, DATA_KEY)
$.removeData(this._element, DATA_KEY)
this._element = null
}
@@ -152,11 +148,10 @@ const Tab = (($) => {
// private
_activate(element, container, callback) {
const active = $(container).find(Selector.ACTIVE_CHILD)[0]
const active = $(container).find(Selector.ACTIVE)[0]
const isTransitioning = callback
&& Util.supportsTransitionEnd()
&& (active && $(active).hasClass(ClassName.FADE)
|| Boolean($(container).find(Selector.FADE_CHILD)[0]))
&& (active && $(active).hasClass(ClassName.FADE))
const complete = () => this._transitionComplete(
element,
+147 -93
View File
@@ -1,11 +1,11 @@
/* global Tether */
/* global Popper */
import Util from './util'
/**
* --------------------------------------------------------------------------
* Bootstrap (v4.0.0-alpha.6): tooltip.js
* Bootstrap (v4.0.0-beta): tooltip.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* --------------------------------------------------------------------------
*/
@@ -13,11 +13,11 @@ import Util from './util'
const Tooltip = (($) => {
/**
* Check for Tether dependency
* Tether - http://tether.io/
* Check for Popper dependency
* Popper - https://popper.js.org
*/
if (typeof Tether === 'undefined') {
throw new Error('Bootstrap tooltips require Tether (http://tether.io/)')
if (typeof Popper === 'undefined') {
throw new Error('Bootstrap tooltips require Popper.js (https://popper.js.org)')
}
@@ -28,47 +28,50 @@ const Tooltip = (($) => {
*/
const NAME = 'tooltip'
const VERSION = '4.0.0-alpha.6'
const VERSION = '4.0.0-beta'
const DATA_KEY = 'bs.tooltip'
const EVENT_KEY = `.${DATA_KEY}`
const JQUERY_NO_CONFLICT = $.fn[NAME]
const TRANSITION_DURATION = 150
const CLASS_PREFIX = 'bs-tether'
const Default = {
animation : true,
template : '<div class="tooltip" role="tooltip">'
+ '<div class="tooltip-inner"></div></div>',
trigger : 'hover focus',
title : '',
delay : 0,
html : false,
selector : false,
placement : 'top',
offset : '0 0',
constraints : [],
container : false
}
const CLASS_PREFIX = 'bs-tooltip'
const BSCLS_PREFIX_REGEX = new RegExp(`(^|\\s)${CLASS_PREFIX}\\S+`, 'g')
const DefaultType = {
animation : 'boolean',
template : 'string',
title : '(string|element|function)',
trigger : 'string',
delay : '(number|object)',
html : 'boolean',
selector : '(string|boolean)',
placement : '(string|function)',
offset : 'string',
constraints : 'array',
container : '(string|element|boolean)'
animation : 'boolean',
template : 'string',
title : '(string|element|function)',
trigger : 'string',
delay : '(number|object)',
html : 'boolean',
selector : '(string|boolean)',
placement : '(string|function)',
offset : '(number|string)',
container : '(string|element|boolean)',
fallbackPlacement : '(string|array)'
}
const AttachmentMap = {
TOP : 'bottom center',
RIGHT : 'middle left',
BOTTOM : 'top center',
LEFT : 'middle right'
AUTO : 'auto',
TOP : 'top',
RIGHT : 'right',
BOTTOM : 'bottom',
LEFT : 'left'
}
const Default = {
animation : true,
template : '<div class="tooltip" role="tooltip">'
+ '<div class="arrow"></div>'
+ '<div class="tooltip-inner"></div></div>',
trigger : 'hover focus',
title : '',
delay : 0,
html : false,
selector : false,
placement : 'top',
offset : 0,
container : false,
fallbackPlacement : 'flip'
}
const HoverState = {
@@ -96,12 +99,8 @@ const Tooltip = (($) => {
const Selector = {
TOOLTIP : '.tooltip',
TOOLTIP_INNER : '.tooltip-inner'
}
const TetherClass = {
element : false,
enabled : false
TOOLTIP_INNER : '.tooltip-inner',
ARROW : '.arrow'
}
const Trigger = {
@@ -123,12 +122,11 @@ const Tooltip = (($) => {
constructor(element, config) {
// private
this._isEnabled = true
this._timeout = 0
this._hoverState = ''
this._activeTrigger = {}
this._isTransitioning = false
this._tether = null
this._isEnabled = true
this._timeout = 0
this._hoverState = ''
this._activeTrigger = {}
this._popper = null
// protected
this.element = element
@@ -220,8 +218,6 @@ const Tooltip = (($) => {
dispose() {
clearTimeout(this._timeout)
this.cleanupTether()
$.removeData(this.element, this.constructor.DATA_KEY)
$(this.element).off(this.constructor.EVENT_KEY)
@@ -235,7 +231,10 @@ const Tooltip = (($) => {
this._timeout = null
this._hoverState = null
this._activeTrigger = null
this._tether = null
if (this._popper !== null) {
this._popper.destroy()
}
this._popper = null
this.element = null
this.config = null
@@ -249,9 +248,6 @@ const Tooltip = (($) => {
const showEvent = $.Event(this.constructor.Event.SHOW)
if (this.isWithContent() && this._isEnabled) {
if (this._isTransitioning) {
throw new Error('Tooltip is transitioning')
}
$(this.element).trigger(showEvent)
const isInTheDom = $.contains(
@@ -280,35 +276,57 @@ const Tooltip = (($) => {
this.config.placement
const attachment = this._getAttachment(placement)
this.addAttachmentClass(attachment)
const container = this.config.container === false ? document.body : $(this.config.container)
$(tip)
.data(this.constructor.DATA_KEY, this)
.appendTo(container)
$(tip).data(this.constructor.DATA_KEY, this)
if (!$.contains(this.element.ownerDocument.documentElement, this.tip)) {
$(tip).appendTo(container)
}
$(this.element).trigger(this.constructor.Event.INSERTED)
this._tether = new Tether({
attachment,
element : tip,
target : this.element,
classes : TetherClass,
classPrefix : CLASS_PREFIX,
offset : this.config.offset,
constraints : this.config.constraints,
addTargetClasses: false
this._popper = new Popper(this.element, tip, {
placement: attachment,
modifiers: {
offset: {
offset: this.config.offset
},
flip: {
behavior: this.config.fallbackPlacement
},
arrow: {
element: Selector.ARROW
}
},
onCreate: (data) => {
if (data.originalPlacement !== data.placement) {
this._handlePopperPlacementChange(data)
}
},
onUpdate : (data) => {
this._handlePopperPlacementChange(data)
}
})
Util.reflow(tip)
this._tether.position()
$(tip).addClass(ClassName.SHOW)
// if this is a touch-enabled device we add extra
// empty mouseover listeners to the body's immediate children;
// only needed because of broken event delegation on iOS
// https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html
if ('ontouchstart' in document.documentElement) {
$('body').children().on('mouseover', null, $.noop)
}
const complete = () => {
if (this.config.animation) {
this._fixTransition()
}
const prevHoverState = this._hoverState
this._hoverState = null
this._isTransitioning = false
this._hoverState = null
$(this.element).trigger(this.constructor.Event.SHOWN)
@@ -318,32 +336,29 @@ const Tooltip = (($) => {
}
if (Util.supportsTransitionEnd() && $(this.tip).hasClass(ClassName.FADE)) {
this._isTransitioning = true
$(this.tip)
.one(Util.TRANSITION_END, complete)
.emulateTransitionEnd(Tooltip._TRANSITION_DURATION)
return
} else {
complete()
}
complete()
}
}
hide(callback) {
const tip = this.getTipElement()
const hideEvent = $.Event(this.constructor.Event.HIDE)
if (this._isTransitioning) {
throw new Error('Tooltip is transitioning')
}
const complete = () => {
if (this._hoverState !== HoverState.SHOW && tip.parentNode) {
tip.parentNode.removeChild(tip)
}
this._cleanTipClass()
this.element.removeAttribute('aria-describedby')
$(this.element).trigger(this.constructor.Event.HIDDEN)
this._isTransitioning = false
this.cleanupTether()
if (this._popper !== null) {
this._popper.destroy()
}
if (callback) {
callback()
@@ -358,13 +373,19 @@ const Tooltip = (($) => {
$(tip).removeClass(ClassName.SHOW)
// if this is a touch-enabled device we remove the extra
// empty mouseover listeners we added for iOS support
if ('ontouchstart' in document.documentElement) {
$('body').children().off('mouseover', null, $.noop)
}
this._activeTrigger[Trigger.CLICK] = false
this._activeTrigger[Trigger.FOCUS] = false
this._activeTrigger[Trigger.HOVER] = false
if (Util.supportsTransitionEnd() &&
$(this.tip).hasClass(ClassName.FADE)) {
this._isTransitioning = true
$(tip)
.one(Util.TRANSITION_END, complete)
.emulateTransitionEnd(TRANSITION_DURATION)
@@ -374,8 +395,14 @@ const Tooltip = (($) => {
}
this._hoverState = ''
}
update() {
if (this._popper !== null) {
this._popper.scheduleUpdate()
}
}
// protected
@@ -383,18 +410,18 @@ const Tooltip = (($) => {
return Boolean(this.getTitle())
}
addAttachmentClass(attachment) {
$(this.getTipElement()).addClass(`${CLASS_PREFIX}-${attachment}`)
}
getTipElement() {
return this.tip = this.tip || $(this.config.template)[0]
}
setContent() {
const $tip = $(this.getTipElement())
this.setElementContent($tip.find(Selector.TOOLTIP_INNER), this.getTitle())
$tip.removeClass(`${ClassName.FADE} ${ClassName.SHOW}`)
this.cleanupTether()
}
setElementContent($element, content) {
@@ -425,12 +452,6 @@ const Tooltip = (($) => {
return title
}
cleanupTether() {
if (this._tether) {
this._tether.destroy()
}
}
// private
@@ -603,6 +624,14 @@ const Tooltip = (($) => {
}
}
if (config.title && typeof config.title === 'number') {
config.title = config.title.toString()
}
if (config.content && typeof config.content === 'number') {
config.content = config.content.toString()
}
Util.typeCheckConfig(
NAME,
config,
@@ -626,6 +655,31 @@ const Tooltip = (($) => {
return config
}
_cleanTipClass() {
const $tip = $(this.getTipElement())
const tabClass = $tip.attr('class').match(BSCLS_PREFIX_REGEX)
if (tabClass !== null && tabClass.length > 0) {
$tip.removeClass(tabClass.join(''))
}
}
_handlePopperPlacementChange(data) {
this._cleanTipClass()
this.addAttachmentClass(this._getAttachment(data.placement))
}
_fixTransition() {
const tip = this.getTipElement()
const initConfigAnimation = this.config.animation
if (tip.getAttribute('x-placement') !== null) {
return
}
$(tip).removeClass(ClassName.FADE)
this.config.animation = false
this.hide()
this.show()
this.config.animation = initConfigAnimation
}
// static
+8 -5
View File
@@ -1,6 +1,6 @@
/**
* --------------------------------------------------------------------------
* Bootstrap (v4.0.0-alpha.6): util.js
* Bootstrap (v4.0.0-beta): util.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* --------------------------------------------------------------------------
*/
@@ -112,13 +112,16 @@ const Util = (($) => {
getSelectorFromElement(element) {
let selector = element.getAttribute('data-target')
if (!selector) {
if (!selector || selector === '#') {
selector = element.getAttribute('href') || ''
selector = /^#[a-z]/i.test(selector) ? selector : null
}
return selector
try {
const $selector = $(selector)
return $selector.length > 0 ? selector : null
} catch (error) {
return null
}
},
reflow(element) {
+2 -2
View File
@@ -6,7 +6,7 @@ Bootstrap uses [QUnit](https://qunitjs.com/), a powerful, easy-to-use JavaScript
* `vendor/` contains third-party testing-related code (QUnit and jQuery).
* `visual/` contains "visual" tests which are run interactively in real browsers and require manual verification by humans.
To run the unit test suite via [PhantomJS](http://phantomjs.org/), run `grunt test-js`.
To run the unit test suite via [PhantomJS](http://phantomjs.org/), run `npm run js-test`.
To run the unit test suite via a real web browser, open `index.html` in the browser.
@@ -16,7 +16,7 @@ To run the unit test suite via a real web browser, open `index.html` in the brow
1. Locate and open the file dedicated to the plugin which you need to add tests to (`unit/<plugin-name>.js`).
2. Review the [QUnit API Documentation](https://api.qunitjs.com/) and use the existing tests as references for how to structure your new tests.
3. Write the necessary unit test(s) for the new or revised functionality.
4. Run `grunt test-js` to see the results of your newly-added test(s).
4. Run `npm run js-test` to see the results of your newly-added test(s).
**Note:** Your new unit tests should fail before your changes are applied to the plugin, and should pass after your changes are applied to the plugin.
+35
View File
@@ -138,4 +138,39 @@ $(function () {
assert.ok($btn2.find('input').prop('checked'), 'btn2 is checked')
})
QUnit.test('should not add aria-pressed on labels for radio/checkbox inputs in a data-toggle="buttons" group', function (assert) {
assert.expect(2)
var groupHTML = '<div class="btn-group" data-toggle="buttons">'
+ '<label class="btn btn-primary"><input type="checkbox" autocomplete="off"> Checkbox</label>'
+ '<label class="btn btn-primary"><input type="radio" name="options" autocomplete="off"> Radio</label>'
+ '</div>'
var $group = $(groupHTML).appendTo('#qunit-fixture')
var $btn1 = $group.children().eq(0)
var $btn2 = $group.children().eq(1)
$btn1.find('input').trigger('click')
assert.ok($btn1.is(':not([aria-pressed])'), 'label for nested checkbox input has not been given an aria-pressed attribute')
$btn2.find('input').trigger('click')
assert.ok($btn2.is(':not([aria-pressed])'), 'label for nested radio input has not been given an aria-pressed attribute')
})
QUnit.test('should handle disabled attribute on non-button elements', function (assert) {
assert.expect(2)
var groupHTML = ' <div class="btn-group disabled" data-toggle="buttons" aria-disabled="true" disabled>'
+ '<label class="btn btn-danger disabled" aria-disabled="true" disabled>'
+ '<input type="checkbox" aria-disabled="true" autocomplete="off" disabled class="disabled"/>'
+ '</label>'
+ '</div>'
var $group = $(groupHTML).appendTo('#qunit-fixture')
var $btn = $group.children().eq(0)
var $input = $btn.children().eq(0)
$btn.trigger('click')
assert.ok($btn.is(':not(.active)'), 'button did not become active')
assert.ok(!$input.is(':checked'), 'checkbox did not get checked')
})
})
+43 -23
View File
@@ -341,6 +341,49 @@ $(function () {
.bootstrapCarousel('next')
})
QUnit.test('should fire slid and slide events with from and to', function (assert) {
assert.expect(4)
var template = '<div id="myCarousel" class="carousel slide">'
+ '<div class="carousel-inner">'
+ '<div class="carousel-item active">'
+ '<img alt="">'
+ '<div class="carousel-caption">'
+ '<h4>First Thumbnail label</h4>'
+ '</div>'
+ '</div>'
+ '<div class="carousel-item">'
+ '<img alt="">'
+ '<div class="carousel-caption">'
+ '<h4>Second Thumbnail label</h4>'
+ '</div>'
+ '</div>'
+ '<div class="carousel-item">'
+ '<img alt="">'
+ '<div class="carousel-caption">'
+ '<h4>Third Thumbnail label</h4>'
+ '</div>'
+ '</div>'
+ '</div>'
+ '<a class="left carousel-control" href="#myCarousel" data-slide="prev">&lsaquo;</a>'
+ '<a class="right carousel-control" href="#myCarousel" data-slide="next">&rsaquo;</a>'
+ '</div>'
var done = assert.async()
$(template)
.on('slid.bs.carousel', function (e) {
assert.ok(e.from !== undefined, 'from present')
assert.ok(e.to !== undefined, 'to present')
$(this).off()
done()
})
.on('slide.bs.carousel', function (e) {
assert.ok(e.from !== undefined, 'from present')
assert.ok(e.to !== undefined, 'to present')
$(this).off('slide.bs.carousel')
})
.bootstrapCarousel('next')
})
QUnit.test('should set interval from data attribute', function (assert) {
assert.expect(4)
var templateHTML = '<div id="myCarousel" class="carousel slide">'
@@ -611,29 +654,6 @@ $(function () {
assert.strictEqual($template.find('.carousel-item')[0], $template.find('.active')[0], 'first item still active after left arrow press in <textarea>')
})
QUnit.test('should only add mouseenter and mouseleave listeners when not on mobile', function (assert) {
assert.expect(2)
var isMobile = 'ontouchstart' in document.documentElement
var templateHTML = '<div id="myCarousel" class="carousel" data-interval="false" data-pause="hover">'
+ '<div class="carousel-inner">'
+ '<div id="first" class="carousel-item active">'
+ '<img alt="">'
+ '</div>'
+ '<div id="second" class="carousel-item">'
+ '<img alt="">'
+ '</div>'
+ '<div id="third" class="carousel-item">'
+ '<img alt="">'
+ '</div>'
+ '</div>'
+ '</div>'
var $template = $(templateHTML).bootstrapCarousel()
$.each(['mouseover', 'mouseout'], function (i, type) {
assert.strictEqual(type in $._data($template[0], 'events'), !isMobile, 'does' + (isMobile ? ' not' : '') + ' listen for ' + type + ' events')
})
})
QUnit.test('should wrap around from end to start when wrap option is true', function (assert) {
assert.expect(3)
var carouselHTML = '<div id="carousel-example-generic" class="carousel slide" data-wrap="true">'
+219 -36
View File
@@ -52,8 +52,28 @@ $(function () {
assert.ok(!/height/i.test($el.attr('style')), 'has height reset')
})
QUnit.test('should show multiple collapsed elements', function (assert) {
assert.expect(4)
var done = assert.async()
var $target = $('<a role="button" data-toggle="collapse" class="collapsed" href=".multi"/>').appendTo('#qunit-fixture')
var $el = $('<div class="collapse multi"/>').appendTo('#qunit-fixture')
var $el2 = $('<div class="collapse multi"/>').appendTo('#qunit-fixture')
$el.one('shown.bs.collapse', function () {
assert.ok($el.hasClass('show'), 'has class "show"')
assert.ok(!/height/i.test($el.attr('style')), 'has height reset')
})
$el2.one('shown.bs.collapse', function () {
assert.ok($el2.hasClass('show'), 'has class "show"')
assert.ok(!/height/i.test($el2.attr('style')), 'has height reset')
done()
})
$target.trigger('click')
})
QUnit.test('should collapse only the first collapse', function (assert) {
assert.expect(2)
var done = assert.async()
var html = [
'<div class="panel-group" id="accordion1">',
'<div class="panel">',
@@ -69,10 +89,11 @@ $(function () {
$(html).appendTo('#qunit-fixture')
var $el1 = $('#collapse1')
var $el2 = $('#collapse2')
$el1.bootstrapCollapse('show')
assert.ok($el1.hasClass('show'))
assert.ok($el2.hasClass('show'))
$el1.one('shown.bs.collapse', function () {
assert.ok($el1.hasClass('show'))
assert.ok($el2.hasClass('show'))
done()
}).bootstrapCollapse('show')
})
QUnit.test('should hide a collapsed element', function (assert) {
@@ -265,17 +286,17 @@ $(function () {
+ '</div>'
var $groups = $(accordionHTML).appendTo('#qunit-fixture').find('.card')
var $target1 = $('<a role="button" data-toggle="collapse" href="#body1" data-parent="#accordion"/>').appendTo($groups.eq(0))
var $target1 = $('<a role="button" data-toggle="collapse" href="#body1" />').appendTo($groups.eq(0))
$('<div id="body1" class="show"/>').appendTo($groups.eq(0))
$('<div id="body1" class="show" data-parent="#accordion"/>').appendTo($groups.eq(0))
var $target2 = $('<a class="collapsed" data-toggle="collapse" role="button" href="#body2" data-parent="#accordion"/>').appendTo($groups.eq(1))
var $target2 = $('<a class="collapsed" data-toggle="collapse" role="button" href="#body2" />').appendTo($groups.eq(1))
$('<div id="body2"/>').appendTo($groups.eq(1))
$('<div id="body2" data-parent="#accordion"/>').appendTo($groups.eq(1))
var $target3 = $('<a class="collapsed" data-toggle="collapse" role="button" href="#body3" data-parent="#accordion"/>').appendTo($groups.eq(2))
var $target3 = $('<a class="collapsed" data-toggle="collapse" role="button" href="#body3" />').appendTo($groups.eq(2))
$('<div id="body3"/>')
$('<div id="body3" data-parent="#accordion"/>')
.appendTo($groups.eq(2))
.on('shown.bs.collapse', function () {
assert.ok($target1.hasClass('collapsed'), 'inactive target 1 does have class "collapsed"')
@@ -299,17 +320,17 @@ $(function () {
+ '</div>'
var $groups = $(accordionHTML).appendTo('#qunit-fixture').find('.card')
var $target1 = $('<a role="button" data-toggle="collapse" href="#body1" data-parent=".accordion"/>').appendTo($groups.eq(0))
var $target1 = $('<a role="button" data-toggle="collapse" href="#body1"/>').appendTo($groups.eq(0))
$('<div id="body1" class="show"/>').appendTo($groups.eq(0))
$('<div id="body1" class="show" data-parent=".accordion"/>').appendTo($groups.eq(0))
var $target2 = $('<a class="collapsed" data-toggle="collapse" role="button" href="#body2" data-parent=".accordion"/>').appendTo($groups.eq(1))
var $target2 = $('<a class="collapsed" data-toggle="collapse" role="button" href="#body2"/>').appendTo($groups.eq(1))
$('<div id="body2"/>').appendTo($groups.eq(1))
$('<div id="body2" data-parent=".accordion"/>').appendTo($groups.eq(1))
var $target3 = $('<a class="collapsed" data-toggle="collapse" role="button" href="#body3" data-parent=".accordion"/>').appendTo($groups.eq(2))
var $target3 = $('<a class="collapsed" data-toggle="collapse" role="button" href="#body3"/>').appendTo($groups.eq(2))
$('<div id="body3"/>')
$('<div id="body3" data-parent=".accordion"/>')
.appendTo($groups.eq(2))
.on('shown.bs.collapse', function () {
assert.ok($target1.hasClass('collapsed'), 'inactive target 1 does have class "collapsed"')
@@ -322,7 +343,7 @@ $(function () {
$target3.trigger('click')
})
QUnit.test('should set aria-expanded="true" on target when collapse is shown', function (assert) {
QUnit.test('should set aria-expanded="true" on trigger/control when collapse is shown', function (assert) {
assert.expect(1)
var done = assert.async()
@@ -338,7 +359,7 @@ $(function () {
$target.trigger('click')
})
QUnit.test('should set aria-expanded="false" on target when collapse is hidden', function (assert) {
QUnit.test('should set aria-expanded="false" on trigger/control when collapse is hidden', function (assert) {
assert.expect(1)
var done = assert.async()
@@ -364,8 +385,8 @@ $(function () {
$('<div id="test1"/>')
.appendTo('#qunit-fixture')
.on('shown.bs.collapse', function () {
assert.strictEqual($target.attr('aria-expanded'), 'true', 'aria-expanded on target is "true"')
assert.strictEqual($alt.attr('aria-expanded'), 'true', 'aria-expanded on alt is "true"')
assert.strictEqual($target.attr('aria-expanded'), 'true', 'aria-expanded on trigger/control is "true"')
assert.strictEqual($alt.attr('aria-expanded'), 'true', 'aria-expanded on alternative trigger/control is "true"')
done()
})
@@ -382,15 +403,15 @@ $(function () {
$('<div id="test1" class="show"/>')
.appendTo('#qunit-fixture')
.on('hidden.bs.collapse', function () {
assert.strictEqual($target.attr('aria-expanded'), 'false', 'aria-expanded on target is "false"')
assert.strictEqual($alt.attr('aria-expanded'), 'false', 'aria-expanded on alt is "false"')
assert.strictEqual($target.attr('aria-expanded'), 'false', 'aria-expanded on trigger/control is "false"')
assert.strictEqual($alt.attr('aria-expanded'), 'false', 'aria-expanded on alternative trigger/control is "false"')
done()
})
$target.trigger('click')
})
QUnit.test('should change aria-expanded from active accordion target to "false" and set the newly active one to "true"', function (assert) {
QUnit.test('should change aria-expanded from active accordion trigger/control to "false" and set the trigger/control for the newly active one to "true"', function (assert) {
assert.expect(3)
var done = assert.async()
@@ -401,22 +422,22 @@ $(function () {
+ '</div>'
var $groups = $(accordionHTML).appendTo('#qunit-fixture').find('.card')
var $target1 = $('<a role="button" data-toggle="collapse" href="#body1" data-parent="#accordion"/>').appendTo($groups.eq(0))
var $target1 = $('<a role="button" data-toggle="collapse" aria-expanded="true" href="#body1"/>').appendTo($groups.eq(0))
$('<div id="body1" aria-expanded="true" class="show"/>').appendTo($groups.eq(0))
$('<div id="body1" class="show" data-parent="#accordion"/>').appendTo($groups.eq(0))
var $target2 = $('<a role="button" data-toggle="collapse" href="#body2" data-parent="#accordion" class="collapsed" />').appendTo($groups.eq(1))
var $target2 = $('<a role="button" data-toggle="collapse" aria-expanded="false" href="#body2" class="collapsed" aria-expanded="false" />').appendTo($groups.eq(1))
$('<div id="body2" aria-expanded="false"/>').appendTo($groups.eq(1))
$('<div id="body2" data-parent="#accordion"/>').appendTo($groups.eq(1))
var $target3 = $('<a class="collapsed" data-toggle="collapse" role="button" href="#body3" data-parent="#accordion"/>').appendTo($groups.eq(2))
var $target3 = $('<a class="collapsed" data-toggle="collapse" aria-expanded="false" role="button" href="#body3"/>').appendTo($groups.eq(2))
$('<div id="body3" aria-expanded="false"/>')
$('<div id="body3" data-parent="#accordion"/>')
.appendTo($groups.eq(2))
.on('shown.bs.collapse', function () {
assert.strictEqual($target1.attr('aria-expanded'), 'false', 'inactive target 1 has aria-expanded="false"')
assert.strictEqual($target2.attr('aria-expanded'), 'false', 'inactive target 2 has aria-expanded="false"')
assert.strictEqual($target3.attr('aria-expanded'), 'true', 'active target 3 has aria-expanded="false"')
assert.strictEqual($target1.attr('aria-expanded'), 'false', 'inactive trigger/control 1 has aria-expanded="false"')
assert.strictEqual($target2.attr('aria-expanded'), 'false', 'inactive trigger/control 2 has aria-expanded="false"')
assert.strictEqual($target3.attr('aria-expanded'), 'true', 'active trigger/control 3 has aria-expanded="true"')
done()
})
@@ -435,16 +456,16 @@ $(function () {
var showFired = false
var $groups = $(accordionHTML).appendTo('#qunit-fixture').find('.card')
var $target1 = $('<a role="button" data-toggle="collapse" href="#body1" data-parent="#accordion"/>').appendTo($groups.eq(0))
var $target1 = $('<a role="button" data-toggle="collapse" href="#body1"/>').appendTo($groups.eq(0))
$('<div id="body1" class="collapse"/>')
$('<div id="body1" class="collapse" data-parent="#accordion"/>')
.appendTo($groups.eq(0))
.on('show.bs.collapse', function () {
showFired = true
})
var $target2 = $('<a role="button" data-toggle="collapse" href="#body2" data-parent="#accordion"/>').appendTo($groups.eq(1))
var $body2 = $('<div id="body2" class="collapse"/>').appendTo($groups.eq(1))
var $target2 = $('<a role="button" data-toggle="collapse" href="#body2"/>').appendTo($groups.eq(1))
var $body2 = $('<div id="body2" class="collapse" data-parent="#accordion"/>').appendTo($groups.eq(1))
$target2.trigger('click')
@@ -490,4 +511,166 @@ $(function () {
.bootstrapCollapse('show')
})
QUnit.test('should allow accordion to use children other than card', function (assert) {
assert.expect(4)
var done = assert.async()
var accordionHTML = '<div id="accordion">'
+ '<div class="item">'
+ '<a id="linkTrigger" data-parent="#accordion" data-toggle="collapse" href="#collapseOne" aria-expanded="false" aria-controls="collapseOne"></a>'
+ '<div id="collapseOne" class="collapse" role="tabpanel" aria-labelledby="headingThree"></div>'
+ '</div>'
+ '<div class="item">'
+ '<a id="linkTriggerTwo" data-toggle="collapse" data-parent="#accordion" href="#collapseTwo" aria-expanded="false" aria-controls="collapseTwo"></a>'
+ '<div id="collapseTwo" class="collapse show" role="tabpanel" aria-labelledby="headingTwo"></div>'
+ '</div>'
+ '</div>'
$(accordionHTML).appendTo('#qunit-fixture')
var $trigger = $('#linkTrigger')
var $triggerTwo = $('#linkTriggerTwo')
var $collapseOne = $('#collapseOne')
var $collapseTwo = $('#collapseTwo')
$collapseOne.on('shown.bs.collapse', function () {
assert.ok($collapseOne.hasClass('show'), '#collapseOne is shown')
assert.ok(!$collapseTwo.hasClass('show'), '#collapseTwo is not shown')
$collapseTwo.on('shown.bs.collapse', function () {
assert.ok(!$collapseOne.hasClass('show'), '#collapseOne is not shown')
assert.ok($collapseTwo.hasClass('show'), '#collapseTwo is shown')
done()
})
$triggerTwo.trigger($.Event('click'))
})
$trigger.trigger($.Event('click'))
})
QUnit.test('should collapse accordion children but not nested accordion children', function (assert) {
assert.expect(9)
var done = assert.async()
$('<div id="accordion">'
+ '<div class="item">'
+ '<a id="linkTrigger" data-parent="#accordion" data-toggle="collapse" href="#collapseOne" aria-expanded="false" aria-controls="collapseOne"></a>'
+ '<div id="collapseOne" class="collapse" role="tabpanel" aria-labelledby="headingThree">'
+ '<div id="nestedAccordion">'
+ '<div class="item">'
+ '<a id="nestedLinkTrigger" data-parent="#nestedAccordion" data-toggle="collapse" href="#nestedCollapseOne" aria-expanded="false" aria-controls="nestedCollapseOne"></a>'
+ '<div id="nestedCollapseOne" class="collapse" role="tabpanel" aria-labelledby="headingThree">'
+ '</div>'
+ '</div>'
+ '</div>'
+ '</div>'
+ '</div>'
+ '<div class="item">'
+ '<a id="linkTriggerTwo" data-toggle="collapse" data-parent="#accordion" href="#collapseTwo" aria-expanded="false" aria-controls="collapseTwo"></a>'
+ '<div id="collapseTwo" class="collapse show" role="tabpanel" aria-labelledby="headingTwo"></div>'
+ '</div>'
+ '</div>').appendTo('#qunit-fixture')
var $trigger = $('#linkTrigger')
var $triggerTwo = $('#linkTriggerTwo')
var $nestedTrigger = $('#nestedLinkTrigger')
var $collapseOne = $('#collapseOne')
var $collapseTwo = $('#collapseTwo')
var $nestedCollapseOne = $('#nestedCollapseOne')
$collapseOne.one('shown.bs.collapse', function () {
assert.ok($collapseOne.hasClass('show'), '#collapseOne is shown')
assert.ok(!$collapseTwo.hasClass('show'), '#collapseTwo is not shown')
assert.ok(!$('#nestedCollapseOne').hasClass('show'), '#nestedCollapseOne is not shown')
$nestedCollapseOne.one('shown.bs.collapse', function () {
assert.ok($collapseOne.hasClass('show'), '#collapseOne is shown')
assert.ok(!$collapseTwo.hasClass('show'), '#collapseTwo is not shown')
assert.ok($nestedCollapseOne.hasClass('show'), '#nestedCollapseOne is shown')
$collapseTwo.one('shown.bs.collapse', function () {
assert.ok(!$collapseOne.hasClass('show'), '#collapseOne is not shown')
assert.ok($collapseTwo.hasClass('show'), '#collapseTwo is shown')
assert.ok($nestedCollapseOne.hasClass('show'), '#nestedCollapseOne is shown')
done()
})
$triggerTwo.trigger($.Event('click'))
})
$nestedTrigger.trigger($.Event('click'))
})
$trigger.trigger($.Event('click'))
})
QUnit.test('should not prevent event for input', function (assert) {
assert.expect(3)
var done = assert.async()
var $target = $('<input type="checkbox" data-toggle="collapse" data-target="#collapsediv1" />').appendTo('#qunit-fixture')
$('<div id="collapsediv1"/>')
.appendTo('#qunit-fixture')
.on('shown.bs.collapse', function () {
assert.ok($(this).hasClass('show'))
assert.ok($target.attr('aria-expanded') === 'true')
assert.ok($target.prop('checked'))
done()
})
$target.trigger($.Event('click'))
})
QUnit.test('should add "collapsed" class to triggers only when all the targeted collapse are hidden', function (assert) {
assert.expect(9)
var done = assert.async()
var $trigger1 = $('<a role="button" data-toggle="collapse" href="#test1"/>').appendTo('#qunit-fixture')
var $trigger2 = $('<a role="button" data-toggle="collapse" href="#test2"/>').appendTo('#qunit-fixture')
var $trigger3 = $('<a role="button" data-toggle="collapse" href=".multi"/>').appendTo('#qunit-fixture')
var $target1 = $('<div id="test1" class="multi"/>').appendTo('#qunit-fixture')
var $target2 = $('<div id="test2" class="multi"/>').appendTo('#qunit-fixture')
$target2.one('shown.bs.collapse', function () {
assert.ok(!$trigger1.hasClass('collapsed'), 'trigger1 does not have collapsed class')
assert.ok(!$trigger2.hasClass('collapsed'), 'trigger2 does not have collapsed class')
assert.ok(!$trigger3.hasClass('collapsed'), 'trigger3 does not have collapsed class')
$target2.one('hidden.bs.collapse', function () {
assert.ok(!$trigger1.hasClass('collapsed'), 'trigger1 does not have collapsed class')
assert.ok($trigger2.hasClass('collapsed'), 'trigger2 has collapsed class')
assert.ok(!$trigger3.hasClass('collapsed'), 'trigger3 does not have collapsed class')
$target1.one('hidden.bs.collapse', function () {
assert.ok($trigger1.hasClass('collapsed'), 'trigger1 has collapsed class')
assert.ok($trigger2.hasClass('collapsed'), 'trigger2 has collapsed class')
assert.ok($trigger3.hasClass('collapsed'), 'trigger3 has collapsed class')
done()
})
$trigger1.trigger('click')
})
$trigger2.trigger('click')
})
$trigger3.trigger('click')
})
QUnit.test('should set aria-expanded="true" to triggers targetting shown collaspe and aria-expanded="false" only when all the targeted collapses are shown', function (assert) {
assert.expect(9)
var done = assert.async()
var $trigger1 = $('<a role="button" data-toggle="collapse" href="#test1"/>').appendTo('#qunit-fixture')
var $trigger2 = $('<a role="button" data-toggle="collapse" href="#test2"/>').appendTo('#qunit-fixture')
var $trigger3 = $('<a role="button" data-toggle="collapse" href=".multi"/>').appendTo('#qunit-fixture')
var $target1 = $('<div id="test1" class="multi collapse"/>').appendTo('#qunit-fixture')
var $target2 = $('<div id="test2" class="multi collapse"/>').appendTo('#qunit-fixture')
$target2.one('shown.bs.collapse', function () {
assert.strictEqual($trigger1.attr('aria-expanded'), 'true', 'aria-expanded on trigger1 is "true"')
assert.strictEqual($trigger2.attr('aria-expanded'), 'true', 'aria-expanded on trigger2 is "true"')
assert.strictEqual($trigger3.attr('aria-expanded'), 'true', 'aria-expanded on trigger3 is "true"')
$target2.one('hidden.bs.collapse', function () {
assert.strictEqual($trigger1.attr('aria-expanded'), 'true', 'aria-expanded on trigger1 is "true"')
assert.strictEqual($trigger2.attr('aria-expanded'), 'false', 'aria-expanded on trigger2 is "false"')
assert.strictEqual($trigger3.attr('aria-expanded'), 'true', 'aria-expanded on trigger3 is "true"')
$target1.one('hidden.bs.collapse', function () {
assert.strictEqual($trigger1.attr('aria-expanded'), 'false', 'aria-expanded on trigger1 is "fasle"')
assert.strictEqual($trigger2.attr('aria-expanded'), 'false', 'aria-expanded on trigger2 is "false"')
assert.strictEqual($trigger3.attr('aria-expanded'), 'false', 'aria-expanded on trigger3 is "false"')
done()
})
$trigger1.trigger('click')
})
$trigger2.trigger('click')
})
$trigger3.trigger('click')
})
})
+357 -200
View File
@@ -46,57 +46,68 @@ $(function () {
QUnit.test('should not open dropdown if target is disabled via attribute', function (assert) {
assert.expect(1)
var dropdownHTML = '<ul class="tabs">'
+ '<li class="dropdown">'
var done = assert.async()
var dropdownHTML = '<div class="tabs">'
+ '<div class="dropdown">'
+ '<button disabled href="#" class="btn dropdown-toggle" data-toggle="dropdown">Dropdown</button>'
+ '<ul class="dropdown-menu">'
+ '<li><a href="#">Secondary link</a></li>'
+ '<li><a href="#">Something else here</a></li>'
+ '<li class="divider"/>'
+ '<li><a href="#">Another link</a></li>'
+ '</ul>'
+ '</li>'
+ '</ul>'
var $dropdown = $(dropdownHTML).find('[data-toggle="dropdown"]').bootstrapDropdown().trigger('click')
assert.ok(!$dropdown.parent('.dropdown').hasClass('show'), '"show" class added on click')
+ '<div class="dropdown-menu">'
+ '<a class="dropdown-item" href="#">Secondary link</a>'
+ '<a class="dropdown-item" href="#">Something else here</a>'
+ '<div class="divider"/>'
+ '<a class="dropdown-item" href="#">Another link</a>'
+ '</div>'
+ '</div>'
+ '</div>'
$(dropdownHTML).appendTo('#qunit-fixture')
var $dropdown = $('#qunit-fixture').find('[data-toggle="dropdown"]').bootstrapDropdown()
$dropdown.on('click', function () {
assert.ok(!$dropdown.parent('.dropdown').hasClass('show'))
done()
})
$dropdown.trigger($.Event('click'))
})
QUnit.test('should set aria-expanded="true" on target when dropdown menu is shown', function (assert) {
assert.expect(1)
var dropdownHTML = '<ul class="tabs">'
+ '<li class="dropdown">'
var done = assert.async()
var dropdownHTML = '<div class="tabs">'
+ '<div class="dropdown">'
+ '<a href="#" class="dropdown-toggle" data-toggle="dropdown" aria-expanded="false">Dropdown</a>'
+ '<ul class="dropdown-menu">'
+ '<li><a href="#">Secondary link</a></li>'
+ '<li><a href="#">Something else here</a></li>'
+ '<li class="divider"/>'
+ '<li><a href="#">Another link</a></li>'
+ '</ul>'
+ '</li>'
+ '</ul>'
+ '<div class="dropdown-menu">'
+ '<a class="dropdown-item" href="#">Secondary link</a>'
+ '<a class="dropdown-item" href="#">Something else here</a>'
+ '<div class="divider"/>'
+ '<a class="dropdown-item" href="#">Another link</a>'
+ '</div>'
+ '</div>'
+ '</div>'
var $dropdown = $(dropdownHTML)
.find('[data-toggle="dropdown"]')
.bootstrapDropdown()
.trigger('click')
assert.strictEqual($dropdown.attr('aria-expanded'), 'true', 'aria-expanded is set to string "true" on click')
.appendTo('#qunit-fixture')
.find('[data-toggle="dropdown"]')
.bootstrapDropdown()
$dropdown
.parent('.dropdown')
.on('shown.bs.dropdown', function () {
assert.strictEqual($dropdown.attr('aria-expanded'), 'true', 'aria-expanded is set to string "true" on click')
done()
})
$dropdown.trigger('click')
})
QUnit.test('should set aria-expanded="false" on target when dropdown menu is hidden', function (assert) {
assert.expect(1)
var done = assert.async()
var dropdownHTML = '<ul class="tabs">'
+ '<li class="dropdown">'
var dropdownHTML = '<div class="tabs">'
+ '<div class="dropdown">'
+ '<a href="#" class="dropdown-toggle" aria-expanded="false" data-toggle="dropdown">Dropdown</a>'
+ '<ul class="dropdown-menu">'
+ '<li><a href="#">Secondary link</a></li>'
+ '<li><a href="#">Something else here</a></li>'
+ '<li class="divider"/>'
+ '<li><a href="#">Another link</a></li>'
+ '</ul>'
+ '</li>'
+ '</ul>'
+ '<div class="dropdown-menu">'
+ '<a class="dropdown-item" href="#">Secondary link</a>'
+ '<a class="dropdown-item" href="#">Something else here</a>'
+ '<div class="divider"/>'
+ '<a class="dropdown-item" href="#">Another link</a>'
+ '</div>'
+ '</div>'
+ '</div>'
var $dropdown = $(dropdownHTML)
.appendTo('#qunit-fixture')
.find('[data-toggle="dropdown"]')
@@ -115,85 +126,111 @@ $(function () {
QUnit.test('should not open dropdown if target is disabled via class', function (assert) {
assert.expect(1)
var dropdownHTML = '<ul class="tabs">'
+ '<li class="dropdown">'
var done = assert.async()
var dropdownHTML = '<div class="tabs">'
+ '<div class="dropdown">'
+ '<button href="#" class="btn dropdown-toggle disabled" data-toggle="dropdown">Dropdown</button>'
+ '<ul class="dropdown-menu">'
+ '<li><a href="#">Secondary link</a></li>'
+ '<li><a href="#">Something else here</a></li>'
+ '<li class="divider"/>'
+ '<li><a href="#">Another link</a></li>'
+ '</ul>'
+ '</li>'
+ '</ul>'
var $dropdown = $(dropdownHTML).find('[data-toggle="dropdown"]').bootstrapDropdown().trigger('click')
+ '<div class="dropdown-menu">'
+ '<a class="dropdown-item" href="#">Secondary link</a>'
+ '<a class="dropdown-item" href="#">Something else here</a>'
+ '<div class="divider"/>'
+ '<a class="dropdown-item" href="#">Another link</a>'
+ '</div>'
+ '</div>'
+ '</div>'
assert.ok(!$dropdown.parent('.dropdown').hasClass('show'), '"show" class added on click')
$(dropdownHTML).appendTo('#qunit-fixture')
var $dropdown = $('#qunit-fixture').find('[data-toggle="dropdown"]').bootstrapDropdown()
$dropdown.on('click', function () {
assert.ok(!$dropdown.parent('.dropdown').hasClass('show'))
done()
})
$dropdown.trigger($.Event('click'))
})
QUnit.test('should add class show to menu if clicked', function (assert) {
assert.expect(1)
var dropdownHTML = '<ul class="tabs">'
+ '<li class="dropdown">'
var done = assert.async()
var dropdownHTML = '<div class="tabs">'
+ '<div class="dropdown">'
+ '<a href="#" class="dropdown-toggle" data-toggle="dropdown">Dropdown</a>'
+ '<ul class="dropdown-menu">'
+ '<li><a href="#">Secondary link</a></li>'
+ '<li><a href="#">Something else here</a></li>'
+ '<li class="divider"/>'
+ '<li><a href="#">Another link</a></li>'
+ '</ul>'
+ '</li>'
+ '</ul>'
var $dropdown = $(dropdownHTML).find('[data-toggle="dropdown"]').bootstrapDropdown().trigger('click')
assert.ok($dropdown.parent('.dropdown').hasClass('show'), '"show" class added on click')
+ '<div class="dropdown-menu">'
+ '<a class="dropdown-item" href="#">Secondary link</a>'
+ '<a class="dropdown-item" href="#">Something else here</a>'
+ '<div class="divider"/>'
+ '<a class="dropdown-item" href="#">Another link</a>'
+ '</div>'
+ '</div>'
+ '</div>'
var $dropdown = $(dropdownHTML).find('[data-toggle="dropdown"]').bootstrapDropdown()
$dropdown
.parent('.dropdown')
.on('shown.bs.dropdown', function () {
assert.ok($dropdown.parent('.dropdown').hasClass('show'), '"show" class added on click')
done()
})
$dropdown.trigger('click')
})
QUnit.test('should test if element has a # before assuming it\'s a selector', function (assert) {
assert.expect(1)
var dropdownHTML = '<ul class="tabs">'
+ '<li class="dropdown">'
var done = assert.async()
var dropdownHTML = '<div class="tabs">'
+ '<div class="dropdown">'
+ '<a href="/foo/" class="dropdown-toggle" data-toggle="dropdown">Dropdown</a>'
+ '<ul class="dropdown-menu">'
+ '<li><a href="#">Secondary link</a></li>'
+ '<li><a href="#">Something else here</a></li>'
+ '<li class="divider"/>'
+ '<li><a href="#">Another link</a></li>'
+ '</ul>'
+ '</li>'
+ '</ul>'
var $dropdown = $(dropdownHTML).find('[data-toggle="dropdown"]').bootstrapDropdown().trigger('click')
assert.ok($dropdown.parent('.dropdown').hasClass('show'), '"show" class added on click')
+ '<div class="dropdown-menu">'
+ '<a class="dropdown-item" href="#">Secondary link</a>'
+ '<a class="dropdown-item" href="#">Something else here</a>'
+ '<div class="divider"/>'
+ '<a class="dropdown-item" href="#">Another link</a>'
+ '</div>'
+ '</div>'
+ '</div>'
var $dropdown = $(dropdownHTML).find('[data-toggle="dropdown"]').bootstrapDropdown()
$dropdown
.parent('.dropdown')
.on('shown.bs.dropdown', function () {
assert.ok($dropdown.parent('.dropdown').hasClass('show'), '"show" class added on click')
done()
})
$dropdown.trigger('click')
})
QUnit.test('should remove "show" class if body is clicked', function (assert) {
assert.expect(2)
var dropdownHTML = '<ul class="tabs">'
+ '<li class="dropdown">'
var done = assert.async()
var dropdownHTML = '<div class="tabs">'
+ '<div class="dropdown">'
+ '<a href="#" class="dropdown-toggle" data-toggle="dropdown">Dropdown</a>'
+ '<ul class="dropdown-menu">'
+ '<li><a href="#">Secondary link</a></li>'
+ '<li><a href="#">Something else here</a></li>'
+ '<li class="divider"/>'
+ '<li><a href="#">Another link</a></li>'
+ '</ul>'
+ '</li>'
+ '</ul>'
+ '<div class="dropdown-menu">'
+ '<a class="dropdown-item" href="#">Secondary link</a>'
+ '<a class="dropdown-item" href="#">Something else here</a>'
+ '<div class="divider"/>'
+ '<a class="dropdown-item" href="#">Another link</a>'
+ '</div>'
+ '</div>'
+ '</div>'
var $dropdown = $(dropdownHTML)
.appendTo('#qunit-fixture')
.find('[data-toggle="dropdown"]')
.bootstrapDropdown()
.trigger('click')
assert.ok($dropdown.parent('.dropdown').hasClass('show'), '"show" class added on click')
$(document.body).trigger('click')
assert.ok(!$dropdown.parent('.dropdown').hasClass('show'), '"show" class removed')
$dropdown
.parent('.dropdown')
.on('shown.bs.dropdown', function () {
assert.ok($dropdown.parent('.dropdown').hasClass('show'), '"show" class added on click')
$(document.body).trigger('click')
}).on('hidden.bs.dropdown', function () {
assert.ok(!$dropdown.parent('.dropdown').hasClass('show'), '"show" class removed')
done()
})
$dropdown.trigger('click')
})
QUnit.test('should remove "show" class if body is focused', function (assert) {
QUnit.test('should remove "show" class if tabbing outside of menu', function (assert) {
assert.expect(2)
var done = assert.async()
var dropdownHTML = '<div class="tabs">'
+ '<div class="dropdown">'
+ '<a href="#" class="dropdown-toggle" data-toggle="dropdown">Dropdown</a>'
@@ -209,30 +246,37 @@ $(function () {
.appendTo('#qunit-fixture')
.find('[data-toggle="dropdown"]')
.bootstrapDropdown()
.trigger('click')
assert.ok($dropdown.parent('.dropdown').hasClass('show'), '"show" class added on click')
$(document.body).trigger('focusin')
assert.ok(!$dropdown.parent('.dropdown').hasClass('show'), '"show" class removed')
$dropdown
.parent('.dropdown')
.on('shown.bs.dropdown', function () {
assert.ok($dropdown.parent('.dropdown').hasClass('show'), '"show" class added on click')
var e = $.Event('keyup')
e.which = 9 // Tab
$(document.body).trigger(e)
}).on('hidden.bs.dropdown', function () {
assert.ok(!$dropdown.parent('.dropdown').hasClass('show'), '"show" class removed')
done()
})
$dropdown.trigger('click')
})
QUnit.test('should remove "show" class if body is clicked, with multiple dropdowns', function (assert) {
assert.expect(7)
var dropdownHTML = '<ul class="nav">'
+ '<li><a href="#menu1">Menu 1</a></li>'
+ '<li class="dropdown" id="testmenu">'
var done = assert.async()
var dropdownHTML = '<div class="nav">'
+ '<div class="dropdown" id="testmenu">'
+ '<a class="dropdown-toggle" data-toggle="dropdown" href="#testmenu">Test menu <span class="caret"/></a>'
+ '<ul class="dropdown-menu">'
+ '<li><a href="#sub1">Submenu 1</a></li>'
+ '</ul>'
+ '</li>'
+ '</ul>'
+ '<div class="dropdown-menu">'
+ '<a class="dropdown-item" href="#sub1">Submenu 1</a>'
+ '</div>'
+ '</div>'
+ '</div>'
+ '<div class="btn-group">'
+ '<button class="btn">Actions</button>'
+ '<button class="btn dropdown-toggle" data-toggle="dropdown"><span class="caret"/></button>'
+ '<ul class="dropdown-menu">'
+ '<li><a href="#">Action 1</a></li>'
+ '</ul>'
+ '<button class="btn dropdown-toggle" data-toggle="dropdown"></button>'
+ '<div class="dropdown-menu">'
+ '<a class="dropdown-item" href="#">Action 1</a>'
+ '</div>'
+ '</div>'
var $dropdowns = $(dropdownHTML).appendTo('#qunit-fixture').find('[data-toggle="dropdown"]')
var $first = $dropdowns.first()
@@ -240,21 +284,31 @@ $(function () {
assert.strictEqual($dropdowns.length, 2, 'two dropdowns')
$first.trigger('click')
assert.strictEqual($first.parents('.show').length, 1, '"show" class added on click')
assert.strictEqual($('#qunit-fixture .show').length, 1, 'only one dropdown is shown')
$(document.body).trigger('click')
assert.strictEqual($('#qunit-fixture .show').length, 0, '"show" class removed')
$first.parent('.dropdown')
.on('shown.bs.dropdown', function () {
assert.strictEqual($first.parents('.show').length, 1, '"show" class added on click')
assert.strictEqual($('#qunit-fixture .dropdown-menu.show').length, 1, 'only one dropdown is shown')
$(document.body).trigger('click')
}).on('hidden.bs.dropdown', function () {
assert.strictEqual($('#qunit-fixture .dropdown-menu.show').length, 0, '"show" class removed')
$last.trigger('click')
})
$last.trigger('click')
assert.strictEqual($last.parent('.show').length, 1, '"show" class added on click')
assert.strictEqual($('#qunit-fixture .show').length, 1, 'only one dropdown is shown')
$(document.body).trigger('click')
assert.strictEqual($('#qunit-fixture .show').length, 0, '"show" class removed')
$last.parent('.btn-group')
.on('shown.bs.dropdown', function () {
assert.strictEqual($last.parent('.show').length, 1, '"show" class added on click')
assert.strictEqual($('#qunit-fixture .dropdown-menu.show').length, 1, 'only one dropdown is shown')
$(document.body).trigger('click')
}).on('hidden.bs.dropdown', function () {
assert.strictEqual($('#qunit-fixture .dropdown-menu.show').length, 0, '"show" class removed')
done()
})
$first.trigger('click')
})
QUnit.test('should remove "show" class if body is focused, with multiple dropdowns', function (assert) {
QUnit.test('should remove "show" class if body if tabbing outside of menu, with multiple dropdowns', function (assert) {
assert.expect(7)
var done = assert.async()
var dropdownHTML = '<div class="nav">'
+ '<div class="dropdown" id="testmenu">'
+ '<a class="dropdown-toggle" data-toggle="dropdown" href="#testmenu">Test menu <span class="caret"/></a>'
@@ -276,32 +330,45 @@ $(function () {
assert.strictEqual($dropdowns.length, 2, 'two dropdowns')
$first.trigger('click')
assert.strictEqual($first.parents('.show').length, 1, '"show" class added on click')
assert.strictEqual($('#qunit-fixture .show').length, 1, 'only one dropdown is show')
$(document.body).trigger('focusin')
assert.strictEqual($('#qunit-fixture .show').length, 0, '"show" class removed')
$first.parent('.dropdown')
.on('shown.bs.dropdown', function () {
assert.strictEqual($first.parents('.show').length, 1, '"show" class added on click')
assert.strictEqual($('#qunit-fixture .dropdown-menu.show').length, 1, 'only one dropdown is shown')
var e = $.Event('keyup')
e.which = 9 // Tab
$(document.body).trigger(e)
}).on('hidden.bs.dropdown', function () {
assert.strictEqual($('#qunit-fixture .dropdown-menu.show').length, 0, '"show" class removed')
$last.trigger('click')
})
$last.trigger('click')
assert.strictEqual($last.parent('.show').length, 1, '"show" class added on click')
assert.strictEqual($('#qunit-fixture .show').length, 1, 'only one dropdown is show')
$(document.body).trigger('focusin')
assert.strictEqual($('#qunit-fixture .show').length, 0, '"show" class removed')
$last.parent('.btn-group')
.on('shown.bs.dropdown', function () {
assert.strictEqual($last.parent('.show').length, 1, '"show" class added on click')
assert.strictEqual($('#qunit-fixture .dropdown-menu.show').length, 1, 'only one dropdown is shown')
var e = $.Event('keyup')
e.which = 9 // Tab
$(document.body).trigger(e)
}).on('hidden.bs.dropdown', function () {
assert.strictEqual($('#qunit-fixture .dropdown-menu.show').length, 0, '"show" class removed')
done()
})
$first.trigger('click')
})
QUnit.test('should fire show and hide event', function (assert) {
assert.expect(2)
var dropdownHTML = '<ul class="tabs">'
+ '<li class="dropdown">'
var dropdownHTML = '<div class="tabs">'
+ '<div class="dropdown">'
+ '<a href="#" class="dropdown-toggle" data-toggle="dropdown">Dropdown</a>'
+ '<ul class="dropdown-menu">'
+ '<li><a href="#">Secondary link</a></li>'
+ '<li><a href="#">Something else here</a></li>'
+ '<li class="divider"/>'
+ '<li><a href="#">Another link</a></li>'
+ '</ul>'
+ '</li>'
+ '</ul>'
+ '<div class="dropdown-menu">'
+ '<a class="dropdown-item" href="#">Secondary link</a>'
+ '<a class="dropdown-item" href="#">Something else here</a>'
+ '<div class="divider"/>'
+ '<a class="dropdown-item" href="#">Another link</a>'
+ '</div>'
+ '</div>'
+ '</div>'
var $dropdown = $(dropdownHTML)
.appendTo('#qunit-fixture')
.find('[data-toggle="dropdown"]')
@@ -326,17 +393,17 @@ $(function () {
QUnit.test('should fire shown and hidden event', function (assert) {
assert.expect(2)
var dropdownHTML = '<ul class="tabs">'
+ '<li class="dropdown">'
var dropdownHTML = '<div class="tabs">'
+ '<div class="dropdown">'
+ '<a href="#" class="dropdown-toggle" data-toggle="dropdown">Dropdown</a>'
+ '<ul class="dropdown-menu">'
+ '<li><a href="#">Secondary link</a></li>'
+ '<li><a href="#">Something else here</a></li>'
+ '<li class="divider"/>'
+ '<li><a href="#">Another link</a></li>'
+ '</ul>'
+ '</li>'
+ '</ul>'
+ '<div class="dropdown-menu">'
+ '<a class="dropdown-item" href="#">Secondary link</a>'
+ '<a class="dropdown-item" href="#">Something else here</a>'
+ '<div class="divider"/>'
+ '<a class="dropdown-item" href="#">Another link</a>'
+ '</div>'
+ '</div>'
+ '</div>'
var $dropdown = $(dropdownHTML)
.appendTo('#qunit-fixture')
.find('[data-toggle="dropdown"]')
@@ -360,17 +427,17 @@ $(function () {
QUnit.test('should fire shown and hidden event with a relatedTarget', function (assert) {
assert.expect(2)
var dropdownHTML = '<ul class="tabs">'
+ '<li class="dropdown">'
var dropdownHTML = '<div class="tabs">'
+ '<div class="dropdown">'
+ '<a href="#" class="dropdown-toggle" data-toggle="dropdown">Dropdown</a>'
+ '<ul class="dropdown-menu">'
+ '<li><a href="#">Secondary link</a></li>'
+ '<li><a href="#">Something else here</a></li>'
+ '<li class="divider"/>'
+ '<li><a href="#">Another link</a></li>'
+ '</ul>'
+ '</li>'
+ '</ul>'
+ '<div class="dropdown-menu">'
+ '<a class="dropdown-item" href="#">Secondary link</a>'
+ '<a class="dropdown-item" href="#">Something else here</a>'
+ '<div class="divider"/>'
+ '<a class="dropdown-item" href="#">Another link</a>'
+ '</div>'
+ '</div>'
+ '</div>'
var $dropdown = $(dropdownHTML)
.appendTo('#qunit-fixture')
.find('[data-toggle="dropdown"]')
@@ -394,19 +461,19 @@ $(function () {
assert.expect(3)
var done = assert.async()
var dropdownHTML = '<ul class="tabs">'
+ '<li class="dropdown">'
var dropdownHTML = '<div class="tabs">'
+ '<div class="dropdown">'
+ '<a href="#" class="dropdown-toggle" data-toggle="dropdown">Dropdown</a>'
+ '<ul class="dropdown-menu">'
+ '<li><a href="#">Secondary link</a></li>'
+ '<li><a href="#">Something else here</a></li>'
+ '<li class="divider"/>'
+ '<li><a href="#">Another link</a></li>'
+ '<li><input type="text" id="input"></li>'
+ '<li><textarea id="textarea"/></li>'
+ '</ul>'
+ '</li>'
+ '</ul>'
+ '<div class="dropdown-menu">'
+ '<a class="dropdown-item" href="#">Secondary link</a>'
+ '<a class="dropdown-item" href="#">Something else here</a>'
+ '<div class="divider"/>'
+ '<a class="dropdown-item" href="#">Another link</a>'
+ '<input type="text" id="input">'
+ '<textarea id="textarea"/>'
+ '</div>'
+ '</div>'
+ '</div>'
var $dropdown = $(dropdownHTML)
.appendTo('#qunit-fixture')
.find('[data-toggle="dropdown"]')
@@ -433,63 +500,153 @@ $(function () {
})
QUnit.test('should skip disabled element when using keyboard navigation', function (assert) {
assert.expect(1)
var dropdownHTML = '<ul class="tabs">'
+ '<li class="dropdown">'
assert.expect(2)
var done = assert.async()
var dropdownHTML = '<div class="tabs">'
+ '<div class="dropdown">'
+ '<a href="#" class="dropdown-toggle" data-toggle="dropdown">Dropdown</a>'
+ '<ul class="dropdown-menu">'
+ '<li class="disabled"><a href="#">Disabled link</a></li>'
+ '<li><a href="#">Another link</a></li>'
+ '</ul>'
+ '</li>'
+ '</ul>'
+ '<div class="dropdown-menu">'
+ '<a class="dropdown-item disabled" href="#">Disabled link</a>'
+ '<a class="dropdown-item" href="#">Another link</a>'
+ '</div>'
+ '</div>'
+ '</div>'
var $dropdown = $(dropdownHTML)
.appendTo('#qunit-fixture')
.find('[data-toggle="dropdown"]')
.bootstrapDropdown()
.trigger('click')
$dropdown.trigger($.Event('keydown', { which: 40 }))
$dropdown.trigger($.Event('keydown', { which: 40 }))
$dropdown
.parent('.dropdown')
.on('shown.bs.dropdown', function () {
assert.ok(true, 'shown was fired')
$dropdown.trigger($.Event('keydown', { which: 40 }))
$dropdown.trigger($.Event('keydown', { which: 40 }))
assert.ok(!$(document.activeElement).is('.disabled'), '.disabled is not focused')
done()
})
$dropdown.trigger('click')
})
QUnit.test('should focus next/previous element when using keyboard navigation', function (assert) {
assert.expect(4)
var done = assert.async()
var dropdownHTML = '<div class="tabs">'
+ '<div class="dropdown">'
+ '<a href="#" class="dropdown-toggle" data-toggle="dropdown">Dropdown</a>'
+ '<div class="dropdown-menu">'
+ '<a id="item1" class="dropdown-item" href="#">A link</a>'
+ '<a id="item2" class="dropdown-item" href="#">Another link</a>'
+ '</div>'
+ '</div>'
+ '</div>'
var $dropdown = $(dropdownHTML)
.appendTo('#qunit-fixture')
.find('[data-toggle="dropdown"]')
.bootstrapDropdown()
$dropdown
.parent('.dropdown')
.on('shown.bs.dropdown', function () {
assert.ok(true, 'shown was fired')
$dropdown.trigger($.Event('keydown', { which: 40 }))
assert.ok($(document.activeElement).is($('#item1')), 'item1 is focused')
$(document.activeElement).trigger($.Event('keydown', { which: 40 }))
assert.ok($(document.activeElement).is($('#item2')), 'item2 is focused')
$(document.activeElement).trigger($.Event('keydown', { which: 38 }))
assert.ok($(document.activeElement).is($('#item1')), 'item1 is focused')
done()
})
$dropdown.trigger('click')
assert.ok(!$(document.activeElement).parent().is('.disabled'), '.disabled is not focused')
})
QUnit.test('should not close the dropdown if the user clicks on a text field', function (assert) {
assert.expect(1)
var dropdownHTML = '<div class="btn-group">'
assert.expect(2)
var done = assert.async()
var dropdownHTML = '<div class="dropdown">'
+ '<button type="button" data-toggle="dropdown">Dropdown</button>'
+ '<ul class="dropdown-menu">'
+ '<li><input id="textField" type="text" /></li>'
+ '</ul>'
+ '<div class="dropdown-menu">'
+ '<input id="textField" type="text" />'
+ '</div>'
+ '</div>'
var $dropdown = $(dropdownHTML)
.appendTo('#qunit-fixture')
.find('[data-toggle="dropdown"]')
.bootstrapDropdown()
.trigger('click')
$('#textField').trigger('click')
var $textfield = $('#textField')
$textfield.on('click', function () {
assert.ok($dropdown.parent('.dropdown').hasClass('show'), 'dropdown menu is shown')
done()
})
assert.ok($dropdown.parent('.btn-group').hasClass('show'), 'dropdown menu is shown')
$dropdown
.parent('.dropdown')
.on('shown.bs.dropdown', function () {
assert.ok($dropdown.parent('.dropdown').hasClass('show'), 'dropdown menu is shown')
$textfield.trigger($.Event('click'))
})
$dropdown.trigger('click')
})
QUnit.test('should not close the dropdown if the user clicks on a textarea', function (assert) {
assert.expect(1)
var dropdownHTML = '<div class="btn-group">'
assert.expect(2)
var done = assert.async()
var dropdownHTML = '<div class="dropdown">'
+ '<button type="button" data-toggle="dropdown">Dropdown</button>'
+ '<ul class="dropdown-menu">'
+ '<li><textarea id="textArea"></textarea></li>'
+ '</ul>'
+ '<div class="dropdown-menu">'
+ '<textarea id="textArea"></textarea>'
+ '</div>'
+ '</div>'
var $dropdown = $(dropdownHTML)
.appendTo('#qunit-fixture')
.find('[data-toggle="dropdown"]')
.bootstrapDropdown()
.trigger('click')
$('#textArea').trigger('click')
var $textarea = $('#textArea')
$textarea.on('click', function () {
assert.ok($dropdown.parent('.dropdown').hasClass('show'), 'dropdown menu is shown')
done()
})
assert.ok($dropdown.parent('.btn-group').hasClass('show'), 'dropdown menu is shown')
$dropdown
.parent('.dropdown')
.on('shown.bs.dropdown', function () {
assert.ok($dropdown.parent('.dropdown').hasClass('show'), 'dropdown menu is shown')
$textarea.trigger($.Event('click'))
})
$dropdown.trigger('click')
})
QUnit.test('Dropdown should not use Popper.js in navbar', function (assert) {
assert.expect(1)
var done = assert.async()
var html = '<nav class="navbar navbar-expand-md navbar-light bg-light">'
+ '<div class="dropdown">'
+ ' <a class="nav-link dropdown-toggle" href="#" id="dropdown" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Dropdown</a>'
+ ' <div class="dropdown-menu" aria-labelledby="dropdown">'
+ ' <a class="dropdown-item" href="#">Action</a>'
+ ' <a class="dropdown-item" href="#">Another action</a>'
+ ' <a class="dropdown-item" href="#">Something else here</a>'
+ ' </div>'
+ '</div>'
+ '</nav>'
$(html).appendTo('#qunit-fixture')
var $triggerDropdown = $('#qunit-fixture')
.find('[data-toggle="dropdown"]')
.bootstrapDropdown()
var $dropdownMenu = $triggerDropdown.next()
$triggerDropdown
.parent('.dropdown')
.on('shown.bs.dropdown', function () {
assert.ok($dropdownMenu.attr('style') === undefined, 'No inline style applied by Popper.js')
done()
})
$triggerDropdown.trigger($.Event('click'))
})
})
+124 -45
View File
@@ -9,6 +9,19 @@ $(function () {
})
QUnit.module('modal', {
before: function () {
// Enable the scrollbar measurer
$('<style type="text/css"> .modal-scrollbar-measure { position: absolute; top: -9999px; width: 50px; height: 50px; overflow: scroll; } </style>').appendTo('head')
// Function to calculate the scrollbar width which is then compared to the padding or margin changes
$.fn.getScrollbarWidth = function () {
var scrollDiv = document.createElement('div')
scrollDiv.className = 'modal-scrollbar-measure'
document.body.appendChild(scrollDiv)
var scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth
document.body.removeChild(scrollDiv)
return scrollbarWidth
}
},
beforeEach: function () {
// Run all tests in noConflict mode -- it's the only way to ensure that the plugin works in noConflict mode
$.fn.bootstrapModal = $.fn.modal.noConflict()
@@ -336,23 +349,127 @@ $(function () {
$toggleBtn.trigger('click')
})
QUnit.test('should restore inline body padding after closing', function (assert) {
QUnit.test('should adjust the inline body padding when opening and restore when closing', function (assert) {
assert.expect(2)
var done = assert.async()
var originalBodyPad = 0
var $body = $(document.body)
$body.css('padding-right', originalBodyPad)
var originalPadding = $body.css('padding-right')
$('<div id="modal-test"/>')
.on('hidden.bs.modal', function () {
var currentBodyPad = parseInt($body.css('padding-right'), 10)
assert.notStrictEqual($body.attr('style'), '', 'body has non-empty style attribute')
assert.strictEqual(currentBodyPad, originalBodyPad, 'original body padding was not changed')
var currentPadding = $body.css('padding-right')
assert.strictEqual(currentPadding, originalPadding, 'body padding should be reset after closing')
$body.removeAttr('style')
done()
})
.on('shown.bs.modal', function () {
var expectedPadding = parseFloat(originalPadding) + $(this).getScrollbarWidth() + 'px'
var currentPadding = $body.css('padding-right')
assert.strictEqual(currentPadding, expectedPadding, 'body padding should be adjusted while opening')
$(this).bootstrapModal('hide')
})
.bootstrapModal('show')
})
QUnit.test('should store the original body padding in data-padding-right before showing', function (assert) {
assert.expect(2)
var done = assert.async()
var $body = $(document.body)
var originalPadding = '0px'
$body.css('padding-right', originalPadding)
$('<div id="modal-test"/>')
.on('hidden.bs.modal', function () {
assert.strictEqual($body.data('padding-right'), undefined, 'data-padding-right should be cleared after closing')
$body.removeAttr('style')
done()
})
.on('shown.bs.modal', function () {
assert.strictEqual($body.data('padding-right'), originalPadding, 'original body padding should be stored in data-padding-right')
$(this).bootstrapModal('hide')
})
.bootstrapModal('show')
})
QUnit.test('should adjust the inline padding of fixed elements when opening and restore when closing', function (assert) {
assert.expect(2)
var done = assert.async()
var $element = $('<div class="fixed-top"></div>').appendTo('#qunit-fixture')
var originalPadding = $element.css('padding-right')
$('<div id="modal-test"/>')
.on('hidden.bs.modal', function () {
var currentPadding = $element.css('padding-right')
assert.strictEqual(currentPadding, originalPadding, 'fixed element padding should be reset after closing')
$element.remove()
done()
})
.on('shown.bs.modal', function () {
var expectedPadding = parseFloat(originalPadding) + $(this).getScrollbarWidth() + 'px'
var currentPadding = $element.css('padding-right')
assert.strictEqual(currentPadding, expectedPadding, 'fixed element padding should be adjusted while opening')
$(this).bootstrapModal('hide')
})
.bootstrapModal('show')
})
QUnit.test('should store the original padding of fixed elements in data-padding-right before showing', function (assert) {
assert.expect(2)
var done = assert.async()
var $element = $('<div class="fixed-top"></div>').appendTo('#qunit-fixture')
var originalPadding = '0px'
$element.css('padding-right', originalPadding)
$('<div id="modal-test"/>')
.on('hidden.bs.modal', function () {
assert.strictEqual($element.data('padding-right'), undefined, 'data-padding-right should be cleared after closing')
$element.remove()
done()
})
.on('shown.bs.modal', function () {
assert.strictEqual($element.data('padding-right'), originalPadding, 'original fixed element padding should be stored in data-padding-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()
var $element = $('<div class="navbar-toggler"></div>').appendTo('#qunit-fixture')
var originalMargin = $element.css('margin-right')
$('<div id="modal-test"/>')
.on('hidden.bs.modal', function () {
var currentMargin = $element.css('margin-right')
assert.strictEqual(currentMargin, originalMargin, 'navbar-toggler margin should be reset after closing')
$element.remove()
done()
})
.on('shown.bs.modal', function () {
var expectedMargin = parseFloat(originalMargin) + $(this).getScrollbarWidth() + 'px'
var currentMargin = $element.css('margin-right')
assert.strictEqual(currentMargin, expectedMargin, 'navbar-toggler margin should be adjusted while opening')
$(this).bootstrapModal('hide')
})
.bootstrapModal('show')
})
QUnit.test('should store the original margin of the navbar-toggler in data-margin-right before showing', function (assert) {
assert.expect(2)
var done = assert.async()
var $element = $('<div class="navbar-toggler"></div>').appendTo('#qunit-fixture')
var originalMargin = '0px'
$element.css('margin-right', originalMargin)
$('<div id="modal-test"/>')
.on('hidden.bs.modal', function () {
assert.strictEqual($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'), originalMargin, 'original navbar-toggler margin should be stored in data-margin-right')
$(this).bootstrapModal('hide')
})
.bootstrapModal('show')
@@ -376,44 +493,6 @@ $(function () {
.bootstrapModal('show')
})
QUnit.test('should have a paddingRight when the modal is taller than the viewport', function (assert) {
assert.expect(2)
var done = assert.async()
$('<div class="fixed-top fixed-bottom sticky-top is-fixed">@Johann-S</div>').appendTo('#qunit-fixture')
$('.fixed-top, .fixed-bottom, .is-fixed, .sticky-top').css('padding-right', '10px')
$('<div id="modal-test"/>')
.on('shown.bs.modal', function () {
var paddingRight = parseInt($(document.body).css('padding-right'), 10)
assert.strictEqual(isNaN(paddingRight), false)
assert.strictEqual(paddingRight !== 0, true)
$(document.body).css('padding-right', '') // Because test case "should ignore other inline styles when trying to restore body padding after closing" fail if not
done()
})
.bootstrapModal('show')
})
QUnit.test('should remove padding-right on modal after closing', function (assert) {
assert.expect(3)
var done = assert.async()
$('<div class="fixed-top fixed-bottom is-fixed sticky-top">@Johann-S</div>').appendTo('#qunit-fixture')
$('.fixed-top, .fixed-bottom, .is-fixed, .sticky-top').css('padding-right', '10px')
$('<div id="modal-test"/>')
.on('shown.bs.modal', function () {
var paddingRight = parseInt($(document.body).css('padding-right'), 10)
assert.strictEqual(isNaN(paddingRight), false)
assert.strictEqual(paddingRight !== 0, true)
$(this).bootstrapModal('hide')
})
.on('hidden.bs.modal', function () {
var paddingRight = parseInt($(document.body).css('padding-right'), 10)
assert.strictEqual(paddingRight, 0)
done()
})
.bootstrapModal('show')
})
QUnit.test('should ignore other inline styles when trying to restore body padding after closing', function (assert) {
assert.expect(2)
var done = assert.async()
-72
View File
@@ -1,72 +0,0 @@
/*
* grunt-contrib-qunit
* http://gruntjs.com/
*
* Copyright (c) 2014 "Cowboy" Ben Alman, contributors
* Licensed under the MIT license.
*/
(function () {
'use strict'
// Don't re-order tests.
QUnit.config.reorder = false
// Run tests serially, not in parallel.
QUnit.config.autorun = false
// Send messages to the parent PhantomJS process via alert! Good times!!
function sendMessage() {
var args = [].slice.call(arguments)
alert(JSON.stringify(args))
}
// These methods connect QUnit to PhantomJS.
QUnit.log(function (obj) {
// What is this I dont even
if (obj.message === '[object Object], undefined:undefined') { return }
// Parse some stuff before sending it.
var actual
var expected
if (!obj.result) {
// Dumping large objects can be very slow, and the dump isn't used for
// passing tests, so only dump if the test failed.
actual = QUnit.dump.parse(obj.actual)
expected = QUnit.dump.parse(obj.expected)
}
// Send it.
sendMessage('qunit.log', obj.result, actual, expected, obj.message, obj.source)
})
QUnit.testStart(function (obj) {
sendMessage('qunit.testStart', obj.name)
})
QUnit.testDone(function (obj) {
sendMessage('qunit.testDone', obj.name, obj.failed, obj.passed, obj.total, obj.duration)
})
QUnit.moduleStart(function (obj) {
sendMessage('qunit.moduleStart', obj.name)
})
QUnit.moduleDone(function (obj) {
if (obj.failed === 0) {
console.log('\r\u221A All tests passed in "' + obj.name + '" module')
} else {
console.log('\u00D7 ' + obj.failed + ' tests failed in "' + obj.name + '" module')
}
sendMessage('qunit.moduleDone', obj.name, obj.failed, obj.passed, obj.total)
})
QUnit.begin(function () {
sendMessage('qunit.begin')
console.log('\n\nStarting test suite')
console.log('================================================\n')
})
QUnit.done(function (obj) {
sendMessage('qunit.done', obj.failed, obj.passed, obj.total, obj.runtime)
})
}())
+40 -17
View File
@@ -47,13 +47,18 @@ $(function () {
QUnit.test('should render popover element', function (assert) {
assert.expect(2)
var $popover = $('<a href="#" title="mdo" data-content="https://twitter.com/mdo">@mdo</a>')
var done = assert.async()
$('<a href="#" title="mdo" data-content="https://twitter.com/mdo">@mdo</a>')
.appendTo('#qunit-fixture')
.on('shown.bs.popover', function () {
assert.notEqual($('.popover').length, 0, 'popover was inserted')
$(this).bootstrapPopover('hide')
})
.on('hidden.bs.popover', function () {
assert.strictEqual($('.popover').length, 0, 'popover removed')
done()
})
.bootstrapPopover('show')
assert.notEqual($('.popover').length, 0, 'popover was inserted')
$popover.bootstrapPopover('hide')
assert.strictEqual($('.popover').length, 0, 'popover removed')
})
QUnit.test('should store popover instance in popover data object', function (assert) {
@@ -90,8 +95,8 @@ $(function () {
$popover.bootstrapPopover('show')
assert.notEqual($('.popover').length, 0, 'popover was inserted')
assert.strictEqual($('.popover .popover-title').text(), '@fat', 'title correctly inserted')
assert.strictEqual($('.popover .popover-content').text(), 'loves writing tests (╯°□°)╯︵ ┻━┻', 'content correctly inserted')
assert.strictEqual($('.popover .popover-header').text(), '@fat', 'title correctly inserted')
assert.strictEqual($('.popover .popover-body').text(), 'loves writing tests (╯°□°)╯︵ ┻━┻', 'content correctly inserted')
$popover.bootstrapPopover('hide')
@@ -109,10 +114,10 @@ $(function () {
$popover.bootstrapPopover('show')
assert.notEqual($('.popover').length, 0, 'popover inserted')
assert.strictEqual($('.popover .popover-title').text(), '@glebm <3 writing tests', 'title inserted')
assert.strictEqual($('.popover .popover-header').text(), '@glebm <3 writing tests', 'title inserted')
assert.ok($.contains($('.popover').get(0), title), 'title node moved, not copied')
// toLowerCase because IE8 will return <I>...</I>
assert.strictEqual($('.popover .popover-content').html().toLowerCase(), '<i>¯\\_(ツ)_/¯</i>', 'content inserted')
assert.strictEqual($('.popover .popover-body').html().toLowerCase(), '<i>¯\\_(ツ)_/¯</i>', 'content inserted')
assert.ok($.contains($('.popover').get(0), content), 'content node moved, not copied')
})
@@ -127,9 +132,9 @@ $(function () {
$popover.bootstrapPopover('show')
assert.notEqual($('.popover').length, 0, 'popover inserted')
assert.strictEqual($('.popover .popover-title').text(), '@glebm <3 writing tests', 'title inserted')
assert.strictEqual($('.popover .popover-header').text(), '@glebm <3 writing tests', 'title inserted')
assert.ok(!$.contains($('.popover').get(0), title), 'title node copied, not moved')
assert.strictEqual($('.popover .popover-content').html(), '¯\\_(ツ)_/¯', 'content inserted')
assert.strictEqual($('.popover .popover-body').html(), '¯\\_(ツ)_/¯', 'content inserted')
assert.ok(!$.contains($('.popover').get(0), content), 'content node copied, not moved')
})
@@ -149,14 +154,14 @@ $(function () {
$popover.bootstrapPopover('show')
assert.notEqual($('.popover').length, 0, 'popover was inserted')
assert.equal($('.popover .popover-content').html(), $div[0].outerHTML, 'content correctly inserted')
assert.equal($('.popover .popover-body').html(), $div[0].outerHTML, 'content correctly inserted')
$popover.bootstrapPopover('hide')
assert.strictEqual($('.popover').length, 0, 'popover was removed')
$popover.bootstrapPopover('show')
assert.notEqual($('.popover').length, 0, 'popover was inserted')
assert.equal($('.popover .popover-content').html(), $div[0].outerHTML, 'content correctly inserted')
assert.equal($('.popover .popover-body').html(), $div[0].outerHTML, 'content correctly inserted')
$popover.bootstrapPopover('hide')
assert.strictEqual($('.popover').length, 0, 'popover was removed')
@@ -170,8 +175,8 @@ $(function () {
.bootstrapPopover('show')
assert.notEqual($('.popover').length, 0, 'popover was inserted')
assert.strictEqual($('.popover .popover-title').text(), '@mdo', 'title correctly inserted')
assert.strictEqual($('.popover .popover-content').text(), 'loves data attributes (づ。◕‿‿◕。)づ ︵ ┻━┻', 'content correctly inserted')
assert.strictEqual($('.popover .popover-header').text(), '@mdo', 'title correctly inserted')
assert.strictEqual($('.popover .popover-body').text(), 'loves data attributes (づ。◕‿‿◕。)づ ︵ ┻━┻', 'content correctly inserted')
$popover.bootstrapPopover('hide')
assert.strictEqual($('.popover').length, 0, 'popover was removed')
@@ -188,8 +193,8 @@ $(function () {
.bootstrapPopover('show')
assert.notEqual($('.popover').length, 0, 'popover was inserted')
assert.strictEqual($('.popover .popover-title').text(), '@mdo', 'title correctly inserted')
assert.strictEqual($('.popover .popover-content').text(), 'loves data attributes (づ。◕‿‿◕。)づ ︵ ┻━┻', 'content correctly inserted')
assert.strictEqual($('.popover .popover-header').text(), '@mdo', 'title correctly inserted')
assert.strictEqual($('.popover .popover-body').text(), 'loves data attributes (づ。◕‿‿◕。)づ ︵ ┻━┻', 'content correctly inserted')
$popover.bootstrapPopover('hide')
assert.strictEqual($('.popover').length, 0, 'popover was removed')
@@ -364,4 +369,22 @@ $(function () {
})
.modal('show')
})
QUnit.test('should convert number to string without error for content and title', function (assert) {
assert.expect(2)
var done = assert.async()
var $popover = $('<a href="#">@mdo</a>')
.appendTo('#qunit-fixture')
.bootstrapPopover({
title: 5,
content: 7
})
.on('shown.bs.popover', function () {
assert.strictEqual($('.popover .popover-header').text(), '5')
assert.strictEqual($('.popover .popover-body').text(), '7')
done()
})
$popover.bootstrapPopover('show')
})
})
+188 -34
View File
@@ -26,7 +26,7 @@ $(function () {
QUnit.test('should throw explicit error on undefined method', function (assert) {
assert.expect(1)
var $el = $('<div/>')
var $el = $('<div/>').appendTo('#qunit-fixture')
$el.bootstrapScrollspy()
try {
$el.bootstrapScrollspy('noMethod')
@@ -38,7 +38,7 @@ $(function () {
QUnit.test('should return jquery collection containing the element', function (assert) {
assert.expect(2)
var $el = $('<div/>')
var $el = $('<div/>').appendTo('#qunit-fixture')
var $scrollspy = $el.bootstrapScrollspy()
assert.ok($scrollspy instanceof $, 'returns jquery collection')
assert.strictEqual($scrollspy[0], $el[0], 'collection contains element')
@@ -53,8 +53,8 @@ $(function () {
+ '<div class="topbar-inner">'
+ '<div class="container" id="ss-target">'
+ '<ul class="nav">'
+ '<li><a href="#masthead">Overview</a></li>'
+ '<li><a href="#detail">Detail</a></li>'
+ '<li class="nav-item"><a href="#masthead">Overview</a></li>'
+ '<li class="nav-item"><a href="#detail">Detail</a></li>'
+ '</ul>'
+ '</div>'
+ '</div>'
@@ -98,8 +98,8 @@ $(function () {
+ '<div class="topbar-inner">'
+ '<div class="container" id="ss-target">'
+ '<ul class="nav">'
+ '<li><a href="#masthead">Overview</a></li>'
+ '<li><a href="#detail">Detail</a></li>'
+ '<li class="nav-item"><a href="#masthead">Overview</a></li>'
+ '<li class="nav-item"><a href="#detail">Detail</a></li>'
+ '</ul>'
+ '</div>'
+ '</div>'
@@ -140,10 +140,10 @@ $(function () {
var sectionHTML = '<div id="header" style="height: 500px;"></div>'
+ '<nav id="navigation" class="navbar">'
+ '<ul class="nav navbar-nav">'
+ '<li class="active"><a class="nav-link" id="one-link" href="#one">One</a></li>'
+ '<li><a class="nav-link" id="two-link" href="#two">Two</a></li>'
+ '<li><a class="nav-link" id="three-link" href="#three">Three</a></li>'
+ '<ul class="navbar-nav">'
+ '<li class="nav-item active"><a class="nav-link" id="one-link" href="#one">One</a></li>'
+ '<li class="nav-item"><a class="nav-link" id="two-link" href="#two">Two</a></li>'
+ '<li class="nav-item"><a class="nav-link" id="three-link" href="#three">Three</a></li>'
+ '</ul>'
+ '</nav>'
+ '<div id="content" style="height: 200px; overflow-y: auto;">'
@@ -173,8 +173,8 @@ $(function () {
var navbarHtml =
'<nav class="navbar">'
+ '<ul class="nav">'
+ '<li><a class="nav-link" id="a-1" href="#div-1">div 1</a></li>'
+ '<li><a class="nav-link" id="a-2" href="#div-2">div 2</a></li>'
+ '<li class="nav-item"><a class="nav-link" id="a-1" href="#div-1">div 1</a></li>'
+ '<li class="nav-item"><a class="nav-link" id="a-2" href="#div-2">div 2</a></li>'
+ '</ul>'
+ '</nav>'
var contentHtml =
@@ -205,15 +205,89 @@ $(function () {
.then(function () { done() })
})
QUnit.test('should add the active class to the correct element (nav markup)', function (assert) {
assert.expect(2)
var navbarHtml =
'<nav class="navbar">'
+ '<nav class="nav">'
+ '<a class="nav-link" id="a-1" href="#div-1">div 1</a>'
+ '<a class="nav-link" id="a-2" href="#div-2">div 2</a>'
+ '</nav>'
+ '</nav>'
var contentHtml =
'<div class="content" style="overflow: auto; height: 50px">'
+ '<div id="div-1" style="height: 100px; padding: 0; margin: 0">div 1</div>'
+ '<div id="div-2" style="height: 200px; padding: 0; margin: 0">div 2</div>'
+ '</div>'
$(navbarHtml).appendTo('#qunit-fixture')
var $content = $(contentHtml)
.appendTo('#qunit-fixture')
.bootstrapScrollspy({ offset: 0, target: '.navbar' })
var done = assert.async()
var testElementIsActiveAfterScroll = function (element, target) {
var deferred = $.Deferred()
var scrollHeight = Math.ceil($content.scrollTop() + $(target).position().top)
$content.one('scroll', function () {
assert.ok($(element).hasClass('active'), 'target:' + target + ', element' + element)
deferred.resolve()
})
$content.scrollTop(scrollHeight)
return deferred.promise()
}
$.when(testElementIsActiveAfterScroll('#a-1', '#div-1'))
.then(function () { return testElementIsActiveAfterScroll('#a-2', '#div-2') })
.then(function () { done() })
})
QUnit.test('should add the active class to the correct element (list-group markup)', function (assert) {
assert.expect(2)
var navbarHtml =
'<nav class="navbar">'
+ '<div class="list-group">'
+ '<a class="list-group-item" id="a-1" href="#div-1">div 1</a>'
+ '<a class="list-group-item" id="a-2" href="#div-2">div 2</a>'
+ '</div>'
+ '</nav>'
var contentHtml =
'<div class="content" style="overflow: auto; height: 50px">'
+ '<div id="div-1" style="height: 100px; padding: 0; margin: 0">div 1</div>'
+ '<div id="div-2" style="height: 200px; padding: 0; margin: 0">div 2</div>'
+ '</div>'
$(navbarHtml).appendTo('#qunit-fixture')
var $content = $(contentHtml)
.appendTo('#qunit-fixture')
.bootstrapScrollspy({ offset: 0, target: '.navbar' })
var done = assert.async()
var testElementIsActiveAfterScroll = function (element, target) {
var deferred = $.Deferred()
var scrollHeight = Math.ceil($content.scrollTop() + $(target).position().top)
$content.one('scroll', function () {
assert.ok($(element).hasClass('active'), 'target:' + target + ', element' + element)
deferred.resolve()
})
$content.scrollTop(scrollHeight)
return deferred.promise()
}
$.when(testElementIsActiveAfterScroll('#a-1', '#div-1'))
.then(function () { return testElementIsActiveAfterScroll('#a-2', '#div-2') })
.then(function () { done() })
})
QUnit.test('should add the active class correctly when there are nested elements at 0 scroll offset', function (assert) {
assert.expect(6)
var times = 0
var done = assert.async()
var navbarHtml = '<nav id="navigation" class="navbar">'
+ '<ul class="nav">'
+ '<li><a id="a-1" class="nav-link" href="#div-1">div 1</a>'
+ '<ul>'
+ '<li><a id="a-2" class="nav-link" href="#div-2">div 2</a></li>'
+ '<li class="nav-item"><a id="a-1" class="nav-link" href="#div-1">div 1</a>'
+ '<ul class="nav">'
+ '<li class="nav-item"><a id="a-2" class="nav-link" href="#div-2">div 2</a></li>'
+ '</ul>'
+ '</li>'
+ '</ul>'
@@ -246,16 +320,96 @@ $(function () {
testActiveElements()
})
QUnit.test('should add the active class correctly when there are nested elements (nav markup)', function (assert) {
assert.expect(6)
var times = 0
var done = assert.async()
var navbarHtml = '<nav id="navigation" class="navbar">'
+ '<nav class="nav">'
+ '<a id="a-1" class="nav-link" href="#div-1">div 1</a>'
+ '<nav class="nav">'
+ '<a id="a-2" class="nav-link" href="#div-2">div 2</a>'
+ '</nav>'
+ '</nav>'
+ '</nav>'
var contentHtml = '<div class="content" style="position: absolute; top: 0px; overflow: auto; height: 50px">'
+ '<div id="div-1" style="padding: 0; margin: 0">'
+ '<div id="div-2" style="height: 200px; padding: 0; margin: 0">div 2</div>'
+ '</div>'
+ '</div>'
$(navbarHtml).appendTo('#qunit-fixture')
var $content = $(contentHtml)
.appendTo('#qunit-fixture')
.bootstrapScrollspy({ offset: 0, target: '#navigation' })
function testActiveElements() {
if (++times > 3) { return done() }
$content.one('scroll', function () {
assert.ok($('#a-1').hasClass('active'), 'nav item for outer element has "active" class')
assert.ok($('#a-2').hasClass('active'), 'nav item for inner element has "active" class')
testActiveElements()
})
$content.scrollTop($content.scrollTop() + 10)
}
testActiveElements()
})
QUnit.test('should add the active class correctly when there are nested elements (list-group markup)', function (assert) {
assert.expect(6)
var times = 0
var done = assert.async()
var navbarHtml = '<nav id="navigation" class="navbar">'
+ '<div class="list-group">'
+ '<a id="a-1" class="list-group-item" href="#div-1">div 1</a>'
+ '<div class="list-group">'
+ '<a id="a-2" class="list-group-item" href="#div-2">div 2</a>'
+ '</div>'
+ '</div>'
+ '</nav>'
var contentHtml = '<div class="content" style="position: absolute; top: 0px; overflow: auto; height: 50px">'
+ '<div id="div-1" style="padding: 0; margin: 0">'
+ '<div id="div-2" style="height: 200px; padding: 0; margin: 0">div 2</div>'
+ '</div>'
+ '</div>'
$(navbarHtml).appendTo('#qunit-fixture')
var $content = $(contentHtml)
.appendTo('#qunit-fixture')
.bootstrapScrollspy({ offset: 0, target: '#navigation' })
function testActiveElements() {
if (++times > 3) { return done() }
$content.one('scroll', function () {
assert.ok($('#a-1').hasClass('active'), 'nav item for outer element has "active" class')
assert.ok($('#a-2').hasClass('active'), 'nav item for inner element has "active" class')
testActiveElements()
})
$content.scrollTop($content.scrollTop() + 10)
}
testActiveElements()
})
QUnit.test('should clear selection if above the first section', function (assert) {
assert.expect(3)
var done = assert.async()
var sectionHTML = '<div id="header" style="height: 500px;"></div>'
+ '<nav id="navigation" class="navbar">'
+ '<ul class="nav navbar-nav">'
+ '<li><a id="one-link" class="nav-link active" href="#one">One</a></li>'
+ '<li><a id="two-link" class="nav-link" href="#two">Two</a></li>'
+ '<li><a id="three-link" class="nav-link" href="#three">Three</a></li>'
+ '<ul class="navbar-nav">'
+ '<li class="nav-item"><a id="one-link" class="nav-link active" href="#one">One</a></li>'
+ '<li class="nav-item"><a id="two-link" class="nav-link" href="#two">Two</a></li>'
+ '<li class="nav-item"><a id="three-link" class="nav-link" href="#three">Three</a></li>'
+ '</ul>'
+ '</nav>'
$(sectionHTML).appendTo('#qunit-fixture')
@@ -293,10 +447,10 @@ $(function () {
var sectionHTML = '<div id="header" style="height: 500px;"></div>'
+ '<nav id="navigation" class="navbar">'
+ '<ul class="nav navbar-nav">'
+ '<li><a id="one-link" class="nav-link active" href="#one">One</a></li>'
+ '<li><a id="two-link" class="nav-link" href="#two">Two</a></li>'
+ '<li><a id="three-link" class="nav-link" href="#three">Three</a></li>'
+ '<ul class="navbar-nav">'
+ '<li class="nav-item"><a id="one-link" class="nav-link active" href="#one">One</a></li>'
+ '<li class="nav-item"><a id="two-link" class="nav-link" href="#two">Two</a></li>'
+ '<li class="nav-item"><a id="three-link" class="nav-link" href="#three">Three</a></li>'
+ '</ul>'
+ '</nav>'
$(sectionHTML).appendTo('#qunit-fixture')
@@ -336,11 +490,11 @@ $(function () {
var navbarHtml =
'<nav class="navbar">'
+ '<ul class="nav">'
+ '<li><a id="li-100-1" class="nav-link" href="#div-100-1">div 1</a></li>'
+ '<li><a id="li-100-2" class="nav-link" href="#div-100-2">div 2</a></li>'
+ '<li><a id="li-100-3" class="nav-link" href="#div-100-3">div 3</a></li>'
+ '<li><a id="li-100-4" class="nav-link" href="#div-100-4">div 4</a></li>'
+ '<li><a id="li-100-5" class="nav-link" href="#div-100-5">div 5</a></li>'
+ '<li class="nav-item"><a id="li-100-1" class="nav-link" href="#div-100-1">div 1</a></li>'
+ '<li class="nav-item"><a id="li-100-2" class="nav-link" href="#div-100-2">div 2</a></li>'
+ '<li class="nav-item"><a id="li-100-3" class="nav-link" href="#div-100-3">div 3</a></li>'
+ '<li class="nav-item"><a id="li-100-4" class="nav-link" href="#div-100-4">div 4</a></li>'
+ '<li class="nav-item"><a id="li-100-5" class="nav-link" href="#div-100-5">div 5</a></li>'
+ '</ul>'
+ '</nav>'
var contentHtml =
@@ -384,9 +538,9 @@ $(function () {
var $navbar = $(
'<nav class="navbar"' + (type === 'data' ? ' id="navbar-offset-method-menu"' : '') + '>'
+ '<ul class="nav">'
+ '<li><a id="li-' + type + 'm-1" class="nav-link" href="#div-' + type + 'm-1">div 1</a></li>'
+ '<li><a id="li-' + type + 'm-2" class="nav-link" href="#div-' + type + 'm-2">div 2</a></li>'
+ '<li><a id="li-' + type + 'm-3" class="nav-link" href="#div-' + type + 'm-3">div 3</a></li>'
+ '<li class="nav-item"><a id="li-' + type + 'm-1" class="nav-link" href="#div-' + type + 'm-1">div 1</a></li>'
+ '<li class="nav-item"><a id="li-' + type + 'm-2" class="nav-link" href="#div-' + type + 'm-2">div 2</a></li>'
+ '<li class="nav-item"><a id="li-' + type + 'm-3" class="nav-link" href="#div-' + type + 'm-3">div 3</a></li>'
+ '</ul>'
+ '</nav>'
)
@@ -428,9 +582,9 @@ $(function () {
var $navbar = $(
'<nav class="navbar"' + (type === 'data' ? ' id="navbar-offset-method-menu"' : '') + '>'
+ '<ul class="nav">'
+ '<li><a class="nav-link" id="li-' + type + 'm-1" href="#div-' + type + 'm-1">div 1</a></li>'
+ '<li><a class="nav-link" id="li-' + type + 'm-2" href="#div-' + type + 'm-2">div 2</a></li>'
+ '<li><a class="nav-link" id="li-' + type + 'm-3" href="#div-' + type + 'm-3">div 3</a></li>'
+ '<li class="nav-item"><a class="nav-link" id="li-' + type + 'm-1" href="#div-' + type + 'm-1">div 1</a></li>'
+ '<li class="nav-item"><a class="nav-link" id="li-' + type + 'm-2" href="#div-' + type + 'm-2">div 2</a></li>'
+ '<li class="nav-item"><a class="nav-link" id="li-' + type + 'm-3" href="#div-' + type + 'm-3">div 3</a></li>'
+ '</ul>'
+ '</nav>'
)
+24 -8
View File
@@ -46,7 +46,7 @@ $(function () {
QUnit.test('should activate element by tab id', function (assert) {
assert.expect(2)
var tabsHTML = '<ul class="tabs">'
var tabsHTML = '<ul class="nav">'
+ '<li><a href="#home">Home</a></li>'
+ '<li><a href="#profile">Profile</a></li>'
+ '</ul>'
@@ -62,7 +62,7 @@ $(function () {
QUnit.test('should activate element by tab id', function (assert) {
assert.expect(2)
var pillsHTML = '<ul class="pills">'
var pillsHTML = '<ul class="nav nav-pills">'
+ '<li><a href="#home">Home</a></li>'
+ '<li><a href="#profile">Profile</a></li>'
+ '</ul>'
@@ -78,7 +78,7 @@ $(function () {
QUnit.test('should activate element by tab id in ordered list', function (assert) {
assert.expect(2)
var pillsHTML = '<ol class="pills">'
var pillsHTML = '<ol class="nav nav-pills">'
+ '<li><a href="#home">Home</a></li>'
+ '<li><a href="#profile">Profile</a></li>'
+ '</ol>'
@@ -108,11 +108,27 @@ $(function () {
assert.strictEqual($('#qunit-fixture').find('.active').attr('id'), 'home')
})
QUnit.test('should activate element by tab id in list group', function (assert) {
assert.expect(2)
var tabsHTML = '<div class="list-group">' +
'<a href="#home">Home</a>' +
'<a href="#profile">Profile</a>' +
'</div>'
$('<nav><div id="home"></div><div id="profile"></div></nav>').appendTo('#qunit-fixture')
$(tabsHTML).find('a:last').bootstrapTab('show')
assert.strictEqual($('#qunit-fixture').find('.active').attr('id'), 'profile')
$(tabsHTML).find('a:first').bootstrapTab('show')
assert.strictEqual($('#qunit-fixture').find('.active').attr('id'), 'home')
})
QUnit.test('should not fire shown when show is prevented', function (assert) {
assert.expect(1)
var done = assert.async()
$('<div class="tab"/>')
$('<div class="nav"/>')
.on('show.bs.tab', function (e) {
e.preventDefault()
assert.ok(true, 'show event fired')
@@ -166,7 +182,7 @@ $(function () {
assert.expect(2)
var done = assert.async()
var dropHTML = '<ul class="drop">'
var dropHTML = '<ul class="drop nav">'
+ '<li class="dropdown"><a data-toggle="dropdown" href="#">1</a>'
+ '<ul class="dropdown-menu">'
+ '<li><a href="#1-1" data-toggle="tab">1-1</a></li>'
@@ -194,7 +210,7 @@ $(function () {
assert.expect(2)
var done = assert.async()
var tabsHTML = '<ul class="tabs">'
var tabsHTML = '<ul class="nav">'
+ '<li><a href="#home">Home</a></li>'
+ '<li><a href="#profile">Profile</a></li>'
+ '</ul>'
@@ -225,7 +241,7 @@ $(function () {
assert.expect(1)
var done = assert.async()
var tabsHTML = '<ul class="tabs">'
var tabsHTML = '<ul class="nav">'
+ '<li><a href="#home">Home</a></li>'
+ '<li><a href="#profile">Profile</a></li>'
+ '</ul>'
@@ -250,7 +266,7 @@ $(function () {
assert.expect(2)
var done = assert.async()
var tabsHTML = '<ul class="tabs">'
var tabsHTML = '<ul class="nav">'
+ '<li><a href="#home">Home</a></li>'
+ '<li><a href="#profile">Profile</a></li>'
+ '</ul>'
+60 -103
View File
@@ -111,7 +111,7 @@ $(function () {
assert
.ok($('.tooltip')
.is('.fade.bs-tether-element-attached-top.bs-tether-element-attached-center.show'), 'has correct classes applied')
.is('.fade.bs-tooltip-bottom.show'), 'has correct classes applied')
$tooltip.bootstrapTooltip('hide')
@@ -364,32 +364,29 @@ $(function () {
})
QUnit.test('should add position class before positioning so that position-specific styles are taken into account', function (assert) {
assert.expect(1)
assert.expect(2)
var done = assert.async()
var styles = '<style>'
+ '.tooltip.right { white-space: nowrap; }'
+ '.tooltip.right .tooltip-inner { max-width: none; }'
+ '.bs-tooltip-right { white-space: nowrap; }'
+ '.bs-tooltip-right .tooltip-inner { max-width: none; }'
+ '</style>'
var $styles = $(styles).appendTo('head')
var $container = $('<div/>').appendTo('#qunit-fixture')
var $target = $('<a href="#" rel="tooltip" title="very very very very very very very very long tooltip in one line"/>')
$('<a href="#" rel="tooltip" title="very very very very very very very very long tooltip in one line"/>')
.appendTo($container)
.bootstrapTooltip({
placement: 'right'
placement: 'right',
trigger: 'manual'
})
.on('inserted.bs.tooltip', function () {
var $tooltip = $($(this).data('bs.tooltip').tip)
assert.ok($tooltip.hasClass('bs-tooltip-right'))
assert.ok($tooltip.attr('style') === undefined)
$styles.remove()
done()
})
.bootstrapTooltip('show')
var $tooltip = $($target.data('bs.tooltip').tip)
// this is some dumb hack stuff because sub pixels in firefox
var top = Math.round($target.offset().top + $target[0].offsetHeight / 2 - $tooltip[0].offsetHeight / 2)
var top2 = Math.round($tooltip.offset().top)
var topDiff = top - top2
assert.ok(topDiff <= 1 && topDiff >= -1)
$target.bootstrapTooltip('hide')
$container.remove()
$styles.remove()
})
QUnit.test('should use title attribute for tooltip text', function (assert) {
@@ -459,7 +456,7 @@ $(function () {
assert.expect(1)
var done = assert.async()
var containerHTML = '<div>'
var containerHTML = '<div id="test">'
+ '<p style="margin-top: 200px">'
+ '<a href="#" title="very very very very very very very long tooltip">Hover me</a>'
+ '</p>'
@@ -476,21 +473,24 @@ $(function () {
})
.appendTo('#qunit-fixture')
var $trigger = $container
$container
.find('a')
.css('margin-top', 200)
.bootstrapTooltip({
placement: 'top',
animate: false
})
.on('shown.bs.tooltip', function () {
var $tooltip = $($(this).data('bs.tooltip').tip)
if (/iPhone|iPad|iPod/.test(navigator.userAgent)) {
assert.ok(Math.round($tooltip.offset().top + $tooltip.outerHeight()) <= Math.round($(this).offset().top))
}
else {
assert.ok(Math.round($tooltip.offset().top + $tooltip.outerHeight()) >= Math.round($(this).offset().top))
}
done()
})
.bootstrapTooltip('show')
var $tooltip = $($trigger.data('bs.tooltip').tip)
setTimeout(function () {
assert.ok(Math.round($tooltip.offset().top + $tooltip.outerHeight()) <= Math.round($trigger.offset().top))
done()
}, 0)
})
QUnit.test('should show tooltip if leave event hasn\'t occurred before delay expires', function (assert) {
@@ -629,45 +629,6 @@ $(function () {
$tooltip.trigger('mouseenter')
})
QUnit.test('should correctly position tooltips on SVG elements', function (assert) {
if (!window.SVGElement) {
// Skip IE8 since it doesn't support SVG
assert.expect(0)
return
}
assert.expect(2)
var done = assert.async()
var styles = '<style>'
+ '.tooltip, .tooltip *, .tooltip *:before, .tooltip *:after { box-sizing: border-box; }'
+ '.tooltip { position: absolute; }'
+ '.tooltip .tooltip-inner { width: 24px; height: 24px; font-family: Helvetica; }'
+ '</style>'
var $styles = $(styles).appendTo('head')
$('#qunit-fixture').append(
'<div style="position: fixed; top: 0; left: 0;">'
+ ' <svg width="200" height="200">'
+ ' <circle cx="100" cy="100" r="10" title="m" id="theCircle" />'
+ ' </svg>'
+ '</div>')
var $circle = $('#theCircle')
$circle
.on('shown.bs.tooltip', function () {
var offset = $('.tooltip').offset()
$styles.remove()
assert.ok(Math.abs(offset.left - 88) <= 1, 'tooltip has correct horizontal location')
$circle.bootstrapTooltip('hide')
assert.strictEqual($('.tooltip').length, 0, 'tooltip removed from dom')
done()
})
.bootstrapTooltip({ placement: 'top', trigger: 'manual' })
$circle.bootstrapTooltip('show')
})
QUnit.test('should not reload the tooltip on subsequent mouseenter events', function (assert) {
assert.expect(1)
var titleHtml = function () {
@@ -731,43 +692,6 @@ $(function () {
assert.strictEqual(currentUid, $('#tt-content').text())
})
QUnit.test('should correctly position tooltips on transformed elements', function (assert) {
var styleProps = document.documentElement.style
if (!('transform' in styleProps) && !('webkitTransform' in styleProps) && !('msTransform' in styleProps)) {
assert.expect(0)
return
}
assert.expect(2)
var done = assert.async()
var styles = '<style>'
+ '#qunit-fixture { top: 0; left: 0; }'
+ '.tooltip, .tooltip *, .tooltip *:before, .tooltip *:after { box-sizing: border-box; }'
+ '.tooltip { position: absolute; }'
+ '.tooltip .tooltip-inner { width: 24px; height: 24px; font-family: Helvetica; }'
+ '#target { position: absolute; top: 100px; left: 50px; width: 100px; height: 200px; -webkit-transform: rotate(270deg); -ms-transform: rotate(270deg); transform: rotate(270deg); }'
+ '</style>'
var $styles = $(styles).appendTo('head')
var $element = $('<div id="target" title="1"/>').appendTo('#qunit-fixture')
$element
.on('shown.bs.tooltip', function () {
var offset = $('.tooltip').offset()
$styles.remove()
assert.ok(Math.abs(offset.left - 88) <= 1, 'tooltip has correct horizontal location')
assert.ok(Math.abs(offset.top - 126) <= 1, 'tooltip has correct vertical location')
$element.bootstrapTooltip('hide')
done()
})
.bootstrapTooltip({
trigger: 'manual'
})
$element.bootstrapTooltip('show')
})
QUnit.test('should do nothing when an attempt is made to hide an uninitialized tooltip', function (assert) {
assert.expect(1)
@@ -869,4 +793,37 @@ $(function () {
})
.modal('show')
})
QUnit.test('should reset tip classes when hidden event triggered', function (assert) {
assert.expect(2)
var done = assert.async()
var $el = $('<a href="#" rel="tooltip" title="Test tooltip"/>')
.appendTo('#qunit-fixture')
.bootstrapTooltip('show')
.on('hidden.bs.tooltip', function () {
var tooltip = $el.data('bs.tooltip')
var $tooltip = $(tooltip.getTipElement())
assert.ok($tooltip.hasClass('tooltip'))
assert.ok($tooltip.hasClass('fade'))
done()
})
$el.bootstrapTooltip('hide')
})
QUnit.test('should convert number in title to string', function (assert) {
assert.expect(1)
var done = assert.async()
var $el = $('<a href="#" rel="tooltip" title="7"/>')
.appendTo('#qunit-fixture')
.bootstrapTooltip('show')
.on('shown.bs.tooltip', function () {
var tooltip = $el.data('bs.tooltip')
var $tooltip = $(tooltip.getTipElement())
assert.strictEqual($tooltip.children().text(), '7')
done()
})
$el.bootstrapTooltip('show')
})
})
+5039 -4428
View File
File diff suppressed because it is too large Load Diff
+86 -105
View File
@@ -1,51 +1,28 @@
{
"_args": [
[
{
"raw": "bootstrap@4.0.0-alpha.6",
"scope": null,
"escapedName": "bootstrap",
"name": "bootstrap",
"rawSpec": "4.0.0-alpha.6",
"spec": "4.0.0-alpha.6",
"type": "version"
},
"c:\\xampp\\htdocs\\laravel"
]
],
"_from": "bootstrap@4.0.0-alpha.6",
"_id": "bootstrap@4.0.0-alpha.6",
"_inCache": true,
"_from": "bootstrap@4.0.0-beta",
"_id": "bootstrap@4.0.0-beta",
"_inBundle": false,
"_integrity": "sha512-I/r3fYtUZr+rUNkh8HI+twxZ56p6ehNn27eA1XSebLVQKAJ2xZHnEvZrSR+UR2A/bONcd9gHC3xatVhQlH6R6w==",
"_location": "/bootstrap",
"_nodeVersion": "5.10.0",
"_npmOperationalInternal": {
"host": "packages-12-west.internal.npmjs.com",
"tmp": "tmp/bootstrap-4.0.0-alpha.6.tgz_1483723623729_0.6719418407883495"
},
"_npmUser": {
"name": "twbs",
"email": "getbootstrap@gmail.com"
},
"_npmVersion": "3.8.3",
"_phantomChildren": {},
"_requested": {
"raw": "bootstrap@4.0.0-alpha.6",
"scope": null,
"escapedName": "bootstrap",
"type": "version",
"registry": true,
"raw": "bootstrap@4.0.0-beta",
"name": "bootstrap",
"rawSpec": "4.0.0-alpha.6",
"spec": "4.0.0-alpha.6",
"type": "version"
"escapedName": "bootstrap",
"rawSpec": "4.0.0-beta",
"saveSpec": null,
"fetchSpec": "4.0.0-beta"
},
"_requiredBy": [
"#DEV:/",
"#USER"
],
"_resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.0.0-alpha.6.tgz",
"_shasum": "4f54dd33ac0deac3b28407bc2df7ec608869c9c8",
"_shrinkwrap": null,
"_spec": "bootstrap@4.0.0-alpha.6",
"_where": "c:\\xampp\\htdocs\\laravel",
"_resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.0.0-beta.tgz",
"_shasum": "dc5928175d2e71310bc668cf9e05a907211b72a6",
"_spec": "bootstrap@4.0.0-beta",
"_where": "D:\\dev\\dp\\dp",
"author": {
"name": "The Bootstrap Authors",
"url": "https://github.com/twbs/bootstrap/graphs/contributors"
@@ -53,66 +30,53 @@
"bugs": {
"url": "https://github.com/twbs/bootstrap/issues"
},
"bundleDependencies": false,
"contributors": [
{
"name": "Twitter, Inc."
}
],
"dependencies": {
"jquery": ">=1.9.1",
"tether": "^1.4.0"
},
"dependencies": {},
"deprecated": false,
"description": "The most popular front-end framework for developing responsive, mobile first projects on the web.",
"devDependencies": {
"autoprefixer": "^6.6.1",
"babel-eslint": "^7.1.1",
"babel-plugin-transform-es2015-modules-strip": "^0.1.0",
"babel-preset-es2015": "^6.18.0",
"clean-css": "^3.4.23",
"eslint": "^3.12.2",
"autoprefixer": "^7.1.2",
"babel-cli": "^6.24.1",
"babel-eslint": "^7.2.3",
"babel-plugin-transform-es2015-modules-strip": "^0.1.1",
"babel-preset-es2015": "^6.24.1",
"clean-css-cli": "^4.1.6",
"eslint": "^4.2.0",
"grunt": "^1.0.1",
"grunt-babel": "^6.0.0",
"grunt-build-control": "^0.7.1",
"grunt-contrib-clean": "^1.0.0",
"grunt-contrib-compress": "^1.3.0",
"grunt-contrib-concat": "^1.0.1",
"grunt-contrib-connect": "^1.0.2",
"grunt-contrib-copy": "^1.0.0",
"grunt-contrib-qunit": "^1.2.0",
"grunt-contrib-watch": "^1.0.0",
"grunt-exec": "^1.0.1",
"grunt-html": "^8.1.0",
"grunt-jekyll": "^0.4.4",
"grunt-cli": "^1.2.0",
"grunt-saucelabs": "^9.0.0",
"grunt-stamp": "^0.3.0",
"htmlhint": "^0.9.13",
"is-travis": "^1.0.0",
"load-grunt-tasks": "^3.5.2",
"node-sass": "^4.1.1",
"postcss-cli": "^2.6.0",
"postcss-flexbugs-fixes": "^2.1.0",
"shelljs": "^0.7.5",
"shx": "^0.2.1",
"time-grunt": "^1.4.0",
"uglify-js": "^2.7.5"
},
"directories": {},
"dist": {
"shasum": "4f54dd33ac0deac3b28407bc2df7ec608869c9c8",
"tarball": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.0.0-alpha.6.tgz"
"htmllint-cli": "^0.0.6",
"node-sass": "^4.5.3",
"nodemon": "^1.11.0",
"npm-run-all": "^4.0.2",
"phantomjs-prebuilt": "^2.1.14",
"postcss-cli": "^4.1.0",
"qunit-phantomjs-runner": "^2.3.0",
"qunitjs": "^2.4.0",
"shelljs": "^0.7.8",
"shx": "^0.2.2",
"uglify-js": "^3.0.24"
},
"engines": {
"node": ">=4"
},
"files": [
"dist",
"grunt",
"js/**/*.js",
"scss/**/*.scss",
".babelrc",
".eslintignore",
"Gruntfile.js",
"dist",
"build",
"js/.eslintrc.json",
"js/**/*.js",
".scss-lint.yml",
"scss/**/*.scss",
"LICENSE"
],
"gitHead": "65ffb1c3b6e94440812a2e228cb8e8be512652ec",
"homepage": "https://getbootstrap.com",
"jspm": {
"main": "js/bootstrap",
@@ -142,37 +106,54 @@
],
"license": "MIT",
"main": "dist/js/bootstrap",
"maintainers": [
{
"name": "twbs",
"email": "bigj95t+bsnpm@gmail.com"
}
],
"name": "bootstrap",
"optionalDependencies": {},
"readme": "ERROR: No README data found!",
"peerDependencies": {
"jquery": ">=3.0.0",
"popper.js": "^1.11.0"
},
"repository": {
"type": "git",
"url": "git+https://github.com/twbs/bootstrap.git"
},
"sass": "scss/bootstrap.scss",
"scripts": {
"change-version": "node grunt/change-version.js",
"clean-css": "cleancss --skip-advanced --source-map --output dist/css/bootstrap.min.css dist/css/bootstrap.css && cleancss --skip-advanced --source-map --output dist/css/bootstrap-grid.min.css dist/css/bootstrap-grid.css && cleancss --skip-advanced --source-map --output dist/css/bootstrap-reboot.min.css dist/css/bootstrap-reboot.css",
"clean-css-docs": "cleancss --skip-advanced --source-map --output docs/assets/css/docs.min.css docs/assets/css/docs.min.css",
"eslint": "eslint --ignore-path .eslintignore js && eslint --config js/tests/.eslintrc.json --env node grunt Gruntfile.js && eslint --config js/tests/.eslintrc.json docs/assets/js/src docs/assets/js/ie-emulation-modes-warning.js docs/assets/js/ie10-viewport-bug-workaround.js",
"htmlhint": "htmlhint --config docs/.htmlhintrc _gh_pages/",
"postcss": "postcss --config grunt/postcss.js --replace dist/css/*.css",
"postcss-docs": "postcss --config grunt/postcss.js --no-map --replace docs/assets/css/docs.min.css && postcss --config grunt/postcss.js --no-map --replace docs/examples/**/*.css",
"sass": "node-sass --output-style expanded --source-map true --precision 6 scss/bootstrap.scss dist/css/bootstrap.css && node-sass --output-style expanded --source-map true --precision 6 scss/bootstrap-grid.scss dist/css/bootstrap-grid.css && node-sass --output-style expanded --source-map true --precision 6 scss/bootstrap-reboot.scss dist/css/bootstrap-reboot.css",
"sass-docs": "node-sass --output-style expanded --source-map true --precision 6 docs/assets/scss/docs.scss docs/assets/css/docs.min.css",
"scss-lint": "bundle exec scss-lint --config scss/.scss-lint.yml --exclude scss/_normalize.scss scss/*.scss",
"scss-lint-docs": "bundle exec scss-lint --config scss/.scss-lint.yml --exclude docs/assets/scss/docs.scss docs/assets/scss/*.scss",
"test": "npm run eslint && grunt test",
"uglify": "uglifyjs --compress warnings=false --mangle --comments '/^!/' --output dist/js/bootstrap.min.js dist/js/bootstrap.js",
"uglify-docs": "uglifyjs --compress warnings=false --mangle --comments '/^!/' --output docs/assets/js/docs.min.js docs/assets/js/vendor/*.js docs/assets/js/src/application.js",
"update-shrinkwrap": "npm shrinkwrap --dev && shx mv ./npm-shrinkwrap.json ./grunt/npm-shrinkwrap.json"
"bash": "bash",
"css": "npm-run-all css-lint css-compile css-prefix css-minify",
"css-compile": "node-sass --output-style expanded --source-map true --source-map-contents true --precision 6 scss/bootstrap.scss dist/css/bootstrap.css && node-sass --output-style expanded --source-map true --source-map-contents true --precision 6 scss/bootstrap-grid.scss dist/css/bootstrap-grid.css && node-sass --output-style expanded --source-map true --source-map-contents true --precision 6 scss/bootstrap-reboot.scss dist/css/bootstrap-reboot.css",
"css-compile-docs": "node-sass --output-style expanded --source-map true --source-map-contents true --precision 6 assets/scss/docs.scss assets/css/docs.min.css",
"css-docs": "npm-run-all css-lint-docs css-compile-docs css-prefix-docs css-minify-docs",
"css-lint": "bundle exec scss-lint --config .scss-lint.yml scss/*.scss",
"css-lint-docs": "bundle exec scss-lint --config .scss-lint.yml --exclude assets/scss/docs.scss assets/scss/*.scss",
"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",
"css-prefix": "postcss --config build/postcss.config.js --replace dist/css/*.css",
"css-prefix-docs": "postcss --config build/postcss.config.js --no-map --replace assets/css/docs.min.css",
"dist": "npm-run-all --parallel css js css-docs",
"docs": "npm-run-all docs-compile docs-lint",
"docs-compile": "bundle exec jekyll build",
"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-lint": "htmllint --rc build/.htmllintrc _gh_pages/*.html _gh_pages/**/*.html js/tests/visual/*.html",
"docs-serve": "bundle exec jekyll serve",
"docs-upload-preview": "build/upload-preview.sh",
"js": "npm-run-all js-lint js-compile js-minify",
"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",
"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-minify": "uglifyjs --config-file build/uglifyjs.config.json --output dist/js/bootstrap.min.js dist/js/bootstrap.js",
"js-minify-docs": "uglifyjs --config-file build/uglifyjs.config.json --output assets/js/docs.min.js assets/js/vendor/anchor.min.js assets/js/vendor/clipboard.min.js assets/js/vendor/holder.min.js assets/js/src/application.js",
"js-test": "phantomjs ./node_modules/qunit-phantomjs-runner/runner.js js/tests/index.html 60",
"js-test-cloud": "ruby -r webrick -e \"s = WEBrick::HTTPServer.new(:Port => 3000, :DocumentRoot => Dir.pwd, :Logger => WEBrick::Log.new('/dev/null'), :AccessLog => []); trap('INT') { s.shutdown }; s.start\" & grunt saucelabs-qunit",
"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",
"release-zip": "cd dist/ && zip -r9 bootstrap-$npm_package_version-dist.zip * && shx mv bootstrap-$npm_package_version-dist.zip ..",
"test": "npm-run-all dist js-test docs",
"watch": "npm-run-all --parallel watch-css watch-js",
"watch-css": "nodemon --ignore js/ --ignore dist/ -e scss -x \"npm run css && npm run css-docs\"",
"watch-js": "nodemon --ignore scss/ --ignore js/dist/ --ignore dist/ -e js -x \"npm run js-compile-plugins\""
},
"style": "dist/css/bootstrap.css",
"version": "4.0.0-alpha.6"
"version": "4.0.0-beta"
}
+4 -11
View File
@@ -41,15 +41,8 @@
//
// Generate contextual modifier classes for colorizing the alert.
.alert-success {
@include alert-variant($alert-success-bg, $alert-success-border, $alert-success-text);
}
.alert-info {
@include alert-variant($alert-info-bg, $alert-info-border, $alert-info-text);
}
.alert-warning {
@include alert-variant($alert-warning-bg, $alert-warning-border, $alert-warning-text);
}
.alert-danger {
@include alert-variant($alert-danger-bg, $alert-danger-border, $alert-danger-text);
@each $color, $value in $theme-colors {
.alert-#{$color} {
@include alert-variant(theme-color-level($color, -10), theme-color-level($color, -9), theme-color-level($color, 6));
}
}
+4 -33
View File
@@ -27,17 +27,6 @@
top: -1px;
}
// scss-lint:disable QualifyingElement
// Add hover effects, but only for links
a.badge {
@include hover-focus {
color: $badge-link-hover-color;
text-decoration: none;
cursor: pointer;
}
}
// scss-lint:enable QualifyingElement
// Pill badges
//
// Make them extra rounded with a modifier to replace v3's badges.
@@ -52,26 +41,8 @@ a.badge {
//
// Contextual variations (linked badges get darker on :hover).
.badge-default {
@include badge-variant($badge-default-bg);
}
.badge-primary {
@include badge-variant($badge-primary-bg);
}
.badge-success {
@include badge-variant($badge-success-bg);
}
.badge-info {
@include badge-variant($badge-info-bg);
}
.badge-warning {
@include badge-variant($badge-warning-bg);
}
.badge-danger {
@include badge-variant($badge-danger-bg);
@each $color, $value in $theme-colors {
.badge-#{$color} {
@include badge-variant($value);
}
}
+1 -1
View File
@@ -1,6 +1,6 @@
.breadcrumb {
padding: $breadcrumb-padding-y $breadcrumb-padding-x;
margin-bottom: $spacer-y;
margin-bottom: $breadcrumb-margin-bottom;
list-style: none;
background-color: $breadcrumb-bg;
@include border-radius($border-radius);
+11 -15
View File
@@ -10,8 +10,9 @@
> .btn {
position: relative;
flex: 0 1 auto;
margin-bottom: 0;
// Bring the hover, focused, and "active" buttons to the fron to overlay
// Bring the hover, focused, and "active" buttons to the front to overlay
// the borders properly
@include hover {
z-index: 2;
@@ -35,6 +36,7 @@
// Optional: Group multiple button groups together for a toolbar
.btn-toolbar {
display: flex;
flex-wrap: wrap;
justify-content: flex-start;
.input-group {
@@ -77,12 +79,6 @@
@include border-left-radius(0);
}
// On active and open, don't show outline
.btn-group .dropdown-toggle:active,
.btn-group.open .dropdown-toggle {
outline: 0;
}
// Sizing
//
@@ -97,8 +93,8 @@
//
.btn + .dropdown-toggle-split {
padding-right: $btn-padding-x * .75;
padding-left: $btn-padding-x * .75;
padding-right: $input-btn-padding-x * .75;
padding-left: $input-btn-padding-x * .75;
&::after {
margin-left: 0;
@@ -106,19 +102,19 @@
}
.btn-sm + .dropdown-toggle-split {
padding-right: $btn-padding-x-sm * .75;
padding-left: $btn-padding-x-sm * .75;
padding-right: $input-btn-padding-x-sm * .75;
padding-left: $input-btn-padding-x-sm * .75;
}
.btn-lg + .dropdown-toggle-split {
padding-right: $btn-padding-x-lg * .75;
padding-left: $btn-padding-x-lg * .75;
padding-right: $input-btn-padding-x-lg * .75;
padding-left: $input-btn-padding-x-lg * .75;
}
// The clickable button for toggling the menu
// Remove the gradient and set the same inset shadow as the :active state
.btn-group.open .dropdown-toggle {
// Set the same inset shadow as the :active state
.btn-group.show .dropdown-toggle {
@include box-shadow($btn-active-box-shadow);
// Show no shadow for `.btn-link` since it has no other button styles.
+13 -42
View File
@@ -7,13 +7,12 @@
.btn {
display: inline-block;
font-weight: $btn-font-weight;
line-height: $btn-line-height;
text-align: center;
white-space: nowrap;
vertical-align: middle;
user-select: none;
border: $input-btn-border-width solid transparent;
@include button-size($btn-padding-y, $btn-padding-x, $font-size-base, $btn-border-radius);
@include button-size($input-btn-padding-y, $input-btn-padding-x, $font-size-base, $input-btn-line-height, $btn-border-radius);
@include transition($btn-transition);
// Share hover and focus styles
@@ -29,7 +28,6 @@
// Disabled comes first so active can properly restyle
&.disabled,
&:disabled {
cursor: $cursor-disabled;
opacity: .65;
@include box-shadow(none);
}
@@ -52,43 +50,16 @@ fieldset[disabled] a.btn {
// Alternate buttons
//
.btn-primary {
@include button-variant($btn-primary-color, $btn-primary-bg, $btn-primary-border);
}
.btn-secondary {
@include button-variant($btn-secondary-color, $btn-secondary-bg, $btn-secondary-border);
}
.btn-info {
@include button-variant($btn-info-color, $btn-info-bg, $btn-info-border);
}
.btn-success {
@include button-variant($btn-success-color, $btn-success-bg, $btn-success-border);
}
.btn-warning {
@include button-variant($btn-warning-color, $btn-warning-bg, $btn-warning-border);
}
.btn-danger {
@include button-variant($btn-danger-color, $btn-danger-bg, $btn-danger-border);
@each $color, $value in $theme-colors {
.btn-#{$color} {
@include button-variant($value, $value);
}
}
// Remove all backgrounds
.btn-outline-primary {
@include button-outline-variant($btn-primary-bg);
}
.btn-outline-secondary {
@include button-outline-variant($btn-secondary-border);
}
.btn-outline-info {
@include button-outline-variant($btn-info-bg);
}
.btn-outline-success {
@include button-outline-variant($btn-success-bg);
}
.btn-outline-warning {
@include button-outline-variant($btn-warning-bg);
}
.btn-outline-danger {
@include button-outline-variant($btn-danger-bg);
@each $color, $value in $theme-colors {
.btn-outline-#{$color} {
@include button-outline-variant($value, #fff);
}
}
@@ -113,6 +84,7 @@ fieldset[disabled] a.btn {
&:focus,
&:active {
border-color: transparent;
box-shadow: none;
}
@include hover {
border-color: transparent;
@@ -137,12 +109,11 @@ fieldset[disabled] a.btn {
//
.btn-lg {
// line-height: ensure even-numbered height of button next to large input
@include button-size($btn-padding-y-lg, $btn-padding-x-lg, $font-size-lg, $btn-border-radius-lg);
@include button-size($input-btn-padding-y-lg, $input-btn-padding-x-lg, $font-size-lg, $line-height-lg, $btn-border-radius-lg);
}
.btn-sm {
// line-height: ensure proper height of button next to small input
@include button-size($btn-padding-y-sm, $btn-padding-x-sm, $font-size-sm, $btn-border-radius-sm);
@include button-size($input-btn-padding-y-sm, $input-btn-padding-x-sm, $font-size-sm, $line-height-sm, $btn-border-radius-sm);
}
+27 -80
View File
@@ -6,12 +6,15 @@
position: relative;
display: flex;
flex-direction: column;
min-width: 0;
word-wrap: break-word;
background-color: $card-bg;
background-clip: border-box;
border: $card-border-width solid $card-border-color;
@include border-radius($card-border-radius);
}
.card-block {
.card-body {
// Enable `flex-grow: 1` for decks and groups so that card blocks take up
// as much space as possible, ensuring footers are aligned to the bottom.
flex: 1 1 auto;
@@ -67,7 +70,7 @@
border-bottom: $card-border-width solid $card-border-color;
&:first-child {
@include border-radius($card-border-radius-inner $card-border-radius-inner 0 0);
@include border-radius($card-inner-border-radius $card-inner-border-radius 0 0);
}
}
@@ -77,7 +80,7 @@
border-top: $card-border-width solid $card-border-color;
&:last-child {
@include border-radius(0 0 $card-border-radius-inner $card-border-radius-inner);
@include border-radius(0 0 $card-inner-border-radius $card-inner-border-radius);
}
}
@@ -98,70 +101,7 @@
margin-left: -($card-spacer-x / 2);
}
//
// Background variations
//
.card-primary {
@include card-variant($brand-primary, $brand-primary);
}
.card-success {
@include card-variant($brand-success, $brand-success);
}
.card-info {
@include card-variant($brand-info, $brand-info);
}
.card-warning {
@include card-variant($brand-warning, $brand-warning);
}
.card-danger {
@include card-variant($brand-danger, $brand-danger);
}
// Remove all backgrounds
.card-outline-primary {
@include card-outline-variant($btn-primary-bg);
}
.card-outline-secondary {
@include card-outline-variant($btn-secondary-border);
}
.card-outline-info {
@include card-outline-variant($btn-info-bg);
}
.card-outline-success {
@include card-outline-variant($btn-success-bg);
}
.card-outline-warning {
@include card-outline-variant($btn-warning-bg);
}
.card-outline-danger {
@include card-outline-variant($btn-danger-bg);
}
//
// Inverse text within a card for use with dark backgrounds
//
.card-inverse {
@include card-inverse;
}
//
// Blockquote
//
.card-blockquote {
padding: 0;
margin-bottom: 0;
border-left: 0;
}
// Card image
.card-img {
// margin: -1.325rem;
@include border-radius($card-border-radius-inner);
}
.card-img-overlay {
position: absolute;
top: 0;
@@ -171,14 +111,20 @@
padding: $card-img-overlay-padding;
}
.card-img {
width: 100%; // Required because we use flexbox and this inherently applies align-self: stretch
@include border-radius($card-inner-border-radius);
}
// Card image caps
.card-img-top {
@include border-top-radius($card-border-radius-inner);
width: 100%; // Required because we use flexbox and this inherently applies align-self: stretch
@include border-top-radius($card-inner-border-radius);
}
.card-img-bottom {
@include border-bottom-radius($card-border-radius-inner);
width: 100%; // Required because we use flexbox and this inherently applies align-self: stretch
@include border-bottom-radius($card-inner-border-radius);
}
@@ -188,17 +134,15 @@
.card-deck {
display: flex;
flex-flow: row wrap;
margin-right: -$card-deck-margin;
margin-left: -$card-deck-margin;
.card {
display: flex;
flex: 1 0 0;
flex: 1 0 0%;
flex-direction: column;
// Selectively apply horizontal margins to cards to avoid doing the
// negative margin dance like our grid. This differs from the grid
// due to the use of margins as gutters instead of padding.
&:not(:first-child) { margin-left: $card-deck-margin; }
&:not(:last-child) { margin-right: $card-deck-margin; }
margin-right: $card-deck-margin;
margin-left: $card-deck-margin;
}
}
}
@@ -214,7 +158,7 @@
flex-flow: row wrap;
.card {
flex: 1 0 0;
flex: 1 0 0%;
+ .card {
margin-left: 0;
@@ -262,15 +206,18 @@
// Columns
//
@include media-breakpoint-up(sm) {
.card-columns {
.card-columns {
.card {
margin-bottom: $card-columns-margin;
}
@include media-breakpoint-up(sm) {
column-count: $card-columns-count;
column-gap: $card-columns-gap;
.card {
display: inline-block; // Don't let them vertically span multiple columns
width: 100%; // Don't let their width change
margin-bottom: $card-columns-margin;
}
}
}
+24 -17
View File
@@ -12,19 +12,17 @@
.carousel-item {
position: relative;
display: none;
align-items: center;
width: 100%;
@include if-supports-3d-transforms() {
@include transition($carousel-transition);
backface-visibility: hidden;
perspective: 1000px;
}
@include transition($carousel-transition);
backface-visibility: hidden;
perspective: 1000px;
}
.carousel-item.active,
.carousel-item-next,
.carousel-item-prev {
display: flex;
display: block;
}
.carousel-item-next,
@@ -34,19 +32,29 @@
}
// CSS3 transforms when supported by the browser
@include if-supports-3d-transforms() {
.carousel-item-next.carousel-item-left,
.carousel-item-prev.carousel-item-right {
.carousel-item-next.carousel-item-left,
.carousel-item-prev.carousel-item-right {
transform: translateX(0);
@supports (transform-style: preserve-3d) {
transform: translate3d(0, 0, 0);
}
}
.carousel-item-next,
.active.carousel-item-right {
.carousel-item-next,
.active.carousel-item-right {
transform: translateX(100%);
@supports (transform-style: preserve-3d) {
transform: translate3d(100%, 0, 0);
}
}
.carousel-item-prev,
.active.carousel-item-left {
.carousel-item-prev,
.active.carousel-item-left {
transform: translateX(-100%);
@supports (transform-style: preserve-3d) {
transform: translate3d(-100%, 0, 0);
}
}
@@ -125,13 +133,12 @@
li {
position: relative;
flex: 1 0 auto;
max-width: $carousel-indicator-width;
flex: 0 1 auto;
width: $carousel-indicator-width;
height: $carousel-indicator-height;
margin-right: $carousel-indicator-spacer;
margin-left: $carousel-indicator-spacer;
text-indent: -999px;
cursor: pointer;
background-color: rgba($carousel-indicator-active-bg, .5);
// Use pseudo classes to increase the hit area by 10px on top and bottom.
-2
View File
@@ -10,7 +10,6 @@
@include hover-focus {
color: $close-color;
text-decoration: none;
cursor: pointer;
opacity: .75;
}
}
@@ -23,7 +22,6 @@
// scss-lint:disable QualifyingElement
button.close {
padding: 0;
cursor: pointer;
background: transparent;
border: 0;
-webkit-appearance: none;
+36 -44
View File
@@ -1,4 +1,4 @@
// scss-lint:disable PropertyCount
// scss-lint:disable PropertyCount, VendorPrefix
// Embedded icons from Open Iconic.
// Released under MIT and copyright 2014 Waybury.
@@ -15,7 +15,6 @@
min-height: (1rem * $line-height-base);
padding-left: $custom-control-gutter;
margin-right: $custom-control-spacer-x;
cursor: pointer;
}
.custom-control-input {
@@ -24,31 +23,29 @@
opacity: 0;
&:checked ~ .custom-control-indicator {
color: $custom-control-checked-indicator-color;
background-color: $custom-control-checked-indicator-bg;
@include box-shadow($custom-control-checked-indicator-box-shadow);
color: $custom-control-indicator-checked-color;
background-color: $custom-control-indicator-checked-bg;
@include box-shadow($custom-control-indicator-checked-box-shadow);
}
&:focus ~ .custom-control-indicator {
// the mixin is not used here to make sure there is feedback
box-shadow: $custom-control-focus-indicator-box-shadow;
box-shadow: $custom-control-indicator-focus-box-shadow;
}
&:active ~ .custom-control-indicator {
color: $custom-control-active-indicator-color;
background-color: $custom-control-active-indicator-bg;
@include box-shadow($custom-control-active-indicator-box-shadow);
color: $custom-control-indicator-active-color;
background-color: $custom-control-indicator-active-bg;
@include box-shadow($custom-control-indicator-active-box-shadow);
}
&:disabled {
~ .custom-control-indicator {
cursor: $custom-control-disabled-cursor;
background-color: $custom-control-disabled-indicator-bg;
background-color: $custom-control-indicator-disabled-bg;
}
~ .custom-control-description {
color: $custom-control-disabled-description-color;
cursor: $custom-control-disabled-cursor;
color: $custom-control-description-disabled-color;
}
}
}
@@ -79,17 +76,17 @@
.custom-checkbox {
.custom-control-indicator {
@include border-radius($custom-checkbox-radius);
@include border-radius($custom-checkbox-indicator-border-radius);
}
.custom-control-input:checked ~ .custom-control-indicator {
background-image: $custom-checkbox-checked-icon;
background-image: $custom-checkbox-indicator-icon-checked;
}
.custom-control-input:indeterminate ~ .custom-control-indicator {
background-color: $custom-checkbox-indeterminate-bg;
background-image: $custom-checkbox-indeterminate-icon;
@include box-shadow($custom-checkbox-indeterminate-box-shadow);
background-color: $custom-checkbox-indicator-indeterminate-bg;
background-image: $custom-checkbox-indicator-icon-indeterminate;
@include box-shadow($custom-checkbox-indicator-indeterminate-box-shadow);
}
}
@@ -99,11 +96,11 @@
.custom-radio {
.custom-control-indicator {
border-radius: $custom-radio-radius;
border-radius: $custom-radio-indicator-border-radius;
}
.custom-control-input:checked ~ .custom-control-indicator {
background-image: $custom-radio-checked-icon;
background-image: $custom-radio-indicator-icon-checked;
}
}
@@ -136,19 +133,21 @@
.custom-select {
display: inline-block;
max-width: 100%;
$select-border-width: ($border-width * 2);
height: calc(#{$input-height} + #{$select-border-width});
height: $input-height;
padding: $custom-select-padding-y ($custom-select-padding-x + $custom-select-indicator-padding) $custom-select-padding-y $custom-select-padding-x;
line-height: $custom-select-line-height;
color: $custom-select-color;
vertical-align: middle;
background: $custom-select-bg $custom-select-indicator no-repeat right $custom-select-padding-x center;
background-clip: padding-box;
background-size: $custom-select-bg-size;
border: $custom-select-border-width solid $custom-select-border-color;
@include border-radius($custom-select-border-radius);
// Use vendor prefixes as `appearance` isn't part of the CSS spec.
-moz-appearance: none;
-webkit-appearance: none;
@if $enable-rounded {
border-radius: $custom-select-border-radius;
} @else {
border-radius: 0;
}
appearance: none;
&:focus {
border-color: $custom-select-focus-border-color;
@@ -168,7 +167,6 @@
&:disabled {
color: $custom-select-disabled-color;
cursor: $cursor-disabled;
background-color: $custom-select-disabled-bg;
}
@@ -179,14 +177,10 @@
}
.custom-select-sm {
height: $custom-select-height-sm;
padding-top: $custom-select-padding-y;
padding-bottom: $custom-select-padding-y;
font-size: $custom-select-sm-font-size;
// &:not([multiple]) {
// height: 26px;
// min-height: 26px;
// }
font-size: $custom-select-font-size-sm;
}
@@ -200,7 +194,6 @@
max-width: 100%;
height: $custom-file-height;
margin-bottom: 0;
cursor: pointer;
}
.custom-file-input {
@@ -208,11 +201,10 @@
max-width: 100%;
height: $custom-file-height;
margin: 0;
filter: alpha(opacity = 0);
opacity: 0;
&:focus ~ .custom-file-control {
@include box-shadow($custom-file-focus-box-shadow);
box-shadow: $custom-file-focus-box-shadow;
}
}
@@ -223,36 +215,36 @@
left: 0;
z-index: 5;
height: $custom-file-height;
padding: $custom-file-padding-x $custom-file-padding-y;
padding: $custom-file-padding-y $custom-file-padding-x;
overflow: hidden;
line-height: $custom-file-line-height;
color: $custom-file-color;
pointer-events: none;
user-select: none;
background-color: $custom-file-bg;
background-clip: padding-box;
border: $custom-file-border-width solid $custom-file-border-color;
@include border-radius($custom-file-border-radius);
@include box-shadow($custom-file-box-shadow);
@each $lang, $text in map-get($custom-file-text, placeholder) {
&:lang(#{$lang})::after {
&:lang(#{$lang}):empty::after {
content: $text;
}
}
&::before {
position: absolute;
top: -$custom-file-border-width;
right: -$custom-file-border-width;
bottom: -$custom-file-border-width;
top: 0;
right: 0;
z-index: 6;
display: block;
height: $custom-file-height;
padding: $custom-file-padding-x $custom-file-padding-y;
padding: $custom-file-padding-y $custom-file-padding-x;
line-height: $custom-file-line-height;
color: $custom-file-button-color;
background-color: $custom-file-button-bg;
border: $custom-file-border-width solid $custom-file-border-color;
@include border-radius(0 $custom-file-border-radius $custom-file-border-radius 0);
border-left: $custom-file-border-width solid $custom-file-border-color;
}
@each $lang, $text in map-get($custom-file-text, button-label) {
-4
View File
@@ -1,4 +0,0 @@
// Bootstrap overrides
//
// Copy variables from `_variables.scss` to this file to override default values
// without modifying source files.
+15 -48
View File
@@ -10,21 +10,27 @@
display: inline-block;
width: 0;
height: 0;
margin-left: $caret-width;
vertical-align: middle;
margin-left: $caret-width * .85;
vertical-align: $caret-width * .85;
content: "";
border-top: $caret-width solid;
border-right: $caret-width solid transparent;
border-left: $caret-width solid transparent;
}
// Prevent the focus on the dropdown toggle when closing dropdowns
&:focus {
outline: 0;
&:empty::after {
margin-left: 0;
}
}
// Allow for dropdowns to go bottom up (aka, dropup-menu)
// Just add .dropup after the standard .dropdown class and you're set.
.dropup {
.dropdown-menu {
margin-top: 0;
margin-bottom: $dropdown-spacer;
}
.dropdown-toggle {
&::after {
border-top: 0;
@@ -43,7 +49,7 @@
float: left;
min-width: $dropdown-min-width;
padding: $dropdown-padding-y 0;
margin: $dropdown-margin-top 0 0; // override default ul
margin: $dropdown-spacer 0 0; // override default ul
font-size: $font-size-base; // Redeclare because nesting can cause inheritance issues
color: $body-color;
text-align: left; // Ensures proper alignment if parent has it changed (e.g., modal footer)
@@ -66,7 +72,7 @@
.dropdown-item {
display: block;
width: 100%; // For `<button>`s
padding: 3px $dropdown-item-padding-x;
padding: $dropdown-item-padding-y $dropdown-item-padding-x;
clear: both;
font-weight: $font-weight-normal;
color: $dropdown-link-color;
@@ -91,7 +97,6 @@
&.disabled,
&:disabled {
color: $dropdown-link-disabled-color;
cursor: $cursor-disabled;
background-color: transparent;
// Remove CSS gradients if they're enabled
@if $enable-gradients {
@@ -102,29 +107,14 @@
// Open state for the dropdown
.show {
// Show the menu
> .dropdown-menu {
display: block;
}
// Remove the outline when :focus is triggered
> a {
outline: 0;
}
}
// Menu positioning
//
// Add extra class to `.dropdown-menu` to flip the alignment of the dropdown
// menu with the parent.
.dropdown-menu-right {
right: 0;
left: auto; // Reset the default from `.dropdown-menu`
}
.dropdown-menu-left {
right: auto;
left: 0;
.dropdown-menu.show {
display: block;
}
// Dropdown section headers
@@ -136,26 +126,3 @@
color: $dropdown-header-color;
white-space: nowrap; // as with > li > a
}
// Backdrop to catch body clicks on mobile, etc.
.dropdown-backdrop {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: $zindex-dropdown-backdrop;
}
// Allow for dropdowns to go bottom up (aka, dropup-menu)
//
// Just add .dropup after the standard .dropdown class and you're set.
.dropup {
// Different positioning for bottom up menu
.dropdown-menu {
top: auto;
bottom: 100%;
margin-bottom: $dropdown-margin-top;
}
}
+69 -71
View File
@@ -1,4 +1,4 @@
// scss-lint:disable QualifyingElement
// scss-lint:disable QualifyingElement, VendorPrefix
//
// Textual form controls
@@ -9,9 +9,9 @@
width: 100%;
// // Make inputs at least the height of their button counterpart (base line-height + padding + border)
// height: $input-height;
padding: $input-padding-y $input-padding-x;
padding: $input-btn-padding-y $input-btn-padding-x;
font-size: $font-size-base;
line-height: $input-line-height;
line-height: $input-btn-line-height;
color: $input-color;
background-color: $input-bg;
// Reset unusual Firefox-on-Android default style; see https://github.com/necolas/normalize.css/issues/214.
@@ -42,7 +42,7 @@
// Placeholder
&::placeholder {
color: $input-color-placeholder;
color: $input-placeholder-color;
// Override Firefox's unusual default opacity; see https://github.com/twbs/bootstrap/pull/11526.
opacity: 1;
}
@@ -54,20 +54,15 @@
// don't honor that edge case; we style them as disabled anyway.
&:disabled,
&[readonly] {
background-color: $input-bg-disabled;
background-color: $input-disabled-bg;
// iOS fix for unreadable disabled content; see https://github.com/twbs/bootstrap/issues/11655.
opacity: 1;
}
&:disabled {
cursor: $cursor-disabled;
}
}
select.form-control {
&:not([size]):not([multiple]) {
$select-border-width: ($border-width * 2);
height: calc(#{$input-height} + #{$select-border-width});
height: $input-height;
}
&:focus::-ms-value {
@@ -95,20 +90,20 @@ select.form-control {
// For use with horizontal and inline forms, when you need the label text to
// align with the form controls.
.col-form-label {
padding-top: calc(#{$input-padding-y} - #{$input-btn-border-width} * 2);
padding-bottom: calc(#{$input-padding-y} - #{$input-btn-border-width} * 2);
padding-top: calc(#{$input-btn-padding-y} - #{$input-btn-border-width} * 2);
padding-bottom: calc(#{$input-btn-padding-y} - #{$input-btn-border-width} * 2);
margin-bottom: 0; // Override the `<label>` default
}
.col-form-label-lg {
padding-top: calc(#{$input-padding-y-lg} - #{$input-btn-border-width} * 2);
padding-bottom: calc(#{$input-padding-y-lg} - #{$input-btn-border-width} * 2);
padding-top: calc(#{$input-btn-padding-y-lg} - #{$input-btn-border-width} * 2);
padding-bottom: calc(#{$input-btn-padding-y-lg} - #{$input-btn-border-width} * 2);
font-size: $font-size-lg;
}
.col-form-label-sm {
padding-top: calc(#{$input-padding-y-sm} - #{$input-btn-border-width} * 2);
padding-bottom: calc(#{$input-padding-y-sm} - #{$input-btn-border-width} * 2);
padding-top: calc(#{$input-btn-padding-y-sm} - #{$input-btn-border-width} * 2);
padding-bottom: calc(#{$input-btn-padding-y-sm} - #{$input-btn-border-width} * 2);
font-size: $font-size-sm;
}
@@ -120,23 +115,23 @@ select.form-control {
// For use with horizontal and inline forms, when you need the legend text to
// be the same size as regular labels, and to align with the form controls.
.col-form-legend {
padding-top: $input-padding-y;
padding-bottom: $input-padding-y;
padding-top: $input-btn-padding-y;
padding-bottom: $input-btn-padding-y;
margin-bottom: 0;
font-size: $font-size-base;
}
// Static form control text
// Readonly controls as plain text
//
// Apply class to an element to make any string of text align with labels in a
// horizontal form layout.
// Apply class to a readonly input to make it appear like regular plain
// text (without any border, background color, focus indicator)
.form-control-static {
padding-top: $input-padding-y;
padding-bottom: $input-padding-y;
.form-control-plaintext {
padding-top: $input-btn-padding-y;
padding-bottom: $input-btn-padding-y;
margin-bottom: 0; // match inputs if this class comes on inputs with default margins
line-height: $input-line-height;
line-height: $input-btn-line-height;
border: solid transparent;
border-width: $input-btn-border-width 0;
@@ -157,8 +152,9 @@ select.form-control {
// issue documented in https://github.com/twbs/bootstrap/issues/15074.
.form-control-sm {
padding: $input-padding-y-sm $input-padding-x-sm;
padding: $input-btn-padding-y-sm $input-btn-padding-x-sm;
font-size: $font-size-sm;
line-height: $input-btn-line-height-sm;
@include border-radius($input-border-radius-sm);
}
@@ -169,8 +165,9 @@ select.form-control-sm {
}
.form-control-lg {
padding: $input-padding-y-lg $input-padding-x-lg;
padding: $input-btn-padding-y-lg $input-btn-padding-x-lg;
font-size: $font-size-lg;
line-height: $input-btn-line-height-lg;
@include border-radius($input-border-radius-lg);
}
@@ -196,6 +193,24 @@ select.form-control-lg {
}
// Form grid
//
// Special replacement for our grid system's `.row` for tighter form layouts.
.form-row {
display: flex;
flex-wrap: wrap;
margin-right: -5px;
margin-left: -5px;
> .col,
> [class*="col-"] {
padding-right: 5px;
padding-left: 5px;
}
}
// Checkboxes and radios
//
// Indent the labels to position radios/checkboxes as hanging controls.
@@ -208,7 +223,6 @@ select.form-control-lg {
&.disabled {
.form-check-label {
color: $text-muted;
cursor: $cursor-disabled;
}
}
}
@@ -216,17 +230,12 @@ select.form-control-lg {
.form-check-label {
padding-left: $form-check-input-gutter;
margin-bottom: 0; // Override default `<label>` bottom margin
cursor: pointer;
}
.form-check-input {
position: absolute;
margin-top: $form-check-input-margin-y;
margin-left: -$form-check-input-gutter;
&:only-child {
position: static;
}
}
// Radios and checkboxes on same line
@@ -243,48 +252,37 @@ select.form-control-lg {
}
// Form control feedback states
// Form validation
//
// Apply contextual and semantic states to individual form controls.
// Provide feedback to users when form field values are valid or invalid. Works
// primarily for client-side validation via scoped `:invalid` and `:valid`
// pseudo-classes but also includes `.is-invalid` and `.is-valid` classes for
// server side validation.
.form-control-feedback {
margin-top: $form-feedback-margin-top;
.invalid-feedback {
display: none;
margin-top: .25rem;
font-size: .875rem;
color: $form-feedback-invalid-color;
}
.form-control-success,
.form-control-warning,
.form-control-danger {
padding-right: ($input-padding-x * 3);
background-repeat: no-repeat;
background-position: center right ($input-height / 4);
background-size: ($input-height / 2) ($input-height / 2);
}
// Form validation states
.has-success {
@include form-control-validation($brand-success);
.form-control-success {
background-image: $form-icon-success;
}
}
.has-warning {
@include form-control-validation($brand-warning);
.form-control-warning {
background-image: $form-icon-warning;
}
}
.has-danger {
@include form-control-validation($brand-danger);
.form-control-danger {
background-image: $form-icon-danger;
}
.invalid-tooltip {
position: absolute;
top: 100%;
z-index: 5;
display: none;
width: 250px;
padding: .5rem;
margin-top: .1rem;
font-size: .875rem;
line-height: 1;
color: #fff;
background-color: rgba($form-feedback-invalid-color,.8);
border-radius: .2rem;
}
@include form-validation-state("valid", $form-feedback-valid-color);
@include form-validation-state("invalid", $form-feedback-invalid-color);
// Inline forms
//
@@ -333,7 +331,7 @@ select.form-control-lg {
}
// Make static controls behave like regular ones
.form-control-static {
.form-control-plaintext {
display: inline-block;
}
+3 -2
View File
@@ -11,11 +11,12 @@
// Fluid container
//
// Utilizes the mixin meant for fixed width containers, but without any defined
// width for fluid, full width layouts.
// Utilizes the mixin meant for fixed width containers, but with 100% width for
// fluid, full width layouts.
@if $enable-grid-classes {
.container-fluid {
width: 100%;
@include make-container();
}
}
+1 -1
View File
@@ -33,7 +33,7 @@
}
.figure-img {
margin-bottom: ($spacer-y / 2);
margin-bottom: ($spacer / 2);
line-height: 1;
}
+10 -9
View File
@@ -30,8 +30,7 @@
.input-group .form-control {
// Vertically centers the content of the addons within the input group
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
&:not(:first-child):not(:last-child) {
@include border-radius(0);
@@ -67,25 +66,27 @@
//
.input-group-addon {
padding: $input-padding-y $input-padding-x;
padding: $input-btn-padding-y $input-btn-padding-x;
margin-bottom: 0; // Allow use of <label> elements by overriding our default margin-bottom
font-size: $font-size-base; // Match inputs
font-weight: $font-weight-normal;
line-height: $input-line-height;
color: $input-color;
line-height: $input-btn-line-height;
color: $input-group-addon-color;
text-align: center;
background-color: $input-group-addon-bg;
background-clip: padding-box;
border: $input-btn-border-width solid $input-group-addon-border-color;
@include border-radius($input-border-radius);
// Sizing
&.form-control-sm {
padding: $input-padding-y-sm $input-padding-x-sm;
padding: $input-btn-padding-y-sm $input-btn-padding-x-sm;
font-size: $font-size-sm;
@include border-radius($input-border-radius-sm);
}
&.form-control-lg {
padding: $input-padding-y-lg $input-padding-x-lg;
padding: $input-btn-padding-y-lg $input-btn-padding-x-lg;
font-size: $font-size-lg;
@include border-radius($input-border-radius-lg);
}
@@ -144,8 +145,8 @@
// element above the siblings.
> .btn {
position: relative;
// Vertically stretch the button and center its content
flex: 1;
background-clip: padding-box;
border: $input-btn-border-width solid $input-group-btn-border-color;
+ .btn {
margin-left: (-$input-btn-border-width);
-4
View File
@@ -9,10 +9,6 @@
}
}
.jumbotron-hr {
border-top-color: darken($jumbotron-bg, 10%);
}
.jumbotron-fluid {
padding-right: 0;
padding-left: 0;
+9 -36
View File
@@ -19,23 +19,19 @@
.list-group-item-action {
width: 100%; // For `<button>`s (anchors become 100% by default though)
color: $list-group-link-color;
color: $list-group-action-color;
text-align: inherit; // For `<button>`s (anchors inherit)
.list-group-item-heading {
color: $list-group-link-heading-color;
}
// Hover state
@include hover-focus {
color: $list-group-link-hover-color;
color: $list-group-action-hover-color;
text-decoration: none;
background-color: $list-group-hover-bg;
}
&:active {
color: $list-group-link-active-color;
background-color: $list-group-link-active-bg;
color: $list-group-action-active-color;
background-color: $list-group-action-active-bg;
}
}
@@ -46,9 +42,7 @@
.list-group-item {
position: relative;
display: flex;
flex-flow: row wrap;
align-items: center;
display: block;
padding: $list-group-item-padding-y $list-group-item-padding-x;
// Place the border on the list items and negative margin up for better styling
margin-bottom: -$list-group-border-width;
@@ -71,16 +65,7 @@
&.disabled,
&:disabled {
color: $list-group-disabled-color;
cursor: $cursor-disabled;
background-color: $list-group-disabled-bg;
// Force color to inherit for custom content
.list-group-item-heading {
color: inherit;
}
.list-group-item-text {
color: $list-group-disabled-text-color;
}
}
// Include both here for `<a>`s and `<button>`s
@@ -88,18 +73,7 @@
z-index: 2; // Place active items above their siblings for proper border styling
color: $list-group-active-color;
background-color: $list-group-active-bg;
border-color: $list-group-active-border;
// Force color to inherit for custom content
.list-group-item-heading,
.list-group-item-heading > small,
.list-group-item-heading > .small {
color: inherit;
}
.list-group-item-text {
color: $list-group-active-text-color;
}
border-color: $list-group-active-border-color;
}
}
@@ -135,7 +109,6 @@
// Add modifier classes to change text and background color on individual items.
// Organizationally, this must come after the `:hover` states.
@include list-group-item-variant(success, $state-success-bg, $state-success-text);
@include list-group-item-variant(info, $state-info-bg, $state-info-text);
@include list-group-item-variant(warning, $state-warning-bg, $state-warning-text);
@include list-group-item-variant(danger, $state-danger-bg, $state-danger-text);
@each $color, $value in $theme-colors {
@include list-group-item-variant($color, theme-color-level($color, -9), theme-color-level($color, 6));
}
+2 -18
View File
@@ -2,22 +2,6 @@
//
// Used in conjunction with global variables to enable certain theme features.
@mixin box-shadow($shadow...) {
@if $enable-shadows {
box-shadow: $shadow;
}
}
@mixin transition($transition...) {
@if $enable-transitions {
@if length($transition) == 0 {
transition: $transition-base;
} @else {
transition: $transition;
}
}
}
// Utilities
@import "mixins/breakpoints";
@import "mixins/hover";
@@ -30,13 +14,11 @@
@import "mixins/text-emphasis";
@import "mixins/text-hide";
@import "mixins/text-truncate";
@import "mixins/transforms";
@import "mixins/visibility";
// // Components
@import "mixins/alert";
@import "mixins/buttons";
@import "mixins/cards";
@import "mixins/pagination";
@import "mixins/lists";
@import "mixins/list-group";
@@ -47,7 +29,9 @@
// // Skins
@import "mixins/background-variant";
@import "mixins/border-radius";
@import "mixins/box-shadow";
@import "mixins/gradients";
@import "mixins/transition";
// // Layout
@import "mixins/clearfix";
+7 -3
View File
@@ -54,7 +54,7 @@
background-clip: padding-box;
border: $modal-content-border-width solid $modal-content-border-color;
@include border-radius($border-radius-lg);
@include box-shadow($modal-content-xs-box-shadow);
@include box-shadow($modal-content-box-shadow-xs);
// Remove focus outline from opened modal
outline: 0;
}
@@ -82,6 +82,10 @@
justify-content: space-between; // Put modal header elements (title and dismiss) on opposite ends
padding: $modal-header-padding;
border-bottom: $modal-header-border-width solid $modal-header-border-color;
.close {
margin-left: auto; // Force icon to the right even when there's no .modal-title
}
}
// Title text within header
@@ -127,11 +131,11 @@
// Automatically set modal's width for larger viewports
.modal-dialog {
max-width: $modal-md;
margin: $modal-dialog-sm-up-margin-y auto;
margin: $modal-dialog-margin-y-sm-up auto;
}
.modal-content {
@include box-shadow($modal-content-sm-up-box-shadow);
@include box-shadow($modal-content-box-shadow-sm-up);
}
.modal-sm { max-width: $modal-sm; }
+15 -16
View File
@@ -5,6 +5,7 @@
.nav {
display: flex;
flex-wrap: wrap;
padding-left: 0;
margin-bottom: 0;
list-style: none;
@@ -12,20 +13,18 @@
.nav-link {
display: block;
padding: $nav-link-padding;
padding: $nav-link-padding-y $nav-link-padding-x;
@include hover-focus {
text-decoration: none;
}
// Disabled state lightens text and removes hover/tab effects
// Disabled state lightens text
&.disabled {
color: $nav-disabled-link-color;
cursor: $cursor-disabled;
color: $nav-link-disabled-color;
}
}
//
// Tabs
//
@@ -46,7 +45,7 @@
}
&.disabled {
color: $nav-disabled-link-color;
color: $nav-link-disabled-color;
background-color: transparent;
border-color: transparent;
}
@@ -54,9 +53,9 @@
.nav-link.active,
.nav-item.show .nav-link {
color: $nav-tabs-active-link-hover-color;
background-color: $nav-tabs-active-link-hover-bg;
border-color: $nav-tabs-active-link-hover-border-color $nav-tabs-active-link-hover-border-color $nav-tabs-active-link-hover-bg;
color: $nav-tabs-link-active-color;
background-color: $nav-tabs-link-active-bg;
border-color: $nav-tabs-link-active-border-color $nav-tabs-link-active-border-color $nav-tabs-link-active-bg;
}
.dropdown-menu {
@@ -75,13 +74,12 @@
.nav-pills {
.nav-link {
@include border-radius($nav-pills-border-radius);
}
.nav-link.active,
.nav-item.show .nav-link {
color: $nav-pills-active-link-color;
cursor: default;
background-color: $nav-pills-active-link-bg;
&.active,
.show > & {
color: $nav-pills-link-active-color;
background-color: $nav-pills-link-active-bg;
}
}
}
@@ -99,7 +97,8 @@
.nav-justified {
.nav-item {
flex: 1 1 100%;
flex-basis: 0;
flex-grow: 1;
text-align: center;
}
}
+70 -54
View File
@@ -18,8 +18,20 @@
.navbar {
position: relative;
display: flex;
flex-direction: column;
flex-wrap: wrap; // allow us to do the line break for collapsing content
align-items: center;
justify-content: space-between; // space out brand from logo
padding: $navbar-padding-y $navbar-padding-x;
// Because flex properties aren't inherited, we need to redeclare these first
// few properities so that content nested within behave properly.
> .container,
> .container-fluid {
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: space-between;
}
}
@@ -29,10 +41,10 @@
.navbar-brand {
display: inline-block;
padding-top: .25rem;
padding-bottom: .25rem;
padding-top: $navbar-brand-padding-y;
padding-bottom: $navbar-brand-padding-y;
margin-right: $navbar-padding-x;
font-size: $font-size-lg;
font-size: $navbar-brand-font-size;
line-height: inherit;
white-space: nowrap;
@@ -57,6 +69,11 @@
padding-right: 0;
padding-left: 0;
}
.dropdown-menu {
position: static;
float: none;
}
}
@@ -66,8 +83,8 @@
.navbar-text {
display: inline-block;
padding-top: .425rem;
padding-bottom: .425rem;
padding-top: $nav-link-padding-y;
padding-bottom: $nav-link-padding-y;
}
@@ -76,9 +93,18 @@
// Custom styles for responsive collapsing and toggling of navbar contents.
// Powered by the collapse Bootstrap JavaScript plugin.
// When collapsed, prevent the toggleable navbar contents from appearing in
// the default flexbox row orienation. Requires the use of `flex-wrap: wrap`
// on the `.navbar` parent.
.navbar-collapse {
flex-basis: 100%;
// For always expanded or extra full navbars, ensure content aligns itself
// properly vertically. Can be easily overridden with flex utilities.
align-items: center;
}
// Button for toggling the navbar when in its collapsed state
.navbar-toggler {
align-self: flex-start; // Prevent toggler from growing to full width when it's the only visible navbar child
padding: $navbar-toggler-padding-y $navbar-toggler-padding-x;
font-size: $navbar-toggler-font-size;
line-height: 1;
@@ -103,34 +129,17 @@
background-size: 100% 100%;
}
// Use `position` on the toggler to prevent it from being auto placed as a flex
// item and allow easy placement.
.navbar-toggler-left {
position: absolute;
left: $navbar-padding-x;
}
.navbar-toggler-right {
position: absolute;
right: $navbar-padding-x;
}
// Generate series of `.navbar-toggleable-*` responsive classes for configuring
// Generate series of `.navbar-expand-*` responsive classes for configuring
// where your navbar collapses.
.navbar-toggleable {
.navbar-expand {
@each $breakpoint in map-keys($grid-breakpoints) {
$next: breakpoint-next($breakpoint, $grid-breakpoints);
$infix: breakpoint-infix($breakpoint, $grid-breakpoints);
$infix: breakpoint-infix($next, $grid-breakpoints);
&#{$infix} {
@include media-breakpoint-down($breakpoint) {
.navbar-nav {
.dropdown-menu {
position: static;
float: none;
}
}
> .container {
> .container,
> .container-fluid {
padding-right: 0;
padding-left: 0;
}
@@ -139,11 +148,20 @@
@include media-breakpoint-up($next) {
flex-direction: row;
flex-wrap: nowrap;
align-items: center;
justify-content: flex-start;
.navbar-nav {
flex-direction: row;
.dropdown-menu {
position: absolute;
}
.dropdown-menu-right {
right: 0;
left: auto; // Reset the default from `.dropdown-menu`
}
.nav-link {
padding-right: .5rem;
padding-left: .5rem;
@@ -151,16 +169,14 @@
}
// For nesting containers, have to redeclare for alignment purposes
> .container {
display: flex;
> .container,
> .container-fluid {
flex-wrap: nowrap;
align-items: center;
}
// scss-lint:disable ImportantRule
.navbar-collapse {
display: flex !important;
width: 100%;
}
// scss-lint:enable ImportantRule
@@ -179,8 +195,7 @@
// Dark links against a light background
.navbar-light {
.navbar-brand,
.navbar-toggler {
.navbar-brand {
color: $navbar-light-active-color;
@include hover-focus {
@@ -201,20 +216,21 @@
}
}
.open > .nav-link,
.show > .nav-link,
.active > .nav-link,
.nav-link.open,
.nav-link.show,
.nav-link.active {
color: $navbar-light-active-color;
}
}
.navbar-toggler {
border-color: $navbar-light-toggler-border;
color: $navbar-light-color;
border-color: $navbar-light-toggler-border-color;
}
.navbar-toggler-icon {
background-image: $navbar-light-toggler-bg;
background-image: $navbar-light-toggler-icon-bg;
}
.navbar-text {
@@ -223,46 +239,46 @@
}
// White links against a dark background
.navbar-inverse {
.navbar-brand,
.navbar-toggler {
color: $navbar-inverse-active-color;
.navbar-dark {
.navbar-brand {
color: $navbar-dark-active-color;
@include hover-focus {
color: $navbar-inverse-active-color;
color: $navbar-dark-active-color;
}
}
.navbar-nav {
.nav-link {
color: $navbar-inverse-color;
color: $navbar-dark-color;
@include hover-focus {
color: $navbar-inverse-hover-color;
color: $navbar-dark-hover-color;
}
&.disabled {
color: $navbar-inverse-disabled-color;
color: $navbar-dark-disabled-color;
}
}
.open > .nav-link,
.show > .nav-link,
.active > .nav-link,
.nav-link.open,
.nav-link.show,
.nav-link.active {
color: $navbar-inverse-active-color;
color: $navbar-dark-active-color;
}
}
.navbar-toggler {
border-color: $navbar-inverse-toggler-border;
color: $navbar-dark-color;
border-color: $navbar-dark-toggler-border-color;
}
.navbar-toggler-icon {
background-image: $navbar-inverse-toggler-bg;
background-image: $navbar-dark-toggler-icon-bg;
}
.navbar-text {
color: $navbar-inverse-color;
color: $navbar-dark-color;
}
}
-461
View File
@@ -1,461 +0,0 @@
/*! normalize.css v5.0.0 | MIT License | github.com/necolas/normalize.css */
//
// 1. Change the default font family in all browsers (opinionated).
// 2. Correct the line height in all browsers.
// 3. Prevent adjustments of font size after orientation changes in
// IE on Windows Phone and in iOS.
//
// Document
// ==========================================================================
html {
font-family: sans-serif; // 1
line-height: 1.15; // 2
-ms-text-size-adjust: 100%; // 3
-webkit-text-size-adjust: 100%; // 3
}
// Sections
// ==========================================================================
//
// Remove the margin in all browsers (opinionated).
//
body {
margin: 0;
}
//
// Add the correct display in IE 9-.
//
article,
aside,
footer,
header,
nav,
section {
display: block;
}
//
// Correct the font size and margin on `h1` elements within `section` and
// `article` contexts in Chrome, Firefox, and Safari.
//
h1 {
font-size: 2em;
margin: 0.67em 0;
}
// Grouping content
// ==========================================================================
//
// Add the correct display in IE 9-.
// 1. Add the correct display in IE.
//
figcaption,
figure,
main { // 1
display: block;
}
//
// Add the correct margin in IE 8.
//
figure {
margin: 1em 40px;
}
//
// 1. Add the correct box sizing in Firefox.
// 2. Show the overflow in Edge and IE.
//
hr {
box-sizing: content-box; // 1
height: 0; // 1
overflow: visible; // 2
}
//
// 1. Correct the inheritance and scaling of font size in all browsers.
// 2. Correct the odd `em` font sizing in all browsers.
//
pre {
font-family: monospace, monospace; // 1
font-size: 1em; // 2
}
// Text-level semantics
// ==========================================================================
//
// 1. Remove the gray background on active links in IE 10.
// 2. Remove gaps in links underline in iOS 8+ and Safari 8+.
//
a {
background-color: transparent; // 1
-webkit-text-decoration-skip: objects; // 2
}
//
// Remove the outline on focused links when they are also active or hovered
// in all browsers (opinionated).
//
a:active,
a:hover {
outline-width: 0;
}
//
// 1. Remove the bottom border in Firefox 39-.
// 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.
//
abbr[title] {
border-bottom: none; // 1
text-decoration: underline; // 2
text-decoration: underline dotted; // 2
}
//
// Prevent the duplicate application of `bolder` by the next rule in Safari 6.
//
b,
strong {
font-weight: inherit;
}
//
// Add the correct font weight in Chrome, Edge, and Safari.
//
b,
strong {
font-weight: bolder;
}
//
// 1. Correct the inheritance and scaling of font size in all browsers.
// 2. Correct the odd `em` font sizing in all browsers.
//
code,
kbd,
samp {
font-family: monospace, monospace; // 1
font-size: 1em; // 2
}
//
// Add the correct font style in Android 4.3-.
//
dfn {
font-style: italic;
}
//
// Add the correct background and color in IE 9-.
//
mark {
background-color: #ff0;
color: #000;
}
//
// Add the correct font size in all browsers.
//
small {
font-size: 80%;
}
//
// Prevent `sub` and `sup` elements from affecting the line height in
// all browsers.
//
sub,
sup {
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: baseline;
}
sub {
bottom: -0.25em;
}
sup {
top: -0.5em;
}
// Embedded content
// ==========================================================================
//
// Add the correct display in IE 9-.
//
audio,
video {
display: inline-block;
}
//
// Add the correct display in iOS 4-7.
//
audio:not([controls]) {
display: none;
height: 0;
}
//
// Remove the border on images inside links in IE 10-.
//
img {
border-style: none;
}
//
// Hide the overflow in IE.
//
svg:not(:root) {
overflow: hidden;
}
// Forms
// ==========================================================================
//
// 1. Change the font styles in all browsers (opinionated).
// 2. Remove the margin in Firefox and Safari.
//
button,
input,
optgroup,
select,
textarea {
font-family: sans-serif; // 1
font-size: 100%; // 1
line-height: 1.15; // 1
margin: 0; // 2
}
//
// Show the overflow in IE.
// 1. Show the overflow in Edge.
//
button,
input { // 1
overflow: visible;
}
//
// Remove the inheritance of text transform in Edge, Firefox, and IE.
// 1. Remove the inheritance of text transform in Firefox.
//
button,
select { // 1
text-transform: none;
}
//
// 1. Prevent a WebKit bug where (2) destroys native `audio` and `video`
// controls in Android 4.
// 2. Correct the inability to style clickable types in iOS and Safari.
//
button,
html [type="button"], // 1
[type="reset"],
[type="submit"] {
-webkit-appearance: button; // 2
}
//
// Remove the inner border and padding in Firefox.
//
button::-moz-focus-inner,
[type="button"]::-moz-focus-inner,
[type="reset"]::-moz-focus-inner,
[type="submit"]::-moz-focus-inner {
border-style: none;
padding: 0;
}
//
// Restore the focus styles unset by the previous rule.
//
button:-moz-focusring,
[type="button"]:-moz-focusring,
[type="reset"]:-moz-focusring,
[type="submit"]:-moz-focusring {
outline: 1px dotted ButtonText;
}
//
// Change the border, margin, and padding in all browsers (opinionated).
//
fieldset {
border: 1px solid #c0c0c0;
margin: 0 2px;
padding: 0.35em 0.625em 0.75em;
}
//
// 1. Correct the text wrapping in Edge and IE.
// 2. Correct the color inheritance from `fieldset` elements in IE.
// 3. Remove the padding so developers are not caught out when they zero out
// `fieldset` elements in all browsers.
//
legend {
box-sizing: border-box; // 1
color: inherit; // 2
display: table; // 1
max-width: 100%; // 1
padding: 0; // 3
white-space: normal; // 1
}
//
// 1. Add the correct display in IE 9-.
// 2. Add the correct vertical alignment in Chrome, Firefox, and Opera.
//
progress {
display: inline-block; // 1
vertical-align: baseline; // 2
}
//
// Remove the default vertical scrollbar in IE.
//
textarea {
overflow: auto;
}
//
// 1. Add the correct box sizing in IE 10-.
// 2. Remove the padding in IE 10-.
//
[type="checkbox"],
[type="radio"] {
box-sizing: border-box; // 1
padding: 0; // 2
}
//
// Correct the cursor style of increment and decrement buttons in Chrome.
//
[type="number"]::-webkit-inner-spin-button,
[type="number"]::-webkit-outer-spin-button {
height: auto;
}
//
// 1. Correct the odd appearance in Chrome and Safari.
// 2. Correct the outline style in Safari.
//
[type="search"] {
-webkit-appearance: textfield; // 1
outline-offset: -2px; // 2
}
//
// Remove the inner padding and cancel buttons in Chrome and Safari on macOS.
//
[type="search"]::-webkit-search-cancel-button,
[type="search"]::-webkit-search-decoration {
-webkit-appearance: none;
}
//
// 1. Correct the inability to style clickable types in iOS and Safari.
// 2. Change font properties to `inherit` in Safari.
//
::-webkit-file-upload-button {
-webkit-appearance: button; // 1
font: inherit; // 2
}
// Interactive
// ==========================================================================
//
// Add the correct display in IE 9-.
// 1. Add the correct display in Edge, IE, and Firefox.
//
details, // 1
menu {
display: block;
}
//
// Add the correct display in all browsers.
//
summary {
display: list-item;
}
// Scripting
// ==========================================================================
//
// Add the correct display in IE 9-.
//
canvas {
display: inline-block;
}
//
// Add the correct display in IE.
//
template {
display: none;
}
// Hidden
// ==========================================================================
//
// Add the correct display in IE 10-.
//
[hidden] {
display: none;
}
+3 -4
View File
@@ -23,15 +23,14 @@
z-index: 2;
color: $pagination-active-color;
background-color: $pagination-active-bg;
border-color: $pagination-active-border;
border-color: $pagination-active-border-color;
}
&.disabled .page-link {
color: $pagination-disabled-color;
pointer-events: none;
cursor: $cursor-disabled; // While `pointer-events: none` removes the cursor in modern browsers, we provide a disabled cursor as a fallback.
background-color: $pagination-disabled-bg;
border-color: $pagination-disabled-border;
border-color: $pagination-disabled-border-color;
}
}
@@ -49,7 +48,7 @@
color: $pagination-hover-color;
text-decoration: none;
background-color: $pagination-hover-bg;
border-color: $pagination-hover-border;
border-color: $pagination-hover-border-color;
}
}
+96 -72
View File
@@ -18,79 +18,110 @@
@include border-radius($border-radius-lg);
@include box-shadow($popover-box-shadow);
// Arrows
//
// .arrow is outer, .arrow::after is inner
.arrow {
position: absolute;
display: block;
width: $popover-arrow-width;
height: $popover-arrow-height;
}
.arrow::before,
.arrow::after {
position: absolute;
display: block;
border-color: transparent;
border-style: solid;
}
.arrow::before {
content: "";
border-width: $popover-arrow-outer-width;
}
.arrow::after {
content: "";
border-width: $popover-arrow-outer-width;
}
// Popover directions
&.popover-top,
&.bs-tether-element-attached-bottom {
margin-top: -$popover-arrow-width;
&.bs-popover-top {
margin-bottom: $popover-arrow-width;
&::before,
&::after {
left: 50%;
.arrow {
bottom: 0;
}
.arrow::before,
.arrow::after {
border-bottom-width: 0;
}
&::before {
.arrow::before {
bottom: -$popover-arrow-outer-width;
margin-left: -$popover-arrow-outer-width;
margin-left: -($popover-arrow-outer-width - 5);
border-top-color: $popover-arrow-outer-color;
}
&::after {
.arrow::after {
bottom: -($popover-arrow-outer-width - 1);
margin-left: -$popover-arrow-width;
margin-left: -($popover-arrow-outer-width - 5);
border-top-color: $popover-arrow-color;
}
}
&.popover-right,
&.bs-tether-element-attached-left {
&.bs-popover-right {
margin-left: $popover-arrow-width;
&::before,
&::after {
top: 50%;
.arrow {
left: 0;
}
.arrow::before,
.arrow::after {
margin-top: -($popover-arrow-outer-width - 3);
border-left-width: 0;
}
&::before {
.arrow::before {
left: -$popover-arrow-outer-width;
margin-top: -$popover-arrow-outer-width;
border-right-color: $popover-arrow-outer-color;
}
&::after {
.arrow::after {
left: -($popover-arrow-outer-width - 1);
margin-top: -($popover-arrow-outer-width - 1);
border-right-color: $popover-arrow-color;
}
}
&.popover-bottom,
&.bs-tether-element-attached-top {
&.bs-popover-bottom {
margin-top: $popover-arrow-width;
&::before,
&::after {
left: 50%;
.arrow {
top: 0;
}
.arrow::before,
.arrow::after {
margin-left: -($popover-arrow-width - 3);
border-top-width: 0;
}
&::before {
.arrow::before {
top: -$popover-arrow-outer-width;
margin-left: -$popover-arrow-outer-width;
border-bottom-color: $popover-arrow-outer-color;
}
&::after {
.arrow::after {
top: -($popover-arrow-outer-width - 1);
margin-left: -$popover-arrow-width;
border-bottom-color: $popover-title-bg;
border-bottom-color: $popover-arrow-color;
}
// This will remove the popover-title's border just below the arrow
.popover-title::before {
// This will remove the popover-header's border just below the arrow
.popover-header::before {
position: absolute;
top: 0;
left: 50%;
@@ -98,42 +129,58 @@
width: 20px;
margin-left: -10px;
content: "";
border-bottom: 1px solid $popover-title-bg;
border-bottom: 1px solid $popover-header-bg;
}
}
&.popover-left,
&.bs-tether-element-attached-right {
margin-left: -$popover-arrow-width;
&.bs-popover-left {
margin-right: $popover-arrow-width;
&::before,
&::after {
top: 50%;
.arrow {
right: 0;
}
.arrow::before,
.arrow::after {
margin-top: -($popover-arrow-outer-width - 3);
border-right-width: 0;
}
&::before {
.arrow::before {
right: -$popover-arrow-outer-width;
margin-top: -$popover-arrow-outer-width;
border-left-color: $popover-arrow-outer-color;
}
&::after {
.arrow::after {
right: -($popover-arrow-outer-width - 1);
margin-top: -($popover-arrow-outer-width - 1);
border-left-color: $popover-arrow-color;
}
}
&.bs-popover-auto {
&[x-placement^="top"] {
@extend .bs-popover-top;
}
&[x-placement^="right"] {
@extend .bs-popover-right;
}
&[x-placement^="bottom"] {
@extend .bs-popover-bottom;
}
&[x-placement^="left"] {
@extend .bs-popover-left;
}
}
}
// Offset the popover to account for the popover arrow
.popover-title {
padding: $popover-title-padding-y $popover-title-padding-x;
.popover-header {
padding: $popover-header-padding-y $popover-header-padding-x;
margin-bottom: 0; // Reset the default from Reboot
font-size: $font-size-base;
background-color: $popover-title-bg;
border-bottom: $popover-border-width solid darken($popover-title-bg, 5%);
color: $popover-header-color;
background-color: $popover-header-bg;
border-bottom: $popover-border-width solid darken($popover-header-bg, 5%);
$offset-border-width: calc(#{$border-radius-lg} - #{$popover-border-width});
@include border-top-radius($offset-border-width);
@@ -142,30 +189,7 @@
}
}
.popover-content {
padding: $popover-content-padding-y $popover-content-padding-x;
}
// Arrows
//
// .popover-arrow is outer, .popover-arrow::after is inner
.popover::before,
.popover::after {
position: absolute;
display: block;
width: 0;
height: 0;
border-color: transparent;
border-style: solid;
}
.popover::before {
content: "";
border-width: $popover-arrow-outer-width;
}
.popover::after {
content: "";
border-width: $popover-arrow-width;
.popover-body {
padding: $popover-body-padding-y $popover-body-padding-x;
color: $popover-body-color;
}
+1 -9
View File
@@ -12,15 +12,7 @@
@media print {
*,
*::before,
*::after,
p::first-letter,
div::first-letter,
blockquote::first-letter,
li::first-letter,
p::first-line,
div::first-line,
blockquote::first-line,
li::first-line {
*::after {
// Bootstrap specific; comment out `color` and `background`
//color: #000 !important; // Black prints faster:
// http://www.sanbeiji.com/archives/953
+5 -7
View File
@@ -1,32 +1,30 @@
// Progress animations
@keyframes progress-bar-stripes {
from { background-position: $progress-height 0; }
to { background-position: 0 0; }
}
// Basic progress bar
.progress {
display: flex;
height: $progress-height;
overflow: hidden; // force rounded corners by cropping it
font-size: $progress-font-size;
line-height: $progress-height;
text-align: center;
background-color: $progress-bg;
@include border-radius($progress-border-radius);
}
.progress-bar {
height: $progress-height;
display: flex;
align-items: center;
justify-content: center;
color: $progress-bar-color;
background-color: $progress-bar-bg;
}
// Striped
.progress-bar-striped {
@include gradient-striped();
background-size: $progress-height $progress-height;
}
// Animated
.progress-bar-animated {
animation: progress-bar-stripes $progress-bar-animation-timing;
}
+195 -100
View File
@@ -1,86 +1,64 @@
// scss-lint:disable QualifyingElement, DuplicateProperty
// scss-lint:disable QualifyingElement, DuplicateProperty, VendorPrefix
// Reboot
//
// Global resets to common HTML elements and more for easier usage by Bootstrap.
// Adds additional rules on top of Normalize.css, including several overrides.
// Normalization of HTML elements, manually forked from Normalize.css to remove
// styles targeting irrelevant browsers while applying new styles.
//
// Normalize is licensed MIT. https://github.com/necolas/normalize.css
// Reset the box-sizing
// Document
//
// Change from `box-sizing: content-box` to `border-box` so that when you add
// `padding` or `border`s to an element, the overall declared `width` does not
// change. For example, `width: 100px;` will always be `100px` despite the
// `border: 10px solid red;` and `padding: 20px;`.
//
// Heads up! This reset may cause conflicts with some third-party widgets. For
// recommendations on resolving such conflicts, see
// https://getbootstrap.com/getting-started/#third-box-sizing.
//
// Credit: https://css-tricks.com/inheriting-box-sizing-probably-slightly-better-best-practice/
html {
box-sizing: border-box;
}
// 1. Change from `box-sizing: content-box` so that `width` is not affected by `padding` or `border`.
// 2. Change the default font family in all browsers.
// 3. Correct the line height in all browsers.
// 4. Prevent adjustments of font size after orientation changes in IE on Windows Phone and in iOS.
// 5. Setting @viewport causes scrollbars to overlap content in IE11 and Edge, so
// we force a non-overlapping, non-auto-hiding scrollbar to counteract.
// 6. Change the default tap highlight to be completely transparent in iOS.
*,
*::before,
*::after {
box-sizing: inherit;
box-sizing: border-box; // 1
}
html {
font-family: sans-serif; // 2
line-height: 1.15; // 3
-webkit-text-size-adjust: 100%; // 4
-ms-text-size-adjust: 100%; // 4
-ms-overflow-style: scrollbar; // 5
-webkit-tap-highlight-color: rgba(0,0,0,0); // 6
}
// Make viewport responsive
//
// @viewport is needed because IE 10+ doesn't honor <meta name="viewport"> in
// some cases. See https://timkadlec.com/2012/10/ie10-snap-mode-and-responsive-design/.
// Eventually @viewport will replace <meta name="viewport">.
//
// However, `device-width` is broken on IE 10 on Windows (Phone) 8,
// (see https://timkadlec.com/2013/01/windows-phone-8-and-device-width/ and https://github.com/twbs/bootstrap/issues/10497)
// and the fix for that involves a snippet of JavaScript to sniff the user agent
// and apply some conditional CSS.
//
// See https://getbootstrap.com/getting-started/#support-ie10-width for the relevant hack.
//
// Wrap `@viewport` with `@at-root` for when folks do a nested import (e.g.,
// `.class-name { @import "bootstrap"; }`).
// IE10+ doesn't honor `<meta name="viewport">` in some cases.
@at-root {
@-ms-viewport { width: device-width; }
}
//
// Reset HTML, body, and more
//
html {
// We assume no initial pixel `font-size` for accessibility reasons. This
// allows web visitors to customize their browser default font-size, making
// your project more inclusive and accessible to everyone.
// As a side-effect of setting the @viewport above,
// IE11 & Edge make the scrollbar overlap the content and automatically hide itself when not in use.
// Unfortunately, the auto-showing of the scrollbar is sometimes too sensitive,
// thus making it hard to click on stuff near the right edge of the page.
// So we add this style to force IE11 & Edge to use a "normal", non-overlapping, non-auto-hiding scrollbar.
// See https://github.com/twbs/bootstrap/issues/18543
// and https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/7165383/
-ms-overflow-style: scrollbar;
// Changes the default tap highlight to be completely transparent in iOS.
-webkit-tap-highlight-color: rgba(0,0,0,0);
// Shim for "new" HTML5 structural elements to display correctly (IE10, older browsers)
article, aside, dialog, figcaption, figure, footer, header, hgroup, main, nav, section {
display: block;
}
// Body
//
// 1. Remove the margin in all browsers.
// 2. As a best practice, apply a default `background-color`.
// 3. Set an explicit initial text-align value so that we can later use the
// the `inherit` value on things like `<th>` elements.
body {
margin: 0; // 1
font-family: $font-family-base;
font-size: $font-size-base;
font-weight: $font-weight-base;
line-height: $line-height-base;
// Go easy on the eyes and use something other than `#000` for text
color: $body-color;
// By default, `<body>` has no `background-color` so we set one as a best practice.
background-color: $body-bg;
text-align: left; // 3
background-color: $body-bg; // 2
}
// Suppress the focus outline on elements that cannot be accessed via keyboard.
@@ -93,6 +71,18 @@ body {
}
// Content grouping
//
// 1. Add the correct box sizing in Firefox.
// 2. Show the overflow in Edge and IE.
hr {
box-sizing: content-box; // 1
height: 0; // 1
overflow: visible; // 2
}
//
// Typography
//
@@ -112,14 +102,22 @@ h1, h2, h3, h4, h5, h6 {
// bottom margin to use `rem` units instead of `em`.
p {
margin-top: 0;
margin-bottom: 1rem;
margin-bottom: $paragraph-margin-bottom;
}
// Abbreviations
//
// 1. Remove the bottom border in Firefox 39-.
// 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.
// 3. Add explicit cursor to indicate changed behavior.
// 4. Duplicate behavior to the data-* attribute for our tooltip plugin
abbr[title],
// Add data-* attribute to help out our tooltip plugin, per https://github.com/twbs/bootstrap/issues/5257
abbr[data-original-title] {
cursor: help;
abbr[data-original-title] { // 4
text-decoration: underline; // 2
text-decoration: underline dotted; // 2
cursor: help; // 3
border-bottom: 0; // 1
}
address {
@@ -155,6 +153,35 @@ blockquote {
margin: 0 0 1rem;
}
dfn {
font-style: italic; // Add the correct font style in Android 4.3-
}
b,
strong {
font-weight: bolder; // Add the correct font weight in Chrome, Edge, and Safari
}
small {
font-size: 80%; // Add the correct font size in all browsers
}
//
// Prevent `sub` and `sup` elements from affecting the line height in
// all browsers.
//
sub,
sup {
position: relative;
font-size: 75%;
line-height: 0;
vertical-align: baseline;
}
sub { bottom: -.25em; }
sup { top: -.5em; }
//
// Links
@@ -163,8 +190,10 @@ blockquote {
a {
color: $link-color;
text-decoration: $link-decoration;
background-color: transparent; // Remove the gray background on active links in IE 10.
-webkit-text-decoration-skip: objects; // Remove gaps in links underline in iOS 8+ and Safari 8+.
@include hover-focus {
@include hover {
color: $link-hover-color;
text-decoration: $link-hover-decoration;
}
@@ -195,12 +224,20 @@ a:not([href]):not([tabindex]) {
// Code
//
pre,
code,
kbd,
samp {
font-family: monospace, monospace; // Correct the inheritance and scaling of font size in all browsers.
font-size: 1em; // Correct the odd `em` font sizing in all browsers.
}
pre {
// Remove browser default top margin
margin-top: 0;
// Reset browser default of `1em` to use `rem`s
margin-bottom: 1rem;
// Normalize v4 removed this property, causing `<pre>` content to break out of wrapping code snippets
// Don't allow content to break outside
overflow: auto;
}
@@ -210,33 +247,22 @@ pre {
//
figure {
// Normalize adds `margin` to `figure`s as browsers apply it inconsistently.
// We reset that to create a better flow in-page.
// Apply a consistent margin strategy (matches our type styles).
margin: 0 0 1rem;
}
//
// Images
// Images and content
//
img {
// By default, `<img>`s are `inline-block`. This assumes that, and vertically
// centers them. This won't apply should you reset them to `block` level.
vertical-align: middle;
// Note: `<img>`s are deliberately not made responsive by default.
// For the rationale behind this, see the comments on the `.img-fluid` class.
border-style: none; // Remove the border on images inside links in IE 10-.
}
// iOS "clickable elements" fix for role="button"
//
// Fixes "clickability" issue (and more generally, the firing of events such as focus as well)
// for traditionally non-focusable elements with role="button"
// see https://developer.mozilla.org/en-US/docs/Web/Events/click#Safari_Mobile
[role="button"] {
cursor: pointer;
svg:not(:root) {
overflow: hidden; // Hide the overflow in IE
}
@@ -268,10 +294,7 @@ textarea {
//
table {
// No longer part of Normalize since v4
border-collapse: collapse;
// Reset for nesting within parents with `background-color`.
background-color: $table-bg;
border-collapse: collapse; // Prevent double borders
}
caption {
@@ -283,8 +306,9 @@ caption {
}
th {
// Centered by default, but left-align-ed to match the `td`s below.
text-align: left;
// Matches default `<td>` alignment by inheriting from the `<body>`, or the
// closest parent with a set `text-align`.
text-align: inherit;
}
@@ -310,20 +334,47 @@ button:focus {
input,
button,
select,
optgroup,
textarea {
// Normalize includes `font: inherit;`, so `font-family`. `font-size`, etc are
// properly inherited. However, `line-height` isn't inherited there.
margin: 0; // Remove the margin in Firefox and Safari
font-family: inherit;
font-size: inherit;
line-height: inherit;
}
button,
input {
overflow: visible; // Show the overflow in Edge
}
button,
select {
text-transform: none; // Remove the inheritance of text transform in Firefox
}
// 1. Prevent a WebKit bug where (2) destroys native `audio` and `video`
// controls in Android 4.
// 2. Correct the inability to style clickable types in iOS and Safari.
button,
html [type="button"], // 1
[type="reset"],
[type="submit"] {
-webkit-appearance: button; // 2
}
// Remove inner border and padding from Firefox, but don't restore the outline like Normalize.
button::-moz-focus-inner,
[type="button"]::-moz-focus-inner,
[type="reset"]::-moz-focus-inner,
[type="submit"]::-moz-focus-inner {
padding: 0;
border-style: none;
}
input[type="radio"],
input[type="checkbox"] {
// Apply a disabled cursor for radios and checkboxes.
//
// Note: Neither radios nor checkboxes can be readonly.
&:disabled {
cursor: $cursor-disabled;
}
box-sizing: border-box; // 1. Add the correct box sizing in IE 10-
padding: 0; // 2. Remove the padding in IE 10-
}
@@ -340,6 +391,7 @@ input[type="month"] {
}
textarea {
overflow: auto; // Remove the default vertical scrollbar in IE.
// Textareas should really only resize vertically so they don't break their (horizontal) containers.
resize: vertical;
}
@@ -357,33 +409,76 @@ fieldset {
border: 0;
}
// 1. Correct the text wrapping in Edge and IE.
// 2. Correct the color inheritance from `fieldset` elements in IE.
legend {
// Reset the entire legend element to match the `fieldset`
display: block;
width: 100%;
max-width: 100%; // 1
padding: 0;
margin-bottom: .5rem;
font-size: 1.5rem;
line-height: inherit;
color: inherit; // 2
white-space: normal; // 1
}
input[type="search"] {
progress {
vertical-align: baseline; // Add the correct vertical alignment in Chrome, Firefox, and Opera.
}
// Correct the cursor style of increment and decrement buttons in Chrome.
[type="number"]::-webkit-inner-spin-button,
[type="number"]::-webkit-outer-spin-button {
height: auto;
}
[type="search"] {
// This overrides the extra rounded corners on search inputs in iOS so that our
// `.form-control` class can properly style them. Note that this cannot simply
// be added to `.form-control` as it's not specific enough. For details, see
// https://github.com/twbs/bootstrap/issues/11586.
outline-offset: -2px; // 2. Correct the outline style in Safari.
-webkit-appearance: none;
}
// todo: needed?
//
// Remove the inner padding and cancel buttons in Chrome and Safari on macOS.
//
[type="search"]::-webkit-search-cancel-button,
[type="search"]::-webkit-search-decoration {
-webkit-appearance: none;
}
//
// 1. Correct the inability to style clickable types in iOS and Safari.
// 2. Change font properties to `inherit` in Safari.
//
::-webkit-file-upload-button {
font: inherit; // 2
-webkit-appearance: button; // 1
}
//
// Correct element displays
//
output {
display: inline-block;
// font-size: $font-size-base;
// line-height: $line-height;
// color: $input-color;
}
summary {
display: list-item; // Add the correct display in all browsers
}
template {
display: none; // Add the correct display in IE
}
// Always hide an element with the `hidden` HTML attribute (from PureCSS).
// Needed for proper display in IE 10-.
[hidden] {
display: none !important;
}
-52
View File
@@ -1,52 +0,0 @@
// Credit: Nicolas Gallagher and SUIT CSS.
.embed-responsive {
position: relative;
display: block;
width: 100%;
padding: 0;
overflow: hidden;
&::before {
display: block;
content: "";
}
.embed-responsive-item,
iframe,
embed,
object,
video {
position: absolute;
top: 0;
bottom: 0;
left: 0;
width: 100%;
height: 100%;
border: 0;
}
}
.embed-responsive-21by9 {
&::before {
padding-top: percentage(9 / 21);
}
}
.embed-responsive-16by9 {
&::before {
padding-top: percentage(9 / 16);
}
}
.embed-responsive-4by3 {
&::before {
padding-top: percentage(3 / 4);
}
}
.embed-responsive-1by1 {
&::before {
padding-top: percentage(1 / 1);
}
}
+33 -18
View File
@@ -6,6 +6,7 @@
width: 100%;
max-width: 100%;
margin-bottom: $spacer;
background-color: $table-bg; // Reset for nesting within parents with `background-color`.
th,
td {
@@ -36,7 +37,7 @@
.table-sm {
th,
td {
padding: $table-sm-cell-padding;
padding: $table-cell-padding-sm;
}
}
@@ -68,7 +69,7 @@
.table-striped {
tbody tr:nth-of-type(odd) {
background-color: $table-bg-accent;
background-color: $table-accent-bg;
}
}
@@ -80,7 +81,7 @@
.table-hover {
tbody tr {
@include hover {
background-color: $table-bg-hover;
background-color: $table-hover-bg;
}
}
}
@@ -91,12 +92,11 @@
// Exact selectors below required to override `.table-striped` and prevent
// inheritance to nested tables.
// Generate the contextual variants
@include table-row-variant(active, $table-bg-active);
@include table-row-variant(success, $state-success-bg);
@include table-row-variant(info, $state-info-bg);
@include table-row-variant(warning, $state-warning-bg);
@include table-row-variant(danger, $state-danger-bg);
@each $color, $value in $theme-colors {
@include table-row-variant($color, theme-color-level($color, -9));
}
@include table-row-variant(active, $table-active-bg);
// Inverse styles
@@ -124,14 +124,27 @@
th,
td,
thead th {
border-color: $body-bg;
border-color: $table-inverse-border-color;
}
&.table-bordered {
border: 0;
}
}
&.table-striped {
tbody tr:nth-of-type(odd) {
background-color: $table-inverse-accent-bg;
}
}
&.table-hover {
tbody tr {
@include hover {
background-color: $table-inverse-hover-bg;
}
}
}
}
// Responsive tables
@@ -141,13 +154,15 @@
// will display normally.
.table-responsive {
display: block;
width: 100%;
overflow-x: auto;
-ms-overflow-style: -ms-autohiding-scrollbar; // See https://github.com/twbs/bootstrap/pull/10057
@include media-breakpoint-down(md) {
display: block;
width: 100%;
overflow-x: auto;
-ms-overflow-style: -ms-autohiding-scrollbar; // See https://github.com/twbs/bootstrap/pull/10057
// Prevent double border on horizontal scroll due to use of `display: block;`
&.table-bordered {
border: 0;
// Prevent double border on horizontal scroll due to use of `display: block;`
&.table-bordered {
border: 0;
}
}
}
+53 -36
View File
@@ -3,6 +3,7 @@
position: absolute;
z-index: $zindex-tooltip;
display: block;
margin: $tooltip-margin;
// Our parent element can be arbitrary since tooltips are by default inserted as a sibling of their target element.
// So reset our font and text properties to avoid inheriting weird values.
@include reset-text();
@@ -13,62 +14,86 @@
&.show { opacity: $tooltip-opacity; }
&.tooltip-top,
&.bs-tether-element-attached-bottom {
padding: $tooltip-arrow-width 0;
margin-top: -$tooltip-margin;
.arrow {
position: absolute;
display: block;
width: $tooltip-arrow-width;
height: $tooltip-arrow-height;
}
.tooltip-inner::before {
&.bs-tooltip-top {
padding: $tooltip-arrow-width 0;
.arrow {
bottom: 0;
left: 50%;
margin-left: -$tooltip-arrow-width;
}
.arrow::before {
margin-left: -($tooltip-arrow-width - 2);
content: "";
border-width: $tooltip-arrow-width $tooltip-arrow-width 0;
border-top-color: $tooltip-arrow-color;
}
}
&.tooltip-right,
&.bs-tether-element-attached-left {
&.bs-tooltip-right {
padding: 0 $tooltip-arrow-width;
margin-left: $tooltip-margin;
.tooltip-inner::before {
top: 50%;
.arrow {
left: 0;
margin-top: -$tooltip-arrow-width;
}
.arrow::before {
margin-top: -($tooltip-arrow-width - 2);
content: "";
border-width: $tooltip-arrow-width $tooltip-arrow-width $tooltip-arrow-width 0;
border-right-color: $tooltip-arrow-color;
}
}
&.tooltip-bottom,
&.bs-tether-element-attached-top {
&.bs-tooltip-bottom {
padding: $tooltip-arrow-width 0;
margin-top: $tooltip-margin;
.tooltip-inner::before {
.arrow {
top: 0;
left: 50%;
margin-left: -$tooltip-arrow-width;
}
.arrow::before {
margin-left: -($tooltip-arrow-width - 2);
content: "";
border-width: 0 $tooltip-arrow-width $tooltip-arrow-width;
border-bottom-color: $tooltip-arrow-color;
}
}
&.tooltip-left,
&.bs-tether-element-attached-right {
&.bs-tooltip-left {
padding: 0 $tooltip-arrow-width;
margin-left: -$tooltip-margin;
.tooltip-inner::before {
top: 50%;
.arrow {
right: 0;
margin-top: -$tooltip-arrow-width;
}
.arrow::before {
right: 0;
margin-top: -($tooltip-arrow-width - 2);
content: "";
border-width: $tooltip-arrow-width 0 $tooltip-arrow-width $tooltip-arrow-width;
border-left-color: $tooltip-arrow-color;
}
}
&.bs-tooltip-auto {
&[x-placement^="top"] {
@extend .bs-tooltip-top;
}
&[x-placement^="right"] {
@extend .bs-tooltip-right;
}
&[x-placement^="bottom"] {
@extend .bs-tooltip-bottom;
}
&[x-placement^="left"] {
@extend .bs-tooltip-left;
}
}
.arrow::before {
position: absolute;
border-color: transparent;
border-style: solid;
}
}
// Wrapper for the tooltip content
@@ -79,12 +104,4 @@
text-align: center;
background-color: $tooltip-bg;
@include border-radius($border-radius);
&::before {
position: absolute;
width: 0;
height: 0;
border-color: transparent;
border-style: solid;
}
}
+8 -28
View File
@@ -11,12 +11,12 @@ h1, h2, h3, h4, h5, h6,
color: $headings-color;
}
h1, .h1 { font-size: $font-size-h1; }
h2, .h2 { font-size: $font-size-h2; }
h3, .h3 { font-size: $font-size-h3; }
h4, .h4 { font-size: $font-size-h4; }
h5, .h5 { font-size: $font-size-h5; }
h6, .h6 { font-size: $font-size-h6; }
h1, .h1 { font-size: $h1-font-size; }
h2, .h2 { font-size: $h2-font-size; }
h3, .h3 { font-size: $h3-font-size; }
h4, .h4 { font-size: $h4-font-size; }
h5, .h5 { font-size: $h5-font-size; }
h6, .h6 { font-size: $h6-font-size; }
.lead {
font-size: $lead-font-size;
@@ -51,8 +51,8 @@ h6, .h6 { font-size: $font-size-h6; }
//
hr {
margin-top: $spacer-y;
margin-bottom: $spacer-y;
margin-top: 1rem;
margin-bottom: 1rem;
border: 0;
border-top: $hr-border-width solid $hr-border-color;
}
@@ -108,10 +108,8 @@ mark,
// Blockquotes
.blockquote {
padding: ($spacer / 2) $spacer;
margin-bottom: $spacer;
font-size: $blockquote-font-size;
border-left: $blockquote-border-width solid $blockquote-border-color;
}
.blockquote-footer {
@@ -123,21 +121,3 @@ mark,
content: "\2014 \00A0"; // em dash, nbsp
}
}
// Opposite alignment of blockquote
.blockquote-reverse {
padding-right: $spacer;
padding-left: 0;
text-align: right;
border-right: $blockquote-border-width solid $blockquote-border-color;
border-left: 0;
}
.blockquote-reverse .blockquote-footer {
&::before {
content: "";
}
&::after {
content: "\00A0 \2014"; // nbsp, em dash
}
}
+1
View File
@@ -3,6 +3,7 @@
@import "utilities/borders";
@import "utilities/clearfix";
@import "utilities/display";
@import "utilities/embed";
@import "utilities/flex";
@import "utilities/float";
@import "utilities/position";
+305 -416
View File
File diff suppressed because it is too large Load Diff
+2 -8
View File
@@ -22,22 +22,16 @@ html {
box-sizing: inherit;
}
//
// Variables
//
@import "functions";
@import "variables";
//
// Grid mixins
//
@import "mixins/clearfix";
@import "mixins/breakpoints";
@import "mixins/grid-framework";
@import "mixins/grid";
@import "custom";
@import "grid";
@import "utilities/flex";
+1 -2
View File
@@ -2,9 +2,8 @@
//
// Includes only Normalize and our custom Reboot reset.
@import "functions";
@import "variables";
@import "mixins";
@import "custom";
@import "normalize";
@import "reboot";
+2 -15
View File
@@ -1,20 +1,14 @@
/*!
* Bootstrap v4.0.0-alpha.6 (https://getbootstrap.com)
* Bootstrap v4.0.0-beta (https://getbootstrap.com)
* Copyright 2011-2017 The Bootstrap Authors
* Copyright 2011-2017 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
*/
// Core variables and mixins
@import "functions";
@import "variables";
@import "mixins";
@import "custom";
// Reset and dependencies
@import "normalize";
@import "print";
// Core CSS
@import "reboot";
@import "type";
@import "images";
@@ -23,8 +17,6 @@
@import "tables";
@import "forms";
@import "buttons";
// Components
@import "transitions";
@import "dropdown";
@import "button-group";
@@ -41,14 +33,9 @@
@import "progress";
@import "media";
@import "list-group";
@import "responsive-embed";
@import "close";
// Components w/ JavaScript
@import "modal";
@import "tooltip";
@import "popover";
@import "carousel";
// Utility classes
@import "utilities";
+4 -5
View File
@@ -1,14 +1,13 @@
// Alerts
@mixin alert-variant($background, $border, $body-color) {
@mixin alert-variant($background, $border, $color) {
color: $color;
background-color: $background;
border-color: $border;
color: $body-color;
hr {
border-top-color: darken($border, 5%);
}
.alert-link {
color: darken($body-color, 10%);
color: darken($color, 10%);
}
}
+6 -5
View File
@@ -1,11 +1,12 @@
// Badges
@mixin badge-variant($color) {
background-color: $color;
@mixin badge-variant($bg) {
@include color-yiq($bg);
background-color: $bg;
&[href] {
@include hover-focus {
background-color: darken($color, 10%);
@include color-yiq($bg);
text-decoration: none;
background-color: darken($bg, 10%);
}
}
}
+3 -3
View File
@@ -8,15 +8,15 @@
@mixin border-top-radius($radius) {
@if $enable-rounded {
border-top-right-radius: $radius;
border-top-left-radius: $radius;
border-top-right-radius: $radius;
}
}
@mixin border-right-radius($radius) {
@if $enable-rounded {
border-bottom-right-radius: $radius;
border-top-right-radius: $radius;
border-bottom-right-radius: $radius;
}
}
@@ -29,7 +29,7 @@
@mixin border-left-radius($radius) {
@if $enable-rounded {
border-bottom-left-radius: $radius;
border-top-left-radius: $radius;
border-bottom-left-radius: $radius;
}
}
+23 -13
View File
@@ -2,7 +2,7 @@
//
// Breakpoints are defined as a map of (name: minimum width), order from small to large:
//
// (xs: 0, sm: 576px, md: 768px)
// (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px)
//
// The map defined in the `$grid-breakpoints` global variable is used as the `$breakpoints` argument by default.
@@ -10,9 +10,9 @@
//
// >> breakpoint-next(sm)
// md
// >> breakpoint-next(sm, (xs: 0, sm: 576px, md: 768px))
// >> breakpoint-next(sm, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px))
// md
// >> breakpoint-next(sm, $breakpoint-names: (xs sm md))
// >> breakpoint-next(sm, $breakpoint-names: (xs sm md lg xl))
// md
@function breakpoint-next($name, $breakpoints: $grid-breakpoints, $breakpoint-names: map-keys($breakpoints)) {
$n: index($breakpoint-names, $name);
@@ -21,7 +21,7 @@
// Minimum breakpoint width. Null for the smallest (first) breakpoint.
//
// >> breakpoint-min(sm, (xs: 0, sm: 576px, md: 768px))
// >> breakpoint-min(sm, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px))
// 576px
@function breakpoint-min($name, $breakpoints: $grid-breakpoints) {
$min: map-get($breakpoints, $name);
@@ -31,7 +31,7 @@
// 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: 576px, md: 768px))
// >> breakpoint-max(sm, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px))
// 767px
@function breakpoint-max($name, $breakpoints: $grid-breakpoints) {
$next: breakpoint-next($name, $breakpoints);
@@ -41,9 +41,9 @@
// Returns a blank string if smallest breakpoint, otherwise returns the name with a dash infront.
// Useful for making responsive utilities.
//
// >> breakpoint-infix(xs, (xs: 0, sm: 576px, md: 768px))
// >> breakpoint-infix(xs, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px))
// "" (Returns a blank string)
// >> breakpoint-infix(sm, (xs: 0, sm: 576px, md: 768px))
// >> breakpoint-infix(sm, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px))
// "-sm"
@function breakpoint-infix($name, $breakpoints: $grid-breakpoints) {
@return if(breakpoint-min($name, $breakpoints) == null, "", "-#{$name}");
@@ -78,10 +78,11 @@
// Media that spans multiple breakpoint widths.
// Makes the @content apply between the min and max breakpoints
@mixin media-breakpoint-between($lower, $upper, $breakpoints: $grid-breakpoints) {
@include media-breakpoint-up($lower, $breakpoints) {
@include media-breakpoint-down($upper, $breakpoints) {
@content;
}
$min: breakpoint-min($lower, $breakpoints);
$max: breakpoint-max($upper, $breakpoints);
@media (min-width: $min) and (max-width: $max) {
@content;
}
}
@@ -89,7 +90,16 @@
// No minimum for the smallest breakpoint, and no maximum for the largest one.
// Makes the @content apply only to the given breakpoint, not viewports any wider or narrower.
@mixin media-breakpoint-only($name, $breakpoints: $grid-breakpoints) {
@include media-breakpoint-between($name, $name, $breakpoints) {
@content;
$min: breakpoint-min($name, $breakpoints);
$max: breakpoint-max($name, $breakpoints);
@if $min != null and $max != null {
@media (min-width: $min) and (max-width: $max) {
@content;
}
} @else if $max == null {
@include media-breakpoint-up($name)
} @else if $min == null {
@include media-breakpoint-down($name)
}
}
+11 -14
View File
@@ -3,28 +3,25 @@
// Easily pump out default styles, as well as :hover, :focus, :active,
// and disabled options for all buttons
@mixin button-variant($color, $background, $border) {
$active-background: darken($background, 10%);
$active-border: darken($border, 12%);
color: $color;
@mixin button-variant($background, $border, $active-background: darken($background, 7.5%), $active-border: darken($border, 10%)) {
@include color-yiq($background);
background-color: $background;
border-color: $border;
@include box-shadow($btn-box-shadow);
// Hover and focus styles are shared
@include hover {
color: $color;
&:hover {
@include color-yiq($background);
background-color: $active-background;
border-color: $active-border;
}
&:focus,
&.focus {
// Avoid using mixin so we can pass custom focus shadow properly
@if $enable-shadows {
box-shadow: $btn-box-shadow, 0 0 0 2px rgba($border, .5);
box-shadow: $btn-box-shadow, 0 0 0 3px rgba($border, .5);
} @else {
box-shadow: 0 0 0 2px rgba($border, .5);
box-shadow: 0 0 0 3px rgba($border, .5);
}
}
@@ -38,7 +35,6 @@
&:active,
&.active,
.show > &.dropdown-toggle {
color: $color;
background-color: $active-background;
background-image: none; // Remove the gradient for the pressed/active state
border-color: $active-border;
@@ -48,8 +44,8 @@
@mixin button-outline-variant($color, $color-hover: #fff) {
color: $color;
background-image: none;
background-color: transparent;
background-image: none;
border-color: $color;
@include hover {
@@ -60,7 +56,7 @@
&:focus,
&.focus {
box-shadow: 0 0 0 2px rgba($color, .5);
box-shadow: 0 0 0 3px rgba($color, .5);
}
&.disabled,
@@ -79,8 +75,9 @@
}
// Button sizes
@mixin button-size($padding-y, $padding-x, $font-size, $border-radius) {
@mixin button-size($padding-y, $padding-x, $font-size, $line-height, $border-radius) {
padding: $padding-y $padding-x;
font-size: $font-size;
line-height: $line-height;
@include border-radius($border-radius);
}

Some files were not shown because too many files have changed in this diff Show More