bootstrap-sass 3.2.0.4 → 3.3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of bootstrap-sass might be problematic. Click here for more details.

Files changed (81) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +2 -1
  3. data/.travis.yml +8 -2
  4. data/CHANGELOG.md +7 -0
  5. data/CONTRIBUTING.md +1 -1
  6. data/README.md +29 -6
  7. data/Rakefile +3 -4
  8. data/assets/fonts/bootstrap/glyphicons-halflings-regular.svg +1 -1
  9. data/assets/javascripts/bootstrap.js +329 -176
  10. data/assets/javascripts/bootstrap/affix.js +43 -23
  11. data/assets/javascripts/bootstrap/alert.js +6 -4
  12. data/assets/javascripts/bootstrap/button.js +16 -10
  13. data/assets/javascripts/bootstrap/carousel.js +26 -10
  14. data/assets/javascripts/bootstrap/collapse.js +69 -28
  15. data/assets/javascripts/bootstrap/dropdown.js +20 -10
  16. data/assets/javascripts/bootstrap/modal.js +22 -21
  17. data/assets/javascripts/bootstrap/popover.js +13 -7
  18. data/assets/javascripts/bootstrap/scrollspy.js +12 -7
  19. data/assets/javascripts/bootstrap/tab.js +41 -16
  20. data/assets/javascripts/bootstrap/tooltip.js +60 -39
  21. data/assets/javascripts/bootstrap/transition.js +1 -1
  22. data/assets/stylesheets/bootstrap/_button-groups.scss +18 -11
  23. data/assets/stylesheets/bootstrap/_buttons.scss +8 -5
  24. data/assets/stylesheets/bootstrap/_carousel.scss +25 -1
  25. data/assets/stylesheets/bootstrap/_code.scss +1 -0
  26. data/assets/stylesheets/bootstrap/_component-animations.scss +5 -2
  27. data/assets/stylesheets/bootstrap/_dropdowns.scss +4 -6
  28. data/assets/stylesheets/bootstrap/_forms.scss +51 -28
  29. data/assets/stylesheets/bootstrap/_glyphicons.scss +2 -5
  30. data/assets/stylesheets/bootstrap/_grid.scss +4 -4
  31. data/assets/stylesheets/bootstrap/_jumbotron.scss +4 -4
  32. data/assets/stylesheets/bootstrap/_list-group.scss +1 -0
  33. data/assets/stylesheets/bootstrap/_media.scss +27 -36
  34. data/assets/stylesheets/bootstrap/_modals.scss +3 -4
  35. data/assets/stylesheets/bootstrap/_navbar.scss +35 -33
  36. data/assets/stylesheets/bootstrap/_navs.scss +5 -3
  37. data/assets/stylesheets/bootstrap/_normalize.scss +5 -3
  38. data/assets/stylesheets/bootstrap/_pager.scss +2 -3
  39. data/assets/stylesheets/bootstrap/_pagination.scss +1 -1
  40. data/assets/stylesheets/bootstrap/_panels.scss +22 -4
  41. data/assets/stylesheets/bootstrap/_popovers.scss +5 -4
  42. data/assets/stylesheets/bootstrap/_print.scss +102 -96
  43. data/assets/stylesheets/bootstrap/_progress-bars.scss +2 -20
  44. data/assets/stylesheets/bootstrap/_responsive-embed.scss +2 -1
  45. data/assets/stylesheets/bootstrap/_scaffolding.scss +3 -3
  46. data/assets/stylesheets/bootstrap/_tables.scss +11 -10
  47. data/assets/stylesheets/bootstrap/_theme.scss +16 -14
  48. data/assets/stylesheets/bootstrap/_thumbnails.scss +2 -2
  49. data/assets/stylesheets/bootstrap/_type.scss +10 -16
  50. data/assets/stylesheets/bootstrap/_utilities.scss +3 -4
  51. data/assets/stylesheets/bootstrap/_variables.scss +29 -19
  52. data/assets/stylesheets/bootstrap/mixins/_buttons.scss +2 -0
  53. data/assets/stylesheets/bootstrap/mixins/_forms.scss +5 -1
  54. data/assets/stylesheets/bootstrap/mixins/_grid.scss +2 -2
  55. data/assets/stylesheets/bootstrap/mixins/_hide-text.scss +1 -1
  56. data/assets/stylesheets/bootstrap/mixins/_image.scss +0 -1
  57. data/assets/stylesheets/bootstrap/mixins/_labels.scss +1 -1
  58. data/assets/stylesheets/bootstrap/mixins/_progress-bar.scss +1 -1
  59. data/assets/stylesheets/bootstrap/mixins/_vendor-prefixes.scss +6 -3
  60. data/lib/bootstrap-sass.rb +2 -5
  61. data/lib/bootstrap-sass/engine.rb +1 -1
  62. data/lib/bootstrap-sass/version.rb +2 -2
  63. data/package.json +3 -3
  64. data/tasks/converter/less_conversion.rb +60 -28
  65. data/tasks/converter/network.rb +12 -6
  66. data/templates/project/_bootstrap-variables.sass +866 -0
  67. data/templates/project/manifest.rb +5 -11
  68. data/test/node_sass_compile_test.sh +8 -0
  69. metadata +7 -28
  70. data/templates/project/_bootstrap-variables.sass.erb +0 -4
  71. data/test/dummy_rails/bin/bundle +0 -3
  72. data/test/dummy_rails/bin/rails +0 -4
  73. data/test/dummy_rails/bin/rake +0 -4
  74. data/test/dummy_rails/db/test.sqlite3 +0 -0
  75. data/test/dummy_rails/lib/assets/.keep +0 -0
  76. data/test/dummy_rails/public/404.html +0 -58
  77. data/test/dummy_rails/public/422.html +0 -58
  78. data/test/dummy_rails/public/500.html +0 -57
  79. data/test/dummy_rails/public/favicon.ico +0 -0
  80. data/test/node_sass_test.rb +0 -16
  81. data/test/support/integration_test.rb +0 -22
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA256:
3
- metadata.gz: 6050eccd4daf64b5e5d72bca8ac1292f271cf035c73b3e5eff62f385816fa2f3
4
- data.tar.gz: 387b67ca35856109dc25957a2eb2da470dc65a6cd53d5facdeb10d12c9f943d6
2
+ SHA1:
3
+ metadata.gz: d99caaebc96473fc43200f9761918c7d434a606a
4
+ data.tar.gz: e7d8b2f1bd54b8a8023d99edf4d8b869035ccf16
5
5
  SHA512:
6
- metadata.gz: 41456d7bbd25cc93328e1ae7038636f54200fbc021b841fb52882226a527b5aa8da37a2311df2c189eb8c5e25c9c78f75fa475c664b4a7147f21f332081191aa
7
- data.tar.gz: '0732993db77d14da653cf64d5d1cca86cb948c4337bda6ee9f256fbedcaf03f55fce53b5eedb0abcbc042ff443c9efccfb2fc88a0e0dad504f78f2fa366ce1d9'
6
+ metadata.gz: 3ad30c63d7281dabc739b5968595db9dd52dfa1553f173cc6b1de72893bfcc299bc59a2c8990717c962f4716d4479764e1f25f9118a65985082b95eac7921e28
7
+ data.tar.gz: 54abaa619e7ead56462ed5f811661b4b279d0bfe8d94c844896841913b0414229834fbd3f8a36daeb046a07315b8eae37ed16de342898e2c50b2b9616aa96d43
data/.gitignore CHANGED
@@ -14,5 +14,6 @@ Gemfile.lock
14
14
  tmp/
15
15
  test/screenshots/
