problem_child 0.0.1

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.
Files changed (63) hide show
  1. checksums.yaml +7 -0
  2. data/.bowerrc +3 -0
  3. data/.gitignore +10 -0
  4. data/Gemfile +4 -0
  5. data/LICENSE.txt +22 -0
  6. data/Procfile +1 -0
  7. data/README.md +53 -0
  8. data/Rakefile +8 -0
  9. data/bower.json +13 -0
  10. data/config.ru +3 -0
  11. data/lib/problem_child.rb +126 -0
  12. data/lib/problem_child/public/vendor/bootstrap/.bower.json +47 -0
  13. data/lib/problem_child/public/vendor/bootstrap/Gruntfile.js +472 -0
  14. data/lib/problem_child/public/vendor/bootstrap/LICENSE +21 -0
  15. data/lib/problem_child/public/vendor/bootstrap/README.md +129 -0
  16. data/lib/problem_child/public/vendor/bootstrap/bower.json +38 -0
  17. data/lib/problem_child/public/vendor/bootstrap/dist/css/bootstrap-theme.css +470 -0
  18. data/lib/problem_child/public/vendor/bootstrap/dist/css/bootstrap-theme.css.map +1 -0
  19. data/lib/problem_child/public/vendor/bootstrap/dist/css/bootstrap-theme.min.css +5 -0
  20. data/lib/problem_child/public/vendor/bootstrap/dist/css/bootstrap.css +6332 -0
  21. data/lib/problem_child/public/vendor/bootstrap/dist/css/bootstrap.css.map +1 -0
  22. data/lib/problem_child/public/vendor/bootstrap/dist/css/bootstrap.min.css +5 -0
  23. data/lib/problem_child/public/vendor/bootstrap/dist/fonts/glyphicons-halflings-regular.eot +0 -0
  24. data/lib/problem_child/public/vendor/bootstrap/dist/fonts/glyphicons-halflings-regular.svg +229 -0
  25. data/lib/problem_child/public/vendor/bootstrap/dist/fonts/glyphicons-halflings-regular.ttf +0 -0
  26. data/lib/problem_child/public/vendor/bootstrap/dist/fonts/glyphicons-halflings-regular.woff +0 -0
  27. data/lib/problem_child/public/vendor/bootstrap/dist/js/bootstrap.js +2320 -0
  28. data/lib/problem_child/public/vendor/bootstrap/dist/js/bootstrap.min.js +7 -0
  29. data/lib/problem_child/public/vendor/bootstrap/dist/js/npm.js +13 -0
  30. data/lib/problem_child/public/vendor/bootstrap/fonts/glyphicons-halflings-regular.eot +0 -0
  31. data/lib/problem_child/public/vendor/bootstrap/fonts/glyphicons-halflings-regular.svg +229 -0
  32. data/lib/problem_child/public/vendor/bootstrap/fonts/glyphicons-halflings-regular.ttf +0 -0
  33. data/lib/problem_child/public/vendor/bootstrap/fonts/glyphicons-halflings-regular.woff +0 -0
  34. data/lib/problem_child/public/vendor/bootstrap/js/.jscsrc +34 -0
  35. data/lib/problem_child/public/vendor/bootstrap/js/.jshintrc +15 -0
  36. data/lib/problem_child/public/vendor/bootstrap/js/affix.js +162 -0
  37. data/lib/problem_child/public/vendor/bootstrap/js/alert.js +94 -0
  38. data/lib/problem_child/public/vendor/bootstrap/js/button.js +116 -0
  39. data/lib/problem_child/public/vendor/bootstrap/js/carousel.js +240 -0
  40. data/lib/problem_child/public/vendor/bootstrap/js/collapse.js +211 -0
  41. data/lib/problem_child/public/vendor/bootstrap/js/dropdown.js +161 -0
  42. data/lib/problem_child/public/vendor/bootstrap/js/modal.js +324 -0
  43. data/lib/problem_child/public/vendor/bootstrap/js/popover.js +119 -0
  44. data/lib/problem_child/public/vendor/bootstrap/js/scrollspy.js +175 -0
  45. data/lib/problem_child/public/vendor/bootstrap/js/tab.js +153 -0
  46. data/lib/problem_child/public/vendor/bootstrap/js/tooltip.js +478 -0
  47. data/lib/problem_child/public/vendor/bootstrap/js/transition.js +59 -0
  48. data/lib/problem_child/public/vendor/bootstrap/package.json +82 -0
  49. data/lib/problem_child/public/vendor/jquery/.bower.json +37 -0
  50. data/lib/problem_child/public/vendor/jquery/MIT-LICENSE.txt +21 -0
  51. data/lib/problem_child/public/vendor/jquery/bower.json +27 -0
  52. data/lib/problem_child/public/vendor/jquery/dist/jquery.js +9205 -0
  53. data/lib/problem_child/public/vendor/jquery/dist/jquery.min.js +5 -0
  54. data/lib/problem_child/public/vendor/jquery/dist/jquery.min.map +1 -0
  55. data/lib/problem_child/version.rb +3 -0
  56. data/lib/problem_child/views/form.erb +22 -0
  57. data/lib/problem_child/views/layout.erb +27 -0
  58. data/problem_child.gemspec +32 -0
  59. data/script/bootstrap +1 -0
  60. data/script/console +1 -0
  61. data/script/release +38 -0
  62. data/script/server +1 -0
  63. metadata +260 -0
