locomotivecms_wagon 2.0.0.rc2 → 2.0.0.rc3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (159) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +1 -1
  3. data/generators/{bootstrap3 → bootstrap}/Gemfile.tt +0 -0
  4. data/generators/{bootstrap3 → bootstrap}/app/content_types/.empty_directory +0 -0
  5. data/generators/bootstrap/app/views/pages/404.liquid +18 -0
  6. data/generators/bootstrap/app/views/pages/404.liquid.haml +14 -0
  7. data/generators/bootstrap/app/views/pages/index.liquid +31 -0
  8. data/generators/bootstrap/app/views/pages/index.liquid.haml +25 -0
  9. data/generators/bootstrap/app/views/pages/layouts/default.liquid +31 -0
  10. data/generators/bootstrap/app/views/pages/layouts/default.liquid.haml +30 -0
  11. data/generators/bootstrap/app/views/pages/layouts/simple.liquid +36 -0
  12. data/generators/bootstrap/app/views/pages/layouts/simple.liquid.haml +29 -0
  13. data/generators/bootstrap/app/views/snippets/footer.liquid +5 -0
  14. data/generators/bootstrap/app/views/snippets/footer.liquid.haml +3 -0
  15. data/generators/bootstrap/app/views/snippets/nav.liquid +26 -0
  16. data/generators/bootstrap/app/views/snippets/nav.liquid.haml +19 -0
  17. data/generators/{bootstrap3 → bootstrap}/config/deploy.yml +0 -0
  18. data/generators/bootstrap/config/site.yml.tt +1 -6
  19. data/generators/{bootstrap3 → bootstrap}/config/translations.yml +0 -0
  20. data/generators/{bootstrap3 → bootstrap}/data/.empty_directory +0 -0
  21. data/generators/{bootstrap3 → bootstrap}/icon.png +0 -0
  22. data/generators/bootstrap/public/fonts/bootstrap/glyphicons-halflings-regular.eot +0 -0
  23. data/generators/bootstrap/public/fonts/bootstrap/glyphicons-halflings-regular.svg +288 -0
  24. data/generators/bootstrap/public/fonts/bootstrap/glyphicons-halflings-regular.ttf +0 -0
  25. data/generators/bootstrap/public/fonts/bootstrap/glyphicons-halflings-regular.woff +0 -0
  26. data/generators/bootstrap/public/fonts/bootstrap/glyphicons-halflings-regular.woff2 +0 -0
  27. data/generators/{bootstrap3/public/samples → bootstrap/public/images}/favicon.png +0 -0
  28. data/generators/bootstrap/public/javascripts/application.js +2 -0
  29. data/generators/{bootstrap3 → bootstrap}/public/javascripts/bootstrap/affix.js +60 -35
  30. data/generators/{bootstrap3 → bootstrap}/public/javascripts/bootstrap/alert.js +15 -9
  31. data/generators/{bootstrap3 → bootstrap}/public/javascripts/bootstrap/button.js +33 -20
  32. data/generators/{bootstrap3 → bootstrap}/public/javascripts/bootstrap/carousel.js +79 -47
  33. data/generators/{bootstrap3 → bootstrap}/public/javascripts/bootstrap/collapse.js +84 -43
  34. data/generators/{bootstrap3 → bootstrap}/public/javascripts/bootstrap/dropdown.js +64 -46
  35. data/generators/bootstrap/public/javascripts/bootstrap/modal.js +337 -0
  36. data/generators/{bootstrap3 → bootstrap}/public/javascripts/bootstrap/popover.js +12 -14
  37. data/generators/{bootstrap3 → bootstrap}/public/javascripts/bootstrap/scrollspy.js +57 -38
  38. data/generators/{bootstrap3 → bootstrap}/public/javascripts/bootstrap/tab.js +54 -24
  39. data/generators/{bootstrap3 → bootstrap}/public/javascripts/bootstrap/tooltip.js +202 -87
  40. data/generators/{bootstrap3 → bootstrap}/public/javascripts/bootstrap/transition.js +19 -8
  41. data/generators/bootstrap/public/javascripts/bootstrap.min.js +7 -0
  42. data/generators/bootstrap/public/javascripts/jquery.min.js +5 -0
  43. data/generators/bootstrap/public/stylesheets/application.css +7 -0
  44. data/generators/bootstrap/public/stylesheets/application.scss +7 -0
  45. data/generators/{bootstrap3 → bootstrap}/public/stylesheets/bootstrap/_alerts.scss +9 -3
  46. data/generators/{bootstrap3 → bootstrap}/public/stylesheets/bootstrap/_badges.scss +26 -13
  47. data/generators/{bootstrap3 → bootstrap}/public/stylesheets/bootstrap/_breadcrumbs.scss +3 -1
  48. data/generators/{bootstrap3 → bootstrap}/public/stylesheets/bootstrap/_button-groups.scss +32 -14
  49. data/generators/{bootstrap3 → bootstrap}/public/stylesheets/bootstrap/_buttons.scss +22 -13
  50. data/generators/{bootstrap3 → bootstrap}/public/stylesheets/bootstrap/_carousel.scss +43 -6
  51. data/generators/{bootstrap3 → bootstrap}/public/stylesheets/bootstrap/_close.scss +1 -0
  52. data/generators/{bootstrap3 → bootstrap}/public/stylesheets/bootstrap/_code.scss +7 -1
  53. data/generators/bootstrap/public/stylesheets/bootstrap/_component-animations.scss +37 -0
  54. data/generators/{bootstrap3 → bootstrap}/public/stylesheets/bootstrap/_dropdowns.scss +12 -9
  55. data/generators/{bootstrap3 → bootstrap}/public/stylesheets/bootstrap/_forms.scss +240 -65
  56. data/generators/{bootstrap3 → bootstrap}/public/stylesheets/bootstrap/_glyphicons.scss +83 -9
  57. data/generators/{bootstrap3 → bootstrap}/public/stylesheets/bootstrap/_grid.scss +4 -4
  58. data/generators/{bootstrap3 → bootstrap}/public/stylesheets/bootstrap/_input-groups.scss +7 -2
  59. data/generators/{bootstrap3 → bootstrap}/public/stylesheets/bootstrap/_jumbotron.scss +12 -4
  60. data/generators/{bootstrap3 → bootstrap}/public/stylesheets/bootstrap/_labels.scss +11 -9
  61. data/generators/{bootstrap3 → bootstrap}/public/stylesheets/bootstrap/_list-group.scss +32 -12
  62. data/generators/bootstrap/public/stylesheets/bootstrap/_media.scss +66 -0
  63. data/generators/bootstrap/public/stylesheets/bootstrap/_mixins.scss +40 -0
  64. data/generators/{bootstrap3 → bootstrap}/public/stylesheets/bootstrap/_modals.scss +18 -7
  65. data/generators/{bootstrap3 → bootstrap}/public/stylesheets/bootstrap/_navbar.scss +75 -33
  66. data/generators/{bootstrap3 → bootstrap}/public/stylesheets/bootstrap/_navs.scss +4 -4
  67. data/generators/{bootstrap3 → bootstrap}/public/stylesheets/bootstrap/_normalize.scss +29 -28
  68. data/generators/{bootstrap3 → bootstrap}/public/stylesheets/bootstrap/_pager.scss +2 -3
  69. data/generators/{bootstrap3 → bootstrap}/public/stylesheets/bootstrap/_pagination.scss +4 -3
  70. data/generators/{bootstrap3 → bootstrap}/public/stylesheets/bootstrap/_panels.scss +40 -10
  71. data/generators/{bootstrap3 → bootstrap}/public/stylesheets/bootstrap/_popovers.scss +6 -8
  72. data/generators/bootstrap/public/stylesheets/bootstrap/_print.scss +101 -0
  73. data/generators/{bootstrap3 → bootstrap}/public/stylesheets/bootstrap/_progress-bars.scss +13 -6
  74. data/generators/bootstrap/public/stylesheets/bootstrap/_responsive-embed.scss +35 -0
  75. data/generators/bootstrap/public/stylesheets/bootstrap/_responsive-utilities.scss +179 -0
  76. data/generators/{bootstrap3 → bootstrap}/public/stylesheets/bootstrap/_scaffolding.scss +31 -4
  77. data/generators/{bootstrap3 → bootstrap}/public/stylesheets/bootstrap/_tables.scss +17 -16
  78. data/generators/{bootstrap3 → bootstrap}/public/stylesheets/bootstrap/_theme.scss +57 -13
  79. data/generators/{bootstrap3 → bootstrap}/public/stylesheets/bootstrap/_thumbnails.scss +2 -2
  80. data/generators/{bootstrap3 → bootstrap}/public/stylesheets/bootstrap/_tooltip.scss +13 -7
  81. data/generators/{bootstrap3 → bootstrap}/public/stylesheets/bootstrap/_type.scss +38 -24
  82. data/generators/{bootstrap3 → bootstrap}/public/stylesheets/bootstrap/_utilities.scss +3 -4
  83. data/generators/{bootstrap3 → bootstrap}/public/stylesheets/bootstrap/_variables.scss +86 -47
  84. data/generators/{bootstrap3 → bootstrap}/public/stylesheets/bootstrap/_wells.scss +0 -0
  85. data/generators/bootstrap/public/stylesheets/bootstrap/mixins/_alerts.scss +14 -0
  86. data/generators/bootstrap/public/stylesheets/bootstrap/mixins/_background-variant.scss +12 -0
  87. data/generators/bootstrap/public/stylesheets/bootstrap/mixins/_border-radius.scss +18 -0
  88. data/generators/bootstrap/public/stylesheets/bootstrap/mixins/_buttons.scss +68 -0
  89. data/generators/bootstrap/public/stylesheets/bootstrap/mixins/_center-block.scss +7 -0
  90. data/generators/bootstrap/public/stylesheets/bootstrap/mixins/_clearfix.scss +22 -0
  91. data/generators/bootstrap/public/stylesheets/bootstrap/mixins/_forms.scss +88 -0
  92. data/generators/bootstrap/public/stylesheets/bootstrap/mixins/_gradients.scss +58 -0
  93. data/generators/bootstrap/public/stylesheets/bootstrap/mixins/_grid-framework.scss +81 -0
  94. data/generators/bootstrap/public/stylesheets/bootstrap/mixins/_grid.scss +122 -0
  95. data/generators/bootstrap/public/stylesheets/bootstrap/mixins/_hide-text.scss +21 -0
  96. data/generators/bootstrap/public/stylesheets/bootstrap/mixins/_image.scss +33 -0
  97. data/generators/bootstrap/public/stylesheets/bootstrap/mixins/_labels.scss +12 -0
  98. data/generators/bootstrap/public/stylesheets/bootstrap/mixins/_list-group.scss +32 -0
  99. data/generators/bootstrap/public/stylesheets/bootstrap/mixins/_nav-divider.scss +10 -0
  100. data/generators/bootstrap/public/stylesheets/bootstrap/mixins/_nav-vertical-align.scss +9 -0
  101. data/generators/bootstrap/public/stylesheets/bootstrap/mixins/_opacity.scss +8 -0
  102. data/generators/bootstrap/public/stylesheets/bootstrap/mixins/_pagination.scss +24 -0
  103. data/generators/bootstrap/public/stylesheets/bootstrap/mixins/_panels.scss +24 -0
  104. data/generators/bootstrap/public/stylesheets/bootstrap/mixins/_progress-bar.scss +10 -0
  105. data/generators/bootstrap/public/stylesheets/bootstrap/mixins/_reset-filter.scss +8 -0
  106. data/generators/bootstrap/public/stylesheets/bootstrap/mixins/_reset-text.scss +18 -0
  107. data/generators/bootstrap/public/stylesheets/bootstrap/mixins/_resize.scss +6 -0
  108. data/generators/bootstrap/public/stylesheets/bootstrap/mixins/_responsive-visibility.scss +21 -0
  109. data/generators/bootstrap/public/stylesheets/bootstrap/mixins/_size.scss +10 -0
  110. data/generators/bootstrap/public/stylesheets/bootstrap/mixins/_tab-focus.scss +9 -0
  111. data/generators/bootstrap/public/stylesheets/bootstrap/mixins/_table-row.scss +28 -0
  112. data/generators/bootstrap/public/stylesheets/bootstrap/mixins/_text-emphasis.scss +12 -0
  113. data/generators/bootstrap/public/stylesheets/bootstrap/mixins/_text-overflow.scss +8 -0
  114. data/generators/bootstrap/public/stylesheets/bootstrap/mixins/_vendor-prefixes.scss +222 -0
  115. data/generators/bootstrap/public/stylesheets/bootstrap.css +5 -0
  116. data/generators/{bootstrap3/public/stylesheets/bootstrap.css.scss → bootstrap/public/stylesheets/bootstrap.scss} +16 -2
  117. data/lib/locomotive/wagon/cli.rb +3 -3
  118. data/lib/locomotive/wagon/commands/authenticate_command.rb +2 -1
  119. data/lib/locomotive/wagon/commands/concerns/spinner_concern.rb +29 -0
  120. data/lib/locomotive/wagon/commands/pull_command.rb +18 -3
  121. data/lib/locomotive/wagon/commands/push_command.rb +28 -4
  122. data/lib/locomotive/wagon/commands/sync_command.rb +21 -6
  123. data/lib/locomotive/wagon/commands/sync_sub_commands/sync_pages_command.rb +27 -3
  124. data/lib/locomotive/wagon/generators/site/{bootstrap3.rb → bootstrap.rb} +12 -6
  125. data/lib/locomotive/wagon/generators/site.rb +1 -1
  126. data/lib/locomotive/wagon/tools/listen.rb +1 -1
  127. data/lib/locomotive/wagon/version.rb +1 -1
  128. data/lib/locomotive/wagon.rb +2 -2
  129. data/locomotivecms_wagon.gemspec +3 -2
  130. data/spec/unit/decorators/theme_asset_decorator_spec.rb +10 -0
  131. metadata +124 -90
  132. data/generators/bootstrap3/app/views/pages/404.liquid +0 -13
  133. data/generators/bootstrap3/app/views/pages/404.liquid.haml +0 -10
  134. data/generators/bootstrap3/app/views/pages/index.liquid +0 -738
  135. data/generators/bootstrap3/app/views/pages/index.liquid.haml +0 -1018
  136. data/generators/bootstrap3/app/views/snippets/footer.liquid +0 -3
  137. data/generators/bootstrap3/app/views/snippets/footer.liquid.haml +0 -2
  138. data/generators/bootstrap3/config/site.yml.tt +0 -28
  139. data/generators/bootstrap3/public/fonts/glyphicons-halflings-regular.eot +0 -0
  140. data/generators/bootstrap3/public/fonts/glyphicons-halflings-regular.svg +0 -229
  141. data/generators/bootstrap3/public/fonts/glyphicons-halflings-regular.ttf +0 -0
  142. data/generators/bootstrap3/public/fonts/glyphicons-halflings-regular.woff +0 -0
  143. data/generators/bootstrap3/public/images/.empty_directory +0 -1
  144. data/generators/bootstrap3/public/javascripts/bootstrap/modal.js +0 -243
  145. data/generators/bootstrap3/public/javascripts/bootstrap.min.js +0 -12
  146. data/generators/bootstrap3/public/samples/apple-touch-icon-114x114-precomposed.png +0 -0
  147. data/generators/bootstrap3/public/samples/apple-touch-icon-144x144-precomposed.png +0 -0
  148. data/generators/bootstrap3/public/samples/apple-touch-icon-72x72-precomposed.png +0 -0
  149. data/generators/bootstrap3/public/samples/apple-touch-icon-precomposed.png +0 -0
  150. data/generators/bootstrap3/public/stylesheets/application.css +0 -1
  151. data/generators/bootstrap3/public/stylesheets/application.css.scss +0 -8
  152. data/generators/bootstrap3/public/stylesheets/bootstrap/_component-animations.scss +0 -29
  153. data/generators/bootstrap3/public/stylesheets/bootstrap/_media.scss +0 -56
  154. data/generators/bootstrap3/public/stylesheets/bootstrap/_mixins.scss +0 -947
  155. data/generators/bootstrap3/public/stylesheets/bootstrap/_print.scss +0 -101
  156. data/generators/bootstrap3/public/stylesheets/bootstrap/_responsive-utilities.scss +0 -74
  157. data/generators/bootstrap3/public/stylesheets/bootstrap/bootstrap.css.scss +0 -49
  158. data/generators/bootstrap3/public/stylesheets/bootstrap.css +0 -5784
  159. data/lib/locomotive/wagon/generators/site/bootstrap2.rb +0 -34
