bootstrap-jasny 0.1.12

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 (100) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +20 -0
  3. data/README.rdoc +27 -0
  4. data/lib/bootstrap-jasny.rb +51 -0
  5. data/lib/bootstrap-jasny/compass_functions.rb +24 -0
  6. data/lib/bootstrap-jasny/engine.rb +7 -0
  7. data/lib/bootstrap-jasny/less_functions.rb +14 -0
  8. data/vendor/assets/fonts/bootstrap/iconic/iconic_fill.eot +0 -0
  9. data/vendor/assets/fonts/bootstrap/iconic/iconic_fill.otf +0 -0
  10. data/vendor/assets/fonts/bootstrap/iconic/iconic_fill.svg +475 -0
  11. data/vendor/assets/fonts/bootstrap/iconic/iconic_fill.ttf +0 -0
  12. data/vendor/assets/fonts/bootstrap/iconic/iconic_fill.woff +0 -0
  13. data/vendor/assets/fonts/bootstrap/iconic/iconic_stroke.eot +0 -0
  14. data/vendor/assets/fonts/bootstrap/iconic/iconic_stroke.otf +0 -0
  15. data/vendor/assets/fonts/bootstrap/iconic/iconic_stroke.svg +492 -0
  16. data/vendor/assets/fonts/bootstrap/iconic/iconic_stroke.ttf +0 -0
  17. data/vendor/assets/fonts/bootstrap/iconic/iconic_stroke.woff +0 -0
  18. data/vendor/assets/images/bootstrap/glyphicons-halflings-white.png +0 -0
  19. data/vendor/assets/images/bootstrap/glyphicons-halflings.png +0 -0
  20. data/vendor/assets/javascripts/bootstrap-affix.js +117 -0
  21. data/vendor/assets/javascripts/bootstrap-alert.js +99 -0
  22. data/vendor/assets/javascripts/bootstrap-button.js +105 -0
  23. data/vendor/assets/javascripts/bootstrap-carousel.js +207 -0
  24. data/vendor/assets/javascripts/bootstrap-collapse.js +167 -0
  25. data/vendor/assets/javascripts/bootstrap-dropdown.js +165 -0
  26. data/vendor/assets/javascripts/bootstrap-fileupload.js +169 -0
  27. data/vendor/assets/javascripts/bootstrap-inputmask.js +355 -0
  28. data/vendor/assets/javascripts/bootstrap-modal.js +247 -0
  29. data/vendor/assets/javascripts/bootstrap-popover.js +114 -0
  30. data/vendor/assets/javascripts/bootstrap-rowlink.js +71 -0
  31. data/vendor/assets/javascripts/bootstrap-scrollspy.js +162 -0
  32. data/vendor/assets/javascripts/bootstrap-tab.js +144 -0
  33. data/vendor/assets/javascripts/bootstrap-tooltip.js +361 -0
  34. data/vendor/assets/javascripts/bootstrap-transition.js +60 -0
  35. data/vendor/assets/javascripts/bootstrap-typeahead.js +524 -0
  36. data/vendor/assets/javascripts/bootstrap.js +21 -0
  37. data/vendor/assets/stylesheets/bootstrap-responsive.less +1 -0
  38. data/vendor/assets/stylesheets/bootstrap.less +2 -0
  39. data/vendor/assets/stylesheets/bootstrap/accordion.less +34 -0
  40. data/vendor/assets/stylesheets/bootstrap/action-areas.less +14 -0
  41. data/vendor/assets/stylesheets/bootstrap/action-links.less +57 -0
  42. data/vendor/assets/stylesheets/bootstrap/alerts.less +79 -0
  43. data/vendor/assets/stylesheets/bootstrap/bootstrap.less +63 -0
  44. data/vendor/assets/stylesheets/bootstrap/breadcrumbs.less +24 -0
  45. data/vendor/assets/stylesheets/bootstrap/button-groups.less +229 -0
  46. data/vendor/assets/stylesheets/bootstrap/buttons.less +228 -0
  47. data/vendor/assets/stylesheets/bootstrap/carousel.less +158 -0
  48. data/vendor/assets/stylesheets/bootstrap/close.less +32 -0
  49. data/vendor/assets/stylesheets/bootstrap/code.less +61 -0
  50. data/vendor/assets/stylesheets/bootstrap/component-animations.less +22 -0
  51. data/vendor/assets/stylesheets/bootstrap/dropdowns.less +237 -0
  52. data/vendor/assets/stylesheets/bootstrap/fileupload.less +105 -0
  53. data/vendor/assets/stylesheets/bootstrap/forms-uneditable.less +159 -0
  54. data/vendor/assets/stylesheets/bootstrap/forms.less +690 -0
  55. data/vendor/assets/stylesheets/bootstrap/grid.less +21 -0
  56. data/vendor/assets/stylesheets/bootstrap/hero-unit.less +25 -0
  57. data/vendor/assets/stylesheets/bootstrap/iconic.less +209 -0
  58. data/vendor/assets/stylesheets/bootstrap/jasny-bootstrap.less +31 -0
  59. data/vendor/assets/stylesheets/bootstrap/jasny-forms.less +99 -0
  60. data/vendor/assets/stylesheets/bootstrap/jasny-forms.responsive-1200px-min.less +16 -0
  61. data/vendor/assets/stylesheets/bootstrap/jasny-forms.responsive-767px-max.less +17 -0
  62. data/vendor/assets/stylesheets/bootstrap/jasny-forms.responsive-768px-979px.less +36 -0
  63. data/vendor/assets/stylesheets/bootstrap/jasny-navs-tabbable.less +148 -0
  64. data/vendor/assets/stylesheets/bootstrap/jasny-responsive.less +27 -0
  65. data/vendor/assets/stylesheets/bootstrap/labels-badges.less +84 -0
  66. data/vendor/assets/stylesheets/bootstrap/layouts-semifluid.less +11 -0
  67. data/vendor/assets/stylesheets/bootstrap/layouts-semifluid.responsive-1200px-min.less +7 -0
  68. data/vendor/assets/stylesheets/bootstrap/layouts.less +16 -0
  69. data/vendor/assets/stylesheets/bootstrap/media.less +55 -0
  70. data/vendor/assets/stylesheets/bootstrap/mixins.less +702 -0
  71. data/vendor/assets/stylesheets/bootstrap/modals.less +95 -0
  72. data/vendor/assets/stylesheets/bootstrap/navbar.less +497 -0
  73. data/vendor/assets/stylesheets/bootstrap/navs.less +409 -0
  74. data/vendor/assets/stylesheets/bootstrap/page-alert.less +23 -0
  75. data/vendor/assets/stylesheets/bootstrap/page-alert.responsive-1200px-min.less +11 -0
  76. data/vendor/assets/stylesheets/bootstrap/page-alert.responsive-767px-max.less +20 -0
  77. data/vendor/assets/stylesheets/bootstrap/pager.less +43 -0
  78. data/vendor/assets/stylesheets/bootstrap/pagination.less +123 -0
  79. data/vendor/assets/stylesheets/bootstrap/popovers.less +133 -0
  80. data/vendor/assets/stylesheets/bootstrap/progress-bars.less +122 -0
  81. data/vendor/assets/stylesheets/bootstrap/reset.less +216 -0
  82. data/vendor/assets/stylesheets/bootstrap/responsive-1200px-min.less +28 -0
  83. data/vendor/assets/stylesheets/bootstrap/responsive-767px-max.less +193 -0
  84. data/vendor/assets/stylesheets/bootstrap/responsive-768px-979px.less +19 -0
  85. data/vendor/assets/stylesheets/bootstrap/responsive-navbar.less +189 -0
  86. data/vendor/assets/stylesheets/bootstrap/responsive-row-desktop.less +23 -0
  87. data/vendor/assets/stylesheets/bootstrap/responsive-tables.less +30 -0
  88. data/vendor/assets/stylesheets/bootstrap/responsive-utilities.less +59 -0
  89. data/vendor/assets/stylesheets/bootstrap/responsive.less +48 -0
  90. data/vendor/assets/stylesheets/bootstrap/rowlink.less +20 -0
  91. data/vendor/assets/stylesheets/bootstrap/scaffolding.less +53 -0
  92. data/vendor/assets/stylesheets/bootstrap/sprites.less +197 -0
  93. data/vendor/assets/stylesheets/bootstrap/tables.less +244 -0
  94. data/vendor/assets/stylesheets/bootstrap/thumbnails.less +53 -0
  95. data/vendor/assets/stylesheets/bootstrap/tooltip.less +70 -0
  96. data/vendor/assets/stylesheets/bootstrap/type.less +247 -0
  97. data/vendor/assets/stylesheets/bootstrap/utilities.less +30 -0
  98. data/vendor/assets/stylesheets/bootstrap/variables.less +302 -0
  99. data/vendor/assets/stylesheets/bootstrap/wells.less +29 -0
  100. metadata +241 -0