16
16
  test/dummy_rails/log/*.log
17
-
17
+ test/dummy_rails/public/assets/
18
18
  .DS_Store
19
+ node_modules
@@ -1,12 +1,12 @@
1
1
  language: ruby
2
2
  rvm:
3
- - 2.1.1
4
- - 2.0.0
3
+ - 2.1.2
5
4
  - jruby
6
5
  - rbx-2
7
6
  gemfile:
8
7
  - test/gemfiles/sass_3_2.gemfile
9
8
  - test/gemfiles/sass_3_3.gemfile
9
+ - test/gemfiles/sass_3_4.gemfile
10
10
  - test/gemfiles/sass_head.gemfile
11
11
  before_install:
12
12
  - "npm install"
@@ -17,3 +17,9 @@ matrix:
17
17
  - gemfile: test/gemfiles/sass_head.gemfile
18
18
  notifications:
19
19
  slack: heybb:3n88HHilXn76ji9vV4gL819Y
20
+ env:
21
+ global:
22
+ - VERBOSE=1
23
+ script:
24
+ - bundle exec rake
25
+ - sh test/*.sh
@@ -1,7 +1,14 @@
1
1
  # Changelog
2
2
 
3
+ ## 3.3.0
4
+
5
+ * Improve libsass compatibility
6
+ * Support using Bower package with Rails
7
+
3
8
  ## 3.2.0.2
4
9
 
10
+ Main bootstrap file is now a partial (_bootstrap.scss), for compatibility with Compass 1+.
11
+
5
12
  Fixed a number of bugs. [Issues closed in v3.2.0.2](https://github.com/twbs/bootstrap-sass/issues?q=is%3Aissue+is%3Aclosed+milestone%3Av3.2.0.2).
6
13
 
7
14
  ## 3.2.0.1
@@ -3,7 +3,7 @@
3
3
  ## Asset Changes
4
4
 
5
5
  Any changes to `bootstrap-sass` assets (scss, javascripts, fonts) should be checked against the `convert` rake task.
6
- For usage instructions, see the [README](https://github.com/twbs/bootstrap-sass/blob/3/README.md).
6
+ For usage instructions, see the [README](/README.md).
7
7
 
8
8
  If something is broken in the converter, it's preferable to update the converter along with the asset itself.
9
9
 
data/README.md CHANGED
@@ -17,7 +17,7 @@ Please see the appropriate guide for your environment of choice:
17
17
  In your Gemfile you need to add the `bootstrap-sass` gem, and ensure that the `sass-rails` gem is present - it is added to new Rails applications by default.
18
18
 
19
19
  ```ruby
20
- gem 'bootstrap-sass', '~> 3.2.0'
20
+ gem 'bootstrap-sass', '~> 3.3.0'
21
21
  gem 'sass-rails', '>= 3.2'
22
22
  ```
23
23
 
@@ -33,10 +33,13 @@ gem 'autoprefixer-rails'
33
33
  Import Bootstrap styles in `app/assets/stylesheets/application.css.scss`:
34
34
 
35
35
  ```scss
36
+ // "bootstrap-sprockets" must be imported before "bootstrap" and "bootstrap/variables"
36
37
  @import "bootstrap-sprockets";
37
38
  @import "bootstrap";
38
39
  ```
39
40
 
41
+ `bootstrap-sprockets` must be imported before `bootstrap` for the icon fonts to work.
42
+
40
43
  Make sure the file has `.css.scss` extension (or `.css.sass` for Sass syntax). If you have just generated a new Rails app,
41
44
  it may come with a `.css` file instead. If this file exists, it will be served instead of Sass, so remove it:
42
45
 
@@ -55,14 +58,28 @@ Require Bootstrap Javascripts in `app/assets/javascripts/application.js`:
55
58
 
56
59
  #### Bower with Rails
57
60
 
58
- When using [bootstrap-sass Bower package](#c-bower) in Rails, ensure [minimum Sass number precision](#sass-number-precision):
61
+ When using [bootstrap-sass Bower package](#c-bower) instead of the gem in Rails, add Bootstrap asset paths:
62
+
63
+ ```ruby
64
+ # config/application.rb
65
+ # bootstrap-sass asset paths
66
+ root.join('vendor/assets/bower_components/bootstrap-sass/assets').tap do |path|
67
+ config.sass.load_paths << path.join('stylesheets')
68
+ config.assets.paths += %w(javascripts fonts images).map(&path.method(:join))
69
+ end
70
+ ```
71
+
72
+ Then, ensure [minimum Sass number precision](#sass-number-precision):
59
73
 
60
74
  ```ruby
61
- # e.g. config/initializers/sass.rb
75
+ # config/initializers/sass.rb
76
+ # Minimum precision required by bootstrap-sass
62
77
  ::Sass::Script::Number.precision = [10, ::Sass::Script::Number.precision].max
63
78
  ```
64
79
 
65
- `bootstrap-sprockets` must be imported before `bootstrap` for the icon fonts to work.
80
+ #### Rails 4.x
81
+
82
+ Please make sure `sprockets-rails` is at least v2.1.4.
66
83
 
67
84
  #### Rails 3.2.x
68
85
 
@@ -159,8 +176,8 @@ See also this [example manifest.js](/test/dummy_node_mincer/manifest.js) for min
159
176
  By default all of Bootstrap is imported.
160
177
 
161
178
  You can also import components explicitly. To start with a full list of modules copy
162
- [`bootstrap.scss`](assets/stylesheets/bootstrap.scss) file into your assets as `bootstrap-custom.scss`.
163
- Then comment out components you do not want from `bootstrap-custom`.
179
+ [`_bootstrap.scss`](assets/stylesheets/_bootstrap.scss) file into your assets as `_bootstrap-custom.scss`.
180
+ Then comment out components you do not want from `_bootstrap-custom`.
164
181
  In the application Sass file, replace `@import 'bootstrap'` with:
165
182
 
166
183
  ```scss
@@ -253,6 +270,12 @@ $navbar-default-color: $light-orange;
253
270
  @import "bootstrap";
254
271
  ```
255
272
 
273
+ ## Version
274
+
275
+ `bootstrap-sass` version reflects the upstream version, with an additional number for Sass-specific changes.
276
+
277
+ Always refer to [CHANGELOG.md](/CHANGELOG.md) when upgrading.
278
+
256
279
  ---
257
280
 
258
281
  ## Development and Contributing
data/Rakefile CHANGED
@@ -4,10 +4,9 @@ $:.unshift(lib_path) unless $:.include?(lib_path)
4
4
  load './tasks/bower.rake'
5
5
 
6
6
  require 'rake/testtask'
7
- Rake::TestTask.new do |t|
8
- t.libs << "test"
9
- t.test_files = FileList['test/*_test.rb']
10
- t.verbose = true
7
+ task :test do |t|
8
+ $: << File.expand_path('test/')
9
+ Dir.glob('./test/**/*_test.rb').each { |file| require file }
11
10
  end
12
11
 
13
12
  desc 'Dumps output to a CSS file for testing'
@@ -226,4 +226,4 @@
226
226
  <glyph unicode="&#xe199;" d="M100 200h400v-155l-75 -45h350l-75 45v155h400l-270 300h170l-270 300h170l-300 333l-300 -333h170l-270 -300h170z" />
227
227
  <glyph unicode="&#xe200;" d="M121 700q0 -53 28.5 -97t75.5 -65q-4 -16 -4 -38q0 -74 52.5 -126.5t126.5 -52.5q56 0 100 30v-306l-75 -45h350l-75 45v306q46 -30 100 -30q74 0 126.5 52.5t52.5 126.5q0 24 -9 55q50 32 79.5 83t29.5 112q0 90 -61.5 155.5t-150.5 71.5q-26 89 -99.5 145.5 t-167.5 56.5q-116 0 -197.5 -81.5t-81.5 -197.5q0 -4 1 -11.5t1 -11.5q-14 2 -23 2q-74 0 -126.5 -52.5t-52.5 -126.5z" />
228
228
  </font>