@@ -0,0 +1,119 @@
1
+ /* ========================================================================
2
+ * Bootstrap: popover.js v3.3.1
3
+ * http://getbootstrap.com/javascript/#popovers
4
+ * ========================================================================
5
+ * Copyright 2011-2014 Twitter, Inc.
6
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
7
+ * ======================================================================== */
8
+
9
+
10
+ +function ($) {
11
+ 'use strict';
12
+
13
+ // POPOVER PUBLIC CLASS DEFINITION
14
+ // ===============================
15
+
16
+ var Popover = function (element, options) {
17
+ this.init('popover', element, options)
18
+ }
19
+
20
+ if (!$.fn.tooltip) throw new Error('Popover requires tooltip.js')
21
+
22
+ Popover.VERSION = '3.3.1'
23
+
24
+ Popover.DEFAULTS = $.extend({}, $.fn.tooltip.Constructor.DEFAULTS, {
25
+ placement: 'right',
26
+ trigger: 'click',
27
+ content: '',
28
+ template: '<div class="popover" role="tooltip"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'
29
+ })
30
+
31
+
32
+ // NOTE: POPOVER EXTENDS tooltip.js
33
+ // ================================
34
+
35
+ Popover.prototype = $.extend({}, $.fn.tooltip.Constructor.prototype)
36
+
37
+ Popover.prototype.constructor = Popover
38
+
39
+ Popover.prototype.getDefaults = function () {
40
+ return Popover.DEFAULTS
41
+ }
42
+
43
+ Popover.prototype.setContent = function () {
44
+ var $tip = this.tip()
45
+ var title = this.getTitle()
46
+ var content = this.getContent()
47
+
48
+ $tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title)
49
+ $tip.find('.popover-content').children().detach().end()[ // we use append for html objects to maintain js events
50
+ this.options.html ? (typeof content == 'string' ? 'html' : 'append') : 'text'
51
+ ](content)
52
+
53
+ $tip.removeClass('fade top bottom left right in')
54
+
55
+ // IE8 doesn't accept hiding via the `:empty` pseudo selector, we have to do
56
+ // this manually by checking the contents.
57
+ if (!$tip.find('.popover-title').html()) $tip.find('.popover-title').hide()
58
+ }
59
+
60
+ Popover.prototype.hasContent = function () {
61
+ return this.getTitle() || this.getContent()
62
+ }
63
+
64
+ Popover.prototype.getContent = function () {
65
+ var $e = this.$element
66
+ var o = this.options
67
+
68
+ return $e.attr('data-content')
69
+ || (typeof o.content == 'function' ?
70
+ o.content.call($e[0]) :
71
+ o.content)
72
+ }
73
+
74
+ Popover.prototype.arrow = function () {
75
+ return (this.$arrow = this.$arrow || this.tip().find('.arrow'))
76
+ }
77
+
78
+ Popover.prototype.tip = function () {
79
+ if (!this.$tip) this.$tip = $(this.options.template)
80
+ return this.$tip
81
+ }
82
+
83
+
84
+ // POPOVER PLUGIN DEFINITION
85
+ // =========================
86
+
87
+ function Plugin(option) {
88
+ return this.each(function () {
89
+ var $this = $(this)
90
+ var data = $this.data('bs.popover')
91
+ var options = typeof option == 'object' && option
92
+ var selector = options && options.selector
93
+
94
+ if (!data && option == 'destroy') return
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
+ }
101
+ if (typeof option == 'string') data[option]()
102
+ })
103
+ }
104
+
105
+ var old = $.fn.popover
106
+
107
+ $.fn.popover = Plugin
108
+ $.fn.popover.Constructor = Popover
109
+
110
+
111
+ // POPOVER NO CONFLICT
112
+ // ===================
113
+
114
+ $.fn.popover.noConflict = function () {
115
+ $.fn.popover = old
116
+ return this
117
+ }
118
+
119
+ }(jQuery);
@@ -0,0 +1,175 @@
1
+ /* ========================================================================
2
+ * Bootstrap: scrollspy.js v3.3.1
3
+ * http://getbootstrap.com/javascript/#scrollspy
4
+ * ========================================================================
5
+ * Copyright 2011-2014 Twitter, Inc.
6
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
7
+ * ======================================================================== */
8
+
9
+
10
+ +function ($) {
11
+ 'use strict';
12
+
13
+ // SCROLLSPY CLASS DEFINITION
14
+ // ==========================
15
+
16
+ function ScrollSpy(element, options) {
17
+ var process = $.proxy(this.process, this)
18
+
19
+ this.$body = $('body')
20
+ this.$scrollElement = $(element).is('body') ? $(window) : $(element)
21
+ this.options = $.extend({}, ScrollSpy.DEFAULTS, options)
22
+ this.selector = (this.options.target || '') + ' .nav li > a'
23
+ this.offsets = []
24
+ this.targets = []
25
+ this.activeTarget = null
26
+ this.scrollHeight = 0
27
+
28
+ this.$scrollElement.on('scroll.bs.scrollspy', process)
29
+ this.refresh()
30
+ this.process()
31
+ }
32
+
33
+ ScrollSpy.VERSION = '3.3.1'
34
+
35
+ ScrollSpy.DEFAULTS = {
36
+ offset: 10
37
+ }
38
+
39
+ ScrollSpy.prototype.getScrollHeight = function () {
40
+ return this.$scrollElement[0].scrollHeight || Math.max(this.$body[0].scrollHeight, document.documentElement.scrollHeight)
41
+ }
42
+
43
+ ScrollSpy.prototype.refresh = function () {
44
+ var offsetMethod = 'offset'
45
+ var offsetBase = 0
46
+
47
+ if (!$.isWindow(this.$scrollElement[0])) {
48
+ offsetMethod = 'position'
49
+ offsetBase = this.$scrollElement.scrollTop()
50
+ }
51
+
52
+ this.offsets = []
53
+ this.targets = []
54
+ this.scrollHeight = this.getScrollHeight()
55
+
56
+ var self = this
57
+
58
+ this.$body
59
+ .find(this.selector)
60
+ .map(function () {
61
+ var $el = $(this)
62
+ var href = $el.data('target') || $el.attr('href')
63
+ var $href = /^#./.test(href) && $(href)
64
+
65
+ return ($href
66
+ && $href.length
67
+ && $href.is(':visible')
68
+ && [[$href[offsetMethod]().top + offsetBase, href]]) || null
69
+ })
70
+ .sort(function (a, b) { return a[0] - b[0] })
71
+ .each(function () {
72
+ self.offsets.push(this[0])
73
+ self.targets.push(this[1])
74
+ })
75
+ }
76
+
77
+ ScrollSpy.prototype.process = function () {
78
+ var scrollTop = this.$scrollElement.scrollTop() + this.options.offset
79
+ var scrollHeight = this.getScrollHeight()
80
+ var maxScroll = this.options.offset + scrollHeight - this.$scrollElement.height()
81
+ var offsets = this.offsets
82
+ var targets = this.targets
83
+ var activeTarget = this.activeTarget
84
+ var i
85
+
86
+ if (this.scrollHeight != scrollHeight) {
87
+ this.refresh()
88
+ }
89
+
90
+ if (scrollTop >= maxScroll) {
91
+ return activeTarget != (i = targets[targets.length - 1]) && this.activate(i)
92
+ }
93
+
94
+ if (activeTarget && scrollTop < offsets[0]) {
95
+ this.activeTarget = null
96
+ return this.clear()
97
+ }
98
+
99
+ for (i = offsets.length; i--;) {
100
+ activeTarget != targets[i]
101
+ && scrollTop >= offsets[i]
102
+ && (!offsets[i + 1] || scrollTop <= offsets[i + 1])
103
+ && this.activate(targets[i])
104
+ }
105
+ }
106
+
107
+ ScrollSpy.prototype.activate = function (target) {
108
+ this.activeTarget = target
109
+
110
+ this.clear()
111
+
112
+ var selector = this.selector +
113
+ '[data-target="' + target + '"],' +
114
+ this.selector + '[href="' + target + '"]'
115
+
116
+ var active = $(selector)
117
+ .parents('li')
118
+ .addClass('active')
119
+
120
+ if (active.parent('.dropdown-menu').length) {
121
+ active = active
122
+ .closest('li.dropdown')
123
+ .addClass('active')
124
+ }
125
+
126
+ active.trigger('activate.bs.scrollspy')
127
+ }
128
+
129
+ ScrollSpy.prototype.clear = function () {
130
+ $(this.selector)
131
+ .parentsUntil(this.options.target, '.active')
132
+ .removeClass('active')
133
+ }
134
+
135
+
136
+ // SCROLLSPY PLUGIN DEFINITION
137
+ // ===========================
138
+
139
+ function Plugin(option) {
140
+ return this.each(function () {
141
+ var $this = $(this)
142
+ var data = $this.data('bs.scrollspy')
143
+ var options = typeof option == 'object' && option
144
+
145
+ if (!data) $this.data('bs.scrollspy', (data = new ScrollSpy(this, options)))
146
+ if (typeof option == 'string') data[option]()
147
+ })
148
+ }
149
+
150
+ var old = $.fn.scrollspy
151
+
152
+ $.fn.scrollspy = Plugin
153
+ $.fn.scrollspy.Constructor = ScrollSpy
154
+
155
+
156
+ // SCROLLSPY NO CONFLICT
157
+ // =====================
158
+
159
+ $.fn.scrollspy.noConflict = function () {
160
+ $.fn.scrollspy = old
161
+ return this
162
+ }
163
+
164
+
165
+ // SCROLLSPY DATA-API
166
+ // ==================
167
+
168
+ $(window).on('load.bs.scrollspy.data-api', function () {
169
+ $('[data-spy="scroll"]').each(function () {
170
+ var $spy = $(this)
171
+ Plugin.call($spy, $spy.data())
172
+ })
173
+ })
174
+
175
+ }(jQuery);
@@ -0,0 +1,153 @@
1
+ /* ========================================================================
2
+ * Bootstrap: tab.js v3.3.1
3
+ * http://getbootstrap.com/javascript/#tabs
4
+ * ========================================================================
5
+ * Copyright 2011-2014 Twitter, Inc.
6
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
7
+ * ======================================================================== */
8
+
9
+
10
+ +function ($) {
11
+ 'use strict';
12
+
13
+ // TAB CLASS DEFINITION
14
+ // ====================
15
+
16
+ var Tab = function (element) {
17
+ this.element = $(element)
18
+ }
19
+
20
+ Tab.VERSION = '3.3.1'
21
+
22
+ Tab.TRANSITION_DURATION = 150
23
+
24
+ Tab.prototype.show = function () {
25
+ var $this = this.element
26
+ var $ul = $this.closest('ul:not(.dropdown-menu)')
27
+ var selector = $this.data('target')
28
+
29
+ if (!selector) {
30
+ selector = $this.attr('href')
31
+ selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
32
+ }
33
+
34
+ if ($this.parent('li').hasClass('active')) return
35
+
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]
42
+ })
43
+
44
+ $previous.trigger(hideEvent)
45
+ $this.trigger(showEvent)
46
+
47
+ if (showEvent.isDefaultPrevented() || hideEvent.isDefaultPrevented()) return
48
+
49
+ var $target = $(selector)
50
+
51
+ this.activate($this.closest('li'), $ul)
52
+ this.activate($target, $target.parent(), function () {
53
+ $previous.trigger({
54
+ type: 'hidden.bs.tab',
55
+ relatedTarget: $this[0]
56
+ })
57
+ $this.trigger({
58
+ type: 'shown.bs.tab',
59
+ relatedTarget: $previous[0]
60
+ })
61
+ })
62
+ }
63
+
64
+ Tab.prototype.activate = function (element, container, callback) {
65
+ var $active = container.find('> .active')
66
+ var transition = callback
67
+ && $.support.transition
68
+ && (($active.length && $active.hasClass('fade')) || !!container.find('> .fade').length)
69
+
70
+ function next() {
71
+ $active
72
+ .removeClass('active')
73
+ .find('> .dropdown-menu > .active')
74
+ .removeClass('active')
75
+ .end()
76
+ .find('[data-toggle="tab"]')
77
+ .attr('aria-expanded', false)
78
+
79
+ element
80
+ .addClass('active')
81
+ .find('[data-toggle="tab"]')
82
+ .attr('aria-expanded', true)
83
+
84
+ if (transition) {
85
+ element[0].offsetWidth // reflow for transition
86
+ element.addClass('in')
87
+ } else {
88
+ element.removeClass('fade')
89
+ }
90
+
91
+ if (element.parent('.dropdown-menu')) {
92
+ element
93
+ .closest('li.dropdown')
94
+ .addClass('active')
95
+ .end()
96
+ .find('[data-toggle="tab"]')
97
+ .attr('aria-expanded', true)
98
+ }
99
+
100
+ callback && callback()
101
+ }
102
+
103
+ $active.length && transition ?
104
+ $active
105
+ .one('bsTransitionEnd', next)
106
+ .emulateTransitionEnd(Tab.TRANSITION_DURATION) :
107
+ next()
108
+
109
+ $active.removeClass('in')
110
+ }
111
+
112
+
113
+ // TAB PLUGIN DEFINITION
114
+ // =====================
115
+
116
+ function Plugin(option) {
117
+ return this.each(function () {
118
+ var $this = $(this)
119
+ var data = $this.data('bs.tab')
120
+
121
+ if (!data) $this.data('bs.tab', (data = new Tab(this)))
122
+ if (typeof option == 'string') data[option]()
123
+ })
124
+ }
125
+
126
+ var old = $.fn.tab
127
+
128
+ $.fn.tab = Plugin
129
+ $.fn.tab.Constructor = Tab
130
+
131
+
132
+ // TAB NO CONFLICT
133
+ // ===============
134
+
135
+ $.fn.tab.noConflict = function () {
136
+ $.fn.tab = old
137
+ return this
138
+ }
139
+
140
+
141
+ // TAB DATA-API
142
+ // ============
143
+
144
+ var clickHandler = function (e) {
145
+ e.preventDefault()
146
+ Plugin.call($(this), 'show')
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)
152
+
153
+ }(jQuery);
@@ -0,0 +1,478 @@
1
+ /* ========================================================================
2
+ * Bootstrap: tooltip.js v3.3.1
3
+ * http://getbootstrap.com/javascript/#tooltip
4
+ * Inspired by the original jQuery.tipsy by Jason Frame
5
+ * ========================================================================
6
+ * Copyright 2011-2014 Twitter, Inc.
7
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
8
+ * ======================================================================== */
9
+
10
+
11
+ +function ($) {
12
+ 'use strict';
13
+
14
+ // TOOLTIP PUBLIC CLASS DEFINITION
15
+ // ===============================
16
+
17
+ var Tooltip = function (element, options) {
18
+ this.type =
19
+ this.options =
20
+ this.enabled =
21
+ this.timeout =
22
+ this.hoverState =
23
+ this.$element = null
24
+
25
+ this.init('tooltip', element, options)
26
+ }
27
+
28
+ Tooltip.VERSION = '3.3.1'
29
+
30
+ Tooltip.TRANSITION_DURATION = 150
31
+
32
+ Tooltip.DEFAULTS = {
33
+ animation: true,
34
+ placement: 'top',
35
+ selector: false,
36
+ template: '<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',
37
+ trigger: 'hover focus',
38
+ title: '',
39
+ delay: 0,
40
+ html: false,
41
+ container: false,
42
+ viewport: {
43
+ selector: 'body',
44
+ padding: 0
45
+ }
46
+ }
47
+
48
+ Tooltip.prototype.init = function (type, element, options) {
49
+ this.enabled = true
50
+ this.type = type
51
+ this.$element = $(element)
52
+ this.options = this.getOptions(options)
53
+ this.$viewport = this.options.viewport && $(this.options.viewport.selector || this.options.viewport)
54
+
55
+ var triggers = this.options.trigger.split(' ')
56
+
57
+ for (var i = triggers.length; i--;) {
58
+ var trigger = triggers[i]
59
+
60
+ if (trigger == 'click') {
61
+ this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this))
62
+ } else if (trigger != 'manual') {
63
+ var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
64
+ var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
65
+
66
+ this.$element.on(eventIn + '.' + this.type, this.options.selector, $.proxy(this.enter, this))
67
+ this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this))
68
+ }
69
+ }
70
+
71
+ this.options.selector ?
72
+ (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) :
73
+ this.fixTitle()
74
+ }
75
+
76
+ Tooltip.prototype.getDefaults = function () {
77
+ return Tooltip.DEFAULTS
78
+ }
79
+
80
+ Tooltip.prototype.getOptions = function (options) {
81
+ options = $.extend({}, this.getDefaults(), this.$element.data(), options)
82
+
83
+ if (options.delay && typeof options.delay == 'number') {
84
+ options.delay = {
85
+ show: options.delay,
86
+ hide: options.delay
87
+ }
88
+ }
89
+
90
+ return options
91
+ }
92
+
93
+ Tooltip.prototype.getDelegateOptions = function () {
94
+ var options = {}
95
+ var defaults = this.getDefaults()
96
+
97
+ this._options && $.each(this._options, function (key, value) {
98
+ if (defaults[key] != value) options[key] = value
99
+ })
100
+
101
+ return options
102
+ }
103
+
104
+ Tooltip.prototype.enter = function (obj) {
105
+ var self = obj instanceof this.constructor ?
106
+ obj : $(obj.currentTarget).data('bs.' + this.type)
107
+
108
+ if (self && self.$tip && self.$tip.is(':visible')) {
109
+ self.hoverState = 'in'
110
+ return
111
+ }
112
+
113
+ if (!self) {
114
+ self = new this.constructor(obj.currentTarget, this.getDelegateOptions())
115
+ $(obj.currentTarget).data('bs.' + this.type, self)
116
+ }
117
+
118
+ clearTimeout(self.timeout)
119
+
120
+ self.hoverState = 'in'
121
+
122
+ if (!self.options.delay || !self.options.delay.show) return self.show()
123
+
124
+ self.timeout = setTimeout(function () {
125
+ if (self.hoverState == 'in') self.show()
126
+ }, self.options.delay.show)
127
+ }
128
+
129
+ Tooltip.prototype.leave = function (obj) {
130
+ var self = obj instanceof this.constructor ?
131
+ obj : $(obj.currentTarget).data('bs.' + this.type)
132
+
133
+ if (!self) {
134
+ self = new this.constructor(obj.currentTarget, this.getDelegateOptions())
135
+ $(obj.currentTarget).data('bs.' + this.type, self)
136
+ }
137
+
138
+ clearTimeout(self.timeout)
139
+
140
+ self.hoverState = 'out'
141
+
142
+ if (!self.options.delay || !self.options.delay.hide) return self.hide()
143
+
144
+ self.timeout = setTimeout(function () {
145
+ if (self.hoverState == 'out') self.hide()
146
+ }, self.options.delay.hide)
147
+ }
148
+
149
+ Tooltip.prototype.show = function () {
150
+ var e = $.Event('show.bs.' + this.type)
151
+
152
+ if (this.hasContent() && this.enabled) {
153
+ this.$element.trigger(e)
154
+
155
+ var inDom = $.contains(this.$element[0].ownerDocument.documentElement, this.$element[0])
156
+ if (e.isDefaultPrevented() || !inDom) return
157
+ var that = this
158
+
159
+ var $tip = this.tip()
160
+
161
+ var tipId = this.getUID(this.type)
162
+
163
+ this.setContent()
164
+ $tip.attr('id', tipId)
165
+ this.$element.attr('aria-describedby', tipId)
166
+
167
+ if (this.options.animation) $tip.addClass('fade')
168
+
169
+ var placement = typeof this.options.placement == 'function' ?
170
+ this.options.placement.call(this, $tip[0], this.$element[0]) :
171
+ this.options.placement
172
+
173
+ var autoToken = /\s?auto?\s?/i
174
+ var autoPlace = autoToken.test(placement)
175
+ if (autoPlace) placement = placement.replace(autoToken, '') || 'top'
176
+
177
+ $tip
178
+ .detach()
179
+ .css({ top: 0, left: 0, display: 'block' })
180
+ .addClass(placement)
181
+ .data('bs.' + this.type, this)
182
+
183
+ this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element)
184
+
185
+ var pos = this.getPosition()
186
+ var actualWidth = $tip[0].offsetWidth
187
+ var actualHeight = $tip[0].offsetHeight
188
+
189
+ if (autoPlace) {
190
+ var orgPlacement = placement
191
+ var $container = this.options.container ? $(this.options.container) : this.$element.parent()
192
+ var containerDim = this.getPosition($container)
193
+
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' :
198
+ placement
199
+
200
+ $tip
201
+ .removeClass(orgPlacement)
202
+ .addClass(placement)
203
+ }
204
+
205
+ var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight)
206
+
207
+ this.applyPlacement(calculatedOffset, placement)
208
+
209
+ var complete = function () {
210
+ var prevHoverState = that.hoverState
211
+ that.$element.trigger('shown.bs.' + that.type)
212
+ that.hoverState = null
213
+
214
+ if (prevHoverState == 'out') that.leave(that)
215
+ }
216
+
217
+ $.support.transition && this.$tip.hasClass('fade') ?
218
+ $tip
219
+ .one('bsTransitionEnd', complete)
220
+ .emulateTransitionEnd(Tooltip.TRANSITION_DURATION) :
221
+ complete()
222
+ }
223
+ }
224
+
225
+ Tooltip.prototype.applyPlacement = function (offset, placement) {
226
+ var $tip = this.tip()
227
+ var width = $tip[0].offsetWidth
228
+ var height = $tip[0].offsetHeight
229
+
230
+ // manually read margins because getBoundingClientRect includes difference
231
+ var marginTop = parseInt($tip.css('margin-top'), 10)
232
+ var marginLeft = parseInt($tip.css('margin-left'), 10)
233
+
234
+ // we must check for NaN for ie 8/9
235
+ if (isNaN(marginTop)) marginTop = 0
236
+ if (isNaN(marginLeft)) marginLeft = 0
237
+
238
+ offset.top = offset.top + marginTop
239
+ offset.left = offset.left + marginLeft
240
+
241
+ // $.fn.offset doesn't round pixel values
242
+ // so we use setOffset directly with our own function B-0
243
+ $.offset.setOffset($tip[0], $.extend({
244
+ using: function (props) {
245
+ $tip.css({
246
+ top: Math.round(props.top),
247
+ left: Math.round(props.left)
248
+ })
249
+ }
250
+ }, offset), 0)
251
+
252
+ $tip.addClass('in')
253
+
254
+ // check to see if placing tip in new offset caused the tip to resize itself
255
+ var actualWidth = $tip[0].offsetWidth
256
+ var actualHeight = $tip[0].offsetHeight
257
+
258
+ if (placement == 'top' && actualHeight != height) {
259
+ offset.top = offset.top + height - actualHeight
260
+ }
261
+
262
+ var delta = this.getViewportAdjustedDelta(placement, offset, actualWidth, actualHeight)
263
+
264
+ if (delta.left) offset.left += delta.left
265
+ else offset.top += delta.top
266
+
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'
270
+
271
+ $tip.offset(offset)
272
+ this.replaceArrow(arrowDelta, $tip[0][arrowOffsetPosition], isVertical)
273
+ }
274
+
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', '')
279
+ }
280
+
281
+ Tooltip.prototype.setContent = function () {
282
+ var $tip = this.tip()
283
+ var title = this.getTitle()
284
+
285
+ $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title)
286
+ $tip.removeClass('fade in top bottom left right')
287
+ }
288
+
289
+ Tooltip.prototype.hide = function (callback) {
290
+ var that = this
291
+ var $tip = this.tip()
292
+ var e = $.Event('hide.bs.' + this.type)
293
+
294
+ function complete() {
295
+ if (that.hoverState != 'in') $tip.detach()
296
+ that.$element
297
+ .removeAttr('aria-describedby')
298
+ .trigger('hidden.bs.' + that.type)
299
+ callback && callback()
300
+ }
301
+
302
+ this.$element.trigger(e)
303
+
304
+ if (e.isDefaultPrevented()) return
305
+
306
+ $tip.removeClass('in')
307
+
308
+ $.support.transition && this.$tip.hasClass('fade') ?
309
+ $tip
310
+ .one('bsTransitionEnd', complete)
311
+ .emulateTransitionEnd(Tooltip.TRANSITION_DURATION) :
312
+ complete()
313
+
314
+ this.hoverState = null
315
+
316
+ return this
317
+ }
318
+
319
+ Tooltip.prototype.fixTitle = function () {
320
+ var $e = this.$element
321
+ if ($e.attr('title') || typeof ($e.attr('data-original-title')) != 'string') {
322
+ $e.attr('data-original-title', $e.attr('title') || '').attr('title', '')
323
+ }
324
+ }
325
+
326
+ Tooltip.prototype.hasContent = function () {
327
+ return this.getTitle()
328
+ }
329
+
330
+ Tooltip.prototype.getPosition = function ($element) {
331
+ $element = $element || this.$element
332
+
333
+ var el = $element[0]
334
+ var isBody = el.tagName == 'BODY'
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)
346
+ }
347
+
348
+ Tooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight) {
349
+ return placement == 'bottom' ? { top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2 } :
350
+ placement == 'top' ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2 } :
351
+ placement == 'left' ? { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth } :
352
+ /* placement == 'right' */ { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width }
353
+
354
+ }
355
+
356
+ Tooltip.prototype.getViewportAdjustedDelta = function (placement, pos, actualWidth, actualHeight) {
357
+ var delta = { top: 0, left: 0 }
358
+ if (!this.$viewport) return delta
359
+
360
+ var viewportPadding = this.options.viewport && this.options.viewport.padding || 0
361
+ var viewportDimensions = this.getPosition(this.$viewport)
362
+
363
+ if (/right|left/.test(placement)) {
364
+ var topEdgeOffset = pos.top - viewportPadding - viewportDimensions.scroll
365
+ var bottomEdgeOffset = pos.top + viewportPadding - viewportDimensions.scroll + actualHeight
366
+ if (topEdgeOffset < viewportDimensions.top) { // top overflow
367
+ delta.top = viewportDimensions.top - topEdgeOffset
368
+ } else if (bottomEdgeOffset > viewportDimensions.top + viewportDimensions.height) { // bottom overflow
369
+ delta.top = viewportDimensions.top + viewportDimensions.height - bottomEdgeOffset
370
+ }
371
+ } else {
372
+ var leftEdgeOffset = pos.left - viewportPadding
373
+ var rightEdgeOffset = pos.left + viewportPadding + actualWidth
374
+ if (leftEdgeOffset < viewportDimensions.left) { // left overflow
375
+ delta.left = viewportDimensions.left - leftEdgeOffset
376
+ } else if (rightEdgeOffset > viewportDimensions.width) { // right overflow
377
+ delta.left = viewportDimensions.left + viewportDimensions.width - rightEdgeOffset
378
+ }
379
+ }
380
+
381
+ return delta
382
+ }
383
+
384
+ Tooltip.prototype.getTitle = function () {
385
+ var title
386
+ var $e = this.$element
387
+ var o = this.options
388
+
389
+ title = $e.attr('data-original-title')
390
+ || (typeof o.title == 'function' ? o.title.call($e[0]) : o.title)
391
+
392
+ return title
393
+ }
394
+
395
+ Tooltip.prototype.getUID = function (prefix) {
396
+ do prefix += ~~(Math.random() * 1000000)
397
+ while (document.getElementById(prefix))
398
+ return prefix
399
+ }
400
+
401
+ Tooltip.prototype.tip = function () {
402
+ return (this.$tip = this.$tip || $(this.options.template))
403
+ }
404
+
405
+ Tooltip.prototype.arrow = function () {
406
+ return (this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow'))
407
+ }
408
+
409
+ Tooltip.prototype.enable = function () {
410
+ this.enabled = true
411
+ }
412
+
413
+ Tooltip.prototype.disable = function () {
414
+ this.enabled = false
415
+ }
416
+
417
+ Tooltip.prototype.toggleEnabled = function () {
418
+ this.enabled = !this.enabled
419
+ }
420
+
421
+ Tooltip.prototype.toggle = function (e) {
422
+ var self = this
423
+ if (e) {
424
+ self = $(e.currentTarget).data('bs.' + this.type)
425
+ if (!self) {
426
+ self = new this.constructor(e.currentTarget, this.getDelegateOptions())
427
+ $(e.currentTarget).data('bs.' + this.type, self)
428
+ }
429
+ }
430
+
431
+ self.tip().hasClass('in') ? self.leave(self) : self.enter(self)
432
+ }
433
+
434
+ Tooltip.prototype.destroy = function () {
435
+ var that = this
436
+ clearTimeout(this.timeout)
437
+ this.hide(function () {
438
+ that.$element.off('.' + that.type).removeData('bs.' + that.type)
439
+ })
440
+ }
441
+
442
+
443
+ // TOOLTIP PLUGIN DEFINITION
444
+ // =========================
445
+
446
+ function Plugin(option) {
447
+ return this.each(function () {
448
+ var $this = $(this)
449
+ var data = $this.data('bs.tooltip')
450
+ var options = typeof option == 'object' && option
451
+ var selector = options && options.selector
452
+
453
+ if (!data && option == 'destroy') return
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
+ }
460
+ if (typeof option == 'string') data[option]()
461
+ })
462
+ }
463
+
464
+ var old = $.fn.tooltip
465
+
466
+ $.fn.tooltip = Plugin
467
+ $.fn.tooltip.Constructor = Tooltip
468
+
469
+
470
+ // TOOLTIP NO CONFLICT
471
+ // ===================
472
+
473
+ $.fn.tooltip.noConflict = function () {
474
+ $.fn.tooltip = old
475
+ return this
476
+ }
477
+
478
+ }(jQuery);