@@ -0,0 +1,361 @@
1
+ /* ===========================================================
2
+ * bootstrap-tooltip.js v2.3.1
3
+ * http://twitter.github.com/bootstrap/javascript.html#tooltips
4
+ * Inspired by the original jQuery.tipsy by Jason Frame
5
+ * ===========================================================
6
+ * Copyright 2012 Twitter, Inc.
7
+ *
8
+ * Licensed under the Apache License, Version 2.0 (the "License");
9
+ * you may not use this file except in compliance with the License.
10
+ * You may obtain a copy of the License at
11
+ *
12
+ * http://www.apache.org/licenses/LICENSE-2.0
13
+ *
14
+ * Unless required by applicable law or agreed to in writing, software
15
+ * distributed under the License is distributed on an "AS IS" BASIS,
16
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
+ * See the License for the specific language governing permissions and
18
+ * limitations under the License.
19
+ * ========================================================== */
20
+
21
+
22
+ !function ($) {
23
+
24
+ "use strict"; // jshint ;_;
25
+
26
+
27
+ /* TOOLTIP PUBLIC CLASS DEFINITION
28
+ * =============================== */
29
+
30
+ var Tooltip = function (element, options) {
31
+ this.init('tooltip', element, options)
32
+ }
33
+
34
+ Tooltip.prototype = {
35
+
36
+ constructor: Tooltip
37
+
38
+ , init: function (type, element, options) {
39
+ var eventIn
40
+ , eventOut
41
+ , triggers
42
+ , trigger
43
+ , i
44
+
45
+ this.type = type
46
+ this.$element = $(element)
47
+ this.options = this.getOptions(options)
48
+ this.enabled = true
49
+
50
+ triggers = this.options.trigger.split(' ')
51
+
52
+ for (i = triggers.length; i--;) {
53
+ trigger = triggers[i]
54
+ if (trigger == 'click') {
55
+ this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this))
56
+ } else if (trigger != 'manual') {
57
+ eventIn = trigger == 'hover' ? 'mouseenter' : 'focus'
58
+ eventOut = trigger == 'hover' ? 'mouseleave' : 'blur'
59
+ this.$element.on(eventIn + '.' + this.type, this.options.selector, $.proxy(this.enter, this))
60
+ this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this))
61
+ }
62
+ }
63
+
64
+ this.options.selector ?
65
+ (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) :
66
+ this.fixTitle()
67
+ }
68
+
69
+ , getOptions: function (options) {
70
+ options = $.extend({}, $.fn[this.type].defaults, this.$element.data(), options)
71
+
72
+ if (options.delay && typeof options.delay == 'number') {
73
+ options.delay = {
74
+ show: options.delay
75
+ , hide: options.delay
76
+ }
77
+ }
78
+
79
+ return options
80
+ }
81
+
82
+ , enter: function (e) {
83
+ var defaults = $.fn[this.type].defaults
84
+ , options = {}
85
+ , self
86
+
87
+ this._options && $.each(this._options, function (key, value) {
88
+ if (defaults[key] != value) options[key] = value
89
+ }, this)
90
+
91
+ self = $(e.currentTarget)[this.type](options).data(this.type)
92
+
93
+ if (!self.options.delay || !self.options.delay.show) return self.show()
94
+
95
+ clearTimeout(this.timeout)
96
+ self.hoverState = 'in'
97
+ this.timeout = setTimeout(function() {
98
+ if (self.hoverState == 'in') self.show()
99
+ }, self.options.delay.show)
100
+ }
101
+
102
+ , leave: function (e) {
103
+ var self = $(e.currentTarget)[this.type](this._options).data(this.type)
104
+
105
+ if (this.timeout) clearTimeout(this.timeout)
106
+ if (!self.options.delay || !self.options.delay.hide) return self.hide()
107
+
108
+ self.hoverState = 'out'
109
+ this.timeout = setTimeout(function() {
110
+ if (self.hoverState == 'out') self.hide()
111
+ }, self.options.delay.hide)
112
+ }
113
+
114
+ , show: function () {
115
+ var $tip
116
+ , pos
117
+ , actualWidth
118
+ , actualHeight
119
+ , placement
120
+ , tp
121
+ , e = $.Event('show')
122
+
123
+ if (this.hasContent() && this.enabled) {
124
+ this.$element.trigger(e)
125
+ if (e.isDefaultPrevented()) return
126
+ $tip = this.tip()
127
+ this.setContent()
128
+
129
+ if (this.options.animation) {
130
+ $tip.addClass('fade')
131
+ }
132
+
133
+ placement = typeof this.options.placement == 'function' ?
134
+ this.options.placement.call(this, $tip[0], this.$element[0]) :
135
+ this.options.placement
136
+
137
+ $tip
138
+ .detach()
139
+ .css({ top: 0, left: 0, display: 'block' })
140
+
141
+ this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element)
142
+
143
+ pos = this.getPosition()
144
+
145
+ actualWidth = $tip[0].offsetWidth
146
+ actualHeight = $tip[0].offsetHeight
147
+
148
+ switch (placement) {
149
+ case 'bottom':
150
+ tp = {top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2}
151
+ break
152
+ case 'top':
153
+ tp = {top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2}
154
+ break
155
+ case 'left':
156
+ tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth}
157
+ break
158
+ case 'right':
159
+ tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width}
160
+ break
161
+ }
162
+
163
+ this.applyPlacement(tp, placement)
164
+ this.$element.trigger('shown')
165
+ }
166
+ }
167
+
168
+ , applyPlacement: function(offset, placement){
169
+ var $tip = this.tip()
170
+ , width = $tip[0].offsetWidth
171
+ , height = $tip[0].offsetHeight
172
+ , actualWidth
173
+ , actualHeight
174
+ , delta
175
+ , replace
176
+
177
+ $tip
178
+ .offset(offset)
179
+ .addClass(placement)
180
+ .addClass('in')
181
+
182
+ actualWidth = $tip[0].offsetWidth
183
+ actualHeight = $tip[0].offsetHeight
184
+
185
+ if (placement == 'top' && actualHeight != height) {
186
+ offset.top = offset.top + height - actualHeight
187
+ replace = true
188
+ }
189
+
190
+ if (placement == 'bottom' || placement == 'top') {
191
+ delta = 0
192
+
193
+ if (offset.left < 0){
194
+ delta = offset.left * -2
195
+ offset.left = 0
196
+ $tip.offset(offset)
197
+ actualWidth = $tip[0].offsetWidth
198
+ actualHeight = $tip[0].offsetHeight
199
+ }
200
+
201
+ this.replaceArrow(delta - width + actualWidth, actualWidth, 'left')
202
+ } else {
203
+ this.replaceArrow(actualHeight - height, actualHeight, 'top')
204
+ }
205
+
206
+ if (replace) $tip.offset(offset)
207
+ }
208
+
209
+ , replaceArrow: function(delta, dimension, position){
210
+ this
211
+ .arrow()
212
+ .css(position, delta ? (50 * (1 - delta / dimension) + "%") : '')
213
+ }
214
+
215
+ , setContent: function () {
216
+ var $tip = this.tip()
217
+ , title = this.getTitle()
218
+
219
+ $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title)
220
+ $tip.removeClass('fade in top bottom left right')
221
+ }
222
+
223
+ , hide: function () {
224
+ var that = this
225
+ , $tip = this.tip()
226
+ , e = $.Event('hide')
227
+
228
+ this.$element.trigger(e)
229
+ if (e.isDefaultPrevented()) return
230
+
231
+ $tip.removeClass('in')
232
+
233
+ function removeWithAnimation() {
234
+ var timeout = setTimeout(function () {
235
+ $tip.off($.support.transition.end).detach()
236
+ }, 500)
237
+
238
+ $tip.one($.support.transition.end, function () {
239
+ clearTimeout(timeout)
240
+ $tip.detach()
241
+ })
242
+ }
243
+
244
+ $.support.transition && this.$tip.hasClass('fade') ?
245
+ removeWithAnimation() :
246
+ $tip.detach()
247
+
248
+ this.$element.trigger('hidden')
249
+
250
+ return this
251
+ }
252
+
253
+ , fixTitle: function () {
254
+ var $e = this.$element
255
+ if ($e.attr('title') || typeof($e.attr('data-original-title')) != 'string') {
256
+ $e.attr('data-original-title', $e.attr('title') || '').attr('title', '')
257
+ }
258
+ }
259
+
260
+ , hasContent: function () {
261
+ return this.getTitle()
262
+ }
263
+
264
+ , getPosition: function () {
265
+ var el = this.$element[0]
266
+ return $.extend({}, (typeof el.getBoundingClientRect == 'function') ? el.getBoundingClientRect() : {
267
+ width: el.offsetWidth
268
+ , height: el.offsetHeight
269
+ }, this.$element.offset())
270
+ }
271
+
272
+ , getTitle: function () {
273
+ var title
274
+ , $e = this.$element
275
+ , o = this.options
276
+
277
+ title = $e.attr('data-original-title')
278
+ || (typeof o.title == 'function' ? o.title.call($e[0]) : o.title)
279
+
280
+ return title
281
+ }
282
+
283
+ , tip: function () {
284
+ return this.$tip = this.$tip || $(this.options.template)
285
+ }
286
+
287
+ , arrow: function(){
288
+ return this.$arrow = this.$arrow || this.tip().find(".tooltip-arrow")
289
+ }
290
+
291
+ , validate: function () {
292
+ if (!this.$element[0].parentNode) {
293
+ this.hide()
294
+ this.$element = null
295
+ this.options = null
296
+ }
297
+ }
298
+
299
+ , enable: function () {
300
+ this.enabled = true
301
+ }
302
+
303
+ , disable: function () {
304
+ this.enabled = false
305
+ }
306
+
307
+ , toggleEnabled: function () {
308
+ this.enabled = !this.enabled
309
+ }
310
+
311
+ , toggle: function (e) {
312
+ var self = e ? $(e.currentTarget)[this.type](this._options).data(this.type) : this
313
+ self.tip().hasClass('in') ? self.hide() : self.show()
314
+ }
315
+
316
+ , destroy: function () {
317
+ this.hide().$element.off('.' + this.type).removeData(this.type)
318
+ }
319
+
320
+ }
321
+
322
+
323
+ /* TOOLTIP PLUGIN DEFINITION
324
+ * ========================= */
325
+
326
+ var old = $.fn.tooltip
327
+
328
+ $.fn.tooltip = function ( option ) {
329
+ return this.each(function () {
330
+ var $this = $(this)
331
+ , data = $this.data('tooltip')
332
+ , options = typeof option == 'object' && option
333
+ if (!data) $this.data('tooltip', (data = new Tooltip(this, options)))
334
+ if (typeof option == 'string') data[option]()
335
+ })
336
+ }
337
+
338
+ $.fn.tooltip.Constructor = Tooltip
339
+
340
+ $.fn.tooltip.defaults = {
341
+ animation: true
342
+ , placement: 'top'
343
+ , selector: false
344
+ , template: '<div class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>'
345
+ , trigger: 'hover focus'
346
+ , title: ''
347
+ , delay: 0
348
+ , html: false
349
+ , container: false
350
+ }
351
+
352
+
353
+ /* TOOLTIP NO CONFLICT
354
+ * =================== */
355
+
356
+ $.fn.tooltip.noConflict = function () {
357
+ $.fn.tooltip = old
358
+ return this
359
+ }
360
+
361
+ }(window.jQuery);
@@ -0,0 +1,60 @@
1
+ /* ===================================================
2
+ * bootstrap-transition.js v2.3.1
3
+ * http://twitter.github.com/bootstrap/javascript.html#transitions
4
+ * ===================================================
5
+ * Copyright 2012 Twitter, Inc.
6
+ *
7
+ * Licensed under the Apache License, Version 2.0 (the "License");
8
+ * you may not use this file except in compliance with the License.
9
+ * You may obtain a copy of the License at
10
+ *
11
+ * http://www.apache.org/licenses/LICENSE-2.0
12
+ *
13
+ * Unless required by applicable law or agreed to in writing, software
14
+ * distributed under the License is distributed on an "AS IS" BASIS,
15
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ * See the License for the specific language governing permissions and
17
+ * limitations under the License.
18
+ * ========================================================== */
19
+
20
+
21
+ !function ($) {
22
+
23
+ "use strict"; // jshint ;_;
24
+
25
+
26
+ /* CSS TRANSITION SUPPORT (http://www.modernizr.com/)
27
+ * ======================================================= */
28
+
29
+ $(function () {
30
+
31
+ $.support.transition = (function () {
32
+
33
+ var transitionEnd = (function () {
34
+
35
+ var el = document.createElement('bootstrap')
36
+ , transEndEventNames = {
37
+ 'WebkitTransition' : 'webkitTransitionEnd'
38
+ , 'MozTransition' : 'transitionend'
39
+ , 'OTransition' : 'oTransitionEnd otransitionend'
40
+ , 'transition' : 'transitionend'
41
+ }
42
+ , name
43
+
44
+ for (name in transEndEventNames){
45
+ if (el.style[name] !== undefined) {
46
+ return transEndEventNames[name]
47
+ }
48
+ }
49
+
50
+ }())
51
+
52
+ return transitionEnd && {
53
+ end: transitionEnd
54
+ }
55
+
56
+ })()
57
+
58
+ })
59
+
60
+ }(window.jQuery);
@@ -0,0 +1,524 @@
1
+ /* =============================================================
2
+ * bootstrap-typeahead.js v2.3.1-j6
3
+ * http://twitter.github.com/bootstrap/javascript.html#typeahead
4
+ * =============================================================
5
+ * Copyright 2012 Twitter, Inc.
6
+ *
7
+ * Licensed under the Apache License, Version 2.0 (the "License");
8
+ * you may not use this file except in compliance with the License.
9
+ * You may obtain a copy of the License at
10
+ *
11
+ * http://www.apache.org/licenses/LICENSE-2.0
12
+ *
13
+ * Unless required by applicable law or agreed to in writing, software
14
+ * distributed under the License is distributed on an "AS IS" BASIS,
15
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ * See the License for the specific language governing permissions and
17
+ * limitations under the License.
18
+ * ============================================================ */
19
+
20
+
21
+ !function($){
22
+
23
+ "use strict"; // jshint ;_;
24
+
25
+
26
+ /* TYPEAHEAD PUBLIC CLASS DEFINITION
27
+ * ================================= */
28
+
29
+ var Typeahead = function (element, options) {
30
+ this.$element = $(element)
31
+ this.options = $.extend({}, $.fn.typeahead.defaults, options)
32
+ if (this.options.target) this.$target = $(this.options.target)
33
+ this.matcher = this.options.matcher || this.matcher
34
+ this.sorter = this.options.sorter || this.sorter
35
+ this.highlighter = this.options.highlighter || this.highlighter
36
+ this.updater = this.options.updater || this.updater
37
+ this.source = this.options.source
38
+ this.strict = this.options.strict
39
+ this.$menu = $(this.options.menu)
40
+ this.shown = false
41
+
42
+ if (typeof this.source == 'string') {
43
+ this.url = this.source
44
+ this.source = this.searchAjax
45
+ }
46
+
47
+ if (element.nodeName == 'SELECT') this.replaceSelect()
48
+
49
+ this.text = this.$element.val()
50
+
51
+ this.$element
52
+ .attr('data-text', this.value)
53
+ .attr('autocomplete', "off")
54
+
55
+ if (typeof this.$target != 'undefined') this.$element.attr('data-value', this.$target.val())
56
+ else if (typeof this.$element.attr('data-value') == 'undefined') this.$element.attr('data-value', this.strict ? '' : this.value)
57
+
58
+ this.$menu.css('min-width', this.$element.width() + 12)
59
+
60
+ this.listen()
61
+ }
62
+
63
+ Typeahead.prototype = {
64
+
65
+ constructor: Typeahead
66
+
67
+ , replaceSelect: function () {
68
+ this.$target = this.$element
69
+ this.$element = $('<input type="text" />')
70
+
71
+ this.source = {}
72
+ this.strict = true
73
+
74
+ var options = this.$target.find('option')
75
+ var $option;
76
+ for (var i=0; i<options.length; i++) {
77
+ $option = $(options[i]);
78
+ if ($option.val() === '') {
79
+ this.$element.attr('placeholder', $option.html());
80
+ continue;
81
+ }
82
+
83
+ this.source[$option.val()] = $option.html()
84
+ if (this.$target.val() == $option.val()) this.$element.val($option.html())
85
+ }
86
+
87
+ var attr = this.$target[0].attributes
88
+ for (i=0; i<attr.length; i++) {
89
+ if (attr[i].nodeName != 'type' && attr[i].nodeName != 'name' && attr[i].nodeName != 'id' && attr[i].nodeName != 'data-provide' && !attr[i].nodeName.match(/^on/)) {
90
+ this.$element.attr(attr[i].nodeName, attr[i].nodeValue)
91
+ }
92
+ }
93
+
94
+ this.$element.insertAfter(this.$target)
95
+ if (this.$target.attr('autofocus')) this.$element.trigger('focus').select()
96
+ this.$target.attr('autofocus', false)
97
+ this.$target.hide()
98
+ }
99
+
100
+ , destroyReplacement: function () {
101
+ // Detroy replacement element, so it doesn't mess up the browsers autofill on refresh
102
+ if (typeof this.$target != 'undefined' && this.$target[0].nodeName == 'SELECT') {
103
+ this.$element.replaceWith('');
104
+ }
105
+ }
106
+
107
+ , select: function () {
108
+ var li = this.$menu.find('.active')
109
+ , val = li.attr('data-value')
110
+ , text = li.find('.item-text').length > 0 ? li.find('.item-text').text() : li.text()
111
+
112
+ val = this.updater(val, 'value')
113
+ text = this.updater(text, 'text')
114
+
115
+ this.$element
116
+ .val(text)
117
+ .attr('data-value', val)
118
+
119
+ this.text = text
120
+
121
+ if (typeof this.$target != 'undefined') {
122
+ this.$target
123
+ .val(val)
124
+ .trigger('change')
125
+ }
126
+
127
+ this.$element.trigger('change')
128
+
129
+ return this.hide()
130
+ }
131
+
132
+ , updater: function (text, type) {
133
+ return text
134
+ }
135
+
136
+ , show: function () {
137
+ var pos = $.extend({}, this.$element.position(), {
138
+ height: this.$element[0].offsetHeight
139
+ })
140
+
141
+ this.$menu
142
+ .insertAfter(this.$element)
143
+ .css({
144
+ top: pos.top + pos.height
145
+ , left: pos.left
146
+ })
147
+ .show()
148
+
149
+ this.shown = true
150
+ return this
151
+ }
152
+
153
+ , hide: function () {
154
+ this.$menu.hide()
155
+ this.shown = false
156
+ return this
157
+ }
158
+
159
+ , lookup: function (event) {
160
+ var items
161
+
162
+ this.query = this.$element.val()
163
+
164
+ if (!this.query || this.query.length < this.options.minLength) {
165
+ return this.shown ? this.hide() : this
166
+ }
167
+
168
+ items = $.isFunction(this.source) ? this.source(this.query, $.proxy(this.process, this)) : this.source
169
+
170
+ return items ? this.process(items) : this
171
+ }
172
+
173
+ , process: function (items) {
174
+ return $.isArray(items) ? this.processArray(items) : this.processObject(items)
175
+ }
176
+
177
+ , processArray: function (items) {
178
+ var that = this
179
+
180
+ items = $.grep(items, function (item) {
181
+ return that.matcher(item)
182
+ })
183
+
184
+ items = this.sorter(items)
185
+
186
+ if (!items.length) {
187
+ return this.shown ? this.hide() : this
188
+ }
189
+
190
+ return this.render(items.slice(0, this.options.items)).show()
191
+ }
192
+
193
+ , processObject: function (itemsIn) {
194
+ var that = this
195
+ , items = {}
196
+ , i = 0
197
+
198
+ $.each(itemsIn, function (key, item) {
199
+ if (that.matcher(item)) items[key] = item
200
+ })
201
+
202
+ items = this.sorter(items)
203
+
204
+ if ($.isEmptyObject(items)) {
205
+ return this.shown ? this.hide() : this
206
+ }
207
+
208
+ $.each(items, function(key, item) {
209
+ if (i++ >= that.options.items) delete items[key]
210
+ })
211
+
212
+ return this.render(items).show()
213
+ }
214
+
215
+ , searchAjax: function (query, process) {
216
+ var that = this
217
+
218
+ if (this.ajaxTimeout) clearTimeout(this.ajaxTimeout)
219
+
220
+ this.ajaxTimeout = setTimeout(function () {
221
+ if (that.ajaxTimeout) clearTimeout(that.ajaxTimeout)
222
+
223
+ if (query === "") {
224
+ that.hide()
225
+ return
226
+ }
227
+
228
+ $.get(that.url, {'q': query, 'limit': that.options.items }, function (items) {
229
+ if (typeof items == 'string') items = JSON.parse(items)
230
+ process(items)
231
+ })
232
+ }, this.options.ajaxdelay)
233
+ }
234
+
235
+ , matcher: function (item) {
236
+ return ~item.toLowerCase().indexOf(this.query.toLowerCase())
237
+ }
238
+
239
+ , sorter: function (items) {
240
+ return $.isArray(items) ? this.sortArray(items) : this.sortObject(items)
241
+ }
242
+
243
+ , sortArray: function (items) {
244
+ var beginswith = []
245
+ , caseSensitive = []
246
+ , caseInsensitive = []
247
+ , item
248
+
249
+ while (item = items.shift()) {
250
+ if (!item.toLowerCase().indexOf(this.query.toLowerCase())) beginswith.push(item)
251
+ else if (~item.indexOf(this.query)) caseSensitive.push(item)
252
+ else caseInsensitive.push(item)
253
+ }
254
+
255
+ return beginswith.concat(caseSensitive, caseInsensitive)
256
+ }
257
+
258
+ , sortObject: function (items) {
259
+ var sorted = {}
260
+ , key;
261
+
262
+ for (key in items) {
263
+ if (!items[key].toLowerCase().indexOf(this.query.toLowerCase())) {
264
+ sorted[key] = items[key];
265
+ delete items[key]
266
+ }
267
+ }
268
+
269
+ for (key in items) {
270
+ if (~items[key].indexOf(this.query)) {
271
+ sorted[key] = items[key];
272
+ delete items[key]
273
+ }
274
+ }
275
+
276
+ for (key in items) {
277
+ sorted[key] = items[key]
278
+ }
279
+
280
+ return sorted
281
+ }
282
+
283
+ , highlighter: function (item) {
284
+ var query = this.query.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, '\\$&')
285
+ return item.replace(new RegExp('(' + query + ')', 'ig'), function ($1, match) {
286
+ return '<strong>' + match + '</strong>'
287
+ })
288
+ }
289
+
290
+ , render: function (items) {
291
+ var that = this
292
+ , list = $([])
293
+
294
+ $.map(items, function (item, value) {
295
+ if (list.length >= that.options.items) return
296
+
297
+ var li
298
+ , a
299
+
300
+ if ($.isArray(items)) value = item
301
+
302
+ li = $(that.options.item)
303
+ a = li.find('a').length ? li.find('a') : li
304
+ a.html(that.highlighter(item))
305
+
306
+ li.attr('data-value', value)
307
+ if (li.find('a').length === 0) li.addClass('dropdown-header')
308
+
309
+ list.push(li[0])
310
+ })
311
+
312
+ list.not('.dropdown-header').first().addClass('active')
313
+
314
+ this.$menu.html(list)
315
+
316
+ return this
317
+ }
318
+
319
+ , next: function (event) {
320
+ var active = this.$menu.find('.active').removeClass('active')
321
+ , next = active.nextAll('li:not(.dropdown-header)').first()
322
+
323
+ if (!next.length) {
324
+ next = $(this.$menu.find('li:not(.dropdown-header)')[0])
325
+ }
326
+
327
+ next.addClass('active')
328
+ }
329
+
330
+ , prev: function (event) {
331
+ var active = this.$menu.find('.active').removeClass('active')
332
+ , prev = active.prevAll('li:not(.dropdown-header)').first()
333
+
334
+ if (!prev.length) {
335
+ prev = this.$menu.find('li:not(.dropdown-header)').last()
336
+ }
337
+
338
+ prev.addClass('active')
339
+ }
340
+
341
+ , listen: function () {
342
+ this.$element
343
+ .on('focus', $.proxy(this.focus, this))
344
+ .on('blur', $.proxy(this.blur, this))
345
+ .on('change', $.proxy(this.change, this))
346
+ .on('keypress', $.proxy(this.keypress, this))
347
+ .on('keyup', $.proxy(this.keyup, this))
348
+
349
+ if (this.eventSupported('keydown')) {
350
+ this.$element.on('keydown', $.proxy(this.keydown, this))
351
+ }
352
+
353
+ this.$menu
354
+ .on('click', $.proxy(this.click, this))
355
+ .on('mouseenter', 'li', $.proxy(this.mouseenter, this))
356
+ .on('mouseleave', 'li', $.proxy(this.mouseleave, this))
357
+
358
+ $(window).on('unload', $.proxy(this.destroyReplacement, this))
359
+ }
360
+
361
+ , eventSupported: function(eventName) {
362
+ var isSupported = eventName in this.$element
363
+ if (!isSupported) {
364
+ this.$element.setAttribute(eventName, 'return;')
365
+ isSupported = typeof this.$element[eventName] === 'function'
366
+ }
367
+ return isSupported
368
+ }
369
+
370
+ , move: function (e) {
371
+ if (!this.shown) return
372
+
373
+ switch(e.keyCode) {
374
+ case 9: // tab
375
+ case 13: // enter
376
+ case 27: // escape
377
+ e.preventDefault()
378
+ break
379
+
380
+ case 38: // up arrow
381
+ e.preventDefault()
382
+ this.prev()
383
+ break
384
+
385
+ case 40: // down arrow
386
+ e.preventDefault()
387
+ this.next()
388
+ break
389
+ }
390
+
391
+ e.stopPropagation()
392
+ }
393
+
394
+ , keydown: function (e) {
395
+ this.suppressKeyPressRepeat = ~$.inArray(e.keyCode, [40,38,9,13,27])
396
+ this.move(e)
397
+ }
398
+
399
+ , keypress: function (e) {
400
+ if (this.suppressKeyPressRepeat) return
401
+ this.move(e)
402
+ }
403
+
404
+ , keyup: function (e) {
405
+ switch(e.keyCode) {
406
+ case 40: // down arrow
407
+ case 38: // up arrow
408
+ case 16: // shift
409
+ case 17: // ctrl
410
+ case 18: // alt
411
+ break
412
+
413
+ case 9: // tab
414
+ case 13: // enter
415
+ if (!this.shown) return
416
+ this.select()
417
+ break
418
+
419
+ case 27: // escape
420
+ if (!this.shown) return
421
+ this.hide()
422
+ break
423
+
424
+ default:
425
+ this.lookup()
426
+ }
427
+
428
+ e.stopPropagation()
429
+ e.preventDefault()
430
+ }
431
+
432
+ , change: function (e) {
433
+ var value
434
+
435
+ if (this.$element.val() != this.text) {
436
+ value = this.$element.val() === '' || this.strict ? '' : this.$element.val()
437
+
438
+ this.$element.val(value)
439
+ this.$element.attr('data-value', value)
440
+ this.text = value
441
+ if (typeof this.$target != 'undefined') this.$target.val(value)
442
+ }
443
+ }
444
+
445
+ , focus: function (e) {
446
+ this.focused = true
447
+ }
448
+
449
+ , blur: function (e) {
450
+ this.focused = false
451
+ if (!this.mousedover && this.shown) this.hide()
452
+ }
453
+
454
+ , click: function (e) {
455
+ e.stopPropagation()
456
+ e.preventDefault()
457
+ this.select()
458
+ this.$element.focus()
459
+ }
460
+
461
+ , mouseenter: function (e) {
462
+ this.mousedover = true
463
+ this.$menu.find('.active').removeClass('active')
464
+ $(e.currentTarget).addClass('active')
465
+ }
466
+
467
+ , mouseleave: function (e) {
468
+ this.mousedover = false
469
+ if (!this.focused && this.shown) this.hide()
470
+ }
471
+
472
+ }
473
+
474
+
475
+ /* TYPEAHEAD PLUGIN DEFINITION
476
+ * =========================== */
477
+
478
+ var old = $.fn.typeahead
479
+
480
+ $.fn.typeahead = function (option) {
481
+ return this.each(function () {
482
+ var $this = $(this)
483
+ , data = $this.data('typeahead')
484
+ , options = typeof option == 'object' && option
485
+ if (!data) $this.data('typeahead', (data = new Typeahead(this, options)))
486
+ if (typeof option == 'string') data[option]()
487
+ })
488
+ }
489
+
490
+ $.fn.typeahead.defaults = {
491
+ source: []
492
+ , items: 8
493
+ , menu: '<ul class="typeahead dropdown-menu"></ul>'
494
+ , item: '<li><a href="#"></a></li>'
495
+ , ajaxdelay: 400
496
+ , minLength: 1
497
+ }
498
+
499
+ $.fn.typeahead.Constructor = Typeahead
500
+
501
+
502
+ /* TYPEAHEAD NO CONFLICT
503
+ * =================== */
504
+
505
+ $.fn.typeahead.noConflict = function () {
506
+ $.fn.typeahead = old
507
+ return this
508
+ }
509
+
510
+
511
+ /* TYPEAHEAD DATA-API
512
+ * ================== */
513
+
514
+ $(document)
515
+ .off('focus.typeahead.data-api') // overwriting Twitter's typeahead
516
+ .on('focus.typeahead.data-api', '[data-provide="typeahead"]', function (e) {
517
+ var $this = $(this)
518
+ if ($this.data('typeahead')) return
519
+ if ($this.is('select')) $this.attr('autofocus', true)
520
+ e.preventDefault()
521
+ $this.typeahead($this.data())
522
+ })
523
+
524
+ }(window.jQuery);