229
- </defs></svg>
229
+ </defs></svg>
@@ -1,5 +1,5 @@
1
1
  /* ========================================================================
2
- * Bootstrap: affix.js v3.2.0
2
+ * Bootstrap: affix.js v3.3.0
3
3
  * http://getbootstrap.com/javascript/#affix
4
4
  * ========================================================================
5
5
  * Copyright 2011-2014 Twitter, Inc.
@@ -28,7 +28,7 @@
28
28
  this.checkPosition()
29
29
  }
30
30
 
31
- Affix.VERSION = '3.2.0'
31
+ Affix.VERSION = '3.3.0'
32
32
 
33
33
  Affix.RESET = 'affix affix-top affix-bottom'
34
34
 
@@ -37,6 +37,28 @@
37
37
  target: window
38
38
  }
39
39
 
40
+ Affix.prototype.getState = function (scrollHeight, height, offsetTop, offsetBottom) {
41
+ var scrollTop = this.$target.scrollTop()
42
+ var position = this.$element.offset()
43
+ var targetHeight = this.$target.height()
44
+
45
+ if (offsetTop != null && this.affixed == 'top') return scrollTop < offsetTop ? 'top' : false
46
+
47
+ if (this.affixed == 'bottom') {
48
+ if (offsetTop != null) return (scrollTop + this.unpin <= position.top) ? false : 'bottom'
49
+ return (scrollTop + targetHeight <= scrollHeight - offsetBottom) ? false : 'bottom'
50
+ }
51
+
52
+ var initializing = this.affixed == null
53
+ var colliderTop = initializing ? scrollTop : position.top
54
+ var colliderHeight = initializing ? targetHeight : height
55
+
56
+ if (offsetTop != null && colliderTop <= offsetTop) return 'top'
57
+ if (offsetBottom != null && (colliderTop + colliderHeight >= scrollHeight - offsetBottom)) return 'bottom'
58
+
59
+ return false
60
+ }
61
+
40
62
  Affix.prototype.getPinnedOffset = function () {
41
63
  if (this.pinnedOffset) return this.pinnedOffset
42
64
  this.$element.removeClass(Affix.RESET).addClass('affix')
@@ -52,42 +74,40 @@
52
74
  Affix.prototype.checkPosition = function () {
53
75
  if (!this.$element.is(':visible')) return
54
76
 
55
- var scrollHeight = $(document).height()
56
- var scrollTop = this.$target.scrollTop()
57
- var position = this.$element.offset()
77
+ var height = this.$element.height()
58
78
  var offset = this.options.offset
59
79
  var offsetTop = offset.top
60
80
  var offsetBottom = offset.bottom
81
+ var scrollHeight = $('body').height()
61
82
 
62
83
  if (typeof offset != 'object') offsetBottom = offsetTop = offset
63
84
  if (typeof offsetTop == 'function') offsetTop = offset.top(this.$element)
64
85
  if (typeof offsetBottom == 'function') offsetBottom = offset.bottom(this.$element)
65
86
 
66
- var affix = this.unpin != null && (scrollTop + this.unpin <= position.top) ? false :
67
- offsetBottom != null && (position.top + this.$element.height() >= scrollHeight - offsetBottom) ? 'bottom' :
68
- offsetTop != null && (scrollTop <= offsetTop) ? 'top' : false
87
+ var affix = this.getState(scrollHeight, height, offsetTop, offsetBottom)
69
88
 
70
- if (this.affixed === affix) return
71
- if (this.unpin != null) this.$element.css('top', '')
89
+ if (this.affixed != affix) {
90
+ if (this.unpin != null) this.$element.css('top', '')
72
91
 
73
- var affixType = 'affix' + (affix ? '-' + affix : '')
74
- var e = $.Event(affixType + '.bs.affix')
92
+ var affixType = 'affix' + (affix ? '-' + affix : '')
93
+ var e = $.Event(affixType + '.bs.affix')
75
94
 
76
- this.$element.trigger(e)
95
+ this.$element.trigger(e)
77
96
 
78
- if (e.isDefaultPrevented()) return
97
+ if (e.isDefaultPrevented()) return
79
98
 
80
- this.affixed = affix
81
- this.unpin = affix == 'bottom' ? this.getPinnedOffset() : null
99
+ this.affixed = affix
100
+ this.unpin = affix == 'bottom' ? this.getPinnedOffset() : null
82
101
 
83
- this.$element
84
- .removeClass(Affix.RESET)
85
- .addClass(affixType)
86
- .trigger($.Event(affixType.replace('affix', 'affixed')))
102
+ this.$element
103
+ .removeClass(Affix.RESET)
104
+ .addClass(affixType)
105
+ .trigger(affixType.replace('affix', 'affixed') + '.bs.affix')
106
+ }
87
107
 
88
108
  if (affix == 'bottom') {
89
109
  this.$element.offset({
90
- top: scrollHeight - this.$element.height() - offsetBottom
110
+ top: scrollHeight - height - offsetBottom
91
111
  })
92
112
  }
93
113
  }
@@ -132,8 +152,8 @@
132
152
 
133
153
  data.offset = data.offset || {}
134
154
 
135
- if (data.offsetBottom) data.offset.bottom = data.offsetBottom
136
- if (data.offsetTop) data.offset.top = data.offsetTop
155
+ if (data.offsetBottom != null) data.offset.bottom = data.offsetBottom
156
+ if (data.offsetTop != null) data.offset.top = data.offsetTop
137
157
 
138
158
  Plugin.call($spy, data)
139
159
  })
@@ -142,7 +162,7 @@
142
162
  }(jQuery);
143
163
 
144
164
  /* ========================================================================
145
- * Bootstrap: alert.js v3.2.0
165
+ * Bootstrap: alert.js v3.3.0
146
166
  * http://getbootstrap.com/javascript/#alerts
147
167
  * ========================================================================
148
168
  * Copyright 2011-2014 Twitter, Inc.
@@ -161,7 +181,9 @@
161
181
  $(el).on('click', dismiss, this.close)
162
182
  }
163
183
 
164
- Alert.VERSION = '3.2.0'
184
+ Alert.VERSION = '3.3.0'
185
+
186
+ Alert.TRANSITION_DURATION = 150
165
187
 
166
188
  Alert.prototype.close = function (e) {
167
189
  var $this = $(this)
@@ -177,7 +199,7 @@
177
199
  if (e) e.preventDefault()
178
200
 
179
201
  if (!$parent.length) {
180
- $parent = $this.hasClass('alert') ? $this : $this.parent()
202
+ $parent = $this.closest('.alert')
181
203
  }
182
204
 
183
205
  $parent.trigger(e = $.Event('close.bs.alert'))
@@ -194,7 +216,7 @@
194
216
  $.support.transition && $parent.hasClass('fade') ?
195
217
  $parent
196
218
  .one('bsTransitionEnd', removeElement)
197
- .emulateTransitionEnd(150) :
219
+ .emulateTransitionEnd(Alert.TRANSITION_DURATION) :
198
220
  removeElement()
199
221
  }
200
222
 
@@ -235,7 +257,7 @@
235
257
  }(jQuery);
236
258
 
237
259
  /* ========================================================================
238
- * Bootstrap: button.js v3.2.0
260
+ * Bootstrap: button.js v3.3.0
239
261
  * http://getbootstrap.com/javascript/#buttons
240
262
  * ========================================================================
241
263
  * Copyright 2011-2014 Twitter, Inc.
@@ -255,7 +277,7 @@
255
277
  this.isLoading = false
256
278
  }
257
279
 
258
- Button.VERSION = '3.2.0'
280
+ Button.VERSION = '3.3.0'
259
281
 
260
282
  Button.DEFAULTS = {
261
283
  loadingText: 'loading...'
@@ -271,10 +293,10 @@
271
293
 
272
294
  if (data.resetText == null) $el.data('resetText', $el[val]())
273
295
 
274
- $el[val](data[state] == null ? this.options[state] : data[state])
275
-
276
296
  // push to event loop to allow forms to submit
277
297
  setTimeout($.proxy(function () {
298
+ $el[val](data[state] == null ? this.options[state] : data[state])
299
+
278
300
  if (state == 'loadingText') {
279
301
  this.isLoading = true
280
302
  $el.addClass(d).attr(d, d)
@@ -296,6 +318,8 @@
296
318
  else $parent.find('.active').removeClass('active')
297
319
  }
298
320
  if (changed) $input.prop('checked', !this.$element.hasClass('active')).trigger('change')
321
+ } else {
322
+ this.$element.attr('aria-pressed', !this.$element.hasClass('active'))
299
323
  }
300
324
 
301
325
  if (changed) this.$element.toggleClass('active')
@@ -336,17 +360,21 @@
336
360
  // BUTTON DATA-API
337
361
  // ===============
338
362
 
339
- $(document).on('click.bs.button.data-api', '[data-toggle^="button"]', function (e) {
340
- var $btn = $(e.target)
341
- if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn')
342
- Plugin.call($btn, 'toggle')
343
- e.preventDefault()
344
- })
363
+ $(document)
364
+ .on('click.bs.button.data-api', '[data-toggle^="button"]', function (e) {
365
+ var $btn = $(e.target)
366
+ if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn')
367
+ Plugin.call($btn, 'toggle')
368
+ e.preventDefault()
369
+ })
370
+ .on('focus.bs.button.data-api blur.bs.button.data-api', '[data-toggle^="button"]', function (e) {
371
+ $(e.target).closest('.btn').toggleClass('focus', e.type == 'focus')
372
+ })
345
373
 
346
374
  }(jQuery);
347
375
 
348
376
  /* ========================================================================
349
- * Bootstrap: carousel.js v3.2.0
377
+ * Bootstrap: carousel.js v3.3.0
350
378
  * http://getbootstrap.com/javascript/#carousel
351
379
  * ========================================================================
352
380
  * Copyright 2011-2014 Twitter, Inc.
@@ -361,7 +389,7 @@
361
389
  // =========================
362
390
 
363
391
  var Carousel = function (element, options) {
364
- this.$element = $(element).on('keydown.bs.carousel', $.proxy(this.keydown, this))
392
+ this.$element = $(element)
365
393
  this.$indicators = this.$element.find('.carousel-indicators')
366
394
  this.options = options
367
395
  this.paused =
@@ -370,17 +398,22 @@
370
398
  this.$active =
371
399
  this.$items = null
372
400
 
373
- this.options.pause == 'hover' && this.$element
401
+ this.options.keyboard && this.$element.on('keydown.bs.carousel', $.proxy(this.keydown, this))
402
+
403
+ this.options.pause == 'hover' && !('ontouchstart' in document.documentElement) && this.$element
374
404
  .on('mouseenter.bs.carousel', $.proxy(this.pause, this))
375
405
  .on('mouseleave.bs.carousel', $.proxy(this.cycle, this))
376
406
  }
377
407
 
378
- Carousel.VERSION = '3.2.0'
408
+ Carousel.VERSION = '3.3.0'
409
+
410
+ Carousel.TRANSITION_DURATION = 600
379
411
 
380
412
  Carousel.DEFAULTS = {
381
413
  interval: 5000,
382
414
  pause: 'hover',
383
- wrap: true
415
+ wrap: true,
416
+ keyboard: true
384
417
  }
385
418
 
386
419
  Carousel.prototype.keydown = function (e) {
@@ -410,6 +443,13 @@
410
443
  return this.$items.index(item || this.$active)
411
444
  }
412
445
 
446
+ Carousel.prototype.getItemForDirection = function (direction, active) {
447
+ var delta = direction == 'prev' ? -1 : 1
448
+ var activeIndex = this.getItemIndex(active)
449
+ var itemIndex = (activeIndex + delta) % this.$items.length
450
+ return this.$items.eq(itemIndex)
451
+ }
452
+
413
453
  Carousel.prototype.to = function (pos) {
414
454
  var that = this
415
455
  var activeIndex = this.getItemIndex(this.$active = this.$element.find('.item.active'))
@@ -419,7 +459,7 @@
419
459
  if (this.sliding) return this.$element.one('slid.bs.carousel', function () { that.to(pos) }) // yes, "slid"
420
460
  if (activeIndex == pos) return this.pause().cycle()
421
461
 
422
- return this.slide(pos > activeIndex ? 'next' : 'prev', $(this.$items[pos]))
462
+ return this.slide(pos > activeIndex ? 'next' : 'prev', this.$items.eq(pos))
423
463
  }
424
464
 
425
465
  Carousel.prototype.pause = function (e) {
@@ -447,7 +487,7 @@
447
487
 
448
488
  Carousel.prototype.slide = function (type, next) {
449
489
  var $active = this.$element.find('.item.active')
450
- var $next = next || $active[type]()
490
+ var $next = next || this.getItemForDirection(type, $active)
451
491
  var isCycling = this.interval
452
492
  var direction = type == 'next' ? 'left' : 'right'
453
493
  var fallback = type == 'next' ? 'first' : 'last'
@@ -493,7 +533,7 @@
493
533
  that.$element.trigger(slidEvent)
494
534
  }, 0)
495
535
  })
496
- .emulateTransitionEnd($active.css('transition-duration').slice(0, -1) * 1000)
536
+ .emulateTransitionEnd(Carousel.TRANSITION_DURATION)
497
537
  } else {
498
538
  $active.removeClass('active')
499
539
  $next.addClass('active')
@@ -542,7 +582,7 @@
542
582
  // CAROUSEL DATA-API
543
583
  // =================
544
584
 
545
- $(document).on('click.bs.carousel.data-api', '[data-slide], [data-slide-to]', function (e) {
585
+ var clickHandler = function (e) {
546
586
  var href
547
587
  var $this = $(this)
548
588
  var $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) // strip for ie7
@@ -558,7 +598,11 @@
558
598
  }
559
599
 
560
600
  e.preventDefault()
561
- })
601
+ }
602
+
603
+ $(document)
604
+ .on('click.bs.carousel.data-api', '[data-slide]', clickHandler)
605
+ .on('click.bs.carousel.data-api', '[data-slide-to]', clickHandler)
562
606
 
563
607
  $(window).on('load', function () {
564
608
  $('[data-ride="carousel"]').each(function () {
@@ -570,7 +614,7 @@
570
614
  }(jQuery);
571
615
 
572
616
  /* ========================================================================
573
- * Bootstrap: collapse.js v3.2.0
617
+ * Bootstrap: collapse.js v3.3.0
574
618
  * http://getbootstrap.com/javascript/#collapse
575
619
  * ========================================================================
576
620
  * Copyright 2011-2014 Twitter, Inc.
@@ -587,16 +631,25 @@
587
631
  var Collapse = function (element, options) {
588
632
  this.$element = $(element)
589
633
  this.options = $.extend({}, Collapse.DEFAULTS, options)
634
+ this.$trigger = $(this.options.trigger).filter('[href="#' + element.id + '"], [data-target="#' + element.id + '"]')
590
635
  this.transitioning = null
591
636
 
592
- if (this.options.parent) this.$parent = $(this.options.parent)
637
+ if (this.options.parent) {
638
+ this.$parent = this.getParent()
639
+ } else {
640
+ this.addAriaAndCollapsedClass(this.$element, this.$trigger)
641
+ }
642
+
593
643
  if (this.options.toggle) this.toggle()
594
644
  }
595
645
 
596
- Collapse.VERSION = '3.2.0'
646
+ Collapse.VERSION = '3.3.0'
647
+
648
+ Collapse.TRANSITION_DURATION = 350
597
649
 
598
650
  Collapse.DEFAULTS = {
599
- toggle: true
651
+ toggle: true,
652
+ trigger: '[data-toggle="collapse"]'
600
653
  }
601
654
 
602
655
  Collapse.prototype.dimension = function () {
@@ -607,17 +660,21 @@
607
660
  Collapse.prototype.show = function () {
608
661
  if (this.transitioning || this.$element.hasClass('in')) return
609
662
 
663
+ var activesData
664
+ var actives = this.$parent && this.$parent.find('> .panel').children('.in, .collapsing')
665
+
666
+ if (actives && actives.length) {
667
+ activesData = actives.data('bs.collapse')
668
+ if (activesData && activesData.transitioning) return
669
+ }
670
+
610
671
  var startEvent = $.Event('show.bs.collapse')
611
672
  this.$element.trigger(startEvent)
612
673
  if (startEvent.isDefaultPrevented()) return
613
674
 
614
- var actives = this.$parent && this.$parent.find('> .panel > .in')
615
-
616
675
  if (actives && actives.length) {
617
- var hasData = actives.data('bs.collapse')
618
- if (hasData && hasData.transitioning) return
619
676
  Plugin.call(actives, 'hide')
620
- hasData || actives.data('bs.collapse', null)
677
+ activesData || actives.data('bs.collapse', null)
621
678
  }
622
679
 
623
680
  var dimension = this.dimension()
@@ -625,6 +682,11 @@
625
682
  this.$element
626
683
  .removeClass('collapse')
627
684
  .addClass('collapsing')[dimension](0)
685
+ .attr('aria-expanded', true)
686
+
687
+ this.$trigger
688
+ .removeClass('collapsed')
689
+ .attr('aria-expanded', true)
628
690
 
629
691
  this.transitioning = 1
630
692
 
@@ -643,7 +705,7 @@
643
705
 
644
706
  this.$element
645
707
  .one('bsTransitionEnd', $.proxy(complete, this))
646
- .emulateTransitionEnd(350)[dimension](this.$element[0][scrollSize])
708
+ .emulateTransitionEnd(Collapse.TRANSITION_DURATION)[dimension](this.$element[0][scrollSize])
647
709
  }
648
710
 
649
711
  Collapse.prototype.hide = function () {
@@ -659,17 +721,21 @@
659
721
 
660
722
  this.$element
661
723
  .addClass('collapsing')
662
- .removeClass('collapse')
663
- .removeClass('in')
724
+ .removeClass('collapse in')
725
+ .attr('aria-expanded', false)
726
+
727
+ this.$trigger
728
+ .addClass('collapsed')
729
+ .attr('aria-expanded', false)
664
730
 
665
731
  this.transitioning = 1
666
732
 
667
733
  var complete = function () {
668
734
  this.transitioning = 0
669
735
  this.$element
670
- .trigger('hidden.bs.collapse')
671
736
  .removeClass('collapsing')
672
737
  .addClass('collapse')
738
+ .trigger('hidden.bs.collapse')
673
739
  }
674
740
 
675
741
  if (!$.support.transition) return complete.call(this)
@@ -677,13 +743,40 @@
677
743
  this.$element
678
744
  [dimension](0)
679
745
  .one('bsTransitionEnd', $.proxy(complete, this))
680
- .emulateTransitionEnd(350)
746
+ .emulateTransitionEnd(Collapse.TRANSITION_DURATION)
681
747
  }
682
748
 
683
749
  Collapse.prototype.toggle = function () {
684
750
  this[this.$element.hasClass('in') ? 'hide' : 'show']()
685
751
  }
686
752
 
753
+ Collapse.prototype.getParent = function () {
754
+ return $(this.options.parent)
755
+ .find('[data-toggle="collapse"][data-parent="' + this.options.parent + '"]')
756
+ .each($.proxy(function (i, element) {
757
+ var $element = $(element)
758
+ this.addAriaAndCollapsedClass(getTargetFromTrigger($element), $element)
759
+ }, this))
760
+ .end()
761
+ }
762
+
763
+ Collapse.prototype.addAriaAndCollapsedClass = function ($element, $trigger) {
764
+ var isOpen = $element.hasClass('in')
765
+
766
+ $element.attr('aria-expanded', isOpen)
767
+ $trigger
768
+ .toggleClass('collapsed', !isOpen)
769
+ .attr('aria-expanded', isOpen)
770
+ }
771
+
772
+ function getTargetFromTrigger($trigger) {
773
+ var href
774
+ var target = $trigger.attr('data-target')
775
+ || (href = $trigger.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') // strip for ie7
776
+
777
+ return $(target)
778
+ }
779
+
687
780
 
688
781
  // COLLAPSE PLUGIN DEFINITION
689
782
  // ==========================
@@ -694,7 +787,7 @@
694
787
  var data = $this.data('bs.collapse')
695
788
  var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option)
696
789
 
697
- if (!data && options.toggle && option == 'show') option = !option
790
+ if (!data && options.toggle && option == 'show') options.toggle = false
698
791
  if (!data) $this.data('bs.collapse', (data = new Collapse(this, options)))
699
792
  if (typeof option == 'string') data[option]()
700
793
  })
@@ -719,21 +812,13 @@
719
812
  // =================
720
813
 
721
814
  $(document).on('click.bs.collapse.data-api', '[data-toggle="collapse"]', function (e) {
722
- var href
723
815
  var $this = $(this)
724
- var target = $this.attr('data-target')
725
- || e.preventDefault()
726
- || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') // strip for ie7
727
- var $target = $(target)
728
- var data = $target.data('bs.collapse')
729
- var option = data ? 'toggle' : $this.data()
730
- var parent = $this.attr('data-parent')
731
- var $parent = parent && $(parent)
732
816
 
733
- if (!data || !data.transitioning) {
734
- if ($parent) $parent.find('[data-toggle="collapse"][data-parent="' + parent + '"]').not($this).addClass('collapsed')
735
- $this[$target.hasClass('in') ? 'addClass' : 'removeClass']('collapsed')
736
- }
817
+ if (!$this.attr('data-target')) e.preventDefault()
818
+
819
+ var $target = getTargetFromTrigger($this)
820
+ var data = $target.data('bs.collapse')
821
+ var option = data ? 'toggle' : $.extend({}, $this.data(), { trigger: this })
737
822
 
738
823
  Plugin.call($target, option)
739
824
  })
@@ -741,7 +826,7 @@
741
826
  }(jQuery);
742
827
 
743
828
  /* ========================================================================
744
- * Bootstrap: dropdown.js v3.2.0
829
+ * Bootstrap: dropdown.js v3.3.0
745
830
  * http://getbootstrap.com/javascript/#dropdowns
746
831
  * ========================================================================
747
832
  * Copyright 2011-2014 Twitter, Inc.
@@ -761,7 +846,7 @@
761
846
  $(element).on('click.bs.dropdown', this.toggle)
762
847
  }
763
848
 
764
- Dropdown.VERSION = '3.2.0'
849
+ Dropdown.VERSION = '3.3.0'
765
850
 
766
851
  Dropdown.prototype.toggle = function (e) {
767
852
  var $this = $(this)
@@ -784,7 +869,9 @@
784
869
 
785
870
  if (e.isDefaultPrevented()) return
786
871
 
787
- $this.trigger('focus')
872
+ $this
873
+ .trigger('focus')
874
+ .attr('aria-expanded', 'true')
788
875
 
789
876
  $parent
790
877
  .toggleClass('open')
@@ -795,7 +882,7 @@
795
882
  }
796
883
 
797
884
  Dropdown.prototype.keydown = function (e) {
798
- if (!/(38|40|27)/.test(e.keyCode)) return
885
+ if (!/(38|40|27|32)/.test(e.which)) return
799
886
 
800
887
  var $this = $(this)
801
888
 
@@ -807,7 +894,7 @@
807
894
  var $parent = getParent($this)
808
895
  var isActive = $parent.hasClass('open')
809
896
 
810
- if (!isActive || (isActive && e.keyCode == 27)) {
897
+ if ((!isActive && e.which != 27) || (isActive && e.which == 27)) {
811
898
  if (e.which == 27) $parent.find(toggle).trigger('focus')
812
899
  return $this.trigger('click')
813
900
  }
@@ -817,10 +904,10 @@
817
904
 
818
905
  if (!$items.length) return
819
906
 
820
- var index = $items.index($items.filter(':focus'))
907
+ var index = $items.index(e.target)
821
908
 
822
- if (e.keyCode == 38 && index > 0) index-- // up
823
- if (e.keyCode == 40 && index < $items.length - 1) index++ // down
909
+ if (e.which == 38 && index > 0) index-- // up
910
+ if (e.which == 40 && index < $items.length - 1) index++ // down
824
911
  if (!~index) index = 0
825
912
 
826
913
  $items.eq(index).trigger('focus')
@@ -830,11 +917,17 @@
830
917
  if (e && e.which === 3) return
831
918
  $(backdrop).remove()
832
919
  $(toggle).each(function () {
833
- var $parent = getParent($(this))
920
+ var $this = $(this)
921
+ var $parent = getParent($this)
834
922
  var relatedTarget = { relatedTarget: this }
923
+
835
924
  if (!$parent.hasClass('open')) return
925
+
836
926
  $parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
927
+
837
928
  if (e.isDefaultPrevented()) return
929
+
930
+ $this.attr('aria-expanded', 'false')
838
931
  $parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
839
932
  })
840
933
  }
@@ -888,12 +981,14 @@
888
981
  .on('click.bs.dropdown.data-api', clearMenus)
889
982
  .on('click.bs.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() })
890
983
  .on('click.bs.dropdown.data-api', toggle, Dropdown.prototype.toggle)
891
- .on('keydown.bs.dropdown.data-api', toggle + ', [role="menu"], [role="listbox"]', Dropdown.prototype.keydown)
984
+ .on('keydown.bs.dropdown.data-api', toggle, Dropdown.prototype.keydown)
985
+ .on('keydown.bs.dropdown.data-api', '[role="menu"]', Dropdown.prototype.keydown)
986
+ .on('keydown.bs.dropdown.data-api', '[role="listbox"]', Dropdown.prototype.keydown)
892
987
 
893
988
  }(jQuery);
894
989
 
895
990
  /* ========================================================================
896
- * Bootstrap: tab.js v3.2.0
991
+ * Bootstrap: tab.js v3.3.0
897
992
  * http://getbootstrap.com/javascript/#tabs
898
993
  * ========================================================================
899
994
  * Copyright 2011-2014 Twitter, Inc.
@@ -911,7 +1006,9 @@
911
1006
  this.element = $(element)
912
1007
  }
913
1008
 
914
- Tab.VERSION = '3.2.0'
1009
+ Tab.VERSION = '3.3.0'
1010
+
1011
+ Tab.TRANSITION_DURATION = 150
915
1012
 
916
1013
  Tab.prototype.show = function () {
917
1014
  var $this = this.element
@@ -925,22 +1022,30 @@
925
1022
 
926
1023
  if ($this.parent('li').hasClass('active')) return
927
1024
 
928
- var previous = $ul.find('.active:last a')[0]
929
- var e = $.Event('show.bs.tab', {
930
- relatedTarget: previous
1025
+ var $previous = $ul.find('.active:last a')
1026
+ var hideEvent = $.Event('hide.bs.tab', {
1027
+ relatedTarget: $this[0]
1028
+ })
1029
+ var showEvent = $.Event('show.bs.tab', {
1030
+ relatedTarget: $previous[0]
931
1031
  })
932
1032
 
933
- $this.trigger(e)
1033
+ $previous.trigger(hideEvent)
1034
+ $this.trigger(showEvent)
934
1035
 
935
- if (e.isDefaultPrevented()) return
1036
+ if (showEvent.isDefaultPrevented() || hideEvent.isDefaultPrevented()) return
936
1037
 
937
1038
  var $target = $(selector)
938
1039
 
939
1040
  this.activate($this.closest('li'), $ul)
940
1041
  this.activate($target, $target.parent(), function () {
1042
+ $previous.trigger({
1043
+ type: 'hidden.bs.tab',
1044
+ relatedTarget: $this[0]
1045
+ })
941
1046
  $this.trigger({
942
1047
  type: 'shown.bs.tab',
943
- relatedTarget: previous
1048
+ relatedTarget: $previous[0]
944
1049
  })
945
1050
  })
946
1051
  }
@@ -949,15 +1054,21 @@
949
1054
  var $active = container.find('> .active')
950
1055
  var transition = callback
951
1056
  && $.support.transition
952
- && $active.hasClass('fade')
1057
+ && (($active.length && $active.hasClass('fade')) || !!container.find('> .fade').length)
953
1058
 
954
1059
  function next() {
955
1060
  $active
956
1061
  .removeClass('active')
957
1062
  .find('> .dropdown-menu > .active')
958
- .removeClass('active')
1063
+ .removeClass('active')
1064
+ .end()
1065
+ .find('[data-toggle="tab"]')
1066
+ .attr('aria-expanded', false)
959
1067
 
960
- element.addClass('active')
1068
+ element
1069
+ .addClass('active')
1070
+ .find('[data-toggle="tab"]')
1071
+ .attr('aria-expanded', true)
961
1072
 
962
1073
  if (transition) {
963
1074
  element[0].offsetWidth // reflow for transition
@@ -967,16 +1078,21 @@
967
1078
  }
968
1079
 
969
1080
  if (element.parent('.dropdown-menu')) {
970
- element.closest('li.dropdown').addClass('active')
1081
+ element
1082
+ .closest('li.dropdown')
1083
+ .addClass('active')
1084
+ .end()
1085
+ .find('[data-toggle="tab"]')
1086
+ .attr('aria-expanded', true)
971
1087
  }
972
1088
 
973
1089
  callback && callback()
974
1090
  }
975
1091
 
976
- transition ?
1092
+ $active.length && transition ?
977
1093
  $active
978
1094
  .one('bsTransitionEnd', next)
979
- .emulateTransitionEnd(150) :
1095
+ .emulateTransitionEnd(Tab.TRANSITION_DURATION) :
980
1096
  next()
981
1097
 
982
1098
  $active.removeClass('in')
@@ -1014,15 +1130,19 @@
1014
1130
  // TAB DATA-API
1015
1131
  // ============
1016
1132
 
1017
- $(document).on('click.bs.tab.data-api', '[data-toggle="tab"], [data-toggle="pill"]', function (e) {
1133
+ var clickHandler = function (e) {
1018
1134
  e.preventDefault()
1019
1135
  Plugin.call($(this), 'show')
1020
- })
1136
+ }
1137
+
1138
+ $(document)
1139
+ .on('click.bs.tab.data-api', '[data-toggle="tab"]', clickHandler)
1140
+ .on('click.bs.tab.data-api', '[data-toggle="pill"]', clickHandler)
1021
1141
 
1022
1142
  }(jQuery);
1023
1143
 
1024
1144
  /* ========================================================================
1025
- * Bootstrap: transition.js v3.2.0
1145
+ * Bootstrap: transition.js v3.3.0
1026
1146
  * http://getbootstrap.com/javascript/#transitions
1027
1147
  * ========================================================================
1028
1148
  * Copyright 2011-2014 Twitter, Inc.
@@ -1082,7 +1202,7 @@
1082
1202
  }(jQuery);
1083
1203
 
1084
1204
  /* ========================================================================
1085
- * Bootstrap: scrollspy.js v3.2.0
1205
+ * Bootstrap: scrollspy.js v3.3.0
1086
1206
  * http://getbootstrap.com/javascript/#scrollspy
1087
1207
  * ========================================================================
1088
1208
  * Copyright 2011-2014 Twitter, Inc.
@@ -1113,7 +1233,7 @@
1113
1233
  this.process()
1114
1234
  }
1115
1235
 
1116
- ScrollSpy.VERSION = '3.2.0'
1236
+ ScrollSpy.VERSION = '3.3.0'
1117
1237
 
1118
1238
  ScrollSpy.DEFAULTS = {
1119
1239
  offset: 10
@@ -1174,8 +1294,9 @@
1174
1294
  return activeTarget != (i = targets[targets.length - 1]) && this.activate(i)
1175
1295
  }
1176
1296
 
1177
- if (activeTarget && scrollTop <= offsets[0]) {
1178
- return activeTarget != (i = targets[0]) && this.activate(i)
1297
+ if (activeTarget && scrollTop < offsets[0]) {
1298
+ this.activeTarget = null
1299
+ return this.clear()
1179
1300
  }
1180
1301
 
1181
1302
  for (i = offsets.length; i--;) {
@@ -1189,9 +1310,7 @@
1189
1310
  ScrollSpy.prototype.activate = function (target) {
1190
1311
  this.activeTarget = target
1191
1312
 
1192
- $(this.selector)
1193
- .parentsUntil(this.options.target, '.active')
1194
- .removeClass('active')
1313
+ this.clear()
1195
1314
 
1196
1315
  var selector = this.selector +
1197
1316
  '[data-target="' + target + '"],' +
@@ -1210,6 +1329,12 @@
1210
1329
  active.trigger('activate.bs.scrollspy')
1211
1330
  }
1212
1331
 
1332
+ ScrollSpy.prototype.clear = function () {
1333
+ $(this.selector)
1334
+ .parentsUntil(this.options.target, '.active')
1335
+ .removeClass('active')
1336
+ }
1337
+
1213
1338
 
1214
1339
  // SCROLLSPY PLUGIN DEFINITION
1215
1340
  // ===========================
@@ -1253,7 +1378,7 @@
1253
1378
  }(jQuery);
1254
1379
 
1255
1380
  /* ========================================================================
1256
- * Bootstrap: modal.js v3.2.0
1381
+ * Bootstrap: modal.js v3.3.0
1257
1382
  * http://getbootstrap.com/javascript/#modals
1258
1383
  * ========================================================================
1259
1384
  * Copyright 2011-2014 Twitter, Inc.
@@ -1284,7 +1409,10 @@
1284
1409
  }
1285
1410
  }
1286
1411
 
1287
- Modal.VERSION = '3.2.0'
1412
+ Modal.VERSION = '3.3.0'
1413
+
1414
+ Modal.TRANSITION_DURATION = 300
1415
+ Modal.BACKDROP_TRANSITION_DURATION = 150
1288
1416
 
1289
1417
  Modal.DEFAULTS = {
1290
1418
  backdrop: true,
@@ -1342,7 +1470,7 @@
1342
1470
  .one('bsTransitionEnd', function () {
1343
1471
  that.$element.trigger('focus').trigger(e)
1344
1472
  })
1345
- .emulateTransitionEnd(300) :
1473
+ .emulateTransitionEnd(Modal.TRANSITION_DURATION) :
1346
1474
  that.$element.trigger('focus').trigger(e)
1347
1475
  })
1348
1476
  }
@@ -1358,9 +1486,6 @@
1358
1486
 
1359
1487
  this.isShown = false
1360
1488
 
1361
- this.$body.removeClass('modal-open')
1362
-
1363
- this.resetScrollbar()
1364
1489
  this.escape()
1365
1490
 
1366
1491
  $(document).off('focusin.bs.modal')
@@ -1373,7 +1498,7 @@
1373
1498
  $.support.transition && this.$element.hasClass('fade') ?
1374
1499
  this.$element
1375
1500
  .one('bsTransitionEnd', $.proxy(this.hideModal, this))
1376
- .emulateTransitionEnd(300) :
1501
+ .emulateTransitionEnd(Modal.TRANSITION_DURATION) :
1377
1502
  this.hideModal()
1378
1503
  }
1379
1504
 
@@ -1389,11 +1514,11 @@
1389
1514
 
1390
1515
  Modal.prototype.escape = function () {
1391
1516
  if (this.isShown && this.options.keyboard) {
1392
- this.$element.on('keyup.dismiss.bs.modal', $.proxy(function (e) {
1517
+ this.$element.on('keydown.dismiss.bs.modal', $.proxy(function (e) {
1393
1518
  e.which == 27 && this.hide()
1394
1519
  }, this))
1395
1520
  } else if (!this.isShown) {
1396
- this.$element.off('keyup.dismiss.bs.modal')
1521
+ this.$element.off('keydown.dismiss.bs.modal')
1397
1522
  }
1398
1523
  }
1399
1524
 
@@ -1401,6 +1526,8 @@
1401
1526
  var that = this
1402
1527
  this.$element.hide()
1403
1528
  this.backdrop(function () {
1529
+ that.$body.removeClass('modal-open')
1530
+ that.resetScrollbar()
1404
1531
  that.$element.trigger('hidden.bs.modal')
1405
1532
  })
1406
1533
  }
@@ -1418,14 +1545,13 @@
1418
1545
  var doAnimate = $.support.transition && animate
1419
1546
 
1420
1547
  this.$backdrop = $('<div class="modal-backdrop ' + animate + '" />')
1421
- .appendTo(this.$body)
1422
-
1423
- this.$element.on('click.dismiss.bs.modal', $.proxy(function (e) {
1424
- if (e.target !== e.currentTarget) return
1425
- this.options.backdrop == 'static'
1426
- ? this.$element[0].focus.call(this.$element[0])
1427
- : this.hide.call(this)
1428
- }, this))
1548
+ .prependTo(this.$element)
1549
+ .on('click.dismiss.bs.modal', $.proxy(function (e) {
1550
+ if (e.target !== e.currentTarget) return
1551
+ this.options.backdrop == 'static'
1552
+ ? this.$element[0].focus.call(this.$element[0])
1553
+ : this.hide.call(this)
1554
+ }, this))
1429
1555
 
1430
1556
  if (doAnimate) this.$backdrop[0].offsetWidth // force reflow
1431
1557
 
@@ -1436,7 +1562,7 @@
1436
1562
  doAnimate ?
1437
1563
  this.$backdrop
1438
1564
  .one('bsTransitionEnd', callback)
1439
- .emulateTransitionEnd(150) :
1565
+ .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) :
1440
1566
  callback()
1441
1567
 
1442
1568
  } else if (!this.isShown && this.$backdrop) {
@@ -1449,7 +1575,7 @@
1449
1575
  $.support.transition && this.$element.hasClass('fade') ?
1450
1576
  this.$backdrop
1451
1577
  .one('bsTransitionEnd', callbackRemove)
1452
- .emulateTransitionEnd(150) :
1578
+ .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) :
1453
1579
  callbackRemove()
1454
1580
 
1455
1581
  } else if (callback) {
@@ -1458,8 +1584,7 @@
1458
1584
  }
1459
1585
 
1460
1586
  Modal.prototype.checkScrollbar = function () {
1461
- if (document.body.clientWidth >= window.innerWidth) return
1462
- this.scrollbarWidth = this.scrollbarWidth || this.measureScrollbar()
1587
+ this.scrollbarWidth = this.measureScrollbar()
1463
1588
  }
1464
1589
 
1465
1590
  Modal.prototype.setScrollbar = function () {
@@ -1472,6 +1597,7 @@
1472
1597
  }
1473
1598
 
1474
1599
  Modal.prototype.measureScrollbar = function () { // thx walsh
1600
+ if (document.body.clientWidth >= window.innerWidth) return 0
1475
1601
  var scrollDiv = document.createElement('div')
1476
1602
  scrollDiv.className = 'modal-scrollbar-measure'
1477
1603
  this.$body.append(scrollDiv)
@@ -1534,7 +1660,7 @@
1534
1660
  }(jQuery);
1535
1661
 
1536
1662
  /* ========================================================================
1537
- * Bootstrap: tooltip.js v3.2.0
1663
+ * Bootstrap: tooltip.js v3.3.0
1538
1664
  * http://getbootstrap.com/javascript/#tooltip
1539
1665
  * Inspired by the original jQuery.tipsy by Jason Frame
1540
1666
  * ========================================================================
@@ -1560,7 +1686,9 @@
1560
1686
  this.init('tooltip', element, options)
1561
1687
  }
1562
1688
 
1563
- Tooltip.VERSION = '3.2.0'
1689
+ Tooltip.VERSION = '3.3.0'
1690
+
1691
+ Tooltip.TRANSITION_DURATION = 150
1564
1692
 
1565
1693
  Tooltip.DEFAULTS = {
1566
1694
  animation: true,
@@ -1638,6 +1766,11 @@
1638
1766
  var self = obj instanceof this.constructor ?
1639
1767
  obj : $(obj.currentTarget).data('bs.' + this.type)
1640
1768
 
1769
+ if (self && self.$tip && self.$tip.is(':visible')) {
1770
+ self.hoverState = 'in'
1771
+ return
1772
+ }
1773
+
1641
1774
  if (!self) {
1642
1775
  self = new this.constructor(obj.currentTarget, this.getDelegateOptions())
1643
1776
  $(obj.currentTarget).data('bs.' + this.type, self)
@@ -1680,7 +1813,7 @@
1680
1813
  if (this.hasContent() && this.enabled) {
1681
1814
  this.$element.trigger(e)
1682
1815
 
1683
- var inDom = $.contains(document.documentElement, this.$element[0])
1816
+ var inDom = $.contains(this.$element[0].ownerDocument.documentElement, this.$element[0])
1684
1817
  if (e.isDefaultPrevented() || !inDom) return
1685
1818
  var that = this
1686
1819
 
@@ -1716,13 +1849,13 @@
1716
1849
 
1717
1850
  if (autoPlace) {
1718
1851
  var orgPlacement = placement
1719
- var $parent = this.$element.parent()
1720
- var parentDim = this.getPosition($parent)
1852
+ var $container = this.options.container ? $(this.options.container) : this.$element.parent()
1853
+ var containerDim = this.getPosition($container)
1721
1854
 
1722
- placement = placement == 'bottom' && pos.top + pos.height + actualHeight - parentDim.scroll > parentDim.height ? 'top' :
1723
- placement == 'top' && pos.top - parentDim.scroll - actualHeight < 0 ? 'bottom' :
1724
- placement == 'right' && pos.right + actualWidth > parentDim.width ? 'left' :
1725
- placement == 'left' && pos.left - actualWidth < parentDim.left ? 'right' :
1855
+ placement = placement == 'bottom' && pos.bottom + actualHeight > containerDim.bottom ? 'top' :
1856
+ placement == 'top' && pos.top - actualHeight < containerDim.top ? 'bottom' :
1857
+ placement == 'right' && pos.right + actualWidth > containerDim.width ? 'left' :
1858
+ placement == 'left' && pos.left - actualWidth < containerDim.left ? 'right' :
1726
1859
  placement
1727
1860
 
1728
1861
  $tip
@@ -1735,14 +1868,17 @@
1735
1868
  this.applyPlacement(calculatedOffset, placement)
1736
1869
 
1737
1870
  var complete = function () {
1871
+ var prevHoverState = that.hoverState
1738
1872
  that.$element.trigger('shown.bs.' + that.type)
1739
1873
  that.hoverState = null
1874
+
1875
+ if (prevHoverState == 'out') that.leave(that)
1740
1876
  }
1741
1877
 
1742
1878
  $.support.transition && this.$tip.hasClass('fade') ?
1743
1879
  $tip
1744
1880
  .one('bsTransitionEnd', complete)
1745
- .emulateTransitionEnd(150) :
1881
+ .emulateTransitionEnd(Tooltip.TRANSITION_DURATION) :
1746
1882
  complete()
1747
1883
  }
1748
1884
  }
@@ -1789,16 +1925,18 @@
1789
1925
  if (delta.left) offset.left += delta.left
1790
1926
  else offset.top += delta.top
1791
1927
 
1792
- var arrowDelta = delta.left ? delta.left * 2 - width + actualWidth : delta.top * 2 - height + actualHeight
1793
- var arrowPosition = delta.left ? 'left' : 'top'
1794
- var arrowOffsetPosition = delta.left ? 'offsetWidth' : 'offsetHeight'
1928
+ var isVertical = /top|bottom/.test(placement)
1929
+ var arrowDelta = isVertical ? delta.left * 2 - width + actualWidth : delta.top * 2 - height + actualHeight
1930
+ var arrowOffsetPosition = isVertical ? 'offsetWidth' : 'offsetHeight'
1795
1931
 
1796
1932
  $tip.offset(offset)
1797
- this.replaceArrow(arrowDelta, $tip[0][arrowOffsetPosition], arrowPosition)
1933
+ this.replaceArrow(arrowDelta, $tip[0][arrowOffsetPosition], isVertical)
1798
1934
  }
1799
1935
 
1800
- Tooltip.prototype.replaceArrow = function (delta, dimension, position) {
1801
- this.arrow().css(position, delta ? (50 * (1 - delta / dimension) + '%') : '')
1936
+ Tooltip.prototype.replaceArrow = function (delta, dimension, isHorizontal) {
1937
+ this.arrow()
1938
+ .css(isHorizontal ? 'left' : 'top', 50 * (1 - delta / dimension) + '%')
1939
+ .css(isHorizontal ? 'top' : 'left', '')
1802
1940
  }
1803
1941
 
1804
1942
  Tooltip.prototype.setContent = function () {
@@ -1809,16 +1947,17 @@
1809
1947
  $tip.removeClass('fade in top bottom left right')
1810
1948
  }
1811
1949
 
1812
- Tooltip.prototype.hide = function () {
1950
+ Tooltip.prototype.hide = function (callback) {
1813
1951
  var that = this
1814
1952
  var $tip = this.tip()
1815
1953
  var e = $.Event('hide.bs.' + this.type)
1816
1954
 
1817
- this.$element.removeAttr('aria-describedby')
1818
-
1819
1955
  function complete() {
1820
1956
  if (that.hoverState != 'in') $tip.detach()
1821
- that.$element.trigger('hidden.bs.' + that.type)
1957
+ that.$element
1958
+ .removeAttr('aria-describedby')
1959
+ .trigger('hidden.bs.' + that.type)
1960
+ callback && callback()
1822
1961
  }
1823
1962
 
1824
1963
  this.$element.trigger(e)
@@ -1830,7 +1969,7 @@
1830
1969
  $.support.transition && this.$tip.hasClass('fade') ?
1831
1970
  $tip
1832
1971
  .one('bsTransitionEnd', complete)
1833
- .emulateTransitionEnd(150) :
1972
+ .emulateTransitionEnd(Tooltip.TRANSITION_DURATION) :
1834
1973
  complete()
1835
1974
 
1836
1975
  this.hoverState = null
@@ -1851,13 +1990,20 @@
1851
1990
 
1852
1991
  Tooltip.prototype.getPosition = function ($element) {
1853
1992
  $element = $element || this.$element
1993
+
1854
1994
  var el = $element[0]
1855
1995
  var isBody = el.tagName == 'BODY'
1856
- return $.extend({}, (typeof el.getBoundingClientRect == 'function') ? el.getBoundingClientRect() : null, {
1857
- scroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop : $element.scrollTop(),
1858
- width: isBody ? $(window).width() : $element.outerWidth(),
1859
- height: isBody ? $(window).height() : $element.outerHeight()
1860
- }, isBody ? { top: 0, left: 0 } : $element.offset())
1996
+
1997
+ var elRect = el.getBoundingClientRect()
1998
+ if (elRect.width == null) {
1999
+ // width and height are missing in IE8, so compute them manually; see https://github.com/twbs/bootstrap/issues/14093
2000
+ elRect = $.extend({}, elRect, { width: elRect.right - elRect.left, height: elRect.bottom - elRect.top })
2001
+ }
2002
+ var elOffset = isBody ? { top: 0, left: 0 } : $element.offset()
2003
+ var scroll = { scroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop : $element.scrollTop() }
2004
+ var outerDims = isBody ? { width: $(window).width(), height: $(window).height() } : null
2005
+
2006
+ return $.extend({}, elRect, scroll, outerDims, elOffset)
1861
2007
  }
1862
2008
 
1863
2009
  Tooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight) {
@@ -1921,14 +2067,6 @@
1921
2067
  return (this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow'))
1922
2068
  }
1923
2069
 
1924
- Tooltip.prototype.validate = function () {
1925
- if (!this.$element[0].parentNode) {
1926
- this.hide()
1927
- this.$element = null
1928
- this.options = null
1929
- }
1930
- }
1931
-
1932
2070
  Tooltip.prototype.enable = function () {
1933
2071
  this.enabled = true
1934
2072
  }
@@ -1955,8 +2093,11 @@
1955
2093
  }
1956
2094
 
1957
2095
  Tooltip.prototype.destroy = function () {
2096
+ var that = this
1958
2097
  clearTimeout(this.timeout)
1959
- this.hide().$element.off('.' + this.type).removeData('bs.' + this.type)
2098
+ this.hide(function () {
2099
+ that.$element.off('.' + that.type).removeData('bs.' + that.type)
2100
+ })
1960
2101
  }
1961
2102
 
1962
2103
 
@@ -1965,12 +2106,18 @@
1965
2106
 
1966
2107
  function Plugin(option) {
1967
2108
  return this.each(function () {
1968
- var $this = $(this)
1969
- var data = $this.data('bs.tooltip')
1970
- var options = typeof option == 'object' && option
2109
+ var $this = $(this)
2110
+ var data = $this.data('bs.tooltip')
2111
+ var options = typeof option == 'object' && option
2112
+ var selector = options && options.selector
1971
2113
 
1972
2114
  if (!data && option == 'destroy') return
1973
- if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options)))
2115
+ if (selector) {
2116
+ if (!data) $this.data('bs.tooltip', (data = {}))
2117
+ if (!data[selector]) data[selector] = new Tooltip(this, options)
2118
+ } else {
2119
+ if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options)))
2120
+ }
1974
2121
  if (typeof option == 'string') data[option]()
1975
2122
  })
1976
2123
  }
@@ -1992,7 +2139,7 @@
1992
2139
  }(jQuery);
1993
2140
 
1994
2141
  /* ========================================================================
1995
- * Bootstrap: popover.js v3.2.0
2142
+ * Bootstrap: popover.js v3.3.0
1996
2143
  * http://getbootstrap.com/javascript/#popovers
1997
2144
  * ========================================================================
1998
2145
  * Copyright 2011-2014 Twitter, Inc.
@@ -2012,7 +2159,7 @@
2012
2159
 
2013
2160
  if (!$.fn.tooltip) throw new Error('Popover requires tooltip.js')
2014
2161
 
2015
- Popover.VERSION = '3.2.0'
2162
+ Popover.VERSION = '3.3.0'
2016
2163
 
2017
2164
  Popover.DEFAULTS = $.extend({}, $.fn.tooltip.Constructor.DEFAULTS, {
2018
2165
  placement: 'right',
@@ -2039,7 +2186,7 @@
2039
2186
  var content = this.getContent()
2040
2187
 
2041
2188
  $tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title)
2042
- $tip.find('.popover-content').empty()[ // we use append for html objects to maintain js events
2189
+ $tip.find('.popover-content').children().detach().end()[ // we use append for html objects to maintain js events
2043
2190
  this.options.html ? (typeof content == 'string' ? 'html' : 'append') : 'text'
2044
2191
  ](content)
2045
2192
 
@@ -2079,12 +2226,18 @@
2079
2226
 
2080
2227
  function Plugin(option) {
2081
2228
  return this.each(function () {
2082
- var $this = $(this)
2083
- var data = $this.data('bs.popover')
2084
- var options = typeof option == 'object' && option
2229
+ var $this = $(this)
2230
+ var data = $this.data('bs.popover')
2231
+ var options = typeof option == 'object' && option
2232
+ var selector = options && options.selector
2085
2233
 
2086
2234
  if (!data && option == 'destroy') return
2087
- if (!data) $this.data('bs.popover', (data = new Popover(this, options)))
2235
+ if (selector) {
2236
+ if (!data) $this.data('bs.popover', (data = {}))
2237
+ if (!data[selector]) data[selector] = new Popover(this, options)
2238
+ } else {
2239
+ if (!data) $this.data('bs.popover', (data = new Popover(this, options)))
2240
+ }
2088
2241
  if (typeof option == 'string') data[option]()
2089
2242
  })
2090
2243
  }