0
0
mirror of https://github.com/twbs/bootstrap.git synced 2024-11-29 11:24:18 +01:00

Merge branch 'master' into equal-height-experiment

This commit is contained in:
Mark Otto 2014-04-08 20:51:56 -07:00
commit 11a835f566
62 changed files with 523 additions and 331 deletions

View File

@ -4,14 +4,15 @@ node_js:
before_install:
- time sudo pip install --use-mirrors -r test-infra/requirements.txt
- rvm use 1.9.3 --fuzzy
- if [ "$TWBS_TEST" = validate-html ]; then echo "ruby=$(basename $(rvm gemdir)) jekyll=$JEKYLL_VERSION" > pseudo_Gemfile.lock; fi
- export GEMDIR=$(rvm gemdir)
- if [ "$TWBS_TEST" = validate-html ]; then echo "ruby=$(basename $GEMDIR) jekyll=$JEKYLL_VERSION" > pseudo_Gemfile.lock; fi
install:
- time npm install -g grunt-cli
- time ./test-infra/s3_cache.py download 'npm packages' test-infra/npm-shrinkwrap.canonical.json ./node_modules || time ./test-infra/uncached-npm-install.sh
- if [ "$TWBS_TEST" = validate-html ]; then time ./test-infra/s3_cache.py download rubygems pseudo_Gemfile.lock $(rvm gemdir) || gem install -N jekyll -v $JEKYLL_VERSION; fi
- ./test-infra/s3_cache.py download npm-modules
- if [ "$TWBS_TEST" = validate-html ]; then ./test-infra/s3_cache.py download rubygems; fi
after_script:
- if [ "$TWBS_TEST" = core ]; then time ./test-infra/s3_cache.py upload 'npm packages' test-infra/npm-shrinkwrap.canonical.json ./node_modules; fi
- if [ "$TWBS_TEST" = validate-html ]; then time ./test-infra/s3_cache.py upload rubygems pseudo_Gemfile.lock $(rvm gemdir); fi
- if [ "$TWBS_TEST" = core ]; then ./test-infra/s3_cache.py upload npm-modules; fi
- if [ "$TWBS_TEST" = validate-html ]; then ./test-infra/s3_cache.py upload rubygems; fi
env:
global:
- JEKYLL_VERSION: 1.5.0

View File

@ -78,6 +78,9 @@ module.exports = function (grunt) {
src: '<%= jshint.test.src %>'
},
assets: {
options: {
requireCamelCaseOrUpperCaseIdentifiers: null
},
src: '<%= jshint.assets.src %>'
}
},

View File

