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
@@ -1,5 +1,5 @@
1
1
  /* ========================================================================
2
- * Bootstrap: dropdown.js v3.2.0
2
+ * Bootstrap: dropdown.js v3.3.0
3
3
  * http://getbootstrap.com/javascript/#dropdowns
4
4
  * ========================================================================
5
5
  * Copyright 2011-2014 Twitter, Inc.
@@ -19,7 +19,7 @@
19
19
  $(element).on('click.bs.dropdown', this.toggle)
20
20
  }
21
21
 
22
- Dropdown.VERSION = '3.2.0'
22
+ Dropdown.VERSION = '3.3.0'
23
23
 
24
24
  Dropdown.prototype.toggle = function (e) {
25
25
  var $this = $(this)
@@ -42,7 +42,9 @@
42
42
 
43
43
  if (e.isDefaultPrevented()) return
44
44
 
45
- $this.trigger('focus')
45
+ $this
46
+ .trigger('focus')
47
+ .attr('aria-expanded', 'true')
46
48
 
47
49
  $parent
48
50
  .toggleClass('open')
@@ -53,7 +55,7 @@
53
55
  }
54
56
 
55
57
  Dropdown.prototype.keydown = function (e) {
56
- if (!/(38|40|27)/.test(e.keyCode)) return
58
+ if (!/(38|40|27|32)/.test(e.which)) return
57
59
 
58
60
  var $this = $(this)
59
61
 
@@ -65,7 +67,7 @@
65
67
  var $parent = getParent($this)
66
68
  var isActive = $parent.hasClass('open')
67
69
 
68
- if (!isActive || (isActive && e.keyCode == 27)) {
70
+ if ((!isActive && e.which != 27) || (isActive && e.which == 27)) {
69
71
  if (e.which == 27) $parent.find(toggle).trigger('focus')
70
72
  return $this.trigger('click')
71
73
  }
@@ -75,10 +77,10 @@
75
77
 
76
78
  if (!$items.length) return
77
79
 
78
- var index = $items.index($items.filter(':focus'))
80
+ var index = $items.index(e.target)
79
81
 
80
- if (e.keyCode == 38 && index > 0) index-- // up
81
- if (e.keyCode == 40 && index < $items.length - 1) index++ // down
82
+ if (e.which == 38 && index > 0) index-- // up
83
+ if (e.which == 40 && index < $items.length - 1) index++ // down
82
84
  if (!~index) index = 0
83
85
 
84
86
  $items.eq(index).trigger('focus')
@@ -88,11 +90,17 @@
88
90
  if (e && e.which === 3) return
89
91
  $(backdrop).remove()
90
92
  $(toggle).each(function () {
91
- var $parent = getParent($(this))
93
+ var $this = $(this)
94
+ var $parent = getParent($this)
92
95
  var relatedTarget = { relatedTarget: this }
96
+
93
97
  if (!$parent.hasClass('open')) return
98
+
94
99
  $parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
100
+
95
101
  if (e.isDefaultPrevented()) return
102
+
103
+ $this.attr('aria-expanded', 'false')
96
104
  $parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
97
105
  })
98
106
  }
@@ -146,6 +154,8 @@
146
154
  .on('click.bs.dropdown.data-api', clearMenus)
147
155
  .on('click.bs.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() })
148
156
  .on('click.bs.dropdown.data-api', toggle, Dropdown.prototype.toggle)
149
- .on('keydown.bs.dropdown.data-api', toggle + ', [role="menu"], [role="listbox"]', Dropdown.prototype.keydown)
157
+ .on('keydown.bs.dropdown.data-api', toggle, Dropdown.prototype.keydown)
158
+ .on('keydown.bs.dropdown.data-api', '[role="menu"]', Dropdown.prototype.keydown)
159
+ .on('keydown.bs.dropdown.data-api', '[role="listbox"]', Dropdown.prototype.keydown)
150
160
 
151
161
  }(jQuery);
@@ -1,5 +1,5 @@
1
1
  /* ========================================================================
2
- * Bootstrap: modal.js v3.2.0
2
+ * Bootstrap: modal.js v3.3.0
3
3
  * http://getbootstrap.com/javascript/#modals
4
4
  * ========================================================================
5
5
  * Copyright 2011-2014 Twitter, Inc.
@@ -30,7 +30,10 @@
30
30
  }
31
31
  }
32
32
 
33
- Modal.VERSION = '3.2.0'
33
+ Modal.VERSION = '3.3.0'
34
+
35
+ Modal.TRANSITION_DURATION = 300
36
+ Modal.BACKDROP_TRANSITION_DURATION = 150
34
37
 
35
38
  Modal.DEFAULTS = {
36
39
  backdrop: true,
@@ -88,7 +91,7 @@
88
91
  .one('bsTransitionEnd', function () {
89
92
  that.$element.trigger('focus').trigger(e)
90
93
  })
91
- .emulateTransitionEnd(300) :
94
+ .emulateTransitionEnd(Modal.TRANSITION_DURATION) :
92
95
  that.$element.trigger('focus').trigger(e)
93
96
  })
94
97
  }
@@ -104,9 +107,6 @@
104
107
 
105
108
  this.isShown = false
106
109
 
107
- this.$body.removeClass('modal-open')
108
-
109
- this.resetScrollbar()
110
110
  this.escape()
111
111
 
112
112
  $(document).off('focusin.bs.modal')
@@ -119,7 +119,7 @@
119
119
  $.support.transition && this.$element.hasClass('fade') ?
120
120
  this.$element
121
121
  .one('bsTransitionEnd', $.proxy(this.hideModal, this))
122
- .emulateTransitionEnd(300) :
122
+ .emulateTransitionEnd(Modal.TRANSITION_DURATION) :
123
123
  this.hideModal()
124
124
  }
125
125
 
@@ -135,11 +135,11 @@
135
135
 
136
136
  Modal.prototype.escape = function () {
137
137
  if (this.isShown && this.options.keyboard) {
138
- this.$element.on('keyup.dismiss.bs.modal', $.proxy(function (e) {
138
+ this.$element.on('keydown.dismiss.bs.modal', $.proxy(function (e) {
139
139
  e.which == 27 && this.hide()
140
140
  }, this))
141
141
  } else if (!this.isShown) {
142
- this.$element.off('keyup.dismiss.bs.modal')
142
+ this.$element.off('keydown.dismiss.bs.modal')
143
143
  }
144
144
  }
145
145
 
@@ -147,6 +147,8 @@
147
147
  var that = this
148
148
  this.$element.hide()
149
149
  this.backdrop(function () {
150
+ that.$body.removeClass('modal-open')
151
+ that.resetScrollbar()
150
152
  that.$element.trigger('hidden.bs.modal')
151
153
  })
152
154
  }
@@ -164,14 +166,13 @@
164
166
  var doAnimate = $.support.transition && animate
165
167
 
166
168
  this.$backdrop = $('<div class="modal-backdrop ' + animate + '" />')
167
- .appendTo(this.$body)
168
-
169
- this.$element.on('click.dismiss.bs.modal', $.proxy(function (e) {
170
- if (e.target !== e.currentTarget) return
171
- this.options.backdrop == 'static'
172
- ? this.$element[0].focus.call(this.$element[0])
173
- : this.hide.call(this)
174
- }, this))
169
+ .prependTo(this.$element)
170
+ .on('click.dismiss.bs.modal', $.proxy(function (e) {
171
+ if (e.target !== e.currentTarget) return
172
+ this.options.backdrop == 'static'
173
+ ? this.$element[0].focus.call(this.$element[0])
174
+ : this.hide.call(this)
175
+ }, this))
175
176
 
176
177
  if (doAnimate) this.$backdrop[0].offsetWidth // force reflow
177
178
 
@@ -182,7 +183,7 @@
182
183
  doAnimate ?
183
184
  this.$backdrop
184
185
  .one('bsTransitionEnd', callback)
185
- .emulateTransitionEnd(150) :
186
+ .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) :
186
187
  callback()
187
188
 
188
189
  } else if (!this.isShown && this.$backdrop) {
@@ -195,7 +196,7 @@
195
196
  $.support.transition && this.$element.hasClass('fade') ?
196
197
  this.$backdrop
197
198
  .one('bsTransitionEnd', callbackRemove)
198
- .emulateTransitionEnd(150) :
199
+ .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) :
199
200
  callbackRemove()
200
201
 
201
202
  } else if (callback) {
@@ -204,8 +205,7 @@
204
205
  }
205
206
 
206
207
  Modal.prototype.checkScrollbar = function () {
207
- if (document.body.clientWidth >= window.innerWidth) return
208
- this.scrollbarWidth = this.scrollbarWidth || this.measureScrollbar()
208
+ this.scrollbarWidth = this.measureScrollbar()
209
209
  }
210
210
 
211
211
  Modal.prototype.setScrollbar = function () {
@@ -218,6 +218,7 @@
218
218
  }
219
219
 
220
220
  Modal.prototype.measureScrollbar = function () { // thx walsh
221
+ if (document.body.clientWidth >= window.innerWidth) return 0
221
222
  var scrollDiv = document.createElement('div')
222
223
  scrollDiv.className = 'modal-scrollbar-measure'
223
224
  this.$body.append(scrollDiv)
@@ -1,5 +1,5 @@
1
1
  /* ========================================================================
2
- * Bootstrap: popover.js v3.2.0
2
+ * Bootstrap: popover.js v3.3.0
3
3
  * http://getbootstrap.com/javascript/#popovers
4
4
  * ========================================================================
5
5
  * Copyright 2011-2014 Twitter, Inc.
@@ -19,7 +19,7 @@
19
19
 
20
20
  if (!$.fn.tooltip) throw new Error('Popover requires tooltip.js')
21
21
 
22
- Popover.VERSION = '3.2.0'
22
+ Popover.VERSION = '3.3.0'
23
23
 
24
24
  Popover.DEFAULTS = $.extend({}, $.fn.tooltip.Constructor.DEFAULTS, {
25
25
  placement: 'right',
@@ -46,7 +46,7 @@
46
46
  var content = this.getContent()
47
47
 
48
48
  $tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title)
49
- $tip.find('.popover-content').empty()[ // we use append for html objects to maintain js events
49
+ $tip.find('.popover-content').children().detach().end()[ // we use append for html objects to maintain js events
50
50
  this.options.html ? (typeof content == 'string' ? 'html' : 'append') : 'text'
51
51
  ](content)
52
52
 
@@ -86,12 +86,18 @@
86
86
 
87
87
  function Plugin(option) {
88
88
  return this.each(function () {
89
- var $this = $(this)
90
- var data = $this.data('bs.popover')
91
- var options = typeof option == 'object' && option
89
+ var $this = $(this)
90
+ var data = $this.data('bs.popover')
91
+ var options = typeof option == 'object' && option
92
+ var selector = options && options.selector
92
93
 
93
94
  if (!data && option == 'destroy') return
94
- if (!data) $this.data('bs.popover', (data = new Popover(this, options)))
95
+ if (selector) {
96
+ if (!data) $this.data('bs.popover', (data = {}))
97
+ if (!data[selector]) data[selector] = new Popover(this, options)
98
+ } else {
99
+ if (!data) $this.data('bs.popover', (data = new Popover(this, options)))
100
+ }
95
101
  if (typeof option == 'string') data[option]()
96
102
  })
97
103
  }
@@ -1,5 +1,5 @@
1
1
  /* ========================================================================
2
- * Bootstrap: scrollspy.js v3.2.0
2
+ * Bootstrap: scrollspy.js v3.3.0
3
3
  * http://getbootstrap.com/javascript/#scrollspy
4
4
  * ========================================================================
5
5
  * Copyright 2011-2014 Twitter, Inc.
@@ -30,7 +30,7 @@
30
30
  this.process()
31
31
  }
32
32
 
33
- ScrollSpy.VERSION = '3.2.0'
33
+ ScrollSpy.VERSION = '3.3.0'
34
34
 
35
35
  ScrollSpy.DEFAULTS = {
36
36
  offset: 10
@@ -91,8 +91,9 @@
91
91
  return activeTarget != (i = targets[targets.length - 1]) && this.activate(i)
92
92
  }
93
93
 
94
- if (activeTarget && scrollTop <= offsets[0]) {
95
- return activeTarget != (i = targets[0]) && this.activate(i)
94
+ if (activeTarget && scrollTop < offsets[0]) {
95
+ this.activeTarget = null
96
+ return this.clear()
96
97
  }
97
98
 
98
99
  for (i = offsets.length; i--;) {
@@ -106,9 +107,7 @@
106
107
  ScrollSpy.prototype.activate = function (target) {
107
108
  this.activeTarget = target
108
109
 
109
- $(this.selector)
110
- .parentsUntil(this.options.target, '.active')
111
- .removeClass('active')
110
+ this.clear()
112
111
 
113
112
  var selector = this.selector +
114
113
  '[data-target="' + target + '"],' +
@@ -127,6 +126,12 @@
127
126
  active.trigger('activate.bs.scrollspy')
128
127
  }
129
128
 
129
+ ScrollSpy.prototype.clear = function () {
130
+ $(this.selector)
131
+ .parentsUntil(this.options.target, '.active')
132
+ .removeClass('active')
133
+ }
134
+
130
135
 
131
136
  // SCROLLSPY PLUGIN DEFINITION
132
137
  // ===========================
@@ -1,5 +1,5 @@
1
1
  /* ========================================================================
2
- * Bootstrap: tab.js v3.2.0
2
+ * Bootstrap: tab.js v3.3.0
3
3
  * http://getbootstrap.com/javascript/#tabs
4
4
  * ========================================================================
5
5
  * Copyright 2011-2014 Twitter, Inc.
@@ -17,7 +17,9 @@
17
17
  this.element = $(element)
18
18
  }
19
19
 
20
- Tab.VERSION = '3.2.0'
20
+ Tab.VERSION = '3.3.0'
21
+
22
+ Tab.TRANSITION_DURATION = 150
21
23
 
22
24
  Tab.prototype.show = function () {
23
25
  var $this = this.element
@@ -31,22 +33,30 @@
31
33
 
32
34
  if ($this.parent('li').hasClass('active')) return
33
35
 
34
- var previous = $ul.find('.active:last a')[0]
35
- var e = $.Event('show.bs.tab', {
36
- relatedTarget: previous
36
+ var $previous = $ul.find('.active:last a')
37
+ var hideEvent = $.Event('hide.bs.tab', {
38
+ relatedTarget: $this[0]
39
+ })
40
+ var showEvent = $.Event('show.bs.tab', {
41
+ relatedTarget: $previous[0]
37
42
  })
38
43
 
39
- $this.trigger(e)
44
+ $previous.trigger(hideEvent)
45
+ $this.trigger(showEvent)
40
46
 
41
- if (e.isDefaultPrevented()) return
47
+ if (showEvent.isDefaultPrevented() || hideEvent.isDefaultPrevented()) return
42
48
 
43
49
  var $target = $(selector)
44
50
 
45
51
  this.activate($this.closest('li'), $ul)
46
52
  this.activate($target, $target.parent(), function () {
53
+ $previous.trigger({
54
+ type: 'hidden.bs.tab',
55
+ relatedTarget: $this[0]
56
+ })
47
57
  $this.trigger({
48
58
  type: 'shown.bs.tab',
49
- relatedTarget: previous
59
+ relatedTarget: $previous[0]
50
60
  })
51
61
  })
52
62
  }
@@ -55,15 +65,21 @@
55
65
  var $active = container.find('> .active')
56
66
  var transition = callback
57
67
  && $.support.transition
58
- && $active.hasClass('fade')
68
+ && (($active.length && $active.hasClass('fade')) || !!container.find('> .fade').length)
59
69
 
60
70
  function next() {
61
71
  $active
62
72
  .removeClass('active')
63
73
  .find('> .dropdown-menu > .active')
64
- .removeClass('active')
74
+ .removeClass('active')
75
+ .end()
76
+ .find('[data-toggle="tab"]')
77
+ .attr('aria-expanded', false)
65
78
 
66
- element.addClass('active')
79
+ element
80
+ .addClass('active')
81
+ .find('[data-toggle="tab"]')
82
+ .attr('aria-expanded', true)
67
83
 
68
84
  if (transition) {
69
85
  element[0].offsetWidth // reflow for transition
@@ -73,16 +89,21 @@
73
89
  }
74
90
 
75
91
  if (element.parent('.dropdown-menu')) {
76
- element.closest('li.dropdown').addClass('active')
92
+ element
93
+ .closest('li.dropdown')
94
+ .addClass('active')
95
+ .end()
96
+ .find('[data-toggle="tab"]')
97
+ .attr('aria-expanded', true)
77
98
  }
78
99
 
79
100
  callback && callback()
80
101
  }
81
102
 
82
- transition ?
103
+ $active.length && transition ?
83
104
  $active
84
105
  .one('bsTransitionEnd', next)
85
- .emulateTransitionEnd(150) :
106
+ .emulateTransitionEnd(Tab.TRANSITION_DURATION) :
86
107
  next()
87
108
 
88
109
  $active.removeClass('in')
@@ -120,9 +141,13 @@
120
141
  // TAB DATA-API
121
142
  // ============
122
143
 
123
- $(document).on('click.bs.tab.data-api', '[data-toggle="tab"], [data-toggle="pill"]', function (e) {
144
+ var clickHandler = function (e) {
124
145
  e.preventDefault()
125
146
  Plugin.call($(this), 'show')
126
- })
147
+ }
148
+
149
+ $(document)
150
+ .on('click.bs.tab.data-api', '[data-toggle="tab"]', clickHandler)
151
+ .on('click.bs.tab.data-api', '[data-toggle="pill"]', clickHandler)
127
152
 
128
153
  }(jQuery);
@@ -1,5 +1,5 @@
1
1
  /* ========================================================================
2
- * Bootstrap: tooltip.js v3.2.0
2
+ * Bootstrap: tooltip.js v3.3.0
3
3
  * http://getbootstrap.com/javascript/#tooltip
4
4
  * Inspired by the original jQuery.tipsy by Jason Frame
5
5
  * ========================================================================
@@ -25,7 +25,9 @@
25
25
  this.init('tooltip', element, options)
26
26
  }
27
27
 
28
- Tooltip.VERSION = '3.2.0'
28
+ Tooltip.VERSION = '3.3.0'
29
+
30
+ Tooltip.TRANSITION_DURATION = 150
29
31
 
30
32
  Tooltip.DEFAULTS = {
31
33
  animation: true,
@@ -103,6 +105,11 @@
103
105
  var self = obj instanceof this.constructor ?
104
106
  obj : $(obj.currentTarget).data('bs.' + this.type)
105
107
 
108
+ if (self && self.$tip && self.$tip.is(':visible')) {
109
+ self.hoverState = 'in'
110
+ return
111
+ }
112
+
106
113
  if (!self) {
107
114
  self = new this.constructor(obj.currentTarget, this.getDelegateOptions())
108
115
  $(obj.currentTarget).data('bs.' + this.type, self)
@@ -145,7 +152,7 @@
145
152
  if (this.hasContent() && this.enabled) {
146
153
  this.$element.trigger(e)
147
154
 
148
- var inDom = $.contains(document.documentElement, this.$element[0])
155
+ var inDom = $.contains(this.$element[0].ownerDocument.documentElement, this.$element[0])
149
156
  if (e.isDefaultPrevented() || !inDom) return
150
157
  var that = this
151
158
 
@@ -181,13 +188,13 @@
181
188
 
182
189
  if (autoPlace) {
183
190
  var orgPlacement = placement
184
- var $parent = this.$element.parent()
185
- var parentDim = this.getPosition($parent)
191
+ var $container = this.options.container ? $(this.options.container) : this.$element.parent()
192
+ var containerDim = this.getPosition($container)
186
193
 
187
- placement = placement == 'bottom' && pos.top + pos.height + actualHeight - parentDim.scroll > parentDim.height ? 'top' :
188
- placement == 'top' && pos.top - parentDim.scroll - actualHeight < 0 ? 'bottom' :
189
- placement == 'right' && pos.right + actualWidth > parentDim.width ? 'left' :
190
- placement == 'left' && pos.left - actualWidth < parentDim.left ? 'right' :
194
+ placement = placement == 'bottom' && pos.bottom + actualHeight > containerDim.bottom ? 'top' :
195
+ placement == 'top' && pos.top - actualHeight < containerDim.top ? 'bottom' :
196
+ placement == 'right' && pos.right + actualWidth > containerDim.width ? 'left' :
197
+ placement == 'left' && pos.left - actualWidth < containerDim.left ? 'right' :
191
198
  placement
192
199
 
193
200
  $tip
@@ -200,14 +207,17 @@
200
207
  this.applyPlacement(calculatedOffset, placement)
201
208
 
202
209
  var complete = function () {
210
+ var prevHoverState = that.hoverState
203
211
  that.$element.trigger('shown.bs.' + that.type)
204
212
  that.hoverState = null
213
+
214
+ if (prevHoverState == 'out') that.leave(that)
205
215
  }
206
216
 
207
217
  $.support.transition && this.$tip.hasClass('fade') ?
208
218
  $tip
209
219
  .one('bsTransitionEnd', complete)
210
- .emulateTransitionEnd(150) :
220
+ .emulateTransitionEnd(Tooltip.TRANSITION_DURATION) :
211
221
  complete()
212
222
  }
213
223
  }
@@ -254,16 +264,18 @@
254
264
  if (delta.left) offset.left += delta.left
255
265
  else offset.top += delta.top
256
266
 
257
- var arrowDelta = delta.left ? delta.left * 2 - width + actualWidth : delta.top * 2 - height + actualHeight
258
- var arrowPosition = delta.left ? 'left' : 'top'
259
- var arrowOffsetPosition = delta.left ? 'offsetWidth' : 'offsetHeight'
267
+ var isVertical = /top|bottom/.test(placement)
268
+ var arrowDelta = isVertical ? delta.left * 2 - width + actualWidth : delta.top * 2 - height + actualHeight
269
+ var arrowOffsetPosition = isVertical ? 'offsetWidth' : 'offsetHeight'
260
270
 
261
271
  $tip.offset(offset)
262
- this.replaceArrow(arrowDelta, $tip[0][arrowOffsetPosition], arrowPosition)
272
+ this.replaceArrow(arrowDelta, $tip[0][arrowOffsetPosition], isVertical)
263
273
  }
264
274
 
265
- Tooltip.prototype.replaceArrow = function (delta, dimension, position) {
266
- this.arrow().css(position, delta ? (50 * (1 - delta / dimension) + '%') : '')
275
+ Tooltip.prototype.replaceArrow = function (delta, dimension, isHorizontal) {
276
+ this.arrow()
277
+ .css(isHorizontal ? 'left' : 'top', 50 * (1 - delta / dimension) + '%')
278
+ .css(isHorizontal ? 'top' : 'left', '')
267
279
  }
268
280
 
269
281
  Tooltip.prototype.setContent = function () {
@@ -274,16 +286,17 @@
274
286
  $tip.removeClass('fade in top bottom left right')
275
287
  }
276
288
 
277
- Tooltip.prototype.hide = function () {
289
+ Tooltip.prototype.hide = function (callback) {
278
290
  var that = this
279
291
  var $tip = this.tip()
280
292
  var e = $.Event('hide.bs.' + this.type)
281
293
 
282
- this.$element.removeAttr('aria-describedby')
283
-
284
294
  function complete() {
285
295
  if (that.hoverState != 'in') $tip.detach()
286
- that.$element.trigger('hidden.bs.' + that.type)
296
+ that.$element
297
+ .removeAttr('aria-describedby')
298
+ .trigger('hidden.bs.' + that.type)
299
+ callback && callback()
287
300
  }
288
301
 
289
302
  this.$element.trigger(e)
@@ -295,7 +308,7 @@
295
308
  $.support.transition && this.$tip.hasClass('fade') ?
296
309
  $tip
297
310
  .one('bsTransitionEnd', complete)
298
- .emulateTransitionEnd(150) :
311
+ .emulateTransitionEnd(Tooltip.TRANSITION_DURATION) :
299
312
  complete()
300
313
 
301
314
  this.hoverState = null
@@ -316,13 +329,20 @@
316
329
 
317
330
  Tooltip.prototype.getPosition = function ($element) {
318
331
  $element = $element || this.$element
332
+
319
333
  var el = $element[0]
320
334
  var isBody = el.tagName == 'BODY'
321
- return $.extend({}, (typeof el.getBoundingClientRect == 'function') ? el.getBoundingClientRect() : null, {
322
- scroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop : $element.scrollTop(),
323
- width: isBody ? $(window).width() : $element.outerWidth(),
324
- height: isBody ? $(window).height() : $element.outerHeight()
325
- }, isBody ? { top: 0, left: 0 } : $element.offset())
335
+
336
+ var elRect = el.getBoundingClientRect()
337
+ if (elRect.width == null) {
338
+ // width and height are missing in IE8, so compute them manually; see https://github.com/twbs/bootstrap/issues/14093
339
+ elRect = $.extend({}, elRect, { width: elRect.right - elRect.left, height: elRect.bottom - elRect.top })
340
+ }
341
+ var elOffset = isBody ? { top: 0, left: 0 } : $element.offset()
342
+ var scroll = { scroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop : $element.scrollTop() }
343
+ var outerDims = isBody ? { width: $(window).width(), height: $(window).height() } : null
344
+
345
+ return $.extend({}, elRect, scroll, outerDims, elOffset)
326
346
  }
327
347
 
328
348
  Tooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight) {
@@ -386,14 +406,6 @@
386
406
  return (this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow'))
387
407
  }
388
408
 
389
- Tooltip.prototype.validate = function () {
390
- if (!this.$element[0].parentNode) {
391
- this.hide()
392
- this.$element = null
393
- this.options = null
394
- }
395
- }
396
-
397
409
  Tooltip.prototype.enable = function () {
398
410
  this.enabled = true
399
411
  }
@@ -420,8 +432,11 @@
420
432
  }
421
433
 
422
434
  Tooltip.prototype.destroy = function () {
435
+ var that = this
423
436
  clearTimeout(this.timeout)
424
- this.hide().$element.off('.' + this.type).removeData('bs.' + this.type)
437
+ this.hide(function () {
438
+ that.$element.off('.' + that.type).removeData('bs.' + that.type)
439
+ })
425
440
  }
426
441
 
427
442
 
@@ -430,12 +445,18 @@
430
445
 
431
446
  function Plugin(option) {
432
447
  return this.each(function () {
433
- var $this = $(this)
434
- var data = $this.data('bs.tooltip')
435
- var options = typeof option == 'object' && option
448
+ var $this = $(this)
449
+ var data = $this.data('bs.tooltip')
450
+ var options = typeof option == 'object' && option
451
+ var selector = options && options.selector
436
452
 
437
453
  if (!data && option == 'destroy') return
438
- if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options)))
454
+ if (selector) {
455
+ if (!data) $this.data('bs.tooltip', (data = {}))
456
+ if (!data[selector]) data[selector] = new Tooltip(this, options)
457
+ } else {
458
+ if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options)))
459
+ }
439
460
  if (typeof option == 'string') data[option]()
440
461
  })
441
462
  }