@@ -1,8 +1,8 @@
1
1
  /* ========================================================================
2
- * Bootstrap: tab.js v3.1.1
2
+ * Bootstrap: tab.js v3.3.5
3
3
  * http://getbootstrap.com/javascript/#tabs
4
4
  * ========================================================================
5
- * Copyright 2011-2014 Twitter, Inc.
5
+ * Copyright 2011-2015 Twitter, Inc.
6
6
  * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
7
7
  * ======================================================================== */
8
8
 
@@ -14,9 +14,15 @@
14
14
  // ====================
15
15
 
16
16
  var Tab = function (element) {
17
+ // jscs:disable requireDollarBeforejQueryAssignment
17
18
  this.element = $(element)
19
+ // jscs:enable requireDollarBeforejQueryAssignment
18
20
  }
19
21
 
22
+ Tab.VERSION = '3.3.5'
23
+
24
+ Tab.TRANSITION_DURATION = 150
25
+
20
26
  Tab.prototype.show = function () {
21
27
  var $this = this.element
22
28
  var $ul = $this.closest('ul:not(.dropdown-menu)')
@@ -24,27 +30,35 @@
24
30
 
25
31
  if (!selector) {
26
32
  selector = $this.attr('href')
27
- selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
33
+ selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
28
34
  }
29
35
 
30
36
  if ($this.parent('li').hasClass('active')) return
31
37
 
32
- var previous = $ul.find('.active:last a')[0]
33
- var e = $.Event('show.bs.tab', {
34
- relatedTarget: previous
38
+ var $previous = $ul.find('.active:last a')
39
+ var hideEvent = $.Event('hide.bs.tab', {
40
+ relatedTarget: $this[0]
41
+ })
42
+ var showEvent = $.Event('show.bs.tab', {
43
+ relatedTarget: $previous[0]
35
44
  })
36
45
 
37
- $this.trigger(e)
46
+ $previous.trigger(hideEvent)
47
+ $this.trigger(showEvent)
38
48
 
39
- if (e.isDefaultPrevented()) return
49
+ if (showEvent.isDefaultPrevented() || hideEvent.isDefaultPrevented()) return
40
50
 
41
51
  var $target = $(selector)
42
52
 
43
- this.activate($this.parent('li'), $ul)
53
+ this.activate($this.closest('li'), $ul)
44
54
  this.activate($target, $target.parent(), function () {
55
+ $previous.trigger({
56
+ type: 'hidden.bs.tab',
57
+ relatedTarget: $this[0]
58
+ })
45
59
  $this.trigger({
46
60
  type: 'shown.bs.tab',
47
- relatedTarget: previous
61
+ relatedTarget: $previous[0]
48
62
  })
49
63
  })
50
64
  }
@@ -53,15 +67,21 @@
53
67
  var $active = container.find('> .active')
54
68
  var transition = callback
55
69
  && $.support.transition
56
- && $active.hasClass('fade')
70
+ && ($active.length && $active.hasClass('fade') || !!container.find('> .fade').length)
57
71
 
58
72
  function next() {
59
73
  $active
60
74
  .removeClass('active')
61
75
  .find('> .dropdown-menu > .active')
62
- .removeClass('active')
76
+ .removeClass('active')
77
+ .end()
78
+ .find('[data-toggle="tab"]')
79
+ .attr('aria-expanded', false)
63
80
 
64
- element.addClass('active')
81
+ element
82
+ .addClass('active')
83
+ .find('[data-toggle="tab"]')
84
+ .attr('aria-expanded', true)
65
85
 
66
86
  if (transition) {
67
87
  element[0].offsetWidth // reflow for transition
@@ -70,17 +90,22 @@
70
90
  element.removeClass('fade')
71
91
  }
72
92
 
73
- if (element.parent('.dropdown-menu')) {
74
- element.closest('li.dropdown').addClass('active')
93
+ if (element.parent('.dropdown-menu').length) {
94
+ element
95
+ .closest('li.dropdown')
96
+ .addClass('active')
97
+ .end()
98
+ .find('[data-toggle="tab"]')
99
+ .attr('aria-expanded', true)
75
100
  }
76
101
 
77
102
  callback && callback()
78
103
  }
79
104
 
80
- transition ?
105
+ $active.length && transition ?
81
106
  $active
82
- .one($.support.transition.end, next)
83
- .emulateTransitionEnd(150) :
107
+ .one('bsTransitionEnd', next)
108
+ .emulateTransitionEnd(Tab.TRANSITION_DURATION) :
84
109
  next()
85
110
 
86
111
  $active.removeClass('in')
@@ -90,9 +115,7 @@
90
115
  // TAB PLUGIN DEFINITION
91
116
  // =====================
92
117
 
93
- var old = $.fn.tab
94
-
95
- $.fn.tab = function ( option ) {
118
+ function Plugin(option) {
96
119
  return this.each(function () {
97
120
  var $this = $(this)
98
121
  var data = $this.data('bs.tab')
@@ -102,6 +125,9 @@
102
125
  })
103
126
  }
104
127
 
128
+ var old = $.fn.tab
129
+
130
+ $.fn.tab = Plugin
105
131
  $.fn.tab.Constructor = Tab
106
132
 
107
133
 
@@ -117,9 +143,13 @@
117
143
  // TAB DATA-API
118
144
  // ============
119
145
 
120
- $(document).on('click.bs.tab.data-api', '[data-toggle="tab"], [data-toggle="pill"]', function (e) {
146
+ var clickHandler = function (e) {
121
147
  e.preventDefault()
122
- $(this).tab('show')
123
- })
148
+ Plugin.call($(this), 'show')
149
+ }
150
+
151
+ $(document)
152
+ .on('click.bs.tab.data-api', '[data-toggle="tab"]', clickHandler)
153
+ .on('click.bs.tab.data-api', '[data-toggle="pill"]', clickHandler)
124
154
 
125
155
  }(jQuery);
@@ -1,9 +1,9 @@
1
1
  /* ========================================================================
2
- * Bootstrap: tooltip.js v3.1.1
2
+ * Bootstrap: tooltip.js v3.3.5
3
3
  * http://getbootstrap.com/javascript/#tooltip
4
4
  * Inspired by the original jQuery.tipsy by Jason Frame
5
5
  * ========================================================================
6
- * Copyright 2011-2014 Twitter, Inc.
6
+ * Copyright 2011-2015 Twitter, Inc.
7
7
  * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
8
8
  * ======================================================================== */
9
9
 
@@ -15,33 +15,48 @@
15
15
  // ===============================
16
16
 
17
17
  var Tooltip = function (element, options) {
18
- this.type =
19
- this.options =
20
- this.enabled =
21
- this.timeout =
22
- this.hoverState =
18
+ this.type = null
19
+ this.options = null
20
+ this.enabled = null
21
+ this.timeout = null
22
+ this.hoverState = null
23
23
  this.$element = null
24
+ this.inState = null
24
25
 
25
26
  this.init('tooltip', element, options)
26
27
  }
27
28
 
29
+ Tooltip.VERSION = '3.3.5'
30
+
31
+ Tooltip.TRANSITION_DURATION = 150
32
+
28
33
  Tooltip.DEFAULTS = {
29
34
  animation: true,
30
35
  placement: 'top',
31
36
  selector: false,
32
- template: '<div class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',
37
+ template: '<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',
33
38
  trigger: 'hover focus',
34
39
  title: '',
35
40
  delay: 0,
36
41
  html: false,
37
- container: false
42
+ container: false,
43
+ viewport: {
44
+ selector: 'body',
45
+ padding: 0
46
+ }
38
47
  }
39
48
 
40
49
  Tooltip.prototype.init = function (type, element, options) {
41
- this.enabled = true
42
- this.type = type
43
- this.$element = $(element)
44
- this.options = this.getOptions(options)
50
+ this.enabled = true
51
+ this.type = type
52
+ this.$element = $(element)
53
+ this.options = this.getOptions(options)
54
+ this.$viewport = this.options.viewport && $($.isFunction(this.options.viewport) ? this.options.viewport.call(this, this.$element) : (this.options.viewport.selector || this.options.viewport))
55
+ this.inState = { click: false, hover: false, focus: false }
56
+
57
+ if (this.$element[0] instanceof document.constructor && !this.options.selector) {
58
+ throw new Error('`selector` option must be specified when initializing ' + this.type + ' on the window.document object!')
59
+ }
45
60
 
46
61
  var triggers = this.options.trigger.split(' ')
47
62
 
@@ -94,7 +109,21 @@
94
109
 
95
110
  Tooltip.prototype.enter = function (obj) {
96
111
  var self = obj instanceof this.constructor ?
97
- obj : $(obj.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type)
112
+ obj : $(obj.currentTarget).data('bs.' + this.type)
113
+
114
+ if (!self) {
115
+ self = new this.constructor(obj.currentTarget, this.getDelegateOptions())
116
+ $(obj.currentTarget).data('bs.' + this.type, self)
117
+ }
118
+
119
+ if (obj instanceof $.Event) {
120
+ self.inState[obj.type == 'focusin' ? 'focus' : 'hover'] = true
121
+ }
122
+
123
+ if (self.tip().hasClass('in') || self.hoverState == 'in') {
124
+ self.hoverState = 'in'
125
+ return
126
+ }
98
127
 
99
128
  clearTimeout(self.timeout)
100
129
 
@@ -107,9 +136,28 @@
107
136
  }, self.options.delay.show)
108
137
  }
109
138
 
139
+ Tooltip.prototype.isInStateTrue = function () {
140
+ for (var key in this.inState) {
141
+ if (this.inState[key]) return true
142
+ }
143
+
144
+ return false
145
+ }
146
+
110
147
  Tooltip.prototype.leave = function (obj) {
111
148
  var self = obj instanceof this.constructor ?
112
- obj : $(obj.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type)
149
+ obj : $(obj.currentTarget).data('bs.' + this.type)
150
+
151
+ if (!self) {
152
+ self = new this.constructor(obj.currentTarget, this.getDelegateOptions())
153
+ $(obj.currentTarget).data('bs.' + this.type, self)
154
+ }
155
+
156
+ if (obj instanceof $.Event) {
157
+ self.inState[obj.type == 'focusout' ? 'focus' : 'hover'] = false
158
+ }
159
+
160
+ if (self.isInStateTrue()) return
113
161
 
114
162
  clearTimeout(self.timeout)
115
163
 
@@ -128,12 +176,17 @@
128
176
  if (this.hasContent() && this.enabled) {
129
177
  this.$element.trigger(e)
130
178
 
131
- if (e.isDefaultPrevented()) return
132
- var that = this;
179
+ var inDom = $.contains(this.$element[0].ownerDocument.documentElement, this.$element[0])
180
+ if (e.isDefaultPrevented() || !inDom) return
181
+ var that = this
133
182
 
134
183
  var $tip = this.tip()
135
184
 
185
+ var tipId = this.getUID(this.type)
186
+
136
187
  this.setContent()
188
+ $tip.attr('id', tipId)
189
+ this.$element.attr('aria-describedby', tipId)
137
190
 
138
191
  if (this.options.animation) $tip.addClass('fade')
139
192
 
@@ -149,26 +202,23 @@
149
202
  .detach()
150
203
  .css({ top: 0, left: 0, display: 'block' })
151
204
  .addClass(placement)
205
+ .data('bs.' + this.type, this)
152
206
 
153
207
  this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element)
208
+ this.$element.trigger('inserted.bs.' + this.type)
154
209
 
155
210
  var pos = this.getPosition()
156
211
  var actualWidth = $tip[0].offsetWidth
157
212
  var actualHeight = $tip[0].offsetHeight
158
213
 
159
214
  if (autoPlace) {
160
- var $parent = this.$element.parent()
161
-
162
215
  var orgPlacement = placement
163
- var docScroll = document.documentElement.scrollTop || document.body.scrollTop
164
- var parentWidth = this.options.container == 'body' ? window.innerWidth : $parent.outerWidth()
165
- var parentHeight = this.options.container == 'body' ? window.innerHeight : $parent.outerHeight()
166
- var parentLeft = this.options.container == 'body' ? 0 : $parent.offset().left
167
-
168
- placement = placement == 'bottom' && pos.top + pos.height + actualHeight - docScroll > parentHeight ? 'top' :
169
- placement == 'top' && pos.top - docScroll - actualHeight < 0 ? 'bottom' :
170
- placement == 'right' && pos.right + actualWidth > parentWidth ? 'left' :
171
- placement == 'left' && pos.left - actualWidth < parentLeft ? 'right' :
216
+ var viewportDim = this.getPosition(this.$viewport)
217
+
218
+ placement = placement == 'bottom' && pos.bottom + actualHeight > viewportDim.bottom ? 'top' :
219
+ placement == 'top' && pos.top - actualHeight < viewportDim.top ? 'bottom' :
220
+ placement == 'right' && pos.right + actualWidth > viewportDim.width ? 'left' :
221
+ placement == 'left' && pos.left - actualWidth < viewportDim.left ? 'right' :
172
222
  placement
173
223
 
174
224
  $tip
@@ -179,22 +229,24 @@
179
229
  var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight)
180
230
 
181
231
  this.applyPlacement(calculatedOffset, placement)
182
- this.hoverState = null
183
232
 
184
- var complete = function() {
233
+ var complete = function () {
234
+ var prevHoverState = that.hoverState
185
235
  that.$element.trigger('shown.bs.' + that.type)
236
+ that.hoverState = null
237
+
238
+ if (prevHoverState == 'out') that.leave(that)
186
239
  }
187
240
 
188
241
  $.support.transition && this.$tip.hasClass('fade') ?
189
242
  $tip
190
- .one($.support.transition.end, complete)
191
- .emulateTransitionEnd(150) :
243
+ .one('bsTransitionEnd', complete)
244
+ .emulateTransitionEnd(Tooltip.TRANSITION_DURATION) :
192
245
  complete()
193
246
  }
194
247
  }
195
248
 
196
249
  Tooltip.prototype.applyPlacement = function (offset, placement) {
197
- var replace
198
250
  var $tip = this.tip()
199
251
  var width = $tip[0].offsetWidth
200
252
  var height = $tip[0].offsetHeight
@@ -207,8 +259,8 @@
207
259
  if (isNaN(marginTop)) marginTop = 0
208
260
  if (isNaN(marginLeft)) marginLeft = 0
209
261
 
210
- offset.top = offset.top + marginTop
211
- offset.left = offset.left + marginLeft
262
+ offset.top += marginTop
263
+ offset.left += marginLeft
212
264
 
213
265
  // $.fn.offset doesn't round pixel values
214
266
  // so we use setOffset directly with our own function B-0
@@ -228,33 +280,26 @@
228
280
  var actualHeight = $tip[0].offsetHeight
229
281
 
230
282
  if (placement == 'top' && actualHeight != height) {
231
- replace = true
232
283
  offset.top = offset.top + height - actualHeight
233
284
  }
234
285
 
235
- if (/bottom|top/.test(placement)) {
236
- var delta = 0
286
+ var delta = this.getViewportAdjustedDelta(placement, offset, actualWidth, actualHeight)
237
287
 
238
- if (offset.left < 0) {
239
- delta = offset.left * -2
240
- offset.left = 0
288
+ if (delta.left) offset.left += delta.left
289
+ else offset.top += delta.top
241
290
 
242
- $tip.offset(offset)
291
+ var isVertical = /top|bottom/.test(placement)
292
+ var arrowDelta = isVertical ? delta.left * 2 - width + actualWidth : delta.top * 2 - height + actualHeight
293
+ var arrowOffsetPosition = isVertical ? 'offsetWidth' : 'offsetHeight'
243
294
 
244
- actualWidth = $tip[0].offsetWidth
245
- actualHeight = $tip[0].offsetHeight
246
- }
247
-
248
- this.replaceArrow(delta - width + actualWidth, actualWidth, 'left')
249
- } else {
250
- this.replaceArrow(actualHeight - height, actualHeight, 'top')
251
- }
252
-
253
- if (replace) $tip.offset(offset)
295
+ $tip.offset(offset)
296
+ this.replaceArrow(arrowDelta, $tip[0][arrowOffsetPosition], isVertical)
254
297
  }
255
298
 
256
- Tooltip.prototype.replaceArrow = function (delta, dimension, position) {
257
- this.arrow().css(position, delta ? (50 * (1 - delta / dimension) + '%') : '')
299
+ Tooltip.prototype.replaceArrow = function (delta, dimension, isVertical) {
300
+ this.arrow()
301
+ .css(isVertical ? 'left' : 'top', 50 * (1 - delta / dimension) + '%')
302
+ .css(isVertical ? 'top' : 'left', '')
258
303
  }
259
304
 
260
305
  Tooltip.prototype.setContent = function () {
@@ -265,14 +310,17 @@
265
310
  $tip.removeClass('fade in top bottom left right')
266
311
  }
267
312
 
268
- Tooltip.prototype.hide = function () {
313
+ Tooltip.prototype.hide = function (callback) {
269
314
  var that = this
270
- var $tip = this.tip()
315
+ var $tip = $(this.$tip)
271
316
  var e = $.Event('hide.bs.' + this.type)
272
317
 
273
318
  function complete() {
274
319
  if (that.hoverState != 'in') $tip.detach()
275
- that.$element.trigger('hidden.bs.' + that.type)
320
+ that.$element
321
+ .removeAttr('aria-describedby')
322
+ .trigger('hidden.bs.' + that.type)
323
+ callback && callback()
276
324
  }
277
325
 
278
326
  this.$element.trigger(e)
@@ -281,10 +329,10 @@
281
329
 
282
330
  $tip.removeClass('in')
283
331
 
284
- $.support.transition && this.$tip.hasClass('fade') ?
332
+ $.support.transition && $tip.hasClass('fade') ?
285
333
  $tip
286
- .one($.support.transition.end, complete)
287
- .emulateTransitionEnd(150) :
334
+ .one('bsTransitionEnd', complete)
335
+ .emulateTransitionEnd(Tooltip.TRANSITION_DURATION) :
288
336
  complete()
289
337
 
290
338
  this.hoverState = null
@@ -294,7 +342,7 @@
294
342
 
295
343
  Tooltip.prototype.fixTitle = function () {
296
344
  var $e = this.$element
297
- if ($e.attr('title') || typeof($e.attr('data-original-title')) != 'string') {
345
+ if ($e.attr('title') || typeof $e.attr('data-original-title') != 'string') {
298
346
  $e.attr('data-original-title', $e.attr('title') || '').attr('title', '')
299
347
  }
300
348
  }
@@ -303,19 +351,58 @@
303
351
  return this.getTitle()
304
352
  }
305
353
 
306
- Tooltip.prototype.getPosition = function () {
307
- var el = this.$element[0]
308
- return $.extend({}, (typeof el.getBoundingClientRect == 'function') ? el.getBoundingClientRect() : {
309
- width: el.offsetWidth,
310
- height: el.offsetHeight
311
- }, this.$element.offset())
354
+ Tooltip.prototype.getPosition = function ($element) {
355
+ $element = $element || this.$element
356
+
357
+ var el = $element[0]
358
+ var isBody = el.tagName == 'BODY'
359
+
360
+ var elRect = el.getBoundingClientRect()
361
+ if (elRect.width == null) {
362
+ // width and height are missing in IE8, so compute them manually; see https://github.com/twbs/bootstrap/issues/14093
363
+ elRect = $.extend({}, elRect, { width: elRect.right - elRect.left, height: elRect.bottom - elRect.top })
364
+ }
365
+ var elOffset = isBody ? { top: 0, left: 0 } : $element.offset()
366
+ var scroll = { scroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop : $element.scrollTop() }
367
+ var outerDims = isBody ? { width: $(window).width(), height: $(window).height() } : null
368
+
369
+ return $.extend({}, elRect, scroll, outerDims, elOffset)
312
370
  }
313
371
 
314
372
  Tooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight) {
315
- return placement == 'bottom' ? { top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2 } :
316
- placement == 'top' ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2 } :
373
+ return placement == 'bottom' ? { top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2 } :
374
+ placement == 'top' ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2 } :
317
375
  placement == 'left' ? { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth } :
318
- /* placement == 'right' */ { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width }
376
+ /* placement == 'right' */ { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width }
377
+
378
+ }
379
+
380
+ Tooltip.prototype.getViewportAdjustedDelta = function (placement, pos, actualWidth, actualHeight) {
381
+ var delta = { top: 0, left: 0 }
382
+ if (!this.$viewport) return delta
383
+
384
+ var viewportPadding = this.options.viewport && this.options.viewport.padding || 0
385
+ var viewportDimensions = this.getPosition(this.$viewport)
386
+
387
+ if (/right|left/.test(placement)) {
388
+ var topEdgeOffset = pos.top - viewportPadding - viewportDimensions.scroll
389
+ var bottomEdgeOffset = pos.top + viewportPadding - viewportDimensions.scroll + actualHeight
390
+ if (topEdgeOffset < viewportDimensions.top) { // top overflow
391
+ delta.top = viewportDimensions.top - topEdgeOffset
392
+ } else if (bottomEdgeOffset > viewportDimensions.top + viewportDimensions.height) { // bottom overflow
393
+ delta.top = viewportDimensions.top + viewportDimensions.height - bottomEdgeOffset
394
+ }
395
+ } else {
396
+ var leftEdgeOffset = pos.left - viewportPadding
397
+ var rightEdgeOffset = pos.left + viewportPadding + actualWidth
398
+ if (leftEdgeOffset < viewportDimensions.left) { // left overflow
399
+ delta.left = viewportDimensions.left - leftEdgeOffset
400
+ } else if (rightEdgeOffset > viewportDimensions.right) { // right overflow
401
+ delta.left = viewportDimensions.left + viewportDimensions.width - rightEdgeOffset
402
+ }
403
+ }
404
+
405
+ return delta
319
406
  }
320
407
 
321
408
  Tooltip.prototype.getTitle = function () {
@@ -329,20 +416,24 @@
329
416
  return title
330
417
  }
331
418
 
332
- Tooltip.prototype.tip = function () {
333
- return this.$tip = this.$tip || $(this.options.template)
419
+ Tooltip.prototype.getUID = function (prefix) {
420
+ do prefix += ~~(Math.random() * 1000000)
421
+ while (document.getElementById(prefix))
422
+ return prefix
334
423
  }
335
424
 
336
- Tooltip.prototype.arrow = function () {
337
- return this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow')
425
+ Tooltip.prototype.tip = function () {
426
+ if (!this.$tip) {
427
+ this.$tip = $(this.options.template)
428
+ if (this.$tip.length != 1) {
429
+ throw new Error(this.type + ' `template` option must consist of exactly 1 top-level element!')
430
+ }
431
+ }
432
+ return this.$tip
338
433
  }
339
434
 
340
- Tooltip.prototype.validate = function () {
341
- if (!this.$element[0].parentNode) {
342
- this.hide()
343
- this.$element = null
344
- this.options = null
345
- }
435
+ Tooltip.prototype.arrow = function () {
436
+ return (this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow'))
346
437
  }
347
438
 
348
439
  Tooltip.prototype.enable = function () {
@@ -358,33 +449,57 @@
358
449
  }
359
450
 
360
451
  Tooltip.prototype.toggle = function (e) {
361
- var self = e ? $(e.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type) : this
362
- self.tip().hasClass('in') ? self.leave(self) : self.enter(self)
452
+ var self = this
453
+ if (e) {
454
+ self = $(e.currentTarget).data('bs.' + this.type)
455
+ if (!self) {
456
+ self = new this.constructor(e.currentTarget, this.getDelegateOptions())
457
+ $(e.currentTarget).data('bs.' + this.type, self)
458
+ }
459
+ }
460
+
461
+ if (e) {
462
+ self.inState.click = !self.inState.click
463
+ if (self.isInStateTrue()) self.enter(self)
464
+ else self.leave(self)
465
+ } else {
466
+ self.tip().hasClass('in') ? self.leave(self) : self.enter(self)
467
+ }
363
468
  }
364
469
 
365
470
  Tooltip.prototype.destroy = function () {
471
+ var that = this
366
472
  clearTimeout(this.timeout)
367
- this.hide().$element.off('.' + this.type).removeData('bs.' + this.type)
473
+ this.hide(function () {
474
+ that.$element.off('.' + that.type).removeData('bs.' + that.type)
475
+ if (that.$tip) {
476
+ that.$tip.detach()
477
+ }
478
+ that.$tip = null
479
+ that.$arrow = null
480
+ that.$viewport = null
481
+ })
368
482
  }
369
483
 
370
484
 
371
485
  // TOOLTIP PLUGIN DEFINITION
372
486
  // =========================
373
487
 
374
- var old = $.fn.tooltip
375
-
376
- $.fn.tooltip = function (option) {
488
+ function Plugin(option) {
377
489
  return this.each(function () {
378
490
  var $this = $(this)
379
491
  var data = $this.data('bs.tooltip')
380
492
  var options = typeof option == 'object' && option
381
493
 
382
- if (!data && option == 'destroy') return
494
+ if (!data && /destroy|hide/.test(option)) return
383
495
  if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options)))
384
496
  if (typeof option == 'string') data[option]()
385
497
  })
386
498
  }
387
499
 
500
+ var old = $.fn.tooltip
501
+
502
+ $.fn.tooltip = Plugin
388
503
  $.fn.tooltip.Constructor = Tooltip
389
504
 
390
505