@ -1,4 +1,4 @@
# [Bootstrap](http://getbootstrap.com) [![Bower version](https://badge.fury.io/bo/bootstrap.png)](http://badge.fury.io/bo/bootstrap) [![Build Status](https://secure.travis-ci.org/twbs/bootstrap.png)](http://travis-ci.org/twbs/bootstrap) [![devDependency Status](https://david-dm.org/twbs/bootstrap/dev-status.png?theme=shields.io)](https://david-dm.org/twbs/bootstrap#info=devDependencies)
# [Bootstrap](http://getbootstrap.com) [![Bower version](https://badge.fury.io/bo/bootstrap.svg)](http://badge.fury.io/bo/bootstrap) [![Build Status](https://secure.travis-ci.org/twbs/bootstrap.svg)](http://travis-ci.org/twbs/bootstrap) [![devDependency Status](https://david-dm.org/twbs/bootstrap/dev-status.svg?theme=.io)](https://david-dm.org/twbs/bootstrap#info=devDependencies)
[![Selenium Test Status](https://saucelabs.com/browser-matrix/bootstrap.svg)](https://saucelabs.com/u/bootstrap)
Bootstrap is a sleek, intuitive, and powerful front-end framework for faster and easier web development, created by [Mark Otto](http://twitter.com/mdo) and [Jacob Thornton](http://twitter.com/fat), and maintained by the [core team](https://github.com/twbs?tab=members) with the massive support and involvement of the community.

View File

@ -4,7 +4,7 @@
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
*/
/*! normalize.css v3.0.0 | MIT License | git.io/normalize */
/*! normalize.css v3.0.1 | MIT License | git.io/normalize */
html {
font-family: sans-serif;
@ -6684,7 +6684,7 @@ button.close {
.tooltip {
position: absolute;
z-index: 1030;
z-index: 1070;
display: block;
font-size: 12px;
line-height: 1.4;
@ -6800,7 +6800,7 @@ button.close {
position: absolute;
top: 0;
right: 0;
z-index: 1010;
z-index: 1060;
display: none;
max-width: 276px;
padding: 1px;
@ -7053,11 +7053,13 @@ button.close {
.carousel-control .icon-prev,
.carousel-control .glyphicon-chevron-left {
right: 50%;
margin-right: -10px;
}
.carousel-control .icon-next,
.carousel-control .glyphicon-chevron-right {
left: 50%;
margin-left: -10px;
}
.carousel-control .icon-prev,
@ -7065,7 +7067,6 @@ button.close {
width: 20px;
height: 20px;
margin-top: -10px;
margin-right: -10px;
font-family: serif;
}
@ -7134,10 +7135,19 @@ button.close {
width: 30px;
height: 30px;
margin-top: -15px;
margin-right: -15px;
font-size: 30px;
}
.carousel-control .glyphicon-chevron-left,
.carousel-control .icon-prev {
margin-right: -15px;
}
.carousel-control .glyphicon-chevron-right,
.carousel-control .icon-next {
margin-left: -15px;
}
.carousel-caption {
right: 20%;
left: 20%;

File diff suppressed because one or more lines are too long

View File

@ -4,7 +4,7 @@
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
*/
/*! normalize.css v3.0.0 | MIT License | git.io/normalize */
/*! normalize.css v3.0.1 | MIT License | git.io/normalize */
html {
font-family: sans-serif;
-webkit-text-size-adjust: 100%;
@ -5399,7 +5399,7 @@ button.close {
}
.tooltip {
position: absolute;
z-index: 1030;
z-index: 1070;
display: block;
font-size: 12px;
line-height: 1.4;
@ -5499,7 +5499,7 @@ button.close {
position: absolute;
top: 0;
left: 0;
z-index: 1010;
z-index: 1060;
display: none;
max-width: 276px;
padding: 1px;
@ -5717,17 +5717,18 @@ button.close {
.carousel-control .icon-prev,
.carousel-control .glyphicon-chevron-left {
left: 50%;
margin-left: -10px;
}
.carousel-control .icon-next,
.carousel-control .glyphicon-chevron-right {
right: 50%;
margin-right: -10px;
}
.carousel-control .icon-prev,
.carousel-control .icon-next {
width: 20px;
height: 20px;
margin-top: -10px;
margin-left: -10px;
font-family: serif;
}
.carousel-control .icon-prev:before {
@ -5788,9 +5789,16 @@ button.close {
width: 30px;
height: 30px;
margin-top: -15px;
margin-left: -15px;
font-size: 30px;
}
.carousel-control .glyphicon-chevron-left,
.carousel-control .icon-prev {
margin-left: -15px;
}
.carousel-control .glyphicon-chevron-right,
.carousel-control .icon-next {
margin-right: -15px;
}
.carousel-caption {
right: 20%;
left: 20%;

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

44
dist/js/bootstrap.js vendored
View File

@ -313,7 +313,7 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
if (pos > (this.$items.length - 1) || pos < 0) return
if (this.sliding) return this.$element.one('slid.bs.carousel', function () { that.to(pos) })
if (this.sliding) return this.$element.one('slid.bs.carousel', function () { that.to(pos) }) // yes, "slid". not a typo. past tense of "to slide".
if (activeIndex == pos) return this.pause().cycle()
return this.slide(pos > activeIndex ? 'next' : 'prev', $(this.$items[pos]))
@ -367,7 +367,7 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
if (this.$indicators.length) {
this.$indicators.find('.active').removeClass('active')
this.$element.one('slid.bs.carousel', function () {
this.$element.one('slid.bs.carousel', function () { // yes, "slid". not a typo. past tense of "to slide".
var $nextIndicator = $(that.$indicators.children()[that.getActiveIndex()])
$nextIndicator && $nextIndicator.addClass('active')
})
@ -383,14 +383,14 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
$next.removeClass([type, direction].join(' ')).addClass('active')
$active.removeClass(['active', direction].join(' '))
that.sliding = false
setTimeout(function () { that.$element.trigger('slid.bs.carousel') }, 0)
setTimeout(function () { that.$element.trigger('slid.bs.carousel') }, 0) // yes, "slid". not a typo. past tense of "to slide".
})
.emulateTransitionEnd($active.css('transition-duration').slice(0, -1) * 1000)
} else {
$active.removeClass('active')
$next.addClass('active')
this.sliding = false
this.$element.trigger('slid.bs.carousel')
this.$element.trigger('slid.bs.carousel') // yes, "slid". not a typo. past tense of "to slide".
}
isCycling && this.cycle()
@ -511,8 +511,7 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
this.$element
.removeClass('collapse')
.addClass('collapsing')
[dimension](0)
.addClass('collapsing')[dimension](0)
this.transitioning = 1
@ -520,8 +519,7 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
if (e && e.target != this.$element[0]) return
this.$element
.removeClass('collapsing')
.addClass('collapse in')
[dimension]('auto')
.addClass('collapse in')[dimension]('auto')
this.transitioning = 0
this.$element.trigger('shown.bs.collapse')
}
@ -532,8 +530,7 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
this.$element
.one($.support.transition.end, $.proxy(complete, this))
.emulateTransitionEnd(350)
[dimension](this.$element[0][scrollSize])
.emulateTransitionEnd(350)[dimension](this.$element[0][scrollSize])
}
Collapse.prototype.hide = function () {
@ -545,9 +542,7 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
var dimension = this.dimension()
this.$element
[dimension](this.$element[dimension]())
[0].offsetHeight
this.$element[dimension](this.$element[dimension]())[0].offsetHeight
this.$element
.addClass('collapsing')
@ -795,11 +790,12 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
// ======================
var Modal = function (element, options) {
this.options = options
this.$body = $(document.body)
this.$element = $(element)
this.$backdrop =
this.isShown = null
this.options = options
this.$body = $(document.body)
this.$element = $(element)
this.$backdrop =
this.isShown = null
this.scrollbarWidth = 0
if (this.options.remote) {
this.$element
@ -830,6 +826,7 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
this.isShown = true
this.checkScrollbar()
this.$body.addClass('modal-open')
this.setScrollbar()
@ -976,11 +973,14 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
}
}
Modal.prototype.checkScrollbar = function () {
if (document.body.clientWidth >= window.innerWidth) return
this.scrollbarWidth = this.scrollbarWidth || this.measureScrollbar()
}
Modal.prototype.setScrollbar = function () {
if (document.body.clientHeight <= window.innerHeight) return
var scrollbarWidth = this.measureScrollbar()
var bodyPad = parseInt(this.$body.css('padding-right') || 0)
if (scrollbarWidth) this.$body.css('padding-right', bodyPad + scrollbarWidth)
var bodyPad = parseInt(this.$body.css('padding-right') || 0)
if (this.scrollbarWidth) this.$body.css('padding-right', bodyPad + this.scrollbarWidth)
}
Modal.prototype.resetScrollbar = function () {

File diff suppressed because one or more lines are too long

View File

@ -13,6 +13,11 @@
description: Bootstrap auf Deutsch
url: http://holdirbootstrap.de/
- name: Italian
code: it
description: Bootstrap in Italiano
url: http://www.hackerstribe.com/guide/IT-bootstrap-3.1.1/
- name: Korean
code: ko
description: Bootstrap 한국어

View File

@ -21,6 +21,10 @@
<h4>Don't mix with other components</h4>
<p>Icon classes cannot be directly combined with other components. They should not be used along with other classes on the same element. Instead, add a nested <code>&lt;span&gt;</code> and apply the icon classes to the <code>&lt;span&gt;</code>.</p>
</div>
<div class="bs-callout bs-callout-danger">
<h4>Only for use on empty elements</h4>
<p>Icon classes should only be used on elements that contain no text content and have no child elements.</p>
</div>
{% highlight html %}
<span class="glyphicon glyphicon-search"></span>
{% endhighlight %}

View File

@ -17,6 +17,10 @@
<h4>Requires JavaScript</h4>
<p>If JavaScript is disabled and the viewport is narrow enough that the navbar collapses, it will be impossible to expand the navbar and view the content within the <code>.navbar-collapse</code>.</p>
</div>
<div class="bs-callout bs-callout-info">
<h4>Changing the collapsed mobile navbar breakpoint</h4>
<p>The navbar collapses into its vertical mobile view when the viewport is narrower than <code>@grid-float-breakpoint</code>, and expands into its horizontal non-mobile view when the viewport is at least <code>@grid-float-breakpoint</code> in width. Adjust this variable in the Less source to control when the navbar collapses/expands. The default value is <code>768px</code> (the smallest "small" or "tablet" screen).</p>
</div>
<div class="bs-example">
<nav class="navbar navbar-default" role="navigation">
@ -38,7 +42,7 @@
<li class="active"><a href="#">Link</a></li>
<li><a href="#">Link</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Dropdown <b class="caret"></b></a>
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Dropdown <span class="caret"></span></a>
<ul class="dropdown-menu" role="menu">
<li><a href="#">Action</a></li>
<li><a href="#">Another action</a></li>
@ -59,7 +63,7 @@
<ul class="nav navbar-nav navbar-right">
<li><a href="#">Link</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Dropdown <b class="caret"></b></a>
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Dropdown <span class="caret"></span></a>
<ul class="dropdown-menu" role="menu">
<li><a href="#">Action</a></li>
<li><a href="#">Another action</a></li>
@ -93,7 +97,7 @@
<li class="active"><a href="#">Link</a></li>
<li><a href="#">Link</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Dropdown <b class="caret"></b></a>
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Dropdown <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="#">Action</a></li>
<li><a href="#">Another action</a></li>
@ -114,7 +118,7 @@
<ul class="nav navbar-nav navbar-right">
<li><a href="#">Link</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Dropdown <b class="caret"></b></a>
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Dropdown <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="#">Action</a></li>
<li><a href="#">Another action</a></li>

View File

@ -348,7 +348,7 @@
<h2 id="tables-responsive">Responsive tables</h2>
<p>Create responsive tables by wrapping any <code>.table</code> in <code>.table-responsive</code> to make them scroll horizontally up to small devices (under 768px). When viewing on anything larger than 768px wide, you will not see any difference in these tables.</p>
<p>Create responsive tables by wrapping any <code>.table</code> in <code>.table-responsive</code> to make them scroll horizontally on small devices (under 768px). When viewing on anything larger than 768px wide, you will not see any difference in these tables.</p>
<div class="bs-example">
<div class="table-responsive">
<table class="table">

View File

@ -146,10 +146,10 @@ You can use the mark tag to <mark>highlight</mark> text.
<h3>Underlined text</h3>
<p>To underline text use the <code>&lt;u&gt;</code> tag.</p>
<div class="bs-example">
<p><u>This line of text is will render as underlined</u></p>
<p><u>This line of text will render as underlined</u></p>
</div>
{% highlight html %}
<u>This line of text is will render as underlined</u>
<u>This line of text will render as underlined</u>
{% endhighlight %}
<p>Make use of HTML's default emphasis tags with lightweight styles.</p>

View File

@ -176,11 +176,13 @@ if (navigator.userAgent.match(/IEMobile\/10\.0/)) {
<p>On <code>&lt;select&gt;</code> elements, the Android stock browser will not display the side controls if there is a <code>border-radius</code> and/or <code>border</code> applied. Use the snippet of code below to remove the offending CSS and render the <code>&lt;select&gt;</code> as an unstyled element on the Android stock browser. The user agent sniffing avoids interference with Chrome, Safari, and Mozilla browsers.</p>
{% highlight html %}
<script>
var nua = navigator.userAgent
var isAndroid = (nua.indexOf('Mozilla/5.0') > -1 && nua.indexOf('Android ') > -1 && nua.indexOf('AppleWebKit') > -1 && nua.indexOf('Chrome') === -1)
if (isAndroid) {
$('select.form-control').removeClass('form-control').css('width', '100%')
}
$(function () {
var nua = navigator.userAgent
var isAndroid = (nua.indexOf('Mozilla/5.0') > -1 && nua.indexOf('Android ') > -1 && nua.indexOf('AppleWebKit') > -1 && nua.indexOf('Chrome') === -1)
if (isAndroid) {
$('select.form-control').removeClass('form-control').css('width', '100%')
}
})
</script>
{% endhighlight %}
<p>Want to see an example? <a href="http://jsbin.com/OyaqoDO/2">Check out this JS Bin demo.</a></p>

View File

@ -8,21 +8,21 @@
<h3 id="download-bootstrap">Bootstrap</h3>
<p>Compiled and minified CSS, JavaScript, and fonts. No docs or original source files are included.</p>
<p>
<a href="{{ site.download.dist }}" class="btn btn-lg btn-outline" role="button" onclick="_gaq.push(['_trackEvent', 'Getting started', 'Download', 'Download compiled']);">Download Bootstrap</a>
<a href="{{ site.download.dist }}" class="btn btn-lg btn-outline" role="button" onclick="ga('send', 'event', 'Getting started', 'Download', 'Download compiled');">Download Bootstrap</a>
</p>
</div>
<div class="col-sm-4">
<h3 id="download-source">Source code</h3>
<p>Source Less, JavaScript, and font files, along with our docs. <strong>Requires a Less compiler and <a href="{{ site.repo }}#compiling-css-and-javascript">some setup.</a></strong></p>
<p>
<a href="{{ site.download.source }}" class="btn btn-lg btn-outline" role="button" onclick="_gaq.push(['_trackEvent', 'Getting started', 'Download', 'Download source']);">Download source</a>
<a href="{{ site.download.source }}" class="btn btn-lg btn-outline" role="button" onclick="ga('send', 'event', 'Getting started', 'Download', 'Download source');">Download source</a>
</p>
</div>
<div class="col-sm-4">
<h3 id="download-sass">Sass</h3>
<p><a href="{{ site.sass_repo }}">Bootstrap ported from Less to Sass</a> for easy inclusion in Rails, Compass, or Sass-only projects.</p>
<p>
<a href="{{ site.download.sass }}" class="btn btn-lg btn-outline" role="button" onclick="_gaq.push(['_trackEvent', 'Getting started', 'Download', 'Download Sass']);">Download Sass</a>
<a href="{{ site.download.sass }}" class="btn btn-lg btn-outline" role="button" onclick="ga('send', 'event', 'Getting started', 'Download', 'Download Sass');">Download Sass</a>
</p>
</div>
</div>

View File

@ -35,6 +35,8 @@
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-146052-10', 'getbootstrap.com');
ga('send', 'pageview');
</script>

View File

@ -64,7 +64,7 @@
</table>
</div><!-- /.table-responsive -->
{% highlight js %}
$('#my-alert').bind('closed.bs.alert', function () {
$('#my-alert').on('closed.bs.alert', function () {
// do something…
})
{% endhighlight %}

View File

@ -37,10 +37,14 @@
<h4>Checkbox</h4>
<p>Add <code>data-toggle="buttons"</code> to a group of checkboxes for checkbox style toggling on btn-group.</p>
<div class="bs-callout bs-callout-warning">
<h4>Pre-checked options need <code>.active</code></h4>
<p>For pre-checked options, you must add the <code>.active</code> class to the input's <code>label</code> yourself.</p>
</div>
<div class="bs-example" style="padding-bottom: 24px;">
<div class="btn-group" data-toggle="buttons">
<label class="btn btn-primary">
<input type="checkbox"> Option 1
<label class="btn btn-primary active">
<input type="checkbox" checked> Option 1 (pre-checked)
</label>
<label class="btn btn-primary">
<input type="checkbox"> Option 2
@ -52,8 +56,8 @@
</div><!-- /example -->
{% highlight html %}
<div class="btn-group" data-toggle="buttons">
<label class="btn btn-primary">
<input type="checkbox"> Option 1
<label class="btn btn-primary active">
<input type="checkbox" checked> Option 1 (pre-checked)
</label>
<label class="btn btn-primary">
<input type="checkbox"> Option 2
@ -66,10 +70,14 @@
<h4>Radio</h4>
<p>Add <code>data-toggle="buttons"</code> to a group of radio inputs for radio style toggling on btn-group.</p>
<div class="bs-callout bs-callout-warning">
<h4>Preselected options need <code>.active</code></h4>
<p>For preselected options, you must add the <code>.active</code> class to the input's <code>label</code> yourself.</p>
</div>
<div class="bs-example" style="padding-bottom: 24px;">
<div class="btn-group" data-toggle="buttons">
<label class="btn btn-primary">
<input type="radio" name="options" id="option1"> Option 1
<label class="btn btn-primary active">
<input type="radio" name="options" id="option1" checked> Option 1 (preselected)
</label>
<label class="btn btn-primary">
<input type="radio" name="options" id="option2"> Option 2
@ -81,8 +89,8 @@
</div><!-- /example -->
{% highlight html %}
<div class="btn-group" data-toggle="buttons">
<label class="btn btn-primary">
<input type="radio" name="options" id="option1"> Option 1
<label class="btn btn-primary active">
<input type="radio" name="options" id="option1" checked> Option 1 (preselected)
</label>
<label class="btn btn-primary">
<input type="radio" name="options" id="option2"> Option 2

View File

@ -46,6 +46,12 @@
...
</div>
</div>
<div class="item">
<img src="..." alt="...">
<div class="carousel-caption">
...
</div>
</div>
...
</div>
@ -105,7 +111,7 @@
</div>
</div><!-- /example -->
{% highlight html %}
<div class="item active">
<div class="item">
<img src="..." alt="...">
<div class="carousel-caption">
<h3>...</h3>

View File

@ -20,7 +20,7 @@
<div class="collapse navbar-collapse bs-example-js-navbar-collapse">
<ul class="nav navbar-nav">
<li class="dropdown">
<a id="drop1" href="#" role="button" class="dropdown-toggle" data-toggle="dropdown">Dropdown <b class="caret"></b></a>
<a id="drop1" href="#" role="button" class="dropdown-toggle" data-toggle="dropdown">Dropdown <span class="caret"></span></a>
<ul class="dropdown-menu" role="menu" aria-labelledby="drop1">
<li role="presentation"><a role="menuitem" tabindex="-1" href="http://twitter.com/fat">Action</a></li>
<li role="presentation"><a role="menuitem" tabindex="-1" href="http://twitter.com/fat">Another action</a></li>
@ -30,7 +30,7 @@
</ul>
</li>
<li class="dropdown">
<a href="#" id="drop2" role="button" class="dropdown-toggle" data-toggle="dropdown">Dropdown 2 <b class="caret"></b></a>
<a href="#" id="drop2" role="button" class="dropdown-toggle" data-toggle="dropdown">Dropdown 2 <span class="caret"></span></a>
<ul class="dropdown-menu" role="menu" aria-labelledby="drop2">
<li role="presentation"><a role="menuitem" tabindex="-1" href="http://twitter.com/fat">Action</a></li>
<li role="presentation"><a role="menuitem" tabindex="-1" href="http://twitter.com/fat">Another action</a></li>
@ -42,7 +42,7 @@
</ul>
<ul class="nav navbar-nav navbar-right">
<li id="fat-menu" class="dropdown">
<a href="#" id="drop3" role="button" class="dropdown-toggle" data-toggle="dropdown">Dropdown 3 <b class="caret"></b></a>
<a href="#" id="drop3" role="button" class="dropdown-toggle" data-toggle="dropdown">Dropdown 3 <span class="caret"></span></a>
<ul class="dropdown-menu" role="menu" aria-labelledby="drop3">
<li role="presentation"><a role="menuitem" tabindex="-1" href="http://twitter.com/fat">Action</a></li>
<li role="presentation"><a role="menuitem" tabindex="-1" href="http://twitter.com/fat">Another action</a></li>
@ -62,7 +62,7 @@
<ul class="nav nav-pills">
<li class="active"><a href="#">Regular link</a></li>
<li class="dropdown">
<a id="drop4" role="button" data-toggle="dropdown" href="#">Dropdown <b class="caret"></b></a>
<a id="drop4" role="button" data-toggle="dropdown" href="#">Dropdown <span class="caret"></span></a>
<ul id="menu1" class="dropdown-menu" role="menu" aria-labelledby="drop4">
<li role="presentation"><a role="menuitem" tabindex="-1" href="http://twitter.com/fat">Action</a></li>
<li role="presentation"><a role="menuitem" tabindex="-1" href="http://twitter.com/fat">Another action</a></li>
@ -72,7 +72,7 @@
</ul>
</li>
<li class="dropdown">
<a id="drop5" role="button" data-toggle="dropdown" href="#">Dropdown 2 <b class="caret"></b></a>
<a id="drop5" role="button" data-toggle="dropdown" href="#">Dropdown 2 <span class="caret"></span></a>
<ul id="menu2" class="dropdown-menu" role="menu" aria-labelledby="drop5">
<li role="presentation"><a role="menuitem" tabindex="-1" href="http://twitter.com/fat">Action</a></li>
<li role="presentation"><a role="menuitem" tabindex="-1" href="http://twitter.com/fat">Another action</a></li>
@ -82,7 +82,7 @@
</ul>
</li>
<li class="dropdown">
<a id="drop6" role="button" data-toggle="dropdown" href="#">Dropdown 3 <b class="caret"></b></a>
<a id="drop6" role="button" data-toggle="dropdown" href="#">Dropdown 3 <span class="caret"></span></a>
<ul id="menu3" class="dropdown-menu" role="menu" aria-labelledby="drop6">
<li role="presentation"><a role="menuitem" tabindex="-1" href="http://twitter.com/fat">Action</a></li>
<li role="presentation"><a role="menuitem" tabindex="-1" href="http://twitter.com/fat">Another action</a></li>

View File

@ -193,7 +193,10 @@ $('.popover-dismiss').popover({
<td>content</td>
<td>string | function</td>
<td>''</td>
<td>Default content value if <code>data-content</code> attribute isn't present</td>
<td>
<p>Default content value if <code>data-content</code> attribute isn't present.</p>
<p>If a function is given, it will be called with 1 argument, which is the element that the popover is attached to.</p>
</td>
</tr>
<tr>
<td>delay</td>

View File

@ -20,7 +20,7 @@
<li><a href="#fat">@fat</a></li>
<li><a href="#mdo">@mdo</a></li>
<li class="dropdown">
<a href="#" id="navbarDrop1" class="dropdown-toggle" data-toggle="dropdown">Dropdown <b class="caret"></b></a>
<a href="#" id="navbarDrop1" class="dropdown-toggle" data-toggle="dropdown">Dropdown <span class="caret"></span></a>
<ul class="dropdown-menu" role="menu" aria-labelledby="navbarDrop1">
<li><a href="#one" tabindex="-1">one</a></li>
<li><a href="#two" tabindex="-1">two</a></li>

View File

@ -8,7 +8,7 @@
<li class="active"><a href="#home" data-toggle="tab">Home</a></li>
<li><a href="#profile" data-toggle="tab">Profile</a></li>
<li class="dropdown">
<a href="#" id="myTabDrop1" class="dropdown-toggle" data-toggle="dropdown">Dropdown <b class="caret"></b></a>
<a href="#" id="myTabDrop1" class="dropdown-toggle" data-toggle="dropdown">Dropdown <span class="caret"></span></a>
<ul class="dropdown-menu" role="menu" aria-labelledby="myTabDrop1">
<li><a href="#dropdown1" tabindex="-1" data-toggle="tab">@fat</a></li>
<li><a href="#dropdown2" tabindex="-1" data-toggle="tab">@mdo</a></li>

View File

@ -28,8 +28,8 @@
</li>
</ul>
<ul class="nav navbar-nav navbar-right">
<li><a href="{{ site.expo }}" onclick="_gaq.push(['_trackEvent', 'Navbar', 'Community links', 'Expo']);">Expo</a></li>
<li><a href="{{ site.blog }}" onclick="_gaq.push(['_trackEvent', 'Navbar', 'Community links', 'Blog']);">Blog</a></li>
<li><a href="{{ site.expo }}" onclick="ga('send', 'event', 'Navbar', 'Community links', 'Expo');">Expo</a></li>
<li><a href="{{ site.blog }}" onclick="ga('send', 'event', 'Navbar', 'Community links', 'Blog');">Blog</a></li>
</ul>
</nav>
</div>

View File

@ -43,7 +43,7 @@ window.onload = function () { // wait for load in a dumb way because B-0
return match && decodeURIComponent(match[1].replace(/\+/g, ' '))
}
function createGist(configJson) {
function createGist(configJson, callback) {
var data = {
description: 'Bootstrap Customizer Config',
'public': true,
@ -61,10 +61,18 @@ window.onload = function () { // wait for load in a dumb way because B-0
})
.success(function (result) {
var origin = window.location.protocol + '//' + window.location.host
history.replaceState(false, document.title, origin + window.location.pathname + '?id=' + result.id)
var newUrl = origin + window.location.pathname + '?id=' + result.id
history.replaceState(false, document.title, newUrl)
callback(result.html_url, newUrl)
})
.error(function (err) {
showError('<strong>Ruh roh!</strong> Could not save gist file, configuration not saved.', err)
try {
showError('<strong>Ruh roh!</strong> Could not save gist file, configuration not saved.', err)
}
catch (sameErr) {
// deliberately ignore the error
}
callback('<none>', '<none>')
})
}
@ -155,7 +163,7 @@ window.onload = function () { // wait for load in a dumb way because B-0
complete(content)
}
function generateCustomCSS(vars) {
function generateCustomLess(vars) {
var result = ''
for (var key in vars) {
@ -178,10 +186,20 @@ window.onload = function () { // wait for load in a dumb way because B-0
var IMPORT_REGEX = /^@import \"(.*?)\";$/
var lessLines = __less[lessFilename].split('\n')
for (var i = 0, imports = []; i < lessLines.length; i++) {
var match = IMPORT_REGEX.exec(lessLines[i])
if (match) imports.push(match[1])
}
var imports = []
$.each(lessLines, function (index, lessLine) {
var match = IMPORT_REGEX.exec(lessLine)
if (match) {
var importee = match[1]
var transitiveImports = includedLessFilenames(importee)
$.each(transitiveImports, function (index, transitiveImportee) {
if ($.inArray(transitiveImportee, imports) === -1) {
imports.push(transitiveImportee)
}
})
imports.push(importee)
}
})
return imports
}
@ -189,7 +207,8 @@ window.onload = function () { // wait for load in a dumb way because B-0
function generateLESS(lessFilename, lessFileIncludes, vars) {
var lessSource = __less[lessFilename]
$.each(includedLessFilenames(lessFilename), function(index, filename) {
var lessFilenames = includedLessFilenames(lessFilename)
$.each(lessFilenames, function(index, filename) {
var fileInclude = lessFileIncludes[filename]
// Files not explicitly unchecked are compiled into the final stylesheet.
@ -200,7 +219,7 @@ window.onload = function () { // wait for load in a dumb way because B-0
// Custom variables are added after Bootstrap variables so the custom
// ones take precedence.
if (('variables.less' === filename) && vars) lessSource += generateCustomCSS(vars)
if (('variables.less' === filename) && vars) lessSource += generateCustomLess(vars)
})
lessSource = lessSource.replace(/@import[^\n]*/gi, '') //strip any imports
@ -221,7 +240,7 @@ window.onload = function () { // wait for load in a dumb way because B-0
})
}
function generateCSS() {
function generateCSS(preamble) {
var oneChecked = false
var lessFileIncludes = {}
$('#less-section input').each(function() {
@ -242,8 +261,8 @@ window.onload = function () { // wait for load in a dumb way because B-0
$(this).val() && (vars[$(this).prev().text()] = $(this).val())
})
var bsLessSource = generateLESS('bootstrap.less', lessFileIncludes, vars)
var themeLessSource = generateLESS('theme.less', lessFileIncludes, vars)
var bsLessSource = preamble + generateLESS('bootstrap.less', lessFileIncludes, vars)
var themeLessSource = preamble + generateLESS('theme.less', lessFileIncludes, vars)
try {
compileLESS(bsLessSource, 'bootstrap', result)
@ -255,7 +274,7 @@ window.onload = function () { // wait for load in a dumb way because B-0
return result
}
function generateJavascript() {
function generateJavascript(preamble) {
var $checked = $('#plugin-section input:checked')
if (!$checked.length) return false
@ -265,8 +284,8 @@ window.onload = function () { // wait for load in a dumb way because B-0
.join('\n')
return {
'bootstrap.js': js,
'bootstrap.min.js': cw + uglify(js)
'bootstrap.js': preamble + js,
'bootstrap.min.js': preamble + cw + uglify(js)
}
}
@ -322,10 +341,19 @@ window.onload = function () { // wait for load in a dumb way because B-0
$compileBtn.attr('disabled', 'disabled')
generateZip(generateCSS(), generateJavascript(), generateFonts(), configJson, function (blob) {
$compileBtn.removeAttr('disabled')
saveAs(blob, 'bootstrap.zip')
createGist(configJson)
createGist(configJson, function (gistUrl, customizerUrl) {
configData.customizerUrl = customizerUrl
configJson = JSON.stringify(configData, null, 2)
var preamble = '/*!\n' +
' * Generated using the Bootstrap Customizer (' + customizerUrl + ')\n' +
' * Config saved to config.json and ' + gistUrl + '\n' +
' */\n'
generateZip(generateCSS(preamble), generateJavascript(preamble), generateFonts(), configJson, function (blob) {
$compileBtn.removeAttr('disabled')
saveAs(blob, 'bootstrap.zip')
})
})
});

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -356,7 +356,7 @@ lead: Customize Bootstrap's components, Less variables, and jQuery plugins to ge
<p class="lead">Hooray! Your custom version of Bootstrap is now ready to be compiled. Just click the button below to finish the process.</p>
<div class="bs-customize-download">
<button type="submit" id="btn-compile" disabled class="btn btn-block btn-lg btn-outline" onclick="_gaq.push(['_trackEvent', 'Customize', 'Download', 'Customize and Download']);">Compile and Download</button>
<button type="submit" id="btn-compile" disabled class="btn btn-block btn-lg btn-outline" onclick="ga('send', 'event', 'Customize', 'Download', 'Customize and Download');">Compile and Download</button>
</div>
</div><!-- /download -->
</form>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -48,7 +48,7 @@
<li><a href="#about">About</a></li>
<li><a href="#contact">Contact</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Dropdown <b class="caret"></b></a>
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Dropdown <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="#">Action</a></li>
<li><a href="#">Another action</a></li>

View File

@ -46,7 +46,7 @@
<li><a href="#about">About</a></li>
<li><a href="#contact">Contact</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Dropdown <b class="caret"></b></a>
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Dropdown <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="#">Action</a></li>
<li><a href="#">Another action</a></li>

View File

@ -46,7 +46,7 @@
<li><a href="#about">About</a></li>
<li><a href="#contact">Contact</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Dropdown <b class="caret"></b></a>
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Dropdown <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="#">Action</a></li>
<li><a href="#">Another action</a></li>

View File

@ -48,7 +48,7 @@
<li><a href="#">Link</a></li>
<li><a href="#">Link</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Dropdown <b class="caret"></b></a>
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Dropdown <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="#">Action</a></li>
<li><a href="#">Another action</a></li>

View File

@ -48,7 +48,7 @@
<li><a href="#about">About</a></li>
<li><a href="#contact">Contact</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Dropdown <b class="caret"></b></a>
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Dropdown <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="#">Action</a></li>
<li><a href="#">Another action</a></li>

View File

@ -46,7 +46,7 @@
<li><a href="#about">About</a></li>
<li><a href="#contact">Contact</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Dropdown <b class="caret"></b></a>
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Dropdown <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="#">Action</a></li>
<li><a href="#">Another action</a></li>
@ -343,7 +343,7 @@
<h1>Dropdown menus</h1>
</div>
<div class="dropdown theme-dropdown clearfix">
<a id="dropdownMenu1" href="#" role="button" class="sr-only dropdown-toggle" data-toggle="dropdown">Dropdown <b class="caret"></b></a>
<a id="dropdownMenu1" href="#" role="button" class="sr-only dropdown-toggle" data-toggle="dropdown">Dropdown <span class="caret"></span></a>
<ul class="dropdown-menu" role="menu" aria-labelledby="dropdownMenu1">
<li class="active" role="presentation"><a role="menuitem" tabindex="-1" href="#">Action</a></li>
<li role="presentation"><a role="menuitem" tabindex="-1" href="#">Another action</a></li>
@ -392,7 +392,7 @@
<li><a href="#about">About</a></li>
<li><a href="#contact">Contact</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Dropdown <b class="caret"></b></a>
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Dropdown <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="#">Action</a></li>
<li><a href="#">Another action</a></li>
@ -425,7 +425,7 @@
<li><a href="#about">About</a></li>
<li><a href="#contact">Contact</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Dropdown <b class="caret"></b></a>
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Dropdown <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="#">Action</a></li>
<li><a href="#">Another action</a></li>

View File

@ -46,7 +46,7 @@
<li><a href="#about">About</a></li>
<li><a href="#contact">Contact</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Dropdown <b class="caret"></b></a>
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Dropdown <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="#">Action</a></li>
<li><a href="#">Another action</a></li>

View File

@ -48,7 +48,7 @@
<li><a href="#about">About</a></li>
<li><a href="#contact">Contact</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Dropdown <b class="caret"></b></a>
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Dropdown <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="#">Action</a></li>
<li><a href="#">Another action</a></li>
@ -345,7 +345,7 @@
<h1>Dropdown menus</h1>
</div>
<div class="dropdown theme-dropdown clearfix">
<a id="dropdownMenu1" href="#" role="button" class="sr-only dropdown-toggle" data-toggle="dropdown">Dropdown <b class="caret"></b></a>
<a id="dropdownMenu1" href="#" role="button" class="sr-only dropdown-toggle" data-toggle="dropdown">Dropdown <span class="caret"></span></a>
<ul class="dropdown-menu" role="menu" aria-labelledby="dropdownMenu1">
<li class="active" role="presentation"><a role="menuitem" tabindex="-1" href="#">Action</a></li>
<li role="presentation"><a role="menuitem" tabindex="-1" href="#">Another action</a></li>
@ -394,7 +394,7 @@
<li><a href="#about">About</a></li>
<li><a href="#contact">Contact</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Dropdown <b class="caret"></b></a>
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Dropdown <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="#">Action</a></li>
<li><a href="#">Another action</a></li>
@ -427,7 +427,7 @@
<li><a href="#about">About</a></li>
<li><a href="#contact">Contact</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Dropdown <b class="caret"></b></a>
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Dropdown <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="#">Action</a></li>
<li><a href="#">Another action</a></li>

View File

@ -0,0 +1,56 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="">
<meta name="author" content="">
<link rel="icon" href="../../assets/ico/favicon.ico">
<title>Tooltip Viewport Example for Bootstrap</title>
<!-- Bootstrap core CSS -->
<link href="../../dist/css/bootstrap.min.css" rel="stylesheet">
<!-- Custom styles for this template -->
<link href="tooltip-viewport.css" rel="stylesheet">
<!-- Just for debugging purposes. Don't actually copy this line! -->
<!--[if lt IE 9]><script src="../../assets/js/ie8-responsive-file-warning.js"></script><![endif]-->
<!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
<script src="https://oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js"></script>
<![endif]-->
</head>
<body>
<button class="btn pull-right tooltip-bottom" title="This should be shifted to the left">Shift Left</button>
<button class="btn tooltip-bottom" title="This should be shifted to the right">Shift Right</button>
<button class="btn tooltip-right" title="This should be shifted down">Shift Down</button>
<div class="placeholder">There is a button down there ↓</div>
<button class="btn tooltip-right" title="This should be shifted up">Shift Up</button>
<div class="container-viewport">
<button class="btn tooltip-viewport-bottom" title="This should be shifted to the left">Shift Left</button>
<button class="btn tooltip-viewport-right" title="This should be shifted down">Shift Down</button>
<button class="btn pull-right tooltip-viewport-bottom" title="This should be shifted to the right">Shift Right</button>
<button class="btn tooltip-viewport-right btn-bottom" title="This should be shifted up">Shift Up</button>
</div>
<!-- Bootstrap core JavaScript
================================================== -->
<!-- Placed at the end of the document so the pages load faster -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<script src="../../dist/js/bootstrap.min.js"></script>
<script src="tooltip-viewport.js"></script>
</body>
</html>

View File

@ -0,0 +1,28 @@
body {
height: 1200px;
}
.tooltip {
min-width: 250px;
max-width: 500px;
}
.tooltip .tooltip-inner {
min-width: 250px;
max-width: 500px;
min-height: 200px;
}
.placeholder {
height: 900px;
}
.container-viewport {
position: absolute;
top: 600px;
left: 200px;
width: 600px;
height: 400px;
background: #c00;
}
.btn-bottom {
position: absolute;
bottom: 0;
left: 0;
}

View File

@ -0,0 +1,18 @@
$(document).ready(function () {
$('.tooltip-right').tooltip({
placement: 'right',
viewport: {selector: 'body', padding: 2}
})
$('.tooltip-bottom').tooltip({
placement: 'bottom',
viewport: {selector: 'body', padding: 2}
})
$('.tooltip-viewport-right').tooltip({
placement: 'right',
viewport: {selector: '.container-viewport', padding: 2}
})
$('.tooltip-viewport-bottom').tooltip({
placement: 'bottom',
viewport: {selector: '.container-viewport', padding: 2}
})
})

View File

@ -9,7 +9,7 @@ title: Bootstrap
<!-- <h1>Bootstrap</h1> -->
<p class="lead">The most popular front-end framework for developing responsive, mobile first projects on the web.</p>
<p class="lead">
<a href="getting-started#download" class="btn btn-outline-inverse btn-lg" onclick="_gaq.push(['_trackEvent', 'Jumbotron actions', 'Download', 'Download {{ site.current_version }}']);">Download Bootstrap</a>
<a href="getting-started#download" class="btn btn-outline-inverse btn-lg" onclick="ga('send', 'event', 'Jumbotron actions', 'Download', 'Download {{ site.current_version }}');">Download Bootstrap</a>
</p>
<p class="version">Currently v{{ site.current_version }}</p>
{% include ads.html %}

View File

@ -1,103 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="">
<meta name="author" content="">
<link rel="shortcut icon" href="../../docs-assets/ico/favicon.png">
<title>Tooltip Viewport Example for Bootstrap</title>
<!-- Bootstrap core CSS -->
<link href="../../dist/css/bootstrap.css" rel="stylesheet">
<!-- Just for debugging purposes. Don't actually copy this line! -->
<!--[if lt IE 9]><script src="../../docs-assets/js/ie8-responsive-file-warning.js"></script><![endif]-->
<!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
<script src="https://oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js"></script>
<![endif]-->
<style>
body {
height: 1200px;
}
.tooltip {
min-width: 250px;
max-width: 500px;
}
.tooltip .tooltip-inner {
min-height: 200px;
min-width: 250px;
max-width: 500px;
}
.placeholder {
height: 900px;
}
.container-viewport {
position: absolute;
left: 200px;
top: 600px;
width: 600px;
height: 400px;
background: #c00;
}
.btn-bottom {
position: absolute;
left: 0;
bottom: 0;
}
</style>
</head>
<body>
<button class="btn pull-right tooltip-bottom", title="This should be shifted to the left">Shift Left</button>
<button class="btn tooltip-bottom", title="This should be shifted to the right">Shift Right</button>
<button class="btn tooltip-right", title="This should be shifted down">Shift Down</button>
<div class="placeholder">There is a button down there ↓</div>
<button class="btn tooltip-right", title="This should be shifted up">Shift Up</button>
<div class="container-viewport">
<button class="btn tooltip-viewport-bottom", title="This should be shifted Left">Shift Left</button>
<button class="btn tooltip-viewport-right", title="This should be shifted Down">Shift Down</button>
<button class="btn pull-right tooltip-viewport-bottom", title="This should be shifted Right">Shift Right</button>
<button class="btn tooltip-viewport-right btn-bottom", title="This should be shifted up">Shift Up</button>
</div>
<!-- Bootstrap core JavaScript
================================================== -->
<!-- Placed at the end of the document so the pages load faster -->
<script src="https://code.jquery.com/jquery-1.10.2.min.js"></script>
<script src="../../js/tooltip.js"></script>
<script>
$(function(){
$('.tooltip-right').tooltip({
placement: 'right',
viewport: {selector: 'body', padding: 2}
});
$('.tooltip-bottom').tooltip({
placement: 'bottom',
viewport: {selector: 'body', padding: 2}
});
$('.tooltip-viewport-right').tooltip({
placement: 'right',
viewport: {selector: '.container-viewport', padding: 2}
});
$('.tooltip-viewport-bottom').tooltip({
placement: 'bottom',
viewport: {selector: '.container-viewport', padding: 2}
});
});
</script>
</body>
</html>

View File

@ -10,16 +10,19 @@
'use strict';
var fs = require('fs');
var btoa = require('btoa');
var glob = require('glob');
function getFiles(type) {
var files = {};
fs.readdirSync(type)
var recursive = (type === 'less');
var globExpr = (recursive ? '/**/*' : '/*');
glob.sync(type + globExpr)
.filter(function (path) {
return type === 'fonts' ? true : new RegExp('\\.' + type + '$').test(path);
})
.forEach(function (path) {
var fullPath = type + '/' + path;
files[path] = (type === 'fonts' ? btoa(fs.readFileSync(fullPath)) : fs.readFileSync(fullPath, 'utf8'));
.forEach(function (fullPath) {
var relativePath = fullPath.replace(/^[^/]+\//, '');
files[relativePath] = (type === 'fonts' ? btoa(fs.readFileSync(fullPath)) : fs.readFileSync(fullPath, 'utf8'));
});
return 'var __' + type + ' = ' + JSON.stringify(files) + '\n';
}
@ -28,7 +31,10 @@ module.exports = function generateRawFilesJs(grunt, banner) {
if (!banner) {
banner = '';
}
var files = banner + getFiles('js') + getFiles('less') + getFiles('fonts');
var dirs = ['js', 'less', 'fonts'];
var files = banner + dirs.map(getFiles).reduce(function (combined, file) {
return combined + file;
}, '');
var rawFilesJs = 'docs/assets/js/raw-files.min.js';
try {
fs.writeFileSync(rawFilesJs, files);

View File

@ -58,7 +58,7 @@
{
browserName: "iphone",
platform: "OS X 10.9",
version: "7"
version: "7.1"
},
# iOS Chrome not currently supported by Sauce Labs

View File

@ -59,7 +59,7 @@
if (pos > (this.$items.length - 1) || pos < 0) return
if (this.sliding) return this.$element.one('slid.bs.carousel', function () { that.to(pos) })
if (this.sliding) return this.$element.one('slid.bs.carousel', function () { that.to(pos) }) // yes, "slid". not a typo. past tense of "to slide".
if (activeIndex == pos) return this.pause().cycle()
return this.slide(pos > activeIndex ? 'next' : 'prev', $(this.$items[pos]))
@ -113,7 +113,7 @@
if (this.$indicators.length) {
this.$indicators.find('.active').removeClass('active')
this.$element.one('slid.bs.carousel', function () {
this.$element.one('slid.bs.carousel', function () { // yes, "slid". not a typo. past tense of "to slide".
var $nextIndicator = $(that.$indicators.children()[that.getActiveIndex()])
$nextIndicator && $nextIndicator.addClass('active')
})
@ -129,14 +129,14 @@
$next.removeClass([type, direction].join(' ')).addClass('active')
$active.removeClass(['active', direction].join(' '))
that.sliding = false
setTimeout(function () { that.$element.trigger('slid.bs.carousel') }, 0)
setTimeout(function () { that.$element.trigger('slid.bs.carousel') }, 0) // yes, "slid". not a typo. past tense of "to slide".
})
.emulateTransitionEnd($active.css('transition-duration').slice(0, -1) * 1000)
} else {
$active.removeClass('active')
$next.addClass('active')
this.sliding = false
this.$element.trigger('slid.bs.carousel')
this.$element.trigger('slid.bs.carousel') // yes, "slid". not a typo. past tense of "to slide".
}
isCycling && this.cycle()

View File

@ -51,8 +51,7 @@
this.$element
.removeClass('collapse')
.addClass('collapsing')
[dimension](0)
.addClass('collapsing')[dimension](0)
this.transitioning = 1
@ -60,8 +59,7 @@
if (e && e.target != this.$element[0]) return
this.$element
.removeClass('collapsing')
.addClass('collapse in')
[dimension]('auto')
.addClass('collapse in')[dimension]('auto')
this.transitioning = 0
this.$element.trigger('shown.bs.collapse')
}
@ -72,8 +70,7 @@
this.$element
.one($.support.transition.end, $.proxy(complete, this))
.emulateTransitionEnd(350)
[dimension](this.$element[0][scrollSize])
.emulateTransitionEnd(350)[dimension](this.$element[0][scrollSize])
}
Collapse.prototype.hide = function () {
@ -85,9 +82,7 @@
var dimension = this.dimension()
this.$element
[dimension](this.$element[dimension]())
[0].offsetHeight
this.$element[dimension](this.$element[dimension]())[0].offsetHeight
this.$element
.addClass('collapsing')

View File

@ -14,11 +14,12 @@
// ======================
var Modal = function (element, options) {
this.options = options
this.$body = $(document.body)
this.$element = $(element)
this.$backdrop =
this.isShown = null
this.options = options
this.$body = $(document.body)
this.$element = $(element)
this.$backdrop =
this.isShown = null
this.scrollbarWidth = 0
if (this.options.remote) {
this.$element
@ -49,6 +50,7 @@
this.isShown = true
this.checkScrollbar()
this.$body.addClass('modal-open')
this.setScrollbar()
@ -195,11 +197,14 @@
}
}
Modal.prototype.checkScrollbar = function () {
if (document.body.clientWidth >= window.innerWidth) return
this.scrollbarWidth = this.scrollbarWidth || this.measureScrollbar()
}
Modal.prototype.setScrollbar = function () {
if (document.body.clientHeight <= window.innerHeight) return
var scrollbarWidth = this.measureScrollbar()
var bodyPad = parseInt(this.$body.css('padding-right') || 0)
if (scrollbarWidth) this.$body.css('padding-right', bodyPad + scrollbarWidth)
var bodyPad = parseInt(this.$body.css('padding-right') || 0)
if (this.scrollbarWidth) this.$body.css('padding-right', bodyPad + this.scrollbarWidth)
}
Modal.prototype.resetScrollbar = function () {

View File

@ -169,10 +169,10 @@ $(function () {
dropdown
.parent('.dropdown')
.bind('show.bs.dropdown', function () {
.on('show.bs.dropdown', function () {
ok(true, 'show was called')
})
.bind('hide.bs.dropdown', function () {
.on('hide.bs.dropdown', function () {
ok(true, 'hide was called')
start()
})
@ -203,10 +203,10 @@ $(function () {
dropdown
.parent('.dropdown')
.bind('shown.bs.dropdown', function () {
.on('shown.bs.dropdown', function () {
ok(true, 'show was called')
})
.bind('hidden.bs.dropdown', function () {
.on('hidden.bs.dropdown', function () {
ok(true, 'hide was called')
start()
})

View File

@ -140,13 +140,13 @@ $(function () {
$.support.transition = false
var div = $('<div id="modal-test"><div class="contents"></div></div>')
div
.bind('shown.bs.modal', function () {
.on('shown.bs.modal', function () {
ok($('#modal-test').length, 'modal insterted into dom')
$('.contents').click()
ok($('#modal-test').is(':visible'), 'modal visible')
$('#modal-test').click()
})
.bind('hidden.bs.modal', function () {
.on('hidden.bs.modal', function () {
ok(!$('#modal-test').is(':visible'), 'modal hidden')
div.remove()
start()
@ -162,11 +162,11 @@ $(function () {
var div = $('<div id="modal-test"><div class="contents"></div></div>')
div
.bind('shown.bs.modal', function () {
.on('shown.bs.modal', function () {
triggered = 0
$('#modal-test').click()
})
.bind('hide.bs.modal', function () {
.on('hide.bs.modal', function () {
triggered += 1
ok(triggered === 1, 'modal hide triggered once')
start()
@ -179,7 +179,7 @@ $(function () {
$.support.transition = false
var div = $('<div id="modal-test"><div class="contents"><div id="close" data-dismiss="modal"></div></div></div>')
div
.bind('shown.bs.modal', function () {
.on('shown.bs.modal', function () {
$('#close').click()
ok(!$('#modal-test').is(':visible'), 'modal hidden')
})

View File

@ -110,20 +110,22 @@
.icon-prev,
.glyphicon-chevron-left {
left: 50%;
margin-left: -10px;
}
.icon-next,
.glyphicon-chevron-right {
right: 50%;
margin-right: -10px;
}
.icon-prev,
.icon-next {
width: 20px;
height: 20px;
margin-top: -10px;
margin-left: -10px;
font-family: serif;
}
.icon-prev {
&:before {
content: '\2039';// SINGLE LEFT-POINTING ANGLE QUOTATION MARK (U+2039)
@ -213,9 +215,16 @@
width: 30px;
height: 30px;
margin-top: -15px;
margin-left: -15px;
font-size: 30px;
}
.glyphicon-chevron-left,
.icon-prev {
margin-left: -15px;
}
.glyphicon-chevron-right,
.icon-next {
margin-right: -15px;
}
}
// Show and left align the captions

40
less/normalize.less vendored
View File

@ -1,4 +1,4 @@
/*! normalize.css v3.0.0 | MIT License | git.io/normalize */
/*! normalize.css v3.0.1 | MIT License | git.io/normalize */
//
// 1. Set default font family to sans-serif.
@ -24,7 +24,9 @@ body {
// ==========================================================================
//
// Correct `block` display not defined in IE 8/9.
// Correct `block` display not defined for any HTML5 element in IE 8/9.
// Correct `block` display not defined for `details` or `summary` in IE 10/11 and Firefox.
// Correct `block` display not defined for `main` in IE 11.
//
article,
@ -66,8 +68,8 @@ audio:not([controls]) {
}
//
// Address `[hidden]` styling not present in IE 8/9.
// Hide the `template` element in IE, Safari, and Firefox < 22.
// Address `[hidden]` styling not present in IE 8/9/10.
// Hide the `template` element in IE 8/9/11, Safari, and Firefox < 22.
//
[hidden],
@ -99,7 +101,7 @@ a:hover {
// ==========================================================================
//
// Address styling not present in IE 8/9, Safari 5, and Chrome.
// Address styling not present in IE 8/9/10/11, Safari, and Chrome.
//
abbr[title] {
@ -107,7 +109,7 @@ abbr[title] {
}
//
// Address style set to `bolder` in Firefox 4+, Safari 5, and Chrome.
// Address style set to `bolder` in Firefox 4+, Safari, and Chrome.
//
b,
@ -116,7 +118,7 @@ strong {
}
//
// Address styling not present in Safari 5 and Chrome.
// Address styling not present in Safari and Chrome.
//
dfn {
@ -125,7 +127,7 @@ dfn {
//
// Address variable `h1` font-size and margin within `section` and `article`
// contexts in Firefox 4+, Safari 5, and Chrome.
// contexts in Firefox 4+, Safari, and Chrome.
//
h1 {
@ -174,7 +176,7 @@ sub {
// ==========================================================================
//
// Remove border when inside `a` element in IE 8/9.
// Remove border when inside `a` element in IE 8/9/10.
//
img {
@ -182,7 +184,7 @@ img {
}
//
// Correct overflow displayed oddly in IE 9.
// Correct overflow not hidden in IE 9/10/11.
//
svg:not(:root) {
@ -193,7 +195,7 @@ svg:not(:root) {
// ==========================================================================
//
// Address margin not present in IE 8/9 and Safari 5.
// Address margin not present in IE 8/9 and Safari.
//
figure {
@ -242,7 +244,7 @@ samp {
// 1. Correct color not being inherited.
// Known issue: affects color of disabled elements.
// 2. Correct font properties not being inherited.
// 3. Address margins set differently in Firefox 4+, Safari 5, and Chrome.
// 3. Address margins set differently in Firefox 4+, Safari, and Chrome.
//
button,
@ -256,7 +258,7 @@ textarea {
}
//
// Address `overflow` set to `hidden` in IE 8/9/10.
// Address `overflow` set to `hidden` in IE 8/9/10/11.
//
button {
@ -266,7 +268,7 @@ button {
//
// Address inconsistent `text-transform` inheritance for `button` and `select`.
// All other form control elements do not inherit `text-transform` values.
// Correct `button` style inheritance in Firefox, IE 8+, and Opera
// Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera.
// Correct `select` style inheritance in Firefox.
//
@ -345,8 +347,8 @@ input[type="number"]::-webkit-outer-spin-button {
}
//
// 1. Address `appearance` set to `searchfield` in Safari 5 and Chrome.
// 2. Address `box-sizing` set to `border-box` in Safari 5 and Chrome
// 1. Address `appearance` set to `searchfield` in Safari and Chrome.
// 2. Address `box-sizing` set to `border-box` in Safari and Chrome
// (include `-moz` to future-proof).
//
@ -379,7 +381,7 @@ fieldset {
}
//
// 1. Correct `color` not being inherited in IE 8/9.
// 1. Correct `color` not being inherited in IE 8/9/10/11.
// 2. Remove padding so people aren't caught out if they zero out fieldsets.
//
@ -389,7 +391,7 @@ legend {
}
//
// Remove default vertical scrollbar in IE 8/9.
// Remove default vertical scrollbar in IE 8/9/10/11.
//
textarea {
@ -420,4 +422,4 @@ table {
td,
th {
padding: 0;
}
}

View File

@ -249,8 +249,8 @@
@zindex-navbar: 1000;
@zindex-dropdown: 1000;
@zindex-popover: 1010;
@zindex-tooltip: 1030;
@zindex-popover: 1060; // @fix #13216
@zindex-tooltip: 1070; // @fix #13216
@zindex-navbar-fixed: 1030;
@zindex-modal-background: 1040;
@zindex-modal: 1050;
@ -262,6 +262,7 @@
// Extra small screen / phone
// Note: Deprecated @screen-xs and @screen-phone as of v3.0.1
// Note: Deprecated @screen-xs-min as of v3.2.0
@screen-xs: 480px;
@screen-xs-min: @screen-xs;
@screen-phone: @screen-xs-min;

View File

@ -32,28 +32,29 @@
"devDependencies": {
"btoa": "~1.1.1",
"canonical-json": "~0.0.4",
"glob": "^3.2.9",
"grunt": "~0.4.4",
"grunt-autoprefixer": "~0.7.2",
"grunt-banner": "~0.2.2",
"grunt-contrib-clean": "~0.5.0",
"grunt-contrib-concat": "~0.3.0",
"grunt-contrib-concat": "~0.4.0",
"grunt-contrib-connect": "~0.7.1",
"grunt-contrib-copy": "~0.5.0",
"grunt-contrib-csslint": "~0.2.0",
"grunt-contrib-cssmin": "~0.9.0",
"grunt-contrib-jade": "~0.11.0",
"grunt-contrib-jshint": "~0.9.2",
"grunt-contrib-jshint": "~0.10.0",
"grunt-contrib-less": "~0.11.0",
"grunt-contrib-qunit": "~0.4.0",
"grunt-contrib-uglify": "~0.4.0",
"grunt-contrib-watch": "~0.6.0",
"grunt-contrib-watch": "~0.6.1",
"grunt-csscomb": "~2.0.1",
"grunt-css-flip": "~0.2.1",
"grunt-exec": "~0.4.5",
"grunt-html-validation": "~0.1.13",
"grunt-html-validation": "~0.1.15",
"grunt-jekyll": "~0.4.1",
"grunt-jscs-checker": "~0.4.0",
"grunt-saucelabs": "~5.1.0",
"grunt-jscs-checker": "~0.4.1",
"grunt-saucelabs": "~5.1.1",
"grunt-sed": "~0.1.1",
"load-grunt-tasks": "~0.4.0",
"markdown": "~0.5.0",

View File

@ -0,0 +1,12 @@
{
"npm-modules": {
"key": "./npm-shrinkwrap.canonical.json",
"cache": "../node_modules",
"generate": "./uncached-npm-install.sh"
},
"rubygems": {
"key": "../pseudo_Gemfile.lock",
"cache": "$GEMDIR",
"generate": "gem install -N jekyll -v $JEKYLL_VERSION"
}
}

File diff suppressed because one or more lines are too long

View File

@ -1,23 +1,51 @@
#!/usr/bin/env python2.7
# pylint: disable=C0301
from __future__ import absolute_import, unicode_literals, print_function, division
from sys import argv
from os import environ, stat, remove as _delete_file
from os.path import isfile, dirname, basename, abspath
from os import environ, stat, chdir, remove as _delete_file
from os.path import dirname, basename, abspath, realpath, expandvars
from hashlib import sha256
from subprocess import check_call as run
from json import load, dump as save
from contextlib import contextmanager
from datetime import datetime
from boto.s3.connection import S3Connection
from boto.s3.key import Key
from boto.exception import S3ResponseError
NEED_TO_UPLOAD_MARKER = '.need-to-upload'
CONFIG_FILE = './S3Cachefile.json'
UPLOAD_TODO_FILE = './S3CacheTodo.json'
BYTES_PER_MB = 1024 * 1024
try:
BUCKET_NAME = environ['TWBS_S3_BUCKET']
except KeyError:
raise SystemExit("TWBS_S3_BUCKET environment variable not set!")
@contextmanager
def timer():
start = datetime.utcnow()
yield
end = datetime.utcnow()
elapsed = end - start
print("\tDone. Took", int(elapsed.total_seconds()), "second(s).")
@contextmanager
def todo_file(writeback=True):
try:
with open(UPLOAD_TODO_FILE, 'rt') as json_file:
todo = load(json_file)
except (IOError, OSError, ValueError):
todo = {}
yield todo
if writeback:
try:
with open(UPLOAD_TODO_FILE, 'wt') as json_file:
save(todo, json_file)
except (OSError, IOError) as save_err:
print("Error saving {}:".format(UPLOAD_TODO_FILE), save_err)
def _sha256_of_file(filename):
@ -36,6 +64,21 @@ def _delete_file_quietly(filename):
pass
def mark_needs_uploading(cache_name):
with todo_file() as todo:
todo[cache_name] = True
def mark_uploaded(cache_name):
with todo_file() as todo:
todo.pop(cache_name, None)
def need_to_upload(cache_name):
with todo_file(writeback=False) as todo:
return todo.get(cache_name, False)
def _tarball_size(directory):
kib = stat(_tarball_filename_for(directory)).st_size // BYTES_PER_MB
return "{} MiB".format(kib)
@ -47,34 +90,37 @@ def _tarball_filename_for(directory):
def _create_tarball(directory):
print("Creating tarball of {}...".format(directory))
run(['tar', '-czf', _tarball_filename_for(directory), '-C', dirname(directory), basename(directory)])
with timer():
run(['tar', '-czf', _tarball_filename_for(directory), '-C', dirname(directory), basename(directory)])
def _extract_tarball(directory):
print("Extracting tarball of {}...".format(directory))
run(['tar', '-xzf', _tarball_filename_for(directory), '-C', dirname(directory)])
with timer():
run(['tar', '-xzf', _tarball_filename_for(directory), '-C', dirname(directory)])
def download(directory):
_delete_file_quietly(NEED_TO_UPLOAD_MARKER)
mark_uploaded(cache_name) # reset
try:
print("Downloading {} tarball from S3...".format(friendly_name))
key.get_contents_to_filename(_tarball_filename_for(directory))
print("Downloading {} tarball from S3...".format(cache_name))
with timer():
key.get_contents_to_filename(_tarball_filename_for(directory))
except S3ResponseError as err:
open(NEED_TO_UPLOAD_MARKER, 'a').close()
print(err)
raise SystemExit("Cached {} download failed!".format(friendly_name))
mark_needs_uploading(cache_name)
raise SystemExit("Cached {} download failed!".format(cache_name))
print("Downloaded {}.".format(_tarball_size(directory)))
_extract_tarball(directory)
print("{} successfully installed from cache.".format(friendly_name))
print("{} successfully installed from cache.".format(cache_name))
def upload(directory):
_create_tarball(directory)
print("Uploading {} tarball to S3... ({})".format(friendly_name, _tarball_size(directory)))
key.set_contents_from_filename(_tarball_filename_for(directory))
print("{} cache successfully updated.".format(friendly_name))
_delete_file_quietly(NEED_TO_UPLOAD_MARKER)
print("Uploading {} tarball to S3... ({})".format(cache_name, _tarball_size(directory)))
with timer():
key.set_contents_from_filename(_tarball_filename_for(directory))
print("{} cache successfully updated.".format(cache_name))
mark_uploaded(cache_name)
if __name__ == '__main__':
@ -82,26 +128,57 @@ if __name__ == '__main__':
# AWS_ACCESS_KEY_ID -- AWS Access Key ID
# AWS_SECRET_ACCESS_KEY -- AWS Secret Access Key
argv.pop(0)
if len(argv) != 4:
raise SystemExit("USAGE: s3_cache.py <download | upload> <friendly name> <dependencies file> <directory>")
mode, friendly_name, dependencies_file, directory = argv
if len(argv) != 2:
raise SystemExit("USAGE: s3_cache.py <download | upload> <cache name>")
mode, cache_name = argv
script_dir = dirname(realpath(__file__))
chdir(script_dir)
try:
with open(CONFIG_FILE, 'rt') as config_file:
config = load(config_file)
except (IOError, OSError, ValueError) as config_err:
print(config_err)
raise SystemExit("Error when trying to load config from JSON file!")
conn = S3Connection()
bucket = conn.lookup(BUCKET_NAME)
if bucket is None:
raise SystemExit("Could not access bucket!")
try:
cache_info = config[cache_name]
key_file = expandvars(cache_info["key"])
fallback_cmd = cache_info["generate"]
directory = expandvars(cache_info["cache"])
except (TypeError, KeyError) as load_err:
print(load_err)
raise SystemExit("Config for cache named {!r} is missing or malformed!".format(cache_name))
dependencies_file_hash = _sha256_of_file(dependencies_file)
try:
try:
BUCKET_NAME = environ['TWBS_S3_BUCKET']
except KeyError:
raise SystemExit("TWBS_S3_BUCKET environment variable not set!")
key = Key(bucket, dependencies_file_hash)
key.storage_class = 'REDUCED_REDUNDANCY'
conn = S3Connection()
bucket = conn.lookup(BUCKET_NAME)
if bucket is None:
raise SystemExit("Could not access bucket!")
if mode == 'download':
download(directory)
elif mode == 'upload':
if isfile(NEED_TO_UPLOAD_MARKER): # FIXME
upload(directory)
key_file_hash = _sha256_of_file(key_file)
key = Key(bucket, key_file_hash)
key.storage_class = 'REDUCED_REDUNDANCY'
if mode == 'download':
download(directory)
elif mode == 'upload':
if need_to_upload(cache_name):
upload(directory)
else:
print("No need to upload anything.")
else:
print("No need to upload anything.")
else:
raise SystemExit("Unrecognized mode {!r}".format(mode))
raise SystemExit("Unrecognized mode {!r}".format(mode))
except BaseException as exc:
if mode != 'download':
raise
print("Error!:", exc)
print("Unable to download from cache.")
print("Running fallback command to generate cache directory {!r}: {}".format(directory, fallback_cmd))
with timer():
run(fallback_cmd, shell=True)

View File

@ -1,5 +1,6 @@
#!/bin/bash
set -e
cd .. # /bootstrap/
cp test-infra/npm-shrinkwrap.canonical.json npm-shrinkwrap.json
npm install
rm npm-shrinkwrap.json