@ -0,0 +1 @@ | |||
mongodb/ |
@ -1,3 +1,3 @@ | |||
#!/bin/bash | |||
npm i | |||
npm i --unsafe-perm | |||
node server |
@ -1,8 +1,7 @@ | |||
const mongoose = require('mongoose'), | |||
speciesModel = new mongoose.Schema({ | |||
id: mongoose.Schema.Types.ObjectId, | |||
name: mongoose.Schema.Types.String, | |||
descripotion: mongoose.Schema.Types.String | |||
description: mongoose.Schema.Types.String | |||
}) | |||
module.exports = db => db.model('species', speciesModel) |
@ -0,0 +1,22 @@ | |||
The MIT License (MIT) | |||
Copyright (c) 2011-2019 Twitter, Inc. | |||
Copyright (c) 2011-2019 The Bootstrap Authors | |||
Permission is hereby granted, free of charge, to any person obtaining a copy | |||
of this software and associated documentation files (the "Software"), to deal | |||
in the Software without restriction, including without limitation the rights | |||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
copies of the Software, and to permit persons to whom the Software is | |||
furnished to do so, subject to the following conditions: | |||
The above copyright notice and this permission notice shall be included in | |||
all copies or substantial portions of the Software. | |||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |||
THE SOFTWARE. |
@ -0,0 +1,209 @@ | |||
<p align="center"> | |||
<a href="https://getbootstrap.com/"> | |||
<img src="https://getbootstrap.com/docs/4.4/assets/brand/bootstrap-solid.svg" alt="Bootstrap logo" width="72" height="72"> | |||
</a> | |||
</p> | |||
<h3 align="center">Bootstrap</h3> | |||
<p align="center"> | |||
Sleek, intuitive, and powerful front-end framework for faster and easier web development. | |||
<br> | |||
<a href="https://getbootstrap.com/docs/4.4/"><strong>Explore Bootstrap docs »</strong></a> | |||
<br> | |||
<br> | |||
<a href="https://github.com/twbs/bootstrap/issues/new?template=bug.md">Report bug</a> | |||
· | |||
<a href="https://github.com/twbs/bootstrap/issues/new?template=feature.md&labels=feature">Request feature</a> | |||
· | |||
<a href="https://themes.getbootstrap.com/">Themes</a> | |||
· | |||
<a href="https://blog.getbootstrap.com/">Blog</a> | |||
</p> | |||
## 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) | |||
- [Community](#community) | |||
- [Versioning](#versioning) | |||
- [Creators](#creators) | |||
- [Thanks](#thanks) | |||
- [Copyright and license](#copyright-and-license) | |||
## Quick start | |||
Several quick start options are available: | |||
- [Download the latest release.](https://github.com/twbs/bootstrap/archive/v4.4.1.zip) | |||
- Clone the repo: `git clone https://github.com/twbs/bootstrap.git` | |||
- Install with [npm](https://www.npmjs.com/): `npm install bootstrap` | |||
- Install with [yarn](https://yarnpkg.com/): `yarn add bootstrap@4.4.1` | |||
- Install with [Composer](https://getcomposer.org/): `composer require twbs/bootstrap:4.4.1` | |||
- Install with [NuGet](https://www.nuget.org/): CSS: `Install-Package bootstrap` Sass: `Install-Package bootstrap.sass` | |||
Read the [Getting started page](https://getbootstrap.com/docs/4.4/getting-started/introduction/) for information on the framework contents, templates and examples, and more. | |||
## Status | |||
[](https://bootstrap-slack.herokuapp.com/) | |||
[](https://github.com/twbs/bootstrap/actions?workflow=Tests) | |||
[](https://www.npmjs.com/package/bootstrap) | |||
[](https://rubygems.org/gems/bootstrap) | |||
[](https://atmospherejs.com/twbs/bootstrap) | |||
[](https://packagist.org/packages/twbs/bootstrap) | |||
[](https://www.nuget.org/packages/bootstrap/absoluteLatest) | |||
[](https://david-dm.org/twbs/bootstrap?type=peer) | |||
[](https://david-dm.org/twbs/bootstrap?type=dev) | |||
[](https://coveralls.io/github/twbs/bootstrap?branch=v4-dev) | |||
[](https://github.com/twbs/bootstrap/tree/v4-dev/dist/css/bootstrap.min.css) | |||
[](https://github.com/twbs/bootstrap/tree/v4-dev/dist/js/bootstrap.min.js) | |||
[](https://www.browserstack.com/automate/public-build/SkxZcStBeExEdVJqQ2hWYnlWckpkNmNEY213SFp6WHFETWk2bGFuY3pCbz0tLXhqbHJsVlZhQnRBdEpod3NLSDMzaHc9PQ==--3d0b75245708616eb93113221beece33e680b229) | |||
[](#backers) | |||
[](#sponsors) | |||
## 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: | |||
```text | |||
bootstrap/ | |||
└── dist/ | |||
├── css/ | |||
│ ├── bootstrap-grid.css | |||
│ ├── bootstrap-grid.css.map | |||
│ ├── bootstrap-grid.min.css | |||
│ ├── bootstrap-grid.min.css.map | |||
│ ├── bootstrap-reboot.css | |||
│ ├── bootstrap-reboot.css.map | |||
│ ├── bootstrap-reboot.min.css | |||
│ ├── bootstrap-reboot.min.css.map | |||
│ ├── bootstrap.css | |||
│ ├── bootstrap.css.map | |||
│ ├── bootstrap.min.css | |||
│ └── bootstrap.min.css.map | |||
└── js/ | |||
├── bootstrap.bundle.js | |||
├── bootstrap.bundle.js.map | |||
├── bootstrap.bundle.min.js | |||
├── bootstrap.bundle.min.js.map | |||
├── bootstrap.js | |||
├── bootstrap.js.map | |||
├── bootstrap.min.js | |||
└── bootstrap.min.js.map | |||
``` | |||
We provide compiled CSS and JS (`bootstrap.*`), as well as compiled and minified CSS and JS (`bootstrap.min.*`). [source maps](https://developers.google.com/web/tools/chrome-devtools/javascript/source-maps) (`bootstrap.*.map`) are available for use with certain browsers' developer tools. Bundled JS files (`bootstrap.bundle.js` and minified `bootstrap.bundle.min.js`) include [Popper](https://popper.js.org/), but not [jQuery](https://jquery.com/). | |||
## Bugs and feature requests | |||
Have a bug or a feature request? Please first read the [issue guidelines](https://github.com/twbs/bootstrap/blob/master/CONTRIBUTING.md#using-the-issue-tracker) and search for existing and closed issues. If your problem or idea is not addressed yet, [please open a new issue](https://github.com/twbs/bootstrap/issues/new). | |||
## Documentation | |||
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 `site/docs/4.4/assets/js/src/search.js` file. | |||
### Running documentation locally | |||
1. Run through the [tooling setup](https://getbootstrap.com/docs/4.4/getting-started/build-tools/#tooling-setup) to install Jekyll (the site builder) and other Ruby dependencies with `bundle install`. | |||
2. Run `npm install` to install Node.js dependencies. | |||
3. Run `npm start` to compile CSS and JavaScript files, generate our docs, and watch for changes. | |||
4. Open `http://localhost:9001` in your browser, and voilà. | |||
Learn more about using Jekyll by reading its [documentation](https://jekyllrb.com/docs/). | |||
### Documentation for previous releases | |||
You can find all our previous releases docs on <https://getbootstrap.com/docs/versions/>. | |||
[Previous releases](https://github.com/twbs/bootstrap/releases) and their documentation are also available for download. | |||
## Contributing | |||
Please read through our [contributing guidelines](https://github.com/twbs/bootstrap/blob/master/CONTRIBUTING.md). Included are directions for opening issues, coding standards, and notes on development. | |||
Moreover, if your pull request contains JavaScript patches or features, you must include [relevant unit tests](https://github.com/twbs/bootstrap/tree/master/js/tests). All HTML and CSS should conform to the [Code Guide](https://github.com/mdo/code-guide), maintained by [Mark Otto](https://github.com/mdo). | |||
Editor preferences are available in the [editor config](https://github.com/twbs/bootstrap/blob/master/.editorconfig) for easy use in common text editors. Read more and download plugins at <https://editorconfig.org/>. | |||
## Community | |||
Get updates on Bootstrap's development and chat with the project maintainers and community members. | |||
- Follow [@getbootstrap on Twitter](https://twitter.com/getbootstrap). | |||
- Read and subscribe to [The Official Bootstrap Blog](https://blog.getbootstrap.com/). | |||
- Join [the official Slack room](https://bootstrap-slack.herokuapp.com/). | |||
- Chat with fellow Bootstrappers in IRC. On the `irc.freenode.net` server, in the `##bootstrap` channel. | |||
- Implementation help may be found at Stack Overflow (tagged [`bootstrap-4`](https://stackoverflow.com/questions/tagged/bootstrap-4)). | |||
- Developers should use the keyword `bootstrap` on packages which modify or add to the functionality of Bootstrap when distributing through [npm](https://www.npmjs.com/browse/keyword/bootstrap) or similar delivery mechanisms for maximum discoverability. | |||
## Versioning | |||
For transparency into our release cycle and in striving to maintain backward compatibility, Bootstrap is maintained under [the Semantic Versioning guidelines](https://semver.org/). Sometimes we screw up, but we adhere to those rules whenever possible. | |||
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. | |||
## Creators | |||
**Mark Otto** | |||
- <https://twitter.com/mdo> | |||
- <https://github.com/mdo> | |||
**Jacob Thornton** | |||
- <https://twitter.com/fat> | |||
- <https://github.com/fat> | |||
## Thanks | |||
<a href="https://www.browserstack.com/"> | |||
<img src="https://live.browserstack.com/images/opensource/browserstack-logo.svg" alt="BrowserStack Logo" width="192" height="42"> | |||
</a> | |||
Thanks to [BrowserStack](https://www.browserstack.com/) for providing the infrastructure that allows us to test in real browsers! | |||
## Backers | |||
Thank you to all our backers! 🙏 [[Become a backer](https://opencollective.com/bootstrap#backer)] | |||
[](https://opencollective.com/bootstrap#backers) | |||
## Sponsors | |||
Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [[Become a sponsor](https://opencollective.com/bootstrap#sponsor)] | |||
[](https://opencollective.com/bootstrap/sponsor/0/website) | |||
[](https://opencollective.com/bootstrap/sponsor/1/website) | |||
[](https://opencollective.com/bootstrap/sponsor/2/website) | |||
[](https://opencollective.com/bootstrap/sponsor/3/website) | |||
[](https://opencollective.com/bootstrap/sponsor/4/website) | |||
[](https://opencollective.com/bootstrap/sponsor/5/website) | |||
[](https://opencollective.com/bootstrap/sponsor/6/website) | |||
[](https://opencollective.com/bootstrap/sponsor/7/website) | |||
[](https://opencollective.com/bootstrap/sponsor/8/website) | |||
[](https://opencollective.com/bootstrap/sponsor/9/website) | |||
## Copyright and license | |||
Code and documentation copyright 2011-2019 the [Bootstrap Authors](https://github.com/twbs/bootstrap/graphs/contributors) and [Twitter, Inc.](https://twitter.com) Code released under the [MIT License](https://github.com/twbs/bootstrap/blob/master/LICENSE). Docs released under [Creative Commons](https://creativecommons.org/licenses/by/3.0/). |
@ -0,0 +1,327 @@ | |||
/*! | |||
* Bootstrap Reboot v4.4.1 (https://getbootstrap.com/) | |||
* Copyright 2011-2019 The Bootstrap Authors | |||
* Copyright 2011-2019 Twitter, Inc. | |||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) | |||
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md) | |||
*/ | |||
*, | |||
*::before, | |||
*::after { | |||
box-sizing: border-box; | |||
} | |||
html { | |||
font-family: sans-serif; | |||
line-height: 1.15; | |||
-webkit-text-size-adjust: 100%; | |||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0); | |||
} | |||
article, aside, figcaption, figure, footer, header, hgroup, main, nav, section { | |||
display: block; | |||
} | |||
body { | |||
margin: 0; | |||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; | |||
font-size: 1rem; | |||
font-weight: 400; | |||
line-height: 1.5; | |||
color: #212529; | |||
text-align: left; | |||
background-color: #fff; | |||
} | |||
[tabindex="-1"]:focus:not(:focus-visible) { | |||
outline: 0 !important; | |||
} | |||
hr { | |||
box-sizing: content-box; | |||
height: 0; | |||
overflow: visible; | |||
} | |||
h1, h2, h3, h4, h5, h6 { | |||
margin-top: 0; | |||
margin-bottom: 0.5rem; | |||
} | |||
p { | |||
margin-top: 0; | |||
margin-bottom: 1rem; | |||
} | |||
abbr[title], | |||
abbr[data-original-title] { | |||
text-decoration: underline; | |||
-webkit-text-decoration: underline dotted; | |||
text-decoration: underline dotted; | |||
cursor: help; | |||
border-bottom: 0; | |||
-webkit-text-decoration-skip-ink: none; | |||
text-decoration-skip-ink: none; | |||
} | |||
address { | |||
margin-bottom: 1rem; | |||
font-style: normal; | |||
line-height: inherit; | |||
} | |||
ol, | |||
ul, | |||
dl { | |||
margin-top: 0; | |||
margin-bottom: 1rem; | |||
} | |||
ol ol, | |||
ul ul, | |||
ol ul, | |||
ul ol { | |||
margin-bottom: 0; | |||
} | |||
dt { | |||
font-weight: 700; | |||
} | |||
dd { | |||
margin-bottom: .5rem; | |||
margin-left: 0; | |||
} | |||
blockquote { | |||
margin: 0 0 1rem; | |||
} | |||
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; | |||
} | |||
a:hover { | |||
color: #0056b3; | |||
text-decoration: underline; | |||
} | |||
a:not([href]) { | |||
color: inherit; | |||
text-decoration: none; | |||
} | |||
a:not([href]):hover { | |||
color: inherit; | |||
text-decoration: none; | |||
} | |||
pre, | |||
code, | |||
kbd, | |||
samp { | |||
font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", 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 { | |||
overflow: hidden; | |||
vertical-align: middle; | |||
} | |||
table { | |||
border-collapse: collapse; | |||
} | |||
caption { | |||
padding-top: 0.75rem; | |||
padding-bottom: 0.75rem; | |||
color: #6c757d; | |||
text-align: left; | |||
caption-side: bottom; | |||
} | |||
th { | |||
text-align: inherit; | |||
} | |||
label { | |||
display: inline-block; | |||
margin-bottom: 0.5rem; | |||
} | |||
button { | |||
border-radius: 0; | |||
} | |||
button:focus { | |||
outline: 1px dotted; | |||
outline: 5px auto -webkit-focus-ring-color; | |||
} | |||
input, | |||
button, | |||
select, | |||
optgroup, | |||
textarea { | |||
margin: 0; | |||
font-family: inherit; | |||
font-size: inherit; | |||
line-height: inherit; | |||
} | |||
button, | |||
input { | |||
overflow: visible; | |||
} | |||
button, | |||
select { | |||
text-transform: none; | |||
} | |||
select { | |||
word-wrap: normal; | |||
} | |||
button, | |||
[type="button"], | |||
[type="reset"], | |||
[type="submit"] { | |||
-webkit-appearance: button; | |||
} | |||
button:not(:disabled), | |||
[type="button"]:not(:disabled), | |||
[type="reset"]:not(:disabled), | |||
[type="submit"]:not(:disabled) { | |||
cursor: pointer; | |||
} | |||
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"], | |||
input[type="time"], | |||
input[type="datetime-local"], | |||
input[type="month"] { | |||
-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-decoration { | |||
-webkit-appearance: none; | |||
} | |||
::-webkit-file-upload-button { | |||
font: inherit; | |||
-webkit-appearance: button; | |||
} | |||
output { | |||
display: inline-block; | |||
} | |||
summary { | |||
display: list-item; | |||
cursor: pointer; | |||
} | |||
template { | |||
display: none; | |||
} | |||
[hidden] { | |||
display: none !important; | |||
} | |||
/*# sourceMappingURL=bootstrap-reboot.css.map */ |
@ -0,0 +1,8 @@ | |||
/*! | |||
* Bootstrap Reboot v4.4.1 (https://getbootstrap.com/) | |||
* Copyright 2011-2019 The Bootstrap Authors | |||
* Copyright 2011-2019 Twitter, Inc. | |||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) | |||
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md) | |||
*/*,::after,::before{box-sizing:border-box}html{font-family:sans-serif;line-height:1.15;-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}article,aside,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";font-size:1rem;font-weight:400;line-height:1.5;color:#212529;text-align:left;background-color:#fff}[tabindex="-1"]:focus:not(:focus-visible){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;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}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}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}a:hover{color:#0056b3;text-decoration:underline}a:not([href]){color:inherit;text-decoration:none}a:not([href]):hover{color:inherit;text-decoration:none}code,kbd,pre,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",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{overflow:hidden;vertical-align:middle}table{border-collapse:collapse}caption{padding-top:.75rem;padding-bottom:.75rem;color:#6c757d;text-align:left;caption-side:bottom}th{text-align:inherit}label{display:inline-block;margin-bottom:.5rem}button{border-radius:0}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}select{word-wrap:normal}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}[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-decoration{-webkit-appearance:none}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}summary{display:list-item;cursor:pointer}template{display:none}[hidden]{display:none!important} | |||
/*# sourceMappingURL=bootstrap-reboot.min.css.map */ |
@ -0,0 +1,198 @@ | |||
/*! | |||
* Bootstrap alert.js v4.4.1 (https://getbootstrap.com/) | |||
* Copyright 2011-2019 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors) | |||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) | |||
*/ | |||
(function (global, factory) { | |||
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('jquery'), require('./util.js')) : | |||
typeof define === 'function' && define.amd ? define(['jquery', './util.js'], factory) : | |||
(global = global || self, global.Alert = factory(global.jQuery, global.Util)); | |||
}(this, (function ($, Util) { 'use strict'; | |||
$ = $ && $.hasOwnProperty('default') ? $['default'] : $; | |||
Util = Util && Util.hasOwnProperty('default') ? Util['default'] : Util; | |||
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); | |||
} | |||
} | |||
function _createClass(Constructor, protoProps, staticProps) { | |||
if (protoProps) _defineProperties(Constructor.prototype, protoProps); | |||
if (staticProps) _defineProperties(Constructor, staticProps); | |||
return Constructor; | |||
} | |||
/** | |||
* ------------------------------------------------------------------------ | |||
* Constants | |||
* ------------------------------------------------------------------------ | |||
*/ | |||
var NAME = 'alert'; | |||
var VERSION = '4.4.1'; | |||
var DATA_KEY = 'bs.alert'; | |||
var EVENT_KEY = "." + DATA_KEY; | |||
var DATA_API_KEY = '.data-api'; | |||
var JQUERY_NO_CONFLICT = $.fn[NAME]; | |||
var Selector = { | |||
DISMISS: '[data-dismiss="alert"]' | |||
}; | |||
var Event = { | |||
CLOSE: "close" + EVENT_KEY, | |||
CLOSED: "closed" + EVENT_KEY, | |||
CLICK_DATA_API: "click" + EVENT_KEY + DATA_API_KEY | |||
}; | |||
var ClassName = { | |||
ALERT: 'alert', | |||
FADE: 'fade', | |||
SHOW: 'show' | |||
}; | |||
/** | |||
* ------------------------------------------------------------------------ | |||
* Class Definition | |||
* ------------------------------------------------------------------------ | |||
*/ | |||
var Alert = | |||
/*#__PURE__*/ | |||
function () { | |||
function Alert(element) { | |||
this._element = element; | |||
} // Getters | |||
var _proto = Alert.prototype; | |||
// Public | |||
_proto.close = function close(element) { | |||
var rootElement = this._element; | |||
if (element) { | |||
rootElement = this._getRootElement(element); | |||
} | |||
var customEvent = this._triggerCloseEvent(rootElement); | |||
if (customEvent.isDefaultPrevented()) { | |||
return; | |||
} | |||
this._removeElement(rootElement); | |||
}; | |||
_proto.dispose = function dispose() { | |||
$.removeData(this._element, DATA_KEY); | |||
this._element = null; | |||
} // Private | |||
; | |||
_proto._getRootElement = function _getRootElement(element) { | |||
var selector = Util.getSelectorFromElement(element); | |||
var parent = false; | |||
if (selector) { | |||
parent = document.querySelector(selector); | |||
} | |||
if (!parent) { | |||
parent = $(element).closest("." + ClassName.ALERT)[0]; | |||
} | |||
return parent; | |||
}; | |||
_proto._triggerCloseEvent = function _triggerCloseEvent(element) { | |||
var closeEvent = $.Event(Event.CLOSE); | |||
$(element).trigger(closeEvent); | |||
return closeEvent; | |||
}; | |||
_proto._removeElement = function _removeElement(element) { | |||
var _this = this; | |||
$(element).removeClass(ClassName.SHOW); | |||
if (!$(element).hasClass(ClassName.FADE)) { | |||
this._destroyElement(element); | |||
return; | |||
} | |||
var transitionDuration = Util.getTransitionDurationFromElement(element); | |||
$(element).one(Util.TRANSITION_END, function (event) { | |||
return _this._destroyElement(element, event); | |||
}).emulateTransitionEnd(transitionDuration); | |||
}; | |||
_proto._destroyElement = function _destroyElement(element) { | |||
$(element).detach().trigger(Event.CLOSED).remove(); | |||
} // Static | |||
; | |||
Alert._jQueryInterface = function _jQueryInterface(config) { | |||
return this.each(function () { | |||
var $element = $(this); | |||
var data = $element.data(DATA_KEY); | |||
if (!data) { | |||
data = new Alert(this); | |||
$element.data(DATA_KEY, data); | |||
} | |||
if (config === 'close') { | |||
data[config](this); | |||
} | |||
}); | |||
}; | |||
Alert._handleDismiss = function _handleDismiss(alertInstance) { | |||
return function (event) { | |||
if (event) { | |||
event.preventDefault(); | |||
} | |||
alertInstance.close(this); | |||
}; | |||
}; | |||
_createClass(Alert, null, [{ | |||
key: "VERSION", | |||
get: function get() { | |||
return VERSION; | |||
} | |||
}]); | |||
return Alert; | |||
}(); | |||
/** | |||
* ------------------------------------------------------------------------ | |||
* Data Api implementation | |||
* ------------------------------------------------------------------------ | |||
*/ | |||
$(document).on(Event.CLICK_DATA_API, Selector.DISMISS, Alert._handleDismiss(new Alert())); | |||
/** | |||
* ------------------------------------------------------------------------ | |||
* jQuery | |||
* ------------------------------------------------------------------------ | |||
*/ | |||
$.fn[NAME] = Alert._jQueryInterface; | |||
$.fn[NAME].Constructor = Alert; | |||
$.fn[NAME].noConflict = function () { | |||
$.fn[NAME] = JQUERY_NO_CONFLICT; | |||
return Alert._jQueryInterface; | |||
}; | |||
return Alert; | |||
}))); | |||
//# sourceMappingURL=alert.js.map |
@ -0,0 +1,234 @@ | |||
/*! | |||
* Bootstrap button.js v4.4.1 (https://getbootstrap.com/) | |||
* Copyright 2011-2019 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors) | |||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) | |||
*/ | |||
(function (global, factory) { | |||
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('jquery')) : | |||
typeof define === 'function' && define.amd ? define(['jquery'], factory) : | |||
(global = global || self, global.Button = factory(global.jQuery)); | |||
}(this, (function ($) { 'use strict'; | |||
$ = $ && $.hasOwnProperty('default') ? $['default'] : $; | |||
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); | |||
} | |||
} | |||
function _createClass(Constructor, protoProps, staticProps) { | |||
if (protoProps) _defineProperties(Constructor.prototype, protoProps); | |||
if (staticProps) _defineProperties(Constructor, staticProps); | |||
return Constructor; | |||
} | |||
/** | |||
* ------------------------------------------------------------------------ | |||
* Constants | |||
* ------------------------------------------------------------------------ | |||
*/ | |||
var NAME = 'button'; | |||
var VERSION = '4.4.1'; | |||
var DATA_KEY = 'bs.button'; | |||
var EVENT_KEY = "." + DATA_KEY; | |||
var DATA_API_KEY = '.data-api'; | |||
var JQUERY_NO_CONFLICT = $.fn[NAME]; | |||
var ClassName = { | |||
ACTIVE: 'active', | |||
BUTTON: 'btn', | |||
FOCUS: 'focus' | |||
}; | |||
var Selector = { | |||
DATA_TOGGLE_CARROT: '[data-toggle^="button"]', | |||
DATA_TOGGLES: '[data-toggle="buttons"]', | |||
DATA_TOGGLE: '[data-toggle="button"]', | |||
DATA_TOGGLES_BUTTONS: '[data-toggle="buttons"] .btn', | |||
INPUT: 'input:not([type="hidden"])', | |||
ACTIVE: '.active', | |||
BUTTON: '.btn' | |||
}; | |||
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), | |||
LOAD_DATA_API: "load" + EVENT_KEY + DATA_API_KEY | |||
}; | |||
/** | |||
* ------------------------------------------------------------------------ | |||
* Class Definition | |||
* ------------------------------------------------------------------------ | |||
*/ | |||
var Button = | |||
/*#__PURE__*/ | |||
function () { | |||
function Button(element) { | |||
this._element = element; | |||
} // Getters | |||
var _proto = Button.prototype; | |||
// Public | |||
_proto.toggle = function toggle() { | |||
var triggerChangeEvent = true; | |||
var addAriaPressed = true; | |||
var rootElement = $(this._element).closest(Selector.DATA_TOGGLES)[0]; | |||
if (rootElement) { | |||
var input = this._element.querySelector(Selector.INPUT); | |||
if (input) { | |||
if (input.type === 'radio') { | |||
if (input.checked && this._element.classList.contains(ClassName.ACTIVE)) { | |||
triggerChangeEvent = false; | |||
} else { | |||
var activeElement = rootElement.querySelector(Selector.ACTIVE); | |||
if (activeElement) { | |||
$(activeElement).removeClass(ClassName.ACTIVE); | |||
} | |||
} | |||
} else if (input.type === 'checkbox') { | |||
if (this._element.tagName === 'LABEL' && input.checked === this._element.classList.contains(ClassName.ACTIVE)) { | |||
triggerChangeEvent = false; | |||
} | |||
} else { | |||
// if it's not a radio button or checkbox don't add a pointless/invalid checked property to the input | |||
triggerChangeEvent = false; | |||
} | |||
if (triggerChangeEvent) { | |||
input.checked = !this._element.classList.contains(ClassName.ACTIVE); | |||
$(input).trigger('change'); | |||
} | |||
input.focus(); | |||
addAriaPressed = false; | |||
} | |||
} | |||
if (!(this._element.hasAttribute('disabled') || this._element.classList.contains('disabled'))) { | |||
if (addAriaPressed) { | |||
this._element.setAttribute('aria-pressed', !this._element.classList.contains(ClassName.ACTIVE)); | |||
} | |||
if (triggerChangeEvent) { | |||
$(this._element).toggleClass(ClassName.ACTIVE); | |||
} | |||
} | |||
}; | |||
_proto.dispose = function dispose() { | |||
$.removeData(this._element, DATA_KEY); | |||
this._element = null; | |||
} // Static | |||
; | |||
Button._jQueryInterface = function _jQueryInterface(config) { | |||
return this.each(function () { | |||
var data = $(this).data(DATA_KEY); | |||
if (!data) { | |||
data = new Button(this); | |||
$(this).data(DATA_KEY, data); | |||
} | |||
if (config === 'toggle') { | |||
data[config](); | |||
} | |||
}); | |||
}; | |||
_createClass(Button, null, [{ | |||
key: "VERSION", | |||
get: function get() { | |||
return VERSION; | |||
} | |||
}]); | |||
return Button; | |||
}(); | |||
/** | |||
* ------------------------------------------------------------------------ | |||
* Data Api implementation | |||
* ------------------------------------------------------------------------ | |||
*/ | |||
$(document).on(Event.CLICK_DATA_API, Selector.DATA_TOGGLE_CARROT, function (event) { | |||
var button = event.target; | |||
if (!$(button).hasClass(ClassName.BUTTON)) { | |||
button = $(button).closest(Selector.BUTTON)[0]; | |||
} | |||
if (!button || button.hasAttribute('disabled') || button.classList.contains('disabled')) { | |||
event.preventDefault(); // work around Firefox bug #1540995 | |||
} else { | |||
var inputBtn = button.querySelector(Selector.INPUT); | |||
if (inputBtn && (inputBtn.hasAttribute('disabled') || inputBtn.classList.contains('disabled'))) { | |||
event.preventDefault(); // work around Firefox bug #1540995 | |||
return; | |||
} | |||
Button._jQueryInterface.call($(button), 'toggle'); | |||
} | |||
}).on(Event.FOCUS_BLUR_DATA_API, Selector.DATA_TOGGLE_CARROT, function (event) { | |||
var button = $(event.target).closest(Selector.BUTTON)[0]; | |||
$(button).toggleClass(ClassName.FOCUS, /^focus(in)?$/.test(event.type)); | |||
}); | |||
$(window).on(Event.LOAD_DATA_API, function () { | |||
// ensure correct active class is set to match the controls' actual values/states | |||
// find all checkboxes/readio buttons inside data-toggle groups | |||
var buttons = [].slice.call(document.querySelectorAll(Selector.DATA_TOGGLES_BUTTONS)); | |||
for (var i = 0, len = buttons.length; i < len; i++) { | |||
var button = buttons[i]; | |||
var input = button.querySelector(Selector.INPUT); | |||
if (input.checked || input.hasAttribute('checked')) { | |||
button.classList.add(ClassName.ACTIVE); | |||
} else { | |||
button.classList.remove(ClassName.ACTIVE); | |||
} | |||
} // find all button toggles | |||
buttons = [].slice.call(document.querySelectorAll(Selector.DATA_TOGGLE)); | |||
for (var _i = 0, _len = buttons.length; _i < _len; _i++) { | |||
var _button = buttons[_i]; | |||
if (_button.getAttribute('aria-pressed') === 'true') { | |||
_button.classList.add(ClassName.ACTIVE); | |||
} else { | |||
_button.classList.remove(ClassName.ACTIVE); | |||
} | |||
} | |||
}); | |||
/** | |||
* ------------------------------------------------------------------------ | |||
* jQuery | |||
* ------------------------------------------------------------------------ | |||
*/ | |||
$.fn[NAME] = Button._jQueryInterface; | |||
$.fn[NAME].Constructor = Button; | |||
$.fn[NAME].noConflict = function () { | |||
$.fn[NAME] = JQUERY_NO_CONFLICT; | |||
return Button._jQueryInterface; | |||
}; | |||
return Button; | |||
}))); | |||
//# sourceMappingURL=button.js.map |
@ -0,0 +1,681 @@ | |||
/*! | |||
* Bootstrap carousel.js v4.4.1 (https://getbootstrap.com/) | |||
* Copyright 2011-2019 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors) | |||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) | |||
*/ | |||
(function (global, factory) { | |||
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('jquery'), require('./util.js')) : | |||
typeof define === 'function' && define.amd ? define(['jquery', './util.js'], factory) : | |||
(global = global || self, global.Carousel = factory(global.jQuery, global.Util)); | |||
}(this, (function ($, Util) { 'use strict'; | |||
$ = $ && $.hasOwnProperty('default') ? $['default'] : $; | |||
Util = Util && Util.hasOwnProperty('default') ? Util['default'] : Util; | |||
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); | |||
} | |||
} | |||
function _createClass(Constructor, protoProps, staticProps) { | |||
if (protoProps) _defineProperties(Constructor.prototype, protoProps); | |||
if (staticProps) _defineProperties(Constructor, staticProps); | |||
return Constructor; | |||
} | |||
function _defineProperty(obj, key, value) { | |||
if (key in obj) { | |||
Object.defineProperty(obj, key, { | |||
value: value, | |||
enumerable: true, | |||
configurable: true, | |||
writable: true | |||
}); | |||
} else { | |||
obj[key] = value; | |||
} | |||
return obj; | |||
} | |||
function ownKeys(object, enumerableOnly) { | |||
var keys = Object.keys(object); | |||
if (Object.getOwnPropertySymbols) { | |||
var symbols = Object.getOwnPropertySymbols(object); | |||
if (enumerableOnly) symbols = symbols.filter(function (sym) { | |||
return Object.getOwnPropertyDescriptor(object, sym).enumerable; | |||
}); | |||
keys.push.apply(keys, symbols); | |||
} | |||
return keys; | |||
} | |||
function _objectSpread2(target) { | |||
for (var i = 1; i < arguments.length; i++) { | |||
var source = arguments[i] != null ? arguments[i] : {}; | |||
if (i % 2) { | |||
ownKeys(Object(source), true).forEach(function (key) { | |||
_defineProperty(target, key, source[key]); | |||
}); | |||
} else if (Object.getOwnPropertyDescriptors) { | |||
Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); | |||
} else { | |||
ownKeys(Object(source)).forEach(function (key) { | |||
Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); | |||
}); | |||
} | |||
} | |||
return target; | |||
} | |||
/** | |||
* ------------------------------------------------------------------------ | |||
* Constants | |||
* ------------------------------------------------------------------------ | |||
*/ | |||
var NAME = 'carousel'; | |||
var VERSION = '4.4.1'; | |||
var DATA_KEY = 'bs.carousel'; | |||
var EVENT_KEY = "." + DATA_KEY; | |||
var DATA_API_KEY = '.data-api'; | |||
var JQUERY_NO_CONFLICT = $.fn[NAME]; | |||
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 SWIPE_THRESHOLD = 40; | |||
var Default = { | |||
interval: 5000, | |||
keyboard: true, | |||
slide: false, | |||
pause: 'hover', | |||
wrap: true, | |||
touch: true | |||
}; | |||
var DefaultType = { | |||
interval: '(number|boolean)', | |||
keyboard: 'boolean', | |||
slide: '(boolean|string)', | |||
pause: '(string|boolean)', | |||
wrap: 'boolean', | |||
touch: 'boolean' | |||
}; | |||
var Direction = { | |||
NEXT: 'next', | |||
PREV: 'prev', | |||
LEFT: 'left', | |||
RIGHT: 'right' | |||
}; | |||
var Event = { | |||
SLIDE: "slide" + EVENT_KEY, | |||
SLID: "slid" + EVENT_KEY, | |||
KEYDOWN: "keydown" + EVENT_KEY, | |||
MOUSEENTER: "mouseenter" + EVENT_KEY, | |||
MOUSELEAVE: "mouseleave" + EVENT_KEY, | |||
TOUCHSTART: "touchstart" + EVENT_KEY, | |||
TOUCHMOVE: "touchmove" + EVENT_KEY, | |||
TOUCHEND: "touchend" + EVENT_KEY, | |||
POINTERDOWN: "pointerdown" + EVENT_KEY, | |||
POINTERUP: "pointerup" + EVENT_KEY, | |||
DRAG_START: "dragstart" + EVENT_KEY, | |||
LOAD_DATA_API: "load" + EVENT_KEY + DATA_API_KEY, | |||
CLICK_DATA_API: "click" + EVENT_KEY + DATA_API_KEY | |||
}; | |||
var ClassName = { | |||
CAROUSEL: 'carousel', | |||
ACTIVE: 'active', | |||
SLIDE: 'slide', | |||
RIGHT: 'carousel-item-right', | |||
LEFT: 'carousel-item-left', | |||
NEXT: 'carousel-item-next', | |||
PREV: 'carousel-item-prev', | |||
ITEM: 'carousel-item', | |||
POINTER_EVENT: 'pointer-event' | |||
}; | |||
var Selector = { | |||
ACTIVE: '.active', | |||
ACTIVE_ITEM: '.active.carousel-item', | |||
ITEM: '.carousel-item', | |||
ITEM_IMG: '.carousel-item img', | |||
NEXT_PREV: '.carousel-item-next, .carousel-item-prev', | |||
INDICATORS: '.carousel-indicators', | |||
DATA_SLIDE: '[data-slide], [data-slide-to]', | |||
DATA_RIDE: '[data-ride="carousel"]' | |||
}; | |||
var PointerType = { | |||
TOUCH: 'touch', | |||
PEN: 'pen' | |||
}; | |||
/** | |||
* ------------------------------------------------------------------------ | |||
* Class Definition | |||
* ------------------------------------------------------------------------ | |||
*/ | |||
var Carousel = | |||
/*#__PURE__*/ | |||
function () { | |||
function Carousel(element, config) { | |||
this._items = null; | |||
this._interval = null; | |||
this._activeElement = null; | |||
this._isPaused = false; | |||
this._isSliding = false; | |||
this.touchTimeout = null; | |||
this.touchStartX = 0; | |||
this.touchDeltaX = 0; | |||
this._config = this._getConfig(config); | |||
this._element = element; | |||
this._indicatorsElement = this._element.querySelector(Selector.INDICATORS); | |||
this._touchSupported = 'ontouchstart' in document.documentElement || navigator.maxTouchPoints > 0; | |||
this._pointerEvent = Boolean(window.PointerEvent || window.MSPointerEvent); | |||
this._addEventListeners(); | |||
} // Getters | |||
var _proto = Carousel.prototype; | |||
// Public | |||
_proto.next = function next() { | |||
if (!this._isSliding) { | |||
this._slide(Direction.NEXT); | |||
} | |||
}; | |||
_proto.nextWhenVisible = function nextWhenVisible() { | |||
// Don't call next when the page isn't visible | |||
// or the carousel or its parent isn't visible | |||
if (!document.hidden && $(this._element).is(':visible') && $(this._element).css('visibility') !== 'hidden') { | |||
this.next(); | |||
} | |||
}; | |||
_proto.prev = function prev() { | |||
if (!this._isSliding) { | |||
this._slide(Direction.PREV); | |||
} | |||
}; | |||
_proto.pause = function pause(event) { | |||
if (!event) { | |||
this._isPaused = true; | |||
} | |||
if (this._element.querySelector(Selector.NEXT_PREV)) { | |||
Util.triggerTransitionEnd(this._element); | |||
this.cycle(true); | |||
} | |||
clearInterval(this._interval); | |||
this._interval = null; | |||
}; | |||
_proto.cycle = function cycle(event) { | |||
if (!event) { | |||
this._isPaused = false; | |||
} | |||
if (this._interval) { | |||
clearInterval(this._interval); | |||
this._interval = null; | |||
} | |||
if (this._config.interval && !this._isPaused) { | |||
this._interval = setInterval((document.visibilityState ? this.nextWhenVisible : this.next).bind(this), this._config.interval); | |||
} | |||
}; | |||
_proto.to = function to(index) { | |||
var _this = this; | |||
this._activeElement = this._element.querySelector(Selector.ACTIVE_ITEM); | |||
var activeIndex = this._getItemIndex(this._activeElement); | |||
if (index > this._items.length - 1 || index < 0) { | |||
return; | |||
} | |||
if (this._isSliding) { | |||
$(this._element).one(Event.SLID, function () { | |||
return _this.to(index); | |||
}); | |||
return; | |||
} | |||
if (activeIndex === index) { | |||
this.pause(); | |||
this.cycle(); | |||
return; | |||
} | |||
var direction = index > activeIndex ? Direction.NEXT : Direction.PREV; | |||
this._slide(direction, this._items[index]); | |||
}; | |||
_proto.dispose = function dispose() { | |||
$(this._element).off(EVENT_KEY); | |||
$.removeData(this._element, DATA_KEY); | |||
this._items = null; | |||
this._config = null; | |||
this._element = null; | |||
this._interval = null; | |||
this._isPaused = null; | |||
this._isSliding = null; | |||
this._activeElement = null; | |||
this._indicatorsElement = null; | |||
} // Private | |||
; | |||
_proto._getConfig = function _getConfig(config) { | |||
config = _objectSpread2({}, Default, {}, config); | |||
Util.typeCheckConfig(NAME, config, DefaultType); | |||
return config; | |||
}; | |||
_proto._handleSwipe = function _handleSwipe() { | |||
var absDeltax = Math.abs(this.touchDeltaX); | |||
if (absDeltax <= SWIPE_THRESHOLD) { | |||
return; | |||
} | |||
var direction = absDeltax / this.touchDeltaX; | |||
this.touchDeltaX = 0; // swipe left | |||
if (direction > 0) { | |||
this.prev(); | |||
} // swipe right | |||
if (direction < 0) { | |||
this.next(); | |||
} | |||
}; | |||
_proto._addEventListeners = function _addEventListeners() { | |||
var _this2 = this; | |||
if (this._config.keyboard) { | |||
$(this._element).on(Event.KEYDOWN, function (event) { | |||
return _this2._keydown(event); | |||
}); | |||
} | |||
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 (this._config.touch) { | |||
this._addTouchEventListeners(); | |||
} | |||
}; | |||
_proto._addTouchEventListeners = function _addTouchEventListeners() { | |||
var _this3 = this; | |||
if (!this._touchSupported) { | |||
return; | |||
} | |||
var start = function start(event) { | |||
if (_this3._pointerEvent && PointerType[event.originalEvent.pointerType.toUpperCase()]) { | |||
_this3.touchStartX = event.originalEvent.clientX; | |||
} else if (!_this3._pointerEvent) { | |||
_this3.touchStartX = event.originalEvent.touches[0].clientX; | |||
} | |||
}; | |||
var move = function move(event) { | |||
// ensure swiping with one touch and not pinching | |||
if (event.originalEvent.touches && event.originalEvent.touches.length > 1) { | |||
_this3.touchDeltaX = 0; | |||
} else { | |||
_this3.touchDeltaX = event.originalEvent.touches[0].clientX - _this3.touchStartX; | |||
} | |||
}; | |||
var end = function end(event) { | |||
if (_this3._pointerEvent && PointerType[event.originalEvent.pointerType.toUpperCase()]) { | |||
_this3.touchDeltaX = event.originalEvent.clientX - _this3.touchStartX; | |||
} | |||
_this3._handleSwipe(); | |||
if (_this3._config.pause === 'hover') { | |||
// 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 | |||
_this3.pause(); | |||
if (_this3.touchTimeout) { | |||
clearTimeout(_this3.touchTimeout); | |||
} | |||
_this3.touchTimeout = setTimeout(function (event) { | |||
return _this3.cycle(event); | |||
}, TOUCHEVENT_COMPAT_WAIT + _this3._config.interval); | |||
} | |||
}; | |||
$(this._element.querySelectorAll(Selector.ITEM_IMG)).on(Event.DRAG_START, function (e) { | |||
return e.preventDefault(); | |||
}); | |||
if (this._pointerEvent) { | |||
$(this._element).on(Event.POINTERDOWN, function (event) { | |||
return start(event); | |||
}); | |||
$(this._element).on(Event.POINTERUP, function (event) { | |||
return end(event); | |||
}); | |||
this._element.classList.add(ClassName.POINTER_EVENT); | |||
} else { | |||
$(this._element).on(Event.TOUCHSTART, function (event) { | |||
return start(event); | |||
}); | |||
$(this._element).on(Event.TOUCHMOVE, function (event) { | |||
return move(event); | |||
}); | |||
$(this._element).on(Event.TOUCHEND, function (event) { | |||
return end(event); | |||
}); | |||
} | |||
}; | |||
_proto._keydown = function _keydown(event) { | |||
if (/input|textarea/i.test(event.target.tagName)) { | |||
return; | |||
} | |||
switch (event.which) { | |||
case ARROW_LEFT_KEYCODE: | |||
event.preventDefault(); | |||
this.prev(); | |||
break; | |||
case ARROW_RIGHT_KEYCODE: | |||
event.preventDefault(); | |||
this.next(); | |||
break; | |||
} | |||
}; | |||
_proto._getItemIndex = function _getItemIndex(element) { | |||
this._items = element && element.parentNode ? [].slice.call(element.parentNode.querySelectorAll(Selector.ITEM)) : []; | |||
return this._items.indexOf(element); | |||
}; | |||
_proto._getItemByDirection = function _getItemByDirection(direction, activeElement) { | |||
var isNextDirection = direction === Direction.NEXT; | |||
var isPrevDirection = direction === Direction.PREV; | |||
var activeIndex = this._getItemIndex(activeElement); | |||
var lastItemIndex = this._items.length - 1; | |||
var isGoingToWrap = isPrevDirection && activeIndex === 0 || isNextDirection && activeIndex === lastItemIndex; | |||
if (isGoingToWrap && !this._config.wrap) { | |||
return activeElement; | |||
} | |||
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]; | |||
}; | |||
_proto._triggerSlideEvent = function _triggerSlideEvent(relatedTarget, eventDirectionName) { | |||
var targetIndex = this._getItemIndex(relatedTarget); | |||
var fromIndex = this._getItemIndex(this._element.querySelector(Selector.ACTIVE_ITEM)); | |||
var slideEvent = $.Event(Event.SLIDE, { | |||
relatedTarget: relatedTarget, | |||
direction: eventDirectionName, | |||
from: fromIndex, | |||
to: targetIndex | |||
}); | |||
$(this._element).trigger(slideEvent); | |||
return slideEvent; | |||
}; | |||
_proto._setActiveIndicatorElement = function _setActiveIndicatorElement(element) { | |||
if (this._indicatorsElement) { | |||
var indicators = [].slice.call(this._indicatorsElement.querySelectorAll(Selector.ACTIVE)); | |||
$(indicators).removeClass(ClassName.ACTIVE); | |||
var nextIndicator = this._indicatorsElement.children[this._getItemIndex(element)]; | |||
if (nextIndicator) { | |||
$(nextIndicator).addClass(ClassName.ACTIVE); | |||
} | |||
} | |||
}; | |||
_proto._slide = function _slide(direction, element) { | |||
var _this4 = this; | |||
var activeElement = this._element.querySelector(Selector.ACTIVE_ITEM); | |||
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; | |||
var orderClassName; | |||
var eventDirectionName; | |||
if (direction === Direction.NEXT) { | |||
directionalClassName = ClassName.LEFT; | |||
orderClassName = ClassName.NEXT; | |||
eventDirectionName = Direction.LEFT; | |||
} else { | |||
directionalClassName = ClassName.RIGHT; | |||
orderClassName = ClassName.PREV; | |||
eventDirectionName = Direction.RIGHT; | |||
} | |||
if (nextElement && $(nextElement).hasClass(ClassName.ACTIVE)) { | |||
this._isSliding = false; | |||
return; | |||
} | |||
var slideEvent = this._triggerSlideEvent(nextElement, eventDirectionName); | |||
if (slideEvent.isDefaultPrevented()) { | |||
return; | |||
} | |||
if (!activeElement || !nextElement) { | |||
// Some weirdness is happening, so we bail | |||
return; | |||
} | |||
this._isSliding = true; | |||
if (isCycling) { | |||
this.pause(); | |||
} | |||
this._setActiveIndicatorElement(nextElement); | |||
var slidEvent = $.Event(Event.SLID, { | |||
relatedTarget: nextElement, | |||
direction: eventDirectionName, | |||
from: activeElementIndex, | |||
to: nextElementIndex | |||
}); | |||
if ($(this._element).hasClass(ClassName.SLIDE)) { | |||
$(nextElement).addClass(orderClassName); | |||
Util.reflow(nextElement); | |||
$(activeElement).addClass(directionalClassName); | |||
$(nextElement).addClass(directionalClassName); | |||
var nextElementInterval = parseInt(nextElement.getAttribute('data-interval'), 10); | |||
if (nextElementInterval) { | |||
this._config.defaultInterval = this._config.defaultInterval || this._config.interval; | |||
this._config.interval = nextElementInterval; | |||
} else { | |||
this._config.interval = this._config.defaultInterval || this._config.interval; | |||
} | |||
var transitionDuration = Util.getTransitionDurationFromElement(activeElement); | |||
$(activeElement).one(Util.TRANSITION_END, function () { | |||
$(nextElement).removeClass(directionalClassName + " " + orderClassName).addClass(ClassName.ACTIVE); | |||
$(activeElement).removeClass(ClassName.ACTIVE + " " + orderClassName + " " + directionalClassName); | |||
_this4._isSliding = false; | |||
setTimeout(function () { | |||
return $(_this4._element).trigger(slidEvent); | |||
}, 0); | |||
}).emulateTransitionEnd(transitionDuration); | |||
} else { | |||
$(activeElement).removeClass(ClassName.ACTIVE); | |||
$(nextElement).addClass(ClassName.ACTIVE); | |||
this._isSliding = false; | |||
$(this._element).trigger(slidEvent); | |||
} | |||
if (isCycling) { | |||
this.cycle(); | |||
} | |||
} // Static | |||
; | |||
Carousel._jQueryInterface = function _jQueryInterface(config) { | |||
return this.each(function () { | |||
var data = $(this).data(DATA_KEY); | |||
var _config = _objectSpread2({}, Default, {}, $(this).data()); | |||
if (typeof config === 'object') { | |||
_config = _objectSpread2({}, _config, {}, config); | |||
} | |||
var action = typeof config === 'string' ? config : _config.slide; | |||
if (!data) { | |||
data = new Carousel(this, _config); | |||
$(this).data(DATA_KEY, data); | |||
} | |||
if (typeof config === 'number') { | |||
data.to(config); | |||
} else if (typeof action === 'string') { | |||
if (typeof data[action] === 'undefined') { | |||
throw new TypeError("No method named \"" + action + "\""); | |||
} | |||
data[action](); | |||
} else if (_config.interval && _config.ride) { | |||
data.pause(); | |||
data.cycle(); | |||
} | |||
}); | |||
}; | |||
Carousel._dataApiClickHandler = function _dataApiClickHandler(event) { | |||
var selector = Util.getSelectorFromElement(this); | |||
if (!selector) { | |||
return; | |||
} | |||
var target = $(selector)[0]; | |||
if (!target || !$(target).hasClass(ClassName.CAROUSEL)) { | |||
return; | |||
} | |||
var config = _objectSpread2({}, $(target).data(), {}, $(this).data()); | |||
var slideIndex = this.getAttribute('data-slide-to'); | |||
if (slideIndex) { | |||
config.interval = false; | |||
} | |||
Carousel._jQueryInterface.call($(target), config); | |||
if (slideIndex) { | |||
$(target).data(DATA_KEY).to(slideIndex); | |||
} | |||
event.preventDefault(); | |||
}; | |||
_createClass(Carousel, null, [{ | |||
key: "VERSION", | |||
get: function get() { | |||
return VERSION; | |||
} | |||
}, { | |||
key: "Default", | |||
get: function get() { | |||
return Default; | |||
} | |||
}]); | |||
return Carousel; | |||
}(); | |||
/** | |||
* ------------------------------------------------------------------------ | |||
* Data Api implementation | |||
* ------------------------------------------------------------------------ | |||
*/ | |||
$(document).on(Event.CLICK_DATA_API, Selector.DATA_SLIDE, Carousel._dataApiClickHandler); | |||
$(window).on(Event.LOAD_DATA_API, function () { | |||
var carousels = [].slice.call(document.querySelectorAll(Selector.DATA_RIDE)); | |||
for (var i = 0, len = carousels.length; i < len; i++) { | |||
var $carousel = $(carousels[i]); | |||
Carousel._jQueryInterface.call($carousel, $carousel.data()); | |||
} | |||
}); | |||
/** | |||
* ------------------------------------------------------------------------ | |||
* jQuery | |||
* ------------------------------------------------------------------------ | |||
*/ | |||
$.fn[NAME] = Carousel._jQueryInterface; | |||
$.fn[NAME].Constructor = Carousel; | |||
$.fn[NAME].noConflict = function () { | |||
$.fn[NAME] = JQUERY_NO_CONFLICT; | |||
return Carousel._jQueryInterface; | |||
}; | |||
return Carousel; | |||
}))); | |||
//# sourceMappingURL=carousel.js.map |
@ -0,0 +1,442 @@ | |||
/*! | |||
* Bootstrap collapse.js v4.4.1 (https://getbootstrap.com/) | |||
* Copyright 2011-2019 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors) | |||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) | |||
*/ | |||
(function (global, factory) { | |||
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('jquery'), require('./util.js')) : | |||
typeof define === 'function' && define.amd ? define(['jquery', './util.js'], factory) : | |||
(global = global || self, global.Collapse = factory(global.jQuery, global.Util)); | |||
}(this, (function ($, Util) { 'use strict'; | |||
$ = $ && $.hasOwnProperty('default') ? $['default'] : $; | |||
Util = Util && Util.hasOwnProperty('default') ? Util['default'] : Util; | |||
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); | |||
} | |||
} | |||
function _createClass(Constructor, protoProps, staticProps) { | |||
if (protoProps) _defineProperties(Constructor.prototype, protoProps); | |||
if (staticProps) _defineProperties(Constructor, staticProps); | |||
return Constructor; | |||
} | |||
function _defineProperty(obj, key, value) { | |||
if (key in obj) { | |||
Object.defineProperty(obj, key, { | |||
value: value, | |||
enumerable: true, | |||
configurable: true, | |||
writable: true | |||
}); | |||
} else { | |||
obj[key] = value; | |||
} | |||
return obj; | |||
} | |||
function ownKeys(object, enumerableOnly) { | |||
var keys = Object.keys(object); | |||
if (Object.getOwnPropertySymbols) { | |||
var symbols = Object.getOwnPropertySymbols(object); | |||
if (enumerableOnly) symbols = symbols.filter(function (sym) { | |||
return Object.getOwnPropertyDescriptor(object, sym).enumerable; | |||
}); | |||
keys.push.apply(keys, symbols); | |||
} | |||
return keys; | |||
} | |||
function _objectSpread2(target) { | |||
for (var i = 1; i < arguments.length; i++) { | |||
var source = arguments[i] != null ? arguments[i] : {}; | |||
if (i % 2) { | |||
ownKeys(Object(source), true).forEach(function (key) { | |||
_defineProperty(target, key, source[key]); | |||
}); | |||
} else if (Object.getOwnPropertyDescriptors) { | |||
Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); | |||
} else { | |||
ownKeys(Object(source)).forEach(function (key) { | |||
Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); | |||
}); | |||
} | |||
} | |||
return target; | |||
} | |||
/** | |||
* ------------------------------------------------------------------------ | |||
* Constants | |||
* ------------------------------------------------------------------------ | |||
*/ | |||
var NAME = 'collapse'; | |||
var VERSION = '4.4.1'; | |||
var DATA_KEY = 'bs.collapse'; | |||
var EVENT_KEY = "." + DATA_KEY; | |||
var DATA_API_KEY = '.data-api'; | |||
var JQUERY_NO_CONFLICT = $.fn[NAME]; | |||
var Default = { | |||
toggle: true, | |||
parent: '' | |||
}; | |||
var DefaultType = { | |||
toggle: 'boolean', | |||
parent: '(string|element)' | |||
}; | |||
var Event = { | |||
SHOW: "show" + EVENT_KEY, | |||
SHOWN: "shown" + EVENT_KEY, | |||
HIDE: "hide" + EVENT_KEY, | |||
HIDDEN: "hidden" + EVENT_KEY, | |||
CLICK_DATA_API: "click" + EVENT_KEY + DATA_API_KEY | |||
}; | |||
var ClassName = { | |||
SHOW: 'show', | |||
COLLAPSE: 'collapse', | |||
COLLAPSING: 'collapsing', | |||
COLLAPSED: 'collapsed' | |||
}; | |||
var Dimension = { | |||
WIDTH: 'width', | |||
HEIGHT: 'height' | |||
}; | |||
var Selector = { | |||
ACTIVES: '.show, .collapsing', | |||
DATA_TOGGLE: '[data-toggle="collapse"]' | |||
}; | |||
/** | |||
* ------------------------------------------------------------------------ | |||
* Class Definition | |||
* ------------------------------------------------------------------------ | |||
*/ | |||
var Collapse = | |||
/*#__PURE__*/ | |||
function () { | |||
function Collapse(element, config) { | |||
this._isTransitioning = false; | |||
this._element = element; | |||
this._config = this._getConfig(config); | |||
this._triggerArray = [].slice.call(document.querySelectorAll("[data-toggle=\"collapse\"][href=\"#" + element.id + "\"]," + ("[data-toggle=\"collapse\"][data-target=\"#" + element.id + "\"]"))); | |||
var toggleList = [].slice.call(document.querySelectorAll(Selector.DATA_TOGGLE)); | |||
for (var i = 0, len = toggleList.length; i < len; i++) { | |||
var elem = toggleList[i]; | |||
var selector = Util.getSelectorFromElement(elem); | |||
var filterElement = [].slice.call(document.querySelectorAll(selector)).filter(function (foundElem) { | |||
return foundElem === element; | |||
}); | |||
if (selector !== null && filterElement.length > 0) { | |||
this._selector = selector; | |||
this._triggerArray.push(elem); | |||
} | |||
} | |||
this._parent = this._config.parent ? this._getParent() : null; | |||
if (!this._config.parent) { | |||
this._addAriaAndCollapsedClass(this._element, this._triggerArray); | |||
} | |||
if (this._config.toggle) { | |||
this.toggle(); | |||
} | |||
} // Getters | |||
var _proto = Collapse.prototype; | |||
// Public | |||
_proto.toggle = function toggle() { | |||
if ($(this._element).hasClass(ClassName.SHOW)) { | |||
this.hide(); | |||
} else { | |||
this.show(); | |||
} | |||
}; | |||
_proto.show = function show() { | |||
var _this = this; | |||
if (this._isTransitioning || $(this._element).hasClass(ClassName.SHOW)) { | |||
return; | |||
} | |||
var actives; | |||
var activesData; | |||
if (this._parent) { | |||
actives = [].slice.call(this._parent.querySelectorAll(Selector.ACTIVES)).filter(function (elem) { | |||
if (typeof _this._config.parent === 'string') { | |||
return elem.getAttribute('data-parent') === _this._config.parent; | |||
} | |||
return elem.classList.contains(ClassName.COLLAPSE); | |||
}); | |||
if (actives.length === 0) { | |||
actives = null; | |||
} | |||
} | |||
if (actives) { | |||
activesData = $(actives).not(this._selector).data(DATA_KEY); | |||
if (activesData && activesData._isTransitioning) { | |||
return; | |||
} | |||
} | |||
var startEvent = $.Event(Event.SHOW); | |||
$(this._element).trigger(startEvent); | |||
if (startEvent.isDefaultPrevented()) { | |||
return; | |||
} | |||
if (actives) { | |||
Collapse._jQueryInterface.call($(actives).not(this._selector), 'hide'); | |||
if (!activesData) { | |||
$(actives).data(DATA_KEY, null); | |||
} | |||
} | |||
var dimension = this._getDimension(); | |||
$(this._element).removeClass(ClassName.COLLAPSE).addClass(ClassName.COLLAPSING); | |||
this._element.style[dimension] = 0; | |||
if (this._triggerArray.length) { | |||
$(this._triggerArray).removeClass(ClassName.COLLAPSED).attr('aria-expanded', true); | |||
} | |||
this.setTransitioning(true); | |||
var complete = function complete() { | |||
$(_this._element).removeClass(ClassName.COLLAPSING).addClass(ClassName.COLLAPSE).addClass(ClassName.SHOW); | |||
_this._element.style[dimension] = ''; | |||
_this.setTransitioning(false); | |||
$(_this._element).trigger(Event.SHOWN); | |||
}; | |||
var capitalizedDimension = dimension[0].toUpperCase() + dimension.slice(1); | |||
var scrollSize = "scroll" + capitalizedDimension; | |||
var transitionDuration = Util.getTransitionDurationFromElement(this._element); | |||
$(this._element).one(Util.TRANSITION_END, complete).emulateTransitionEnd(transitionDuration); | |||
this._element.style[dimension] = this._element[scrollSize] + "px"; | |||
}; | |||
_proto.hide = function hide() { | |||
var _this2 = this; | |||
if (this._isTransitioning || !$(this._element).hasClass(ClassName.SHOW)) { | |||
return; | |||
} | |||
var startEvent = $.Event(Event.HIDE); | |||
$(this._element).trigger(startEvent); | |||
if (startEvent.isDefaultPrevented()) { | |||
return; | |||
} | |||
var dimension = this._getDimension(); | |||
this._element.style[dimension] = this._element.getBoundingClientRect()[dimension] + "px"; | |||
Util.reflow(this._element); | |||
$(this._element).addClass(ClassName.COLLAPSING).removeClass(ClassName.COLLAPSE).removeClass(ClassName.SHOW); | |||
var triggerArrayLength = this._triggerArray.length; | |||
if (triggerArrayLength > 0) { | |||
for (var i = 0; i < triggerArrayLength; i++) { | |||
var trigger = this._triggerArray[i]; | |||
var selector = Util.getSelectorFromElement(trigger); | |||
if (selector !== null) { | |||
var $elem = $([].slice.call(document.querySelectorAll(selector))); | |||
if (!$elem.hasClass(ClassName.SHOW)) { | |||
$(trigger).addClass(ClassName.COLLAPSED).attr('aria-expanded', false); | |||
} | |||
} | |||
} | |||
} | |||
this.setTransitioning(true); | |||
var complete = function complete() { | |||
_this2.setTransitioning(false); | |||
$(_this2._element).removeClass(ClassName.COLLAPSING).addClass(ClassName.COLLAPSE).trigger(Event.HIDDEN); | |||
}; | |||
this._element.style[dimension] = ''; | |||
var transitionDuration = Util.getTransitionDurationFromElement(this._element); | |||
$(this._element).one(Util.TRANSITION_END, complete).emulateTransitionEnd(transitionDuration); | |||
}; | |||
_proto.setTransitioning = function setTransitioning(isTransitioning) { | |||
this._isTransitioning = isTransitioning; | |||
}; | |||
_proto.dispose = function dispose() { | |||
$.removeData(this._element, DATA_KEY); | |||
this._config = null; | |||
this._parent = null; | |||
this._element = null; | |||
this._triggerArray = null; | |||
this._isTransitioning = null; | |||
} // Private | |||
; | |||
_proto._getConfig = function _getConfig(config) { | |||
config = _objectSpread2({}, Default, {}, config); | |||
config.toggle = Boolean(config.toggle); // Coerce string values | |||
Util.typeCheckConfig(NAME, config, DefaultType); | |||
return config; | |||
}; | |||
_proto._getDimension = function _getDimension() { | |||
var hasWidth = $(this._element).hasClass(Dimension.WIDTH); | |||
return hasWidth ? Dimension.WIDTH : Dimension.HEIGHT; | |||
}; | |||
_proto._getParent = function _getParent() { | |||
var _this3 = this; | |||
var parent; | |||
if (Util.isElement(this._config.parent)) { | |||
parent = this._config.parent; // It's a jQuery object | |||
if (typeof this._config.parent.jquery !== 'undefined') { | |||
parent = this._config.parent[0]; | |||
} | |||
} else { | |||
parent = document.querySelector(this._config.parent); | |||
} | |||
var selector = "[data-toggle=\"collapse\"][data-parent=\"" + this._config.parent + "\"]"; | |||
var children = [].slice.call(parent.querySelectorAll(selector)); | |||
$(children).each(function (i, element) { | |||
_this3._addAriaAndCollapsedClass(Collapse._getTargetFromElement(element), [element]); | |||
}); | |||
return parent; | |||
}; | |||
_proto._addAriaAndCollapsedClass = function _addAriaAndCollapsedClass(element, triggerArray) { | |||
var isOpen = $(element).hasClass(ClassName.SHOW); | |||
if (triggerArray.length) { | |||
$(triggerArray).toggleClass(ClassName.COLLAPSED, !isOpen).attr('aria-expanded', isOpen); | |||
} | |||
} // Static | |||
; | |||
Collapse._getTargetFromElement = function _getTargetFromElement(element) { | |||
var selector = Util.getSelectorFromElement(element); | |||
return selector ? document.querySelector(selector) : null; | |||
}; | |||
Collapse._jQueryInterface = function _jQueryInterface(config) { | |||
return this.each(function () { | |||
var $this = $(this); | |||
var data = $this.data(DATA_KEY); | |||
var _config = _objectSpread2({}, Default, {}, $this.data(), {}, typeof config === 'object' && config ? config : {}); | |||
if (!data && _config.toggle && /show|hide/.test(config)) { | |||
_config.toggle = false; | |||
} | |||
if (!data) { | |||
data = new Collapse(this, _config); | |||
$this.data(DATA_KEY, data); | |||
} | |||
if (typeof config === 'string') { | |||
if (typeof data[config] === 'undefined') { | |||
throw new TypeError("No method named \"" + config + "\""); | |||
} | |||
data[config](); | |||
} | |||
}); | |||
}; | |||
_createClass(Collapse, null, [{ | |||
key: "VERSION", | |||
get: function get() { | |||
return VERSION; | |||
} | |||
}, { | |||
key: "Default", | |||
get: function get() { | |||
return Default; | |||
} | |||
}]); | |||
return Collapse; | |||
}(); | |||
/** | |||
* ------------------------------------------------------------------------ | |||
* Data Api implementation | |||
* ------------------------------------------------------------------------ | |||
*/ | |||
$(document).on(Event.CLICK_DATA_API, Selector.DATA_TOGGLE, function (event) { | |||
// preventDefault only for <a> elements (which change the URL) not inside the collapsible element | |||
if (event.currentTarget.tagName === 'A') { | |||
event.preventDefault(); | |||
} | |||
var $trigger = $(this); | |||
var selector = Util.getSelectorFromElement(this); | |||
var selectors = [].slice.call(document.querySelectorAll(selector)); | |||
$(selectors).each(function () { | |||
var $target = $(this); | |||
var data = $target.data(DATA_KEY); | |||
var config = data ? 'toggle' : $trigger.data(); | |||
Collapse._jQueryInterface.call($target, config); | |||
}); | |||
}); | |||
/** | |||
* ------------------------------------------------------------------------ | |||
* jQuery | |||
* ------------------------------------------------------------------------ | |||
*/ | |||
$.fn[NAME] = Collapse._jQueryInterface; | |||
$.fn[NAME].Constructor = Collapse; | |||
$.fn[NAME].noConflict = function () { | |||
$.fn[NAME] = JQUERY_NO_CONFLICT; | |||
return Collapse._jQueryInterface; | |||
}; | |||
return Collapse; | |||
}))); | |||
//# sourceMappingURL=collapse.js.map |
@ -0,0 +1,616 @@ | |||
/*! | |||
* Bootstrap dropdown.js v4.4.1 (https://getbootstrap.com/) | |||
* Copyright 2011-2019 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors) | |||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) | |||
*/ | |||
(function (global, factory) { | |||
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('jquery'), require('popper.js'), require('./util.js')) : | |||
typeof define === 'function' && define.amd ? define(['jquery', 'popper.js', './util.js'], factory) : | |||
(global = global || self, global.Dropdown = factory(global.jQuery, global.Popper, global.Util)); | |||
}(this, (function ($, Popper, Util) { 'use strict'; | |||
$ = $ && $.hasOwnProperty('default') ? $['default'] : $; | |||
Popper = Popper && Popper.hasOwnProperty('default') ? Popper['default'] : Popper; | |||
Util = Util && Util.hasOwnProperty('default') ? Util['default'] : Util; | |||
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); | |||
} | |||
} | |||
function _createClass(Constructor, protoProps, staticProps) { | |||
if (protoProps) _defineProperties(Constructor.prototype, protoProps); | |||
if (staticProps) _defineProperties(Constructor, staticProps); | |||
return Constructor; | |||
} | |||
function _defineProperty(obj, key, value) { | |||
if (key in obj) { | |||
Object.defineProperty(obj, key, { | |||
value: value, | |||
enumerable: true, | |||
configurable: true, | |||
writable: true | |||
}); | |||
} else { | |||
obj[key] = value; | |||
} | |||
return obj; | |||
} | |||
function ownKeys(object, enumerableOnly) { | |||
var keys = Object.keys(object); | |||
if (Object.getOwnPropertySymbols) { | |||
var symbols = Object.getOwnPropertySymbols(object); | |||
if (enumerableOnly) symbols = symbols.filter(function (sym) { | |||
return Object.getOwnPropertyDescriptor(object, sym).enumerable; | |||
}); | |||
keys.push.apply(keys, symbols); | |||
} | |||
return keys; | |||
} | |||
function _objectSpread2(target) { | |||
for (var i = 1; i < arguments.length; i++) { | |||
var source = arguments[i] != null ? arguments[i] : {}; | |||
if (i % 2) { | |||
ownKeys(Object(source), true).forEach(function (key) { | |||
_defineProperty(target, key, source[key]); | |||
}); | |||
} else if (Object.getOwnPropertyDescriptors) { | |||
Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); | |||
} else { | |||
ownKeys(Object(source)).forEach(function (key) { | |||
Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); | |||
}); | |||
} | |||
} | |||
return target; | |||
} | |||
/** | |||
* ------------------------------------------------------------------------ | |||
* Constants | |||
* ------------------------------------------------------------------------ | |||
*/ | |||
var NAME = 'dropdown'; | |||
var VERSION = '4.4.1'; | |||
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, | |||
HIDDEN: "hidden" + EVENT_KEY, | |||
SHOW: "show" + EVENT_KEY, | |||
SHOWN: "shown" + EVENT_KEY, | |||
CLICK: "click" + EVENT_KEY, | |||
CLICK_DATA_API: "click" + 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 = { | |||
DISABLED: 'disabled', | |||
SHOW: 'show', | |||
DROPUP: 'dropup', | |||
DROPRIGHT: 'dropright', | |||
DROPLEFT: 'dropleft', | |||
MENURIGHT: 'dropdown-menu-right', | |||
MENULEFT: 'dropdown-menu-left', | |||
POSITION_STATIC: 'position-static' | |||
}; | |||
var Selector = { | |||
DATA_TOGGLE: '[data-toggle="dropdown"]', | |||
FORM_CHILD: '.dropdown form', | |||
MENU: '.dropdown-menu', | |||
NAVBAR_NAV: '.navbar-nav', | |||
VISIBLE_ITEMS: '.dropdown-menu .dropdown-item:not(.disabled):not(:disabled)' | |||
}; | |||
var AttachmentMap = { | |||
TOP: 'top-start', | |||
TOPEND: 'top-end', | |||
BOTTOM: 'bottom-start', | |||
BOTTOMEND: 'bottom-end', | |||
RIGHT: 'right-start', | |||
RIGHTEND: 'right-end', | |||
LEFT: 'left-start', | |||
LEFTEND: 'left-end' | |||
}; | |||
var Default = { | |||
offset: 0, | |||
flip: true, | |||
boundary: 'scrollParent', | |||
reference: 'toggle', | |||
display: 'dynamic', | |||
popperConfig: null | |||
}; | |||
var DefaultType = { | |||
offset: '(number|string|function)', | |||
flip: 'boolean', | |||
boundary: '(string|element)', | |||
reference: '(string|element)', | |||
display: 'string', | |||
popperConfig: '(null|object)' | |||
}; | |||
/** | |||
* ------------------------------------------------------------------------ | |||
* Class Definition | |||
* ------------------------------------------------------------------------ | |||
*/ | |||
var Dropdown = | |||
/*#__PURE__*/ | |||
function () { | |||
function Dropdown(element, config) { | |||
this._element = element; | |||
this._popper = null; | |||
this._config = this._getConfig(config); | |||
this._menu = this._getMenuElement(); | |||
this._inNavbar = this._detectNavbar(); | |||
this._addEventListeners(); | |||
} // Getters | |||
var _proto = Dropdown.prototype; | |||
// Public | |||
_proto.toggle = function toggle() { | |||
if (this._element.disabled || $(this._element).hasClass(ClassName.DISABLED)) { | |||
return; | |||
} | |||
var isActive = $(this._menu).hasClass(ClassName.SHOW); | |||
Dropdown._clearMenus(); | |||
if (isActive) { | |||
return; | |||
} | |||
this.show(true); | |||
}; | |||
_proto.show = function show(usePopper) { | |||
if (usePopper === void 0) { | |||
usePopper = false; | |||
} | |||
if (this._element.disabled || $(this._element).hasClass(ClassName.DISABLED) || $(this._menu).hasClass(ClassName.SHOW)) { | |||
return; | |||
} | |||
var relatedTarget = { | |||
relatedTarget: this._element | |||
}; | |||
var showEvent = $.Event(Event.SHOW, relatedTarget); | |||
var parent = Dropdown._getParentFromElement(this._element); | |||
$(parent).trigger(showEvent); | |||
if (showEvent.isDefaultPrevented()) { | |||
return; | |||
} // Disable totally Popper.js for Dropdown in Navbar | |||
if (!this._inNavbar && usePopper) { | |||
/** | |||
* Check for Popper dependency | |||
* Popper - https://popper.js.org | |||
*/ | |||
if (typeof Popper === 'undefined') { | |||
throw new TypeError('Bootstrap\'s dropdowns require Popper.js (https://popper.js.org/)'); | |||
} | |||
var referenceElement = this._element; | |||
if (this._config.reference === 'parent') { | |||
referenceElement = parent; | |||
} else if (Util.isElement(this._config.reference)) { | |||
referenceElement = this._config.reference; // Check if it's jQuery element | |||
if (typeof this._config.reference.jquery !== 'undefined') { | |||
referenceElement = this._config.reference[0]; | |||
} | |||
} // If boundary is not `scrollParent`, then set position to `static` | |||
// to allow the menu to "escape" the scroll parent's boundaries | |||
// https://github.com/twbs/bootstrap/issues/24251 | |||
if (this._config.boundary !== 'scrollParent') { | |||
$(parent).addClass(ClassName.POSITION_STATIC); | |||
} | |||
this._popper = new Popper(referenceElement, this._menu, this._getPopperConfig()); | |||
} // 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 === 0) { | |||
$(document.body).children().on('mouseover', null, $.noop); | |||
} | |||
this._element.focus(); | |||
this._element.setAttribute('aria-expanded', true); | |||
$(this._menu).toggleClass(ClassName.SHOW); | |||
$(parent).toggleClass(ClassName.SHOW).trigger($.Event(Event.SHOWN, relatedTarget)); | |||
}; | |||
_proto.hide = function hide() { | |||
if (this._element.disabled || $(this._element).hasClass(ClassName.DISABLED) || !$(this._menu).hasClass(ClassName.SHOW)) { | |||
return; | |||
} | |||
var relatedTarget = { | |||
relatedTarget: this._element | |||
}; | |||
var hideEvent = $.Event(Event.HIDE, relatedTarget); | |||
var parent = Dropdown._getParentFromElement(this._element); | |||
$(parent).trigger(hideEvent); | |||
if (hideEvent.isDefaultPrevented()) { | |||
return; | |||
} | |||
if (this._popper) { | |||
this._popper.destroy(); | |||
} | |||
$(this._menu).toggleClass(ClassName.SHOW); | |||
$(parent).toggleClass(ClassName.SHOW).trigger($.Event(Event.HIDDEN, relatedTarget)); | |||
}; | |||
_proto.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; | |||
} | |||
}; | |||
_proto.update = function update() { | |||
this._inNavbar = this._detectNavbar(); | |||
if (this._popper !== null) { | |||
this._popper.scheduleUpdate(); | |||
} | |||
} // Private | |||
; | |||
_proto._addEventListeners = function _addEventListeners() { | |||
var _this = this; | |||
$(this._element).on(Event.CLICK, function (event) { | |||
event.preventDefault(); | |||
event.stopPropagation(); | |||
_this.toggle(); | |||
}); | |||
}; | |||
_proto._getConfig = function _getConfig(config) { | |||
config = _objectSpread2({}, this.constructor.Default, {}, $(this._element).data(), {}, config); | |||
Util.typeCheckConfig(NAME, config, this.constructor.DefaultType); | |||
return config; | |||
}; | |||
_proto._getMenuElement = function _getMenuElement() { | |||
if (!this._menu) { | |||
var parent = Dropdown._getParentFromElement(this._element); | |||
if (parent) { | |||
this._menu = parent.querySelector(Selector.MENU); | |||
} | |||
} | |||
return this._menu; | |||
}; | |||
_proto._getPlacement = function _getPlacement() { | |||
var $parentDropdown = $(this._element.parentNode); | |||
var placement = AttachmentMap.BOTTOM; // Handle dropup | |||
if ($parentDropdown.hasClass(ClassName.DROPUP)) { | |||
placement = AttachmentMap.TOP; | |||
if ($(this._menu).hasClass(ClassName.MENURIGHT)) { | |||
placement = AttachmentMap.TOPEND; | |||
} | |||
} else if ($parentDropdown.hasClass(ClassName.DROPRIGHT)) { | |||
placement = AttachmentMap.RIGHT; | |||
} else if ($parentDropdown.hasClass(ClassName.DROPLEFT)) { | |||
placement = AttachmentMap.LEFT; | |||
} else if ($(this._menu).hasClass(ClassName.MENURIGHT)) { | |||
placement = AttachmentMap.BOTTOMEND; | |||
} | |||
return placement; | |||
}; | |||
_proto._detectNavbar = function _detectNavbar() { | |||
return $(this._element).closest('.navbar').length > 0; | |||
}; | |||
_proto._getOffset = function _getOffset() { | |||
var _this2 = this; | |||
var offset = {}; | |||
if (typeof this._config.offset === 'function') { | |||
offset.fn = function (data) { | |||
data.offsets = _objectSpread2({}, data.offsets, {}, _this2._config.offset(data.offsets, _this2._element) || {}); | |||
return data; | |||
}; | |||
} else { | |||
offset.offset = this._config.offset; | |||
} | |||
return offset; | |||
}; | |||
_proto._getPopperConfig = function _getPopperConfig() { | |||
var popperConfig = { | |||
placement: this._getPlacement(), | |||
modifiers: { | |||
offset: this._getOffset(), | |||
flip: { | |||
enabled: this._config.flip | |||
}, | |||
preventOverflow: { | |||
boundariesElement: this._config.boundary | |||
} | |||
} | |||
}; // Disable Popper.js if we have a static display | |||
if (this._config.display === 'static') { | |||
popperConfig.modifiers.applyStyle = { | |||
enabled: false | |||
}; | |||
} | |||
return _objectSpread2({}, popperConfig, {}, this._config.popperConfig); | |||
} // Static | |||
; | |||
Dropdown._jQueryInterface = function _jQueryInterface(config) { | |||
return this.each(function () { | |||
var data = $(this).data(DATA_KEY); | |||
var _config = typeof config === 'object' ? config : null; | |||
if (!data) { | |||
data = new Dropdown(this, _config); | |||
$(this).data(DATA_KEY, data); | |||
} | |||
if (typeof config === 'string') { | |||
if (typeof data[config] === 'undefined') { | |||
throw new TypeError("No method named \"" + config + "\""); | |||
} | |||
data[config](); | |||
} | |||
}); | |||
}; | |||
Dropdown._clearMenus = function _clearMenus(event) { | |||
if (event && (event.which === RIGHT_MOUSE_BUTTON_WHICH || event.type === 'keyup' && event.which !== TAB_KEYCODE)) { | |||
return; | |||
} | |||
var toggles = [].slice.call(document.querySelectorAll(Selector.DATA_TOGGLE)); | |||
for (var i = 0, len = toggles.length; i < len; i++) { | |||
var parent = Dropdown._getParentFromElement(toggles[i]); | |||
var context = $(toggles[i]).data(DATA_KEY); | |||
var relatedTarget = { | |||
relatedTarget: toggles[i] | |||
}; | |||
if (event && event.type === 'click') { | |||
relatedTarget.clickEvent = event; | |||
} | |||
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 === 'keyup' && event.which === TAB_KEYCODE) && $.contains(parent, event.target)) { | |||
continue; | |||
} | |||
var hideEvent = $.Event(Event.HIDE, relatedTarget); | |||
$(parent).trigger(hideEvent); | |||
if (hideEvent.isDefaultPrevented()) { | |||
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) { | |||
$(document.body).children().off('mouseover', null, $.noop); | |||
} | |||
toggles[i].setAttribute('aria-expanded', 'false'); | |||
if (context._popper) { | |||
context._popper.destroy(); | |||
} | |||
$(dropdownMenu).removeClass(ClassName.SHOW); | |||
$(parent).removeClass(ClassName.SHOW).trigger($.Event(Event.HIDDEN, relatedTarget)); | |||
} | |||
}; | |||
Dropdown._getParentFromElement = function _getParentFromElement(element) { | |||
var parent; | |||
var selector = Util.getSelectorFromElement(element); | |||
if (selector) { | |||
parent = document.querySelector(selector); | |||
} | |||
return parent || element.parentNode; | |||
} // eslint-disable-next-line complexity | |||
; | |||
Dropdown._dataApiKeydownHandler = function _dataApiKeydownHandler(event) { | |||
// If not input/textarea: | |||
// - And not a key in REGEXP_KEYDOWN => not a dropdown command | |||
// If input/textarea: | |||
// - If space key => not a dropdown command | |||
// - If key is other than escape | |||
// - If key is not up or down => not a dropdown command | |||
// - If trigger inside the menu => not a dropdown command | |||
if (/input|textarea/i.test(event.target.tagName) ? event.which === SPACE_KEYCODE || event.which !== ESCAPE_KEYCODE && (event.which !== ARROW_DOWN_KEYCODE && event.which !== ARROW_UP_KEYCODE || $(event.target).closest(Selector.MENU).length) : !REGEXP_KEYDOWN.test(event.which)) { | |||
return; | |||
} | |||
event.preventDefault(); | |||
event.stopPropagation(); | |||
if (this.disabled || $(this).hasClass(ClassName.DISABLED)) { | |||
return; | |||
} | |||
var parent = Dropdown._getParentFromElement(this); | |||
var isActive = $(parent).hasClass(ClassName.SHOW); | |||
if (!isActive && event.which === ESCAPE_KEYCODE) { | |||
return; | |||
} | |||
if (!isActive || isActive && (event.which === ESCAPE_KEYCODE || event.which === SPACE_KEYCODE)) { | |||
if (event.which === ESCAPE_KEYCODE) { | |||
var toggle = parent.querySelector(Selector.DATA_TOGGLE); | |||
$(toggle).trigger('focus'); | |||
} | |||
$(this).trigger('click'); | |||
return; | |||
} | |||
var items = [].slice.call(parent.querySelectorAll(Selector.VISIBLE_ITEMS)).filter(function (item) { | |||
return $(item).is(':visible'); | |||
}); | |||
if (items.length === 0) { | |||
return; | |||
} | |||
var index = items.indexOf(event.target); | |||
if (event.which === ARROW_UP_KEYCODE && index > 0) { | |||
// Up | |||
index--; | |||
} | |||
if (event.which === ARROW_DOWN_KEYCODE && index < items.length - 1) { | |||
// Down | |||
index++; | |||
} | |||
if (index < 0) { | |||
index = 0; | |||
} | |||
items[index].focus(); | |||
}; | |||
_createClass(Dropdown, null, [{ | |||
key: "VERSION", | |||
get: function get() { | |||
return VERSION; | |||
} | |||
}, { | |||
key: "Default", | |||
get: function get() { | |||
return Default; | |||
} | |||
}, { | |||
key: "DefaultType", | |||
get: function get() { | |||
return DefaultType; | |||
} | |||
}]); | |||
return Dropdown; | |||
}(); | |||
/** | |||
* ------------------------------------------------------------------------ | |||
* Data Api implementation | |||
* ------------------------------------------------------------------------ | |||
*/ | |||
$(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(); | |||
}); | |||
/** | |||
* ------------------------------------------------------------------------ | |||
* jQuery | |||
* ------------------------------------------------------------------------ | |||
*/ | |||
$.fn[NAME] = Dropdown._jQueryInterface; | |||
$.fn[NAME].Constructor = Dropdown; | |||
$.fn[NAME].noConflict = function () { | |||
$.fn[NAME] = JQUERY_NO_CONFLICT; | |||
return Dropdown._jQueryInterface; | |||
}; | |||
return Dropdown; | |||
}))); | |||
//# sourceMappingURL=dropdown.js.map |
@ -0,0 +1,23 @@ | |||
/** | |||
* -------------------------------------------------------------------------- | |||
* Bootstrap (v4.4.0): index.js | |||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) | |||
* -------------------------------------------------------------------------- | |||
*/ | |||
(function ($) { | |||
if (typeof $ === 'undefined') { | |||
throw new TypeError('Bootstrap\'s JavaScript requires jQuery. jQuery must be included before Bootstrap\'s JavaScript.'); | |||
} | |||
var version = $.fn.jquery.split(' ')[0].split('.'); | |||
var minMajor = 1; | |||
var ltMajor = 2; | |||
var minMinor = 9; | |||
var minPatch = 1; | |||
var maxMajor = 4; | |||
if (version[0] < ltMajor && version[1] < minMinor || version[0] === minMajor && version[1] === minMinor && version[2] < minPatch || version[0] >= maxMajor) { | |||
throw new Error('Bootstrap\'s JavaScript requires at least jQuery v1.9.1 but less than v4.0.0'); | |||
} | |||
})($); | |||
//# sourceMappingURL=index.js.map |
@ -0,0 +1 @@ | |||
{"version":3,"sources":["../src/index.js"],"names":["$","TypeError","version","fn","jquery","split","minMajor","ltMajor","minMinor","minPatch","maxMajor","Error"],"mappings":"AAaA;;;;;;AAOA,CAAC,UAACA,CAAD,EAAO;AACN,MAAI,OAAOA,CAAP,KAAa,WAAjB,EAA8B;AAC5B,UAAM,IAAIC,SAAJ,CAAc,kGAAd,CAAN;AACD;;AAED,MAAMC,UAAUF,EAAEG,EAAF,CAAKC,MAAL,CAAYC,KAAZ,CAAkB,GAAlB,EAAuB,CAAvB,EAA0BA,KAA1B,CAAgC,GAAhC,CAAhB;AACA,MAAMC,WAAW,CAAjB;AACA,MAAMC,UAAU,CAAhB;AACA,MAAMC,WAAW,CAAjB;AACA,MAAMC,WAAW,CAAjB;AACA,MAAMC,WAAW,CAAjB;;AAEA,MAAIR,QAAQ,CAAR,IAAaK,OAAb,IAAwBL,QAAQ,CAAR,IAAaM,QAArC,IAAiDN,QAAQ,CAAR,MAAeI,QAAf,IAA2BJ,QAAQ,CAAR,MAAeM,QAA1C,IAAsDN,QAAQ,CAAR,IAAaO,QAApH,IAAgIP,QAAQ,CAAR,KAAcQ,QAAlJ,EAA4J;AAC1J,UAAM,IAAIC,KAAJ,CAAU,8EAAV,CAAN;AACD;AACF,CAfD,EAeGX,CAfH","sourcesContent":["import $ from 'jquery'\nimport Alert from './alert'\nimport Button from './button'\nimport Carousel from './carousel'\nimport Collapse from './collapse'\nimport Dropdown from './dropdown'\nimport Modal from './modal'\nimport Popover from './popover'\nimport Scrollspy from './scrollspy'\nimport Tab from './tab'\nimport Tooltip from './tooltip'\nimport Util from './util'\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap (v4.1.2): index.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n(($) => {\n if (typeof $ === 'undefined') {\n throw new TypeError('Bootstrap\\'s JavaScript requires jQuery. jQuery must be included before Bootstrap\\'s JavaScript.')\n }\n\n const version = $.fn.jquery.split(' ')[0].split('.')\n const minMajor = 1\n const ltMajor = 2\n const minMinor = 9\n const minPatch = 1\n const maxMajor = 4\n\n if (version[0] < ltMajor && version[1] < minMinor || version[0] === minMajor && version[1] === minMinor && version[2] < minPatch || version[0] >= maxMajor) {\n throw new Error('Bootstrap\\'s JavaScript requires at least jQuery v1.9.1 but less than v4.0.0')\n }\n})($)\n\nexport {\n Util,\n Alert,\n Button,\n Carousel,\n Collapse,\n Dropdown,\n Modal,\n Popover,\n Scrollspy,\n Tab,\n Tooltip\n}\n"],"file":"index.js"} |
@ -0,0 +1,685 @@ | |||
/*! | |||
* Bootstrap modal.js v4.4.1 (https://getbootstrap.com/) | |||
* Copyright 2011-2019 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors) | |||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) | |||
*/ | |||
(function (global, factory) { | |||
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('jquery'), require('./util.js')) : | |||
typeof define === 'function' && define.amd ? define(['jquery', './util.js'], factory) : | |||
(global = global || self, global.Modal = factory(global.jQuery, global.Util)); | |||
}(this, (function ($, Util) { 'use strict'; | |||
$ = $ && $.hasOwnProperty('default') ? $['default'] : $; | |||
Util = Util && Util.hasOwnProperty('default') ? Util['default'] : Util; | |||
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); | |||
} | |||
} | |||
function _createClass(Constructor, protoProps, staticProps) { | |||
if (protoProps) _defineProperties(Constructor.prototype, protoProps); | |||
if (staticProps) _defineProperties(Constructor, staticProps); | |||
return Constructor; | |||
} | |||
function _defineProperty(obj, key, value) { | |||
if (key in obj) { | |||
Object.defineProperty(obj, key, { | |||
value: value, | |||
enumerable: true, | |||
configurable: true, | |||
writable: true | |||
}); | |||
} else { | |||
obj[key] = value; | |||
} | |||
return obj; | |||
} | |||
function ownKeys(object, enumerableOnly) { | |||
var keys = Object.keys(object); | |||
if (Object.getOwnPropertySymbols) { | |||
var symbols = Object.getOwnPropertySymbols(object); | |||
if (enumerableOnly) symbols = symbols.filter(function (sym) { | |||
return Object.getOwnPropertyDescriptor(object, sym).enumerable; | |||
}); | |||
keys.push.apply(keys, symbols); | |||
} | |||
return keys; | |||
} | |||
function _objectSpread2(target) { | |||
for (var i = 1; i < arguments.length; i++) { | |||
var source = arguments[i] != null ? arguments[i] : {}; | |||
if (i % 2) { | |||
ownKeys(Object(source), true).forEach(function (key) { | |||
_defineProperty(target, key, source[key]); | |||
}); | |||
} else if (Object.getOwnPropertyDescriptors) { | |||
Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); | |||
} else { | |||
ownKeys(Object(source)).forEach(function (key) { | |||
Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); | |||
}); | |||
} | |||
} | |||
return target; | |||
} | |||
/** | |||
* ------------------------------------------------------------------------ | |||
* Constants | |||
* ------------------------------------------------------------------------ | |||
*/ | |||
var NAME = 'modal'; | |||
var VERSION = '4.4.1'; | |||
var DATA_KEY = 'bs.modal'; | |||
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 Default = { | |||
backdrop: true, | |||
keyboard: true, | |||
focus: true, | |||
show: true | |||
}; | |||
var DefaultType = { | |||
backdrop: '(boolean|string)', | |||
keyboard: 'boolean', | |||
focus: 'boolean', | |||
show: 'boolean' | |||
}; | |||
var Event = { | |||
HIDE: "hide" + EVENT_KEY, | |||
HIDE_PREVENTED: "hidePrevented" + EVENT_KEY, | |||
HIDDEN: "hidden" + EVENT_KEY, | |||
SHOW: "show" + EVENT_KEY, | |||
SHOWN: "shown" + EVENT_KEY, | |||
FOCUSIN: "focusin" + EVENT_KEY, | |||
RESIZE: "resize" + EVENT_KEY, | |||
CLICK_DISMISS: "click.dismiss" + EVENT_KEY, | |||
KEYDOWN_DISMISS: "keydown.dismiss" + EVENT_KEY, | |||
MOUSEUP_DISMISS: "mouseup.dismiss" + EVENT_KEY, | |||
MOUSEDOWN_DISMISS: "mousedown.dismiss" + EVENT_KEY, | |||
CLICK_DATA_API: "click" + EVENT_KEY + DATA_API_KEY | |||
}; | |||
var ClassName = { | |||
SCROLLABLE: 'modal-dialog-scrollable', | |||
SCROLLBAR_MEASURER: 'modal-scrollbar-measure', | |||
BACKDROP: 'modal-backdrop', | |||
OPEN: 'modal-open', | |||
FADE: 'fade', | |||
SHOW: 'show', | |||
STATIC: 'modal-static' | |||
}; | |||
var Selector = { | |||
DIALOG: '.modal-dialog', | |||
MODAL_BODY: '.modal-body', | |||
DATA_TOGGLE: '[data-toggle="modal"]', | |||
DATA_DISMISS: '[data-dismiss="modal"]', | |||
FIXED_CONTENT: '.fixed-top, .fixed-bottom, .is-fixed, .sticky-top', | |||
STICKY_CONTENT: '.sticky-top' | |||
}; | |||
/** | |||
* ------------------------------------------------------------------------ | |||
* Class Definition | |||
* ------------------------------------------------------------------------ | |||
*/ | |||
var Modal = | |||
/*#__PURE__*/ | |||
function () { | |||
function Modal(element, config) { | |||
this._config = this._getConfig(config); | |||
this._element = element; | |||
this._dialog = element.querySelector(Selector.DIALOG); | |||
this._backdrop = null; | |||
this._isShown = false; | |||
this._isBodyOverflowing = false; | |||
this._ignoreBackdropClick = false; | |||
this._isTransitioning = false; | |||
this._scrollbarWidth = 0; | |||
} // Getters | |||
var _proto = Modal.prototype; | |||
// Public | |||
_proto.toggle = function toggle(relatedTarget) { | |||
return this._isShown ? this.hide() : this.show(relatedTarget); | |||
}; | |||
_proto.show = function show(relatedTarget) { | |||
var _this = this; | |||
if (this._isShown || this._isTransitioning) { | |||
return; | |||
} | |||
if ($(this._element).hasClass(ClassName.FADE)) { | |||
this._isTransitioning = true; | |||
} | |||
var showEvent = $.Event(Event.SHOW, { | |||
relatedTarget: relatedTarget | |||
}); | |||
$(this._element).trigger(showEvent); | |||
if (this._isShown || showEvent.isDefaultPrevented()) { | |||
return; | |||
} | |||
this._isShown = true; | |||
this._checkScrollbar(); | |||
this._setScrollbar(); | |||
this._adjustDialog(); | |||
this._setEscapeEvent(); | |||
this._setResizeEvent(); | |||
$(this._element).on(Event.CLICK_DISMISS, Selector.DATA_DISMISS, function (event) { | |||
return _this.hide(event); | |||
}); | |||
$(this._dialog).on(Event.MOUSEDOWN_DISMISS, function () { | |||
$(_this._element).one(Event.MOUSEUP_DISMISS, function (event) { | |||
if ($(event.target).is(_this._element)) { | |||
_this._ignoreBackdropClick = true; | |||
} | |||
}); | |||
}); | |||
this._showBackdrop(function () { | |||
return _this._showElement(relatedTarget); | |||
}); | |||
}; | |||
_proto.hide = function hide(event) { | |||
var _this2 = this; | |||
if (event) { | |||
event.preventDefault(); | |||
} | |||
if (!this._isShown || this._isTransitioning) { | |||
return; | |||
} | |||
var hideEvent = $.Event(Event.HIDE); | |||
$(this._element).trigger(hideEvent); | |||
if (!this._isShown || hideEvent.isDefaultPrevented()) { | |||
return; | |||
} | |||
this._isShown = false; | |||
var transition = $(this._element).hasClass(ClassName.FADE); | |||
if (transition) { | |||
this._isTransitioning = true; | |||
} | |||
this._setEscapeEvent(); | |||
this._setResizeEvent(); | |||
$(document).off(Event.FOCUSIN); | |||
$(this._element).removeClass(ClassName.SHOW); | |||
$(this._element).off(Event.CLICK_DISMISS); | |||
$(this._dialog).off(Event.MOUSEDOWN_DISMISS); | |||
if (transition) { | |||
var transitionDuration = Util.getTransitionDurationFromElement(this._element); | |||
$(this._element).one(Util.TRANSITION_END, function (event) { | |||
return _this2._hideModal(event); | |||
}).emulateTransitionEnd(transitionDuration); | |||
} else { | |||
this._hideModal(); | |||
} | |||
}; | |||
_proto.dispose = function dispose() { | |||
[window, this._element, this._dialog].forEach(function (htmlElement) { | |||
return $(htmlElement).off(EVENT_KEY); | |||
}); | |||
/** | |||
* `document` has 2 events `Event.FOCUSIN` and `Event.CLICK_DATA_API` | |||
* Do not move `document` in `htmlElements` array | |||
* It will remove `Event.CLICK_DATA_API` event that should remain | |||
*/ | |||
$(document).off(Event.FOCUSIN); | |||
$.removeData(this._element, DATA_KEY); | |||
this._config = null; | |||
this._element = null; | |||
this._dialog = null; | |||
this._backdrop = null; | |||
this._isShown = null; | |||
this._isBodyOverflowing = null; | |||
this._ignoreBackdropClick = null; | |||
this._isTransitioning = null; | |||
this._scrollbarWidth = null; | |||
}; | |||
_proto.handleUpdate = function handleUpdate() { | |||
this._adjustDialog(); | |||
} // Private | |||
; | |||
_proto._getConfig = function _getConfig(config) { | |||
config = _objectSpread2({}, Default, {}, config); | |||
Util.typeCheckConfig(NAME, config, DefaultType); | |||
return config; | |||
}; | |||
_proto._triggerBackdropTransition = function _triggerBackdropTransition() { | |||
var _this3 = this; | |||
if (this._config.backdrop === 'static') { | |||
var hideEventPrevented = $.Event(Event.HIDE_PREVENTED); | |||
$(this._element).trigger(hideEventPrevented); | |||
if (hideEventPrevented.defaultPrevented) { | |||
return; | |||
} | |||
this._element.classList.add(ClassName.STATIC); | |||
var modalTransitionDuration = Util.getTransitionDurationFromElement(this._element); | |||
$(this._element).one(Util.TRANSITION_END, function () { | |||
_this3._element.classList.remove(ClassName.STATIC); | |||
}).emulateTransitionEnd(modalTransitionDuration); | |||
this._element.focus(); | |||
} else { | |||
this.hide(); | |||
} | |||
}; | |||
_proto._showElement = function _showElement(relatedTarget) { | |||
var _this4 = this; | |||
var transition = $(this._element).hasClass(ClassName.FADE); | |||
var modalBody = this._dialog ? this._dialog.querySelector(Selector.MODAL_BODY) : null; | |||
if (!this._element.parentNode || this._element.parentNode.nodeType !== Node.ELEMENT_NODE) { | |||
// Don't move modal's DOM position | |||
document.body.appendChild(this._element); | |||
} | |||
this._element.style.display = 'block'; | |||
this._element.removeAttribute('aria-hidden'); | |||
this._element.setAttribute('aria-modal', true); | |||
if ($(this._dialog).hasClass(ClassName.SCROLLABLE) && modalBody) { | |||
modalBody.scrollTop = 0; | |||
} else { | |||
this._element.scrollTop = 0; | |||
} | |||
if (transition) { | |||
Util.reflow(this._element); | |||
} | |||
$(this._element).addClass(ClassName.SHOW); | |||
if (this._config.focus) { | |||
this._enforceFocus(); | |||
} | |||
var shownEvent = $.Event(Event.SHOWN, { | |||
relatedTarget: relatedTarget | |||
}); | |||
var transitionComplete = function transitionComplete() { | |||
if (_this4._config.focus) { | |||
_this4._element.focus(); | |||
} | |||
_this4._isTransitioning = false; | |||
$(_this4._element).trigger(shownEvent); | |||
}; | |||
if (transition) { | |||
var transitionDuration = Util.getTransitionDurationFromElement(this._dialog); | |||
$(this._dialog).one(Util.TRANSITION_END, transitionComplete).emulateTransitionEnd(transitionDuration); | |||
} else { | |||
transitionComplete(); | |||
} | |||
}; | |||
_proto._enforceFocus = function _enforceFocus() { | |||
var _this5 = this; | |||
$(document).off(Event.FOCUSIN) // Guard against infinite focus loop | |||
.on(Event.FOCUSIN, function (event) { | |||
if (document !== event.target && _this5._element !== event.target && $(_this5._element).has(event.target).length === 0) { | |||
_this5._element.focus(); | |||
} | |||
}); | |||
}; | |||
_proto._setEscapeEvent = function _setEscapeEvent() { | |||
var _this6 = this; | |||
if (this._isShown && this._config.keyboard) { | |||
$(this._element).on(Event.KEYDOWN_DISMISS, function (event) { | |||
if (event.which === ESCAPE_KEYCODE) { | |||
_this6._triggerBackdropTransition(); | |||
} | |||
}); | |||
} else if (!this._isShown) { | |||
$(this._element).off(Event.KEYDOWN_DISMISS); | |||
} | |||
}; | |||
_proto._setResizeEvent = function _setResizeEvent() { | |||
var _this7 = this; | |||
if (this._isShown) { | |||
$(window).on(Event.RESIZE, function (event) { | |||
return _this7.handleUpdate(event); | |||
}); | |||
} else { | |||
$(window).off(Event.RESIZE); | |||
} | |||
}; | |||
_proto._hideModal = function _hideModal() { | |||
var _this8 = this; | |||
this._element.style.display = 'none'; | |||
this._element.setAttribute('aria-hidden', true); | |||
this._element.removeAttribute('aria-modal'); | |||
this._isTransitioning = false; | |||
this._showBackdrop(function () { | |||
$(document.body).removeClass(ClassName.OPEN); | |||
_this8._resetAdjustments(); | |||
_this8._resetScrollbar(); | |||
$(_this8._element).trigger(Event.HIDDEN); | |||
}); | |||
}; | |||
_proto._removeBackdrop = function _removeBackdrop() { | |||
if (this._backdrop) { | |||
$(this._backdrop).remove(); | |||
this._backdrop = null; | |||
} | |||
}; | |||
_proto._showBackdrop = function _showBackdrop(callback) { | |||
var _this9 = this; | |||
var animate = $(this._element).hasClass(ClassName.FADE) ? ClassName.FADE : ''; | |||
if (this._isShown && this._config.backdrop) { | |||
this._backdrop = document.createElement('div'); | |||
this._backdrop.className = ClassName.BACKDROP; | |||
if (animate) { | |||
this._backdrop.classList.add(animate); | |||
} | |||
$(this._backdrop).appendTo(document.body); | |||
$(this._element).on(Event.CLICK_DISMISS, function (event) { | |||
if (_this9._ignoreBackdropClick) { | |||
_this9._ignoreBackdropClick = false; | |||
return; | |||
} | |||
if (event.target !== event.currentTarget) { | |||
return; | |||
} | |||
_this9._triggerBackdropTransition(); | |||
}); | |||
if (animate) { | |||
Util.reflow(this._backdrop); | |||
} | |||
$(this._backdrop).addClass(ClassName.SHOW); | |||
if (!callback) { | |||
return; | |||
} | |||
if (!animate) { | |||
callback(); | |||
return; | |||
} | |||
var backdropTransitionDuration = Util.getTransitionDurationFromElement(this._backdrop); | |||
$(this._backdrop).one(Util.TRANSITION_END, callback).emulateTransitionEnd(backdropTransitionDuration); | |||
} else if (!this._isShown && this._backdrop) { | |||
$(this._backdrop).removeClass(ClassName.SHOW); | |||
var callbackRemove = function callbackRemove() { | |||
_this9._removeBackdrop(); | |||
if (callback) { | |||
callback(); | |||
} | |||
}; | |||
if ($(this._element).hasClass(ClassName.FADE)) { | |||
var _backdropTransitionDuration = Util.getTransitionDurationFromElement(this._backdrop); | |||
$(this._backdrop).one(Util.TRANSITION_END, callbackRemove).emulateTransitionEnd(_backdropTransitionDuration); | |||
} else { | |||
callbackRemove(); | |||
} | |||
} else if (callback) { | |||
callback(); | |||
} | |||
} // ---------------------------------------------------------------------- | |||
// the following methods are used to handle overflowing modals | |||
// todo (fat): these should probably be refactored out of modal.js | |||
// ---------------------------------------------------------------------- | |||
; | |||
_proto._adjustDialog = function _adjustDialog() { | |||
var isModalOverflowing = this._element.scrollHeight > document.documentElement.clientHeight; | |||
if (!this._isBodyOverflowing && isModalOverflowing) { | |||
this._element.style.paddingLeft = this._scrollbarWidth + "px"; | |||
} | |||
if (this._isBodyOverflowing && !isModalOverflowing) { | |||
this._element.style.paddingRight = this._scrollbarWidth + "px"; | |||
} | |||
}; | |||
_proto._resetAdjustments = function _resetAdjustments() { | |||
this._element.style.paddingLeft = ''; | |||
this._element.style.paddingRight = ''; | |||
}; | |||
_proto._checkScrollbar = function _checkScrollbar() { | |||
var rect = document.body.getBoundingClientRect(); | |||
this._isBodyOverflowing = rect.left + rect.right < window.innerWidth; | |||
this._scrollbarWidth = this._getScrollbarWidth(); | |||
}; | |||
_proto._setScrollbar = function _setScrollbar() { | |||
var _this10 = this; | |||
if (this._isBodyOverflowing) { | |||
// 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 | |||
var fixedContent = [].slice.call(document.querySelectorAll(Selector.FIXED_CONTENT)); | |||
var stickyContent = [].slice.call(document.querySelectorAll(Selector.STICKY_CONTENT)); // Adjust fixed content padding | |||
$(fixedContent).each(function (index, element) { | |||
var actualPadding = element.style.paddingRight; | |||
var calculatedPadding = $(element).css('padding-right'); | |||
$(element).data('padding-right', actualPadding).css('padding-right', parseFloat(calculatedPadding) + _this10._scrollbarWidth + "px"); | |||
}); // Adjust sticky content margin | |||
$(stickyContent).each(function (index, element) { | |||
var actualMargin = element.style.marginRight; | |||
var calculatedMargin = $(element).css('margin-right'); | |||
$(element).data('margin-right', actualMargin).css('margin-right', parseFloat(calculatedMargin) - _this10._scrollbarWidth + "px"); | |||
}); // Adjust body padding | |||
var actualPadding = document.body.style.paddingRight; | |||
var calculatedPadding = $(document.body).css('padding-right'); | |||
$(document.body).data('padding-right', actualPadding).css('padding-right', parseFloat(calculatedPadding) + this._scrollbarWidth + "px"); | |||
} | |||
$(document.body).addClass(ClassName.OPEN); | |||
}; | |||
_proto._resetScrollbar = function _resetScrollbar() { | |||
// Restore fixed content padding | |||
var fixedContent = [].slice.call(document.querySelectorAll(Selector.FIXED_CONTENT)); | |||
$(fixedContent).each(function (index, element) { | |||
var padding = $(element).data('padding-right'); | |||
$(element).removeData('padding-right'); | |||
element.style.paddingRight = padding ? padding : ''; | |||
}); // Restore sticky content | |||
var elements = [].slice.call(document.querySelectorAll("" + Selector.STICKY_CONTENT)); | |||
$(elements).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 = $(document.body).data('padding-right'); | |||
$(document.body).removeData('padding-right'); | |||
document.body.style.paddingRight = padding ? padding : ''; | |||
}; | |||
_proto._getScrollbarWidth = function _getScrollbarWidth() { | |||
// thx d.walsh | |||
var scrollDiv = document.createElement('div'); | |||
scrollDiv.className = ClassName.SCROLLBAR_MEASURER; | |||
document.body.appendChild(scrollDiv); | |||
var scrollbarWidth = scrollDiv.getBoundingClientRect().width - scrollDiv.clientWidth; | |||
document.body.removeChild(scrollDiv); | |||
return scrollbarWidth; | |||
} // Static | |||
; | |||
Modal._jQueryInterface = function _jQueryInterface(config, relatedTarget) { | |||
return this.each(function () { | |||
var data = $(this).data(DATA_KEY); | |||
var _config = _objectSpread2({}, Default, {}, $(this).data(), {}, typeof config === 'object' && config ? config : {}); | |||
if (!data) { | |||
data = new Modal(this, _config); | |||
$(this).data(DATA_KEY, data); | |||
} | |||
if (typeof config === 'string') { | |||
if (typeof data[config] === 'undefined') { | |||
throw new TypeError("No method named \"" + config + "\""); | |||
} | |||
data[config](relatedTarget); | |||
} else if (_config.show) { | |||
data.show(relatedTarget); | |||
} | |||
}); | |||
}; | |||
_createClass(Modal, null, [{ | |||
key: "VERSION", | |||
get: function get() { | |||
return VERSION; | |||
} | |||
}, { | |||
key: "Default", | |||
get: function get() { | |||
return Default; | |||
} | |||
}]); | |||
return Modal; | |||
}(); | |||
/** | |||
* ------------------------------------------------------------------------ | |||
* Data Api implementation | |||
* ------------------------------------------------------------------------ | |||
*/ | |||
$(document).on(Event.CLICK_DATA_API, Selector.DATA_TOGGLE, function (event) { | |||
var _this11 = this; | |||
var target; | |||
var selector = Util.getSelectorFromElement(this); | |||
if (selector) { | |||
target = document.querySelector(selector); | |||
} | |||
var config = $(target).data(DATA_KEY) ? 'toggle' : _objectSpread2({}, $(target).data(), {}, $(this).data()); | |||
if (this.tagName === 'A' || this.tagName === 'AREA') { | |||
event.preventDefault(); | |||
} | |||
var $target = $(target).one(Event.SHOW, function (showEvent) { | |||
if (showEvent.isDefaultPrevented()) { | |||
// Only register focus restorer if modal will actually get shown | |||
return; | |||
} | |||
$target.one(Event.HIDDEN, function () { | |||
if ($(_this11).is(':visible')) { | |||
_this11.focus(); | |||
} | |||
}); | |||
}); | |||
Modal._jQueryInterface.call($(target), config, this); | |||
}); | |||
/** | |||
* ------------------------------------------------------------------------ | |||
* jQuery | |||
* ------------------------------------------------------------------------ | |||
*/ | |||
$.fn[NAME] = Modal._jQueryInterface; | |||
$.fn[NAME].Constructor = Modal; | |||
$.fn[NAME].noConflict = function () { | |||
$.fn[NAME] = JQUERY_NO_CONFLICT; | |||
return Modal._jQueryInterface; | |||
}; | |||
return Modal; | |||
}))); | |||
//# sourceMappingURL=modal.js.map |
@ -0,0 +1,275 @@ | |||
/*! | |||
* Bootstrap popover.js v4.4.1 (https://getbootstrap.com/) | |||
* Copyright 2011-2019 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors) | |||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) | |||
*/ | |||
(function (global, factory) { | |||
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('jquery'), require('./tooltip.js')) : | |||
typeof define === 'function' && define.amd ? define(['jquery', './tooltip.js'], factory) : | |||
(global = global || self, global.Popover = factory(global.jQuery, global.Tooltip)); | |||
}(this, (function ($, Tooltip) { 'use strict'; | |||
$ = $ && $.hasOwnProperty('default') ? $['default'] : $; | |||
Tooltip = Tooltip && Tooltip.hasOwnProperty('default') ? Tooltip['default'] : Tooltip; | |||
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); | |||
} | |||
} | |||
function _createClass(Constructor, protoProps, staticProps) { | |||
if (protoProps) _defineProperties(Constructor.prototype, protoProps); | |||
if (staticProps) _defineProperties(Constructor, staticProps); | |||
return Constructor; | |||
} | |||
function _defineProperty(obj, key, value) { | |||
if (key in obj) { | |||
Object.defineProperty(obj, key, { | |||
value: value, | |||
enumerable: true, | |||
configurable: true, | |||
writable: true | |||
}); | |||
} else { | |||
obj[key] = value; | |||
} | |||
return obj; | |||
} | |||
function ownKeys(object, enumerableOnly) { | |||
var keys = Object.keys(object); | |||
if (Object.getOwnPropertySymbols) { | |||
var symbols = Object.getOwnPropertySymbols(object); | |||
if (enumerableOnly) symbols = symbols.filter(function (sym) { | |||
return Object.getOwnPropertyDescriptor(object, sym).enumerable; | |||
}); | |||
keys.push.apply(keys, symbols); | |||
} | |||
return keys; | |||
} | |||
function _objectSpread2(target) { | |||
for (var i = 1; i < arguments.length; i++) { | |||
var source = arguments[i] != null ? arguments[i] : {}; | |||
if (i % 2) { | |||
ownKeys(Object(source), true).forEach(function (key) { | |||
_defineProperty(target, key, source[key]); | |||
}); | |||
} else if (Object.getOwnPropertyDescriptors) { | |||
Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); | |||
} else { | |||
ownKeys(Object(source)).forEach(function (key) { | |||
Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); | |||
}); | |||
} | |||
} | |||
return target; | |||
} | |||
function _inheritsLoose(subClass, superClass) { | |||
subClass.prototype = Object.create(superClass.prototype); | |||
subClass.prototype.constructor = subClass; | |||
subClass.__proto__ = superClass; | |||
} | |||
/** | |||
* ------------------------------------------------------------------------ | |||
* Constants | |||
* ------------------------------------------------------------------------ | |||
*/ | |||
var NAME = 'popover'; | |||
var VERSION = '4.4.1'; | |||
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 = _objectSpread2({}, Tooltip.Default, { | |||
placement: 'right', | |||
trigger: 'click', | |||
content: '', | |||
template: '<div class="popover" role="tooltip">' + '<div class="arrow"></div>' + '<h3 class="popover-header"></h3>' + '<div class="popover-body"></div></div>' | |||
}); | |||
var DefaultType = _objectSpread2({}, Tooltip.DefaultType, { | |||
content: '(string|element|function)' | |||
}); | |||
var ClassName = { | |||
FADE: 'fade', | |||
SHOW: 'show' | |||
}; | |||
var Selector = { | |||
TITLE: '.popover-header', | |||
CONTENT: '.popover-body' | |||
}; | |||
var Event = { | |||
HIDE: "hide" + EVENT_KEY, | |||
HIDDEN: "hidden" + EVENT_KEY, | |||
SHOW: "show" + EVENT_KEY, | |||
SHOWN: "shown" + EVENT_KEY, | |||
INSERTED: "inserted" + EVENT_KEY, | |||
CLICK: "click" + EVENT_KEY, | |||
FOCUSIN: "focusin" + EVENT_KEY, | |||
FOCUSOUT: "focusout" + EVENT_KEY, | |||
MOUSEENTER: "mouseenter" + EVENT_KEY, | |||
MOUSELEAVE: "mouseleave" + EVENT_KEY | |||
}; | |||
/** | |||
* ------------------------------------------------------------------------ | |||
* Class Definition | |||
* ------------------------------------------------------------------------ | |||
*/ | |||
var Popover = | |||
/*#__PURE__*/ | |||
function (_Tooltip) { | |||
_inheritsLoose(Popover, _Tooltip); | |||
function Popover() { | |||
return _Tooltip.apply(this, arguments) || this; | |||
} | |||
var _proto = Popover.prototype; | |||
// Overrides | |||
_proto.isWithContent = function isWithContent() { | |||
return this.getTitle() || this._getContent(); | |||
}; | |||
_proto.addAttachmentClass = function addAttachmentClass(attachment) { | |||
$(this.getTipElement()).addClass(CLASS_PREFIX + "-" + attachment); | |||
}; | |||
_proto.getTipElement = function getTipElement() { | |||
this.tip = this.tip || $(this.config.template)[0]; | |||
return this.tip; | |||
}; | |||
_proto.setContent = function setContent() { | |||
var $tip = $(this.getTipElement()); // We use append for html objects to maintain js events | |||
this.setElementContent($tip.find(Selector.TITLE), this.getTitle()); | |||
var content = this._getContent(); | |||
if (typeof content === 'function') { | |||
content = content.call(this.element); | |||
} | |||
this.setElementContent($tip.find(Selector.CONTENT), content); | |||
$tip.removeClass(ClassName.FADE + " " + ClassName.SHOW); | |||
} // Private | |||
; | |||
_proto._getContent = function _getContent() { | |||
return this.element.getAttribute('data-content') || this.config.content; | |||
}; | |||
_proto._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) { | |||
return this.each(function () { | |||
var data = $(this).data(DATA_KEY); | |||
var _config = typeof config === 'object' ? config : null; | |||
if (!data && /dispose|hide/.test(config)) { | |||
return; | |||
} | |||
if (!data) { | |||
data = new Popover(this, _config); | |||
$(this).data(DATA_KEY, data); | |||
} | |||
if (typeof config === 'string') { | |||
if (typeof data[config] === 'undefined') { | |||
throw new TypeError("No method named \"" + config + "\""); | |||
} | |||
data[config](); | |||
} | |||
}); | |||
}; | |||
_createClass(Popover, null, [{ | |||
key: "VERSION", | |||
// Getters | |||
get: function get() { | |||
return VERSION; | |||
} | |||
}, { | |||
key: "Default", | |||
get: function get() { | |||
return Default; | |||
} | |||
}, { | |||
key: "NAME", | |||
get: function get() { | |||
return NAME; | |||
} | |||
}, { | |||
key: "DATA_KEY", | |||
get: function get() { | |||
return DATA_KEY; | |||
} | |||
}, { | |||
key: "Event", | |||
get: function get() { | |||
return Event; | |||
} | |||
}, { | |||
key: "EVENT_KEY", | |||
get: function get() { | |||
return EVENT_KEY; | |||
} | |||
}, { | |||
key: "DefaultType", | |||
get: function get() { | |||
return DefaultType; | |||
} | |||
}]); | |||
return Popover; | |||
}(Tooltip); | |||
/** | |||
* ------------------------------------------------------------------------ | |||
* jQuery | |||
* ------------------------------------------------------------------------ | |||
*/ | |||
$.fn[NAME] = Popover._jQueryInterface; | |||
$.fn[NAME].Constructor = Popover; | |||
$.fn[NAME].noConflict = function () { | |||
$.fn[NAME] = JQUERY_NO_CONFLICT; | |||
return Popover._jQueryInterface; | |||
}; | |||
return Popover; | |||
}))); | |||
//# sourceMappingURL=popover.js.map |
@ -0,0 +1,389 @@ | |||
/*! | |||
* Bootstrap scrollspy.js v4.4.1 (https://getbootstrap.com/) | |||
* Copyright 2011-2019 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors) | |||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) | |||
*/ | |||
(function (global, factory) { | |||
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('jquery'), require('./util.js')) : | |||
typeof define === 'function' && define.amd ? define(['jquery', './util.js'], factory) : | |||
(global = global || self, global.ScrollSpy = factory(global.jQuery, global.Util)); | |||
}(this, (function ($, Util) { 'use strict'; | |||
$ = $ && $.hasOwnProperty('default') ? $['default'] : $; | |||
Util = Util && Util.hasOwnProperty('default') ? Util['default'] : Util; | |||
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); | |||
} | |||
} | |||
function _createClass(Constructor, protoProps, staticProps) { | |||
if (protoProps) _defineProperties(Constructor.prototype, protoProps); | |||
if (staticProps) _defineProperties(Constructor, staticProps); | |||
return Constructor; | |||
} | |||
function _defineProperty(obj, key, value) { | |||
if (key in obj) { | |||
Object.defineProperty(obj, key, { | |||
value: value, | |||
enumerable: true, | |||
configurable: true, | |||
writable: true | |||
}); | |||
} else { | |||
obj[key] = value; | |||
} | |||
return obj; | |||
} | |||
function ownKeys(object, enumerableOnly) { | |||
var keys = Object.keys(object); | |||
if (Object.getOwnPropertySymbols) { | |||
var symbols = Object.getOwnPropertySymbols(object); | |||
if (enumerableOnly) symbols = symbols.filter(function (sym) { | |||
return Object.getOwnPropertyDescriptor(object, sym).enumerable; | |||
}); | |||
keys.push.apply(keys, symbols); | |||
} | |||
return keys; | |||
} | |||
function _objectSpread2(target) { | |||
for (var i = 1; i < arguments.length; i++) { | |||
var source = arguments[i] != null ? arguments[i] : {}; | |||
if (i % 2) { | |||
ownKeys(Object(source), true).forEach(function (key) { | |||
_defineProperty(target, key, source[key]); | |||
}); | |||
} else if (Object.getOwnPropertyDescriptors) { | |||
Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); | |||
} else { | |||
ownKeys(Object(source)).forEach(function (key) { | |||
Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); | |||
}); | |||
} | |||
} | |||
return target; | |||
} | |||
/** | |||
* ------------------------------------------------------------------------ | |||
* Constants | |||
* ------------------------------------------------------------------------ | |||
*/ | |||
var NAME = 'scrollspy'; | |||
var VERSION = '4.4.1'; | |||
var DATA_KEY = 'bs.scrollspy'; | |||
var EVENT_KEY = "." + DATA_KEY; | |||
var DATA_API_KEY = '.data-api'; | |||
var JQUERY_NO_CONFLICT = $.fn[NAME]; | |||
var Default = { | |||
offset: 10, | |||
method: 'auto', | |||
target: '' | |||
}; | |||
var DefaultType = { | |||
offset: 'number', | |||
method: 'string', | |||
target: '(string|element)' | |||
}; | |||
var Event = { | |||
ACTIVATE: "activate" + EVENT_KEY, | |||
SCROLL: "scroll" + EVENT_KEY, | |||
LOAD_DATA_API: "load" + EVENT_KEY + DATA_API_KEY | |||
}; | |||
var ClassName = { | |||
DROPDOWN_ITEM: 'dropdown-item', | |||
DROPDOWN_MENU: 'dropdown-menu', | |||
ACTIVE: 'active' | |||
}; | |||
var Selector = { | |||
DATA_SPY: '[data-spy="scroll"]', | |||
ACTIVE: '.active', | |||
NAV_LIST_GROUP: '.nav, .list-group', | |||
NAV_LINKS: '.nav-link', | |||
NAV_ITEMS: '.nav-item', | |||
LIST_ITEMS: '.list-group-item', | |||
DROPDOWN: '.dropdown', | |||
DROPDOWN_ITEMS: '.dropdown-item', | |||
DROPDOWN_TOGGLE: '.dropdown-toggle' | |||
}; | |||
var OffsetMethod = { | |||
OFFSET: 'offset', | |||
POSITION: 'position' | |||
}; | |||
/** | |||
* ------------------------------------------------------------------------ | |||
* Class Definition | |||
* ------------------------------------------------------------------------ | |||
*/ | |||
var ScrollSpy = | |||
/*#__PURE__*/ | |||
function () { | |||
function ScrollSpy(element, config) { | |||
var _this = this; | |||
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.LIST_ITEMS + ",") + (this._config.target + " " + Selector.DROPDOWN_ITEMS); | |||
this._offsets = []; | |||
this._targets = []; | |||
this._activeTarget = null; | |||
this._scrollHeight = 0; | |||
$(this._scrollElement).on(Event.SCROLL, function (event) { | |||
return _this._process(event); | |||
}); | |||
this.refresh(); | |||
this._process(); | |||
} // Getters | |||
var _proto = ScrollSpy.prototype; | |||
// Public | |||
_proto.refresh = function refresh() { | |||
var _this2 = this; | |||
var autoMethod = this._scrollElement === this._scrollElement.window ? OffsetMethod.OFFSET : OffsetMethod.POSITION; | |||
var offsetMethod = this._config.method === 'auto' ? autoMethod : this._config.method; | |||
var offsetBase = offsetMethod === OffsetMethod.POSITION ? this._getScrollTop() : 0; | |||
this._offsets = []; | |||
this._targets = []; | |||
this._scrollHeight = this._getScrollHeight(); | |||
var targets = [].slice.call(document.querySelectorAll(this._selector)); | |||
targets.map(function (element) { | |||
var target; | |||
var targetSelector = Util.getSelectorFromElement(element); | |||
if (targetSelector) { | |||
target = document.querySelector(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) { | |||
return item; | |||
}).sort(function (a, b) { | |||
return a[0] - b[0]; | |||
}).forEach(function (item) { | |||
_this2._offsets.push(item[0]); | |||
_this2._targets.push(item[1]); | |||
}); | |||
}; | |||
_proto.dispose = function dispose() { | |||
$.removeData(this._element, DATA_KEY); | |||
$(this._scrollElement).off(EVENT_KEY); | |||
this._element = null; | |||
this._scrollElement = null; | |||
this._config = null; | |||
this._selector = null; | |||
this._offsets = null; | |||
this._targets = null; | |||
this._activeTarget = null; | |||
this._scrollHeight = null; | |||
} // Private | |||
; | |||
_proto._getConfig = function _getConfig(config) { | |||
config = _objectSpread2({}, Default, {}, typeof config === 'object' && config ? config : {}); | |||
if (typeof config.target !== 'string') { | |||
var id = $(config.target).attr('id'); | |||
if (!id) { | |||
id = Util.getUID(NAME); | |||
$(config.target).attr('id', id); | |||
} | |||
config.target = "#" + id; | |||
} | |||
Util.typeCheckConfig(NAME, config, DefaultType); | |||
return config; | |||
}; | |||
_proto._getScrollTop = function _getScrollTop() { | |||
return this._scrollElement === window ? this._scrollElement.pageYOffset : this._scrollElement.scrollTop; | |||
}; | |||
_proto._getScrollHeight = function _getScrollHeight() { | |||
return this._scrollElement.scrollHeight || Math.max(document.body.scrollHeight, document.documentElement.scrollHeight); | |||
}; | |||
_proto._getOffsetHeight = function _getOffsetHeight() { | |||
return this._scrollElement === window ? window.innerHeight : this._scrollElement.getBoundingClientRect().height; | |||
}; | |||
_proto._process = function _process() { | |||
var scrollTop = this._getScrollTop() + this._config.offset; | |||
var scrollHeight = this._getScrollHeight(); | |||
var maxScroll = this._config.offset + scrollHeight - this._getOffsetHeight(); | |||
if (this._scrollHeight !== scrollHeight) { | |||
this.refresh(); | |||
} | |||
if (scrollTop >= maxScroll) { | |||
var target = this._targets[this._targets.length - 1]; | |||
if (this._activeTarget !== target) { | |||
this._activate(target); | |||
} | |||
return; | |||
} | |||
if (this._activeTarget && scrollTop < this._offsets[0] && this._offsets[0] > 0) { | |||
this._activeTarget = null; | |||
this._clear(); | |||
return; | |||
} | |||
var offsetLength = this._offsets.length; | |||
for (var i = offsetLength; i--;) { | |||
var isActiveTarget = this._activeTarget !== this._targets[i] && scrollTop >= this._offsets[i] && (typeof this._offsets[i + 1] === 'undefined' || scrollTop < this._offsets[i + 1]); | |||
if (isActiveTarget) { | |||
this._activate(this._targets[i]); | |||
} | |||
} | |||
}; | |||
_proto._activate = function _activate(target) { | |||
this._activeTarget = target; | |||
this._clear(); | |||
var queries = this._selector.split(',').map(function (selector) { | |||
return selector + "[data-target=\"" + target + "\"]," + selector + "[href=\"" + target + "\"]"; | |||
}); | |||
var $link = $([].slice.call(document.querySelectorAll(queries.join(',')))); | |||
if ($link.hasClass(ClassName.DROPDOWN_ITEM)) { | |||
$link.closest(Selector.DROPDOWN).find(Selector.DROPDOWN_TOGGLE).addClass(ClassName.ACTIVE); | |||
$link.addClass(ClassName.ACTIVE); | |||
} else { | |||
// 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); // Handle special case when .nav-link is inside .nav-item | |||
$link.parents(Selector.NAV_LIST_GROUP).prev(Selector.NAV_ITEMS).children(Selector.NAV_LINKS).addClass(ClassName.ACTIVE); | |||
} | |||
$(this._scrollElement).trigger(Event.ACTIVATE, { | |||
relatedTarget: target | |||
}); | |||
}; | |||
_proto._clear = function _clear() { | |||
[].slice.call(document.querySelectorAll(this._selector)).filter(function (node) { | |||
return node.classList.contains(ClassName.ACTIVE); | |||
}).forEach(function (node) { | |||
return node.classList.remove(ClassName.ACTIVE); | |||
}); | |||
} // Static | |||
; | |||
ScrollSpy._jQueryInterface = function _jQueryInterface(config) { | |||
return this.each(function () { | |||
var data = $(this).data(DATA_KEY); | |||
var _config = typeof config === 'object' && config; | |||
if (!data) { | |||
data = new ScrollSpy(this, _config); | |||
$(this).data(DATA_KEY, data); | |||
} | |||
if (typeof config === 'string') { | |||
if (typeof data[config] === 'undefined') { | |||
throw new TypeError("No method named \"" + config + "\""); | |||
} | |||
data[config](); | |||
} | |||
}); | |||
}; | |||
_createClass(ScrollSpy, null, [{ | |||
key: "VERSION", | |||
get: function get() { | |||
return VERSION; | |||
} | |||
}, { | |||
key: "Default", | |||
get: function get() { | |||
return Default; | |||
} | |||
}]); | |||
return ScrollSpy; | |||
}(); | |||
/** | |||
* ------------------------------------------------------------------------ | |||
* Data Api implementation | |||
* ------------------------------------------------------------------------ | |||
*/ | |||
$(window).on(Event.LOAD_DATA_API, function () { | |||
var scrollSpys = [].slice.call(document.querySelectorAll(Selector.DATA_SPY)); | |||
var scrollSpysLength = scrollSpys.length; | |||
for (var i = scrollSpysLength; i--;) { | |||
var $spy = $(scrollSpys[i]); | |||
ScrollSpy._jQueryInterface.call($spy, $spy.data()); | |||
} | |||
}); | |||
/** | |||
* ------------------------------------------------------------------------ | |||
* jQuery | |||
* ------------------------------------------------------------------------ | |||
*/ | |||
$.fn[NAME] = ScrollSpy._jQueryInterface; | |||
$.fn[NAME].Constructor = ScrollSpy; | |||
$.fn[NAME].noConflict = function () { | |||
$.fn[NAME] = JQUERY_NO_CONFLICT; | |||
return ScrollSpy._jQueryInterface; | |||
}; | |||
return ScrollSpy; | |||
}))); | |||
//# sourceMappingURL=scrollspy.js.map |
@ -0,0 +1,268 @@ | |||
/*! | |||
* Bootstrap tab.js v4.4.1 (https://getbootstrap.com/) | |||
* Copyright 2011-2019 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors) | |||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) | |||
*/ | |||
(function (global, factory) { | |||
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('jquery'), require('./util.js')) : | |||
typeof define === 'function' && define.amd ? define(['jquery', './util.js'], factory) : | |||
(global = global || self, global.Tab = factory(global.jQuery, global.Util)); | |||
}(this, (function ($, Util) { 'use strict'; | |||
$ = $ && $.hasOwnProperty('default') ? $['default'] : $; | |||
Util = Util && Util.hasOwnProperty('default') ? Util['default'] : Util; | |||
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); | |||
} | |||
} | |||
function _createClass(Constructor, protoProps, staticProps) { | |||
if (protoProps) _defineProperties(Constructor.prototype, protoProps); | |||
if (staticProps) _defineProperties(Constructor, staticProps); | |||
return Constructor; | |||
} | |||
/** | |||
* ------------------------------------------------------------------------ | |||
* Constants | |||
* ------------------------------------------------------------------------ | |||
*/ | |||
var NAME = 'tab'; | |||
var VERSION = '4.4.1'; | |||
var DATA_KEY = 'bs.tab'; | |||
var EVENT_KEY = "." + DATA_KEY; | |||
var DATA_API_KEY = '.data-api'; | |||
var JQUERY_NO_CONFLICT = $.fn[NAME]; | |||
var Event = { | |||
HIDE: "hide" + EVENT_KEY, | |||
HIDDEN: "hidden" + EVENT_KEY, | |||
SHOW: "show" + EVENT_KEY, | |||
SHOWN: "shown" + EVENT_KEY, | |||
CLICK_DATA_API: "click" + EVENT_KEY + DATA_API_KEY | |||
}; | |||
var ClassName = { | |||
DROPDOWN_MENU: 'dropdown-menu', | |||
ACTIVE: 'active', | |||
DISABLED: 'disabled', | |||
FADE: 'fade', | |||
SHOW: 'show' | |||
}; | |||
var Selector = { | |||
DROPDOWN: '.dropdown', | |||
NAV_LIST_GROUP: '.nav, .list-group', | |||
ACTIVE: '.active', | |||
ACTIVE_UL: '> li > .active', | |||
DATA_TOGGLE: '[data-toggle="tab"], [data-toggle="pill"], [data-toggle="list"]', | |||
DROPDOWN_TOGGLE: '.dropdown-toggle', | |||
DROPDOWN_ACTIVE_CHILD: '> .dropdown-menu .active' | |||
}; | |||
/** | |||
* ------------------------------------------------------------------------ | |||
* Class Definition | |||
* ------------------------------------------------------------------------ | |||
*/ | |||
var Tab = | |||
/*#__PURE__*/ | |||
function () { | |||
function Tab(element) { | |||
this._element = element; | |||
} // Getters | |||
var _proto = Tab.prototype; | |||
// Public | |||
_proto.show = function show() { | |||
var _this = this; | |||
if (this._element.parentNode && this._element.parentNode.nodeType === Node.ELEMENT_NODE && $(this._element).hasClass(ClassName.ACTIVE) || $(this._element).hasClass(ClassName.DISABLED)) { | |||
return; | |||
} | |||
var target; | |||
var previous; | |||
var listElement = $(this._element).closest(Selector.NAV_LIST_GROUP)[0]; | |||
var selector = Util.getSelectorFromElement(this._element); | |||
if (listElement) { | |||
var itemSelector = listElement.nodeName === 'UL' || listElement.nodeName === 'OL' ? Selector.ACTIVE_UL : Selector.ACTIVE; | |||
previous = $.makeArray($(listElement).find(itemSelector)); | |||
previous = previous[previous.length - 1]; | |||
} | |||
var hideEvent = $.Event(Event.HIDE, { | |||
relatedTarget: this._element | |||
}); | |||
var showEvent = $.Event(Event.SHOW, { | |||
relatedTarget: previous | |||
}); | |||
if (previous) { | |||
$(previous).trigger(hideEvent); | |||
} | |||
$(this._element).trigger(showEvent); | |||
if (showEvent.isDefaultPrevented() || hideEvent.isDefaultPrevented()) { | |||
return; | |||
} | |||
if (selector) { | |||
target = document.querySelector(selector); | |||
} | |||
this._activate(this._element, listElement); | |||
var complete = function complete() { | |||
var hiddenEvent = $.Event(Event.HIDDEN, { | |||
relatedTarget: _this._element | |||
}); | |||
var shownEvent = $.Event(Event.SHOWN, { | |||
relatedTarget: previous | |||
}); | |||
$(previous).trigger(hiddenEvent); | |||
$(_this._element).trigger(shownEvent); | |||
}; | |||
if (target) { | |||
this._activate(target, target.parentNode, complete); | |||
} else { | |||
complete(); | |||
} | |||
}; | |||
_proto.dispose = function dispose() { | |||
$.removeData(this._element, DATA_KEY); | |||
this._element = null; | |||
} // Private | |||
; | |||
_proto._activate = function _activate(element, container, callback) { | |||
var _this2 = this; | |||
var activeElements = container && (container.nodeName === 'UL' || container.nodeName === 'OL') ? $(container).find(Selector.ACTIVE_UL) : $(container).children(Selector.ACTIVE); | |||
var active = activeElements[0]; | |||
var isTransitioning = callback && active && $(active).hasClass(ClassName.FADE); | |||
var complete = function complete() { | |||
return _this2._transitionComplete(element, active, callback); | |||
}; | |||
if (active && isTransitioning) { | |||
var transitionDuration = Util.getTransitionDurationFromElement(active); | |||
$(active).removeClass(ClassName.SHOW).one(Util.TRANSITION_END, complete).emulateTransitionEnd(transitionDuration); | |||
} else { | |||
complete(); | |||
} | |||
}; | |||
_proto._transitionComplete = function _transitionComplete(element, active, callback) { | |||
if (active) { | |||
$(active).removeClass(ClassName.ACTIVE); | |||
var dropdownChild = $(active.parentNode).find(Selector.DROPDOWN_ACTIVE_CHILD)[0]; | |||
if (dropdownChild) { | |||
$(dropdownChild).removeClass(ClassName.ACTIVE); | |||
} | |||
if (active.getAttribute('role') === 'tab') { | |||
active.setAttribute('aria-selected', false); | |||
} | |||
} | |||
$(element).addClass(ClassName.ACTIVE); | |||
if (element.getAttribute('role') === 'tab') { | |||
element.setAttribute('aria-selected', true); | |||
} | |||
Util.reflow(element); | |||
if (element.classList.contains(ClassName.FADE)) { | |||
element.classList.add(ClassName.SHOW); | |||
} | |||
if (element.parentNode && $(element.parentNode).hasClass(ClassName.DROPDOWN_MENU)) { | |||
var dropdownElement = $(element).closest(Selector.DROPDOWN)[0]; | |||
if (dropdownElement) { | |||
var dropdownToggleList = [].slice.call(dropdownElement.querySelectorAll(Selector.DROPDOWN_TOGGLE)); | |||
$(dropdownToggleList).addClass(ClassName.ACTIVE); | |||
} | |||
element.setAttribute('aria-expanded', true); | |||
} | |||
if (callback) { | |||
callback(); | |||
} | |||
} // Static | |||
; | |||
Tab._jQueryInterface = function _jQueryInterface(config) { | |||
return this.each(function () { | |||
var $this = $(this); | |||
var data = $this.data(DATA_KEY); | |||
if (!data) { | |||
data = new Tab(this); | |||
$this.data(DATA_KEY, data); | |||
} | |||
if (typeof config === 'string') { | |||
if (typeof data[config] === 'undefined') { | |||
throw new TypeError("No method named \"" + config + "\""); | |||
} | |||
data[config](); | |||
} | |||
}); | |||
}; | |||
_createClass(Tab, null, [{ | |||
key: "VERSION", | |||
get: function get() { | |||
return VERSION; | |||
} | |||
}]); | |||
return Tab; | |||
}(); | |||
/** | |||
* ------------------------------------------------------------------------ | |||
* Data Api implementation | |||
* ------------------------------------------------------------------------ | |||
*/ | |||
$(document).on(Event.CLICK_DATA_API, Selector.DATA_TOGGLE, function (event) { | |||
event.preventDefault(); | |||
Tab._jQueryInterface.call($(this), 'show'); | |||
}); | |||
/** | |||
* ------------------------------------------------------------------------ | |||
* jQuery | |||
* ------------------------------------------------------------------------ | |||
*/ | |||
$.fn[NAME] = Tab._jQueryInterface; | |||
$.fn[NAME].Constructor = Tab; | |||
$.fn[NAME].noConflict = function () { | |||
$.fn[NAME] = JQUERY_NO_CONFLICT; | |||
return Tab._jQueryInterface; | |||
}; | |||
return Tab; | |||
}))); | |||
//# sourceMappingURL=tab.js.map |
@ -0,0 +1,303 @@ | |||
/*! | |||
* Bootstrap toast.js v4.4.1 (https://getbootstrap.com/) | |||
* Copyright 2011-2019 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors) | |||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) | |||
*/ | |||
(function (global, factory) { | |||
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('jquery'), require('./util.js')) : | |||
typeof define === 'function' && define.amd ? define(['jquery', './util.js'], factory) : | |||
(global = global || self, global.Toast = factory(global.jQuery, global.Util)); | |||
}(this, (function ($, Util) { 'use strict'; | |||
$ = $ && $.hasOwnProperty('default') ? $['default'] : $; | |||
Util = Util && Util.hasOwnProperty('default') ? Util['default'] : Util; | |||
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); | |||
} | |||
} | |||
function _createClass(Constructor, protoProps, staticProps) { | |||
if (protoProps) _defineProperties(Constructor.prototype, protoProps); | |||
if (staticProps) _defineProperties(Constructor, staticProps); | |||
return Constructor; | |||
} | |||
function _defineProperty(obj, key, value) { | |||
if (key in obj) { | |||
Object.defineProperty(obj, key, { | |||
value: value, | |||
enumerable: true, | |||
configurable: true, | |||
writable: true | |||
}); | |||
} else { | |||
obj[key] = value; | |||
} | |||
return obj; | |||
} | |||
function ownKeys(object, enumerableOnly) { | |||
var keys = Object.keys(object); | |||
if (Object.getOwnPropertySymbols) { | |||
var symbols = Object.getOwnPropertySymbols(object); | |||
if (enumerableOnly) symbols = symbols.filter(function (sym) { | |||
return Object.getOwnPropertyDescriptor(object, sym).enumerable; | |||
}); | |||
keys.push.apply(keys, symbols); | |||
} | |||
return keys; | |||
} | |||
function _objectSpread2(target) { | |||
for (var i = 1; i < arguments.length; i++) { | |||
var source = arguments[i] != null ? arguments[i] : {}; | |||
if (i % 2) { | |||
ownKeys(Object(source), true).forEach(function (key) { | |||
_defineProperty(target, key, source[key]); | |||
}); | |||
} else if (Object.getOwnPropertyDescriptors) { | |||
Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); | |||
} else { | |||
ownKeys(Object(source)).forEach(function (key) { | |||
Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); | |||
}); | |||
} | |||
} | |||
return target; | |||
} | |||
/** | |||
* ------------------------------------------------------------------------ | |||
* Constants | |||
* ------------------------------------------------------------------------ | |||
*/ | |||
var NAME = 'toast'; | |||
var VERSION = '4.4.1'; | |||
var DATA_KEY = 'bs.toast'; | |||
var EVENT_KEY = "." + DATA_KEY; | |||
var JQUERY_NO_CONFLICT = $.fn[NAME]; | |||
var Event = { | |||
CLICK_DISMISS: "click.dismiss" + EVENT_KEY, | |||
HIDE: "hide" + EVENT_KEY, | |||
HIDDEN: "hidden" + EVENT_KEY, | |||
SHOW: "show" + EVENT_KEY, | |||
SHOWN: "shown" + EVENT_KEY | |||
}; | |||
var ClassName = { | |||
FADE: 'fade', | |||
HIDE: 'hide', | |||
SHOW: 'show', | |||
SHOWING: 'showing' | |||
}; | |||
var DefaultType = { | |||
animation: 'boolean', | |||
autohide: 'boolean', | |||
delay: 'number' | |||
}; | |||
var Default = { | |||
animation: true, | |||
autohide: true, | |||
delay: 500 | |||
}; | |||
var Selector = { | |||
DATA_DISMISS: '[data-dismiss="toast"]' | |||
}; | |||
/** | |||
* ------------------------------------------------------------------------ | |||
* Class Definition | |||
* ------------------------------------------------------------------------ | |||
*/ | |||
var Toast = | |||
/*#__PURE__*/ | |||
function () { | |||
function Toast(element, config) { | |||
this._element = element; | |||
this._config = this._getConfig(config); | |||
this._timeout = null; | |||
this._setListeners(); | |||
} // Getters | |||
var _proto = Toast.prototype; | |||
// Public | |||
_proto.show = function show() { | |||
var _this = this; | |||
var showEvent = $.Event(Event.SHOW); | |||
$(this._element).trigger(showEvent); | |||
if (showEvent.isDefaultPrevented()) { | |||
return; | |||
} | |||
if (this._config.animation) { | |||
this._element.classList.add(ClassName.FADE); | |||
} | |||
var complete = function complete() { | |||
_this._element.classList.remove(ClassName.SHOWING); | |||
_this._element.classList.add(ClassName.SHOW); | |||
$(_this._element).trigger(Event.SHOWN); | |||
if (_this._config.autohide) { | |||
_this._timeout = setTimeout(function () { | |||
_this.hide(); | |||
}, _this._config.delay); | |||
} | |||
}; | |||
this._element.classList.remove(ClassName.HIDE); | |||
Util.reflow(this._element); | |||
this._element.classList.add(ClassName.SHOWING); | |||
if (this._config.animation) { | |||
var transitionDuration = Util.getTransitionDurationFromElement(this._element); | |||
$(this._element).one(Util.TRANSITION_END, complete).emulateTransitionEnd(transitionDuration); | |||
} else { | |||
complete(); | |||
} | |||
}; | |||
_proto.hide = function hide() { | |||
if (!this._element.classList.contains(ClassName.SHOW)) { | |||
return; | |||
} | |||
var hideEvent = $.Event(Event.HIDE); | |||
$(this._element).trigger(hideEvent); | |||
if (hideEvent.isDefaultPrevented()) { | |||
return; | |||
} | |||
this._close(); | |||
}; | |||
_proto.dispose = function dispose() { | |||
clearTimeout(this._timeout); | |||
this._timeout = null; | |||
if (this._element.classList.contains(ClassName.SHOW)) { | |||
this._element.classList.remove(ClassName.SHOW); | |||
} | |||
$(this._element).off(Event.CLICK_DISMISS); | |||
$.removeData(this._element, DATA_KEY); | |||
this._element = null; | |||
this._config = null; | |||
} // Private | |||
; | |||
_proto._getConfig = function _getConfig(config) { | |||
config = _objectSpread2({}, Default, {}, $(this._element).data(), {}, typeof config === 'object' && config ? config : {}); | |||
Util.typeCheckConfig(NAME, config, this.constructor.DefaultType); | |||
return config; | |||
}; | |||
_proto._setListeners = function _setListeners() { | |||
var _this2 = this; | |||
$(this._element).on(Event.CLICK_DISMISS, Selector.DATA_DISMISS, function () { | |||
return _this2.hide(); | |||
}); | |||
}; | |||
_proto._close = function _close() { | |||
var _this3 = this; | |||
var complete = function complete() { | |||
_this3._element.classList.add(ClassName.HIDE); | |||
$(_this3._element).trigger(Event.HIDDEN); | |||
}; | |||
this._element.classList.remove(ClassName.SHOW); | |||
if (this._config.animation) { | |||
var transitionDuration = Util.getTransitionDurationFromElement(this._element); | |||
$(this._element).one(Util.TRANSITION_END, complete).emulateTransitionEnd(transitionDuration); | |||
} else { | |||
complete(); | |||
} | |||
} // Static | |||
; | |||
Toast._jQueryInterface = function _jQueryInterface(config) { | |||
return this.each(function () { | |||
var $element = $(this); | |||
var data = $element.data(DATA_KEY); | |||
var _config = typeof config === 'object' && config; | |||
if (!data) { | |||
data = new Toast(this, _config); | |||
$element.data(DATA_KEY, data); | |||
} | |||
if (typeof config === 'string') { | |||
if (typeof data[config] === 'undefined') { | |||
throw new TypeError("No method named \"" + config + "\""); | |||
} | |||
data[config](this); | |||
} | |||
}); | |||
}; | |||
_createClass(Toast, null, [{ | |||
key: "VERSION", | |||
get: function get() { | |||
return VERSION; | |||
} | |||
}, { | |||
key: "DefaultType", | |||
get: function get() { | |||
return DefaultType; | |||
} | |||
}, { | |||
key: "Default", | |||
get: function get() { | |||
return Default; | |||
} | |||
}]); | |||
return Toast; | |||
}(); | |||
/** | |||
* ------------------------------------------------------------------------ | |||
* jQuery | |||
* ------------------------------------------------------------------------ | |||
*/ | |||
$.fn[NAME] = Toast._jQueryInterface; | |||
$.fn[NAME].Constructor = Toast; | |||
$.fn[NAME].noConflict = function () { | |||
$.fn[NAME] = JQUERY_NO_CONFLICT; | |||
return Toast._jQueryInterface; | |||
}; | |||
return Toast; | |||
}))); | |||
//# sourceMappingURL=toast.js.map |
@ -0,0 +1,929 @@ | |||
/*! | |||
* Bootstrap tooltip.js v4.4.1 (https://getbootstrap.com/) | |||
* Copyright 2011-2019 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors) | |||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) | |||
*/ | |||
(function (global, factory) { | |||
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('jquery'), require('popper.js'), require('./util.js')) : | |||
typeof define === 'function' && define.amd ? define(['jquery', 'popper.js', './util.js'], factory) : | |||
(global = global || self, global.Tooltip = factory(global.jQuery, global.Popper, global.Util)); | |||
}(this, (function ($, Popper, Util) { 'use strict'; | |||
$ = $ && $.hasOwnProperty('default') ? $['default'] : $; | |||
Popper = Popper && Popper.hasOwnProperty('default') ? Popper['default'] : Popper; | |||
Util = Util && Util.hasOwnProperty('default') ? Util['default'] : Util; | |||
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); | |||
} | |||
} | |||
function _createClass(Constructor, protoProps, staticProps) { | |||
if (protoProps) _defineProperties(Constructor.prototype, protoProps); | |||
if (staticProps) _defineProperties(Constructor, staticProps); | |||
return Constructor; | |||
} | |||
function _defineProperty(obj, key, value) { | |||
if (key in obj) { | |||
Object.defineProperty(obj, key, { | |||
value: value, | |||
enumerable: true, | |||
configurable: true, | |||
writable: true | |||
}); | |||
} else { | |||
obj[key] = value; | |||
} | |||
return obj; | |||
} | |||
function ownKeys(object, enumerableOnly) { | |||
var keys = Object.keys(object); | |||
if (Object.getOwnPropertySymbols) { | |||
var symbols = Object.getOwnPropertySymbols(object); | |||
if (enumerableOnly) symbols = symbols.filter(function (sym) { | |||
return Object.getOwnPropertyDescriptor(object, sym).enumerable; | |||
}); | |||
keys.push.apply(keys, symbols); | |||
} | |||
return keys; | |||
} | |||
function _objectSpread2(target) { | |||
for (var i = 1; i < arguments.length; i++) { | |||
var source = arguments[i] != null ? arguments[i] : {}; | |||
if (i % 2) { | |||
ownKeys(Object(source), true).forEach(function (key) { | |||
_defineProperty(target, key, source[key]); | |||
}); | |||
} else if (Object.getOwnPropertyDescriptors) { | |||
Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); | |||
} else { | |||
ownKeys(Object(source)).forEach(function (key) { | |||
Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); | |||
}); | |||
} | |||
} | |||
return target; | |||
} | |||
/** | |||
* -------------------------------------------------------------------------- | |||
* Bootstrap (v4.4.1): tools/sanitizer.js | |||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) | |||
* -------------------------------------------------------------------------- | |||
*/ | |||
var uriAttrs = ['background', 'cite', 'href', 'itemtype', 'longdesc', 'poster', 'src', 'xlink:href']; | |||
var ARIA_ATTRIBUTE_PATTERN = /^aria-[\w-]*$/i; | |||
var DefaultWhitelist = { | |||
// Global attributes allowed on any supplied element below. | |||
'*': ['class', 'dir', 'id', 'lang', 'role', ARIA_ATTRIBUTE_PATTERN], | |||
a: ['target', 'href', 'title', 'rel'], | |||
area: [], | |||
b: [], | |||
br: [], | |||
col: [], | |||
code: [], | |||
div: [], | |||
em: [], | |||
hr: [], | |||
h1: [], | |||
h2: [], | |||
h3: [], | |||
h4: [], | |||
h5: [], | |||
h6: [], | |||
i: [], | |||
img: ['src', 'alt', 'title', 'width', 'height'], | |||
li: [], | |||
ol: [], | |||
p: [], | |||
pre: [], | |||
s: [], | |||
small: [], | |||
span: [], | |||
sub: [], | |||
sup: [], | |||
strong: [], | |||
u: [], | |||
ul: [] | |||
}; | |||
/** | |||
* A pattern that recognizes a commonly useful subset of URLs that are safe. | |||
* | |||
* Shoutout to Angular 7 https://github.com/angular/angular/blob/7.2.4/packages/core/src/sanitization/url_sanitizer.ts | |||
*/ | |||
var SAFE_URL_PATTERN = /^(?:(?:https?|mailto|ftp|tel|file):|[^&:/?#]*(?:[/?#]|$))/gi; | |||
/** | |||
* A pattern that matches safe data URLs. Only matches image, video and audio types. | |||
* | |||
* Shoutout to Angular 7 https://github.com/angular/angular/blob/7.2.4/packages/core/src/sanitization/url_sanitizer.ts | |||
*/ | |||
var DATA_URL_PATTERN = /^data:(?:image\/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|video\/(?:mpeg|mp4|ogg|webm)|audio\/(?:mp3|oga|ogg|opus));base64,[a-z0-9+/]+=*$/i; | |||
function allowedAttribute(attr, allowedAttributeList) { | |||
var attrName = attr.nodeName.toLowerCase(); | |||
if (allowedAttributeList.indexOf(attrName) !== -1) { | |||
if (uriAttrs.indexOf(attrName) !== -1) { | |||
return Boolean(attr.nodeValue.match(SAFE_URL_PATTERN) || attr.nodeValue.match(DATA_URL_PATTERN)); | |||
} | |||
return true; | |||
} | |||
var regExp = allowedAttributeList.filter(function (attrRegex) { | |||
return attrRegex instanceof RegExp; | |||
}); // Check if a regular expression validates the attribute. | |||
for (var i = 0, l = regExp.length; i < l; i++) { | |||
if (attrName.match(regExp[i])) { | |||
return true; | |||
} | |||
} | |||
return false; | |||
} | |||
function sanitizeHtml(unsafeHtml, whiteList, sanitizeFn) { | |||
if (unsafeHtml.length === 0) { | |||
return unsafeHtml; | |||
} | |||
if (sanitizeFn && typeof sanitizeFn === 'function') { | |||
return sanitizeFn(unsafeHtml); | |||
} | |||
var domParser = new window.DOMParser(); | |||
var createdDocument = domParser.parseFromString(unsafeHtml, 'text/html'); | |||
var whitelistKeys = Object.keys(whiteList); | |||
var elements = [].slice.call(createdDocument.body.querySelectorAll('*')); | |||
var _loop = function _loop(i, len) { | |||
var el = elements[i]; | |||
var elName = el.nodeName.toLowerCase(); | |||
if (whitelistKeys.indexOf(el.nodeName.toLowerCase()) === -1) { | |||
el.parentNode.removeChild(el); | |||
return "continue"; | |||
} | |||
var attributeList = [].slice.call(el.attributes); | |||
var whitelistedAttributes = [].concat(whiteList['*'] || [], whiteList[elName] || []); | |||
attributeList.forEach(function (attr) { | |||
if (!allowedAttribute(attr, whitelistedAttributes)) { | |||
el.removeAttribute(attr.nodeName); | |||
} | |||
}); | |||
}; | |||
for (var i = 0, len = elements.length; i < len; i++) { | |||
var _ret = _loop(i); | |||
if (_ret === "continue") continue; | |||
} | |||
return createdDocument.body.innerHTML; | |||
} | |||
/** | |||
* ------------------------------------------------------------------------ | |||
* Constants | |||
* ------------------------------------------------------------------------ | |||
*/ | |||
var NAME = 'tooltip'; | |||
var VERSION = '4.4.1'; | |||
var DATA_KEY = 'bs.tooltip'; | |||
var EVENT_KEY = "." + DATA_KEY; | |||
var JQUERY_NO_CONFLICT = $.fn[NAME]; | |||
var CLASS_PREFIX = 'bs-tooltip'; | |||
var BSCLS_PREFIX_REGEX = new RegExp("(^|\\s)" + CLASS_PREFIX + "\\S+", 'g'); | |||
var DISALLOWED_ATTRIBUTES = ['sanitize', 'whiteList', 'sanitizeFn']; | |||
var DefaultType = { | |||
animation: 'boolean', | |||
template: 'string', | |||
title: '(string|element|function)', | |||
trigger: 'string', | |||
delay: '(number|object)', | |||
html: 'boolean', | |||
selector: '(string|boolean)', | |||
placement: '(string|function)', | |||
offset: '(number|string|function)', | |||
container: '(string|element|boolean)', | |||
fallbackPlacement: '(string|array)', | |||
boundary: '(string|element)', | |||
sanitize: 'boolean', | |||
sanitizeFn: '(null|function)', | |||
whiteList: 'object', | |||
popperConfig: '(null|object)' | |||
}; | |||
var AttachmentMap = { | |||
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', | |||
boundary: 'scrollParent', | |||
sanitize: true, | |||
sanitizeFn: null, | |||
whiteList: DefaultWhitelist, | |||
popperConfig: null | |||
}; | |||
var HoverState = { | |||
SHOW: 'show', | |||
OUT: 'out' | |||
}; | |||
var Event = { | |||
HIDE: "hide" + EVENT_KEY, | |||
HIDDEN: "hidden" + EVENT_KEY, | |||
SHOW: "show" + EVENT_KEY, | |||
SHOWN: "shown" + EVENT_KEY, | |||
INSERTED: "inserted" + EVENT_KEY, | |||
CLICK: "click" + EVENT_KEY, | |||
FOCUSIN: "focusin" + EVENT_KEY, | |||
FOCUSOUT: "focusout" + EVENT_KEY, | |||
MOUSEENTER: "mouseenter" + EVENT_KEY, | |||
MOUSELEAVE: "mouseleave" + EVENT_KEY | |||
}; | |||
var ClassName = { | |||
FADE: 'fade', | |||
SHOW: 'show' | |||
}; | |||
var Selector = { | |||
TOOLTIP: '.tooltip', | |||
TOOLTIP_INNER: '.tooltip-inner', | |||
ARROW: '.arrow' | |||
}; | |||
var Trigger = { | |||
HOVER: 'hover', | |||
FOCUS: 'focus', | |||
CLICK: 'click', | |||
MANUAL: 'manual' | |||
}; | |||
/** | |||
* ------------------------------------------------------------------------ | |||
* Class Definition | |||
* ------------------------------------------------------------------------ | |||
*/ | |||
var Tooltip = | |||
/*#__PURE__*/ | |||
function () { | |||
function Tooltip(element, config) { | |||
if (typeof Popper === 'undefined') { | |||
throw new TypeError('Bootstrap\'s tooltips require Popper.js (https://popper.js.org/)'); | |||
} // private | |||
this._isEnabled = true; | |||
this._timeout = 0; | |||
this._hoverState = ''; | |||
this._activeTrigger = {}; | |||
this._popper = null; // Protected | |||
this.element = element; | |||
this.config = this._getConfig(config); | |||
this.tip = null; | |||
this._setListeners(); | |||
} // Getters | |||
var _proto = Tooltip.prototype; | |||
// Public | |||
_proto.enable = function enable() { | |||
this._isEnabled = true; | |||
}; | |||
_proto.disable = function disable() { | |||
this._isEnabled = false; | |||
}; | |||
_proto.toggleEnabled = function toggleEnabled() { | |||
this._isEnabled = !this._isEnabled; | |||
}; | |||
_proto.toggle = function toggle(event) { | |||
if (!this._isEnabled) { | |||
return; | |||
} | |||
if (event) { | |||
var dataKey = this.constructor.DATA_KEY; | |||
var context = $(event.currentTarget).data(dataKey); | |||
if (!context) { | |||
context = new this.constructor(event.currentTarget, this._getDelegateConfig()); | |||
$(event.currentTarget).data(dataKey, context); | |||
} | |||
context._activeTrigger.click = !context._activeTrigger.click; | |||
if (context._isWithActiveTrigger()) { | |||
context._enter(null, context); | |||
} else { | |||
context._leave(null, context); | |||
} | |||
} else { | |||
if ($(this.getTipElement()).hasClass(ClassName.SHOW)) { | |||
this._leave(null, this); | |||
return; | |||
} | |||
this._enter(null, this); | |||
} | |||
}; | |||
_proto.dispose = function dispose() { | |||
clearTimeout(this._timeout); | |||
$.removeData(this.element, this.constructor.DATA_KEY); | |||
$(this.element).off(this.constructor.EVENT_KEY); | |||
$(this.element).closest('.modal').off('hide.bs.modal', this._hideModalHandler); | |||
if (this.tip) { | |||
$(this.tip).remove(); | |||
} | |||
this._isEnabled = null; | |||
this._timeout = null; | |||
this._hoverState = null; | |||
this._activeTrigger = null; | |||
if (this._popper) { | |||
this._popper.destroy(); | |||
} | |||
this._popper = null; | |||
this.element = null; | |||
this.config = null; | |||
this.tip = null; | |||
}; | |||
_proto.show = function show() { | |||
var _this = this; | |||
if ($(this.element).css('display') === 'none') { | |||
throw new Error('Please use show on visible elements'); | |||
} | |||
var showEvent = $.Event(this.constructor.Event.SHOW); | |||
if (this.isWithContent() && this._isEnabled) { | |||
$(this.element).trigger(showEvent); | |||
var shadowRoot = Util.findShadowRoot(this.element); | |||
var isInTheDom = $.contains(shadowRoot !== null ? shadowRoot : this.element.ownerDocument.documentElement, this.element); | |||
if (showEvent.isDefaultPrevented() || !isInTheDom) { | |||
return; | |||
} | |||
var tip = this.getTipElement(); | |||
var tipId = Util.getUID(this.constructor.NAME); | |||
tip.setAttribute('id', tipId); | |||
this.element.setAttribute('aria-describedby', tipId); | |||
this.setContent(); | |||
if (this.config.animation) { | |||
$(tip).addClass(ClassName.FADE); | |||
} | |||
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._getContainer(); | |||
$(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._popper = new Popper(this.element, tip, this._getPopperConfig(attachment)); | |||
$(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) { | |||
$(document.body).children().on('mouseover', null, $.noop); | |||
} | |||
var complete = function complete() { | |||
if (_this.config.animation) { | |||
_this._fixTransition(); | |||
} | |||
var prevHoverState = _this._hoverState; | |||
_this._hoverState = null; | |||
$(_this.element).trigger(_this.constructor.Event.SHOWN); | |||
if (prevHoverState === HoverState.OUT) { | |||
_this._leave(null, _this); | |||
} | |||
}; | |||
if ($(this.tip).hasClass(ClassName.FADE)) { | |||
var transitionDuration = Util.getTransitionDurationFromElement(this.tip); | |||
$(this.tip).one(Util.TRANSITION_END, complete).emulateTransitionEnd(transitionDuration); | |||
} else { | |||
complete(); | |||
} | |||
} | |||
}; | |||
_proto.hide = function hide(callback) { | |||
var _this2 = this; | |||
var tip = this.getTipElement(); | |||
var hideEvent = $.Event(this.constructor.Event.HIDE); | |||
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); | |||
if (_this2._popper !== null) { | |||
_this2._popper.destroy(); | |||
} | |||
if (callback) { | |||
callback(); | |||
} | |||
}; | |||
$(this.element).trigger(hideEvent); | |||
if (hideEvent.isDefaultPrevented()) { | |||
return; | |||
} | |||
$(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) { | |||
$(document.body).children().off('mouseover', null, $.noop); | |||
} | |||
this._activeTrigger[Trigger.CLICK] = false; | |||
this._activeTrigger[Trigger.FOCUS] = false; | |||
this._activeTrigger[Trigger.HOVER] = false; | |||
if ($(this.tip).hasClass(ClassName.FADE)) { | |||
var transitionDuration = Util.getTransitionDurationFromElement(tip); | |||
$(tip).one(Util.TRANSITION_END, complete).emulateTransitionEnd(transitionDuration); | |||
} else { | |||
complete(); | |||
} | |||
this._hoverState = ''; | |||
}; | |||
_proto.update = function update() { | |||
if (this._popper !== null) { | |||
this._popper.scheduleUpdate(); | |||
} | |||
} // Protected | |||
; | |||
_proto.isWithContent = function isWithContent() { | |||
return Boolean(this.getTitle()); | |||
}; | |||
_proto.addAttachmentClass = function addAttachmentClass(attachment) { | |||
$(this.getTipElement()).addClass(CLASS_PREFIX + "-" + attachment); | |||
}; | |||
_proto.getTipElement = function getTipElement() { | |||
this.tip = this.tip || $(this.config.template)[0]; | |||
return this.tip; | |||
}; | |||
_proto.setContent = function setContent() { | |||
var tip = this.getTipElement(); | |||
this.setElementContent($(tip.querySelectorAll(Selector.TOOLTIP_INNER)), this.getTitle()); | |||
$(tip).removeClass(ClassName.FADE + " " + ClassName.SHOW); | |||
}; | |||
_proto.setElementContent = function setElementContent($element, content) { | |||
if (typeof content === 'object' && (content.nodeType || content.jquery)) { | |||
// Content is a DOM node or a jQuery | |||
if (this.config.html) { | |||
if (!$(content).parent().is($element)) { | |||
$element.empty().append(content); | |||
} | |||
} else { | |||
$element.text($(content).text()); | |||
} | |||
return; | |||
} | |||
if (this.config.html) { | |||
if (this.config.sanitize) { | |||
content = sanitizeHtml(content, this.config.whiteList, this.config.sanitizeFn); | |||
} | |||
$element.html(content); | |||
} else { | |||
$element.text(content); | |||
} | |||
}; | |||
_proto.getTitle = function getTitle() { | |||
var title = this.element.getAttribute('data-original-title'); | |||
if (!title) { | |||
title = typeof this.config.title === 'function' ? this.config.title.call(this.element) : this.config.title; | |||
} | |||
return title; | |||
} // Private | |||
; | |||
_proto._getPopperConfig = function _getPopperConfig(attachment) { | |||
var _this3 = this; | |||
var defaultBsConfig = { | |||
placement: attachment, | |||
modifiers: { | |||
offset: this._getOffset(), | |||
flip: { | |||
behavior: this.config.fallbackPlacement | |||
}, | |||
arrow: { | |||
element: Selector.ARROW | |||
}, | |||
preventOverflow: { | |||
boundariesElement: this.config.boundary | |||
} | |||
}, | |||
onCreate: function onCreate(data) { | |||
if (data.originalPlacement !== data.placement) { | |||
_this3._handlePopperPlacementChange(data); | |||
} | |||
}, | |||
onUpdate: function onUpdate(data) { | |||
return _this3._handlePopperPlacementChange(data); | |||
} | |||
}; | |||
return _objectSpread2({}, defaultBsConfig, {}, this.config.popperConfig); | |||
}; | |||
_proto._getOffset = function _getOffset() { | |||
var _this4 = this; | |||
var offset = {}; | |||
if (typeof this.config.offset === 'function') { | |||
offset.fn = function (data) { | |||
data.offsets = _objectSpread2({}, data.offsets, {}, _this4.config.offset(data.offsets, _this4.element) || {}); | |||
return data; | |||
}; | |||
} else { | |||
offset.offset = this.config.offset; | |||
} | |||
return offset; | |||
}; | |||
_proto._getContainer = function _getContainer() { | |||
if (this.config.container === false) { | |||
return document.body; | |||
} | |||
if (Util.isElement(this.config.container)) { | |||
return $(this.config.container); | |||
} | |||
return $(document).find(this.config.container); | |||
}; | |||
_proto._getAttachment = function _getAttachment(placement) { | |||
return AttachmentMap[placement.toUpperCase()]; | |||
}; | |||
_proto._setListeners = function _setListeners() { | |||
var _this5 = this; | |||
var triggers = this.config.trigger.split(' '); | |||
triggers.forEach(function (trigger) { | |||
if (trigger === 'click') { | |||
$(_this5.element).on(_this5.constructor.Event.CLICK, _this5.config.selector, function (event) { | |||
return _this5.toggle(event); | |||
}); | |||
} else if (trigger !== Trigger.MANUAL) { | |||
var eventIn = trigger === Trigger.HOVER ? _this5.constructor.Event.MOUSEENTER : _this5.constructor.Event.FOCUSIN; | |||
var eventOut = trigger === Trigger.HOVER ? _this5.constructor.Event.MOUSELEAVE : _this5.constructor.Event.FOCUSOUT; | |||
$(_this5.element).on(eventIn, _this5.config.selector, function (event) { | |||
return _this5._enter(event); | |||
}).on(eventOut, _this5.config.selector, function (event) { | |||
return _this5._leave(event); | |||
}); | |||
} | |||
}); | |||
this._hideModalHandler = function () { | |||
if (_this5.element) { | |||
_this5.hide(); | |||
} | |||
}; | |||
$(this.element).closest('.modal').on('hide.bs.modal', this._hideModalHandler); | |||
if (this.config.selector) { | |||
this.config = _objectSpread2({}, this.config, { | |||
trigger: 'manual', | |||
selector: '' | |||
}); | |||
} else { | |||
this._fixTitle(); | |||
} | |||
}; | |||
_proto._fixTitle = function _fixTitle() { | |||
var titleType = typeof this.element.getAttribute('data-original-title'); | |||
if (this.element.getAttribute('title') || titleType !== 'string') { | |||
this.element.setAttribute('data-original-title', this.element.getAttribute('title') || ''); | |||
this.element.setAttribute('title', ''); | |||
} | |||
}; | |||
_proto._enter = function _enter(event, context) { | |||
var dataKey = this.constructor.DATA_KEY; | |||
context = context || $(event.currentTarget).data(dataKey); | |||
if (!context) { | |||
context = new this.constructor(event.currentTarget, this._getDelegateConfig()); | |||
$(event.currentTarget).data(dataKey, context); | |||
} | |||
if (event) { | |||
context._activeTrigger[event.type === 'focusin' ? Trigger.FOCUS : Trigger.HOVER] = true; | |||
} | |||
if ($(context.getTipElement()).hasClass(ClassName.SHOW) || context._hoverState === HoverState.SHOW) { | |||
context._hoverState = HoverState.SHOW; | |||
return; | |||
} | |||
clearTimeout(context._timeout); | |||
context._hoverState = HoverState.SHOW; | |||
if (!context.config.delay || !context.config.delay.show) { | |||
context.show(); | |||
return; | |||
} | |||
context._timeout = setTimeout(function () { | |||
if (context._hoverState === HoverState.SHOW) { | |||
context.show(); | |||
} | |||
}, context.config.delay.show); | |||
}; | |||
_proto._leave = function _leave(event, context) { | |||
var dataKey = this.constructor.DATA_KEY; | |||
context = context || $(event.currentTarget).data(dataKey); | |||
if (!context) { | |||
context = new this.constructor(event.currentTarget, this._getDelegateConfig()); | |||
$(event.currentTarget).data(dataKey, context); | |||
} | |||
if (event) { | |||
context._activeTrigger[event.type === 'focusout' ? Trigger.FOCUS : Trigger.HOVER] = false; | |||
} | |||
if (context._isWithActiveTrigger()) { | |||
return; | |||
} | |||
clearTimeout(context._timeout); | |||
context._hoverState = HoverState.OUT; | |||
if (!context.config.delay || !context.config.delay.hide) { | |||
context.hide(); | |||
return; | |||
} | |||
context._timeout = setTimeout(function () { | |||
if (context._hoverState === HoverState.OUT) { | |||
context.hide(); | |||
} | |||
}, context.config.delay.hide); | |||
}; | |||
_proto._isWithActiveTrigger = function _isWithActiveTrigger() { | |||
for (var trigger in this._activeTrigger) { | |||
if (this._activeTrigger[trigger]) { | |||
return true; | |||
} | |||
} | |||
return false; | |||
}; | |||
_proto._getConfig = function _getConfig(config) { | |||
var dataAttributes = $(this.element).data(); | |||
Object.keys(dataAttributes).forEach(function (dataAttr) { | |||
if (DISALLOWED_ATTRIBUTES.indexOf(dataAttr) !== -1) { | |||
delete dataAttributes[dataAttr]; | |||
} | |||
}); | |||
config = _objectSpread2({}, this.constructor.Default, {}, dataAttributes, {}, typeof config === 'object' && config ? config : {}); | |||
if (typeof config.delay === 'number') { | |||
config.delay = { | |||
show: config.delay, | |||
hide: config.delay | |||
}; | |||
} | |||
if (typeof config.title === 'number') { | |||
config.title = config.title.toString(); | |||
} | |||
if (typeof config.content === 'number') { | |||
config.content = config.content.toString(); | |||
} | |||
Util.typeCheckConfig(NAME, config, this.constructor.DefaultType); | |||
if (config.sanitize) { | |||
config.template = sanitizeHtml(config.template, config.whiteList, config.sanitizeFn); | |||
} | |||
return config; | |||
}; | |||
_proto._getDelegateConfig = function _getDelegateConfig() { | |||
var config = {}; | |||
if (this.config) { | |||
for (var key in this.config) { | |||
if (this.constructor.Default[key] !== this.config[key]) { | |||
config[key] = this.config[key]; | |||
} | |||
} | |||
} | |||
return config; | |||
}; | |||
_proto._cleanTipClass = function _cleanTipClass() { | |||
var $tip = $(this.getTipElement()); | |||
var tabClass = $tip.attr('class').match(BSCLS_PREFIX_REGEX); | |||
if (tabClass !== null && tabClass.length) { | |||
$tip.removeClass(tabClass.join('')); | |||
} | |||
}; | |||
_proto._handlePopperPlacementChange = function _handlePopperPlacementChange(popperData) { | |||
var popperInstance = popperData.instance; | |||
this.tip = popperInstance.popper; | |||
this._cleanTipClass(); | |||
this.addAttachmentClass(this._getAttachment(popperData.placement)); | |||
}; | |||
_proto._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) { | |||
return this.each(function () { | |||
var data = $(this).data(DATA_KEY); | |||
var _config = typeof config === 'object' && config; | |||
if (!data && /dispose|hide/.test(config)) { | |||
return; | |||
} | |||
if (!data) { | |||
data = new Tooltip(this, _config); | |||
$(this).data(DATA_KEY, data); | |||
} | |||
if (typeof config === 'string') { | |||
if (typeof data[config] === 'undefined') { | |||
throw new TypeError("No method named \"" + config + "\""); | |||
} | |||
data[config](); | |||
} | |||
}); | |||
}; | |||
_createClass(Tooltip, null, [{ | |||
key: "VERSION", | |||
get: function get() { | |||
return VERSION; | |||
} | |||
}, { | |||
key: "Default", | |||
get: function get() { | |||
return Default; | |||
} | |||
}, { | |||
key: "NAME", | |||
get: function get() { | |||
return NAME; | |||
} | |||
}, { | |||
key: "DATA_KEY", | |||
get: function get() { | |||
return DATA_KEY; | |||
} | |||
}, { | |||
key: "Event", | |||
get: function get() { | |||
return Event; | |||
} | |||
}, { | |||
key: "EVENT_KEY", | |||
get: function get() { | |||
return EVENT_KEY; | |||
} | |||
}, { | |||
key: "DefaultType", | |||
get: function get() { | |||
return DefaultType; | |||
} | |||
}]); | |||
return Tooltip; | |||
}(); | |||
/** | |||
* ------------------------------------------------------------------------ | |||
* jQuery | |||
* ------------------------------------------------------------------------ | |||
*/ | |||
$.fn[NAME] = Tooltip._jQueryInterface; | |||
$.fn[NAME].Constructor = Tooltip; | |||
$.fn[NAME].noConflict = function () { | |||
$.fn[NAME] = JQUERY_NO_CONFLICT; | |||
return Tooltip._jQueryInterface; | |||
}; | |||
return Tooltip; | |||
}))); | |||
//# sourceMappingURL=tooltip.js.map |
@ -0,0 +1,189 @@ | |||
/*! | |||
* Bootstrap util.js v4.4.1 (https://getbootstrap.com/) | |||
* Copyright 2011-2019 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors) | |||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) | |||
*/ | |||
(function (global, factory) { | |||
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('jquery')) : | |||
typeof define === 'function' && define.amd ? define(['jquery'], factory) : | |||
(global = global || self, global.Util = factory(global.jQuery)); | |||
}(this, (function ($) { 'use strict'; | |||
$ = $ && $.hasOwnProperty('default') ? $['default'] : $; | |||
/** | |||
* -------------------------------------------------------------------------- | |||
* Bootstrap (v4.4.1): util.js | |||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) | |||
* -------------------------------------------------------------------------- | |||
*/ | |||
/** | |||
* ------------------------------------------------------------------------ | |||
* Private TransitionEnd Helpers | |||
* ------------------------------------------------------------------------ | |||
*/ | |||
var TRANSITION_END = 'transitionend'; | |||
var MAX_UID = 1000000; | |||
var MILLISECONDS_MULTIPLIER = 1000; // Shoutout AngusCroll (https://goo.gl/pxwQGp) | |||
function toType(obj) { | |||
return {}.toString.call(obj).match(/\s([a-z]+)/i)[1].toLowerCase(); | |||
} | |||
function getSpecialTransitionEndEvent() { | |||
return { | |||
bindType: TRANSITION_END, | |||
delegateType: TRANSITION_END, | |||
handle: function handle(event) { | |||
if ($(event.target).is(this)) { | |||
return event.handleObj.handler.apply(this, arguments); // eslint-disable-line prefer-rest-params | |||
} | |||
return undefined; // eslint-disable-line no-undefined | |||
} | |||
}; | |||
} | |||
function transitionEndEmulator(duration) { | |||
var _this = this; | |||
var called = false; | |||
$(this).one(Util.TRANSITION_END, function () { | |||
called = true; | |||
}); | |||
setTimeout(function () { | |||
if (!called) { | |||
Util.triggerTransitionEnd(_this); | |||
} | |||
}, duration); | |||
return this; | |||
} | |||
function setTransitionEndSupport() { | |||
$.fn.emulateTransitionEnd = transitionEndEmulator; | |||
$.event.special[Util.TRANSITION_END] = getSpecialTransitionEndEvent(); | |||
} | |||
/** | |||
* -------------------------------------------------------------------------- | |||
* Public Util Api | |||
* -------------------------------------------------------------------------- | |||
*/ | |||
var Util = { | |||
TRANSITION_END: 'bsTransitionEnd', | |||
getUID: function getUID(prefix) { | |||
do { | |||
// eslint-disable-next-line no-bitwise | |||
prefix += ~~(Math.random() * MAX_UID); // "~~" acts like a faster Math.floor() here | |||
} while (document.getElementById(prefix)); | |||
return prefix; | |||
}, | |||
getSelectorFromElement: function getSelectorFromElement(element) { | |||
var selector = element.getAttribute('data-target'); | |||
if (!selector || selector === '#') { | |||
var hrefAttr = element.getAttribute('href'); | |||
selector = hrefAttr && hrefAttr !== '#' ? hrefAttr.trim() : ''; | |||
} | |||
try { | |||
return document.querySelector(selector) ? selector : null; | |||
} catch (err) { | |||
return null; | |||
} | |||
}, | |||
getTransitionDurationFromElement: function getTransitionDurationFromElement(element) { | |||
if (!element) { | |||
return 0; | |||
} // Get transition-duration of the element | |||
var transitionDuration = $(element).css('transition-duration'); | |||
var transitionDelay = $(element).css('transition-delay'); | |||
var floatTransitionDuration = parseFloat(transitionDuration); | |||
var floatTransitionDelay = parseFloat(transitionDelay); // Return 0 if element or transition duration is not found | |||
if (!floatTransitionDuration && !floatTransitionDelay) { | |||
return 0; | |||
} // If multiple durations are defined, take the first | |||
transitionDuration = transitionDuration.split(',')[0]; | |||
transitionDelay = transitionDelay.split(',')[0]; | |||
return (parseFloat(transitionDuration) + parseFloat(transitionDelay)) * MILLISECONDS_MULTIPLIER; | |||
}, | |||
reflow: function reflow(element) { | |||
return element.offsetHeight; | |||
}, | |||
triggerTransitionEnd: function triggerTransitionEnd(element) { | |||
$(element).trigger(TRANSITION_END); | |||
}, | |||
// TODO: Remove in v5 | |||
supportsTransitionEnd: function supportsTransitionEnd() { | |||
return Boolean(TRANSITION_END); | |||
}, | |||
isElement: function isElement(obj) { | |||
return (obj[0] || obj).nodeType; | |||
}, | |||
typeCheckConfig: function typeCheckConfig(componentName, config, configTypes) { | |||
for (var property in configTypes) { | |||
if (Object.prototype.hasOwnProperty.call(configTypes, property)) { | |||
var expectedTypes = configTypes[property]; | |||
var value = config[property]; | |||
var valueType = value && Util.isElement(value) ? 'element' : toType(value); | |||
if (!new RegExp(expectedTypes).test(valueType)) { | |||
throw new Error(componentName.toUpperCase() + ": " + ("Option \"" + property + "\" provided type \"" + valueType + "\" ") + ("but expected type \"" + expectedTypes + "\".")); | |||
} | |||
} | |||
} | |||
}, | |||
findShadowRoot: function findShadowRoot(element) { | |||
if (!document.documentElement.attachShadow) { | |||
return null; | |||
} // Can find the shadow root otherwise it'll return the document | |||
if (typeof element.getRootNode === 'function') { | |||
var root = element.getRootNode(); | |||
return root instanceof ShadowRoot ? root : null; | |||
} | |||
if (element instanceof ShadowRoot) { | |||
return element; | |||
} // when we don't find a shadow root | |||
if (!element.parentNode) { | |||
return null; | |||
} | |||
return Util.findShadowRoot(element.parentNode); | |||
}, | |||
jQueryDetection: function jQueryDetection() { | |||
if (typeof $ === 'undefined') { | |||
throw new TypeError('Bootstrap\'s JavaScript requires jQuery. jQuery must be included before Bootstrap\'s JavaScript.'); | |||
} | |||
var version = $.fn.jquery.split(' ')[0].split('.'); | |||
var minMajor = 1; | |||
var ltMajor = 2; | |||
var minMinor = 9; | |||
var minPatch = 1; | |||
var maxMajor = 4; | |||
if (version[0] < ltMajor && version[1] < minMinor || version[0] === minMajor && version[1] === minMinor && version[2] < minPatch || version[0] >= maxMajor) { | |||
throw new Error('Bootstrap\'s JavaScript requires at least jQuery v1.9.1 but less than v4.0.0'); | |||
} | |||
} | |||
}; | |||
Util.jQueryDetection(); | |||
setTransitionEndSupport(); | |||
return Util; | |||
}))); | |||
//# sourceMappingURL=util.js.map |
@ -0,0 +1,179 @@ | |||
/** | |||
* -------------------------------------------------------------------------- | |||
* Bootstrap (v4.4.1): alert.js | |||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) | |||
* -------------------------------------------------------------------------- | |||
*/ | |||
import $ from 'jquery' | |||
import Util from './util' | |||
/** | |||
* ------------------------------------------------------------------------ | |||
* Constants | |||
* ------------------------------------------------------------------------ | |||
*/ | |||
const NAME = 'alert' | |||
const VERSION = '4.4.1' | |||
const DATA_KEY = 'bs.alert' | |||
const EVENT_KEY = `.${DATA_KEY}` | |||
const DATA_API_KEY = '.data-api' | |||
const JQUERY_NO_CONFLICT = $.fn[NAME] | |||
const Selector = { | |||
DISMISS : '[data-dismiss="alert"]' | |||
} | |||
const Event = { | |||
CLOSE : `close${EVENT_KEY}`, | |||
CLOSED : `closed${EVENT_KEY}`, | |||
CLICK_DATA_API : `click${EVENT_KEY}${DATA_API_KEY}` | |||
} | |||
const ClassName = { | |||
ALERT : 'alert', | |||
FADE : 'fade', | |||
SHOW : 'show' | |||
} | |||
/** | |||
* ------------------------------------------------------------------------ | |||
* Class Definition | |||
* ------------------------------------------------------------------------ | |||
*/ | |||
class Alert { | |||
constructor(element) { | |||
this._element = element | |||
} | |||
// Getters | |||
static get VERSION() { | |||
return VERSION | |||
} | |||
// Public | |||
close(element) { | |||
let rootElement = this._element | |||
if (element) { | |||
rootElement = this._getRootElement(element) | |||
} | |||
const customEvent = this._triggerCloseEvent(rootElement) | |||
if (customEvent.isDefaultPrevented()) { | |||
return | |||
} | |||
this._removeElement(rootElement) | |||
} | |||
dispose() { | |||
$.removeData(this._element, DATA_KEY) | |||
this._element = null | |||
} | |||
// Private | |||
_getRootElement(element) { | |||
const selector = Util.getSelectorFromElement(element) | |||
let parent = false | |||
if (selector) { | |||
parent = document.querySelector(selector) | |||
} | |||
if (!parent) { | |||
parent = $(element).closest(`.${ClassName.ALERT}`)[0] | |||
} | |||
return parent | |||
} | |||
_triggerCloseEvent(element) { | |||
const closeEvent = $.Event(Event.CLOSE) | |||
$(element).trigger(closeEvent) | |||
return closeEvent | |||
} | |||
_removeElement(element) { | |||
$(element).removeClass(ClassName.SHOW) | |||
if (!$(element).hasClass(ClassName.FADE)) { | |||
this._destroyElement(element) | |||
return | |||
} | |||
const transitionDuration = Util.getTransitionDurationFromElement(element) | |||
$(element) | |||
.one(Util.TRANSITION_END, (event) => this._destroyElement(element, event)) | |||
.emulateTransitionEnd(transitionDuration) | |||
} | |||
_destroyElement(element) { | |||
$(element) | |||
.detach() | |||
.trigger(Event.CLOSED) | |||
.remove() | |||
} | |||
// Static | |||
static _jQueryInterface(config) { | |||
return this.each(function () { | |||
const $element = $(this) | |||
let data = $element.data(DATA_KEY) | |||
if (!data) { | |||
data = new Alert(this) | |||
$element.data(DATA_KEY, data) | |||
} | |||
if (config === 'close') { | |||
data[config](this) | |||
} | |||
}) | |||
} | |||
static _handleDismiss(alertInstance) { | |||
return function (event) { | |||
if (event) { | |||
event.preventDefault() | |||
} | |||
alertInstance.close(this) | |||
} | |||
} | |||
} | |||
/** | |||
* ------------------------------------------------------------------------ | |||
* Data Api implementation | |||
* ------------------------------------------------------------------------ | |||
*/ | |||
$(document).on( | |||
Event.CLICK_DATA_API, | |||
Selector.DISMISS, | |||
Alert._handleDismiss(new Alert()) | |||
) | |||
/** | |||
* ------------------------------------------------------------------------ | |||
* jQuery | |||
* ------------------------------------------------------------------------ | |||
*/ | |||
$.fn[NAME] = Alert._jQueryInterface | |||
$.fn[NAME].Constructor = Alert | |||
$.fn[NAME].noConflict = () => { | |||
$.fn[NAME] = JQUERY_NO_CONFLICT | |||
return Alert._jQueryInterface | |||
} | |||
export default Alert |
@ -0,0 +1,213 @@ | |||
/** | |||
* -------------------------------------------------------------------------- | |||
* Bootstrap (v4.4.1): button.js | |||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) | |||
* -------------------------------------------------------------------------- | |||
*/ | |||
import $ from 'jquery' | |||
/** | |||
* ------------------------------------------------------------------------ | |||
* Constants | |||
* ------------------------------------------------------------------------ | |||
*/ | |||
const NAME = 'button' | |||
const VERSION = '4.4.1' | |||
const DATA_KEY = 'bs.button' | |||
const EVENT_KEY = `.${DATA_KEY}` | |||
const DATA_API_KEY = '.data-api' | |||
const JQUERY_NO_CONFLICT = $.fn[NAME] | |||
const ClassName = { | |||
ACTIVE : 'active', | |||
BUTTON : 'btn', | |||
FOCUS : 'focus' | |||
} | |||
const Selector = { | |||
DATA_TOGGLE_CARROT : '[data-toggle^="button"]', | |||
DATA_TOGGLES : '[data-toggle="buttons"]', | |||
DATA_TOGGLE : '[data-toggle="button"]', | |||
DATA_TOGGLES_BUTTONS : '[data-toggle="buttons"] .btn', | |||
INPUT : 'input:not([type="hidden"])', | |||
ACTIVE : '.active', | |||
BUTTON : '.btn' | |||
} | |||
const 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}`, | |||
LOAD_DATA_API : `load${EVENT_KEY}${DATA_API_KEY}` | |||
} | |||
/** | |||
* ------------------------------------------------------------------------ | |||
* Class Definition | |||
* ------------------------------------------------------------------------ | |||
*/ | |||
class Button { | |||
constructor(element) { | |||
this._element = element | |||
} | |||
// Getters | |||
static get VERSION() { | |||
return VERSION | |||
} | |||
// Public | |||
toggle() { | |||
let triggerChangeEvent = true | |||
let addAriaPressed = true | |||
const rootElement = $(this._element).closest( | |||
Selector.DATA_TOGGLES | |||
)[0] | |||
if (rootElement) { | |||
const input = this._element.querySelector(Selector.INPUT) | |||
if (input) { | |||
if (input.type === 'radio') { | |||
if (input.checked && | |||
this._element.classList.contains(ClassName.ACTIVE)) { | |||
triggerChangeEvent = false | |||
} else { | |||
const activeElement = rootElement.querySelector(Selector.ACTIVE) | |||
if (activeElement) { | |||
$(activeElement).removeClass(ClassName.ACTIVE) | |||
} | |||
} | |||
} else if (input.type === 'checkbox') { | |||
if (this._element.tagName === 'LABEL' && input.checked === this._element.classList.contains(ClassName.ACTIVE)) { | |||
triggerChangeEvent = false | |||
} | |||
} else { | |||
// if it's not a radio button or checkbox don't add a pointless/invalid checked property to the input | |||
triggerChangeEvent = false | |||
} | |||
if (triggerChangeEvent) { | |||
input.checked = !this._element.classList.contains(ClassName.ACTIVE) | |||
$(input).trigger('change') | |||
} | |||
input.focus() | |||
addAriaPressed = false | |||
} | |||
} | |||
if (!(this._element.hasAttribute('disabled') || this._element.classList.contains('disabled'))) { | |||
if (addAriaPressed) { | |||
this._element.setAttribute('aria-pressed', | |||
!this._element.classList.contains(ClassName.ACTIVE)) | |||
} | |||
if (triggerChangeEvent) { | |||
$(this._element).toggleClass(ClassName.ACTIVE) | |||
} | |||
} | |||
} | |||
dispose() { | |||
$.removeData(this._element, DATA_KEY) | |||
this._element = null | |||
} | |||
// Static | |||
static _jQueryInterface(config) { | |||
return this.each(function () { | |||
let data = $(this).data(DATA_KEY) | |||
if (!data) { | |||
data = new Button(this) | |||
$(this).data(DATA_KEY, data) | |||
} | |||
if (config === 'toggle') { | |||
data[config]() | |||
} | |||
}) | |||
} | |||
} | |||
/** | |||
* ------------------------------------------------------------------------ | |||
* Data Api implementation | |||
* ------------------------------------------------------------------------ | |||
*/ | |||
$(document) | |||
.on(Event.CLICK_DATA_API, Selector.DATA_TOGGLE_CARROT, (event) => { | |||
let button = event.target | |||
if (!$(button).hasClass(ClassName.BUTTON)) { | |||
button = $(button).closest(Selector.BUTTON)[0] | |||
} | |||
if (!button || button.hasAttribute('disabled') || button.classList.contains('disabled')) { | |||
event.preventDefault() // work around Firefox bug #1540995 | |||
} else { | |||
const inputBtn = button.querySelector(Selector.INPUT) | |||
if (inputBtn && (inputBtn.hasAttribute('disabled') || inputBtn.classList.contains('disabled'))) { | |||
event.preventDefault() // work around Firefox bug #1540995 | |||
return | |||
} | |||
Button._jQueryInterface.call($(button), 'toggle') | |||
} | |||
}) | |||
.on(Event.FOCUS_BLUR_DATA_API, Selector.DATA_TOGGLE_CARROT, (event) => { | |||
const button = $(event.target).closest(Selector.BUTTON)[0] | |||
$(button).toggleClass(ClassName.FOCUS, /^focus(in)?$/.test(event.type)) | |||
}) | |||
$(window).on(Event.LOAD_DATA_API, () => { | |||
// ensure correct active class is set to match the controls' actual values/states | |||
// find all checkboxes/readio buttons inside data-toggle groups | |||
let buttons = [].slice.call(document.querySelectorAll(Selector.DATA_TOGGLES_BUTTONS)) | |||
for (let i = 0, len = buttons.length; i < len; i++) { | |||
const button = buttons[i] | |||
const input = button.querySelector(Selector.INPUT) | |||
if (input.checked || input.hasAttribute('checked')) { | |||
button.classList.add(ClassName.ACTIVE) | |||
} else { | |||
button.classList.remove(ClassName.ACTIVE) | |||
} | |||
} | |||
// find all button toggles | |||
buttons = [].slice.call(document.querySelectorAll(Selector.DATA_TOGGLE)) | |||
for (let i = 0, len = buttons.length; i < len; i++) { | |||
const button = buttons[i] | |||
if (button.getAttribute('aria-pressed') === 'true') { | |||
button.classList.add(ClassName.ACTIVE) | |||
} else { | |||
button.classList.remove(ClassName.ACTIVE) | |||
} | |||
} | |||
}) | |||
/** | |||
* ------------------------------------------------------------------------ | |||
* jQuery | |||
* ------------------------------------------------------------------------ | |||
*/ | |||
$.fn[NAME] = Button._jQueryInterface | |||
$.fn[NAME].Constructor = Button | |||
$.fn[NAME].noConflict = () => { | |||
$.fn[NAME] = JQUERY_NO_CONFLICT | |||
return Button._jQueryInterface | |||
} | |||
export default Button |
@ -0,0 +1,608 @@ | |||
/** | |||
* -------------------------------------------------------------------------- | |||
* Bootstrap (v4.4.1): carousel.js | |||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) | |||
* -------------------------------------------------------------------------- | |||
*/ | |||
import $ from 'jquery' | |||
import Util from './util' | |||
/** | |||
* ------------------------------------------------------------------------ | |||
* Constants | |||
* ------------------------------------------------------------------------ | |||
*/ | |||
const NAME = 'carousel' | |||
const VERSION = '4.4.1' | |||
const DATA_KEY = 'bs.carousel' | |||
const EVENT_KEY = `.${DATA_KEY}` | |||
const DATA_API_KEY = '.data-api' | |||
const JQUERY_NO_CONFLICT = $.fn[NAME] | |||
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 SWIPE_THRESHOLD = 40 | |||
const Default = { | |||
interval : 5000, | |||
keyboard : true, | |||
slide : false, | |||
pause : 'hover', | |||
wrap : true, | |||
touch : true | |||
} | |||
const DefaultType = { | |||
interval : '(number|boolean)', | |||
keyboard : 'boolean', | |||
slide : '(boolean|string)', | |||
pause : '(string|boolean)', | |||
wrap : 'boolean', | |||
touch : 'boolean' | |||
} | |||
const Direction = { | |||
NEXT : 'next', | |||
PREV : 'prev', | |||
LEFT : 'left', | |||
RIGHT : 'right' | |||
} | |||
const Event = { | |||
SLIDE : `slide${EVENT_KEY}`, | |||
SLID : `slid${EVENT_KEY}`, | |||
KEYDOWN : `keydown${EVENT_KEY}`, | |||
MOUSEENTER : `mouseenter${EVENT_KEY}`, | |||
MOUSELEAVE : `mouseleave${EVENT_KEY}`, | |||
TOUCHSTART : `touchstart${EVENT_KEY}`, | |||
TOUCHMOVE : `touchmove${EVENT_KEY}`, | |||
TOUCHEND : `touchend${EVENT_KEY}`, | |||
POINTERDOWN : `pointerdown${EVENT_KEY}`, | |||
POINTERUP : `pointerup${EVENT_KEY}`, | |||
DRAG_START : `dragstart${EVENT_KEY}`, | |||
LOAD_DATA_API : `load${EVENT_KEY}${DATA_API_KEY}`, | |||
CLICK_DATA_API : `click${EVENT_KEY}${DATA_API_KEY}` | |||
} | |||
const ClassName = { | |||
CAROUSEL : 'carousel', | |||
ACTIVE : 'active', | |||
SLIDE : 'slide', | |||
RIGHT : 'carousel-item-right', | |||
LEFT : 'carousel-item-left', | |||
NEXT : 'carousel-item-next', | |||
PREV : 'carousel-item-prev', | |||
ITEM : 'carousel-item', | |||
POINTER_EVENT : 'pointer-event' | |||
} | |||
const Selector = { | |||
ACTIVE : '.active', | |||
ACTIVE_ITEM : '.active.carousel-item', | |||
ITEM : '.carousel-item', | |||
ITEM_IMG : '.carousel-item img', | |||
NEXT_PREV : '.carousel-item-next, .carousel-item-prev', | |||
INDICATORS : '.carousel-indicators', | |||
DATA_SLIDE : '[data-slide], [data-slide-to]', | |||
DATA_RIDE : '[data-ride="carousel"]' | |||
} | |||
const PointerType = { | |||
TOUCH : 'touch', | |||
PEN : 'pen' | |||
} | |||
/** | |||
* ------------------------------------------------------------------------ | |||
* Class Definition | |||
* ------------------------------------------------------------------------ | |||
*/ | |||
class Carousel { | |||
constructor(element, config) { | |||
this._items = null | |||
this._interval = null | |||
this._activeElement = null | |||
this._isPaused = false | |||
this._isSliding = false | |||
this.touchTimeout = null | |||
this.touchStartX = 0 | |||
this.touchDeltaX = 0 | |||
this._config = this._getConfig(config) | |||
this._element = element | |||
this._indicatorsElement = this._element.querySelector(Selector.INDICATORS) | |||
this._touchSupported = 'ontouchstart' in document.documentElement || navigator.maxTouchPoints > 0 | |||
this._pointerEvent = Boolean(window.PointerEvent || window.MSPointerEvent) | |||
this._addEventListeners() | |||
} | |||
// Getters | |||
static get VERSION() { | |||
return VERSION | |||
} | |||
static get Default() { | |||
return Default | |||
} | |||
// Public | |||
next() { | |||
if (!this._isSliding) { | |||
this._slide(Direction.NEXT) | |||
} | |||
} | |||
nextWhenVisible() { | |||
// Don't call next when the page isn't visible | |||
// or the carousel or its parent isn't visible | |||
if (!document.hidden && | |||
($(this._element).is(':visible') && $(this._element).css('visibility') !== 'hidden')) { | |||
this.next() | |||
} | |||
} | |||
prev() { | |||
if (!this._isSliding) { | |||
this._slide(Direction.PREV) | |||
} | |||
} | |||
pause(event) { | |||
if (!event) { | |||
this._isPaused = true | |||
} | |||
if (this._element.querySelector(Selector.NEXT_PREV)) { | |||
Util.triggerTransitionEnd(this._element) | |||
this.cycle(true) | |||
} | |||
clearInterval(this._interval) | |||
this._interval = null | |||
} | |||
cycle(event) { | |||
if (!event) { | |||
this._isPaused = false | |||
} | |||
if (this._interval) { | |||
clearInterval(this._interval) | |||
this._interval = null | |||
} | |||
if (this._config.interval && !this._isPaused) { | |||
this._interval = setInterval( | |||
(document.visibilityState ? this.nextWhenVisible : this.next).bind(this), | |||
this._config.interval | |||
) | |||
} | |||
} | |||
to(index) { | |||
this._activeElement = this._element.querySelector(Selector.ACTIVE_ITEM) | |||
const activeIndex = this._getItemIndex(this._activeElement) | |||
if (index > this._items.length - 1 || index < 0) { | |||
return | |||
} | |||
if (this._isSliding) { | |||
$(this._element).one(Event.SLID, () => this.to(index)) | |||
return | |||
} | |||
if (activeIndex === index) { | |||
this.pause() | |||
this.cycle() | |||
return | |||
} | |||
const direction = index > activeIndex | |||
? Direction.NEXT | |||
: Direction.PREV | |||
this._slide(direction, this._items[index]) | |||
} | |||
dispose() { | |||
$(this._element).off(EVENT_KEY) | |||
$.removeData(this._element, DATA_KEY) | |||
this._items = null | |||
this._config = null | |||
this._element = null | |||
this._interval = null | |||
this._isPaused = null | |||
this._isSliding = null | |||
this._activeElement = null | |||
this._indicatorsElement = null | |||
} | |||
// Private | |||
_getConfig(config) { | |||
config = { | |||
...Default, | |||
...config | |||
} | |||
Util.typeCheckConfig(NAME, config, DefaultType) | |||
return config | |||
} | |||
_handleSwipe() { | |||
const absDeltax = Math.abs(this.touchDeltaX) | |||
if (absDeltax <= SWIPE_THRESHOLD) { | |||
return | |||
} | |||
const direction = absDeltax / this.touchDeltaX | |||
this.touchDeltaX = 0 | |||
// swipe left | |||
if (direction > 0) { | |||
this.prev() | |||
} | |||
// swipe right | |||
if (direction < 0) { | |||
this.next() | |||
} | |||
} | |||
_addEventListeners() { | |||
if (this._config.keyboard) { | |||
$(this._element) | |||
.on(Event.KEYDOWN, (event) => this._keydown(event)) | |||
} | |||
if (this._config.pause === 'hover') { | |||
$(this._element) | |||
.on(Event.MOUSEENTER, (event) => this.pause(event)) | |||
.on(Event.MOUSELEAVE, (event) => this.cycle(event)) | |||
} | |||
if (this._config.touch) { | |||
this._addTouchEventListeners() | |||
} | |||
} | |||
_addTouchEventListeners() { | |||
if (!this._touchSupported) { | |||
return | |||
} | |||
const start = (event) => { | |||
if (this._pointerEvent && PointerType[event.originalEvent.pointerType.toUpperCase()]) { | |||
this.touchStartX = event.originalEvent.clientX | |||
} else if (!this._pointerEvent) { | |||
this.touchStartX = event.originalEvent.touches[0].clientX | |||
} | |||
} | |||
const move = (event) => { | |||
// ensure swiping with one touch and not pinching | |||
if (event.originalEvent.touches && event.originalEvent.touches.length > 1) { | |||
this.touchDeltaX = 0 | |||
} else { | |||
this.touchDeltaX = event.originalEvent.touches[0].clientX - this.touchStartX | |||
} | |||
} | |||
const end = (event) => { | |||
if (this._pointerEvent && PointerType[event.originalEvent.pointerType.toUpperCase()]) { | |||
this.touchDeltaX = event.originalEvent.clientX - this.touchStartX | |||
} | |||
this._handleSwipe() | |||
if (this._config.pause === 'hover') { | |||
// 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.pause() | |||
if (this.touchTimeout) { | |||
clearTimeout(this.touchTimeout) | |||
} | |||
this.touchTimeout = setTimeout((event) => this.cycle(event), TOUCHEVENT_COMPAT_WAIT + this._config.interval) | |||
} | |||
} | |||
$(this._element.querySelectorAll(Selector.ITEM_IMG)).on(Event.DRAG_START, (e) => e.preventDefault()) | |||
if (this._pointerEvent) { | |||
$(this._element).on(Event.POINTERDOWN, (event) => start(event)) | |||
$(this._element).on(Event.POINTERUP, (event) => end(event)) | |||
this._element.classList.add(ClassName.POINTER_EVENT) | |||
} else { | |||
$(this._element).on(Event.TOUCHSTART, (event) => start(event)) | |||
$(this._element).on(Event.TOUCHMOVE, (event) => move(event)) | |||
$(this._element).on(Event.TOUCHEND, (event) => end(event)) | |||
} | |||
} | |||
_keydown(event) { | |||
if (/input|textarea/i.test(event.target.tagName)) { | |||
return | |||
} | |||
switch (event.which) { | |||
case ARROW_LEFT_KEYCODE: | |||
event.preventDefault() | |||
this.prev() | |||
break | |||
case ARROW_RIGHT_KEYCODE: | |||
event.preventDefault() | |||
this.next() | |||
break | |||
default: | |||
} | |||
} | |||
_getItemIndex(element) { | |||
this._items = element && element.parentNode | |||
? [].slice.call(element.parentNode.querySelectorAll(Selector.ITEM)) | |||
: [] | |||
return this._items.indexOf(element) | |||
} | |||
_getItemByDirection(direction, activeElement) { | |||
const isNextDirection = direction === Direction.NEXT | |||
const isPrevDirection = direction === Direction.PREV | |||
const activeIndex = this._getItemIndex(activeElement) | |||
const lastItemIndex = this._items.length - 1 | |||
const isGoingToWrap = isPrevDirection && activeIndex === 0 || | |||
isNextDirection && activeIndex === lastItemIndex | |||
if (isGoingToWrap && !this._config.wrap) { | |||
return activeElement | |||
} | |||
const delta = direction === Direction.PREV ? -1 : 1 | |||
const itemIndex = (activeIndex + delta) % this._items.length | |||
return itemIndex === -1 | |||
? this._items[this._items.length - 1] : this._items[itemIndex] | |||
} | |||
_triggerSlideEvent(relatedTarget, eventDirectionName) { | |||
const targetIndex = this._getItemIndex(relatedTarget) | |||
const fromIndex = this._getItemIndex(this._element.querySelector(Selector.ACTIVE_ITEM)) | |||
const slideEvent = $.Event(Event.SLIDE, { | |||
relatedTarget, | |||
direction: eventDirectionName, | |||
from: fromIndex, | |||
to: targetIndex | |||
}) | |||
$(this._element).trigger(slideEvent) | |||
return slideEvent | |||
} | |||
_setActiveIndicatorElement(element) { | |||
if (this._indicatorsElement) { | |||
const indicators = [].slice.call(this._indicatorsElement.querySelectorAll(Selector.ACTIVE)) | |||
$(indicators) | |||
.removeClass(ClassName.ACTIVE) | |||
const nextIndicator = this._indicatorsElement.children[ | |||
this._getItemIndex(element) | |||
] | |||
if (nextIndicator) { | |||
$(nextIndicator).addClass(ClassName.ACTIVE) | |||
} | |||
} | |||
} | |||
_slide(direction, element) { | |||
const activeElement = this._element.querySelector(Selector.ACTIVE_ITEM) | |||
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 | |||
let orderClassName | |||
let eventDirectionName | |||
if (direction === Direction.NEXT) { | |||
directionalClassName = ClassName.LEFT | |||
orderClassName = ClassName.NEXT | |||
eventDirectionName = Direction.LEFT | |||
} else { | |||
directionalClassName = ClassName.RIGHT | |||
orderClassName = ClassName.PREV | |||
eventDirectionName = Direction.RIGHT | |||
} | |||
if (nextElement && $(nextElement).hasClass(ClassName.ACTIVE)) { | |||
this._isSliding = false | |||
return | |||
} | |||
const slideEvent = this._triggerSlideEvent(nextElement, eventDirectionName) | |||
if (slideEvent.isDefaultPrevented()) { | |||
return | |||
} | |||
if (!activeElement || !nextElement) { | |||
// Some weirdness is happening, so we bail | |||
return | |||
} | |||
this._isSliding = true | |||
if (isCycling) { | |||
this.pause() | |||
} | |||
this._setActiveIndicatorElement(nextElement) | |||
const slidEvent = $.Event(Event.SLID, { | |||
relatedTarget: nextElement, | |||
direction: eventDirectionName, | |||
from: activeElementIndex, | |||
to: nextElementIndex | |||
}) | |||
if ($(this._element).hasClass(ClassName.SLIDE)) { | |||
$(nextElement).addClass(orderClassName) | |||
Util.reflow(nextElement) | |||
$(activeElement).addClass(directionalClassName) | |||
$(nextElement).addClass(directionalClassName) | |||
const nextElementInterval = parseInt(nextElement.getAttribute('data-interval'), 10) | |||
if (nextElementInterval) { | |||
this._config.defaultInterval = this._config.defaultInterval || this._config.interval | |||
this._config.interval = nextElementInterval | |||
} else { | |||
this._config.interval = this._config.defaultInterval || this._config.interval | |||
} | |||
const transitionDuration = Util.getTransitionDurationFromElement(activeElement) | |||
$(activeElement) | |||
.one(Util.TRANSITION_END, () => { | |||
$(nextElement) | |||
.removeClass(`${directionalClassName} ${orderClassName}`) | |||
.addClass(ClassName.ACTIVE) | |||
$(activeElement).removeClass(`${ClassName.ACTIVE} ${orderClassName} ${directionalClassName}`) | |||
this._isSliding = false | |||
setTimeout(() => $(this._element).trigger(slidEvent), 0) | |||
}) | |||
.emulateTransitionEnd(transitionDuration) | |||
} else { | |||
$(activeElement).removeClass(ClassName.ACTIVE) | |||
$(nextElement).addClass(ClassName.ACTIVE) | |||
this._isSliding = false | |||
$(this._element).trigger(slidEvent) | |||
} | |||
if (isCycling) { | |||
this.cycle() | |||
} | |||
} | |||
// Static | |||
static _jQueryInterface(config) { | |||
return this.each(function () { | |||
let data = $(this).data(DATA_KEY) | |||
let _config = { | |||
...Default, | |||
...$(this).data() | |||
} | |||
if (typeof config === 'object') { | |||
_config = { | |||
..._config, | |||
...config | |||
} | |||
} | |||
const action = typeof config === 'string' ? config : _config.slide | |||
if (!data) { | |||
data = new Carousel(this, _config) | |||
$(this).data(DATA_KEY, data) | |||
} | |||
if (typeof config === 'number') { | |||
data.to(config) | |||
} else if (typeof action === 'string') { | |||
if (typeof data[action] === 'undefined') { | |||
throw new TypeError(`No method named "${action}"`) | |||
} | |||
data[action]() | |||
} else if (_config.interval && _config.ride) { | |||
data.pause() | |||
data.cycle() | |||
} | |||
}) | |||
} | |||
static _dataApiClickHandler(event) { | |||
const selector = Util.getSelectorFromElement(this) | |||
if (!selector) { | |||
return | |||
} | |||
const target = $(selector)[0] | |||
if (!target || !$(target).hasClass(ClassName.CAROUSEL)) { | |||
return | |||
} | |||
const config = { | |||
...$(target).data(), | |||
...$(this).data() | |||
} | |||
const slideIndex = this.getAttribute('data-slide-to') | |||
if (slideIndex) { | |||
config.interval = false | |||
} | |||
Carousel._jQueryInterface.call($(target), config) | |||
if (slideIndex) { | |||
$(target).data(DATA_KEY).to(slideIndex) | |||
} | |||
event.preventDefault() | |||
} | |||
} | |||
/** | |||
* ------------------------------------------------------------------------ | |||
* Data Api implementation | |||
* ------------------------------------------------------------------------ | |||
*/ | |||
$(document) | |||
.on(Event.CLICK_DATA_API, Selector.DATA_SLIDE, Carousel._dataApiClickHandler) | |||
$(window).on(Event.LOAD_DATA_API, () => { | |||
const carousels = [].slice.call(document.querySelectorAll(Selector.DATA_RIDE)) | |||
for (let i = 0, len = carousels.length; i < len; i++) { | |||
const $carousel = $(carousels[i]) | |||
Carousel._jQueryInterface.call($carousel, $carousel.data()) | |||
} | |||
}) | |||
/** | |||
* ------------------------------------------------------------------------ | |||
* jQuery | |||
* ------------------------------------------------------------------------ | |||
*/ | |||
$.fn[NAME] = Carousel._jQueryInterface | |||
$.fn[NAME].Constructor = Carousel | |||
$.fn[NAME].noConflict = () => { | |||
$.fn[NAME] = JQUERY_NO_CONFLICT | |||
return Carousel._jQueryInterface | |||
} | |||
export default Carousel |
@ -0,0 +1,402 @@ | |||
/** | |||
* -------------------------------------------------------------------------- | |||
* Bootstrap (v4.4.1): collapse.js | |||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) | |||
* -------------------------------------------------------------------------- | |||
*/ | |||
import $ from 'jquery' | |||
import Util from './util' | |||
/** | |||
* ------------------------------------------------------------------------ | |||
* Constants | |||
* ------------------------------------------------------------------------ | |||
*/ | |||
const NAME = 'collapse' | |||
const VERSION = '4.4.1' | |||
const DATA_KEY = 'bs.collapse' | |||
const EVENT_KEY = `.${DATA_KEY}` | |||
const DATA_API_KEY = '.data-api' | |||
const JQUERY_NO_CONFLICT = $.fn[NAME] | |||
const Default = { | |||
toggle : true, | |||
parent : '' | |||
} | |||
const DefaultType = { | |||
toggle : 'boolean', | |||
parent : '(string|element)' | |||
} | |||
const Event = { | |||
SHOW : `show${EVENT_KEY}`, | |||
SHOWN : `shown${EVENT_KEY}`, | |||
HIDE : `hide${EVENT_KEY}`, | |||
HIDDEN : `hidden${EVENT_KEY}`, | |||
CLICK_DATA_API : `click${EVENT_KEY}${DATA_API_KEY}` | |||
} | |||
const ClassName = { | |||
SHOW : 'show', | |||
COLLAPSE : 'collapse', | |||
COLLAPSING : 'collapsing', | |||
COLLAPSED : 'collapsed' | |||
} | |||
const Dimension = { | |||
WIDTH : 'width', | |||
HEIGHT : 'height' | |||
} | |||
const Selector = { | |||
ACTIVES : '.show, .collapsing', | |||
DATA_TOGGLE : '[data-toggle="collapse"]' | |||
} | |||
/** | |||
* ------------------------------------------------------------------------ | |||
* Class Definition | |||
* ------------------------------------------------------------------------ | |||
*/ | |||
class Collapse { | |||
constructor(element, config) { | |||
this._isTransitioning = false | |||
this._element = element | |||
this._config = this._getConfig(config) | |||
this._triggerArray = [].slice.call(document.querySelectorAll( | |||
`[data-toggle="collapse"][href="#${element.id}"],` + | |||
`[data-toggle="collapse"][data-target="#${element.id}"]` | |||
)) | |||
const toggleList = [].slice.call(document.querySelectorAll(Selector.DATA_TOGGLE)) | |||
for (let i = 0, len = toggleList.length; i < len; i++) { | |||
const elem = toggleList[i] | |||
const selector = Util.getSelectorFromElement(elem) | |||
const filterElement = [].slice.call(document.querySelectorAll(selector)) | |||
.filter((foundElem) => foundElem === element) | |||
if (selector !== null && filterElement.length > 0) { | |||
this._selector = selector | |||
this._triggerArray.push(elem) | |||
} | |||
} | |||
this._parent = this._config.parent ? this._getParent() : null | |||
if (!this._config.parent) { | |||
this._addAriaAndCollapsedClass(this._element, this._triggerArray) | |||
} | |||
if (this._config.toggle) { | |||
this.toggle() | |||
} | |||
} | |||
// Getters | |||
static get VERSION() { | |||
return VERSION | |||
} | |||
static get Default() { | |||
return Default | |||
} | |||
// Public | |||
toggle() { | |||
if ($(this._element).hasClass(ClassName.SHOW)) { | |||
this.hide() | |||
} else { | |||
this.show() | |||
} | |||
} | |||
show() { | |||
if (this._isTransitioning || | |||
$(this._element).hasClass(ClassName.SHOW)) { | |||
return | |||
} | |||
let actives | |||
let activesData | |||
if (this._parent) { | |||
actives = [].slice.call(this._parent.querySelectorAll(Selector.ACTIVES)) | |||
.filter((elem) => { | |||
if (typeof this._config.parent === 'string') { | |||
return elem.getAttribute('data-parent') === this._config.parent | |||
} | |||
return elem.classList.contains(ClassName.COLLAPSE) | |||
}) | |||
if (actives.length === 0) { | |||
actives = null | |||
} | |||
} | |||
if (actives) { | |||
activesData = $(actives).not(this._selector).data(DATA_KEY) | |||
if (activesData && activesData._isTransitioning) { | |||
return | |||
} | |||
} | |||
const startEvent = $.Event(Event.SHOW) | |||
$(this._element).trigger(startEvent) | |||
if (startEvent.isDefaultPrevented()) { | |||
return | |||
} | |||
if (actives) { | |||
Collapse._jQueryInterface.call($(actives).not(this._selector), 'hide') | |||
if (!activesData) { | |||
$(actives).data(DATA_KEY, null) | |||
} | |||
} | |||
const dimension = this._getDimension() | |||
$(this._element) | |||
.removeClass(ClassName.COLLAPSE) | |||
.addClass(ClassName.COLLAPSING) | |||
this._element.style[dimension] = 0 | |||
if (this._triggerArray.length) { | |||
$(this._triggerArray) | |||
.removeClass(ClassName.COLLAPSED) | |||
.attr('aria-expanded', true) | |||
} | |||
this.setTransitioning(true) | |||
const complete = () => { | |||
$(this._element) | |||
.removeClass(ClassName.COLLAPSING) | |||
.addClass(ClassName.COLLAPSE) | |||
.addClass(ClassName.SHOW) | |||
this._element.style[dimension] = '' | |||
this.setTransitioning(false) | |||
$(this._element).trigger(Event.SHOWN) | |||
} | |||
const capitalizedDimension = dimension[0].toUpperCase() + dimension.slice(1) | |||
const scrollSize = `scroll${capitalizedDimension}` | |||
const transitionDuration = Util.getTransitionDurationFromElement(this._element) | |||
$(this._element) | |||
.one(Util.TRANSITION_END, complete) | |||
.emulateTransitionEnd(transitionDuration) | |||
this._element.style[dimension] = `${this._element[scrollSize]}px` | |||
} | |||
hide() { | |||
if (this._isTransitioning || | |||
!$(this._element).hasClass(ClassName.SHOW)) { | |||
return | |||
} | |||
const startEvent = $.Event(Event.HIDE) | |||
$(this._element).trigger(startEvent) | |||
if (startEvent.isDefaultPrevented()) { | |||
return | |||
} | |||
const dimension = this._getDimension() | |||
this._element.style[dimension] = `${this._element.getBoundingClientRect()[dimension]}px` | |||
Util.reflow(this._element) | |||
$(this._element) | |||
.addClass(ClassName.COLLAPSING) | |||
.removeClass(ClassName.COLLAPSE) | |||
.removeClass(ClassName.SHOW) | |||
const triggerArrayLength = this._triggerArray.length | |||
if (triggerArrayLength > 0) { | |||
for (let i = 0; i < triggerArrayLength; i++) { | |||
const trigger = this._triggerArray[i] | |||
const selector = Util.getSelectorFromElement(trigger) | |||
if (selector !== null) { | |||
const $elem = $([].slice.call(document.querySelectorAll(selector))) | |||
if (!$elem.hasClass(ClassName.SHOW)) { | |||
$(trigger).addClass(ClassName.COLLAPSED) | |||
.attr('aria-expanded', false) | |||
} | |||
} | |||
} | |||
} | |||
this.setTransitioning(true) | |||
const complete = () => { | |||
this.setTransitioning(false) | |||
$(this._element) | |||
.removeClass(ClassName.COLLAPSING) | |||
.addClass(ClassName.COLLAPSE) | |||
.trigger(Event.HIDDEN) | |||
} | |||
this._element.style[dimension] = '' | |||
const transitionDuration = Util.getTransitionDurationFromElement(this._element) | |||
$(this._element) | |||
.one(Util.TRANSITION_END, complete) | |||
.emulateTransitionEnd(transitionDuration) | |||
} | |||
setTransitioning(isTransitioning) { | |||
this._isTransitioning = isTransitioning | |||
} | |||
dispose() { | |||
$.removeData(this._element, DATA_KEY) | |||
this._config = null | |||
this._parent = null | |||
this._element = null | |||
this._triggerArray = null | |||
this._isTransitioning = null | |||
} | |||
// Private | |||
_getConfig(config) { | |||
config = { | |||
...Default, | |||
...config | |||
} | |||
config.toggle = Boolean(config.toggle) // Coerce string values | |||
Util.typeCheckConfig(NAME, config, DefaultType) | |||
return config | |||
} | |||
_getDimension() { | |||
const hasWidth = $(this._element).hasClass(Dimension.WIDTH) | |||
return hasWidth ? Dimension.WIDTH : Dimension.HEIGHT | |||
} | |||
_getParent() { | |||
let parent | |||
if (Util.isElement(this._config.parent)) { | |||
parent = this._config.parent | |||
// It's a jQuery object | |||
if (typeof this._config.parent.jquery !== 'undefined') { | |||
parent = this._config.parent[0] | |||
} | |||
} else { | |||
parent = document.querySelector(this._config.parent) | |||
} | |||
const selector = | |||
`[data-toggle="collapse"][data-parent="${this._config.parent}"]` | |||
const children = [].slice.call(parent.querySelectorAll(selector)) | |||
$(children).each((i, element) => { | |||
this._addAriaAndCollapsedClass( | |||
Collapse._getTargetFromElement(element), | |||
[element] | |||
) | |||
}) | |||
return parent | |||
} | |||
_addAriaAndCollapsedClass(element, triggerArray) { | |||
const isOpen = $(element).hasClass(ClassName.SHOW) | |||
if (triggerArray.length) { | |||
$(triggerArray) | |||
.toggleClass(ClassName.COLLAPSED, !isOpen) | |||
.attr('aria-expanded', isOpen) | |||
} | |||
} | |||
// Static | |||
static _getTargetFromElement(element) { | |||
const selector = Util.getSelectorFromElement(element) | |||
return selector ? document.querySelector(selector) : null | |||
} | |||
static _jQueryInterface(config) { | |||
return this.each(function () { | |||
const $this = $(this) | |||
let data = $this.data(DATA_KEY) | |||
const _config = { | |||
...Default, | |||
...$this.data(), | |||
...typeof config === 'object' && config ? config : {} | |||
} | |||
if (!data && _config.toggle && /show|hide/.test(config)) { | |||
_config.toggle = false | |||
} | |||
if (!data) { | |||
data = new Collapse(this, _config) | |||
$this.data(DATA_KEY, data) | |||
} | |||
if (typeof config === 'string') { | |||
if (typeof data[config] === 'undefined') { | |||
throw new TypeError(`No method named "${config}"`) | |||
} | |||
data[config]() | |||
} | |||
}) | |||
} | |||
} | |||
/** | |||
* ------------------------------------------------------------------------ | |||
* Data Api implementation | |||
* ------------------------------------------------------------------------ | |||
*/ | |||
$(document).on(Event.CLICK_DATA_API, Selector.DATA_TOGGLE, function (event) { | |||
// preventDefault only for <a> elements (which change the URL) not inside the collapsible element | |||
if (event.currentTarget.tagName === 'A') { | |||
event.preventDefault() | |||
} | |||
const $trigger = $(this) | |||
const selector = Util.getSelectorFromElement(this) | |||
const selectors = [].slice.call(document.querySelectorAll(selector)) | |||
$(selectors).each(function () { | |||
const $target = $(this) | |||
const data = $target.data(DATA_KEY) | |||
const config = data ? 'toggle' : $trigger.data() | |||
Collapse._jQueryInterface.call($target, config) | |||
}) | |||
}) | |||
/** | |||
* ------------------------------------------------------------------------ | |||
* jQuery | |||
* ------------------------------------------------------------------------ | |||
*/ | |||
$.fn[NAME] = Collapse._jQueryInterface | |||
$.fn[NAME].Constructor = Collapse | |||
$.fn[NAME].noConflict = () => { | |||
$.fn[NAME] = JQUERY_NO_CONFLICT | |||
return Collapse._jQueryInterface | |||
} | |||
export default Collapse |
@ -0,0 +1,548 @@ | |||
/** | |||
* -------------------------------------------------------------------------- | |||
* Bootstrap (v4.4.1): dropdown.js | |||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) | |||
* -------------------------------------------------------------------------- | |||
*/ | |||
import $ from 'jquery' | |||
import Popper from 'popper.js' | |||
import Util from './util' | |||
/** | |||
* ------------------------------------------------------------------------ | |||
* Constants | |||
* ------------------------------------------------------------------------ | |||
*/ | |||
const NAME = 'dropdown' | |||
const VERSION = '4.4.1' | |||
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}`, | |||
HIDDEN : `hidden${EVENT_KEY}`, | |||
SHOW : `show${EVENT_KEY}`, | |||
SHOWN : `shown${EVENT_KEY}`, | |||
CLICK : `click${EVENT_KEY}`, | |||
CLICK_DATA_API : `click${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 = { | |||
DISABLED : 'disabled', | |||
SHOW : 'show', | |||
DROPUP : 'dropup', | |||
DROPRIGHT : 'dropright', | |||
DROPLEFT : 'dropleft', | |||
MENURIGHT : 'dropdown-menu-right', | |||
MENULEFT : 'dropdown-menu-left', | |||
POSITION_STATIC : 'position-static' | |||
} | |||
const Selector = { | |||
DATA_TOGGLE : '[data-toggle="dropdown"]', | |||
FORM_CHILD : '.dropdown form', | |||
MENU : '.dropdown-menu', | |||
NAVBAR_NAV : '.navbar-nav', | |||
VISIBLE_ITEMS : '.dropdown-menu .dropdown-item:not(.disabled):not(:disabled)' | |||
} | |||
const AttachmentMap = { | |||
TOP : 'top-start', | |||
TOPEND : 'top-end', | |||
BOTTOM : 'bottom-start', | |||
BOTTOMEND : 'bottom-end', | |||
RIGHT : 'right-start', | |||
RIGHTEND : 'right-end', | |||
LEFT : 'left-start', | |||
LEFTEND : 'left-end' | |||
} | |||
const Default = { | |||
offset : 0, | |||
flip : true, | |||
boundary : 'scrollParent', | |||
reference : 'toggle', | |||
display : 'dynamic', | |||
popperConfig : null | |||
} | |||
const DefaultType = { | |||
offset : '(number|string|function)', | |||
flip : 'boolean', | |||
boundary : '(string|element)', | |||
reference : '(string|element)', | |||
display : 'string', | |||
popperConfig : '(null|object)' | |||
} | |||
/** | |||
* ------------------------------------------------------------------------ | |||
* Class Definition | |||
* ------------------------------------------------------------------------ | |||
*/ | |||
class Dropdown { | |||
constructor(element, config) { | |||
this._element = element | |||
this._popper = null | |||
this._config = this._getConfig(config) | |||
this._menu = this._getMenuElement() | |||
this._inNavbar = this._detectNavbar() | |||
this._addEventListeners() | |||
} | |||
// Getters | |||
static get VERSION() { | |||
return VERSION | |||
} | |||
static get Default() { | |||
return Default | |||
} | |||
static get DefaultType() { | |||
return DefaultType | |||
} | |||
// Public | |||
toggle() { | |||
if (this._element.disabled || $(this._element).hasClass(ClassName.DISABLED)) { | |||
return | |||
} | |||
const isActive = $(this._menu).hasClass(ClassName.SHOW) | |||
Dropdown._clearMenus() | |||
if (isActive) { | |||
return | |||
} | |||
this.show(true) | |||
} | |||
show(usePopper = false) { | |||
if (this._element.disabled || $(this._element).hasClass(ClassName.DISABLED) || $(this._menu).hasClass(ClassName.SHOW)) { | |||
return | |||
} | |||
const relatedTarget = { | |||
relatedTarget: this._element | |||
} | |||
const showEvent = $.Event(Event.SHOW, relatedTarget) | |||
const parent = Dropdown._getParentFromElement(this._element) | |||
$(parent).trigger(showEvent) | |||
if (showEvent.isDefaultPrevented()) { | |||
return | |||
} | |||
// Disable totally Popper.js for Dropdown in Navbar | |||
if (!this._inNavbar && usePopper) { | |||
/** | |||
* Check for Popper dependency | |||
* Popper - https://popper.js.org | |||
*/ | |||
if (typeof Popper === 'undefined') { | |||
throw new TypeError('Bootstrap\'s dropdowns require Popper.js (https://popper.js.org/)') | |||
} | |||
let referenceElement = this._element | |||
if (this._config.reference === 'parent') { | |||
referenceElement = parent | |||
} else if (Util.isElement(this._config.reference)) { | |||
referenceElement = this._config.reference | |||
// Check if it's jQuery element | |||
if (typeof this._config.reference.jquery !== 'undefined') { | |||
referenceElement = this._config.reference[0] | |||
} | |||
} | |||
// If boundary is not `scrollParent`, then set position to `static` | |||
// to allow the menu to "escape" the scroll parent's boundaries | |||
// https://github.com/twbs/bootstrap/issues/24251 | |||
if (this._config.boundary !== 'scrollParent') { | |||
$(parent).addClass(ClassName.POSITION_STATIC) | |||
} | |||
this._popper = new Popper(referenceElement, this._menu, this._getPopperConfig()) | |||
} | |||
// 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 === 0) { | |||
$(document.body).children().on('mouseover', null, $.noop) | |||
} | |||
this._element.focus() | |||
this._element.setAttribute('aria-expanded', true) | |||
$(this._menu).toggleClass(ClassName.SHOW) | |||
$(parent) | |||
.toggleClass(ClassName.SHOW) | |||
.trigger($.Event(Event.SHOWN, relatedTarget)) | |||
} | |||
hide() { | |||
if (this._element.disabled || $(this._element).hasClass(ClassName.DISABLED) || !$(this._menu).hasClass(ClassName.SHOW)) { | |||
return | |||
} | |||
const relatedTarget = { | |||
relatedTarget: this._element | |||
} | |||
const hideEvent = $.Event(Event.HIDE, relatedTarget) | |||
const parent = Dropdown._getParentFromElement(this._element) | |||
$(parent).trigger(hideEvent) | |||
if (hideEvent.isDefaultPrevented()) { | |||
return | |||
} | |||
if (this._popper) { | |||
this._popper.destroy() | |||
} | |||
$(this._menu).toggleClass(ClassName.SHOW) | |||
$(parent) | |||
.toggleClass(ClassName.SHOW) | |||
.trigger($.Event(Event.HIDDEN, 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, (event) => { | |||
event.preventDefault() | |||
event.stopPropagation() | |||
this.toggle() | |||
}) | |||
} | |||
_getConfig(config) { | |||
config = { | |||
...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) | |||
if (parent) { | |||
this._menu = parent.querySelector(Selector.MENU) | |||
} | |||
} | |||
return this._menu | |||
} | |||
_getPlacement() { | |||
const $parentDropdown = $(this._element.parentNode) | |||
let placement = AttachmentMap.BOTTOM | |||
// Handle dropup | |||
if ($parentDropdown.hasClass(ClassName.DROPUP)) { | |||
placement = AttachmentMap.TOP | |||
if ($(this._menu).hasClass(ClassName.MENURIGHT)) { | |||
placement = AttachmentMap.TOPEND | |||
} | |||
} else if ($parentDropdown.hasClass(ClassName.DROPRIGHT)) { | |||
placement = AttachmentMap.RIGHT | |||
} else if ($parentDropdown.hasClass(ClassName.DROPLEFT)) { | |||
placement = AttachmentMap.LEFT | |||
} else if ($(this._menu).hasClass(ClassName.MENURIGHT)) { | |||
placement = AttachmentMap.BOTTOMEND | |||
} | |||
return placement | |||
} | |||
_detectNavbar() { | |||
return $(this._element).closest('.navbar').length > 0 | |||
} | |||
_getOffset() { | |||
const offset = {} | |||
if (typeof this._config.offset === 'function') { | |||
offset.fn = (data) => { | |||
data.offsets = { | |||
...data.offsets, | |||
...this._config.offset(data.offsets, this._element) || {} | |||
} | |||
return data | |||
} | |||
} else { | |||
offset.offset = this._config.offset | |||
} | |||
return offset | |||
} | |||
_getPopperConfig() { | |||
const popperConfig = { | |||
placement: this._getPlacement(), | |||
modifiers: { | |||
offset: this._getOffset(), | |||
flip: { | |||
enabled: this._config.flip | |||
}, | |||
preventOverflow: { | |||
boundariesElement: this._config.boundary | |||
} | |||
} | |||
} | |||
// Disable Popper.js if we have a static display | |||
if (this._config.display === 'static') { | |||
popperConfig.modifiers.applyStyle = { | |||
enabled: false | |||
} | |||
} | |||
return { | |||
...popperConfig, | |||
...this._config.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, _config) | |||
$(this).data(DATA_KEY, data) | |||
} | |||
if (typeof config === 'string') { | |||
if (typeof data[config] === 'undefined') { | |||
throw new TypeError(`No method named "${config}"`) | |||
} | |||
data[config]() | |||
} | |||
}) | |||
} | |||
static _clearMenus(event) { | |||
if (event && (event.which === RIGHT_MOUSE_BUTTON_WHICH || | |||
event.type === 'keyup' && event.which !== TAB_KEYCODE)) { | |||
return | |||
} | |||
const toggles = [].slice.call(document.querySelectorAll(Selector.DATA_TOGGLE)) | |||
for (let i = 0, len = toggles.length; i < len; i++) { | |||
const parent = Dropdown._getParentFromElement(toggles[i]) | |||
const context = $(toggles[i]).data(DATA_KEY) | |||
const relatedTarget = { | |||
relatedTarget: toggles[i] | |||
} | |||
if (event && event.type === 'click') { | |||
relatedTarget.clickEvent = event | |||
} | |||
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 === 'keyup' && event.which === TAB_KEYCODE) && | |||
$.contains(parent, event.target)) { | |||
continue | |||
} | |||
const hideEvent = $.Event(Event.HIDE, relatedTarget) | |||
$(parent).trigger(hideEvent) | |||
if (hideEvent.isDefaultPrevented()) { | |||
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) { | |||
$(document.body).children().off('mouseover', null, $.noop) | |||
} | |||
toggles[i].setAttribute('aria-expanded', 'false') | |||
if (context._popper) { | |||
context._popper.destroy() | |||
} | |||
$(dropdownMenu).removeClass(ClassName.SHOW) | |||
$(parent) | |||
.removeClass(ClassName.SHOW) | |||
.trigger($.Event(Event.HIDDEN, relatedTarget)) | |||
} | |||
} | |||
static _getParentFromElement(element) { | |||
let parent | |||
const selector = Util.getSelectorFromElement(element) | |||
if (selector) { | |||
parent = document.querySelector(selector) | |||
} | |||
return parent || element.parentNode | |||
} | |||
// eslint-disable-next-line complexity | |||
static _dataApiKeydownHandler(event) { | |||
// If not input/textarea: | |||
// - And not a key in REGEXP_KEYDOWN => not a dropdown command | |||
// If input/textarea: | |||
// - If space key => not a dropdown command | |||
// - If key is other than escape | |||
// - If key is not up or down => not a dropdown command | |||
// - If trigger inside the menu => not a dropdown command | |||
if (/input|textarea/i.test(event.target.tagName) | |||
? event.which === SPACE_KEYCODE || event.which !== ESCAPE_KEYCODE && | |||
(event.which !== ARROW_DOWN_KEYCODE && event.which !== ARROW_UP_KEYCODE || | |||
$(event.target).closest(Selector.MENU).length) : !REGEXP_KEYDOWN.test(event.which)) { | |||
return | |||
} | |||
event.preventDefault() | |||
event.stopPropagation() | |||
if (this.disabled || $(this).hasClass(ClassName.DISABLED)) { | |||
return | |||
} | |||
const parent = Dropdown._getParentFromElement(this) | |||
const isActive = $(parent).hasClass(ClassName.SHOW) | |||
if (!isActive && event.which === ESCAPE_KEYCODE) { | |||
return | |||
} | |||
if (!isActive || isActive && (event.which === ESCAPE_KEYCODE || event.which === SPACE_KEYCODE)) { | |||
if (event.which === ESCAPE_KEYCODE) { | |||
const toggle = parent.querySelector(Selector.DATA_TOGGLE) | |||
$(toggle).trigger('focus') | |||
} | |||
$(this).trigger('click') | |||
return | |||
} | |||
const items = [].slice.call(parent.querySelectorAll(Selector.VISIBLE_ITEMS)) | |||
.filter((item) => $(item).is(':visible')) | |||
if (items.length === 0) { | |||
return | |||
} | |||
let index = items.indexOf(event.target) | |||
if (event.which === ARROW_UP_KEYCODE && index > 0) { // Up | |||
index-- | |||
} | |||
if (event.which === ARROW_DOWN_KEYCODE && index < items.length - 1) { // Down | |||
index++ | |||
} | |||
if (index < 0) { | |||
index = 0 | |||
} | |||
items[index].focus() | |||
} | |||
} | |||
/** | |||
* ------------------------------------------------------------------------ | |||
* Data Api implementation | |||
* ------------------------------------------------------------------------ | |||
*/ | |||
$(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, (e) => { | |||
e.stopPropagation() | |||
}) | |||
/** | |||
* ------------------------------------------------------------------------ | |||
* jQuery | |||
* ------------------------------------------------------------------------ | |||
*/ | |||
$.fn[NAME] = Dropdown._jQueryInterface | |||
$.fn[NAME].Constructor = Dropdown | |||
$.fn[NAME].noConflict = () => { | |||
$.fn[NAME] = JQUERY_NO_CONFLICT | |||
return Dropdown._jQueryInterface | |||
} | |||
export default Dropdown |
@ -0,0 +1,34 @@ | |||
import Alert from './alert' | |||
import Button from './button' | |||
import Carousel from './carousel' | |||
import Collapse from './collapse' | |||
import Dropdown from './dropdown' | |||
import Modal from './modal' | |||
import Popover from './popover' | |||
import Scrollspy from './scrollspy' | |||
import Tab from './tab' | |||
import Toast from './toast' | |||
import Tooltip from './tooltip' | |||
import Util from './util' | |||
/** | |||
* -------------------------------------------------------------------------- | |||
* Bootstrap (v4.4.1): index.js | |||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) | |||
* -------------------------------------------------------------------------- | |||
*/ | |||
export { | |||
Util, | |||
Alert, | |||
Button, | |||
Carousel, | |||
Collapse, | |||
Dropdown, | |||
Modal, | |||
Popover, | |||
Scrollspy, | |||
Tab, | |||
Toast, | |||
Tooltip | |||
} |
@ -0,0 +1,616 @@ | |||
/** | |||
* -------------------------------------------------------------------------- | |||
* Bootstrap (v4.4.1): modal.js | |||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) | |||
* -------------------------------------------------------------------------- | |||
*/ | |||
import $ from 'jquery' | |||
import Util from './util' | |||
/** | |||
* ------------------------------------------------------------------------ | |||
* Constants | |||
* ------------------------------------------------------------------------ | |||
*/ | |||
const NAME = 'modal' | |||
const VERSION = '4.4.1' | |||
const DATA_KEY = 'bs.modal' | |||
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 Default = { | |||
backdrop : true, | |||
keyboard : true, | |||
focus : true, | |||
show : true | |||
} | |||
const DefaultType = { | |||
backdrop : '(boolean|string)', | |||
keyboard : 'boolean', | |||
focus : 'boolean', | |||
show : 'boolean' | |||
} | |||
const Event = { | |||
HIDE : `hide${EVENT_KEY}`, | |||
HIDE_PREVENTED : `hidePrevented${EVENT_KEY}`, | |||
HIDDEN : `hidden${EVENT_KEY}`, | |||
SHOW : `show${EVENT_KEY}`, | |||
SHOWN : `shown${EVENT_KEY}`, | |||
FOCUSIN : `focusin${EVENT_KEY}`, | |||
RESIZE : `resize${EVENT_KEY}`, | |||
CLICK_DISMISS : `click.dismiss${EVENT_KEY}`, | |||
KEYDOWN_DISMISS : `keydown.dismiss${EVENT_KEY}`, | |||
MOUSEUP_DISMISS : `mouseup.dismiss${EVENT_KEY}`, | |||
MOUSEDOWN_DISMISS : `mousedown.dismiss${EVENT_KEY}`, | |||
CLICK_DATA_API : `click${EVENT_KEY}${DATA_API_KEY}` | |||
} | |||
const ClassName = { | |||
SCROLLABLE : 'modal-dialog-scrollable', | |||
SCROLLBAR_MEASURER : 'modal-scrollbar-measure', | |||
BACKDROP : 'modal-backdrop', | |||
OPEN : 'modal-open', | |||
FADE : 'fade', | |||
SHOW : 'show', | |||
STATIC : 'modal-static' | |||
} | |||
const Selector = { | |||
DIALOG : '.modal-dialog', | |||
MODAL_BODY : '.modal-body', | |||
DATA_TOGGLE : '[data-toggle="modal"]', | |||
DATA_DISMISS : '[data-dismiss="modal"]', | |||
FIXED_CONTENT : '.fixed-top, .fixed-bottom, .is-fixed, .sticky-top', | |||
STICKY_CONTENT : '.sticky-top' | |||
} | |||
/** | |||
* ------------------------------------------------------------------------ | |||
* Class Definition | |||
* ------------------------------------------------------------------------ | |||
*/ | |||
class Modal { | |||
constructor(element, config) { | |||
this._config = this._getConfig(config) | |||
this._element = element | |||
this._dialog = element.querySelector(Selector.DIALOG) | |||
this._backdrop = null | |||
this._isShown = false | |||
this._isBodyOverflowing = false | |||
this._ignoreBackdropClick = false | |||
this._isTransitioning = false | |||
this._scrollbarWidth = 0 | |||
} | |||
// Getters | |||
static get VERSION() { | |||
return VERSION | |||
} | |||
static get Default() { | |||
return Default | |||
} | |||
// Public | |||
toggle(relatedTarget) { | |||
return this._isShown ? this.hide() : this.show(relatedTarget) | |||
} | |||
show(relatedTarget) { | |||
if (this._isShown || this._isTransitioning) { | |||
return | |||
} | |||
if ($(this._element).hasClass(ClassName.FADE)) { | |||
this._isTransitioning = true | |||
} | |||
const showEvent = $.Event(Event.SHOW, { | |||
relatedTarget | |||
}) | |||
$(this._element).trigger(showEvent) | |||
if (this._isShown || showEvent.isDefaultPrevented()) { | |||
return | |||
} | |||
this._isShown = true | |||
this._checkScrollbar() | |||
this._setScrollbar() | |||
this._adjustDialog() | |||
this._setEscapeEvent() | |||
this._setResizeEvent() | |||
$(this._element).on( | |||
Event.CLICK_DISMISS, | |||
Selector.DATA_DISMISS, | |||
(event) => this.hide(event) | |||
) | |||
$(this._dialog).on(Event.MOUSEDOWN_DISMISS, () => { | |||
$(this._element).one(Event.MOUSEUP_DISMISS, (event) => { | |||
if ($(event.target).is(this._element)) { | |||
this._ignoreBackdropClick = true | |||
} | |||
}) | |||
}) | |||
this._showBackdrop(() => this._showElement(relatedTarget)) | |||
} | |||
hide(event) { | |||
if (event) { | |||
event.preventDefault() | |||
} | |||
if (!this._isShown || this._isTransitioning) { | |||
return | |||
} | |||
const hideEvent = $.Event(Event.HIDE) | |||
$(this._element).trigger(hideEvent) | |||
if (!this._isShown || hideEvent.isDefaultPrevented()) { | |||
return | |||
} | |||
this._isShown = false | |||
const transition = $(this._element).hasClass(ClassName.FADE) | |||
if (transition) { | |||
this._isTransitioning = true | |||
} | |||
this._setEscapeEvent() | |||
this._setResizeEvent() | |||
$(document).off(Event.FOCUSIN) | |||
$(this._element).removeClass(ClassName.SHOW) | |||
$(this._element).off(Event.CLICK_DISMISS) | |||
$(this._dialog).off(Event.MOUSEDOWN_DISMISS) | |||
if (transition) { | |||
const transitionDuration = Util.getTransitionDurationFromElement(this._element) | |||
$(this._element) | |||
.one(Util.TRANSITION_END, (event) => this._hideModal(event)) | |||
.emulateTransitionEnd(transitionDuration) | |||
} else { | |||
this._hideModal() | |||
} | |||
} | |||
dispose() { | |||
[window, this._element, this._dialog] | |||
.forEach((htmlElement) => $(htmlElement).off(EVENT_KEY)) | |||
/** | |||
* `document` has 2 events `Event.FOCUSIN` and `Event.CLICK_DATA_API` | |||
* Do not move `document` in `htmlElements` array | |||
* It will remove `Event.CLICK_DATA_API` event that should remain | |||
*/ | |||
$(document).off(Event.FOCUSIN) | |||
$.removeData(this._element, DATA_KEY) | |||
this._config = null | |||
this._element = null | |||
this._dialog = null | |||
this._backdrop = null | |||
this._isShown = null | |||
this._isBodyOverflowing = null | |||
this._ignoreBackdropClick = null | |||
this._isTransitioning = null | |||
this._scrollbarWidth = null | |||
} | |||
handleUpdate() { | |||
this._adjustDialog() | |||
} | |||
// Private | |||
_getConfig(config) { | |||
config = { | |||
...Default, | |||
...config | |||
} | |||
Util.typeCheckConfig(NAME, config, DefaultType) | |||
return config | |||
} | |||
_triggerBackdropTransition() { | |||
if (this._config.backdrop === 'static') { | |||
const hideEventPrevented = $.Event(Event.HIDE_PREVENTED) | |||
$(this._element).trigger(hideEventPrevented) | |||
if (hideEventPrevented.defaultPrevented) { | |||
return | |||
} | |||
this._element.classList.add(ClassName.STATIC) | |||
const modalTransitionDuration = Util.getTransitionDurationFromElement(this._element) | |||
$(this._element).one(Util.TRANSITION_END, () => { | |||
this._element.classList.remove(ClassName.STATIC) | |||
}) | |||
.emulateTransitionEnd(modalTransitionDuration) | |||
this._element.focus() | |||
} else { | |||
this.hide() | |||
} | |||
} | |||
_showElement(relatedTarget) { | |||
const transition = $(this._element).hasClass(ClassName.FADE) | |||
const modalBody = this._dialog ? this._dialog.querySelector(Selector.MODAL_BODY) : null | |||
if (!this._element.parentNode || | |||
this._element.parentNode.nodeType !== Node.ELEMENT_NODE) { | |||
// Don't move modal's DOM position | |||
document.body.appendChild(this._element) | |||
} | |||
this._element.style.display = 'block' | |||
this._element.removeAttribute('aria-hidden') | |||
this._element.setAttribute('aria-modal', true) | |||
if ($(this._dialog).hasClass(ClassName.SCROLLABLE) && modalBody) { | |||
modalBody.scrollTop = 0 | |||
} else { | |||
this._element.scrollTop = 0 | |||
} | |||
if (transition) { | |||
Util.reflow(this._element) | |||
} | |||
$(this._element).addClass(ClassName.SHOW) | |||
if (this._config.focus) { | |||
this._enforceFocus() | |||
} | |||
const shownEvent = $.Event(Event.SHOWN, { | |||
relatedTarget | |||
}) | |||
const transitionComplete = () => { | |||
if (this._config.focus) { | |||
this._element.focus() | |||
} | |||
this._isTransitioning = false | |||
$(this._element).trigger(shownEvent) | |||
} | |||
if (transition) { | |||
const transitionDuration = Util.getTransitionDurationFromElement(this._dialog) | |||
$(this._dialog) | |||
.one(Util.TRANSITION_END, transitionComplete) | |||
.emulateTransitionEnd(transitionDuration) | |||
} else { | |||
transitionComplete() | |||
} | |||
} | |||
_enforceFocus() { | |||
$(document) | |||
.off(Event.FOCUSIN) // Guard against infinite focus loop | |||
.on(Event.FOCUSIN, (event) => { | |||
if (document !== event.target && | |||
this._element !== event.target && | |||
$(this._element).has(event.target).length === 0) { | |||
this._element.focus() | |||
} | |||
}) | |||
} | |||
_setEscapeEvent() { | |||
if (this._isShown && this._config.keyboard) { | |||
$(this._element).on(Event.KEYDOWN_DISMISS, (event) => { | |||
if (event.which === ESCAPE_KEYCODE) { | |||
this._triggerBackdropTransition() | |||
} | |||
}) | |||
} else if (!this._isShown) { | |||
$(this._element).off(Event.KEYDOWN_DISMISS) | |||
} | |||
} | |||
_setResizeEvent() { | |||
if (this._isShown) { | |||
$(window).on(Event.RESIZE, (event) => this.handleUpdate(event)) | |||
} else { | |||
$(window).off(Event.RESIZE) | |||
} | |||
} | |||
_hideModal() { | |||
this._element.style.display = 'none' | |||
this._element.setAttribute('aria-hidden', true) | |||
this._element.removeAttribute('aria-modal') | |||
this._isTransitioning = false | |||
this._showBackdrop(() => { | |||
$(document.body).removeClass(ClassName.OPEN) | |||
this._resetAdjustments() | |||
this._resetScrollbar() | |||
$(this._element).trigger(Event.HIDDEN) | |||
}) | |||
} | |||
_removeBackdrop() { | |||
if (this._backdrop) { | |||
$(this._backdrop).remove() | |||
this._backdrop = null | |||
} | |||
} | |||
_showBackdrop(callback) { | |||
const animate = $(this._element).hasClass(ClassName.FADE) | |||
? ClassName.FADE : '' | |||
if (this._isShown && this._config.backdrop) { | |||
this._backdrop = document.createElement('div') | |||
this._backdrop.className = ClassName.BACKDROP | |||
if (animate) { | |||
this._backdrop.classList.add(animate) | |||
} | |||
$(this._backdrop).appendTo(document.body) | |||
$(this._element).on(Event.CLICK_DISMISS, (event) => { | |||
if (this._ignoreBackdropClick) { | |||
this._ignoreBackdropClick = false | |||
return | |||
} | |||
if (event.target !== event.currentTarget) { | |||
return | |||
} | |||
this._triggerBackdropTransition() | |||
}) | |||
if (animate) { | |||
Util.reflow(this._backdrop) | |||
} | |||
$(this._backdrop).addClass(ClassName.SHOW) | |||
if (!callback) { | |||
return | |||
} | |||
if (!animate) { | |||
callback() | |||
return | |||
} | |||
const backdropTransitionDuration = Util.getTransitionDurationFromElement(this._backdrop) | |||
$(this._backdrop) | |||
.one(Util.TRANSITION_END, callback) | |||
.emulateTransitionEnd(backdropTransitionDuration) | |||
} else if (!this._isShown && this._backdrop) { | |||
$(this._backdrop).removeClass(ClassName.SHOW) | |||
const callbackRemove = () => { | |||
this._removeBackdrop() | |||
if (callback) { | |||
callback() | |||
} | |||
} | |||
if ($(this._element).hasClass(ClassName.FADE)) { | |||
const backdropTransitionDuration = Util.getTransitionDurationFromElement(this._backdrop) | |||
$(this._backdrop) | |||
.one(Util.TRANSITION_END, callbackRemove) | |||
.emulateTransitionEnd(backdropTransitionDuration) | |||
} else { | |||
callbackRemove() | |||
} | |||
} else if (callback) { | |||
callback() | |||
} | |||
} | |||
// ---------------------------------------------------------------------- | |||
// the following methods are used to handle overflowing modals | |||
// todo (fat): these should probably be refactored out of modal.js | |||
// ---------------------------------------------------------------------- | |||
_adjustDialog() { | |||
const isModalOverflowing = | |||
this._element.scrollHeight > document.documentElement.clientHeight | |||
if (!this._isBodyOverflowing && isModalOverflowing) { | |||
this._element.style.paddingLeft = `${this._scrollbarWidth}px` | |||
} | |||
if (this._isBodyOverflowing && !isModalOverflowing) { | |||
this._element.style.paddingRight = `${this._scrollbarWidth}px` | |||
} | |||
} | |||
_resetAdjustments() { | |||
this._element.style.paddingLeft = '' | |||
this._element.style.paddingRight = '' | |||
} | |||
_checkScrollbar() { | |||
const rect = document.body.getBoundingClientRect() | |||
this._isBodyOverflowing = rect.left + rect.right < window.innerWidth | |||
this._scrollbarWidth = this._getScrollbarWidth() | |||
} | |||
_setScrollbar() { | |||
if (this._isBodyOverflowing) { | |||
// 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 | |||
const fixedContent = [].slice.call(document.querySelectorAll(Selector.FIXED_CONTENT)) | |||
const stickyContent = [].slice.call(document.querySelectorAll(Selector.STICKY_CONTENT)) | |||
// Adjust fixed content padding | |||
$(fixedContent).each((index, element) => { | |||
const actualPadding = element.style.paddingRight | |||
const calculatedPadding = $(element).css('padding-right') | |||
$(element) | |||
.data('padding-right', actualPadding) | |||
.css('padding-right', `${parseFloat(calculatedPadding) + this._scrollbarWidth}px`) | |||
}) | |||
// Adjust sticky content margin | |||
$(stickyContent).each((index, element) => { | |||
const actualMargin = element.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 = $(document.body).css('padding-right') | |||
$(document.body) | |||
.data('padding-right', actualPadding) | |||
.css('padding-right', `${parseFloat(calculatedPadding) + this._scrollbarWidth}px`) | |||
} | |||
$(document.body).addClass(ClassName.OPEN) | |||
} | |||
_resetScrollbar() { | |||
// Restore fixed content padding | |||
const fixedContent = [].slice.call(document.querySelectorAll(Selector.FIXED_CONTENT)) | |||
$(fixedContent).each((index, element) => { | |||
const padding = $(element).data('padding-right') | |||
$(element).removeData('padding-right') | |||
element.style.paddingRight = padding ? padding : '' | |||
}) | |||
// Restore sticky content | |||
const elements = [].slice.call(document.querySelectorAll(`${Selector.STICKY_CONTENT}`)) | |||
$(elements).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 = $(document.body).data('padding-right') | |||
$(document.body).removeData('padding-right') | |||
document.body.style.paddingRight = padding ? padding : '' | |||
} | |||
_getScrollbarWidth() { // thx d.walsh | |||
const scrollDiv = document.createElement('div') | |||
scrollDiv.className = ClassName.SCROLLBAR_MEASURER | |||
document.body.appendChild(scrollDiv) | |||
const scrollbarWidth = scrollDiv.getBoundingClientRect().width - scrollDiv.clientWidth | |||
document.body.removeChild(scrollDiv) | |||
return scrollbarWidth | |||
} | |||
// Static | |||
static _jQueryInterface(config, relatedTarget) { | |||
return this.each(function () { | |||
let data = $(this).data(DATA_KEY) | |||
const _config = { | |||
...Default, | |||
...$(this).data(), | |||
...typeof config === 'object' && config ? config : {} | |||
} | |||
if (!data) { | |||
data = new Modal(this, _config) | |||
$(this).data(DATA_KEY, data) | |||
} | |||
if (typeof config === 'string') { | |||
if (typeof data[config] === 'undefined') { | |||
throw new TypeError(`No method named "${config}"`) | |||
} | |||
data[config](relatedTarget) | |||
} else if (_config.show) { | |||
data.show(relatedTarget) | |||
} | |||
}) | |||
} | |||
} | |||
/** | |||
* ------------------------------------------------------------------------ | |||
* Data Api implementation | |||
* ------------------------------------------------------------------------ | |||
*/ | |||
$(document).on(Event.CLICK_DATA_API, Selector.DATA_TOGGLE, function (event) { | |||
let target | |||
const selector = Util.getSelectorFromElement(this) | |||
if (selector) { | |||
target = document.querySelector(selector) | |||
} | |||
const config = $(target).data(DATA_KEY) | |||
? 'toggle' : { | |||
...$(target).data(), | |||
...$(this).data() | |||
} | |||
if (this.tagName === 'A' || this.tagName === 'AREA') { | |||
event.preventDefault() | |||
} | |||
const $target = $(target).one(Event.SHOW, (showEvent) => { | |||
if (showEvent.isDefaultPrevented()) { | |||
// Only register focus restorer if modal will actually get shown | |||
return | |||
} | |||
$target.one(Event.HIDDEN, () => { | |||
if ($(this).is(':visible')) { | |||
this.focus() | |||
} | |||
}) | |||
}) | |||
Modal._jQueryInterface.call($(target), config, this) | |||
}) | |||
/** | |||
* ------------------------------------------------------------------------ | |||
* jQuery | |||
* ------------------------------------------------------------------------ | |||
*/ | |||
$.fn[NAME] = Modal._jQueryInterface | |||
$.fn[NAME].Constructor = Modal | |||
$.fn[NAME].noConflict = () => { | |||
$.fn[NAME] = JQUERY_NO_CONFLICT | |||
return Modal._jQueryInterface | |||
} | |||
export default Modal |
@ -0,0 +1,184 @@ | |||
/** | |||
* -------------------------------------------------------------------------- | |||
* Bootstrap (v4.4.1): popover.js | |||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) | |||
* -------------------------------------------------------------------------- | |||
*/ | |||
import $ from 'jquery' | |||
import Tooltip from './tooltip' | |||
/** | |||
* ------------------------------------------------------------------------ | |||
* Constants | |||
* ------------------------------------------------------------------------ | |||
*/ | |||
const NAME = 'popover' | |||
const VERSION = '4.4.1' | |||
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 = { | |||
...Tooltip.Default, | |||
placement : 'right', | |||
trigger : 'click', | |||
content : '', | |||
template : '<div class="popover" role="tooltip">' + | |||
'<div class="arrow"></div>' + | |||
'<h3 class="popover-header"></h3>' + | |||
'<div class="popover-body"></div></div>' | |||
} | |||
const DefaultType = { | |||
...Tooltip.DefaultType, | |||
content : '(string|element|function)' | |||
} | |||
const ClassName = { | |||
FADE : 'fade', | |||
SHOW : 'show' | |||
} | |||
const Selector = { | |||
TITLE : '.popover-header', | |||
CONTENT : '.popover-body' | |||
} | |||
const Event = { | |||
HIDE : `hide${EVENT_KEY}`, | |||
HIDDEN : `hidden${EVENT_KEY}`, | |||
SHOW : `show${EVENT_KEY}`, | |||
SHOWN : `shown${EVENT_KEY}`, | |||
INSERTED : `inserted${EVENT_KEY}`, | |||
CLICK : `click${EVENT_KEY}`, | |||
FOCUSIN : `focusin${EVENT_KEY}`, | |||
FOCUSOUT : `focusout${EVENT_KEY}`, | |||
MOUSEENTER : `mouseenter${EVENT_KEY}`, | |||
MOUSELEAVE : `mouseleave${EVENT_KEY}` | |||
} | |||
/** | |||
* ------------------------------------------------------------------------ | |||
* Class Definition | |||
* ------------------------------------------------------------------------ | |||
*/ | |||
class Popover extends Tooltip { | |||
// Getters | |||
static get VERSION() { | |||
return VERSION | |||
} | |||
static get Default() { | |||
return Default | |||
} | |||
static get NAME() { | |||
return NAME | |||
} | |||
static get DATA_KEY() { | |||
return DATA_KEY | |||
} | |||
static get Event() { | |||
return Event | |||
} | |||
static get EVENT_KEY() { | |||
return EVENT_KEY | |||
} | |||
static get DefaultType() { | |||
return DefaultType | |||
} | |||
// Overrides | |||
isWithContent() { | |||
return this.getTitle() || this._getContent() | |||
} | |||
addAttachmentClass(attachment) { | |||
$(this.getTipElement()).addClass(`${CLASS_PREFIX}-${attachment}`) | |||
} | |||
getTipElement() { | |||
this.tip = this.tip || $(this.config.template)[0] | |||
return this.tip | |||
} | |||
setContent() { | |||
const $tip = $(this.getTipElement()) | |||
// We use append for html objects to maintain js events | |||
this.setElementContent($tip.find(Selector.TITLE), this.getTitle()) | |||
let content = this._getContent() | |||
if (typeof content === 'function') { | |||
content = content.call(this.element) | |||
} | |||
this.setElementContent($tip.find(Selector.CONTENT), content) | |||
$tip.removeClass(`${ClassName.FADE} ${ClassName.SHOW}`) | |||
} | |||
// Private | |||
_getContent() { | |||
return this.element.getAttribute('data-content') || | |||
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 | |||
static _jQueryInterface(config) { | |||
return this.each(function () { | |||
let data = $(this).data(DATA_KEY) | |||
const _config = typeof config === 'object' ? config : null | |||
if (!data && /dispose|hide/.test(config)) { | |||
return | |||
} | |||
if (!data) { | |||
data = new Popover(this, _config) | |||
$(this).data(DATA_KEY, data) | |||
} | |||
if (typeof config === 'string') { | |||
if (typeof data[config] === 'undefined') { | |||
throw new TypeError(`No method named "${config}"`) | |||
} | |||
data[config]() | |||
} | |||
}) | |||
} | |||
} | |||
/** | |||
* ------------------------------------------------------------------------ | |||
* jQuery | |||
* ------------------------------------------------------------------------ | |||
*/ | |||
$.fn[NAME] = Popover._jQueryInterface | |||
$.fn[NAME].Constructor = Popover | |||
$.fn[NAME].noConflict = () => { | |||
$.fn[NAME] = JQUERY_NO_CONFLICT | |||
return Popover._jQueryInterface | |||
} | |||
export default Popover |
@ -0,0 +1,326 @@ | |||
/** | |||
* -------------------------------------------------------------------------- | |||
* Bootstrap (v4.4.1): scrollspy.js | |||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) | |||
* -------------------------------------------------------------------------- | |||
*/ | |||
import $ from 'jquery' | |||
import Util from './util' | |||
/** | |||
* ------------------------------------------------------------------------ | |||
* Constants | |||
* ------------------------------------------------------------------------ | |||
*/ | |||
const NAME = 'scrollspy' | |||
const VERSION = '4.4.1' | |||
const DATA_KEY = 'bs.scrollspy' | |||
const EVENT_KEY = `.${DATA_KEY}` | |||
const DATA_API_KEY = '.data-api' | |||
const JQUERY_NO_CONFLICT = $.fn[NAME] | |||
const Default = { | |||
offset : 10, | |||
method : 'auto', | |||
target : '' | |||
} | |||
const DefaultType = { | |||
offset : 'number', | |||
method : 'string', | |||
target : '(string|element)' | |||
} | |||
const Event = { | |||
ACTIVATE : `activate${EVENT_KEY}`, | |||
SCROLL : `scroll${EVENT_KEY}`, | |||
LOAD_DATA_API : `load${EVENT_KEY}${DATA_API_KEY}` | |||
} | |||
const ClassName = { | |||
DROPDOWN_ITEM : 'dropdown-item', | |||
DROPDOWN_MENU : 'dropdown-menu', | |||
ACTIVE : 'active' | |||
} | |||
const Selector = { | |||
DATA_SPY : '[data-spy="scroll"]', | |||
ACTIVE : '.active', | |||
NAV_LIST_GROUP : '.nav, .list-group', | |||
NAV_LINKS : '.nav-link', | |||
NAV_ITEMS : '.nav-item', | |||
LIST_ITEMS : '.list-group-item', | |||
DROPDOWN : '.dropdown', | |||
DROPDOWN_ITEMS : '.dropdown-item', | |||
DROPDOWN_TOGGLE : '.dropdown-toggle' | |||
} | |||
const OffsetMethod = { | |||
OFFSET : 'offset', | |||
POSITION : 'position' | |||
} | |||
/** | |||
* ------------------------------------------------------------------------ | |||
* Class Definition | |||
* ------------------------------------------------------------------------ | |||
*/ | |||
class ScrollSpy { | |||
constructor(element, config) { | |||
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.LIST_ITEMS},` + | |||
`${this._config.target} ${Selector.DROPDOWN_ITEMS}` | |||
this._offsets = [] | |||
this._targets = [] | |||
this._activeTarget = null | |||
this._scrollHeight = 0 | |||
$(this._scrollElement).on(Event.SCROLL, (event) => this._process(event)) | |||
this.refresh() | |||
this._process() | |||
} | |||
// Getters | |||
static get VERSION() { | |||
return VERSION | |||
} | |||
static get Default() { | |||
return Default | |||
} | |||
// Public | |||
refresh() { | |||
const autoMethod = this._scrollElement === this._scrollElement.window | |||
? OffsetMethod.OFFSET : OffsetMethod.POSITION | |||
const offsetMethod = this._config.method === 'auto' | |||
? autoMethod : this._config.method | |||
const offsetBase = offsetMethod === OffsetMethod.POSITION | |||
? this._getScrollTop() : 0 | |||
this._offsets = [] | |||
this._targets = [] | |||
this._scrollHeight = this._getScrollHeight() | |||
const targets = [].slice.call(document.querySelectorAll(this._selector)) | |||
targets | |||
.map((element) => { | |||
let target | |||
const targetSelector = Util.getSelectorFromElement(element) | |||
if (targetSelector) { | |||
target = document.querySelector(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 | |||
}) | |||
.filter((item) => item) | |||
.sort((a, b) => a[0] - b[0]) | |||
.forEach((item) => { | |||
this._offsets.push(item[0]) | |||
this._targets.push(item[1]) | |||
}) | |||
} | |||
dispose() { | |||
$.removeData(this._element, DATA_KEY) | |||
$(this._scrollElement).off(EVENT_KEY) | |||
this._element = null | |||
this._scrollElement = null | |||
this._config = null | |||
this._selector = null | |||
this._offsets = null | |||
this._targets = null | |||
this._activeTarget = null | |||
this._scrollHeight = null | |||
} | |||
// Private | |||
_getConfig(config) { | |||
config = { | |||
...Default, | |||
...typeof config === 'object' && config ? config : {} | |||
} | |||
if (typeof config.target !== 'string') { | |||
let id = $(config.target).attr('id') | |||
if (!id) { | |||
id = Util.getUID(NAME) | |||
$(config.target).attr('id', id) | |||
} | |||
config.target = `#${id}` | |||
} | |||
Util.typeCheckConfig(NAME, config, DefaultType) | |||
return config | |||
} | |||
_getScrollTop() { | |||
return this._scrollElement === window | |||
? this._scrollElement.pageYOffset : this._scrollElement.scrollTop | |||
} | |||
_getScrollHeight() { | |||
return this._scrollElement.scrollHeight || Math.max( | |||
document.body.scrollHeight, | |||
document.documentElement.scrollHeight | |||
) | |||
} | |||
_getOffsetHeight() { | |||
return this._scrollElement === window | |||
? window.innerHeight : this._scrollElement.getBoundingClientRect().height | |||
} | |||
_process() { | |||
const scrollTop = this._getScrollTop() + this._config.offset | |||
const scrollHeight = this._getScrollHeight() | |||
const maxScroll = this._config.offset + | |||
scrollHeight - | |||
this._getOffsetHeight() | |||
if (this._scrollHeight !== scrollHeight) { | |||
this.refresh() | |||
} | |||
if (scrollTop >= maxScroll) { | |||
const target = this._targets[this._targets.length - 1] | |||
if (this._activeTarget !== target) { | |||
this._activate(target) | |||
} | |||
return | |||
} | |||
if (this._activeTarget && scrollTop < this._offsets[0] && this._offsets[0] > 0) { | |||
this._activeTarget = null | |||
this._clear() | |||
return | |||
} | |||
const offsetLength = this._offsets.length | |||
for (let i = offsetLength; i--;) { | |||
const isActiveTarget = this._activeTarget !== this._targets[i] && | |||
scrollTop >= this._offsets[i] && | |||
(typeof this._offsets[i + 1] === 'undefined' || | |||
scrollTop < this._offsets[i + 1]) | |||
if (isActiveTarget) { | |||
this._activate(this._targets[i]) | |||
} | |||
} | |||
} | |||
_activate(target) { | |||
this._activeTarget = target | |||
this._clear() | |||
const queries = this._selector | |||
.split(',') | |||
.map((selector) => `${selector}[data-target="${target}"],${selector}[href="${target}"]`) | |||
const $link = $([].slice.call(document.querySelectorAll(queries.join(',')))) | |||
if ($link.hasClass(ClassName.DROPDOWN_ITEM)) { | |||
$link.closest(Selector.DROPDOWN).find(Selector.DROPDOWN_TOGGLE).addClass(ClassName.ACTIVE) | |||
$link.addClass(ClassName.ACTIVE) | |||
} else { | |||
// 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) | |||
// Handle special case when .nav-link is inside .nav-item | |||
$link.parents(Selector.NAV_LIST_GROUP).prev(Selector.NAV_ITEMS).children(Selector.NAV_LINKS).addClass(ClassName.ACTIVE) | |||
} | |||
$(this._scrollElement).trigger(Event.ACTIVATE, { | |||
relatedTarget: target | |||
}) | |||
} | |||
_clear() { | |||
[].slice.call(document.querySelectorAll(this._selector)) | |||
.filter((node) => node.classList.contains(ClassName.ACTIVE)) | |||
.forEach((node) => node.classList.remove(ClassName.ACTIVE)) | |||
} | |||
// Static | |||
static _jQueryInterface(config) { | |||
return this.each(function () { | |||
let data = $(this).data(DATA_KEY) | |||
const _config = typeof config === 'object' && config | |||
if (!data) { | |||
data = new ScrollSpy(this, _config) | |||
$(this).data(DATA_KEY, data) | |||
} | |||
if (typeof config === 'string') { | |||
if (typeof data[config] === 'undefined') { | |||
throw new TypeError(`No method named "${config}"`) | |||
} | |||
data[config]() | |||
} | |||
}) | |||
} | |||
} | |||
/** | |||
* ------------------------------------------------------------------------ | |||
* Data Api implementation | |||
* ------------------------------------------------------------------------ | |||
*/ | |||
$(window).on(Event.LOAD_DATA_API, () => { | |||
const scrollSpys = [].slice.call(document.querySelectorAll(Selector.DATA_SPY)) | |||
const scrollSpysLength = scrollSpys.length | |||
for (let i = scrollSpysLength; i--;) { | |||
const $spy = $(scrollSpys[i]) | |||
ScrollSpy._jQueryInterface.call($spy, $spy.data()) | |||
} | |||
}) | |||
/** | |||
* ------------------------------------------------------------------------ | |||
* jQuery | |||
* ------------------------------------------------------------------------ | |||
*/ | |||
$.fn[NAME] = ScrollSpy._jQueryInterface | |||
$.fn[NAME].Constructor = ScrollSpy | |||
$.fn[NAME].noConflict = () => { | |||
$.fn[NAME] = JQUERY_NO_CONFLICT | |||
return ScrollSpy._jQueryInterface | |||
} | |||
export default ScrollSpy |
@ -0,0 +1,260 @@ | |||
/** | |||
* -------------------------------------------------------------------------- | |||
* Bootstrap (v4.4.1): tab.js | |||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) | |||
* -------------------------------------------------------------------------- | |||
*/ | |||
import $ from 'jquery' | |||
import Util from './util' | |||
/** | |||
* ------------------------------------------------------------------------ | |||
* Constants | |||
* ------------------------------------------------------------------------ | |||
*/ | |||
const NAME = 'tab' | |||
const VERSION = '4.4.1' | |||
const DATA_KEY = 'bs.tab' | |||
const EVENT_KEY = `.${DATA_KEY}` | |||
const DATA_API_KEY = '.data-api' | |||
const JQUERY_NO_CONFLICT = $.fn[NAME] | |||
const Event = { | |||
HIDE : `hide${EVENT_KEY}`, | |||
HIDDEN : `hidden${EVENT_KEY}`, | |||
SHOW : `show${EVENT_KEY}`, | |||
SHOWN : `shown${EVENT_KEY}`, | |||
CLICK_DATA_API : `click${EVENT_KEY}${DATA_API_KEY}` | |||
} | |||
const ClassName = { | |||
DROPDOWN_MENU : 'dropdown-menu', | |||
ACTIVE : 'active', | |||
DISABLED : 'disabled', | |||
FADE : 'fade', | |||
SHOW : 'show' | |||
} | |||
const Selector = { | |||
DROPDOWN : '.dropdown', | |||
NAV_LIST_GROUP : '.nav, .list-group', | |||
ACTIVE : '.active', | |||
ACTIVE_UL : '> li > .active', | |||
DATA_TOGGLE : '[data-toggle="tab"], [data-toggle="pill"], [data-toggle="list"]', | |||
DROPDOWN_TOGGLE : '.dropdown-toggle', | |||
DROPDOWN_ACTIVE_CHILD : '> .dropdown-menu .active' | |||
} | |||
/** | |||
* ------------------------------------------------------------------------ | |||
* Class Definition | |||
* ------------------------------------------------------------------------ | |||
*/ | |||
class Tab { | |||
constructor(element) { | |||
this._element = element | |||
} | |||
// Getters | |||
static get VERSION() { | |||
return VERSION | |||
} | |||
// Public | |||
show() { | |||
if (this._element.parentNode && | |||
this._element.parentNode.nodeType === Node.ELEMENT_NODE && | |||
$(this._element).hasClass(ClassName.ACTIVE) || | |||
$(this._element).hasClass(ClassName.DISABLED)) { | |||
return | |||
} | |||
let target | |||
let previous | |||
const listElement = $(this._element).closest(Selector.NAV_LIST_GROUP)[0] | |||
const selector = Util.getSelectorFromElement(this._element) | |||
if (listElement) { | |||
const itemSelector = listElement.nodeName === 'UL' || listElement.nodeName === 'OL' ? Selector.ACTIVE_UL : Selector.ACTIVE | |||
previous = $.makeArray($(listElement).find(itemSelector)) | |||
previous = previous[previous.length - 1] | |||
} | |||
const hideEvent = $.Event(Event.HIDE, { | |||
relatedTarget: this._element | |||
}) | |||
const showEvent = $.Event(Event.SHOW, { | |||
relatedTarget: previous | |||
}) | |||
if (previous) { | |||
$(previous).trigger(hideEvent) | |||
} | |||
$(this._element).trigger(showEvent) | |||
if (showEvent.isDefaultPrevented() || | |||
hideEvent.isDefaultPrevented()) { | |||
return | |||
} | |||
if (selector) { | |||
target = document.querySelector(selector) | |||
} | |||
this._activate( | |||
this._element, | |||
listElement | |||
) | |||
const complete = () => { | |||
const hiddenEvent = $.Event(Event.HIDDEN, { | |||
relatedTarget: this._element | |||
}) | |||
const shownEvent = $.Event(Event.SHOWN, { | |||
relatedTarget: previous | |||
}) | |||
$(previous).trigger(hiddenEvent) | |||
$(this._element).trigger(shownEvent) | |||
} | |||
if (target) { | |||
this._activate(target, target.parentNode, complete) | |||
} else { | |||
complete() | |||
} | |||
} | |||
dispose() { | |||
$.removeData(this._element, DATA_KEY) | |||
this._element = null | |||
} | |||
// Private | |||
_activate(element, container, callback) { | |||
const activeElements = container && (container.nodeName === 'UL' || container.nodeName === 'OL') | |||
? $(container).find(Selector.ACTIVE_UL) | |||
: $(container).children(Selector.ACTIVE) | |||
const active = activeElements[0] | |||
const isTransitioning = callback && (active && $(active).hasClass(ClassName.FADE)) | |||
const complete = () => this._transitionComplete( | |||
element, | |||
active, | |||
callback | |||
) | |||
if (active && isTransitioning) { | |||
const transitionDuration = Util.getTransitionDurationFromElement(active) | |||
$(active) | |||
.removeClass(ClassName.SHOW) | |||
.one(Util.TRANSITION_END, complete) | |||
.emulateTransitionEnd(transitionDuration) | |||
} else { | |||
complete() | |||
} | |||
} | |||
_transitionComplete(element, active, callback) { | |||
if (active) { | |||
$(active).removeClass(ClassName.ACTIVE) | |||
const dropdownChild = $(active.parentNode).find( | |||
Selector.DROPDOWN_ACTIVE_CHILD | |||
)[0] | |||
if (dropdownChild) { | |||
$(dropdownChild).removeClass(ClassName.ACTIVE) | |||
} | |||
if (active.getAttribute('role') === 'tab') { | |||
active.setAttribute('aria-selected', false) | |||
} | |||
} | |||
$(element).addClass(ClassName.ACTIVE) | |||
if (element.getAttribute('role') === 'tab') { | |||
element.setAttribute('aria-selected', true) | |||
} | |||
Util.reflow(element) | |||
if (element.classList.contains(ClassName.FADE)) { | |||
element.classList.add(ClassName.SHOW) | |||
} | |||
if (element.parentNode && $(element.parentNode).hasClass(ClassName.DROPDOWN_MENU)) { | |||
const dropdownElement = $(element).closest(Selector.DROPDOWN)[0] | |||
if (dropdownElement) { | |||
const dropdownToggleList = [].slice.call(dropdownElement.querySelectorAll(Selector.DROPDOWN_TOGGLE)) | |||
$(dropdownToggleList).addClass(ClassName.ACTIVE) | |||
} | |||
element.setAttribute('aria-expanded', true) | |||
} | |||
if (callback) { | |||
callback() | |||
} | |||
} | |||
// Static | |||
static _jQueryInterface(config) { | |||
return this.each(function () { | |||
const $this = $(this) | |||
let data = $this.data(DATA_KEY) | |||
if (!data) { | |||
data = new Tab(this) | |||
$this.data(DATA_KEY, data) | |||
} | |||
if (typeof config === 'string') { | |||
if (typeof data[config] === 'undefined') { | |||
throw new TypeError(`No method named "${config}"`) | |||
} | |||
data[config]() | |||
} | |||
}) | |||
} | |||
} | |||
/** | |||
* ------------------------------------------------------------------------ | |||
* Data Api implementation | |||
* ------------------------------------------------------------------------ | |||
*/ | |||
$(document) | |||
.on(Event.CLICK_DATA_API, Selector.DATA_TOGGLE, function (event) { | |||
event.preventDefault() | |||
Tab._jQueryInterface.call($(this), 'show') | |||
}) | |||
/** | |||
* ------------------------------------------------------------------------ | |||
* jQuery | |||
* ------------------------------------------------------------------------ | |||
*/ | |||
$.fn[NAME] = Tab._jQueryInterface | |||
$.fn[NAME].Constructor = Tab | |||
$.fn[NAME].noConflict = () => { | |||
$.fn[NAME] = JQUERY_NO_CONFLICT | |||
return Tab._jQueryInterface | |||
} | |||
export default Tab |
@ -0,0 +1,234 @@ | |||
/** | |||
* -------------------------------------------------------------------------- | |||
* Bootstrap (v4.4.1): toast.js | |||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) | |||
* -------------------------------------------------------------------------- | |||
*/ | |||
import $ from 'jquery' | |||
import Util from './util' | |||
/** | |||
* ------------------------------------------------------------------------ | |||
* Constants | |||
* ------------------------------------------------------------------------ | |||
*/ | |||
const NAME = 'toast' | |||
const VERSION = '4.4.1' | |||
const DATA_KEY = 'bs.toast' | |||
const EVENT_KEY = `.${DATA_KEY}` | |||
const JQUERY_NO_CONFLICT = $.fn[NAME] | |||
const Event = { | |||
CLICK_DISMISS : `click.dismiss${EVENT_KEY}`, | |||
HIDE : `hide${EVENT_KEY}`, | |||
HIDDEN : `hidden${EVENT_KEY}`, | |||
SHOW : `show${EVENT_KEY}`, | |||
SHOWN : `shown${EVENT_KEY}` | |||
} | |||
const ClassName = { | |||
FADE : 'fade', | |||
HIDE : 'hide', | |||
SHOW : 'show', | |||
SHOWING : 'showing' | |||
} | |||
const DefaultType = { | |||
animation : 'boolean', | |||
autohide : 'boolean', | |||
delay : 'number' | |||
} | |||
const Default = { | |||
animation : true, | |||
autohide : true, | |||
delay : 500 | |||
} | |||
const Selector = { | |||
DATA_DISMISS : '[data-dismiss="toast"]' | |||
} | |||
/** | |||
* ------------------------------------------------------------------------ | |||
* Class Definition | |||
* ------------------------------------------------------------------------ | |||
*/ | |||
class Toast { | |||
constructor(element, config) { | |||
this._element = element | |||
this._config = this._getConfig(config) | |||
this._timeout = null | |||
this._setListeners() | |||
} | |||
// Getters | |||
static get VERSION() { | |||
return VERSION | |||
} | |||
static get DefaultType() { | |||
return DefaultType | |||
} | |||
static get Default() { | |||
return Default | |||
} | |||
// Public | |||
show() { | |||
const showEvent = $.Event(Event.SHOW) | |||
$(this._element).trigger(showEvent) | |||
if (showEvent.isDefaultPrevented()) { | |||
return | |||
} | |||
if (this._config.animation) { | |||
this._element.classList.add(ClassName.FADE) | |||
} | |||
const complete = () => { | |||
this._element.classList.remove(ClassName.SHOWING) | |||
this._element.classList.add(ClassName.SHOW) | |||
$(this._element).trigger(Event.SHOWN) | |||
if (this._config.autohide) { | |||
this._timeout = setTimeout(() => { | |||
this.hide() | |||
}, this._config.delay) | |||
} | |||
} | |||
this._element.classList.remove(ClassName.HIDE) | |||
Util.reflow(this._element) | |||
this._element.classList.add(ClassName.SHOWING) | |||
if (this._config.animation) { | |||
const transitionDuration = Util.getTransitionDurationFromElement(this._element) | |||
$(this._element) | |||
.one(Util.TRANSITION_END, complete) | |||
.emulateTransitionEnd(transitionDuration) | |||
} else { | |||
complete() | |||
} | |||
} | |||
hide() { | |||
if (!this._element.classList.contains(ClassName.SHOW)) { | |||
return | |||
} | |||
const hideEvent = $.Event(Event.HIDE) | |||
$(this._element).trigger(hideEvent) | |||
if (hideEvent.isDefaultPrevented()) { | |||
return | |||
} | |||
this._close() | |||
} | |||
dispose() { | |||
clearTimeout(this._timeout) | |||
this._timeout = null | |||
if (this._element.classList.contains(ClassName.SHOW)) { | |||
this._element.classList.remove(ClassName.SHOW) | |||
} | |||
$(this._element).off(Event.CLICK_DISMISS) | |||
$.removeData(this._element, DATA_KEY) | |||
this._element = null | |||
this._config = null | |||
} | |||
// Private | |||
_getConfig(config) { | |||
config = { | |||
...Default, | |||
...$(this._element).data(), | |||
...typeof config === 'object' && config ? config : {} | |||
} | |||
Util.typeCheckConfig( | |||
NAME, | |||
config, | |||
this.constructor.DefaultType | |||
) | |||
return config | |||
} | |||
_setListeners() { | |||
$(this._element).on( | |||
Event.CLICK_DISMISS, | |||
Selector.DATA_DISMISS, | |||
() => this.hide() | |||
) | |||
} | |||
_close() { | |||
const complete = () => { | |||
this._element.classList.add(ClassName.HIDE) | |||
$(this._element).trigger(Event.HIDDEN) | |||
} | |||
this._element.classList.remove(ClassName.SHOW) | |||
if (this._config.animation) { | |||
const transitionDuration = Util.getTransitionDurationFromElement(this._element) | |||
$(this._element) | |||
.one(Util.TRANSITION_END, complete) | |||
.emulateTransitionEnd(transitionDuration) | |||
} else { | |||
complete() | |||
} | |||
} | |||
// Static | |||
static _jQueryInterface(config) { | |||
return this.each(function () { | |||
const $element = $(this) | |||
let data = $element.data(DATA_KEY) | |||
const _config = typeof config === 'object' && config | |||
if (!data) { | |||
data = new Toast(this, _config) | |||
$element.data(DATA_KEY, data) | |||
} | |||
if (typeof config === 'string') { | |||
if (typeof data[config] === 'undefined') { | |||
throw new TypeError(`No method named "${config}"`) | |||
} | |||
data[config](this) | |||
} | |||
}) | |||
} | |||
} | |||
/** | |||
* ------------------------------------------------------------------------ | |||
* jQuery | |||
* ------------------------------------------------------------------------ | |||
*/ | |||
$.fn[NAME] = Toast._jQueryInterface | |||
$.fn[NAME].Constructor = Toast | |||
$.fn[NAME].noConflict = () => { | |||
$.fn[NAME] = JQUERY_NO_CONFLICT | |||
return Toast._jQueryInterface | |||
} | |||
export default Toast |
@ -0,0 +1,127 @@ | |||
/** | |||
* -------------------------------------------------------------------------- | |||
* Bootstrap (v4.4.1): tools/sanitizer.js | |||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) | |||
* -------------------------------------------------------------------------- | |||
*/ | |||
const uriAttrs = [ | |||
'background', | |||
'cite', | |||
'href', | |||
'itemtype', | |||
'longdesc', | |||
'poster', | |||
'src', | |||
'xlink:href' | |||
] | |||
const ARIA_ATTRIBUTE_PATTERN = /^aria-[\w-]*$/i | |||
export const DefaultWhitelist = { | |||
// Global attributes allowed on any supplied element below. | |||
'*': ['class', 'dir', 'id', 'lang', 'role', ARIA_ATTRIBUTE_PATTERN], | |||
a: ['target', 'href', 'title', 'rel'], | |||
area: [], | |||
b: [], | |||
br: [], | |||
col: [], | |||
code: [], | |||
div: [], | |||
em: [], | |||
hr: [], | |||
h1: [], | |||
h2: [], | |||
h3: [], | |||
h4: [], | |||
h5: [], | |||
h6: [], | |||
i: [], | |||
img: ['src', 'alt', 'title', 'width', 'height'], | |||
li: [], | |||
ol: [], | |||
p: [], | |||
pre: [], | |||
s: [], | |||
small: [], | |||
span: [], | |||
sub: [], | |||
sup: [], | |||
strong: [], | |||
u: [], | |||
ul: [] | |||
} | |||
/** | |||
* A pattern that recognizes a commonly useful subset of URLs that are safe. | |||
* | |||
* Shoutout to Angular 7 https://github.com/angular/angular/blob/7.2.4/packages/core/src/sanitization/url_sanitizer.ts | |||
*/ | |||
const SAFE_URL_PATTERN = /^(?:(?:https?|mailto|ftp|tel|file):|[^&:/?#]*(?:[/?#]|$))/gi | |||
/** | |||
* A pattern that matches safe data URLs. Only matches image, video and audio types. | |||
* | |||
* Shoutout to Angular 7 https://github.com/angular/angular/blob/7.2.4/packages/core/src/sanitization/url_sanitizer.ts | |||
*/ | |||
const DATA_URL_PATTERN = /^data:(?:image\/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|video\/(?:mpeg|mp4|ogg|webm)|audio\/(?:mp3|oga|ogg|opus));base64,[a-z0-9+/]+=*$/i | |||
function allowedAttribute(attr, allowedAttributeList) { | |||
const attrName = attr.nodeName.toLowerCase() | |||
if (allowedAttributeList.indexOf(attrName) !== -1) { | |||
if (uriAttrs.indexOf(attrName) !== -1) { | |||
return Boolean(attr.nodeValue.match(SAFE_URL_PATTERN) || attr.nodeValue.match(DATA_URL_PATTERN)) | |||
} | |||
return true | |||
} | |||
const regExp = allowedAttributeList.filter((attrRegex) => attrRegex instanceof RegExp) | |||
// Check if a regular expression validates the attribute. | |||
for (let i = 0, l = regExp.length; i < l; i++) { | |||
if (attrName.match(regExp[i])) { | |||
return true | |||
} | |||
} | |||
return false | |||
} | |||
export function sanitizeHtml(unsafeHtml, whiteList, sanitizeFn) { | |||
if (unsafeHtml.length === 0) { | |||
return unsafeHtml | |||
} | |||
if (sanitizeFn && typeof sanitizeFn === 'function') { | |||
return sanitizeFn(unsafeHtml) | |||
} | |||
const domParser = new window.DOMParser() | |||
const createdDocument = domParser.parseFromString(unsafeHtml, 'text/html') | |||
const whitelistKeys = Object.keys(whiteList) | |||
const elements = [].slice.call(createdDocument.body.querySelectorAll('*')) | |||
for (let i = 0, len = elements.length; i < len; i++) { | |||
const el = elements[i] | |||
const elName = el.nodeName.toLowerCase() | |||
if (whitelistKeys.indexOf(el.nodeName.toLowerCase()) === -1) { | |||
el.parentNode.removeChild(el) | |||
continue | |||
} | |||
const attributeList = [].slice.call(el.attributes) | |||
const whitelistedAttributes = [].concat(whiteList['*'] || [], whiteList[elName] || []) | |||
attributeList.forEach((attr) => { | |||
if (!allowedAttribute(attr, whitelistedAttributes)) { | |||
el.removeAttribute(attr.nodeName) | |||
} | |||
}) | |||
} | |||
return createdDocument.body.innerHTML | |||
} |
@ -0,0 +1,794 @@ | |||
/** | |||
* -------------------------------------------------------------------------- | |||
* Bootstrap (v4.4.1): tooltip.js | |||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) | |||
* -------------------------------------------------------------------------- | |||
*/ | |||
import { | |||
DefaultWhitelist, | |||
sanitizeHtml | |||
} from './tools/sanitizer' | |||
import $ from 'jquery' | |||
import Popper from 'popper.js' | |||
import Util from './util' | |||
/** | |||
* ------------------------------------------------------------------------ | |||
* Constants | |||
* ------------------------------------------------------------------------ | |||
*/ | |||
const NAME = 'tooltip' | |||
const VERSION = '4.4.1' | |||
const DATA_KEY = 'bs.tooltip' | |||
const EVENT_KEY = `.${DATA_KEY}` | |||
const JQUERY_NO_CONFLICT = $.fn[NAME] | |||
const CLASS_PREFIX = 'bs-tooltip' | |||
const BSCLS_PREFIX_REGEX = new RegExp(`(^|\\s)${CLASS_PREFIX}\\S+`, 'g') | |||
const DISALLOWED_ATTRIBUTES = ['sanitize', 'whiteList', 'sanitizeFn'] | |||
const DefaultType = { | |||
animation : 'boolean', | |||
template : 'string', | |||
title : '(string|element|function)', | |||
trigger : 'string', | |||
delay : '(number|object)', | |||
html : 'boolean', | |||
selector : '(string|boolean)', | |||
placement : '(string|function)', | |||
offset : '(number|string|function)', | |||
container : '(string|element|boolean)', | |||
fallbackPlacement : '(string|array)', | |||
boundary : '(string|element)', | |||
sanitize : 'boolean', | |||
sanitizeFn : '(null|function)', | |||
whiteList : 'object', | |||
popperConfig : '(null|object)' | |||
} | |||
const AttachmentMap = { | |||
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', | |||
boundary : 'scrollParent', | |||
sanitize : true, | |||
sanitizeFn : null, | |||
whiteList : DefaultWhitelist, | |||
popperConfig : null | |||
} | |||
const HoverState = { | |||
SHOW : 'show', | |||
OUT : 'out' | |||
} | |||
const Event = { | |||
HIDE : `hide${EVENT_KEY}`, | |||
HIDDEN : `hidden${EVENT_KEY}`, | |||
SHOW : `show${EVENT_KEY}`, | |||
SHOWN : `shown${EVENT_KEY}`, | |||
INSERTED : `inserted${EVENT_KEY}`, | |||
CLICK : `click${EVENT_KEY}`, | |||
FOCUSIN : `focusin${EVENT_KEY}`, | |||
FOCUSOUT : `focusout${EVENT_KEY}`, | |||
MOUSEENTER : `mouseenter${EVENT_KEY}`, | |||
MOUSELEAVE : `mouseleave${EVENT_KEY}` | |||
} | |||
const ClassName = { | |||
FADE : 'fade', | |||
SHOW : 'show' | |||
} | |||
const Selector = { | |||
TOOLTIP : '.tooltip', | |||
TOOLTIP_INNER : '.tooltip-inner', | |||
ARROW : '.arrow' | |||
} | |||
const Trigger = { | |||
HOVER : 'hover', | |||
FOCUS : 'focus', | |||
CLICK : 'click', | |||
MANUAL : 'manual' | |||
} | |||
/** | |||
* ------------------------------------------------------------------------ | |||
* Class Definition | |||
* ------------------------------------------------------------------------ | |||
*/ | |||
class Tooltip { | |||
constructor(element, config) { | |||
if (typeof Popper === 'undefined') { | |||
throw new TypeError('Bootstrap\'s tooltips require Popper.js (https://popper.js.org/)') | |||
} | |||
// private | |||
this._isEnabled = true | |||
this._timeout = 0 | |||
this._hoverState = '' | |||
this._activeTrigger = {} | |||
this._popper = null | |||
// Protected | |||
this.element = element | |||
this.config = this._getConfig(config) | |||
this.tip = null | |||
this._setListeners() | |||
} | |||
// Getters | |||
static get VERSION() { | |||
return VERSION | |||
} | |||
static get Default() { | |||
return Default | |||
} | |||
static get NAME() { | |||
return NAME | |||
} | |||
static get DATA_KEY() { | |||
return DATA_KEY | |||
} | |||
static get Event() { | |||
return Event | |||
} | |||
static get EVENT_KEY() { | |||
return EVENT_KEY | |||
} | |||
static get DefaultType() { | |||
return DefaultType | |||
} | |||
// Public | |||
enable() { | |||
this._isEnabled = true | |||
} | |||
disable() { | |||
this._isEnabled = false | |||
} | |||
toggleEnabled() { | |||
this._isEnabled = !this._isEnabled | |||
} | |||
toggle(event) { | |||
if (!this._isEnabled) { | |||
return | |||
} | |||
if (event) { | |||
const dataKey = this.constructor.DATA_KEY | |||
let context = $(event.currentTarget).data(dataKey) | |||
if (!context) { | |||
context = new this.constructor( | |||
event.currentTarget, | |||
this._getDelegateConfig() | |||
) | |||
$(event.currentTarget).data(dataKey, context) | |||
} | |||
context._activeTrigger.click = !context._activeTrigger.click | |||
if (context._isWithActiveTrigger()) { | |||
context._enter(null, context) | |||
} else { | |||
context._leave(null, context) | |||
} | |||
} else { | |||
if ($(this.getTipElement()).hasClass(ClassName.SHOW)) { | |||
this._leave(null, this) | |||
return | |||
} | |||
this._enter(null, this) | |||
} | |||
} | |||
dispose() { | |||
clearTimeout(this._timeout) | |||
$.removeData(this.element, this.constructor.DATA_KEY) | |||
$(this.element).off(this.constructor.EVENT_KEY) | |||
$(this.element).closest('.modal').off('hide.bs.modal', this._hideModalHandler) | |||
if (this.tip) { | |||
$(this.tip).remove() | |||
} | |||
this._isEnabled = null | |||
this._timeout = null | |||
this._hoverState = null | |||
this._activeTrigger = null | |||
if (this._popper) { | |||
this._popper.destroy() | |||
} | |||
this._popper = null | |||
this.element = null | |||
this.config = null | |||
this.tip = null | |||
} | |||
show() { | |||
if ($(this.element).css('display') === 'none') { | |||
throw new Error('Please use show on visible elements') | |||
} | |||
const showEvent = $.Event(this.constructor.Event.SHOW) | |||
if (this.isWithContent() && this._isEnabled) { | |||
$(this.element).trigger(showEvent) | |||
const shadowRoot = Util.findShadowRoot(this.element) | |||
const isInTheDom = $.contains( | |||
shadowRoot !== null ? shadowRoot : this.element.ownerDocument.documentElement, | |||
this.element | |||
) | |||
if (showEvent.isDefaultPrevented() || !isInTheDom) { | |||
return | |||
} | |||
const tip = this.getTipElement() | |||
const tipId = Util.getUID(this.constructor.NAME) | |||
tip.setAttribute('id', tipId) | |||
this.element.setAttribute('aria-describedby', tipId) | |||
this.setContent() | |||
if (this.config.animation) { | |||
$(tip).addClass(ClassName.FADE) | |||
} | |||
const placement = typeof this.config.placement === 'function' | |||
? this.config.placement.call(this, tip, this.element) | |||
: this.config.placement | |||
const attachment = this._getAttachment(placement) | |||
this.addAttachmentClass(attachment) | |||
const container = this._getContainer() | |||
$(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._popper = new Popper(this.element, tip, this._getPopperConfig(attachment)) | |||
$(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) { | |||
$(document.body).children().on('mouseover', null, $.noop) | |||
} | |||
const complete = () => { | |||
if (this.config.animation) { | |||
this._fixTransition() | |||
} | |||
const prevHoverState = this._hoverState | |||
this._hoverState = null | |||
$(this.element).trigger(this.constructor.Event.SHOWN) | |||
if (prevHoverState === HoverState.OUT) { | |||
this._leave(null, this) | |||
} | |||
} | |||
if ($(this.tip).hasClass(ClassName.FADE)) { | |||
const transitionDuration = Util.getTransitionDurationFromElement(this.tip) | |||
$(this.tip) | |||
.one(Util.TRANSITION_END, complete) | |||
.emulateTransitionEnd(transitionDuration) | |||
} else { | |||
complete() | |||
} | |||
} | |||
} | |||
hide(callback) { | |||
const tip = this.getTipElement() | |||
const hideEvent = $.Event(this.constructor.Event.HIDE) | |||
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) | |||
if (this._popper !== null) { | |||
this._popper.destroy() | |||
} | |||
if (callback) { | |||
callback() | |||
} | |||
} | |||
$(this.element).trigger(hideEvent) | |||
if (hideEvent.isDefaultPrevented()) { | |||
return | |||
} | |||
$(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) { | |||
$(document.body).children().off('mouseover', null, $.noop) | |||
} | |||
this._activeTrigger[Trigger.CLICK] = false | |||
this._activeTrigger[Trigger.FOCUS] = false | |||
this._activeTrigger[Trigger.HOVER] = false | |||
if ($(this.tip).hasClass(ClassName.FADE)) { | |||
const transitionDuration = Util.getTransitionDurationFromElement(tip) | |||
$(tip) | |||
.one(Util.TRANSITION_END, complete) | |||
.emulateTransitionEnd(transitionDuration) | |||
} else { | |||
complete() | |||
} | |||
this._hoverState = '' | |||
} | |||
update() { | |||
if (this._popper !== null) { | |||
this._popper.scheduleUpdate() | |||
} | |||
} | |||
// Protected | |||
isWithContent() { | |||
return Boolean(this.getTitle()) | |||
} | |||
addAttachmentClass(attachment) { | |||
$(this.getTipElement()).addClass(`${CLASS_PREFIX}-${attachment}`) | |||
} | |||
getTipElement() { | |||
this.tip = this.tip || $(this.config.template)[0] | |||
return this.tip | |||
} | |||
setContent() { | |||
const tip = this.getTipElement() | |||
this.setElementContent($(tip.querySelectorAll(Selector.TOOLTIP_INNER)), this.getTitle()) | |||
$(tip).removeClass(`${ClassName.FADE} ${ClassName.SHOW}`) | |||
} | |||
setElementContent($element, content) { | |||
if (typeof content === 'object' && (content.nodeType || content.jquery)) { | |||
// Content is a DOM node or a jQuery | |||
if (this.config.html) { | |||
if (!$(content).parent().is($element)) { | |||
$element.empty().append(content) | |||
} | |||
} else { | |||
$element.text($(content).text()) | |||
} | |||
return | |||
} | |||
if (this.config.html) { | |||
if (this.config.sanitize) { | |||
content = sanitizeHtml(content, this.config.whiteList, this.config.sanitizeFn) | |||
} | |||
$element.html(content) | |||
} else { | |||
$element.text(content) | |||
} | |||
} | |||
getTitle() { | |||
let title = this.element.getAttribute('data-original-title') | |||
if (!title) { | |||
title = typeof this.config.title === 'function' | |||
? this.config.title.call(this.element) | |||
: this.config.title | |||
} | |||
return title | |||
} | |||
// Private | |||
_getPopperConfig(attachment) { | |||
const defaultBsConfig = { | |||
placement: attachment, | |||
modifiers: { | |||
offset: this._getOffset(), | |||
flip: { | |||
behavior: this.config.fallbackPlacement | |||
}, | |||
arrow: { | |||
element: Selector.ARROW | |||
}, | |||
preventOverflow: { | |||
boundariesElement: this.config.boundary | |||
} | |||
}, | |||
onCreate: (data) => { | |||
if (data.originalPlacement !== data.placement) { | |||
this._handlePopperPlacementChange(data) | |||
} | |||
}, | |||
onUpdate: (data) => this._handlePopperPlacementChange(data) | |||
} | |||
return { | |||
...defaultBsConfig, | |||
...this.config.popperConfig | |||
} | |||
} | |||
_getOffset() { | |||
const offset = {} | |||
if (typeof this.config.offset === 'function') { | |||
offset.fn = (data) => { | |||
data.offsets = { | |||
...data.offsets, | |||
...this.config.offset(data.offsets, this.element) || {} | |||
} | |||
return data | |||
} | |||
} else { | |||
offset.offset = this.config.offset | |||
} | |||
return offset | |||
} | |||
_getContainer() { | |||
if (this.config.container === false) { | |||
return document.body | |||
} | |||
if (Util.isElement(this.config.container)) { | |||
return $(this.config.container) | |||
} | |||
return $(document).find(this.config.container) | |||
} | |||
_getAttachment(placement) { | |||
return AttachmentMap[placement.toUpperCase()] | |||
} | |||
_setListeners() { | |||
const triggers = this.config.trigger.split(' ') | |||
triggers.forEach((trigger) => { | |||
if (trigger === 'click') { | |||
$(this.element).on( | |||
this.constructor.Event.CLICK, | |||
this.config.selector, | |||
(event) => this.toggle(event) | |||
) | |||
} else if (trigger !== Trigger.MANUAL) { | |||
const eventIn = trigger === Trigger.HOVER | |||
? this.constructor.Event.MOUSEENTER | |||
: this.constructor.Event.FOCUSIN | |||
const eventOut = trigger === Trigger.HOVER | |||
? this.constructor.Event.MOUSELEAVE | |||
: this.constructor.Event.FOCUSOUT | |||
$(this.element) | |||
.on( | |||
eventIn, | |||
this.config.selector, | |||
(event) => this._enter(event) | |||
) | |||
.on( | |||
eventOut, | |||
this.config.selector, | |||
(event) => this._leave(event) | |||
) | |||
} | |||
}) | |||
this._hideModalHandler = () => { | |||
if (this.element) { | |||
this.hide() | |||
} | |||
} | |||
$(this.element).closest('.modal').on( | |||
'hide.bs.modal', | |||
this._hideModalHandler | |||
) | |||
if (this.config.selector) { | |||
this.config = { | |||
...this.config, | |||
trigger: 'manual', | |||
selector: '' | |||
} | |||
} else { | |||
this._fixTitle() | |||
} | |||
} | |||
_fixTitle() { | |||
const titleType = typeof this.element.getAttribute('data-original-title') | |||
if (this.element.getAttribute('title') || titleType !== 'string') { | |||
this.element.setAttribute( | |||
'data-original-title', | |||
this.element.getAttribute('title') || '' | |||
) | |||
this.element.setAttribute('title', '') | |||
} | |||
} | |||
_enter(event, context) { | |||
const dataKey = this.constructor.DATA_KEY | |||
context = context || $(event.currentTarget).data(dataKey) | |||
if (!context) { | |||
context = new this.constructor( | |||
event.currentTarget, | |||
this._getDelegateConfig() | |||
) | |||
$(event.currentTarget).data(dataKey, context) | |||
} | |||
if (event) { | |||
context._activeTrigger[ | |||
event.type === 'focusin' ? Trigger.FOCUS : Trigger.HOVER | |||
] = true | |||
} | |||
if ($(context.getTipElement()).hasClass(ClassName.SHOW) || context._hoverState === HoverState.SHOW) { | |||
context._hoverState = HoverState.SHOW | |||
return | |||
} | |||
clearTimeout(context._timeout) | |||
context._hoverState = HoverState.SHOW | |||
if (!context.config.delay || !context.config.delay.show) { | |||
context.show() | |||
return | |||
} | |||
context._timeout = setTimeout(() => { | |||
if (context._hoverState === HoverState.SHOW) { | |||
context.show() | |||
} | |||
}, context.config.delay.show) | |||
} | |||
_leave(event, context) { | |||
const dataKey = this.constructor.DATA_KEY | |||
context = context || $(event.currentTarget).data(dataKey) | |||
if (!context) { | |||
context = new this.constructor( | |||
event.currentTarget, | |||
this._getDelegateConfig() | |||
) | |||
$(event.currentTarget).data(dataKey, context) | |||
} | |||
if (event) { | |||
context._activeTrigger[ | |||
event.type === 'focusout' ? Trigger.FOCUS : Trigger.HOVER | |||
] = false | |||
} | |||
if (context._isWithActiveTrigger()) { | |||
return | |||
} | |||
clearTimeout(context._timeout) | |||
context._hoverState = HoverState.OUT | |||
if (!context.config.delay || !context.config.delay.hide) { | |||
context.hide() | |||
return | |||
} | |||
context._timeout = setTimeout(() => { | |||
if (context._hoverState === HoverState.OUT) { | |||
context.hide() | |||
} | |||
}, context.config.delay.hide) | |||
} | |||
_isWithActiveTrigger() { | |||
for (const trigger in this._activeTrigger) { | |||
if (this._activeTrigger[trigger]) { | |||
return true | |||
} | |||
} | |||
return false | |||
} | |||
_getConfig(config) { | |||
const dataAttributes = $(this.element).data() | |||
Object.keys(dataAttributes) | |||
.forEach((dataAttr) => { | |||
if (DISALLOWED_ATTRIBUTES.indexOf(dataAttr) !== -1) { | |||
delete dataAttributes[dataAttr] | |||
} | |||
}) | |||
config = { | |||
...this.constructor.Default, | |||
...dataAttributes, | |||
...typeof config === 'object' && config ? config : {} | |||
} | |||
if (typeof config.delay === 'number') { | |||
config.delay = { | |||
show: config.delay, | |||
hide: config.delay | |||
} | |||
} | |||
if (typeof config.title === 'number') { | |||
config.title = config.title.toString() | |||
} | |||
if (typeof config.content === 'number') { | |||
config.content = config.content.toString() | |||
} | |||
Util.typeCheckConfig( | |||
NAME, | |||
config, | |||
this.constructor.DefaultType | |||
) | |||
if (config.sanitize) { | |||
config.template = sanitizeHtml(config.template, config.whiteList, config.sanitizeFn) | |||
} | |||
return config | |||
} | |||
_getDelegateConfig() { | |||
const config = {} | |||
if (this.config) { | |||
for (const key in this.config) { | |||
if (this.constructor.Default[key] !== this.config[key]) { | |||
config[key] = this.config[key] | |||
} | |||
} | |||
} | |||
return config | |||
} | |||
_cleanTipClass() { | |||
const $tip = $(this.getTipElement()) | |||
const tabClass = $tip.attr('class').match(BSCLS_PREFIX_REGEX) | |||
if (tabClass !== null && tabClass.length) { | |||
$tip.removeClass(tabClass.join('')) | |||
} | |||
} | |||
_handlePopperPlacementChange(popperData) { | |||
const popperInstance = popperData.instance | |||
this.tip = popperInstance.popper | |||
this._cleanTipClass() | |||
this.addAttachmentClass(this._getAttachment(popperData.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 | |||
static _jQueryInterface(config) { | |||
return this.each(function () { | |||
let data = $(this).data(DATA_KEY) | |||
const _config = typeof config === 'object' && config | |||
if (!data && /dispose|hide/.test(config)) { | |||
return | |||
} | |||
if (!data) { | |||
data = new Tooltip(this, _config) | |||
$(this).data(DATA_KEY, data) | |||
} | |||
if (typeof config === 'string') { | |||
if (typeof data[config] === 'undefined') { | |||
throw new TypeError(`No method named "${config}"`) | |||
} | |||
data[config]() | |||
} | |||
}) | |||
} | |||
} | |||
/** | |||
* ------------------------------------------------------------------------ | |||
* jQuery | |||
* ------------------------------------------------------------------------ | |||
*/ | |||
$.fn[NAME] = Tooltip._jQueryInterface | |||
$.fn[NAME].Constructor = Tooltip | |||
$.fn[NAME].noConflict = () => { | |||
$.fn[NAME] = JQUERY_NO_CONFLICT | |||
return Tooltip._jQueryInterface | |||
} | |||
export default Tooltip |
@ -0,0 +1,195 @@ | |||
/** | |||
* -------------------------------------------------------------------------- | |||
* Bootstrap (v4.4.1): util.js | |||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) | |||
* -------------------------------------------------------------------------- | |||
*/ | |||
import $ from 'jquery' | |||
/** | |||
* ------------------------------------------------------------------------ | |||
* Private TransitionEnd Helpers | |||
* ------------------------------------------------------------------------ | |||
*/ | |||
const TRANSITION_END = 'transitionend' | |||
const MAX_UID = 1000000 | |||
const MILLISECONDS_MULTIPLIER = 1000 | |||
// Shoutout AngusCroll (https://goo.gl/pxwQGp) | |||
function toType(obj) { | |||
return {}.toString.call(obj).match(/\s([a-z]+)/i)[1].toLowerCase() | |||
} | |||
function getSpecialTransitionEndEvent() { | |||
return { | |||
bindType: TRANSITION_END, | |||
delegateType: TRANSITION_END, | |||
handle(event) { | |||
if ($(event.target).is(this)) { | |||
return event.handleObj.handler.apply(this, arguments) // eslint-disable-line prefer-rest-params | |||
} | |||
return undefined // eslint-disable-line no-undefined | |||
} | |||
} | |||
} | |||
function transitionEndEmulator(duration) { | |||
let called = false | |||
$(this).one(Util.TRANSITION_END, () => { | |||
called = true | |||
}) | |||
setTimeout(() => { | |||
if (!called) { | |||
Util.triggerTransitionEnd(this) | |||
} | |||
}, duration) | |||
return this | |||
} | |||
function setTransitionEndSupport() { | |||
$.fn.emulateTransitionEnd = transitionEndEmulator | |||
$.event.special[Util.TRANSITION_END] = getSpecialTransitionEndEvent() | |||
} | |||
/** | |||
* -------------------------------------------------------------------------- | |||
* Public Util Api | |||
* -------------------------------------------------------------------------- | |||
*/ | |||
const Util = { | |||
TRANSITION_END: 'bsTransitionEnd', | |||
getUID(prefix) { | |||
do { | |||
// eslint-disable-next-line no-bitwise | |||
prefix += ~~(Math.random() * MAX_UID) // "~~" acts like a faster Math.floor() here | |||
} while (document.getElementById(prefix)) | |||
return prefix | |||
}, | |||
getSelectorFromElement(element) { | |||
let selector = element.getAttribute('data-target') | |||
if (!selector || selector === '#') { | |||
const hrefAttr = element.getAttribute('href') | |||
selector = hrefAttr && hrefAttr !== '#' ? hrefAttr.trim() : '' | |||
} | |||
try { | |||
return document.querySelector(selector) ? selector : null | |||
} catch (err) { | |||
return null | |||
} | |||
}, | |||
getTransitionDurationFromElement(element) { | |||
if (!element) { | |||
return 0 | |||
} | |||
// Get transition-duration of the element | |||
let transitionDuration = $(element).css('transition-duration') | |||
let transitionDelay = $(element).css('transition-delay') | |||
const floatTransitionDuration = parseFloat(transitionDuration) | |||
const floatTransitionDelay = parseFloat(transitionDelay) | |||
// Return 0 if element or transition duration is not found | |||
if (!floatTransitionDuration && !floatTransitionDelay) { | |||
return 0 | |||
} | |||
// If multiple durations are defined, take the first | |||
transitionDuration = transitionDuration.split(',')[0] | |||
transitionDelay = transitionDelay.split(',')[0] | |||
return (parseFloat(transitionDuration) + parseFloat(transitionDelay)) * MILLISECONDS_MULTIPLIER | |||
}, | |||
reflow(element) { | |||
return element.offsetHeight | |||
}, | |||
triggerTransitionEnd(element) { | |||
$(element).trigger(TRANSITION_END) | |||
}, | |||
// TODO: Remove in v5 | |||
supportsTransitionEnd() { | |||
return Boolean(TRANSITION_END) | |||
}, | |||
isElement(obj) { | |||
return (obj[0] || obj).nodeType | |||
}, | |||
typeCheckConfig(componentName, config, configTypes) { | |||
for (const property in configTypes) { | |||
if (Object.prototype.hasOwnProperty.call(configTypes, property)) { | |||
const expectedTypes = configTypes[property] | |||
const value = config[property] | |||
const valueType = value && Util.isElement(value) | |||
? 'element' : toType(value) | |||
if (!new RegExp(expectedTypes).test(valueType)) { | |||
throw new Error( | |||
`${componentName.toUpperCase()}: ` + | |||
`Option "${property}" provided type "${valueType}" ` + | |||
`but expected type "${expectedTypes}".`) | |||
} | |||
} | |||
} | |||
}, | |||
findShadowRoot(element) { | |||
if (!document.documentElement.attachShadow) { | |||
return null | |||
} | |||
// Can find the shadow root otherwise it'll return the document | |||
if (typeof element.getRootNode === 'function') { | |||
const root = element.getRootNode() | |||
return root instanceof ShadowRoot ? root : null | |||
} | |||
if (element instanceof ShadowRoot) { | |||
return element | |||
} | |||
// when we don't find a shadow root | |||
if (!element.parentNode) { | |||
return null | |||
} | |||
return Util.findShadowRoot(element.parentNode) | |||
}, | |||
jQueryDetection() { | |||
if (typeof $ === 'undefined') { | |||
throw new TypeError('Bootstrap\'s JavaScript requires jQuery. jQuery must be included before Bootstrap\'s JavaScript.') | |||
} | |||
const version = $.fn.jquery.split(' ')[0].split('.') | |||
const minMajor = 1 | |||
const ltMajor = 2 | |||
const minMinor = 9 | |||
const minPatch = 1 | |||
const maxMajor = 4 | |||
if (version[0] < ltMajor && version[1] < minMinor || version[0] === minMajor && version[1] === minMinor && version[2] < minPatch || version[0] >= maxMajor) { | |||
throw new Error('Bootstrap\'s JavaScript requires at least jQuery v1.9.1 but less than v4.0.0') | |||
} | |||
} | |||
} | |||
Util.jQueryDetection() | |||
setTransitionEndSupport() | |||
export default Util |
@ -0,0 +1,214 @@ | |||
{ | |||
"_from": "bootstrap", | |||
"_id": "bootstrap@4.4.1", | |||
"_inBundle": false, | |||
"_integrity": "sha512-tbx5cHubwE6e2ZG7nqM3g/FZ5PQEDMWmMGNrCUBVRPHXTJaH7CBDdsLeu3eCh3B1tzAxTnAbtmrzvWEvT2NNEA==", | |||
"_location": "/bootstrap", | |||
"_phantomChildren": {}, | |||
"_requested": { | |||
"type": "tag", | |||
"registry": true, | |||
"raw": "bootstrap", | |||
"name": "bootstrap", | |||
"escapedName": "bootstrap", | |||
"rawSpec": "", | |||
"saveSpec": null, | |||
"fetchSpec": "latest" | |||
}, | |||
"_requiredBy": [ | |||
"#USER", | |||
"/" | |||
], | |||
"_resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.4.1.tgz", | |||
"_shasum": "8582960eea0c5cd2bede84d8b0baf3789c3e8b01", | |||
"_spec": "bootstrap", | |||
"_where": "/app", | |||
"author": { | |||
"name": "The Bootstrap Authors", | |||
"url": "https://github.com/twbs/bootstrap/graphs/contributors" | |||
}, | |||
"bugs": { | |||
"url": "https://github.com/twbs/bootstrap/issues" | |||
}, | |||
"bundleDependencies": false, | |||
"contributors": [ | |||
{ | |||
"name": "Twitter, Inc." | |||
} | |||
], | |||
"dependencies": {}, | |||
"deprecated": false, | |||
"description": "The most popular front-end framework for developing responsive, mobile first projects on the web.", | |||
"devDependencies": { | |||
"@babel/cli": "^7.7.4", | |||
"@babel/core": "^7.7.4", | |||
"@babel/plugin-proposal-object-rest-spread": "^7.7.4", | |||
"@babel/preset-env": "^7.7.4", | |||
"autoprefixer": "^9.7.2", | |||
"babel-eslint": "^10.0.3", | |||
"babel-plugin-istanbul": "^5.2.0", | |||
"broken-link-checker": "^0.7.8", | |||
"bundlesize": "^0.18.0", | |||
"clean-css-cli": "^4.3.0", | |||
"cross-env": "^5.2.1", | |||
"eslint": "^5.16.0", | |||
"find-unused-sass-variables": "^0.6.0", | |||
"glob": "^7.1.6", | |||
"hammer-simulator": "0.0.1", | |||
"http-server": "^0.11.1", | |||
"ip": "^1.1.5", | |||
"jquery": "^3.4.1", | |||
"karma": "^3.1.4", | |||
"karma-browserstack-launcher": "1.4.0", | |||
"karma-chrome-launcher": "^3.1.0", | |||
"karma-coverage-istanbul-reporter": "^2.1.1", | |||
"karma-detect-browsers": "^2.3.3", | |||
"karma-firefox-launcher": "^1.2.0", | |||
"karma-qunit": "^3.1.3", | |||
"karma-sinon": "^1.0.5", | |||
"node-sass": "^4.13.0", | |||
"nodemon": "^1.19.4", | |||
"npm-run-all": "^4.1.5", | |||
"popper.js": "^1.16.0", | |||
"postcss-cli": "^6.1.3", | |||
"qunit": "2.9.2", | |||
"rollup": "1.26.5", | |||
"rollup-plugin-babel": "^4.3.3", | |||
"rollup-plugin-commonjs": "^10.1.0", | |||
"rollup-plugin-node-resolve": "^5.2.0", | |||
"shelljs": "^0.8.3", | |||
"shx": "^0.3.2", | |||
"sinon": "^7.5.0", | |||
"stylelint": "^9.10.1", | |||
"stylelint-config-twbs-bootstrap": "^0.5.0", | |||
"uglify-js": "^3.6.9", | |||
"vnu-jar": "19.9.4" | |||
}, | |||
"engines": { | |||
"node": ">=6" | |||
}, | |||
"files": [ | |||
"dist/{css,js}/*.{css,js,map}", | |||
"js/{src,dist}/**/*.{js,map}", | |||
"scss/**/*.scss" | |||
], | |||
"funding": { | |||
"type": "opencollective", | |||
"url": "https://opencollective.com/bootstrap" | |||
}, | |||
"homepage": "https://getbootstrap.com/", | |||
"jspm": { | |||
"registry": "npm", | |||
"main": "js/bootstrap", | |||
"directories": { | |||
"lib": "dist" | |||
}, | |||
"shim": { | |||
"js/bootstrap": { | |||
"deps": [ | |||
"jquery", | |||
"popper.js" | |||
], | |||
"exports": "$" | |||
} | |||
}, | |||
"dependencies": {}, | |||
"peerDependencies": { | |||
"jquery": "1.9.1 - 3", | |||
"popper.js": "^1.16.0" | |||
} | |||
}, | |||
"keywords": [ | |||
"css", | |||
"sass", | |||
"mobile-first", | |||
"responsive", | |||
"front-end", | |||
"framework", | |||
"web" | |||
], | |||
"license": "MIT", | |||
"main": "dist/js/bootstrap", | |||
"name": "bootstrap", | |||
"peerDependencies": { | |||
"jquery": "1.9.1 - 3", | |||
"popper.js": "^1.16.0" | |||
}, | |||
"repository": { | |||
"type": "git", | |||
"url": "git+https://github.com/twbs/bootstrap.git" | |||
}, | |||
"sass": "scss/bootstrap.scss", | |||
"scripts": { | |||
"blc": "blc --exclude-external --filter-level 3 --follow --get --ordered --recursive --host-requests 4 --input http://localhost:3000/", | |||
"bundlesize": "bundlesize", | |||
"check-broken-links": "npm-run-all --parallel --race \"http-server -- _gh_pages/\" blc", | |||
"css": "npm-run-all css-compile css-prefix css-minify css-copy", | |||
"css-compile": "npm-run-all --parallel css-compile-*", | |||
"css-compile-docs": "cross-env-shell node-sass --output-style expanded --source-map true --source-map-contents true --precision 6 site/docs/$npm_package_version_short/assets/scss/docs.scss site/docs/$npm_package_version_short/assets/css/docs.min.css", | |||
"css-compile-main": "node-sass --output-style expanded --source-map true --source-map-contents true --precision 6 scss/ -o dist/css/ && npm run css-copy", | |||
"css-copy": "cross-env-shell shx mkdir -p site/docs/$npm_package_version_short/dist/ && cross-env-shell shx cp -r dist/css/ site/docs/$npm_package_version_short/dist/", | |||
"css-docs": "npm-run-all css-compile-docs css-prefix-docs css-minify-docs", | |||
"css-lint": "npm-run-all --continue-on-error --parallel css-lint-*", | |||
"css-lint-docs": "stylelint \"site/docs/**/assets/scss/*.scss\" \"site/docs/**/*.css\" --cache --cache-location .cache/.stylelintcache", | |||
"css-lint-main": "stylelint \"scss/**/*.scss\" --cache --cache-location .cache/.stylelintcache", | |||
"css-lint-vars": "fusv scss/ site/docs/", | |||
"css-main": "npm-run-all css-lint css-compile-main css-prefix-main css-minify-main css-copy", | |||
"css-minify": "npm-run-all --parallel css-minify-*", | |||
"css-minify-docs": "cross-env-shell cleancss --level 1 --format breakWith=lf --source-map --source-map-inline-sources --output site/docs/$npm_package_version_short/assets/css/docs.min.css site/docs/$npm_package_version_short/assets/css/docs.min.css", | |||
"css-minify-main": "cleancss --level 1 --format breakWith=lf --source-map --source-map-inline-sources --output dist/css/bootstrap.min.css dist/css/bootstrap.css && cleancss --level 1 --format breakWith=lf --source-map --source-map-inline-sources --output dist/css/bootstrap-grid.min.css dist/css/bootstrap-grid.css && cleancss --level 1 --format breakWith=lf --source-map --source-map-inline-sources --output dist/css/bootstrap-reboot.min.css dist/css/bootstrap-reboot.css", | |||
"css-prefix": "npm-run-all --parallel css-prefix-*", | |||
"css-prefix-docs": "postcss --config build/postcss.config.js --replace \"site/docs/**/*.css\"", | |||
"css-prefix-main": "postcss --config build/postcss.config.js --replace \"dist/css/*.css\" \"!dist/css/*.min.css\"", | |||
"dist": "npm-run-all --parallel css js", | |||
"docs": "npm-run-all css-docs js-docs docs-compile docs-lint", | |||
"docs-compile": "bundle exec jekyll build", | |||
"docs-lint": "node build/vnu-jar.js", | |||
"docs-netlify": "cross-env JEKYLL_ENV=netlify npm run docs-compile", | |||
"docs-production": "cross-env JEKYLL_ENV=production npm run docs-compile", | |||
"docs-serve": "bundle exec jekyll serve", | |||
"docs-serve-only": "npm run docs-serve -- --skip-initial-build --no-watch", | |||
"http-server": "http-server --silent -p 3000", | |||
"js": "npm-run-all js-compile js-minify js-copy", | |||
"js-compile": "npm-run-all --parallel js-compile-* --sequential js-copy", | |||
"js-compile-bundle": "rollup --environment BUNDLE:true --config build/rollup.config.js --sourcemap", | |||
"js-compile-plugins": "node build/build-plugins.js", | |||
"js-compile-plugins-coverage": "cross-env NODE_ENV=test node build/build-plugins.js", | |||
"js-compile-standalone": "rollup --environment BUNDLE:false --config build/rollup.config.js --sourcemap", | |||
"js-copy": "cross-env-shell shx mkdir -p site/docs/$npm_package_version_short/dist/ && cross-env-shell shx cp -r dist/js/ site/docs/$npm_package_version_short/dist/", | |||
"js-docs": "npm-run-all js-lint-docs js-minify-docs", | |||
"js-lint": "npm-run-all --continue-on-error --parallel js-lint-*", | |||
"js-lint-docs": "eslint --cache --cache-location .cache/.eslintcache site/", | |||
"js-lint-main": "eslint --cache --cache-location .cache/.eslintcache js/src js/tests build/", | |||
"js-main": "npm-run-all js-lint js-compile js-minify-main", | |||
"js-minify": "npm-run-all --parallel js-minify-main js-minify-docs", | |||
"js-minify-bundle": "uglifyjs --compress typeofs=false --mangle --comments \"/^!/\" --source-map \"content=dist/js/bootstrap.bundle.js.map,includeSources,url=bootstrap.bundle.min.js.map\" --output dist/js/bootstrap.bundle.min.js dist/js/bootstrap.bundle.js", | |||
"js-minify-docs": "cross-env-shell uglifyjs --mangle --comments \\\"/^!/\\\" --output site/docs/$npm_package_version_short/assets/js/docs.min.js site/docs/$npm_package_version_short/assets/js/vendor/anchor.min.js site/docs/$npm_package_version_short/assets/js/vendor/clipboard.min.js site/docs/$npm_package_version_short/assets/js/vendor/bs-custom-file-input.min.js \"site/docs/$npm_package_version_short/assets/js/src/*.js\"", | |||
"js-minify-main": "npm-run-all js-minify-standalone js-minify-bundle", | |||
"js-minify-standalone": "uglifyjs --compress typeofs=false --mangle --comments \"/^!/\" --source-map \"content=dist/js/bootstrap.js.map,includeSources,url=bootstrap.min.js.map\" --output dist/js/bootstrap.min.js dist/js/bootstrap.js", | |||
"js-test": "npm-run-all js-test-karma* js-test-integration", | |||
"js-test-cloud": "cross-env BROWSER=true npm run js-test-karma", | |||
"js-test-integration": "rollup --config js/tests/integration/rollup.bundle.js", | |||
"js-test-karma": "karma start js/tests/karma.conf.js", | |||
"js-test-karma-bundle": "cross-env BUNDLE=true npm run js-test-karma", | |||
"js-test-karma-bundle-old": "cross-env BUNDLE=true USE_OLD_JQUERY=true npm run js-test-karma", | |||
"js-test-karma-old": "cross-env USE_OLD_JQUERY=true npm run js-test-karma", | |||
"lint": "npm-run-all --parallel js-lint css-lint", | |||
"netlify": "npm-run-all dist release-sri docs-netlify", | |||
"release": "npm-run-all dist release-sri release-zip docs-production", | |||
"release-sri": "node build/generate-sri.js", | |||
"release-version": "node build/change-version.js", | |||
"release-zip": "cross-env-shell \"shx rm -rf bootstrap-$npm_package_version-dist && shx cp -r dist/ bootstrap-$npm_package_version-dist && zip -r9 bootstrap-$npm_package_version-dist.zip bootstrap-$npm_package_version-dist && shx rm -rf bootstrap-$npm_package_version-dist\"", | |||
"start": "npm-run-all --parallel watch docs-serve", | |||
"test": "npm-run-all lint dist js-test docs-compile docs-lint", | |||
"update-deps": "ncu -a -x \"cross-env,eslint,find-unused-sass-variables,karma,karma-browserstack-launcher,karma-qunit,nodemon,qunit,rollup,stylelint,stylelint-config-twbs-bootstrap\" && npm update && bundle update && cross-env-shell echo Manually update \\\"site/docs/$npm_package_version_short/assets/js/vendor/\\\"", | |||
"watch": "npm-run-all --parallel watch-*", | |||
"watch-css-docs": "nodemon --watch \"site/docs/**/assets/scss/\" --ext scss --exec \"npm run css-docs\"", | |||
"watch-css-main": "nodemon --watch scss/ --ext scss --exec \"npm run css-main\"", | |||
"watch-js-docs": "nodemon --watch \"site/docs/**/assets/js/src/\" --ext js --exec \"npm run js-docs\"", | |||
"watch-js-main": "nodemon --watch js/src/ --ext js --exec \"npm run js-compile\"" | |||
}, | |||
"style": "dist/css/bootstrap.css", | |||
"version": "4.4.1", | |||
"version_short": "4.4" | |||
} |
@ -0,0 +1,51 @@ | |||
// | |||
// Base styles | |||
// | |||
.alert { | |||
position: relative; | |||
padding: $alert-padding-y $alert-padding-x; | |||
margin-bottom: $alert-margin-bottom; | |||
border: $alert-border-width solid transparent; | |||
@include border-radius($alert-border-radius); | |||
} | |||
// Headings for larger alerts | |||
.alert-heading { | |||
// Specified to prevent conflicts of changing $headings-color | |||
color: inherit; | |||
} | |||
// Provide class for links that match alerts | |||
.alert-link { | |||
font-weight: $alert-link-font-weight; | |||
} | |||
// Dismissible alerts | |||
// | |||
// Expand the right padding and account for the close button's positioning. | |||
.alert-dismissible { | |||
padding-right: $close-font-size + $alert-padding-x * 2; | |||
// Adjust close link position | |||
.close { | |||
position: absolute; | |||
top: 0; | |||
right: 0; | |||
padding: $alert-padding-y $alert-padding-x; | |||
color: inherit; | |||
} | |||
} | |||
// Alternate styles | |||
// | |||
// Generate contextual modifier classes for colorizing the alert. | |||
@each $color, $value in $theme-colors { | |||
.alert-#{$color} { | |||
@include alert-variant(theme-color-level($color, $alert-bg-level), theme-color-level($color, $alert-border-level), theme-color-level($color, $alert-color-level)); | |||
} | |||
} |
@ -0,0 +1,54 @@ | |||
// Base class | |||
// | |||
// Requires one of the contextual, color modifier classes for `color` and | |||
// `background-color`. | |||
.badge { | |||
display: inline-block; | |||
padding: $badge-padding-y $badge-padding-x; | |||
@include font-size($badge-font-size); | |||
font-weight: $badge-font-weight; | |||
line-height: 1; | |||
text-align: center; | |||
white-space: nowrap; | |||
vertical-align: baseline; | |||
@include border-radius($badge-border-radius); | |||
@include transition($badge-transition); | |||
@at-root a#{&} { | |||
@include hover-focus() { | |||
text-decoration: none; | |||
} | |||
} | |||
// Empty badges collapse automatically | |||
&:empty { | |||
display: none; | |||
} | |||
} | |||
// Quick fix for badges in buttons | |||
.btn .badge { | |||
position: relative; | |||
top: -1px; | |||
} | |||
// Pill badges | |||
// | |||
// Make them extra rounded with a modifier to replace v3's badges. | |||
.badge-pill { | |||
padding-right: $badge-pill-padding-x; | |||
padding-left: $badge-pill-padding-x; | |||
@include border-radius($badge-pill-border-radius); | |||
} | |||
// Colors | |||
// | |||
// Contextual variations (linked badges get darker on :hover). | |||
@each $color, $value in $theme-colors { | |||
.badge-#{$color} { | |||
@include badge-variant($value); | |||
} | |||
} |
@ -0,0 +1,42 @@ | |||
.breadcrumb { | |||
display: flex; | |||
flex-wrap: wrap; | |||
padding: $breadcrumb-padding-y $breadcrumb-padding-x; | |||
margin-bottom: $breadcrumb-margin-bottom; | |||
@include font-size($breadcrumb-font-size); | |||
list-style: none; | |||
background-color: $breadcrumb-bg; | |||
@include border-radius($breadcrumb-border-radius); | |||
} | |||
.breadcrumb-item { | |||
// The separator between breadcrumbs (by default, a forward-slash: "/") | |||
+ .breadcrumb-item { | |||
padding-left: $breadcrumb-item-padding; | |||
&::before { | |||
display: inline-block; // Suppress underlining of the separator in modern browsers | |||
padding-right: $breadcrumb-item-padding; | |||
color: $breadcrumb-divider-color; | |||
content: escape-svg($breadcrumb-divider); | |||
} | |||
} | |||
// IE9-11 hack to properly handle hyperlink underlines for breadcrumbs built | |||
// without `<ul>`s. The `::before` pseudo-element generates an element | |||
// *within* the .breadcrumb-item and thereby inherits the `text-decoration`. | |||
// | |||
// To trick IE into suppressing the underline, we give the pseudo-element an | |||
// underline and then immediately remove it. | |||
+ .breadcrumb-item:hover::before { | |||
text-decoration: underline; | |||
} | |||
// stylelint-disable-next-line no-duplicate-selectors | |||
+ .breadcrumb-item:hover::before { | |||
text-decoration: none; | |||
} | |||
&.active { | |||
color: $breadcrumb-active-color; | |||
} | |||
} |
@ -0,0 +1,163 @@ | |||
// stylelint-disable selector-no-qualifying-type | |||
// Make the div behave like a button | |||
.btn-group, | |||
.btn-group-vertical { | |||
position: relative; | |||
display: inline-flex; | |||
vertical-align: middle; // match .btn alignment given font-size hack above | |||
> .btn { | |||
position: relative; | |||
flex: 1 1 auto; | |||
// Bring the hover, focused, and "active" buttons to the front to overlay | |||
// the borders properly | |||
@include hover() { | |||
z-index: 1; | |||
} | |||
&:focus, | |||
&:active, | |||
&.active { | |||
z-index: 1; | |||
} | |||
} | |||
} | |||
// Optional: Group multiple button groups together for a toolbar | |||
.btn-toolbar { | |||
display: flex; | |||
flex-wrap: wrap; | |||
justify-content: flex-start; | |||
.input-group { | |||
width: auto; | |||
} | |||
} | |||
.btn-group { | |||
// Prevent double borders when buttons are next to each other | |||
> .btn:not(:first-child), | |||
> .btn-group:not(:first-child) { | |||
margin-left: -$btn-border-width; | |||
} | |||
// Reset rounded corners | |||
> .btn:not(:last-child):not(.dropdown-toggle), | |||
> .btn-group:not(:last-child) > .btn { | |||
@include border-right-radius(0); | |||
} | |||
> .btn:not(:first-child), | |||
> .btn-group:not(:first-child) > .btn { | |||
@include border-left-radius(0); | |||
} | |||
} | |||
// Sizing | |||
// | |||
// Remix the default button sizing classes into new ones for easier manipulation. | |||
.btn-group-sm > .btn { @extend .btn-sm; } | |||
.btn-group-lg > .btn { @extend .btn-lg; } | |||
// | |||
// Split button dropdowns | |||
// | |||
.dropdown-toggle-split { | |||
padding-right: $btn-padding-x * .75; | |||
padding-left: $btn-padding-x * .75; | |||
&::after, | |||
.dropup &::after, | |||
.dropright &::after { | |||
margin-left: 0; | |||
} | |||
.dropleft &::before { | |||
margin-right: 0; | |||
} | |||
} | |||
.btn-sm + .dropdown-toggle-split { | |||
padding-right: $btn-padding-x-sm * .75; | |||
padding-left: $btn-padding-x-sm * .75; | |||
} | |||
.btn-lg + .dropdown-toggle-split { | |||
padding-right: $btn-padding-x-lg * .75; | |||
padding-left: $btn-padding-x-lg * .75; | |||
} | |||
// The clickable button for toggling the menu | |||
// 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. | |||
&.btn-link { | |||
@include box-shadow(none); | |||
} | |||
} | |||
// | |||
// Vertical button groups | |||
// | |||
.btn-group-vertical { | |||
flex-direction: column; | |||
align-items: flex-start; | |||
justify-content: center; | |||
> .btn, | |||
> .btn-group { | |||
width: 100%; | |||
} | |||
> .btn:not(:first-child), | |||
> .btn-group:not(:first-child) { | |||
margin-top: -$btn-border-width; | |||
} | |||
// Reset rounded corners | |||
> .btn:not(:last-child):not(.dropdown-toggle), | |||
> .btn-group:not(:last-child) > .btn { | |||
@include border-bottom-radius(0); | |||
} | |||
> .btn:not(:first-child), | |||
> .btn-group:not(:first-child) > .btn { | |||
@include border-top-radius(0); | |||
} | |||
} | |||
// Checkbox and radio options | |||
// | |||
// In order to support the browser's form validation feedback, powered by the | |||
// `required` attribute, we have to "hide" the inputs via `clip`. We cannot use | |||
// `display: none;` or `visibility: hidden;` as that also hides the popover. | |||
// Simply visually hiding the inputs via `opacity` would leave them clickable in | |||
// certain cases which is prevented by using `clip` and `pointer-events`. | |||
// This way, we ensure a DOM element is visible to position the popover from. | |||
// | |||
// See https://github.com/twbs/bootstrap/pull/12794 and | |||
// https://github.com/twbs/bootstrap/pull/14559 for more information. | |||
.btn-group-toggle { | |||
> .btn, | |||
> .btn-group > .btn { | |||
margin-bottom: 0; // Override default `<label>` value | |||
input[type="radio"], | |||
input[type="checkbox"] { | |||
position: absolute; | |||
clip: rect(0, 0, 0, 0); | |||
pointer-events: none; | |||
} | |||
} | |||
} |
@ -0,0 +1,139 @@ | |||
// stylelint-disable selector-no-qualifying-type | |||
// | |||
// Base styles | |||
// | |||
.btn { | |||
display: inline-block; | |||
font-family: $btn-font-family; | |||
font-weight: $btn-font-weight; | |||
color: $body-color; | |||
text-align: center; | |||
white-space: $btn-white-space; | |||
vertical-align: middle; | |||
cursor: if($enable-pointer-cursor-for-buttons, pointer, null); | |||
user-select: none; | |||
background-color: transparent; | |||
border: $btn-border-width solid transparent; | |||
@include button-size($btn-padding-y, $btn-padding-x, $btn-font-size, $btn-line-height, $btn-border-radius); | |||
@include transition($btn-transition); | |||
@include hover() { | |||
color: $body-color; | |||
text-decoration: none; | |||
} | |||
&:focus, | |||
&.focus { | |||
outline: 0; | |||
box-shadow: $btn-focus-box-shadow; | |||
} | |||
// Disabled comes first so active can properly restyle | |||
&.disabled, | |||
&:disabled { | |||
opacity: $btn-disabled-opacity; | |||
@include box-shadow(none); | |||
} | |||
&:not(:disabled):not(.disabled):active, | |||
&:not(:disabled):not(.disabled).active { | |||
@include box-shadow($btn-active-box-shadow); | |||
&:focus { | |||
@include box-shadow($btn-focus-box-shadow, $btn-active-box-shadow); | |||
} | |||
} | |||
} | |||
// Future-proof disabling of clicks on `<a>` elements | |||
a.btn.disabled, | |||
fieldset:disabled a.btn { | |||
pointer-events: none; | |||
} | |||
// | |||
// Alternate buttons | |||
// | |||
@each $color, $value in $theme-colors { | |||
.btn-#{$color} { | |||
@include button-variant($value, $value); | |||
} | |||
} | |||
@each $color, $value in $theme-colors { | |||
.btn-outline-#{$color} { | |||
@include button-outline-variant($value); | |||
} | |||
} | |||
// | |||
// Link buttons | |||
// | |||
// Make a button look and behave like a link | |||
.btn-link { | |||
font-weight: $font-weight-normal; | |||
color: $link-color; | |||
text-decoration: $link-decoration; | |||
@include hover() { | |||
color: $link-hover-color; | |||
text-decoration: $link-hover-decoration; | |||
} | |||
&:focus, | |||
&.focus { | |||
text-decoration: $link-hover-decoration; | |||
box-shadow: none; | |||
} | |||
&:disabled, | |||
&.disabled { | |||
color: $btn-link-disabled-color; | |||
pointer-events: none; | |||
} | |||
// No need for an active state here | |||
} | |||
// | |||
// Button Sizes | |||
// | |||
.btn-lg { | |||
@include button-size($btn-padding-y-lg, $btn-padding-x-lg, $btn-font-size-lg, $btn-line-height-lg, $btn-border-radius-lg); | |||
} | |||
.btn-sm { | |||
@include button-size($btn-padding-y-sm, $btn-padding-x-sm, $btn-font-size-sm, $btn-line-height-sm, $btn-border-radius-sm); | |||
} | |||
// | |||
// Block button | |||
// | |||
.btn-block { | |||
display: block; | |||
width: 100%; | |||
// Vertically space out multiple block buttons | |||
+ .btn-block { | |||
margin-top: $btn-block-spacing-y; | |||
} | |||
} | |||
// Specificity overrides | |||
input[type="submit"], | |||
input[type="reset"], | |||
input[type="button"] { | |||
&.btn-block { | |||
width: 100%; | |||
} | |||
} |
@ -0,0 +1,278 @@ | |||
// | |||
// Base styles | |||
// | |||
.card { | |||
position: relative; | |||
display: flex; | |||
flex-direction: column; | |||
min-width: 0; // See https://github.com/twbs/bootstrap/pull/22740#issuecomment-305868106 | |||
height: $card-height; | |||
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); | |||
> hr { | |||
margin-right: 0; | |||
margin-left: 0; | |||
} | |||
> .list-group:first-child { | |||
.list-group-item:first-child { | |||
@include border-top-radius($card-border-radius); | |||
} | |||
} | |||
> .list-group:last-child { | |||
.list-group-item:last-child { | |||
@include border-bottom-radius($card-border-radius); | |||
} | |||
} | |||
} | |||
.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; | |||
// Workaround for the image size bug in IE | |||
// See: https://github.com/twbs/bootstrap/pull/28855 | |||
min-height: 1px; | |||
padding: $card-spacer-x; | |||
color: $card-color; | |||
} | |||
.card-title { | |||
margin-bottom: $card-spacer-y; | |||
} | |||
.card-subtitle { | |||
margin-top: -$card-spacer-y / 2; | |||
margin-bottom: 0; | |||
} | |||
.card-text:last-child { | |||
margin-bottom: 0; | |||
} | |||
.card-link { | |||
@include hover() { | |||
text-decoration: none; | |||
} | |||
+ .card-link { | |||
margin-left: $card-spacer-x; | |||
} | |||
} | |||
// | |||
// Optional textual caps | |||
// | |||
.card-header { | |||
padding: $card-spacer-y $card-spacer-x; | |||
margin-bottom: 0; // Removes the default margin-bottom of <hN> | |||
color: $card-cap-color; | |||
background-color: $card-cap-bg; | |||
border-bottom: $card-border-width solid $card-border-color; | |||
&:first-child { | |||
@include border-radius($card-inner-border-radius $card-inner-border-radius 0 0); | |||
} | |||
+ .list-group { | |||
.list-group-item:first-child { | |||
border-top: 0; | |||
} | |||
} | |||
} | |||
.card-footer { | |||
padding: $card-spacer-y $card-spacer-x; | |||
background-color: $card-cap-bg; | |||
border-top: $card-border-width solid $card-border-color; | |||
&:last-child { | |||
@include border-radius(0 0 $card-inner-border-radius $card-inner-border-radius); | |||
} | |||
} | |||
// | |||
// Header navs | |||
// | |||
.card-header-tabs { | |||
margin-right: -$card-spacer-x / 2; | |||
margin-bottom: -$card-spacer-y; | |||
margin-left: -$card-spacer-x / 2; | |||
border-bottom: 0; | |||
} | |||
.card-header-pills { | |||
margin-right: -$card-spacer-x / 2; | |||
margin-left: -$card-spacer-x / 2; | |||
} | |||
// Card image | |||
.card-img-overlay { | |||
position: absolute; | |||
top: 0; | |||
right: 0; | |||
bottom: 0; | |||
left: 0; | |||
padding: $card-img-overlay-padding; | |||
} | |||
.card-img, | |||
.card-img-top, | |||
.card-img-bottom { | |||
flex-shrink: 0; // For IE: https://github.com/twbs/bootstrap/issues/29396 | |||
width: 100%; // Required because we use flexbox and this inherently applies align-self: stretch | |||
} | |||
.card-img, | |||
.card-img-top { | |||
@include border-top-radius($card-inner-border-radius); | |||
} | |||
.card-img, | |||
.card-img-bottom { | |||
@include border-bottom-radius($card-inner-border-radius); | |||
} | |||
// Card deck | |||
.card-deck { | |||
.card { | |||
margin-bottom: $card-deck-margin; | |||
} | |||
@include media-breakpoint-up(sm) { | |||
display: flex; | |||
flex-flow: row wrap; | |||
margin-right: -$card-deck-margin; | |||
margin-left: -$card-deck-margin; | |||
.card { | |||
// Flexbugs #4: https://github.com/philipwalton/flexbugs#flexbug-4 | |||
flex: 1 0 0%; | |||
margin-right: $card-deck-margin; | |||
margin-bottom: 0; // Override the default | |||
margin-left: $card-deck-margin; | |||
} | |||
} | |||
} | |||
// | |||
// Card groups | |||
// | |||
.card-group { | |||
// The child selector allows nested `.card` within `.card-group` | |||
// to display properly. | |||
> .card { | |||
margin-bottom: $card-group-margin; | |||
} | |||
@include media-breakpoint-up(sm) { | |||
display: flex; | |||
flex-flow: row wrap; | |||
// The child selector allows nested `.card` within `.card-group` | |||
// to display properly. | |||
> .card { | |||
// Flexbugs #4: https://github.com/philipwalton/flexbugs#flexbug-4 | |||
flex: 1 0 0%; | |||
margin-bottom: 0; | |||
+ .card { | |||
margin-left: 0; | |||
border-left: 0; | |||
} | |||
// Handle rounded corners | |||
@if $enable-rounded { | |||
&:not(:last-child) { | |||
@include border-right-radius(0); | |||
.card-img-top, | |||
.card-header { | |||
// stylelint-disable-next-line property-blacklist | |||
border-top-right-radius: 0; | |||
} | |||
.card-img-bottom, | |||
.card-footer { | |||
// stylelint-disable-next-line property-blacklist | |||
border-bottom-right-radius: 0; | |||
} | |||
} | |||
&:not(:first-child) { | |||
@include border-left-radius(0); | |||
.card-img-top, | |||
.card-header { | |||
// stylelint-disable-next-line property-blacklist | |||
border-top-left-radius: 0; | |||
} | |||
.card-img-bottom, | |||
.card-footer { | |||
// stylelint-disable-next-line property-blacklist | |||
border-bottom-left-radius: 0; | |||
} | |||
} | |||
} | |||
} | |||
} | |||
} | |||
// | |||
// Columns | |||
// | |||
.card-columns { | |||
.card { | |||
margin-bottom: $card-columns-margin; | |||
} | |||
@include media-breakpoint-up(sm) { | |||
column-count: $card-columns-count; | |||
column-gap: $card-columns-gap; | |||
orphans: 1; | |||
widows: 1; | |||
.card { | |||
display: inline-block; // Don't let them vertically span multiple columns | |||
width: 100%; // Don't let their width change | |||
} | |||
} | |||
} | |||
// | |||
// Accordion | |||
// | |||
.accordion { | |||
> .card { | |||
overflow: hidden; | |||
&:not(:last-of-type) { | |||
border-bottom: 0; | |||
@include border-bottom-radius(0); | |||
} | |||
&:not(:first-of-type) { | |||
@include border-top-radius(0); | |||
} | |||
> .card-header { | |||
@include border-radius(0); | |||
margin-bottom: -$card-border-width; | |||
} | |||
} | |||
} |
@ -0,0 +1,197 @@ | |||
// Notes on the classes: | |||
// | |||
// 1. .carousel.pointer-event should ideally be pan-y (to allow for users to scroll vertically) | |||
// even when their scroll action started on a carousel, but for compatibility (with Firefox) | |||
// we're preventing all actions instead | |||
// 2. The .carousel-item-left and .carousel-item-right is used to indicate where | |||
// the active slide is heading. | |||
// 3. .active.carousel-item is the current slide. | |||
// 4. .active.carousel-item-left and .active.carousel-item-right is the current | |||
// slide in its in-transition state. Only one of these occurs at a time. | |||
// 5. .carousel-item-next.carousel-item-left and .carousel-item-prev.carousel-item-right | |||
// is the upcoming slide in transition. | |||
.carousel { | |||
position: relative; | |||
} | |||
.carousel.pointer-event { | |||
touch-action: pan-y; | |||
} | |||
.carousel-inner { | |||
position: relative; | |||
width: 100%; | |||
overflow: hidden; | |||
@include clearfix(); | |||
} | |||
.carousel-item { | |||
position: relative; | |||
display: none; | |||
float: left; | |||
width: 100%; | |||
margin-right: -100%; | |||
backface-visibility: hidden; | |||
@include transition($carousel-transition); | |||
} | |||
.carousel-item.active, | |||
.carousel-item-next, | |||
.carousel-item-prev { | |||
display: block; | |||
} | |||
.carousel-item-next:not(.carousel-item-left), | |||
.active.carousel-item-right { | |||
transform: translateX(100%); | |||
} | |||
.carousel-item-prev:not(.carousel-item-right), | |||
.active.carousel-item-left { | |||
transform: translateX(-100%); | |||
} | |||
// | |||
// Alternate transitions | |||
// | |||
.carousel-fade { | |||
.carousel-item { | |||
opacity: 0; | |||
transition-property: opacity; | |||
transform: none; | |||
} | |||
.carousel-item.active, | |||
.carousel-item-next.carousel-item-left, | |||
.carousel-item-prev.carousel-item-right { | |||
z-index: 1; | |||
opacity: 1; | |||
} | |||
.active.carousel-item-left, | |||
.active.carousel-item-right { | |||
z-index: 0; | |||
opacity: 0; | |||
@include transition(opacity 0s $carousel-transition-duration); | |||
} | |||
} | |||
// | |||
// Left/right controls for nav | |||
// | |||
.carousel-control-prev, | |||
.carousel-control-next { | |||
position: absolute; | |||
top: 0; | |||
bottom: 0; | |||
z-index: 1; | |||
// Use flex for alignment (1-3) | |||
display: flex; // 1. allow flex styles | |||
align-items: center; // 2. vertically center contents | |||
justify-content: center; // 3. horizontally center contents | |||
width: $carousel-control-width; | |||
color: $carousel-control-color; | |||
text-align: center; | |||
opacity: $carousel-control-opacity; | |||
@include transition($carousel-control-transition); | |||
// Hover/focus state | |||
@include hover-focus() { | |||
color: $carousel-control-color; | |||
text-decoration: none; | |||
outline: 0; | |||
opacity: $carousel-control-hover-opacity; | |||
} | |||
} | |||
.carousel-control-prev { | |||
left: 0; | |||
@if $enable-gradients { | |||
background-image: linear-gradient(90deg, rgba($black, .25), rgba($black, .001)); | |||
} | |||
} | |||
.carousel-control-next { | |||
right: 0; | |||
@if $enable-gradients { | |||
background-image: linear-gradient(270deg, rgba($black, .25), rgba($black, .001)); | |||
} | |||
} | |||
// Icons for within | |||
.carousel-control-prev-icon, | |||
.carousel-control-next-icon { | |||
display: inline-block; | |||
width: $carousel-control-icon-width; | |||
height: $carousel-control-icon-width; | |||
background: no-repeat 50% / 100% 100%; | |||
} | |||
.carousel-control-prev-icon { | |||
background-image: escape-svg($carousel-control-prev-icon-bg); | |||
} | |||
.carousel-control-next-icon { | |||
background-image: escape-svg($carousel-control-next-icon-bg); | |||
} | |||
// Optional indicator pips | |||
// | |||
// Add an ordered list with the following class and add a list item for each | |||
// slide your carousel holds. | |||
.carousel-indicators { | |||
position: absolute; | |||
right: 0; | |||
bottom: 0; | |||
left: 0; | |||
z-index: 15; | |||
display: flex; | |||
justify-content: center; | |||
padding-left: 0; // override <ol> default | |||
// Use the .carousel-control's width as margin so we don't overlay those | |||
margin-right: $carousel-control-width; | |||
margin-left: $carousel-control-width; | |||
list-style: none; | |||
li { | |||
box-sizing: content-box; | |||
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: $carousel-indicator-active-bg; | |||
background-clip: padding-box; | |||
// Use transparent borders to increase the hit area by 10px on top and bottom. | |||
border-top: $carousel-indicator-hit-area-height solid transparent; | |||
border-bottom: $carousel-indicator-hit-area-height solid transparent; | |||
opacity: .5; | |||
@include transition($carousel-indicator-transition); | |||
} | |||
.active { | |||
opacity: 1; | |||
} | |||
} | |||
// Optional captions | |||
// | |||
// | |||
.carousel-caption { | |||
position: absolute; | |||
right: (100% - $carousel-caption-width) / 2; | |||
bottom: 20px; | |||
left: (100% - $carousel-caption-width) / 2; | |||
z-index: 10; | |||
padding-top: 20px; | |||
padding-bottom: 20px; | |||
color: $carousel-caption-color; | |||
text-align: center; | |||
} |
@ -0,0 +1,41 @@ | |||
.close { | |||
float: right; | |||
@include font-size($close-font-size); | |||
font-weight: $close-font-weight; | |||
line-height: 1; | |||
color: $close-color; | |||
text-shadow: $close-text-shadow; | |||
opacity: .5; | |||
// Override <a>'s hover style | |||
@include hover() { | |||
color: $close-color; | |||
text-decoration: none; | |||
} | |||
&:not(:disabled):not(.disabled) { | |||
@include hover-focus() { | |||
opacity: .75; | |||
} | |||
} | |||
} | |||
// Additional properties for button version | |||
// iOS requires the button element instead of an anchor tag. | |||
// If you want the anchor version, it requires `href="#"`. | |||
// See https://developer.mozilla.org/en-US/docs/Web/Events/click#Safari_Mobile | |||
// stylelint-disable-next-line selector-no-qualifying-type | |||
button.close { | |||
padding: 0; | |||
background-color: transparent; | |||
border: 0; | |||
appearance: none; | |||
} | |||
// Future-proof disabling of clicks on `<a>` elements | |||
// stylelint-disable-next-line selector-no-qualifying-type | |||
a.close.disabled { | |||
pointer-events: none; | |||
} |
@ -0,0 +1,48 @@ | |||
// Inline code | |||
code { | |||
@include font-size($code-font-size); | |||
color: $code-color; | |||
word-wrap: break-word; | |||
// Streamline the style when inside anchors to avoid broken underline and more | |||
a > & { | |||
color: inherit; | |||
} | |||
} | |||
// User input typically entered via keyboard | |||
kbd { | |||
padding: $kbd-padding-y $kbd-padding-x; | |||
@include font-size($kbd-font-size); | |||
color: $kbd-color; | |||
background-color: $kbd-bg; | |||
@include border-radius($border-radius-sm); | |||
@include box-shadow($kbd-box-shadow); | |||
kbd { | |||
padding: 0; | |||
@include font-size(100%); | |||
font-weight: $nested-kbd-font-weight; | |||
@include box-shadow(none); | |||
} | |||
} | |||
// Blocks of code | |||
pre { | |||
display: block; | |||
@include font-size($code-font-size); | |||
color: $pre-color; | |||
// Account for some code outputs that place code tags in pre tags | |||
code { | |||
@include font-size(inherit); | |||
color: inherit; | |||
word-break: normal; | |||
} | |||
} | |||
// Enable scrollable blocks of code | |||
.pre-scrollable { | |||
max-height: $pre-scrollable-max-height; | |||
overflow-y: scroll; | |||
} |
@ -0,0 +1,521 @@ | |||
// Embedded icons from Open Iconic. | |||
// Released under MIT and copyright 2014 Waybury. | |||
// https://useiconic.com/open | |||
// Checkboxes and radios | |||
// | |||
// Base class takes care of all the key behavioral aspects. | |||
.custom-control { | |||
position: relative; | |||
display: block; | |||
min-height: $font-size-base * $line-height-base; | |||
padding-left: $custom-control-gutter + $custom-control-indicator-size; | |||
} | |||
.custom-control-inline { | |||
display: inline-flex; | |||
margin-right: $custom-control-spacer-x; | |||
} | |||
.custom-control-input { | |||
position: absolute; | |||
left: 0; | |||
z-index: -1; // Put the input behind the label so it doesn't overlay text | |||
width: $custom-control-indicator-size; | |||
height: ($font-size-base * $line-height-base + $custom-control-indicator-size) / 2; | |||
opacity: 0; | |||
&:checked ~ .custom-control-label::before { | |||
color: $custom-control-indicator-checked-color; | |||
border-color: $custom-control-indicator-checked-border-color; | |||
@include gradient-bg($custom-control-indicator-checked-bg); | |||
@include box-shadow($custom-control-indicator-checked-box-shadow); | |||
} | |||
&:focus ~ .custom-control-label::before { | |||
// the mixin is not used here to make sure there is feedback | |||
@if $enable-shadows { | |||
box-shadow: $input-box-shadow, $input-focus-box-shadow; | |||
} @else { | |||
box-shadow: $custom-control-indicator-focus-box-shadow; | |||
} | |||
} | |||
&:focus:not(:checked) ~ .custom-control-label::before { | |||
border-color: $custom-control-indicator-focus-border-color; | |||
} | |||
&:not(:disabled):active ~ .custom-control-label::before { | |||
color: $custom-control-indicator-active-color; | |||
background-color: $custom-control-indicator-active-bg; | |||
border-color: $custom-control-indicator-active-border-color; | |||
@include box-shadow($custom-control-indicator-active-box-shadow); | |||
} | |||
// Use [disabled] and :disabled to work around https://github.com/twbs/bootstrap/issues/28247 | |||
&[disabled], | |||
&:disabled { | |||
~ .custom-control-label { | |||
color: $custom-control-label-disabled-color; | |||
&::before { | |||
background-color: $custom-control-indicator-disabled-bg; | |||
} | |||
} | |||
} | |||
} | |||
// Custom control indicators | |||
// | |||
// Build the custom controls out of pseudo-elements. | |||
.custom-control-label { | |||
position: relative; | |||
margin-bottom: 0; | |||
color: $custom-control-label-color; | |||
vertical-align: top; | |||
cursor: $custom-control-cursor; | |||
// Background-color and (when enabled) gradient | |||
&::before { | |||
position: absolute; | |||
top: ($font-size-base * $line-height-base - $custom-control-indicator-size) / 2; | |||
left: -($custom-control-gutter + $custom-control-indicator-size); | |||
display: block; | |||
width: $custom-control-indicator-size; | |||
height: $custom-control-indicator-size; | |||
pointer-events: none; | |||
content: ""; | |||
background-color: $custom-control-indicator-bg; | |||
border: $custom-control-indicator-border-color solid $custom-control-indicator-border-width; | |||
@include box-shadow($custom-control-indicator-box-shadow); | |||
} | |||
// Foreground (icon) | |||
&::after { | |||
position: absolute; | |||
top: ($font-size-base * $line-height-base - $custom-control-indicator-size) / 2; | |||
left: -($custom-control-gutter + $custom-control-indicator-size); | |||
display: block; | |||
width: $custom-control-indicator-size; | |||
height: $custom-control-indicator-size; | |||
content: ""; | |||
background: no-repeat 50% / #{$custom-control-indicator-bg-size}; | |||
} | |||
} | |||
// Checkboxes | |||
// | |||
// Tweak just a few things for checkboxes. | |||
.custom-checkbox { | |||
.custom-control-label::before { | |||
@include border-radius($custom-checkbox-indicator-border-radius); | |||
} | |||
.custom-control-input:checked ~ .custom-control-label { | |||
&::after { | |||
background-image: escape-svg($custom-checkbox-indicator-icon-checked); | |||
} | |||
} | |||
.custom-control-input:indeterminate ~ .custom-control-label { | |||
&::before { | |||
border-color: $custom-checkbox-indicator-indeterminate-border-color; | |||
@include gradient-bg($custom-checkbox-indicator-indeterminate-bg); | |||
@include box-shadow($custom-checkbox-indicator-indeterminate-box-shadow); | |||
} | |||
&::after { | |||
background-image: escape-svg($custom-checkbox-indicator-icon-indeterminate); | |||
} | |||
} | |||
.custom-control-input:disabled { | |||
&:checked ~ .custom-control-label::before { | |||
background-color: $custom-control-indicator-checked-disabled-bg; | |||
} | |||
&:indeterminate ~ .custom-control-label::before { | |||
background-color: $custom-control-indicator-checked-disabled-bg; | |||
} | |||
} | |||
} | |||
// Radios | |||
// | |||
// Tweak just a few things for radios. | |||
.custom-radio { | |||
.custom-control-label::before { | |||
// stylelint-disable-next-line property-blacklist | |||
border-radius: $custom-radio-indicator-border-radius; | |||
} | |||
.custom-control-input:checked ~ .custom-control-label { | |||
&::after { | |||
background-image: escape-svg($custom-radio-indicator-icon-checked); | |||
} | |||
} | |||
.custom-control-input:disabled { | |||
&:checked ~ .custom-control-label::before { | |||
background-color: $custom-control-indicator-checked-disabled-bg; | |||
} | |||
} | |||
} | |||
// switches | |||
// | |||
// Tweak a few things for switches | |||
.custom-switch { | |||
padding-left: $custom-switch-width + $custom-control-gutter; | |||
.custom-control-label { | |||
&::before { | |||
left: -($custom-switch-width + $custom-control-gutter); | |||
width: $custom-switch-width; | |||
pointer-events: all; | |||
// stylelint-disable-next-line property-blacklist | |||
border-radius: $custom-switch-indicator-border-radius; | |||
} | |||
&::after { | |||
top: add(($font-size-base * $line-height-base - $custom-control-indicator-size) / 2, $custom-control-indicator-border-width * 2); | |||
left: add(-($custom-switch-width + $custom-control-gutter), $custom-control-indicator-border-width * 2); | |||
width: $custom-switch-indicator-size; | |||
height: $custom-switch-indicator-size; | |||
background-color: $custom-control-indicator-border-color; | |||
// stylelint-disable-next-line property-blacklist | |||
border-radius: $custom-switch-indicator-border-radius; | |||
@include transition(transform .15s ease-in-out, $custom-forms-transition); | |||
} | |||
} | |||
.custom-control-input:checked ~ .custom-control-label { | |||
&::after { | |||
background-color: $custom-control-indicator-bg; | |||
transform: translateX($custom-switch-width - $custom-control-indicator-size); | |||
} | |||
} | |||
.custom-control-input:disabled { | |||
&:checked ~ .custom-control-label::before { | |||
background-color: $custom-control-indicator-checked-disabled-bg; | |||
} | |||
} | |||
} | |||
// Select | |||
// | |||
// Replaces the browser default select with a custom one, mostly pulled from | |||
// https://primer.github.io/. | |||
// | |||
.custom-select { | |||
display: inline-block; | |||
width: 100%; | |||
height: $custom-select-height; | |||
padding: $custom-select-padding-y ($custom-select-padding-x + $custom-select-indicator-padding) $custom-select-padding-y $custom-select-padding-x; | |||
font-family: $custom-select-font-family; | |||
@include font-size($custom-select-font-size); | |||
font-weight: $custom-select-font-weight; | |||
line-height: $custom-select-line-height; | |||
color: $custom-select-color; | |||
vertical-align: middle; | |||
background: $custom-select-bg $custom-select-background; | |||
border: $custom-select-border-width solid $custom-select-border-color; | |||
@include border-radius($custom-select-border-radius, 0); | |||
@include box-shadow($custom-select-box-shadow); | |||
appearance: none; | |||
&:focus { | |||
border-color: $custom-select-focus-border-color; | |||
outline: 0; | |||
@if $enable-shadows { | |||
box-shadow: $custom-select-box-shadow, $custom-select-focus-box-shadow; | |||
} @else { | |||
box-shadow: $custom-select-focus-box-shadow; | |||
} | |||
&::-ms-value { | |||
// For visual consistency with other platforms/browsers, | |||
// suppress the default white text on blue background highlight given to | |||
// the selected option text when the (still closed) <select> receives focus | |||
// in IE and (under certain conditions) Edge. | |||
// See https://github.com/twbs/bootstrap/issues/19398. | |||
color: $input-color; | |||
background-color: $input-bg; | |||
} | |||
} | |||
&[multiple], | |||
&[size]:not([size="1"]) { | |||
height: auto; | |||
padding-right: $custom-select-padding-x; | |||
background-image: none; | |||
} | |||
&:disabled { | |||
color: $custom-select-disabled-color; | |||
background-color: $custom-select-disabled-bg; | |||
} | |||
// Hides the default caret in IE11 | |||
&::-ms-expand { | |||
display: none; | |||
} | |||
// Remove outline from select box in FF | |||
&:-moz-focusring { | |||
color: transparent; | |||
text-shadow: 0 0 0 $custom-select-color; | |||
} | |||
} | |||
.custom-select-sm { | |||
height: $custom-select-height-sm; | |||
padding-top: $custom-select-padding-y-sm; | |||
padding-bottom: $custom-select-padding-y-sm; | |||
padding-left: $custom-select-padding-x-sm; | |||
@include font-size($custom-select-font-size-sm); | |||
} | |||
.custom-select-lg { | |||
height: $custom-select-height-lg; | |||
padding-top: $custom-select-padding-y-lg; | |||
padding-bottom: $custom-select-padding-y-lg; | |||
padding-left: $custom-select-padding-x-lg; | |||
@include font-size($custom-select-font-size-lg); | |||
} | |||
// File | |||
// | |||
// Custom file input. | |||
.custom-file { | |||
position: relative; | |||
display: inline-block; | |||
width: 100%; | |||
height: $custom-file-height; | |||
margin-bottom: 0; | |||
} | |||
.custom-file-input { | |||
position: relative; | |||
z-index: 2; | |||
width: 100%; | |||
height: $custom-file-height; | |||
margin: 0; | |||
opacity: 0; | |||
&:focus ~ .custom-file-label { | |||
border-color: $custom-file-focus-border-color; | |||
box-shadow: $custom-file-focus-box-shadow; | |||
} | |||
// Use [disabled] and :disabled to work around https://github.com/twbs/bootstrap/issues/28247 | |||
&[disabled] ~ .custom-file-label, | |||
&:disabled ~ .custom-file-label { | |||
background-color: $custom-file-disabled-bg; | |||
} | |||
@each $lang, $value in $custom-file-text { | |||
&:lang(#{$lang}) ~ .custom-file-label::after { | |||
content: $value; | |||
} | |||
} | |||
~ .custom-file-label[data-browse]::after { | |||
content: attr(data-browse); | |||
} | |||
} | |||
.custom-file-label { | |||
position: absolute; | |||
top: 0; | |||
right: 0; | |||
left: 0; | |||
z-index: 1; | |||
height: $custom-file-height; | |||
padding: $custom-file-padding-y $custom-file-padding-x; | |||
font-family: $custom-file-font-family; | |||
font-weight: $custom-file-font-weight; | |||
line-height: $custom-file-line-height; | |||
color: $custom-file-color; | |||
background-color: $custom-file-bg; | |||
border: $custom-file-border-width solid $custom-file-border-color; | |||
@include border-radius($custom-file-border-radius); | |||
@include box-shadow($custom-file-box-shadow); | |||
&::after { | |||
position: absolute; | |||
top: 0; | |||
right: 0; | |||
bottom: 0; | |||
z-index: 3; | |||
display: block; | |||
height: $custom-file-height-inner; | |||
padding: $custom-file-padding-y $custom-file-padding-x; | |||
line-height: $custom-file-line-height; | |||
color: $custom-file-button-color; | |||
content: "Browse"; | |||
@include gradient-bg($custom-file-button-bg); | |||
border-left: inherit; | |||
@include border-radius(0 $custom-file-border-radius $custom-file-border-radius 0); | |||
} | |||
} | |||
// Range | |||
// | |||
// Style range inputs the same across browsers. Vendor-specific rules for pseudo | |||
// elements cannot be mixed. As such, there are no shared styles for focus or | |||
// active states on prefixed selectors. | |||
.custom-range { | |||
width: 100%; | |||
height: add($custom-range-thumb-height, $custom-range-thumb-focus-box-shadow-width * 2); | |||
padding: 0; // Need to reset padding | |||
background-color: transparent; | |||
appearance: none; | |||
&:focus { | |||
outline: none; | |||
// Pseudo-elements must be split across multiple rulesets to have an effect. | |||
// No box-shadow() mixin for focus accessibility. | |||
&::-webkit-slider-thumb { box-shadow: $custom-range-thumb-focus-box-shadow; } | |||
&::-moz-range-thumb { box-shadow: $custom-range-thumb-focus-box-shadow; } | |||
&::-ms-thumb { box-shadow: $custom-range-thumb-focus-box-shadow; } | |||
} | |||
&::-moz-focus-outer { | |||
border: 0; | |||
} | |||
&::-webkit-slider-thumb { | |||
width: $custom-range-thumb-width; | |||
height: $custom-range-thumb-height; | |||
margin-top: ($custom-range-track-height - $custom-range-thumb-height) / 2; // Webkit specific | |||
@include gradient-bg($custom-range-thumb-bg); | |||
border: $custom-range-thumb-border; | |||
@include border-radius($custom-range-thumb-border-radius); | |||
@include box-shadow($custom-range-thumb-box-shadow); | |||
@include transition($custom-forms-transition); | |||
appearance: none; | |||
&:active { | |||
@include gradient-bg($custom-range-thumb-active-bg); | |||
} | |||
} | |||
&::-webkit-slider-runnable-track { | |||
width: $custom-range-track-width; | |||
height: $custom-range-track-height; | |||
color: transparent; // Why? | |||
cursor: $custom-range-track-cursor; | |||
background-color: $custom-range-track-bg; | |||
border-color: transparent; | |||
@include border-radius($custom-range-track-border-radius); | |||
@include box-shadow($custom-range-track-box-shadow); | |||
} | |||
&::-moz-range-thumb { | |||
width: $custom-range-thumb-width; | |||
height: $custom-range-thumb-height; | |||
@include gradient-bg($custom-range-thumb-bg); | |||
border: $custom-range-thumb-border; | |||
@include border-radius($custom-range-thumb-border-radius); | |||
@include box-shadow($custom-range-thumb-box-shadow); | |||
@include transition($custom-forms-transition); | |||
appearance: none; | |||
&:active { | |||
@include gradient-bg($custom-range-thumb-active-bg); | |||
} | |||
} | |||
&::-moz-range-track { | |||
width: $custom-range-track-width; | |||
height: $custom-range-track-height; | |||
color: transparent; | |||
cursor: $custom-range-track-cursor; | |||
background-color: $custom-range-track-bg; | |||
border-color: transparent; // Firefox specific? | |||
@include border-radius($custom-range-track-border-radius); | |||
@include box-shadow($custom-range-track-box-shadow); | |||
} | |||
&::-ms-thumb { | |||
width: $custom-range-thumb-width; | |||
height: $custom-range-thumb-height; | |||
margin-top: 0; // Edge specific | |||
margin-right: $custom-range-thumb-focus-box-shadow-width; // Workaround that overflowed box-shadow is hidden. | |||
margin-left: $custom-range-thumb-focus-box-shadow-width; // Workaround that overflowed box-shadow is hidden. | |||
@include gradient-bg($custom-range-thumb-bg); | |||
border: $custom-range-thumb-border; | |||
@include border-radius($custom-range-thumb-border-radius); | |||
@include box-shadow($custom-range-thumb-box-shadow); | |||
@include transition($custom-forms-transition); | |||
appearance: none; | |||
&:active { | |||
@include gradient-bg($custom-range-thumb-active-bg); | |||
} | |||
} | |||
&::-ms-track { | |||
width: $custom-range-track-width; | |||
height: $custom-range-track-height; | |||
color: transparent; | |||
cursor: $custom-range-track-cursor; | |||
background-color: transparent; | |||
border-color: transparent; | |||
border-width: $custom-range-thumb-height / 2; | |||
@include box-shadow($custom-range-track-box-shadow); | |||
} | |||
&::-ms-fill-lower { | |||
background-color: $custom-range-track-bg; | |||
@include border-radius($custom-range-track-border-radius); | |||
} | |||
&::-ms-fill-upper { | |||
margin-right: 15px; // arbitrary? | |||
background-color: $custom-range-track-bg; | |||
@include border-radius($custom-range-track-border-radius); | |||
} | |||
&:disabled { | |||
&::-webkit-slider-thumb { | |||
background-color: $custom-range-thumb-disabled-bg; | |||
} | |||
&::-webkit-slider-runnable-track { | |||
cursor: default; | |||
} | |||
&::-moz-range-thumb { | |||
background-color: $custom-range-thumb-disabled-bg; | |||
} | |||
&::-moz-range-track { | |||
cursor: default; | |||
} | |||
&::-ms-thumb { | |||
background-color: $custom-range-thumb-disabled-bg; | |||
} | |||
} | |||
} | |||
.custom-control-label::before, | |||
.custom-file-label, | |||
.custom-select { | |||
@include transition($custom-forms-transition); | |||
} |
@ -0,0 +1,191 @@ | |||
// The dropdown wrapper (`<div>`) | |||
.dropup, | |||
.dropright, | |||
.dropdown, | |||
.dropleft { | |||
position: relative; | |||
} | |||
.dropdown-toggle { | |||
white-space: nowrap; | |||
// Generate the caret automatically | |||
@include caret(); | |||
} | |||
// The dropdown menu | |||
.dropdown-menu { | |||
position: absolute; | |||
top: 100%; | |||
left: 0; | |||
z-index: $zindex-dropdown; | |||
display: none; // none by default, but block on "open" of the menu | |||
float: left; | |||
min-width: $dropdown-min-width; | |||
padding: $dropdown-padding-y 0; | |||
margin: $dropdown-spacer 0 0; // override default ul | |||
@include font-size($dropdown-font-size); | |||
color: $dropdown-color; | |||
text-align: left; // Ensures proper alignment if parent has it changed (e.g., modal footer) | |||
list-style: none; | |||
background-color: $dropdown-bg; | |||
background-clip: padding-box; | |||
border: $dropdown-border-width solid $dropdown-border-color; | |||
@include border-radius($dropdown-border-radius); | |||
@include box-shadow($dropdown-box-shadow); | |||
} | |||
@each $breakpoint in map-keys($grid-breakpoints) { | |||
@include media-breakpoint-up($breakpoint) { | |||
$infix: breakpoint-infix($breakpoint, $grid-breakpoints); | |||
.dropdown-menu#{$infix}-left { | |||
right: auto; | |||
left: 0; | |||
} | |||
.dropdown-menu#{$infix}-right { | |||
right: 0; | |||
left: auto; | |||
} | |||
} | |||
} | |||
// 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 { | |||
top: auto; | |||
bottom: 100%; | |||
margin-top: 0; | |||
margin-bottom: $dropdown-spacer; | |||
} | |||
.dropdown-toggle { | |||
@include caret(up); | |||
} | |||
} | |||
.dropright { | |||
.dropdown-menu { | |||
top: 0; | |||
right: auto; | |||
left: 100%; | |||
margin-top: 0; | |||
margin-left: $dropdown-spacer; | |||
} | |||
.dropdown-toggle { | |||
@include caret(right); | |||
&::after { | |||
vertical-align: 0; | |||
} | |||
} | |||
} | |||
.dropleft { | |||
.dropdown-menu { | |||
top: 0; | |||
right: 100%; | |||
left: auto; | |||
margin-top: 0; | |||
margin-right: $dropdown-spacer; | |||
} | |||
.dropdown-toggle { | |||
@include caret(left); | |||
&::before { | |||
vertical-align: 0; | |||
} | |||
} | |||
} | |||
// When enabled Popper.js, reset basic dropdown position | |||
// stylelint-disable-next-line no-duplicate-selectors | |||
.dropdown-menu { | |||
&[x-placement^="top"], | |||
&[x-placement^="right"], | |||
&[x-placement^="bottom"], | |||
&[x-placement^="left"] { | |||
right: auto; | |||
bottom: auto; | |||
} | |||
} | |||
// Dividers (basically an `<hr>`) within the dropdown | |||
.dropdown-divider { | |||
@include nav-divider($dropdown-divider-bg, $dropdown-divider-margin-y, true); | |||
} | |||
// Links, buttons, and more within the dropdown menu | |||
// | |||
// `<button>`-specific styles are denoted with `// For <button>s` | |||
.dropdown-item { | |||
display: block; | |||
width: 100%; // For `<button>`s | |||
padding: $dropdown-item-padding-y $dropdown-item-padding-x; | |||
clear: both; | |||
font-weight: $font-weight-normal; | |||
color: $dropdown-link-color; | |||
text-align: inherit; // For `<button>`s | |||
white-space: nowrap; // prevent links from randomly breaking onto new lines | |||
background-color: transparent; // For `<button>`s | |||
border: 0; // For `<button>`s | |||
// Prevent dropdown overflow if there's no padding | |||
// See https://github.com/twbs/bootstrap/pull/27703 | |||
@if $dropdown-padding-y == 0 { | |||
&:first-child { | |||
@include border-top-radius($dropdown-inner-border-radius); | |||
} | |||
&:last-child { | |||
@include border-bottom-radius($dropdown-inner-border-radius); | |||
} | |||
} | |||
@include hover-focus() { | |||
color: $dropdown-link-hover-color; | |||
text-decoration: none; | |||
@include gradient-bg($dropdown-link-hover-bg); | |||
} | |||
&.active, | |||
&:active { | |||
color: $dropdown-link-active-color; | |||
text-decoration: none; | |||
@include gradient-bg($dropdown-link-active-bg); | |||
} | |||
&.disabled, | |||
&:disabled { | |||
color: $dropdown-link-disabled-color; | |||
pointer-events: none; | |||
background-color: transparent; | |||
// Remove CSS gradients if they're enabled | |||
@if $enable-gradients { | |||
background-image: none; | |||
} | |||
} | |||
} | |||
.dropdown-menu.show { | |||
display: block; | |||
} | |||
// Dropdown section headers | |||
.dropdown-header { | |||
display: block; | |||
padding: $dropdown-padding-y $dropdown-item-padding-x; | |||
margin-bottom: 0; // for use with heading elements | |||
@include font-size($font-size-sm); | |||
color: $dropdown-header-color; | |||
white-space: nowrap; // as with > li > a | |||
} | |||
// Dropdown text | |||
.dropdown-item-text { | |||
display: block; | |||
padding: $dropdown-item-padding-y $dropdown-item-padding-x; | |||
color: $dropdown-link-color; | |||
} |
@ -0,0 +1,338 @@ | |||
// stylelint-disable selector-no-qualifying-type | |||
// | |||
// Textual form controls | |||
// | |||
.form-control { | |||
display: block; | |||
width: 100%; | |||
height: $input-height; | |||
padding: $input-padding-y $input-padding-x; | |||
font-family: $input-font-family; | |||
@include font-size($input-font-size); | |||
font-weight: $input-font-weight; | |||
line-height: $input-line-height; | |||
color: $input-color; | |||
background-color: $input-bg; | |||
background-clip: padding-box; | |||
border: $input-border-width solid $input-border-color; | |||
// Note: This has no effect on <select>s in some browsers, due to the limited stylability of `<select>`s in CSS. | |||
@include border-radius($input-border-radius, 0); | |||
@include box-shadow($input-box-shadow); | |||
@include transition($input-transition); | |||
// Unstyle the caret on `<select>`s in IE10+. | |||
&::-ms-expand { | |||
background-color: transparent; | |||
border: 0; | |||
} | |||
// Remove select outline from select box in FF | |||
&:-moz-focusring { | |||
color: transparent; | |||
text-shadow: 0 0 0 $input-color; | |||
} | |||
// Customize the `:focus` state to imitate native WebKit styles. | |||
@include form-control-focus($ignore-warning: true); | |||
// Placeholder | |||
&::placeholder { | |||
color: $input-placeholder-color; | |||
// Override Firefox's unusual default opacity; see https://github.com/twbs/bootstrap/pull/11526. | |||
opacity: 1; | |||
} | |||
// Disabled and read-only inputs | |||
// | |||
// HTML5 says that controls under a fieldset > legend:first-child won't be | |||
// disabled if the fieldset is disabled. Due to implementation difficulty, we | |||
// don't honor that edge case; we style them as disabled anyway. | |||
&:disabled, | |||
&[readonly] { | |||
background-color: $input-disabled-bg; | |||
// iOS fix for unreadable disabled content; see https://github.com/twbs/bootstrap/issues/11655. | |||
opacity: 1; | |||
} | |||
} | |||
select.form-control { | |||
&:focus::-ms-value { | |||
// Suppress the nested default white text on blue background highlight given to | |||
// the selected option text when the (still closed) <select> receives focus | |||
// in IE and (under certain conditions) Edge, as it looks bad and cannot be made to | |||
// match the appearance of the native widget. | |||
// See https://github.com/twbs/bootstrap/issues/19398. | |||
color: $input-color; | |||
background-color: $input-bg; | |||
} | |||
} | |||
// Make file inputs better match text inputs by forcing them to new lines. | |||
.form-control-file, | |||
.form-control-range { | |||
display: block; | |||
width: 100%; | |||
} | |||
// | |||
// Labels | |||
// | |||
// For use with horizontal and inline forms, when you need the label (or legend) | |||
// text to align with the form controls. | |||
.col-form-label { | |||
padding-top: add($input-padding-y, $input-border-width); | |||
padding-bottom: add($input-padding-y, $input-border-width); | |||
margin-bottom: 0; // Override the `<label>/<legend>` default | |||
@include font-size(inherit); // Override the `<legend>` default | |||
line-height: $input-line-height; | |||
} | |||
.col-form-label-lg { | |||
padding-top: add($input-padding-y-lg, $input-border-width); | |||
padding-bottom: add($input-padding-y-lg, $input-border-width); | |||
@include font-size($input-font-size-lg); | |||
line-height: $input-line-height-lg; | |||
} | |||
.col-form-label-sm { | |||
padding-top: add($input-padding-y-sm, $input-border-width); | |||
padding-bottom: add($input-padding-y-sm, $input-border-width); | |||
@include font-size($input-font-size-sm); | |||
line-height: $input-line-height-sm; | |||
} | |||
// Readonly controls as plain text | |||
// | |||
// Apply class to a readonly input to make it appear like regular plain | |||
// text (without any border, background color, focus indicator) | |||
.form-control-plaintext { | |||
display: block; | |||
width: 100%; | |||
padding: $input-padding-y 0; | |||
margin-bottom: 0; // match inputs if this class comes on inputs with default margins | |||
@include font-size($input-font-size); | |||
line-height: $input-line-height; | |||
color: $input-plaintext-color; | |||
background-color: transparent; | |||
border: solid transparent; | |||
border-width: $input-border-width 0; | |||
&.form-control-sm, | |||
&.form-control-lg { | |||
padding-right: 0; | |||
padding-left: 0; | |||
} | |||
} | |||
// Form control sizing | |||
// | |||
// Build on `.form-control` with modifier classes to decrease or increase the | |||
// height and font-size of form controls. | |||
// | |||
// Repeated in `_input_group.scss` to avoid Sass extend issues. | |||
.form-control-sm { | |||
height: $input-height-sm; | |||
padding: $input-padding-y-sm $input-padding-x-sm; | |||
@include font-size($input-font-size-sm); | |||
line-height: $input-line-height-sm; | |||
@include border-radius($input-border-radius-sm); | |||
} | |||
.form-control-lg { | |||
height: $input-height-lg; | |||
padding: $input-padding-y-lg $input-padding-x-lg; | |||
@include font-size($input-font-size-lg); | |||
line-height: $input-line-height-lg; | |||
@include border-radius($input-border-radius-lg); | |||
} | |||
// stylelint-disable-next-line no-duplicate-selectors | |||
select.form-control { | |||
&[size], | |||
&[multiple] { | |||
height: auto; | |||
} | |||
} | |||
textarea.form-control { | |||
height: auto; | |||
} | |||
// Form groups | |||
// | |||
// Designed to help with the organization and spacing of vertical forms. For | |||
// horizontal forms, use the predefined grid classes. | |||
.form-group { | |||
margin-bottom: $form-group-margin-bottom; | |||
} | |||
.form-text { | |||
display: block; | |||
margin-top: $form-text-margin-top; | |||
} | |||
// Form grid | |||
// | |||
// Special replacement for our grid system's `.row` for tighter form layouts. | |||
.form-row { | |||
display: flex; | |||
flex-wrap: wrap; | |||
margin-right: -$form-grid-gutter-width / 2; | |||
margin-left: -$form-grid-gutter-width / 2; | |||
> .col, | |||
> [class*="col-"] { | |||
padding-right: $form-grid-gutter-width / 2; | |||
padding-left: $form-grid-gutter-width / 2; | |||
} | |||
} | |||
// Checkboxes and radios | |||
// | |||
// Indent the labels to position radios/checkboxes as hanging controls. | |||
.form-check { | |||
position: relative; | |||
display: block; | |||
padding-left: $form-check-input-gutter; | |||
} | |||
.form-check-input { | |||
position: absolute; | |||
margin-top: $form-check-input-margin-y; | |||
margin-left: -$form-check-input-gutter; | |||
// Use [disabled] and :disabled for workaround https://github.com/twbs/bootstrap/issues/28247 | |||
&[disabled] ~ .form-check-label, | |||
&:disabled ~ .form-check-label { | |||
color: $text-muted; | |||
} | |||
} | |||
.form-check-label { | |||
margin-bottom: 0; // Override default `<label>` bottom margin | |||
} | |||
.form-check-inline { | |||
display: inline-flex; | |||
align-items: center; | |||
padding-left: 0; // Override base .form-check | |||
margin-right: $form-check-inline-margin-x; | |||
// Undo .form-check-input defaults and add some `margin-right`. | |||
.form-check-input { | |||
position: static; | |||
margin-top: 0; | |||
margin-right: $form-check-inline-input-margin-x; | |||
margin-left: 0; | |||
} | |||
} | |||
// Form validation | |||
// | |||
// 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. | |||
@each $state, $data in $form-validation-states { | |||
@include form-validation-state($state, map-get($data, color), map-get($data, icon)); | |||
} | |||
// Inline forms | |||
// | |||
// Make forms appear inline(-block) by adding the `.form-inline` class. Inline | |||
// forms begin stacked on extra small (mobile) devices and then go inline when | |||
// viewports reach <768px. | |||
// | |||
// Requires wrapping inputs and labels with `.form-group` for proper display of | |||
// default HTML form controls and our custom form controls (e.g., input groups). | |||
.form-inline { | |||
display: flex; | |||
flex-flow: row wrap; | |||
align-items: center; // Prevent shorter elements from growing to same height as others (e.g., small buttons growing to normal sized button height) | |||
// Because we use flex, the initial sizing of checkboxes is collapsed and | |||
// doesn't occupy the full-width (which is what we want for xs grid tier), | |||
// so we force that here. | |||
.form-check { | |||
width: 100%; | |||
} | |||
// Kick in the inline | |||
@include media-breakpoint-up(sm) { | |||
label { | |||
display: flex; | |||
align-items: center; | |||
justify-content: center; | |||
margin-bottom: 0; | |||
} | |||
// Inline-block all the things for "inline" | |||
.form-group { | |||
display: flex; | |||
flex: 0 0 auto; | |||
flex-flow: row wrap; | |||
align-items: center; | |||
margin-bottom: 0; | |||
} | |||
// Allow folks to *not* use `.form-group` | |||
.form-control { | |||
display: inline-block; | |||
width: auto; // Prevent labels from stacking above inputs in `.form-group` | |||
vertical-align: middle; | |||
} | |||
// Make static controls behave like regular ones | |||
.form-control-plaintext { | |||
display: inline-block; | |||
} | |||
.input-group, | |||
.custom-select { | |||
width: auto; | |||
} | |||
// Remove default margin on radios/checkboxes that were used for stacking, and | |||
// then undo the floating of radios and checkboxes to match. | |||
.form-check { | |||
display: flex; | |||
align-items: center; | |||
justify-content: center; | |||
width: auto; | |||
padding-left: 0; | |||
} | |||
.form-check-input { | |||
position: relative; | |||
flex-shrink: 0; | |||
margin-top: 0; | |||
margin-right: $form-check-input-margin-x; | |||
margin-left: 0; | |||
} | |||
.custom-control { | |||
align-items: center; | |||
justify-content: center; | |||
} | |||
.custom-control-label { | |||
margin-bottom: 0; | |||
} | |||
} | |||
} |
@ -0,0 +1,134 @@ | |||
// Bootstrap functions | |||
// | |||
// Utility mixins and functions for evaluating source code across our variables, maps, and mixins. | |||
// Ascending | |||
// Used to evaluate Sass maps like our grid breakpoints. | |||
@mixin _assert-ascending($map, $map-name) { | |||
$prev-key: null; | |||
$prev-num: null; | |||
@each $key, $num in $map { | |||
@if $prev-num == null or unit($num) == "%" or unit($prev-num) == "%" { | |||
// Do nothing | |||
} @else if not comparable($prev-num, $num) { | |||
@warn "Potentially invalid value for #{$map-name}: This map must be in ascending order, but key '#{$key}' has value #{$num} whose unit makes it incomparable to #{$prev-num}, the value of the previous key '#{$prev-key}' !"; | |||
} @else if $prev-num >= $num { | |||
@warn "Invalid value for #{$map-name}: This map must be in ascending order, but key '#{$key}' has value #{$num} which isn't greater than #{$prev-num}, the value of the previous key '#{$prev-key}' !"; | |||
} | |||
$prev-key: $key; | |||
$prev-num: $num; | |||
} | |||
} | |||
// Starts at zero | |||
// Used to ensure the min-width of the lowest breakpoint starts at 0. | |||
@mixin _assert-starts-at-zero($map, $map-name: "$grid-breakpoints") { | |||
$values: map-values($map); | |||
$first-value: nth($values, 1); | |||
@if $first-value != 0 { | |||
@warn "First breakpoint in #{$map-name} must start at 0, but starts at #{$first-value}."; | |||
} | |||
} | |||
// Replace `$search` with `$replace` in `$string` | |||
// Used on our SVG icon backgrounds for custom forms. | |||
// | |||
// @author Hugo Giraudel | |||
// @param {String} $string - Initial string | |||
// @param {String} $search - Substring to replace | |||
// @param {String} $replace ('') - New value | |||
// @return {String} - Updated string | |||
@function str-replace($string, $search, $replace: "") { | |||
$index: str-index($string, $search); | |||
@if $index { | |||
@return str-slice($string, 1, $index - 1) + $replace + str-replace(str-slice($string, $index + str-length($search)), $search, $replace); | |||
} | |||
@return $string; | |||
} | |||
// See https://codepen.io/kevinweber/pen/dXWoRw | |||
@function escape-svg($string) { | |||
@if str-index($string, "data:image/svg+xml") { | |||
@each $char, $encoded in $escaped-characters { | |||
$string: str-replace($string, $char, $encoded); | |||
} | |||
} | |||
@return $string; | |||
} | |||
// Color contrast | |||
@function color-yiq($color, $dark: $yiq-text-dark, $light: $yiq-text-light) { | |||
$r: red($color); | |||
$g: green($color); | |||
$b: blue($color); | |||
$yiq: (($r * 299) + ($g * 587) + ($b * 114)) / 1000; | |||
@if ($yiq >= $yiq-contrasted-threshold) { | |||
@return $dark; | |||
} @else { | |||
@return $light; | |||
} | |||
} | |||
// Retrieve color Sass maps | |||
@function color($key: "blue") { | |||
@return map-get($colors, $key); | |||
} | |||
@function theme-color($key: "primary") { | |||
@return map-get($theme-colors, $key); | |||
} | |||
@function gray($key: "100") { | |||
@return map-get($grays, $key); | |||
} | |||
// Request a theme color level | |||
@function theme-color-level($color-name: "primary", $level: 0) { | |||
$color: theme-color($color-name); | |||
$color-base: if($level > 0, $black, $white); | |||
$level: abs($level); | |||
@return mix($color-base, $color, $level * $theme-color-interval); | |||
} | |||
// Return valid calc | |||
@function add($value1, $value2, $return-calc: true) { | |||
@if $value1 == null { | |||
@return $value2; | |||
} | |||
@if $value2 == null { | |||
@return $value1; | |||
} | |||
@if type-of($value1) == number and type-of($value2) == number and comparable($value1, $value2) { | |||
@return $value1 + $value2; | |||
} | |||
@return if($return-calc == true, calc(#{$value1} + #{$value2}), $value1 + unquote(" + ") + $value2); | |||
} | |||
@function subtract($value1, $value2, $return-calc: true) { | |||
@if $value1 == null and $value2 == null { | |||
@return null; | |||
} | |||
@if $value1 == null { | |||
@return -$value2; | |||
} | |||
@if $value2 == null { | |||
@return $value1; | |||
} | |||
@if type-of($value1) == number and type-of($value2) == number and comparable($value1, $value2) { | |||
@return $value1 - $value2; | |||
} | |||
@return if($return-calc == true, calc(#{$value1} - #{$value2}), $value1 + unquote(" - ") + $value2); | |||
} |
@ -0,0 +1,69 @@ | |||
// Container widths | |||
// | |||
// Set the container width, and override it for fixed navbars in media queries. | |||
@if $enable-grid-classes { | |||
// Single container class with breakpoint max-widths | |||
.container { | |||
@include make-container(); | |||
@include make-container-max-widths(); | |||
} | |||
// 100% wide container at all breakpoints | |||
.container-fluid { | |||
@include make-container(); | |||
} | |||
// Responsive containers that are 100% wide until a breakpoint | |||
@each $breakpoint, $container-max-width in $container-max-widths { | |||
.container-#{$breakpoint} { | |||
@extend .container-fluid; | |||
} | |||
@include media-breakpoint-up($breakpoint, $grid-breakpoints) { | |||
%responsive-container-#{$breakpoint} { | |||
max-width: $container-max-width; | |||
} | |||
@each $name, $width in $grid-breakpoints { | |||
@if ($container-max-width > $width or $breakpoint == $name) { | |||
.container#{breakpoint-infix($name, $grid-breakpoints)} { | |||
@extend %responsive-container-#{$breakpoint}; | |||
} | |||
} | |||
} | |||
} | |||
} | |||
} | |||
// Row | |||
// | |||
// Rows contain your columns. | |||
@if $enable-grid-classes { | |||
.row { | |||
@include make-row(); | |||
} | |||
// Remove the negative margin from default .row, then the horizontal padding | |||
// from all immediate children columns (to prevent runaway style inheritance). | |||
.no-gutters { | |||
margin-right: 0; | |||
margin-left: 0; | |||
> .col, | |||
> [class*="col-"] { | |||
padding-right: 0; | |||
padding-left: 0; | |||
} | |||
} | |||
} | |||
// Columns | |||
// | |||
// Common styles for small and large grid columns | |||
@if $enable-grid-classes { | |||
@include make-grid-columns(); | |||
} |
@ -0,0 +1,42 @@ | |||
// Responsive images (ensure images don't scale beyond their parents) | |||
// | |||
// This is purposefully opt-in via an explicit class rather than being the default for all `<img>`s. | |||
// We previously tried the "images are responsive by default" approach in Bootstrap v2, | |||
// and abandoned it in Bootstrap v3 because it breaks lots of third-party widgets (including Google Maps) | |||
// which weren't expecting the images within themselves to be involuntarily resized. | |||
// See also https://github.com/twbs/bootstrap/issues/18178 | |||
.img-fluid { | |||
@include img-fluid(); | |||
} | |||
// Image thumbnails | |||
.img-thumbnail { | |||
padding: $thumbnail-padding; | |||
background-color: $thumbnail-bg; | |||
border: $thumbnail-border-width solid $thumbnail-border-color; | |||
@include border-radius($thumbnail-border-radius); | |||
@include box-shadow($thumbnail-box-shadow); | |||
// Keep them at most 100% wide | |||
@include img-fluid(); | |||
} | |||
// | |||
// Figures | |||
// | |||
.figure { | |||
// Ensures the caption's text aligns with the image. | |||
display: inline-block; | |||
} | |||
.figure-img { | |||
margin-bottom: $spacer / 2; | |||
line-height: 1; | |||
} | |||
.figure-caption { | |||
@include font-size($figure-caption-font-size); | |||
color: $figure-caption-color; | |||
} |
@ -0,0 +1,191 @@ | |||
// stylelint-disable selector-no-qualifying-type | |||
// | |||
// Base styles | |||
// | |||
.input-group { | |||
position: relative; | |||
display: flex; | |||
flex-wrap: wrap; // For form validation feedback | |||
align-items: stretch; | |||
width: 100%; | |||
> .form-control, | |||
> .form-control-plaintext, | |||
> .custom-select, | |||
> .custom-file { | |||
position: relative; // For focus state's z-index | |||
flex: 1 1 0%; | |||
min-width: 0; // https://stackoverflow.com/questions/36247140/why-dont-flex-items-shrink-past-content-size | |||
margin-bottom: 0; | |||
+ .form-control, | |||
+ .custom-select, | |||
+ .custom-file { | |||
margin-left: -$input-border-width; | |||
} | |||
} | |||
// Bring the "active" form control to the top of surrounding elements | |||
> .form-control:focus, | |||
> .custom-select:focus, | |||
> .custom-file .custom-file-input:focus ~ .custom-file-label { | |||
z-index: 3; | |||
} | |||
// Bring the custom file input above the label | |||
> .custom-file .custom-file-input:focus { | |||
z-index: 4; | |||
} | |||
> .form-control, | |||
> .custom-select { | |||
&:not(:last-child) { @include border-right-radius(0); } | |||
&:not(:first-child) { @include border-left-radius(0); } | |||
} | |||
// Custom file inputs have more complex markup, thus requiring different | |||
// border-radius overrides. | |||
> .custom-file { | |||
display: flex; | |||
align-items: center; | |||
&:not(:last-child) .custom-file-label, | |||
&:not(:last-child) .custom-file-label::after { @include border-right-radius(0); } | |||
&:not(:first-child) .custom-file-label { @include border-left-radius(0); } | |||
} | |||
} | |||
// Prepend and append | |||
// | |||
// While it requires one extra layer of HTML for each, dedicated prepend and | |||
// append elements allow us to 1) be less clever, 2) simplify our selectors, and | |||
// 3) support HTML5 form validation. | |||
.input-group-prepend, | |||
.input-group-append { | |||
display: flex; | |||
// Ensure buttons are always above inputs for more visually pleasing borders. | |||
// This isn't needed for `.input-group-text` since it shares the same border-color | |||
// as our inputs. | |||
.btn { | |||
position: relative; | |||
z-index: 2; | |||
&:focus { | |||
z-index: 3; | |||
} | |||
} | |||
.btn + .btn, | |||
.btn + .input-group-text, | |||
.input-group-text + .input-group-text, | |||
.input-group-text + .btn { | |||
margin-left: -$input-border-width; | |||
} | |||
} | |||
.input-group-prepend { margin-right: -$input-border-width; } | |||
.input-group-append { margin-left: -$input-border-width; } | |||
// Textual addons | |||
// | |||
// Serves as a catch-all element for any text or radio/checkbox input you wish | |||
// to prepend or append to an input. | |||
.input-group-text { | |||
display: flex; | |||
align-items: center; | |||
padding: $input-padding-y $input-padding-x; | |||
margin-bottom: 0; // Allow use of <label> elements by overriding our default margin-bottom | |||
@include font-size($input-font-size); // Match inputs | |||
font-weight: $font-weight-normal; | |||
line-height: $input-line-height; | |||
color: $input-group-addon-color; | |||
text-align: center; | |||
white-space: nowrap; | |||
background-color: $input-group-addon-bg; | |||
border: $input-border-width solid $input-group-addon-border-color; | |||
@include border-radius($input-border-radius); | |||
// Nuke default margins from checkboxes and radios to vertically center within. | |||
input[type="radio"], | |||
input[type="checkbox"] { | |||
margin-top: 0; | |||
} | |||
} | |||
// Sizing | |||
// | |||
// Remix the default form control sizing classes into new ones for easier | |||
// manipulation. | |||
.input-group-lg > .form-control:not(textarea), | |||
.input-group-lg > .custom-select { | |||
height: $input-height-lg; | |||
} | |||
.input-group-lg > .form-control, | |||
.input-group-lg > .custom-select, | |||
.input-group-lg > .input-group-prepend > .input-group-text, | |||
.input-group-lg > .input-group-append > .input-group-text, | |||
.input-group-lg > .input-group-prepend > .btn, | |||
.input-group-lg > .input-group-append > .btn { | |||
padding: $input-padding-y-lg $input-padding-x-lg; | |||
@include font-size($input-font-size-lg); | |||
line-height: $input-line-height-lg; | |||
@include border-radius($input-border-radius-lg); | |||
} | |||
.input-group-sm > .form-control:not(textarea), | |||
.input-group-sm > .custom-select { | |||
height: $input-height-sm; | |||
} | |||
.input-group-sm > .form-control, | |||
.input-group-sm > .custom-select, | |||
.input-group-sm > .input-group-prepend > .input-group-text, | |||
.input-group-sm > .input-group-append > .input-group-text, | |||
.input-group-sm > .input-group-prepend > .btn, | |||
.input-group-sm > .input-group-append > .btn { | |||
padding: $input-padding-y-sm $input-padding-x-sm; | |||
@include font-size($input-font-size-sm); | |||
line-height: $input-line-height-sm; | |||
@include border-radius($input-border-radius-sm); | |||
} | |||
.input-group-lg > .custom-select, | |||
.input-group-sm > .custom-select { | |||
padding-right: $custom-select-padding-x + $custom-select-indicator-padding; | |||
} | |||
// Prepend and append rounded corners | |||
// | |||
// These rulesets must come after the sizing ones to properly override sm and lg | |||
// border-radius values when extending. They're more specific than we'd like | |||
// with the `.input-group >` part, but without it, we cannot override the sizing. | |||
.input-group > .input-group-prepend > .btn, | |||
.input-group > .input-group-prepend > .input-group-text, | |||
.input-group > .input-group-append:not(:last-child) > .btn, | |||
.input-group > .input-group-append:not(:last-child) > .input-group-text, | |||
.input-group > .input-group-append:last-child > .btn:not(:last-child):not(.dropdown-toggle), | |||
.input-group > .input-group-append:last-child > .input-group-text:not(:last-child) { | |||
@include border-right-radius(0); | |||
} | |||
.input-group > .input-group-append > .btn, | |||
.input-group > .input-group-append > .input-group-text, | |||
.input-group > .input-group-prepend:not(:first-child) > .btn, | |||
.input-group > .input-group-prepend:not(:first-child) > .input-group-text, | |||
.input-group > .input-group-prepend:first-child > .btn:not(:first-child), | |||
.input-group > .input-group-prepend:first-child > .input-group-text:not(:first-child) { | |||
@include border-left-radius(0); | |||
} |
@ -0,0 +1,17 @@ | |||
.jumbotron { | |||
padding: $jumbotron-padding ($jumbotron-padding / 2); | |||
margin-bottom: $jumbotron-padding; | |||
color: $jumbotron-color; | |||
background-color: $jumbotron-bg; | |||
@include border-radius($border-radius-lg); | |||
@include media-breakpoint-up(sm) { | |||
padding: ($jumbotron-padding * 2) $jumbotron-padding; | |||
} | |||
} | |||
.jumbotron-fluid { | |||
padding-right: 0; | |||
padding-left: 0; | |||
@include border-radius(0); | |||
} |
@ -0,0 +1,158 @@ | |||
// Base class | |||
// | |||
// Easily usable on <ul>, <ol>, or <div>. | |||
.list-group { | |||
display: flex; | |||
flex-direction: column; | |||
// No need to set list-style: none; since .list-group-item is block level | |||
padding-left: 0; // reset padding because ul and ol | |||
margin-bottom: 0; | |||
} | |||
// Interactive list items | |||
// | |||
// Use anchor or button elements instead of `li`s or `div`s to create interactive | |||
// list items. Includes an extra `.active` modifier class for selected items. | |||
.list-group-item-action { | |||
width: 100%; // For `<button>`s (anchors become 100% by default though) | |||
color: $list-group-action-color; | |||
text-align: inherit; // For `<button>`s (anchors inherit) | |||
// Hover state | |||
@include hover-focus() { | |||
z-index: 1; // Place hover/focus items above their siblings for proper border styling | |||
color: $list-group-action-hover-color; | |||
text-decoration: none; | |||
background-color: $list-group-hover-bg; | |||
} | |||
&:active { | |||
color: $list-group-action-active-color; | |||
background-color: $list-group-action-active-bg; | |||
} | |||
} | |||
// Individual list items | |||
// | |||
// Use on `li`s or `div`s within the `.list-group` parent. | |||
.list-group-item { | |||
position: relative; | |||
display: block; | |||
padding: $list-group-item-padding-y $list-group-item-padding-x; | |||
color: $list-group-color; | |||
background-color: $list-group-bg; | |||
border: $list-group-border-width solid $list-group-border-color; | |||
&:first-child { | |||
@include border-top-radius($list-group-border-radius); | |||
} | |||
&:last-child { | |||
@include border-bottom-radius($list-group-border-radius); | |||
} | |||
&.disabled, | |||
&:disabled { | |||
color: $list-group-disabled-color; | |||
pointer-events: none; | |||
background-color: $list-group-disabled-bg; | |||
} | |||
// Include both here for `<a>`s and `<button>`s | |||
&.active { | |||
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-color; | |||
} | |||
& + & { | |||
border-top-width: 0; | |||
&.active { | |||
margin-top: -$list-group-border-width; | |||
border-top-width: $list-group-border-width; | |||
} | |||
} | |||
} | |||
// Horizontal | |||
// | |||
// Change the layout of list group items from vertical (default) to horizontal. | |||
@each $breakpoint in map-keys($grid-breakpoints) { | |||
@include media-breakpoint-up($breakpoint) { | |||
$infix: breakpoint-infix($breakpoint, $grid-breakpoints); | |||
.list-group-horizontal#{$infix} { | |||
flex-direction: row; | |||
.list-group-item { | |||
&:first-child { | |||
@include border-bottom-left-radius($list-group-border-radius); | |||
@include border-top-right-radius(0); | |||
} | |||
&:last-child { | |||
@include border-top-right-radius($list-group-border-radius); | |||
@include border-bottom-left-radius(0); | |||
} | |||
&.active { | |||
margin-top: 0; | |||
} | |||
& + .list-group-item { | |||
border-top-width: $list-group-border-width; | |||
border-left-width: 0; | |||
&.active { | |||
margin-left: -$list-group-border-width; | |||
border-left-width: $list-group-border-width; | |||
} | |||
} | |||
} | |||
} | |||
} | |||
} | |||
// Flush list items | |||
// | |||
// Remove borders and border-radius to keep list group items edge-to-edge. Most | |||
// useful within other components (e.g., cards). | |||
.list-group-flush { | |||
.list-group-item { | |||
border-right-width: 0; | |||
border-left-width: 0; | |||
@include border-radius(0); | |||
&:first-child { | |||
border-top-width: 0; | |||
} | |||
} | |||
&:last-child { | |||
.list-group-item:last-child { | |||
border-bottom-width: 0; | |||
} | |||
} | |||
} | |||
// Contextual variants | |||
// | |||
// Add modifier classes to change text and background color on individual items. | |||
// Organizationally, this must come after the `:hover` states. | |||
@each $color, $value in $theme-colors { | |||
@include list-group-item-variant($color, theme-color-level($color, -9), theme-color-level($color, 6)); | |||
} |
@ -0,0 +1,8 @@ | |||
.media { | |||
display: flex; | |||
align-items: flex-start; | |||
} | |||
.media-body { | |||
flex: 1; | |||
} |
@ -0,0 +1,47 @@ | |||
// Toggles | |||
// | |||
// Used in conjunction with global variables to enable certain theme features. | |||
// Vendor | |||
@import "vendor/rfs"; | |||
// Deprecate | |||
@import "mixins/deprecate"; | |||
// Utilities | |||
@import "mixins/breakpoints"; | |||
@import "mixins/hover"; | |||
@import "mixins/image"; | |||
@import "mixins/badge"; | |||
@import "mixins/resize"; | |||
@import "mixins/screen-reader"; | |||
@import "mixins/size"; | |||
@import "mixins/reset-text"; | |||
@import "mixins/text-emphasis"; | |||
@import "mixins/text-hide"; | |||
@import "mixins/text-truncate"; | |||
@import "mixins/visibility"; | |||
// Components | |||
@import "mixins/alert"; | |||
@import "mixins/buttons"; | |||
@import "mixins/caret"; | |||
@import "mixins/pagination"; | |||
@import "mixins/lists"; | |||
@import "mixins/list-group"; | |||
@import "mixins/nav-divider"; | |||
@import "mixins/forms"; | |||
@import "mixins/table-row"; | |||
// Skins | |||
@import "mixins/background-variant"; | |||
@import "mixins/border-radius"; | |||
@import "mixins/box-shadow"; | |||
@import "mixins/gradients"; | |||
@import "mixins/transition"; | |||
// Layout | |||
@import "mixins/clearfix"; | |||
@import "mixins/grid-framework"; | |||
@import "mixins/grid"; | |||
@import "mixins/float"; |
@ -0,0 +1,239 @@ | |||
// .modal-open - body class for killing the scroll | |||
// .modal - container to scroll within | |||
// .modal-dialog - positioning shell for the actual modal | |||
// .modal-content - actual modal w/ bg and corners and stuff | |||
.modal-open { | |||
// Kill the scroll on the body | |||
overflow: hidden; | |||
.modal { | |||
overflow-x: hidden; | |||
overflow-y: auto; | |||
} | |||
} | |||
// Container that the modal scrolls within | |||
.modal { | |||
position: fixed; | |||
top: 0; | |||
left: 0; | |||
z-index: $zindex-modal; | |||
display: none; | |||
width: 100%; | |||
height: 100%; | |||
overflow: hidden; | |||
// Prevent Chrome on Windows from adding a focus outline. For details, see | |||
// https://github.com/twbs/bootstrap/pull/10951. | |||
outline: 0; | |||
// We deliberately don't use `-webkit-overflow-scrolling: touch;` due to a | |||
// gnarly iOS Safari bug: https://bugs.webkit.org/show_bug.cgi?id=158342 | |||
// See also https://github.com/twbs/bootstrap/issues/17695 | |||
} | |||
// Shell div to position the modal with bottom padding | |||
.modal-dialog { | |||
position: relative; | |||
width: auto; | |||
margin: $modal-dialog-margin; | |||
// allow clicks to pass through for custom click handling to close modal | |||
pointer-events: none; | |||
// When fading in the modal, animate it to slide down | |||
.modal.fade & { | |||
@include transition($modal-transition); | |||
transform: $modal-fade-transform; | |||
} | |||
.modal.show & { | |||
transform: $modal-show-transform; | |||
} | |||
// When trying to close, animate focus to scale | |||
.modal.modal-static & { | |||
transform: $modal-scale-transform; | |||
} | |||
} | |||
.modal-dialog-scrollable { | |||
display: flex; // IE10/11 | |||
max-height: subtract(100%, $modal-dialog-margin * 2); | |||
.modal-content { | |||
max-height: subtract(100vh, $modal-dialog-margin * 2); // IE10/11 | |||
overflow: hidden; | |||
} | |||
.modal-header, | |||
.modal-footer { | |||
flex-shrink: 0; | |||
} | |||
.modal-body { | |||
overflow-y: auto; | |||
} | |||
} | |||
.modal-dialog-centered { | |||
display: flex; | |||
align-items: center; | |||
min-height: subtract(100%, $modal-dialog-margin * 2); | |||
// Ensure `modal-dialog-centered` extends the full height of the view (IE10/11) | |||
&::before { | |||
display: block; // IE10 | |||
height: subtract(100vh, $modal-dialog-margin * 2); | |||
content: ""; | |||
} | |||
// Ensure `.modal-body` shows scrollbar (IE10/11) | |||
&.modal-dialog-scrollable { | |||
flex-direction: column; | |||
justify-content: center; | |||
height: 100%; | |||
.modal-content { | |||
max-height: none; | |||
} | |||
&::before { | |||
content: none; | |||
} | |||
} | |||
} | |||
// Actual modal | |||
.modal-content { | |||
position: relative; | |||
display: flex; | |||
flex-direction: column; | |||
width: 100%; // Ensure `.modal-content` extends the full width of the parent `.modal-dialog` | |||
// counteract the pointer-events: none; in the .modal-dialog | |||
color: $modal-content-color; | |||
pointer-events: auto; | |||
background-color: $modal-content-bg; | |||
background-clip: padding-box; | |||
border: $modal-content-border-width solid $modal-content-border-color; | |||
@include border-radius($modal-content-border-radius); | |||
@include box-shadow($modal-content-box-shadow-xs); | |||
// Remove focus outline from opened modal | |||
outline: 0; | |||
} | |||
// Modal background | |||
.modal-backdrop { | |||
position: fixed; | |||
top: 0; | |||
left: 0; | |||
z-index: $zindex-modal-backdrop; | |||
width: 100vw; | |||
height: 100vh; | |||
background-color: $modal-backdrop-bg; | |||
// Fade for backdrop | |||
&.fade { opacity: 0; } | |||
&.show { opacity: $modal-backdrop-opacity; } | |||
} | |||
// Modal header | |||
// Top section of the modal w/ title and dismiss | |||
.modal-header { | |||
display: flex; | |||
align-items: flex-start; // so the close btn always stays on the upper right corner | |||
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; | |||
@include border-top-radius($modal-content-inner-border-radius); | |||
.close { | |||
padding: $modal-header-padding; | |||
// auto on the left force icon to the right even when there is no .modal-title | |||
margin: (-$modal-header-padding-y) (-$modal-header-padding-x) (-$modal-header-padding-y) auto; | |||
} | |||
} | |||
// Title text within header | |||
.modal-title { | |||
margin-bottom: 0; | |||
line-height: $modal-title-line-height; | |||
} | |||
// Modal body | |||
// Where all modal content resides (sibling of .modal-header and .modal-footer) | |||
.modal-body { | |||
position: relative; | |||
// Enable `flex-grow: 1` so that the body take up as much space as possible | |||
// when there should be a fixed height on `.modal-dialog`. | |||
flex: 1 1 auto; | |||
padding: $modal-inner-padding; | |||
} | |||
// Footer (for actions) | |||
.modal-footer { | |||
display: flex; | |||
flex-wrap: wrap; | |||
align-items: center; // vertically center | |||
justify-content: flex-end; // Right align buttons with flex property because text-align doesn't work on flex items | |||
padding: $modal-inner-padding - $modal-footer-margin-between / 2; | |||
border-top: $modal-footer-border-width solid $modal-footer-border-color; | |||
@include border-bottom-radius($modal-content-inner-border-radius); | |||
// Place margin between footer elements | |||
// This solution is far from ideal because of the universal selector usage, | |||
// but is needed to fix https://github.com/twbs/bootstrap/issues/24800 | |||
// stylelint-disable-next-line selector-max-universal | |||
> * { | |||
margin: $modal-footer-margin-between / 2; | |||
} | |||
} | |||
// Measure scrollbar width for padding body during modal show/hide | |||
.modal-scrollbar-measure { | |||
position: absolute; | |||
top: -9999px; | |||
width: 50px; | |||
height: 50px; | |||
overflow: scroll; | |||
} | |||
// Scale up the modal | |||
@include media-breakpoint-up(sm) { | |||
// Automatically set modal's width for larger viewports | |||
.modal-dialog { | |||
max-width: $modal-md; | |||
margin: $modal-dialog-margin-y-sm-up auto; | |||
} | |||
.modal-dialog-scrollable { | |||
max-height: subtract(100%, $modal-dialog-margin-y-sm-up * 2); | |||
.modal-content { | |||
max-height: subtract(100vh, $modal-dialog-margin-y-sm-up * 2); | |||
} | |||
} | |||
.modal-dialog-centered { | |||
min-height: subtract(100%, $modal-dialog-margin-y-sm-up * 2); | |||
&::before { | |||
height: subtract(100vh, $modal-dialog-margin-y-sm-up * 2); | |||
} | |||
} | |||
.modal-content { | |||
@include box-shadow($modal-content-box-shadow-sm-up); | |||
} | |||
.modal-sm { max-width: $modal-sm; } | |||
} | |||
@include media-breakpoint-up(lg) { | |||
.modal-lg, | |||
.modal-xl { | |||
max-width: $modal-lg; | |||
} | |||
} | |||
@include media-breakpoint-up(xl) { | |||
.modal-xl { max-width: $modal-xl; } | |||
} |
@ -0,0 +1,120 @@ | |||
// Base class | |||
// | |||
// Kickstart any navigation component with a set of style resets. Works with | |||
// `<nav>`s, `<ul>`s or `<ol>`s. | |||
.nav { | |||
display: flex; | |||
flex-wrap: wrap; | |||
padding-left: 0; | |||
margin-bottom: 0; | |||
list-style: none; | |||
} | |||
.nav-link { | |||
display: block; | |||
padding: $nav-link-padding-y $nav-link-padding-x; | |||
@include hover-focus() { | |||
text-decoration: none; | |||
} | |||
// Disabled state lightens text | |||
&.disabled { | |||
color: $nav-link-disabled-color; | |||
pointer-events: none; | |||
cursor: default; | |||
} | |||
} | |||
// | |||
// Tabs | |||
// | |||
.nav-tabs { | |||
border-bottom: $nav-tabs-border-width solid $nav-tabs-border-color; | |||
.nav-item { | |||
margin-bottom: -$nav-tabs-border-width; | |||
} | |||
.nav-link { | |||
border: $nav-tabs-border-width solid transparent; | |||
@include border-top-radius($nav-tabs-border-radius); | |||
@include hover-focus() { | |||
border-color: $nav-tabs-link-hover-border-color; | |||
} | |||
&.disabled { | |||
color: $nav-link-disabled-color; | |||
background-color: transparent; | |||
border-color: transparent; | |||
} | |||
} | |||
.nav-link.active, | |||
.nav-item.show .nav-link { | |||
color: $nav-tabs-link-active-color; | |||
background-color: $nav-tabs-link-active-bg; | |||
border-color: $nav-tabs-link-active-border-color; | |||
} | |||
.dropdown-menu { | |||
// Make dropdown border overlap tab border | |||
margin-top: -$nav-tabs-border-width; | |||
// Remove the top rounded corners here since there is a hard edge above the menu | |||
@include border-top-radius(0); | |||
} | |||
} | |||
// | |||
// Pills | |||
// | |||
.nav-pills { | |||
.nav-link { | |||
@include border-radius($nav-pills-border-radius); | |||
} | |||
.nav-link.active, | |||
.show > .nav-link { | |||
color: $nav-pills-link-active-color; | |||
background-color: $nav-pills-link-active-bg; | |||
} | |||
} | |||
// | |||
// Justified variants | |||
// | |||
.nav-fill { | |||
.nav-item { | |||
flex: 1 1 auto; | |||
text-align: center; | |||
} | |||
} | |||
.nav-justified { | |||
.nav-item { | |||
flex-basis: 0; | |||
flex-grow: 1; | |||
text-align: center; | |||
} | |||
} | |||
// Tabbable tabs | |||
// | |||
// Hide tabbable panes to start, show them when `.active` | |||
.tab-content { | |||
> .tab-pane { | |||
display: none; | |||
} | |||
> .active { | |||
display: block; | |||
} | |||
} |
@ -0,0 +1,324 @@ | |||
// Contents | |||
// | |||
// Navbar | |||
// Navbar brand | |||
// Navbar nav | |||
// Navbar text | |||
// Navbar divider | |||
// Responsive navbar | |||
// Navbar position | |||
// Navbar themes | |||
// Navbar | |||
// | |||
// Provide a static navbar from which we expand to create full-width, fixed, and | |||
// other navbar variations. | |||
.navbar { | |||
position: relative; | |||
display: flex; | |||
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 properties so that content nested within behave properly. | |||
%container-flex-properties { | |||
display: flex; | |||
flex-wrap: wrap; | |||
align-items: center; | |||
justify-content: space-between; | |||
} | |||
.container, | |||
.container-fluid { | |||
@extend %container-flex-properties; | |||
} | |||
@each $breakpoint, $container-max-width in $container-max-widths { | |||
> .container#{breakpoint-infix($breakpoint, $container-max-widths)} { | |||
@extend %container-flex-properties; | |||
} | |||
} | |||
} | |||
// Navbar brand | |||
// | |||
// Used for brand, project, or site names. | |||
.navbar-brand { | |||
display: inline-block; | |||
padding-top: $navbar-brand-padding-y; | |||
padding-bottom: $navbar-brand-padding-y; | |||
margin-right: $navbar-padding-x; | |||
@include font-size($navbar-brand-font-size); | |||
line-height: inherit; | |||
white-space: nowrap; | |||
@include hover-focus() { | |||
text-decoration: none; | |||
} | |||
} | |||
// Navbar nav | |||
// | |||
// Custom navbar navigation (doesn't require `.nav`, but does make use of `.nav-link`). | |||
.navbar-nav { | |||
display: flex; | |||
flex-direction: column; // cannot use `inherit` to get the `.navbar`s value | |||
padding-left: 0; | |||
margin-bottom: 0; | |||
list-style: none; | |||
.nav-link { | |||
padding-right: 0; | |||
padding-left: 0; | |||
} | |||
.dropdown-menu { | |||
position: static; | |||
float: none; | |||
} | |||
} | |||
// Navbar text | |||
// | |||
// | |||
.navbar-text { | |||
display: inline-block; | |||
padding-top: $nav-link-padding-y; | |||
padding-bottom: $nav-link-padding-y; | |||
} | |||
// Responsive navbar | |||
// | |||
// 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 orientation. Requires the use of `flex-wrap: wrap` | |||
// on the `.navbar` parent. | |||
.navbar-collapse { | |||
flex-basis: 100%; | |||
flex-grow: 1; | |||
// 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 { | |||
padding: $navbar-toggler-padding-y $navbar-toggler-padding-x; | |||
@include font-size($navbar-toggler-font-size); | |||
line-height: 1; | |||
background-color: transparent; // remove default button style | |||
border: $border-width solid transparent; // remove default button style | |||
@include border-radius($navbar-toggler-border-radius); | |||
@include hover-focus() { | |||
text-decoration: none; | |||
} | |||
} | |||
// Keep as a separate element so folks can easily override it with another icon | |||
// or image file as needed. | |||
.navbar-toggler-icon { | |||
display: inline-block; | |||
width: 1.5em; | |||
height: 1.5em; | |||
vertical-align: middle; | |||
content: ""; | |||
background: no-repeat center center; | |||
background-size: 100% 100%; | |||
} | |||
// Generate series of `.navbar-expand-*` responsive classes for configuring | |||
// where your navbar collapses. | |||
.navbar-expand { | |||
@each $breakpoint in map-keys($grid-breakpoints) { | |||
$next: breakpoint-next($breakpoint, $grid-breakpoints); | |||
$infix: breakpoint-infix($next, $grid-breakpoints); | |||
&#{$infix} { | |||
@include media-breakpoint-down($breakpoint) { | |||
%container-navbar-expand-#{$breakpoint} { | |||
padding-right: 0; | |||
padding-left: 0; | |||
} | |||
> .container, | |||
> .container-fluid { | |||
@extend %container-navbar-expand-#{$breakpoint}; | |||
} | |||
@each $size, $container-max-width in $container-max-widths { | |||
> .container#{breakpoint-infix($size, $container-max-widths)} { | |||
@extend %container-navbar-expand-#{$breakpoint}; | |||
} | |||
} | |||
} | |||
@include media-breakpoint-up($next) { | |||
flex-flow: row nowrap; | |||
justify-content: flex-start; | |||
.navbar-nav { | |||
flex-direction: row; | |||
.dropdown-menu { | |||
position: absolute; | |||
} | |||
.nav-link { | |||
padding-right: $navbar-nav-link-padding-x; | |||
padding-left: $navbar-nav-link-padding-x; | |||
} | |||
} | |||
// For nesting containers, have to redeclare for alignment purposes | |||
%container-nesting-#{$breakpoint} { | |||
flex-wrap: nowrap; | |||
} | |||
> .container, | |||
> .container-fluid { | |||
@extend %container-nesting-#{$breakpoint}; | |||
} | |||
@each $size, $container-max-width in $container-max-widths { | |||
> .container#{breakpoint-infix($size, $container-max-widths)} { | |||
@extend %container-nesting-#{$breakpoint}; | |||
} | |||
} | |||
.navbar-collapse { | |||
display: flex !important; // stylelint-disable-line declaration-no-important | |||
// Changes flex-bases to auto because of an IE10 bug | |||
flex-basis: auto; | |||
} | |||
.navbar-toggler { | |||
display: none; | |||
} | |||
} | |||
} | |||
} | |||
} | |||
// Navbar themes | |||
// | |||
// Styles for switching between navbars with light or dark background. | |||
// Dark links against a light background | |||
.navbar-light { | |||
.navbar-brand { | |||
color: $navbar-light-brand-color; | |||
@include hover-focus() { | |||
color: $navbar-light-brand-hover-color; | |||
} | |||
} | |||
.navbar-nav { | |||
.nav-link { | |||
color: $navbar-light-color; | |||
@include hover-focus() { | |||
color: $navbar-light-hover-color; | |||
} | |||
&.disabled { | |||
color: $navbar-light-disabled-color; | |||
} | |||
} | |||
.show > .nav-link, | |||
.active > .nav-link, | |||
.nav-link.show, | |||
.nav-link.active { | |||
color: $navbar-light-active-color; | |||
} | |||
} | |||
.navbar-toggler { | |||
color: $navbar-light-color; | |||
border-color: $navbar-light-toggler-border-color; | |||
} | |||
.navbar-toggler-icon { | |||
background-image: escape-svg($navbar-light-toggler-icon-bg); | |||
} | |||
.navbar-text { | |||
color: $navbar-light-color; | |||
a { | |||
color: $navbar-light-active-color; | |||
@include hover-focus() { | |||
color: $navbar-light-active-color; | |||
} | |||
} | |||
} | |||
} | |||
// White links against a dark background | |||
.navbar-dark { | |||
.navbar-brand { | |||
color: $navbar-dark-brand-color; | |||
@include hover-focus() { | |||
color: $navbar-dark-brand-hover-color; | |||
} | |||
} | |||
.navbar-nav { | |||
.nav-link { | |||
color: $navbar-dark-color; | |||
@include hover-focus() { | |||
color: $navbar-dark-hover-color; | |||
} | |||
&.disabled { | |||
color: $navbar-dark-disabled-color; | |||
} | |||
} | |||
.show > .nav-link, | |||
.active > .nav-link, | |||
.nav-link.show, | |||
.nav-link.active { | |||
color: $navbar-dark-active-color; | |||
} | |||
} | |||
.navbar-toggler { | |||
color: $navbar-dark-color; | |||
border-color: $navbar-dark-toggler-border-color; | |||
} | |||
.navbar-toggler-icon { | |||
background-image: escape-svg($navbar-dark-toggler-icon-bg); | |||
} | |||
.navbar-text { | |||
color: $navbar-dark-color; | |||
a { | |||
color: $navbar-dark-active-color; | |||
@include hover-focus() { | |||
color: $navbar-dark-active-color; | |||
} | |||
} | |||
} | |||
} |
@ -0,0 +1,73 @@ | |||
.pagination { | |||
display: flex; | |||
@include list-unstyled(); | |||
@include border-radius(); | |||
} | |||
.page-link { | |||
position: relative; | |||
display: block; | |||
padding: $pagination-padding-y $pagination-padding-x; | |||
margin-left: -$pagination-border-width; | |||
line-height: $pagination-line-height; | |||
color: $pagination-color; | |||
background-color: $pagination-bg; | |||
border: $pagination-border-width solid $pagination-border-color; | |||
&:hover { | |||
z-index: 2; | |||
color: $pagination-hover-color; | |||
text-decoration: none; | |||
background-color: $pagination-hover-bg; | |||
border-color: $pagination-hover-border-color; | |||
} | |||
&:focus { | |||
z-index: 3; | |||
outline: $pagination-focus-outline; | |||
box-shadow: $pagination-focus-box-shadow; | |||
} | |||
} | |||
.page-item { | |||
&:first-child { | |||
.page-link { | |||
margin-left: 0; | |||
@include border-left-radius($border-radius); | |||
} | |||
} | |||
&:last-child { | |||
.page-link { | |||
@include border-right-radius($border-radius); | |||
} | |||
} | |||
&.active .page-link { | |||
z-index: 3; | |||
color: $pagination-active-color; | |||
background-color: $pagination-active-bg; | |||
border-color: $pagination-active-border-color; | |||
} | |||
&.disabled .page-link { | |||
color: $pagination-disabled-color; | |||
pointer-events: none; | |||
// Opinionated: remove the "hand" cursor set previously for .page-link | |||
cursor: auto; | |||
background-color: $pagination-disabled-bg; | |||
border-color: $pagination-disabled-border-color; | |||
} | |||
} | |||
// | |||
// Sizing | |||
// | |||
.pagination-lg { | |||
@include pagination-size($pagination-padding-y-lg, $pagination-padding-x-lg, $font-size-lg, $line-height-lg, $border-radius-lg); | |||
} | |||
.pagination-sm { | |||
@include pagination-size($pagination-padding-y-sm, $pagination-padding-x-sm, $font-size-sm, $line-height-sm, $border-radius-sm); | |||
} |
@ -0,0 +1,170 @@ | |||
.popover { | |||
position: absolute; | |||
top: 0; | |||
left: 0; | |||
z-index: $zindex-popover; | |||
display: block; | |||
max-width: $popover-max-width; | |||
// 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(); | |||
@include font-size($popover-font-size); | |||
// Allow breaking very long words so they don't overflow the popover's bounds | |||
word-wrap: break-word; | |||
background-color: $popover-bg; | |||
background-clip: padding-box; | |||
border: $popover-border-width solid $popover-border-color; | |||
@include border-radius($popover-border-radius); | |||
@include box-shadow($popover-box-shadow); | |||
.arrow { | |||
position: absolute; | |||
display: block; | |||
width: $popover-arrow-width; | |||
height: $popover-arrow-height; | |||
margin: 0 $popover-border-radius; | |||
&::before, | |||
&::after { | |||
position: absolute; | |||
display: block; | |||
content: ""; | |||
border-color: transparent; | |||
border-style: solid; | |||
} | |||
} | |||
} | |||
.bs-popover-top { | |||
margin-bottom: $popover-arrow-height; | |||
> .arrow { | |||
bottom: subtract(-$popover-arrow-height, $popover-border-width); | |||
&::before { | |||
bottom: 0; | |||
border-width: $popover-arrow-height ($popover-arrow-width / 2) 0; | |||
border-top-color: $popover-arrow-outer-color; | |||
} | |||
&::after { | |||
bottom: $popover-border-width; | |||
border-width: $popover-arrow-height ($popover-arrow-width / 2) 0; | |||
border-top-color: $popover-arrow-color; | |||
} | |||
} | |||
} | |||
.bs-popover-right { | |||
margin-left: $popover-arrow-height; | |||
> .arrow { | |||
left: subtract(-$popover-arrow-height, $popover-border-width); | |||
width: $popover-arrow-height; | |||
height: $popover-arrow-width; | |||
margin: $popover-border-radius 0; // make sure the arrow does not touch the popover's rounded corners | |||
&::before { | |||
left: 0; | |||
border-width: ($popover-arrow-width / 2) $popover-arrow-height ($popover-arrow-width / 2) 0; | |||
border-right-color: $popover-arrow-outer-color; | |||
} | |||
&::after { | |||
left: $popover-border-width; | |||
border-width: ($popover-arrow-width / 2) $popover-arrow-height ($popover-arrow-width / 2) 0; | |||
border-right-color: $popover-arrow-color; | |||
} | |||
} | |||
} | |||
.bs-popover-bottom { | |||
margin-top: $popover-arrow-height; | |||
> .arrow { | |||
top: subtract(-$popover-arrow-height, $popover-border-width); | |||
&::before { | |||
top: 0; | |||
border-width: 0 ($popover-arrow-width / 2) $popover-arrow-height ($popover-arrow-width / 2); | |||
border-bottom-color: $popover-arrow-outer-color; | |||
} | |||
&::after { | |||
top: $popover-border-width; | |||
border-width: 0 ($popover-arrow-width / 2) $popover-arrow-height ($popover-arrow-width / 2); | |||
border-bottom-color: $popover-arrow-color; | |||
} | |||
} | |||
// This will remove the popover-header's border just below the arrow | |||
.popover-header::before { | |||
position: absolute; | |||
top: 0; | |||
left: 50%; | |||
display: block; | |||
width: $popover-arrow-width; | |||
margin-left: -$popover-arrow-width / 2; | |||
content: ""; | |||
border-bottom: $popover-border-width solid $popover-header-bg; | |||
} | |||
} | |||
.bs-popover-left { | |||
margin-right: $popover-arrow-height; | |||
> .arrow { | |||
right: subtract(-$popover-arrow-height, $popover-border-width); | |||
width: $popover-arrow-height; | |||
height: $popover-arrow-width; | |||
margin: $popover-border-radius 0; // make sure the arrow does not touch the popover's rounded corners | |||
&::before { | |||
right: 0; | |||
border-width: ($popover-arrow-width / 2) 0 ($popover-arrow-width / 2) $popover-arrow-height; | |||
border-left-color: $popover-arrow-outer-color; | |||
} | |||
&::after { | |||
right: $popover-border-width; | |||
border-width: ($popover-arrow-width / 2) 0 ($popover-arrow-width / 2) $popover-arrow-height; | |||
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-header { | |||
padding: $popover-header-padding-y $popover-header-padding-x; | |||
margin-bottom: 0; // Reset the default from Reboot | |||
@include font-size($font-size-base); | |||
color: $popover-header-color; | |||
background-color: $popover-header-bg; | |||
border-bottom: $popover-border-width solid darken($popover-header-bg, 5%); | |||
@include border-top-radius($popover-inner-border-radius); | |||
&:empty { | |||
display: none; | |||
} | |||
} | |||
.popover-body { | |||
padding: $popover-body-padding-y $popover-body-padding-x; | |||
color: $popover-body-color; | |||
} |
@ -0,0 +1,141 @@ | |||
// stylelint-disable declaration-no-important, selector-no-qualifying-type | |||
// Source: https://github.com/h5bp/main.css/blob/master/src/_print.css | |||
// ========================================================================== | |||
// Print styles. | |||
// Inlined to avoid the additional HTTP request: | |||
// https://www.phpied.com/delay-loading-your-print-css/ | |||
// ========================================================================== | |||
@if $enable-print-styles { | |||
@media print { | |||
*, | |||
*::before, | |||
*::after { | |||
// Bootstrap specific; comment out `color` and `background` | |||
//color: $black !important; // Black prints faster | |||
text-shadow: none !important; | |||
//background: transparent !important; | |||
box-shadow: none !important; | |||
} | |||
a { | |||
&:not(.btn) { | |||
text-decoration: underline; | |||
} | |||
} | |||
// Bootstrap specific; comment the following selector out | |||
//a[href]::after { | |||
// content: " (" attr(href) ")"; | |||
//} | |||
abbr[title]::after { | |||
content: " (" attr(title) ")"; | |||
} | |||
// Bootstrap specific; comment the following selector out | |||
// | |||
// Don't show links that are fragment identifiers, | |||
// or use the `javascript:` pseudo protocol | |||
// | |||
//a[href^="#"]::after, | |||
//a[href^="javascript:"]::after { | |||
// content: ""; | |||
//} | |||
pre { | |||
white-space: pre-wrap !important; | |||
} | |||
pre, | |||
blockquote { | |||
border: $border-width solid $gray-500; // Bootstrap custom code; using `$border-width` instead of 1px | |||
page-break-inside: avoid; | |||
} | |||
// | |||
// Printing Tables: | |||
// https://web.archive.org/web/20180815150934/http://css-discuss.incutio.com/wiki/Printing_Tables | |||
// | |||
thead { | |||
display: table-header-group; | |||
} | |||
tr, | |||
img { | |||
page-break-inside: avoid; | |||
} | |||
p, | |||
h2, | |||
h3 { | |||
orphans: 3; | |||
widows: 3; | |||
} | |||
h2, | |||
h3 { | |||
page-break-after: avoid; | |||
} | |||
// Bootstrap specific changes start | |||
// Specify a size and min-width to make printing closer across browsers. | |||
// We don't set margin here because it breaks `size` in Chrome. We also | |||
// don't use `!important` on `size` as it breaks in Chrome. | |||
@page { | |||
size: $print-page-size; | |||
} | |||
body { | |||
min-width: $print-body-min-width !important; | |||
} | |||
.container { | |||
min-width: $print-body-min-width !important; | |||
} | |||
// Bootstrap components | |||
.navbar { | |||
display: none; | |||
} | |||
.badge { | |||
border: $border-width solid $black; | |||
} | |||
.table { | |||
border-collapse: collapse !important; | |||
td, | |||
th { | |||
background-color: $white !important; | |||
} | |||
} | |||
.table-bordered { | |||
th, | |||
td { | |||
border: 1px solid $gray-300 !important; | |||
} | |||
} | |||
.table-dark { | |||
color: inherit; | |||
th, | |||
td, | |||
thead th, | |||
tbody + tbody { | |||
border-color: $table-border-color; | |||
} | |||
} | |||
.table .thead-dark th { | |||
color: inherit; | |||
border-color: $table-border-color; | |||
} | |||
// Bootstrap specific changes end | |||
} | |||
} |
@ -0,0 +1,46 @@ | |||
// Disable animation if transitions are disabled | |||
@if $enable-transitions { | |||
@keyframes progress-bar-stripes { | |||
from { background-position: $progress-height 0; } | |||
to { background-position: 0 0; } | |||
} | |||
} | |||
.progress { | |||
display: flex; | |||
height: $progress-height; | |||
overflow: hidden; // force rounded corners by cropping it | |||
@include font-size($progress-font-size); | |||
background-color: $progress-bg; | |||
@include border-radius($progress-border-radius); | |||
@include box-shadow($progress-box-shadow); | |||
} | |||
.progress-bar { | |||
display: flex; | |||
flex-direction: column; | |||
justify-content: center; | |||
overflow: hidden; | |||
color: $progress-bar-color; | |||
text-align: center; | |||
white-space: nowrap; | |||
background-color: $progress-bar-bg; | |||
@include transition($progress-bar-transition); | |||
} | |||
.progress-bar-striped { | |||
@include gradient-striped(); | |||
background-size: $progress-height $progress-height; | |||
} | |||
@if $enable-transitions { | |||
.progress-bar-animated { | |||
animation: progress-bar-stripes $progress-bar-animation-timing; | |||
@if $enable-prefers-reduced-motion-media-query { | |||
@media (prefers-reduced-motion: reduce) { | |||
animation: none; | |||
} | |||
} | |||
} | |||
} |
@ -0,0 +1,482 @@ | |||
// stylelint-disable at-rule-no-vendor-prefix, declaration-no-important, selector-no-qualifying-type, property-no-vendor-prefix | |||
// Reboot | |||
// | |||
// 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 | |||
// Document | |||
// | |||
// 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. Change the default tap highlight to be completely transparent in iOS. | |||
*, | |||
*::before, | |||
*::after { | |||
box-sizing: border-box; // 1 | |||
} | |||
html { | |||
font-family: sans-serif; // 2 | |||
line-height: 1.15; // 3 | |||
-webkit-text-size-adjust: 100%; // 4 | |||
-webkit-tap-highlight-color: rgba($black, 0); // 5 | |||
} | |||
// Shim for "new" HTML5 structural elements to display correctly (IE10, older browsers) | |||
// TODO: remove in v5 | |||
// stylelint-disable-next-line selector-list-comma-newline-after | |||
article, aside, 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 `inherit` value on things like `<th>` elements. | |||
body { | |||
margin: 0; // 1 | |||
font-family: $font-family-base; | |||
@include font-size($font-size-base); | |||
font-weight: $font-weight-base; | |||
line-height: $line-height-base; | |||
color: $body-color; | |||
text-align: left; // 3 | |||
background-color: $body-bg; // 2 | |||
} | |||
// Future-proof rule: in browsers that support :focus-visible, suppress the focus outline | |||
// on elements that programmatically receive focus but wouldn't normally show a visible | |||
// focus outline. In general, this would mean that the outline is only applied if the | |||
// interaction that led to the element receiving programmatic focus was a keyboard interaction, | |||
// or the browser has somehow determined that the user is primarily a keyboard user and/or | |||
// wants focus outlines to always be presented. | |||
// | |||
// See https://developer.mozilla.org/en-US/docs/Web/CSS/:focus-visible | |||
// and https://developer.paciellogroup.com/blog/2018/03/focus-visible-and-backwards-compatibility/ | |||
[tabindex="-1"]:focus:not(:focus-visible) { | |||
outline: 0 !important; | |||
} | |||
// 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 | |||
// | |||
// Remove top margins from headings | |||
// | |||
// By default, `<h1>`-`<h6>` all receive top and bottom margins. We nuke the top | |||
// margin for easier control within type scales as it avoids margin collapsing. | |||
// stylelint-disable-next-line selector-list-comma-newline-after | |||
h1, h2, h3, h4, h5, h6 { | |||
margin-top: 0; | |||
margin-bottom: $headings-margin-bottom; | |||
} | |||
// Reset margins on paragraphs | |||
// | |||
// Similarly, the top margin on `<p>`s get reset. However, we also reset the | |||
// bottom margin to use `rem` units instead of `em`. | |||
p { | |||
margin-top: 0; | |||
margin-bottom: $paragraph-margin-bottom; | |||
} | |||
// Abbreviations | |||
// | |||
// 1. Duplicate behavior to the data-* attribute for our tooltip plugin | |||
// 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari. | |||
// 3. Add explicit cursor to indicate changed behavior. | |||
// 4. Remove the bottom border in Firefox 39-. | |||
// 5. Prevent the text-decoration to be skipped. | |||
abbr[title], | |||
abbr[data-original-title] { // 1 | |||
text-decoration: underline; // 2 | |||
text-decoration: underline dotted; // 2 | |||
cursor: help; // 3 | |||
border-bottom: 0; // 4 | |||
text-decoration-skip-ink: none; // 5 | |||
} | |||
address { | |||
margin-bottom: 1rem; | |||
font-style: normal; | |||
line-height: inherit; | |||
} | |||
ol, | |||
ul, | |||
dl { | |||
margin-top: 0; | |||
margin-bottom: 1rem; | |||
} | |||
ol ol, | |||
ul ul, | |||
ol ul, | |||
ul ol { | |||
margin-bottom: 0; | |||
} | |||
dt { | |||
font-weight: $dt-font-weight; | |||
} | |||
dd { | |||
margin-bottom: .5rem; | |||
margin-left: 0; // Undo browser default | |||
} | |||
blockquote { | |||
margin: 0 0 1rem; | |||
} | |||
b, | |||
strong { | |||
font-weight: $font-weight-bolder; // Add the correct font weight in Chrome, Edge, and Safari | |||
} | |||
small { | |||
@include 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; | |||
@include font-size(75%); | |||
line-height: 0; | |||
vertical-align: baseline; | |||
} | |||
sub { bottom: -.25em; } | |||
sup { top: -.5em; } | |||
// | |||
// Links | |||
// | |||
a { | |||
color: $link-color; | |||
text-decoration: $link-decoration; | |||
background-color: transparent; // Remove the gray background on active links in IE 10. | |||
@include hover() { | |||
color: $link-hover-color; | |||
text-decoration: $link-hover-decoration; | |||
} | |||
} | |||
// And undo these styles for placeholder links/named anchors (without href). | |||
// It would be more straightforward to just use a[href] in previous block, but that | |||
// causes specificity issues in many other styles that are too complex to fix. | |||
// See https://github.com/twbs/bootstrap/issues/19402 | |||
a:not([href]) { | |||
color: inherit; | |||
text-decoration: none; | |||
@include hover() { | |||
color: inherit; | |||
text-decoration: none; | |||
} | |||
} | |||
// | |||
// Code | |||
// | |||
pre, | |||
code, | |||
kbd, | |||
samp { | |||
font-family: $font-family-monospace; | |||
@include 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; | |||
// Don't allow content to break outside | |||
overflow: auto; | |||
} | |||
// | |||
// Figures | |||
// | |||
figure { | |||
// Apply a consistent margin strategy (matches our type styles). | |||
margin: 0 0 1rem; | |||
} | |||
// | |||
// Images and content | |||
// | |||
img { | |||
vertical-align: middle; | |||
border-style: none; // Remove the border on images inside links in IE 10-. | |||
} | |||
svg { | |||
// Workaround for the SVG overflow bug in IE10/11 is still required. | |||
// See https://github.com/twbs/bootstrap/issues/26878 | |||
overflow: hidden; | |||
vertical-align: middle; | |||
} | |||
// | |||
// Tables | |||
// | |||
table { | |||
border-collapse: collapse; // Prevent double borders | |||
} | |||
caption { | |||
padding-top: $table-cell-padding; | |||
padding-bottom: $table-cell-padding; | |||
color: $table-caption-color; | |||
text-align: left; | |||
caption-side: bottom; | |||
} | |||
th { | |||
// Matches default `<td>` alignment by inheriting from the `<body>`, or the | |||
// closest parent with a set `text-align`. | |||
text-align: inherit; | |||
} | |||
// | |||
// Forms | |||
// | |||
label { | |||
// Allow labels to use `margin` for spacing. | |||
display: inline-block; | |||
margin-bottom: $label-margin-bottom; | |||
} | |||
// Remove the default `border-radius` that macOS Chrome adds. | |||
// | |||
// Details at https://github.com/twbs/bootstrap/issues/24093 | |||
button { | |||
// stylelint-disable-next-line property-blacklist | |||
border-radius: 0; | |||
} | |||
// Work around a Firefox/IE bug where the transparent `button` background | |||
// results in a loss of the default `button` focus styles. | |||
// | |||
// Credit: https://github.com/suitcss/base/ | |||
button:focus { | |||
outline: 1px dotted; | |||
outline: 5px auto -webkit-focus-ring-color; | |||
} | |||
input, | |||
button, | |||
select, | |||
optgroup, | |||
textarea { | |||
margin: 0; // Remove the margin in Firefox and Safari | |||
font-family: inherit; | |||
@include 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 | |||
} | |||
// Remove the inheritance of word-wrap in Safari. | |||
// | |||
// Details at https://github.com/twbs/bootstrap/issues/24990 | |||
select { | |||
word-wrap: normal; | |||
} | |||
// 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, | |||
[type="button"], // 1 | |||
[type="reset"], | |||
[type="submit"] { | |||
-webkit-appearance: button; // 2 | |||
} | |||
// Opinionated: add "hand" cursor to non-disabled button elements. | |||
@if $enable-pointer-cursor-for-buttons { | |||
button, | |||
[type="button"], | |||
[type="reset"], | |||
[type="submit"] { | |||
&:not(:disabled) { | |||
cursor: pointer; | |||
} | |||
} | |||
} | |||
// 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"] { | |||
box-sizing: border-box; // 1. Add the correct box sizing in IE 10- | |||
padding: 0; // 2. Remove the padding in IE 10- | |||
} | |||
input[type="date"], | |||
input[type="time"], | |||
input[type="datetime-local"], | |||
input[type="month"] { | |||
// Remove the default appearance of temporal inputs to avoid a Mobile Safari | |||
// bug where setting a custom line-height prevents text from being vertically | |||
// centered within the input. | |||
// See https://bugs.webkit.org/show_bug.cgi?id=139848 | |||
// and https://github.com/twbs/bootstrap/issues/11266 | |||
-webkit-appearance: listbox; | |||
} | |||
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; | |||
} | |||
fieldset { | |||
// Browsers set a default `min-width: min-content;` on fieldsets, | |||
// unlike e.g. `<div>`s, which have `min-width: 0;` by default. | |||
// So we reset that to ensure fieldsets behave more like a standard block element. | |||
// See https://github.com/twbs/bootstrap/issues/12359 | |||
// and https://html.spec.whatwg.org/multipage/#the-fieldset-and-legend-elements | |||
min-width: 0; | |||
// Reset the default outline behavior of fieldsets so they don't affect page layout. | |||
padding: 0; | |||
margin: 0; | |||
border: 0; | |||
} | |||
// 1. Correct the text wrapping in Edge and IE. | |||
// 2. Correct the color inheritance from `fieldset` elements in IE. | |||
legend { | |||
display: block; | |||
width: 100%; | |||
max-width: 100%; // 1 | |||
padding: 0; | |||
margin-bottom: .5rem; | |||
@include font-size(1.5rem); | |||
line-height: inherit; | |||
color: inherit; // 2 | |||
white-space: normal; // 1 | |||
} | |||
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; | |||
} | |||
// | |||
// Remove the inner padding in Chrome and Safari on macOS. | |||
// | |||
[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; | |||
} | |||
summary { | |||
display: list-item; // Add the correct display in all browsers | |||
cursor: pointer; | |||
} | |||
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; | |||
} |