laces 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (106) hide show
  1. data/CONTRIBUTING.md +38 -0
  2. data/Gemfile +3 -0
  3. data/Gemfile.lock +122 -0
  4. data/LICENSE +21 -0
  5. data/README.md +5 -0
  6. data/Rakefile +8 -0
  7. data/bin/laces +16 -0
  8. data/features/creating_a_heroku_app.feature +9 -0
  9. data/features/rake_clean.feature +21 -0
  10. data/features/skipping_clearance.feature +13 -0
  11. data/features/step_definitions/gem_steps.rb +5 -0
  12. data/features/step_definitions/heroku_steps.rb +3 -0
  13. data/features/step_definitions/shell_steps.rb +55 -0
  14. data/features/support/bin/heroku +5 -0
  15. data/features/support/env.rb +15 -0
  16. data/features/support/fake_heroku.rb +21 -0
  17. data/laces-0.0.1.gem +0 -0
  18. data/laces.gemspec +35 -0
  19. data/lib/laces/actions.rb +35 -0
  20. data/lib/laces/app_builder.rb +237 -0
  21. data/lib/laces/generators/app_generator.rb +111 -0
  22. data/lib/laces/version.rb +3 -0
  23. data/templates/.DS_Store +0 -0
  24. data/templates/Gemfile_template +76 -0
  25. data/templates/HEROKU_README.md +66 -0
  26. data/templates/Procfile +1 -0
  27. data/templates/README.md +81 -0
  28. data/templates/app/assets/imgs/glyphicons-halflings-white.png +0 -0
  29. data/templates/app/assets/imgs/glyphicons-halflings.png +0 -0
  30. data/templates/app/assets/javascripts/admin.coffee +20 -0
  31. data/templates/app/assets/javascripts/application.coffee +21 -0
  32. data/templates/app/assets/javascripts/lib/actinology.coffee +47 -0
  33. data/templates/app/assets/javascripts/lib/analytics.js +11 -0
  34. data/templates/app/assets/javascripts/lib/auth_token_sync.js +17 -0
  35. data/templates/app/assets/javascripts/lib/backbone-ui.js +2455 -0
  36. data/templates/app/assets/javascripts/lib/backbone.coffee +27 -0
  37. data/templates/app/assets/javascripts/lib/backbone/collection.js +249 -0
  38. data/templates/app/assets/javascripts/lib/backbone/events.js +64 -0
  39. data/templates/app/assets/javascripts/lib/backbone/helpers.js +68 -0
  40. data/templates/app/assets/javascripts/lib/backbone/history.js +144 -0
  41. data/templates/app/assets/javascripts/lib/backbone/model.js +291 -0
  42. data/templates/app/assets/javascripts/lib/backbone/router.coffee +45 -0
  43. data/templates/app/assets/javascripts/lib/backbone/sync.coffee +38 -0
  44. data/templates/app/assets/javascripts/lib/backbone/view.js +150 -0
  45. data/templates/app/assets/javascripts/lib/backbone_extended.coffee +276 -0
  46. data/templates/app/assets/javascripts/lib/bootstrap.js +1836 -0
  47. data/templates/app/assets/javascripts/lib/inflection.js +658 -0
  48. data/templates/app/assets/javascripts/lib/jquery-ui.js +343 -0
  49. data/templates/app/assets/javascripts/lib/jquery.hotkeys.js +102 -0
  50. data/templates/app/assets/javascripts/lib/jquery.js +4 -0
  51. data/templates/app/assets/javascripts/lib/milk.js.coffee +265 -0
  52. data/templates/app/assets/javascripts/lib/raw.js +143 -0
  53. data/templates/app/assets/javascripts/lib/strftime.js +732 -0
  54. data/templates/app/assets/javascripts/lib/throttle-debounce.js +251 -0
  55. data/templates/app/assets/javascripts/lib/timeago.js +148 -0
  56. data/templates/app/assets/javascripts/lib/underscore.js +28 -0
  57. data/templates/app/assets/styles/application.sass +21 -0
  58. data/templates/app/assets/styles/layouts/default.sass +15 -0
  59. data/templates/app/assets/styles/layouts/footer.sass +0 -0
  60. data/templates/app/assets/styles/layouts/forms.sass +34 -0
  61. data/templates/app/assets/styles/layouts/header.sass +0 -0
  62. data/templates/app/assets/styles/layouts/navigation.sass +0 -0
  63. data/templates/app/assets/styles/lib/backbone-ui.css +580 -0
  64. data/templates/app/assets/styles/lib/bootstrap.sass +4248 -0
  65. data/templates/app/assets/styles/pages/home.sass +0 -0
  66. data/templates/app/assets/styles/sessions/new.sass +0 -0
  67. data/templates/app/assets/styles/users/activate.sass +0 -0
  68. data/templates/app/assets/styles/users/new.sass +0 -0
  69. data/templates/app/assets/styles/users/suspended.sass +0 -0
  70. data/templates/app/controllers/app_controller.rb +14 -0
  71. data/templates/app/controllers/pages_controller.rb +2 -0
  72. data/templates/app/controllers/sessions_controller.rb +2 -0
  73. data/templates/app/controllers/templating_controller.rb +31 -0
  74. data/templates/app/controllers/users_controller.rb +2 -0
  75. data/templates/app/helpers/app_helper.rb +94 -0
  76. data/templates/app/helpers/users_helper.rb +53 -0
  77. data/templates/app/models/user.rb +9 -0
  78. data/templates/app/views/devise/confirmations/new.haml +9 -0
  79. data/templates/app/views/devise/passwords/edit.haml +11 -0
  80. data/templates/app/views/devise/passwords/new.haml +9 -0
  81. data/templates/app/views/devise/registrations/edit.haml +13 -0
  82. data/templates/app/views/devise/registrations/new.haml +8 -0
  83. data/templates/app/views/devise/sessions/_form.haml +7 -0
  84. data/templates/app/views/devise/sessions/new.haml +5 -0
  85. data/templates/app/views/devise/unlocks/new.haml +7 -0
  86. data/templates/app/views/layouts/_ascii.haml +0 -0
  87. data/templates/app/views/layouts/_column.haml +0 -0
  88. data/templates/app/views/layouts/_content.haml +1 -0
  89. data/templates/app/views/layouts/_extra.haml +0 -0
  90. data/templates/app/views/layouts/_footer.haml +9 -0
  91. data/templates/app/views/layouts/_head.haml +13 -0
  92. data/templates/app/views/layouts/_header.haml +6 -0
  93. data/templates/app/views/layouts/application.html.haml +16 -0
  94. data/templates/app/views/pages/home.haml +1 -0
  95. data/templates/config/app.yml +29 -0
  96. data/templates/config/application.erb +28 -0
  97. data/templates/config/database.yml +32 -0
  98. data/templates/config/initializers/devise.rb +232 -0
  99. data/templates/config/initializers/rabl_init.rb +4 -0
  100. data/templates/config/initializers/setup_mail.rb +13 -0
  101. data/templates/config/initializers/wrap_parameters.rb +12 -0
  102. data/templates/db/migrate/user_migration.rb +36 -0
  103. data/templates/laces_gitignore +9 -0
  104. data/templates/lib/development_mail_interceptor.rb +7 -0
  105. data/templates/lib/templating.rb +40 -0
  106. metadata +225 -0
@@ -0,0 +1,276 @@
1
+ $.ajaxSetup
2
+  beforeSend:(xhr)->
3
+    xhr.setRequestHeader 'Accept', 'application/json'
4
+  cache: false
5
+
6
+ ViewHelpers=
7
+ el_template:(path)->
8
+ attrs = if typeof @model.attrs() is 'function'
9
+ @model.attrs()
10
+ else
11
+ @model.attributes
12
+ html = @template path, attrs
13
+ $(@el).html html
14
+ fire:(event)->
15
+ $(@el).trigger event
16
+ bind_render:->
17
+ _.bindAll @ , 'render'
18
+ @collection.bind 'add' , @render
19
+ @collection.bind 'reset', @render
20
+ validate:->
21
+ Backbone.Validation.bind @,
22
+ invalid: (view, attr, error, selector)->
23
+ l = $("label[for=document_#{attr}]").html()
24
+ $('.errors').addClass 'on'
25
+ $('.errors').append "<tr class='error'><td class='name'>#{l}</td><td>#{error}</td></tr>"
26
+ ModelHelpers=
27
+ attrs:->
28
+ attrs = {}
29
+ self = @
30
+ attrs = @toJSON()
31
+ attrs['id'] = @id if @id
32
+ _.each attrs, (value,attr)->
33
+ a = @get.call this, attr
34
+ a = this[attr](a) if typeof this[attr] == 'function'
35
+ attrs[attr] = a
36
+ ,this
37
+ attrs
38
+ CollectionHelpers =
39
+ # @collection.collect
40
+ # ---------------
41
+ #
42
+ # This method is best used with the BackboneHelpers.collect
43
+ # In your view that has a collection you can call collect on
44
+ # the collection and it will render the the individual models
45
+ # if you used BackboneHelpers.collect to render the current
46
+ # view all you have to do now is:
47
+ #
48
+ # (assuming @collect 'projects' was called)
49
+ # @collection.collect
50
+ #
51
+ # This would render the template 'projects/index' and attach
52
+ # it the '.projects'
53
+ #
54
+ # if you don't want to render a template because it already exists
55
+ # you can just set has_template_index to false
56
+ collect:->
57
+ e = $ @context.el
58
+ find = arguments[0]
59
+ has_find = find isnt undefined
60
+ options = arguments[1]
61
+ options ||= {}
62
+ ti = options.template_index
63
+ delete options.template_index
64
+ template_index = "#{@name}/index"
65
+ html = @context.template template_index, {}
66
+ html = @context.template v, {} if ti isnt undefined
67
+
68
+ hti = options.has_template_index
69
+ delete options.has_template_index
70
+ e.html html if hti != false
71
+
72
+ t = options.template
73
+ delete options.template
74
+ template = "#{@name}/#{@name.singularize()}"
75
+ template = t if t isnt undefined
76
+ selector = e
77
+ selector = e.find(find) if has_find
78
+ primer = options.primer || template_index
79
+ selector.html ''
80
+ if @length == 0
81
+ html = @context.template "#{primer}_primer", {}
82
+ e.html html
83
+ else
84
+ for model in @context.collection.models
85
+ options['model'] = model
86
+ e = @context.partial null, template, options
87
+ selector.append e.el
88
+ BackboneHelpers =
89
+ redirect_on_browse:->
90
+ if @browsing()
91
+ return window.location.pathname = '/signup'
92
+ else
93
+ false
94
+ browsing:->
95
+ $('body').hasClass('browse_pages')
96
+ hash:(i=null)->
97
+ e = window.location.hash.replace /#/, ''
98
+ e = e.replace /\?.+$/, ''
99
+ e = e.split '/'
100
+ if i then e[i] else e
101
+ template: (path,data)->
102
+ template = null
103
+ eval "template = Template.#{path.replace(/\//g,'.')}"
104
+ new throw "template is undefined: Template.#{path.replace(/\//g,'.')}" if template is undefined
105
+ Milk.render template, data
106
+
107
+ # collect
108
+ # ---------------
109
+ # This method makes it easy to quickly render a collection.
110
+ # all you need to do is pass in the name of the collection you
111
+ # want to be rendered eg.
112
+ #
113
+ # collect 'projects'
114
+ #
115
+ # If your dealing with an association:
116
+ #
117
+ # collect 'projects/tasks', id: 5
118
+ #
119
+ # It will create a collection in this case App.Collections.Projects
120
+ # with the model being App.Models.Project and an url with '/projects'.
121
+ # The collection will be assigned to the @collection instance variable
122
+ # so you can reference it in your view. It will not invoke fetch().
123
+ #
124
+ # It will also called @partial '.projects', 'projects/index' and
125
+ # attach the collection and whatever options you pass to to the
126
+ # collect method.
127
+ #
128
+ # If you want to override the el of the partial you just need to specify
129
+ # the el the option. eg.
130
+ #
131
+ # @collect 'users', el: '.people'
132
+ #
133
+ # If you want to override the partial path thats being used in the partial you just
134
+ # need to specify the template option (probably should not be called template since
135
+ # that might confuse people with the actual template being render) eg.
136
+ #
137
+ # #collect 'users', template: 'awesome_people/index'
138
+ #
139
+ # If you want to override the model being use you need to pass just the
140
+ # model name to the model option eg.
141
+ #
142
+ # @collect 'groups', model: 'community'
143
+ #
144
+ collect:->
145
+ name = arguments[0]
146
+ options = arguments[1]
147
+ options ||= {}
148
+ url = if name.match(/\//)
149
+ e = name.split '/'
150
+ context = e[0]
151
+ name = e[1]
152
+ reg = new RegExp "#{context}\\/(\\d+)"
153
+ id = options.id
154
+ "/#{context}/#{id}/#{name}"
155
+ else
156
+ "/#{name}"
157
+ klass = name.camelize()
158
+ has_model = options['model'] isnt undefined
159
+ model_name = if has_model
160
+ model_name = options['model']
161
+ delete options['model']
162
+ model_name.camelize()
163
+ else if @model_name
164
+ model_name = @model_name
165
+ model_name.camelize()
166
+ else
167
+ klass.singularize()
168
+ @collection = new App.Collections[klass]
169
+ result_model = @result_model || "#{model_name}Result"
170
+ if App.Models[result_model]
171
+ @collection.results_model = new App.Models[result_model]()
172
+ @collection.results_model.collection = @collection
173
+ @collection.model = App.Models[model_name]
174
+ @collection.url = url
175
+ @collection.name = name
176
+ options ||= {}
177
+ options.collection = @collection
178
+
179
+ selector = ".#{name}"
180
+ if options['el'] isnt undefined
181
+ selector = options['el']
182
+ delete options['el']
183
+
184
+ template = "#{name}/index"
185
+ if options['template'] isnt undefined
186
+ template = options['template']
187
+ delete options['template']
188
+ e = @partial selector, template, options
189
+ @collection.context = e
190
+ @collection
191
+ partial:->
192
+ el = arguments[0]
193
+ name = arguments[1]
194
+ options = arguments[2]
195
+ scope = 'App'
196
+ if name.match /admin/
197
+ scope = 'Admin'
198
+ name = name.replace /admin\//, ''
199
+ e = name.split '/'
200
+ options ||= {}
201
+ options['el'] = el if el != null
202
+ p = (item.camelize() for item in e)
203
+ eval "var p = new #{scope}.Views.#{p.join('.')}(options)"
204
+ instance_var = e.join('_')
205
+ @[instance_var] = p
206
+ post:(url,success,data)->
207
+ token = $("meta[name='csrf-token']").attr('content')
208
+ data['authenticity_token'] = token
209
+ $.ajax
210
+ type : 'post'
211
+ url : url,
212
+ data : data
213
+ dataType : 'json'
214
+ context : this
215
+ success : success
216
+ get:(url,success,data)->
217
+ $.ajax
218
+ url : url,
219
+ data : data
220
+ dataType : 'json'
221
+ context : this
222
+ success : success
223
+ resize:->
224
+ App.Helpers.Base.resize_panels()
225
+ _.extend Backbone.Router.prototype , BackboneHelpers
226
+ _.extend Backbone.View.prototype , BackboneHelpers
227
+ _.extend Backbone.View.prototype , ViewHelpers
228
+ _.extend Backbone.Model.prototype , ModelHelpers
229
+ _.extend Backbone.Collection.prototype, CollectionHelpers
230
+
231
+ class App.Routers.Queryable extends Backbone.Router
232
+ get_name:->
233
+ @alias || @name
234
+ initialize:->
235
+ @collect @name, el: '.content'
236
+ @routes ||= {}
237
+ n = @name
238
+ n = @alias if @alias
239
+ group_path = "groups/:group_id/#{n}"
240
+ @routes[group_path] = 'group_index' if @group
241
+ @routes[n] = 'index'
242
+ @routes["#{n}?:q"] = 'query'
243
+ if @with_heading
244
+ _.bindAll @, 'heading'
245
+ $('.heading').on 'group', @heading
246
+ @_bindRoutes()
247
+ index:->
248
+ Search.data = {}
249
+ $('#search').val null
250
+ if @with_heading
251
+ $('.column').trigger 'expand'
252
+ if App.skip
253
+ App.skip = false
254
+ else
255
+ @collection.fetch_results()
256
+ query:(data)->
257
+ data = $.deserialize_hash data
258
+ Search.data = data
259
+ $('.column').trigger 'expand'
260
+ $('#search').trigger 'register', @
261
+ $('#search').val data.q
262
+ $('#search').trigger 'engage', data
263
+ group_index:(id)->
264
+ @collection.fetch_results
265
+ group: id
266
+ url: "/#{@name}"
267
+ heading:->
268
+ $('.wrapper').addClass 'with_heading'
269
+ klass = @name.capitalize()
270
+ model = new App.Models.Group()
271
+ model.url = '/groups/1'
272
+ @partial '.heading', 'shared/heading', model: model
273
+ model.fetch()
274
+
275
+ class App.Views.Button extends Backbone.View
276
+ tagName: 'button'
@@ -0,0 +1,1836 @@
1
+ /* ===================================================
2
+ * bootstrap-transition.js v2.0.4
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
+ $(function () {
24
+
25
+ "use strict"; // jshint ;_;
26
+
27
+
28
+ /* CSS TRANSITION SUPPORT (http://www.modernizr.com/)
29
+ * ======================================================= */
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'
40
+ , 'msTransition' : 'MSTransitionEnd'
41
+ , 'transition' : 'transitionend'
42
+ }
43
+ , name
44
+
45
+ for (name in transEndEventNames){
46
+ if (el.style[name] !== undefined) {
47
+ return transEndEventNames[name]
48
+ }
49
+ }
50
+
51
+ }())
52
+
53
+ return transitionEnd && {
54
+ end: transitionEnd
55
+ }
56
+
57
+ })()
58
+
59
+ })
60
+
61
+ }(window.jQuery);
62
+ /* =========================================================
63
+ * bootstrap-modal.js v2.0.4
64
+ * http://twitter.github.com/bootstrap/javascript.html#modals
65
+ * =========================================================
66
+ * Copyright 2012 Twitter, Inc.
67
+ *
68
+ * Licensed under the Apache License, Version 2.0 (the "License");
69
+ * you may not use this file except in compliance with the License.
70
+ * You may obtain a copy of the License at
71
+ *
72
+ * http://www.apache.org/licenses/LICENSE-2.0
73
+ *
74
+ * Unless required by applicable law or agreed to in writing, software
75
+ * distributed under the License is distributed on an "AS IS" BASIS,
76
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
77
+ * See the License for the specific language governing permissions and
78
+ * limitations under the License.
79
+ * ========================================================= */
80
+
81
+
82
+ !function ($) {
83
+
84
+ "use strict"; // jshint ;_;
85
+
86
+
87
+ /* MODAL CLASS DEFINITION
88
+ * ====================== */
89
+
90
+ var Modal = function (content, options) {
91
+ this.options = options
92
+ this.$element = $(content)
93
+ .delegate('[data-dismiss="modal"]', 'click.dismiss.modal', $.proxy(this.hide, this))
94
+ }
95
+
96
+ Modal.prototype = {
97
+
98
+ constructor: Modal
99
+
100
+ , toggle: function () {
101
+ return this[!this.isShown ? 'show' : 'hide']()
102
+ }
103
+
104
+ , show: function () {
105
+ var that = this
106
+ , e = $.Event('show')
107
+
108
+ this.$element.trigger(e)
109
+
110
+ if (this.isShown || e.isDefaultPrevented()) return
111
+
112
+ $('body').addClass('modal-open')
113
+
114
+ this.isShown = true
115
+
116
+ escape.call(this)
117
+ backdrop.call(this, function () {
118
+ var transition = $.support.transition && that.$element.hasClass('fade')
119
+
120
+ if (!that.$element.parent().length) {
121
+ that.$element.appendTo(document.body) //don't move modals dom position
122
+ }
123
+
124
+ that.$element
125
+ .show()
126
+
127
+ if (transition) {
128
+ that.$element[0].offsetWidth // force reflow
129
+ }
130
+
131
+ that.$element.addClass('in')
132
+
133
+ transition ?
134
+ that.$element.one($.support.transition.end, function () { that.$element.trigger('shown') }) :
135
+ that.$element.trigger('shown')
136
+
137
+ })
138
+ }
139
+
140
+ , hide: function (e) {
141
+ e && e.preventDefault()
142
+
143
+ var that = this
144
+
145
+ e = $.Event('hide')
146
+
147
+ this.$element.trigger(e)
148
+
149
+ if (!this.isShown || e.isDefaultPrevented()) return
150
+
151
+ this.isShown = false
152
+
153
+ $('body').removeClass('modal-open')
154
+
155
+ escape.call(this)
156
+
157
+ this.$element.removeClass('in')
158
+
159
+ $.support.transition && this.$element.hasClass('fade') ?
160
+ hideWithTransition.call(this) :
161
+ hideModal.call(this)
162
+ }
163
+
164
+ }
165
+
166
+
167
+ /* MODAL PRIVATE METHODS
168
+ * ===================== */
169
+
170
+ function hideWithTransition() {
171
+ var that = this
172
+ , timeout = setTimeout(function () {
173
+ that.$element.off($.support.transition.end)
174
+ hideModal.call(that)
175
+ }, 500)
176
+
177
+ this.$element.one($.support.transition.end, function () {
178
+ clearTimeout(timeout)
179
+ hideModal.call(that)
180
+ })
181
+ }
182
+
183
+ function hideModal(that) {
184
+ this.$element
185
+ .hide()
186
+ .trigger('hidden')
187
+
188
+ backdrop.call(this)
189
+ }
190
+
191
+ function backdrop(callback) {
192
+ var that = this
193
+ , animate = this.$element.hasClass('fade') ? 'fade' : ''
194
+
195
+ if (this.isShown && this.options.backdrop) {
196
+ var doAnimate = $.support.transition && animate
197
+
198
+ this.$backdrop = $('<div class="modal-backdrop ' + animate + '" />')
199
+ .appendTo(document.body)
200
+
201
+ if (this.options.backdrop != 'static') {
202
+ this.$backdrop.click($.proxy(this.hide, this))
203
+ }
204
+
205
+ if (doAnimate) this.$backdrop[0].offsetWidth // force reflow
206
+
207
+ this.$backdrop.addClass('in')
208
+
209
+ doAnimate ?
210
+ this.$backdrop.one($.support.transition.end, callback) :
211
+ callback()
212
+
213
+ } else if (!this.isShown && this.$backdrop) {
214
+ this.$backdrop.removeClass('in')
215
+
216
+ $.support.transition && this.$element.hasClass('fade')?
217
+ this.$backdrop.one($.support.transition.end, $.proxy(removeBackdrop, this)) :
218
+ removeBackdrop.call(this)
219
+
220
+ } else if (callback) {
221
+ callback()
222
+ }
223
+ }
224
+
225
+ function removeBackdrop() {
226
+ this.$backdrop.remove()
227
+ this.$backdrop = null
228
+ }
229
+
230
+ function escape() {
231
+ var that = this
232
+ if (this.isShown && this.options.keyboard) {
233
+ $(document).on('keyup.dismiss.modal', function ( e ) {
234
+ e.which == 27 && that.hide()
235
+ })
236
+ } else if (!this.isShown) {
237
+ $(document).off('keyup.dismiss.modal')
238
+ }
239
+ }
240
+
241
+
242
+ /* MODAL PLUGIN DEFINITION
243
+ * ======================= */
244
+
245
+ $.fn.modal = function (option) {
246
+ return this.each(function () {
247
+ var $this = $(this)
248
+ , data = $this.data('modal')
249
+ , options = $.extend({}, $.fn.modal.defaults, $this.data(), typeof option == 'object' && option)
250
+ if (!data) $this.data('modal', (data = new Modal(this, options)))
251
+ if (typeof option == 'string') data[option]()
252
+ else if (options.show) data.show()
253
+ })
254
+ }
255
+
256
+ $.fn.modal.defaults = {
257
+ backdrop: true
258
+ , keyboard: true
259
+ , show: true
260
+ }
261
+
262
+ $.fn.modal.Constructor = Modal
263
+
264
+
265
+ /* MODAL DATA-API
266
+ * ============== */
267
+
268
+ $(function () {
269
+ $('body').on('click.modal.data-api', '[data-toggle="modal"]', function ( e ) {
270
+ var $this = $(this), href
271
+ , $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7
272
+ , option = $target.data('modal') ? 'toggle' : $.extend({}, $target.data(), $this.data())
273
+
274
+ e.preventDefault()
275
+ $target.modal(option)
276
+ })
277
+ })
278
+
279
+ }(window.jQuery);
280
+ /* ============================================================
281
+ * bootstrap-dropdown.js v2.0.4
282
+ * http://twitter.github.com/bootstrap/javascript.html#dropdowns
283
+ * ============================================================
284
+ * Copyright 2012 Twitter, Inc.
285
+ *
286
+ * Licensed under the Apache License, Version 2.0 (the "License");
287
+ * you may not use this file except in compliance with the License.
288
+ * You may obtain a copy of the License at
289
+ *
290
+ * http://www.apache.org/licenses/LICENSE-2.0
291
+ *
292
+ * Unless required by applicable law or agreed to in writing, software
293
+ * distributed under the License is distributed on an "AS IS" BASIS,
294
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
295
+ * See the License for the specific language governing permissions and
296
+ * limitations under the License.
297
+ * ============================================================ */
298
+
299
+
300
+ !function ($) {
301
+
302
+ "use strict"; // jshint ;_;
303
+
304
+
305
+ /* DROPDOWN CLASS DEFINITION
306
+ * ========================= */
307
+
308
+ var toggle = '[data-toggle="dropdown"]'
309
+ , Dropdown = function (element) {
310
+ var $el = $(element).on('click.dropdown.data-api', this.toggle)
311
+ $('html').on('click.dropdown.data-api', function () {
312
+ $el.parent().removeClass('open')
313
+ })
314
+ }
315
+
316
+ Dropdown.prototype = {
317
+
318
+ constructor: Dropdown
319
+
320
+ , toggle: function (e) {
321
+ var $this = $(this)
322
+ , $parent
323
+ , selector
324
+ , isActive
325
+
326
+ if ($this.is('.disabled, :disabled')) return
327
+
328
+ selector = $this.attr('data-target')
329
+
330
+ if (!selector) {
331
+ selector = $this.attr('href')
332
+ selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
333
+ }
334
+
335
+ $parent = $(selector)
336
+ $parent.length || ($parent = $this.parent())
337
+
338
+ isActive = $parent.hasClass('open')
339
+
340
+ clearMenus()
341
+
342
+ if (!isActive) $parent.toggleClass('open')
343
+
344
+ return false
345
+ }
346
+
347
+ }
348
+
349
+ function clearMenus() {
350
+ $(toggle).parent().removeClass('open')
351
+ }
352
+
353
+
354
+ /* DROPDOWN PLUGIN DEFINITION
355
+ * ========================== */
356
+
357
+ $.fn.dropdown = function (option) {
358
+ return this.each(function () {
359
+ var $this = $(this)
360
+ , data = $this.data('dropdown')
361
+ if (!data) $this.data('dropdown', (data = new Dropdown(this)))
362
+ if (typeof option == 'string') data[option].call($this)
363
+ })
364
+ }
365
+
366
+ $.fn.dropdown.Constructor = Dropdown
367
+
368
+
369
+ /* APPLY TO STANDARD DROPDOWN ELEMENTS
370
+ * =================================== */
371
+
372
+ $(function () {
373
+ $('html').on('click.dropdown.data-api', clearMenus)
374
+ $('body')
375
+ .on('click.dropdown', '.dropdown form', function (e) { e.stopPropagation() })
376
+ .on('click.dropdown.data-api', toggle, Dropdown.prototype.toggle)
377
+ })
378
+
379
+ }(window.jQuery);
380
+ /* =============================================================
381
+ * bootstrap-scrollspy.js v2.0.4
382
+ * http://twitter.github.com/bootstrap/javascript.html#scrollspy
383
+ * =============================================================
384
+ * Copyright 2012 Twitter, Inc.
385
+ *
386
+ * Licensed under the Apache License, Version 2.0 (the "License");
387
+ * you may not use this file except in compliance with the License.
388
+ * You may obtain a copy of the License at
389
+ *
390
+ * http://www.apache.org/licenses/LICENSE-2.0
391
+ *
392
+ * Unless required by applicable law or agreed to in writing, software
393
+ * distributed under the License is distributed on an "AS IS" BASIS,
394
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
395
+ * See the License for the specific language governing permissions and
396
+ * limitations under the License.
397
+ * ============================================================== */
398
+
399
+
400
+ !function ($) {
401
+
402
+ "use strict"; // jshint ;_;
403
+
404
+
405
+ /* SCROLLSPY CLASS DEFINITION
406
+ * ========================== */
407
+
408
+ function ScrollSpy( element, options) {
409
+ var process = $.proxy(this.process, this)
410
+ , $element = $(element).is('body') ? $(window) : $(element)
411
+ , href
412
+ this.options = $.extend({}, $.fn.scrollspy.defaults, options)
413
+ this.$scrollElement = $element.on('scroll.scroll.data-api', process)
414
+ this.selector = (this.options.target
415
+ || ((href = $(element).attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7
416
+ || '') + ' .nav li > a'
417
+ this.$body = $('body')
418
+ this.refresh()
419
+ this.process()
420
+ }
421
+
422
+ ScrollSpy.prototype = {
423
+
424
+ constructor: ScrollSpy
425
+
426
+ , refresh: function () {
427
+ var self = this
428
+ , $targets
429
+
430
+ this.offsets = $([])
431
+ this.targets = $([])
432
+
433
+ $targets = this.$body
434
+ .find(this.selector)
435
+ .map(function () {
436
+ var $el = $(this)
437
+ , href = $el.data('target') || $el.attr('href')
438
+ , $href = /^#\w/.test(href) && $(href)
439
+ return ( $href
440
+ && href.length
441
+ && [[ $href.position().top, href ]] ) || null
442
+ })
443
+ .sort(function (a, b) { return a[0] - b[0] })
444
+ .each(function () {
445
+ self.offsets.push(this[0])
446
+ self.targets.push(this[1])
447
+ })
448
+ }
449
+
450
+ , process: function () {
451
+ var scrollTop = this.$scrollElement.scrollTop() + this.options.offset
452
+ , scrollHeight = this.$scrollElement[0].scrollHeight || this.$body[0].scrollHeight
453
+ , maxScroll = scrollHeight - this.$scrollElement.height()
454
+ , offsets = this.offsets
455
+ , targets = this.targets
456
+ , activeTarget = this.activeTarget
457
+ , i
458
+
459
+ if (scrollTop >= maxScroll) {
460
+ return activeTarget != (i = targets.last()[0])
461
+ && this.activate ( i )
462
+ }
463
+
464
+ for (i = offsets.length; i--;) {
465
+ activeTarget != targets[i]
466
+ && scrollTop >= offsets[i]
467
+ && (!offsets[i + 1] || scrollTop <= offsets[i + 1])
468
+ && this.activate( targets[i] )
469
+ }
470
+ }
471
+
472
+ , activate: function (target) {
473
+ var active
474
+ , selector
475
+
476
+ this.activeTarget = target
477
+
478
+ $(this.selector)
479
+ .parent('.active')
480
+ .removeClass('active')
481
+
482
+ selector = this.selector
483
+ + '[data-target="' + target + '"],'
484
+ + this.selector + '[href="' + target + '"]'
485
+
486
+ active = $(selector)
487
+ .parent('li')
488
+ .addClass('active')
489
+
490
+ if (active.parent('.dropdown-menu')) {
491
+ active = active.closest('li.dropdown').addClass('active')
492
+ }
493
+
494
+ active.trigger('activate')
495
+ }
496
+
497
+ }
498
+
499
+
500
+ /* SCROLLSPY PLUGIN DEFINITION
501
+ * =========================== */
502
+
503
+ $.fn.scrollspy = function ( option ) {
504
+ return this.each(function () {
505
+ var $this = $(this)
506
+ , data = $this.data('scrollspy')
507
+ , options = typeof option == 'object' && option
508
+ if (!data) $this.data('scrollspy', (data = new ScrollSpy(this, options)))
509
+ if (typeof option == 'string') data[option]()
510
+ })
511
+ }
512
+
513
+ $.fn.scrollspy.Constructor = ScrollSpy
514
+
515
+ $.fn.scrollspy.defaults = {
516
+ offset: 10
517
+ }
518
+
519
+
520
+ /* SCROLLSPY DATA-API
521
+ * ================== */
522
+
523
+ $(function () {
524
+ $('[data-spy="scroll"]').each(function () {
525
+ var $spy = $(this)
526
+ $spy.scrollspy($spy.data())
527
+ })
528
+ })
529
+
530
+ }(window.jQuery);
531
+ /* ========================================================
532
+ * bootstrap-tab.js v2.0.4
533
+ * http://twitter.github.com/bootstrap/javascript.html#tabs
534
+ * ========================================================
535
+ * Copyright 2012 Twitter, Inc.
536
+ *
537
+ * Licensed under the Apache License, Version 2.0 (the "License");
538
+ * you may not use this file except in compliance with the License.
539
+ * You may obtain a copy of the License at
540
+ *
541
+ * http://www.apache.org/licenses/LICENSE-2.0
542
+ *
543
+ * Unless required by applicable law or agreed to in writing, software
544
+ * distributed under the License is distributed on an "AS IS" BASIS,
545
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
546
+ * See the License for the specific language governing permissions and
547
+ * limitations under the License.
548
+ * ======================================================== */
549
+
550
+
551
+ !function ($) {
552
+
553
+ "use strict"; // jshint ;_;
554
+
555
+
556
+ /* TAB CLASS DEFINITION
557
+ * ==================== */
558
+
559
+ var Tab = function ( element ) {
560
+ this.element = $(element)
561
+ }
562
+
563
+ Tab.prototype = {
564
+
565
+ constructor: Tab
566
+
567
+ , show: function () {
568
+ var $this = this.element
569
+ , $ul = $this.closest('ul:not(.dropdown-menu)')
570
+ , selector = $this.attr('data-target')
571
+ , previous
572
+ , $target
573
+ , e
574
+
575
+ if (!selector) {
576
+ selector = $this.attr('href')
577
+ selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
578
+ }
579
+
580
+ if ( $this.parent('li').hasClass('active') ) return
581
+
582
+ previous = $ul.find('.active a').last()[0]
583
+
584
+ e = $.Event('show', {
585
+ relatedTarget: previous
586
+ })
587
+
588
+ $this.trigger(e)
589
+
590
+ if (e.isDefaultPrevented()) return
591
+
592
+ $target = $(selector)
593
+
594
+ this.activate($this.parent('li'), $ul)
595
+ this.activate($target, $target.parent(), function () {
596
+ $this.trigger({
597
+ type: 'shown'
598
+ , relatedTarget: previous
599
+ })
600
+ })
601
+ }
602
+
603
+ , activate: function ( element, container, callback) {
604
+ var $active = container.find('> .active')
605
+ , transition = callback
606
+ && $.support.transition
607
+ && $active.hasClass('fade')
608
+
609
+ function next() {
610
+ $active
611
+ .removeClass('active')
612
+ .find('> .dropdown-menu > .active')
613
+ .removeClass('active')
614
+
615
+ element.addClass('active')
616
+
617
+ if (transition) {
618
+ element[0].offsetWidth // reflow for transition
619
+ element.addClass('in')
620
+ } else {
621
+ element.removeClass('fade')
622
+ }
623
+
624
+ if ( element.parent('.dropdown-menu') ) {
625
+ element.closest('li.dropdown').addClass('active')
626
+ }
627
+
628
+ callback && callback()
629
+ }
630
+
631
+ transition ?
632
+ $active.one($.support.transition.end, next) :
633
+ next()
634
+
635
+ $active.removeClass('in')
636
+ }
637
+ }
638
+
639
+
640
+ /* TAB PLUGIN DEFINITION
641
+ * ===================== */
642
+
643
+ $.fn.tab = function ( option ) {
644
+ return this.each(function () {
645
+ var $this = $(this)
646
+ , data = $this.data('tab')
647
+ if (!data) $this.data('tab', (data = new Tab(this)))
648
+ if (typeof option == 'string') data[option]()
649
+ })
650
+ }
651
+
652
+ $.fn.tab.Constructor = Tab
653
+
654
+
655
+ /* TAB DATA-API
656
+ * ============ */
657
+
658
+ $(function () {
659
+ $('body').on('click.tab.data-api', '[data-toggle="tab"], [data-toggle="pill"]', function (e) {
660
+ e.preventDefault()
661
+ $(this).tab('show')
662
+ })
663
+ })
664
+
665
+ }(window.jQuery);
666
+ /* ===========================================================
667
+ * bootstrap-tooltip.js v2.0.4
668
+ * http://twitter.github.com/bootstrap/javascript.html#tooltips
669
+ * Inspired by the original jQuery.tipsy by Jason Frame
670
+ * ===========================================================
671
+ * Copyright 2012 Twitter, Inc.
672
+ *
673
+ * Licensed under the Apache License, Version 2.0 (the "License");
674
+ * you may not use this file except in compliance with the License.
675
+ * You may obtain a copy of the License at
676
+ *
677
+ * http://www.apache.org/licenses/LICENSE-2.0
678
+ *
679
+ * Unless required by applicable law or agreed to in writing, software
680
+ * distributed under the License is distributed on an "AS IS" BASIS,
681
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
682
+ * See the License for the specific language governing permissions and
683
+ * limitations under the License.
684
+ * ========================================================== */
685
+
686
+
687
+ !function ($) {
688
+
689
+ "use strict"; // jshint ;_;
690
+
691
+
692
+ /* TOOLTIP PUBLIC CLASS DEFINITION
693
+ * =============================== */
694
+
695
+ var Tooltip = function (element, options) {
696
+ this.init('tooltip', element, options)
697
+ }
698
+
699
+ Tooltip.prototype = {
700
+
701
+ constructor: Tooltip
702
+
703
+ , init: function (type, element, options) {
704
+ var eventIn
705
+ , eventOut
706
+
707
+ this.type = type
708
+ this.$element = $(element)
709
+ this.options = this.getOptions(options)
710
+ this.enabled = true
711
+
712
+ if (this.options.trigger != 'manual') {
713
+ eventIn = this.options.trigger == 'hover' ? 'mouseenter' : 'focus'
714
+ eventOut = this.options.trigger == 'hover' ? 'mouseleave' : 'blur'
715
+ this.$element.on(eventIn, this.options.selector, $.proxy(this.enter, this))
716
+ this.$element.on(eventOut, this.options.selector, $.proxy(this.leave, this))
717
+ }
718
+
719
+ this.options.selector ?
720
+ (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) :
721
+ this.fixTitle()
722
+ }
723
+
724
+ , getOptions: function (options) {
725
+ options = $.extend({}, $.fn[this.type].defaults, options, this.$element.data())
726
+
727
+ if (options.delay && typeof options.delay == 'number') {
728
+ options.delay = {
729
+ show: options.delay
730
+ , hide: options.delay
731
+ }
732
+ }
733
+
734
+ return options
735
+ }
736
+
737
+ , enter: function (e) {
738
+ var self = $(e.currentTarget)[this.type](this._options).data(this.type)
739
+
740
+ if (!self.options.delay || !self.options.delay.show) return self.show()
741
+
742
+ clearTimeout(this.timeout)
743
+ self.hoverState = 'in'
744
+ this.timeout = setTimeout(function() {
745
+ if (self.hoverState == 'in') self.show()
746
+ }, self.options.delay.show)
747
+ }
748
+
749
+ , leave: function (e) {
750
+ var self = $(e.currentTarget)[this.type](this._options).data(this.type)
751
+
752
+ if (this.timeout) clearTimeout(this.timeout)
753
+ if (!self.options.delay || !self.options.delay.hide) return self.hide()
754
+
755
+ self.hoverState = 'out'
756
+ this.timeout = setTimeout(function() {
757
+ if (self.hoverState == 'out') self.hide()
758
+ }, self.options.delay.hide)
759
+ }
760
+
761
+ , show: function () {
762
+ var $tip
763
+ , inside
764
+ , pos
765
+ , actualWidth
766
+ , actualHeight
767
+ , placement
768
+ , tp
769
+
770
+ if (this.hasContent() && this.enabled) {
771
+ $tip = this.tip()
772
+ this.setContent()
773
+
774
+ if (this.options.animation) {
775
+ $tip.addClass('fade')
776
+ }
777
+
778
+ placement = typeof this.options.placement == 'function' ?
779
+ this.options.placement.call(this, $tip[0], this.$element[0]) :
780
+ this.options.placement
781
+
782
+ inside = /in/.test(placement)
783
+
784
+ $tip
785
+ .remove()
786
+ .css({ top: 0, left: 0, display: 'block' })
787
+ .appendTo(inside ? this.$element : document.body)
788
+
789
+ pos = this.getPosition(inside)
790
+
791
+ actualWidth = $tip[0].offsetWidth
792
+ actualHeight = $tip[0].offsetHeight
793
+
794
+ switch (inside ? placement.split(' ')[1] : placement) {
795
+ case 'bottom':
796
+ tp = {top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2}
797
+ break
798
+ case 'top':
799
+ tp = {top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2}
800
+ break
801
+ case 'left':
802
+ tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth}
803
+ break
804
+ case 'right':
805
+ tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width}
806
+ break
807
+ }
808
+
809
+ $tip
810
+ .css(tp)
811
+ .addClass(placement)
812
+ .addClass('in')
813
+ }
814
+ }
815
+
816
+ , isHTML: function(text) {
817
+ // html string detection logic adapted from jQuery
818
+ return typeof text != 'string'
819
+ || ( text.charAt(0) === "<"
820
+ && text.charAt( text.length - 1 ) === ">"
821
+ && text.length >= 3
822
+ ) || /^(?:[^<]*<[\w\W]+>[^>]*$)/.exec(text)
823
+ }
824
+
825
+ , setContent: function () {
826
+ var $tip = this.tip()
827
+ , title = this.getTitle()
828
+
829
+ $tip.find('.tooltip-inner')[this.isHTML(title) ? 'html' : 'text'](title)
830
+ $tip.removeClass('fade in top bottom left right')
831
+ }
832
+
833
+ , hide: function () {
834
+ var that = this
835
+ , $tip = this.tip()
836
+
837
+ $tip.removeClass('in')
838
+
839
+ function removeWithAnimation() {
840
+ var timeout = setTimeout(function () {
841
+ $tip.off($.support.transition.end).remove()
842
+ }, 500)
843
+
844
+ $tip.one($.support.transition.end, function () {
845
+ clearTimeout(timeout)
846
+ $tip.remove()
847
+ })
848
+ }
849
+
850
+ $.support.transition && this.$tip.hasClass('fade') ?
851
+ removeWithAnimation() :
852
+ $tip.remove()
853
+ }
854
+
855
+ , fixTitle: function () {
856
+ var $e = this.$element
857
+ if ($e.attr('title') || typeof($e.attr('data-original-title')) != 'string') {
858
+ $e.attr('data-original-title', $e.attr('title') || '').removeAttr('title')
859
+ }
860
+ }
861
+
862
+ , hasContent: function () {
863
+ return this.getTitle()
864
+ }
865
+
866
+ , getPosition: function (inside) {
867
+ return $.extend({}, (inside ? {top: 0, left: 0} : this.$element.offset()), {
868
+ width: this.$element[0].offsetWidth
869
+ , height: this.$element[0].offsetHeight
870
+ })
871
+ }
872
+
873
+ , getTitle: function () {
874
+ var title
875
+ , $e = this.$element
876
+ , o = this.options
877
+
878
+ title = $e.attr('data-original-title')
879
+ || (typeof o.title == 'function' ? o.title.call($e[0]) : o.title)
880
+
881
+ return title
882
+ }
883
+
884
+ , tip: function () {
885
+ return this.$tip = this.$tip || $(this.options.template)
886
+ }
887
+
888
+ , validate: function () {
889
+ if (!this.$element[0].parentNode) {
890
+ this.hide()
891
+ this.$element = null
892
+ this.options = null
893
+ }
894
+ }
895
+
896
+ , enable: function () {
897
+ this.enabled = true
898
+ }
899
+
900
+ , disable: function () {
901
+ this.enabled = false
902
+ }
903
+
904
+ , toggleEnabled: function () {
905
+ this.enabled = !this.enabled
906
+ }
907
+
908
+ , toggle: function () {
909
+ this[this.tip().hasClass('in') ? 'hide' : 'show']()
910
+ }
911
+
912
+ }
913
+
914
+
915
+ /* TOOLTIP PLUGIN DEFINITION
916
+ * ========================= */
917
+
918
+ $.fn.tooltip = function ( option ) {
919
+ return this.each(function () {
920
+ var $this = $(this)
921
+ , data = $this.data('tooltip')
922
+ , options = typeof option == 'object' && option
923
+ if (!data) $this.data('tooltip', (data = new Tooltip(this, options)))
924
+ if (typeof option == 'string') data[option]()
925
+ })
926
+ }
927
+
928
+ $.fn.tooltip.Constructor = Tooltip
929
+
930
+ $.fn.tooltip.defaults = {
931
+ animation: true
932
+ , placement: 'top'
933
+ , selector: false
934
+ , template: '<div class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>'
935
+ , trigger: 'hover'
936
+ , title: ''
937
+ , delay: 0
938
+ }
939
+
940
+ }(window.jQuery);
941
+
942
+ /* ===========================================================
943
+ * bootstrap-popover.js v2.0.4
944
+ * http://twitter.github.com/bootstrap/javascript.html#popovers
945
+ * ===========================================================
946
+ * Copyright 2012 Twitter, Inc.
947
+ *
948
+ * Licensed under the Apache License, Version 2.0 (the "License");
949
+ * you may not use this file except in compliance with the License.
950
+ * You may obtain a copy of the License at
951
+ *
952
+ * http://www.apache.org/licenses/LICENSE-2.0
953
+ *
954
+ * Unless required by applicable law or agreed to in writing, software
955
+ * distributed under the License is distributed on an "AS IS" BASIS,
956
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
957
+ * See the License for the specific language governing permissions and
958
+ * limitations under the License.
959
+ * =========================================================== */
960
+
961
+
962
+ !function ($) {
963
+
964
+ "use strict"; // jshint ;_;
965
+
966
+
967
+ /* POPOVER PUBLIC CLASS DEFINITION
968
+ * =============================== */
969
+
970
+ var Popover = function ( element, options ) {
971
+ this.init('popover', element, options)
972
+ }
973
+
974
+
975
+ /* NOTE: POPOVER EXTENDS BOOTSTRAP-TOOLTIP.js
976
+ ========================================== */
977
+
978
+ Popover.prototype = $.extend({}, $.fn.tooltip.Constructor.prototype, {
979
+
980
+ constructor: Popover
981
+
982
+ , setContent: function () {
983
+ var $tip = this.tip()
984
+ , title = this.getTitle()
985
+ , content = this.getContent()
986
+
987
+ $tip.find('.popover-title')[this.isHTML(title) ? 'html' : 'text'](title)
988
+ $tip.find('.popover-content > *')[this.isHTML(content) ? 'html' : 'text'](content)
989
+
990
+ $tip.removeClass('fade top bottom left right in')
991
+ }
992
+
993
+ , hasContent: function () {
994
+ return this.getTitle() || this.getContent()
995
+ }
996
+
997
+ , getContent: function () {
998
+ var content
999
+ , $e = this.$element
1000
+ , o = this.options
1001
+
1002
+ content = $e.attr('data-content')
1003
+ || (typeof o.content == 'function' ? o.content.call($e[0]) : o.content)
1004
+
1005
+ return content
1006
+ }
1007
+
1008
+ , tip: function () {
1009
+ if (!this.$tip) {
1010
+ this.$tip = $(this.options.template)
1011
+ }
1012
+ return this.$tip
1013
+ }
1014
+
1015
+ })
1016
+
1017
+
1018
+ /* POPOVER PLUGIN DEFINITION
1019
+ * ======================= */
1020
+
1021
+ $.fn.popover = function (option) {
1022
+ return this.each(function () {
1023
+ var $this = $(this)
1024
+ , data = $this.data('popover')
1025
+ , options = typeof option == 'object' && option
1026
+ if (!data) $this.data('popover', (data = new Popover(this, options)))
1027
+ if (typeof option == 'string') data[option]()
1028
+ })
1029
+ }
1030
+
1031
+ $.fn.popover.Constructor = Popover
1032
+
1033
+ $.fn.popover.defaults = $.extend({} , $.fn.tooltip.defaults, {
1034
+ placement: 'right'
1035
+ , content: ''
1036
+ , template: '<div class="popover"><div class="arrow"></div><div class="popover-inner"><h3 class="popover-title"></h3><div class="popover-content"><p></p></div></div></div>'
1037
+ })
1038
+
1039
+ }(window.jQuery);
1040
+ /* ==========================================================
1041
+ * bootstrap-alert.js v2.0.4
1042
+ * http://twitter.github.com/bootstrap/javascript.html#alerts
1043
+ * ==========================================================
1044
+ * Copyright 2012 Twitter, Inc.
1045
+ *
1046
+ * Licensed under the Apache License, Version 2.0 (the "License");
1047
+ * you may not use this file except in compliance with the License.
1048
+ * You may obtain a copy of the License at
1049
+ *
1050
+ * http://www.apache.org/licenses/LICENSE-2.0
1051
+ *
1052
+ * Unless required by applicable law or agreed to in writing, software
1053
+ * distributed under the License is distributed on an "AS IS" BASIS,
1054
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1055
+ * See the License for the specific language governing permissions and
1056
+ * limitations under the License.
1057
+ * ========================================================== */
1058
+
1059
+
1060
+ !function ($) {
1061
+
1062
+ "use strict"; // jshint ;_;
1063
+
1064
+
1065
+ /* ALERT CLASS DEFINITION
1066
+ * ====================== */
1067
+
1068
+ var dismiss = '[data-dismiss="alert"]'
1069
+ , Alert = function (el) {
1070
+ $(el).on('click', dismiss, this.close)
1071
+ }
1072
+
1073
+ Alert.prototype.close = function (e) {
1074
+ var $this = $(this)
1075
+ , selector = $this.attr('data-target')
1076
+ , $parent
1077
+
1078
+ if (!selector) {
1079
+ selector = $this.attr('href')
1080
+ selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
1081
+ }
1082
+
1083
+ $parent = $(selector)
1084
+
1085
+ e && e.preventDefault()
1086
+
1087
+ $parent.length || ($parent = $this.hasClass('alert') ? $this : $this.parent())
1088
+
1089
+ $parent.trigger(e = $.Event('close'))
1090
+
1091
+ if (e.isDefaultPrevented()) return
1092
+
1093
+ $parent.removeClass('in')
1094
+
1095
+ function removeElement() {
1096
+ $parent
1097
+ .trigger('closed')
1098
+ .remove()
1099
+ }
1100
+
1101
+ $.support.transition && $parent.hasClass('fade') ?
1102
+ $parent.on($.support.transition.end, removeElement) :
1103
+ removeElement()
1104
+ }
1105
+
1106
+
1107
+ /* ALERT PLUGIN DEFINITION
1108
+ * ======================= */
1109
+
1110
+ $.fn.alert = function (option) {
1111
+ return this.each(function () {
1112
+ var $this = $(this)
1113
+ , data = $this.data('alert')
1114
+ if (!data) $this.data('alert', (data = new Alert(this)))
1115
+ if (typeof option == 'string') data[option].call($this)
1116
+ })
1117
+ }
1118
+
1119
+ $.fn.alert.Constructor = Alert
1120
+
1121
+
1122
+ /* ALERT DATA-API
1123
+ * ============== */
1124
+
1125
+ $(function () {
1126
+ $('body').on('click.alert.data-api', dismiss, Alert.prototype.close)
1127
+ })
1128
+
1129
+ }(window.jQuery);
1130
+ /* ============================================================
1131
+ * bootstrap-button.js v2.0.4
1132
+ * http://twitter.github.com/bootstrap/javascript.html#buttons
1133
+ * ============================================================
1134
+ * Copyright 2012 Twitter, Inc.
1135
+ *
1136
+ * Licensed under the Apache License, Version 2.0 (the "License");
1137
+ * you may not use this file except in compliance with the License.
1138
+ * You may obtain a copy of the License at
1139
+ *
1140
+ * http://www.apache.org/licenses/LICENSE-2.0
1141
+ *
1142
+ * Unless required by applicable law or agreed to in writing, software
1143
+ * distributed under the License is distributed on an "AS IS" BASIS,
1144
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1145
+ * See the License for the specific language governing permissions and
1146
+ * limitations under the License.
1147
+ * ============================================================ */
1148
+
1149
+
1150
+ !function ($) {
1151
+
1152
+ "use strict"; // jshint ;_;
1153
+
1154
+
1155
+ /* BUTTON PUBLIC CLASS DEFINITION
1156
+ * ============================== */
1157
+
1158
+ var Button = function (element, options) {
1159
+ this.$element = $(element)
1160
+ this.options = $.extend({}, $.fn.button.defaults, options)
1161
+ }
1162
+
1163
+ Button.prototype.setState = function (state) {
1164
+ var d = 'disabled'
1165
+ , $el = this.$element
1166
+ , data = $el.data()
1167
+ , val = $el.is('input') ? 'val' : 'html'
1168
+
1169
+ state = state + 'Text'
1170
+ data.resetText || $el.data('resetText', $el[val]())
1171
+
1172
+ $el[val](data[state] || this.options[state])
1173
+
1174
+ // push to event loop to allow forms to submit
1175
+ setTimeout(function () {
1176
+ state == 'loadingText' ?
1177
+ $el.addClass(d).attr(d, d) :
1178
+ $el.removeClass(d).removeAttr(d)
1179
+ }, 0)
1180
+ }
1181
+
1182
+ Button.prototype.toggle = function () {
1183
+ var $parent = this.$element.parent('[data-toggle="buttons-radio"]')
1184
+
1185
+ $parent && $parent
1186
+ .find('.active')
1187
+ .removeClass('active')
1188
+
1189
+ this.$element.toggleClass('active')
1190
+ }
1191
+
1192
+
1193
+ /* BUTTON PLUGIN DEFINITION
1194
+ * ======================== */
1195
+
1196
+ $.fn.button = function (option) {
1197
+ return this.each(function () {
1198
+ var $this = $(this)
1199
+ , data = $this.data('button')
1200
+ , options = typeof option == 'object' && option
1201
+ if (!data) $this.data('button', (data = new Button(this, options)))
1202
+ if (option == 'toggle') data.toggle()
1203
+ else if (option) data.setState(option)
1204
+ })
1205
+ }
1206
+
1207
+ $.fn.button.defaults = {
1208
+ loadingText: 'loading...'
1209
+ }
1210
+
1211
+ $.fn.button.Constructor = Button
1212
+
1213
+
1214
+ /* BUTTON DATA-API
1215
+ * =============== */
1216
+
1217
+ $(function () {
1218
+ $('body').on('click.button.data-api', '[data-toggle^=button]', function ( e ) {
1219
+ var $btn = $(e.target)
1220
+ if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn')
1221
+ $btn.button('toggle')
1222
+ })
1223
+ })
1224
+
1225
+ }(window.jQuery);
1226
+ /* =============================================================
1227
+ * bootstrap-collapse.js v2.0.4
1228
+ * http://twitter.github.com/bootstrap/javascript.html#collapse
1229
+ * =============================================================
1230
+ * Copyright 2012 Twitter, Inc.
1231
+ *
1232
+ * Licensed under the Apache License, Version 2.0 (the "License");
1233
+ * you may not use this file except in compliance with the License.
1234
+ * You may obtain a copy of the License at
1235
+ *
1236
+ * http://www.apache.org/licenses/LICENSE-2.0
1237
+ *
1238
+ * Unless required by applicable law or agreed to in writing, software
1239
+ * distributed under the License is distributed on an "AS IS" BASIS,
1240
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1241
+ * See the License for the specific language governing permissions and
1242
+ * limitations under the License.
1243
+ * ============================================================ */
1244
+
1245
+
1246
+ !function ($) {
1247
+
1248
+ "use strict"; // jshint ;_;
1249
+
1250
+
1251
+ /* COLLAPSE PUBLIC CLASS DEFINITION
1252
+ * ================================ */
1253
+
1254
+ var Collapse = function (element, options) {
1255
+ this.$element = $(element)
1256
+ this.options = $.extend({}, $.fn.collapse.defaults, options)
1257
+
1258
+ if (this.options.parent) {
1259
+ this.$parent = $(this.options.parent)
1260
+ }
1261
+
1262
+ this.options.toggle && this.toggle()
1263
+ }
1264
+
1265
+ Collapse.prototype = {
1266
+
1267
+ constructor: Collapse
1268
+
1269
+ , dimension: function () {
1270
+ var hasWidth = this.$element.hasClass('width')
1271
+ return hasWidth ? 'width' : 'height'
1272
+ }
1273
+
1274
+ , show: function () {
1275
+ var dimension
1276
+ , scroll
1277
+ , actives
1278
+ , hasData
1279
+
1280
+ if (this.transitioning) return
1281
+
1282
+ dimension = this.dimension()
1283
+ scroll = $.camelCase(['scroll', dimension].join('-'))
1284
+ actives = this.$parent && this.$parent.find('> .accordion-group > .in')
1285
+
1286
+ if (actives && actives.length) {
1287
+ hasData = actives.data('collapse')
1288
+ if (hasData && hasData.transitioning) return
1289
+ actives.collapse('hide')
1290
+ hasData || actives.data('collapse', null)
1291
+ }
1292
+
1293
+ this.$element[dimension](0)
1294
+ this.transition('addClass', $.Event('show'), 'shown')
1295
+ this.$element[dimension](this.$element[0][scroll])
1296
+ }
1297
+
1298
+ , hide: function () {
1299
+ var dimension
1300
+ if (this.transitioning) return
1301
+ dimension = this.dimension()
1302
+ this.reset(this.$element[dimension]())
1303
+ this.transition('removeClass', $.Event('hide'), 'hidden')
1304
+ this.$element[dimension](0)
1305
+ }
1306
+
1307
+ , reset: function (size) {
1308
+ var dimension = this.dimension()
1309
+
1310
+ this.$element
1311
+ .removeClass('collapse')
1312
+ [dimension](size || 'auto')
1313
+ [0].offsetWidth
1314
+
1315
+ this.$element[size !== null ? 'addClass' : 'removeClass']('collapse')
1316
+
1317
+ return this
1318
+ }
1319
+
1320
+ , transition: function (method, startEvent, completeEvent) {
1321
+ var that = this
1322
+ , complete = function () {
1323
+ if (startEvent.type == 'show') that.reset()
1324
+ that.transitioning = 0
1325
+ that.$element.trigger(completeEvent)
1326
+ }
1327
+
1328
+ this.$element.trigger(startEvent)
1329
+
1330
+ if (startEvent.isDefaultPrevented()) return
1331
+
1332
+ this.transitioning = 1
1333
+
1334
+ this.$element[method]('in')
1335
+
1336
+ $.support.transition && this.$element.hasClass('collapse') ?
1337
+ this.$element.one($.support.transition.end, complete) :
1338
+ complete()
1339
+ }
1340
+
1341
+ , toggle: function () {
1342
+ this[this.$element.hasClass('in') ? 'hide' : 'show']()
1343
+ }
1344
+
1345
+ }
1346
+
1347
+
1348
+ /* COLLAPSIBLE PLUGIN DEFINITION
1349
+ * ============================== */
1350
+
1351
+ $.fn.collapse = function (option) {
1352
+ return this.each(function () {
1353
+ var $this = $(this)
1354
+ , data = $this.data('collapse')
1355
+ , options = typeof option == 'object' && option
1356
+ if (!data) $this.data('collapse', (data = new Collapse(this, options)))
1357
+ if (typeof option == 'string') data[option]()
1358
+ })
1359
+ }
1360
+
1361
+ $.fn.collapse.defaults = {
1362
+ toggle: true
1363
+ }
1364
+
1365
+ $.fn.collapse.Constructor = Collapse
1366
+
1367
+
1368
+ /* COLLAPSIBLE DATA-API
1369
+ * ==================== */
1370
+
1371
+ $(function () {
1372
+ $('body').on('click.collapse.data-api', '[data-toggle=collapse]', function ( e ) {
1373
+ var $this = $(this), href
1374
+ , target = $this.attr('data-target')
1375
+ || e.preventDefault()
1376
+ || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7
1377
+ , option = $(target).data('collapse') ? 'toggle' : $this.data()
1378
+ $(target).collapse(option)
1379
+ })
1380
+ })
1381
+
1382
+ }(window.jQuery);
1383
+ /* ==========================================================
1384
+ * bootstrap-carousel.js v2.0.4
1385
+ * http://twitter.github.com/bootstrap/javascript.html#carousel
1386
+ * ==========================================================
1387
+ * Copyright 2012 Twitter, Inc.
1388
+ *
1389
+ * Licensed under the Apache License, Version 2.0 (the "License");
1390
+ * you may not use this file except in compliance with the License.
1391
+ * You may obtain a copy of the License at
1392
+ *
1393
+ * http://www.apache.org/licenses/LICENSE-2.0
1394
+ *
1395
+ * Unless required by applicable law or agreed to in writing, software
1396
+ * distributed under the License is distributed on an "AS IS" BASIS,
1397
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1398
+ * See the License for the specific language governing permissions and
1399
+ * limitations under the License.
1400
+ * ========================================================== */
1401
+
1402
+
1403
+ !function ($) {
1404
+
1405
+ "use strict"; // jshint ;_;
1406
+
1407
+
1408
+ /* CAROUSEL CLASS DEFINITION
1409
+ * ========================= */
1410
+
1411
+ var Carousel = function (element, options) {
1412
+ this.$element = $(element)
1413
+ this.options = options
1414
+ this.options.slide && this.slide(this.options.slide)
1415
+ this.options.pause == 'hover' && this.$element
1416
+ .on('mouseenter', $.proxy(this.pause, this))
1417
+ .on('mouseleave', $.proxy(this.cycle, this))
1418
+ }
1419
+
1420
+ Carousel.prototype = {
1421
+
1422
+ cycle: function (e) {
1423
+ if (!e) this.paused = false
1424
+ this.options.interval
1425
+ && !this.paused
1426
+ && (this.interval = setInterval($.proxy(this.next, this), this.options.interval))
1427
+ return this
1428
+ }
1429
+
1430
+ , to: function (pos) {
1431
+ var $active = this.$element.find('.active')
1432
+ , children = $active.parent().children()
1433
+ , activePos = children.index($active)
1434
+ , that = this
1435
+
1436
+ if (pos > (children.length - 1) || pos < 0) return
1437
+
1438
+ if (this.sliding) {
1439
+ return this.$element.one('slid', function () {
1440
+ that.to(pos)
1441
+ })
1442
+ }
1443
+
1444
+ if (activePos == pos) {
1445
+ return this.pause().cycle()
1446
+ }
1447
+
1448
+ return this.slide(pos > activePos ? 'next' : 'prev', $(children[pos]))
1449
+ }
1450
+
1451
+ , pause: function (e) {
1452
+ if (!e) this.paused = true
1453
+ clearInterval(this.interval)
1454
+ this.interval = null
1455
+ return this
1456
+ }
1457
+
1458
+ , next: function () {
1459
+ if (this.sliding) return
1460
+ return this.slide('next')
1461
+ }
1462
+
1463
+ , prev: function () {
1464
+ if (this.sliding) return
1465
+ return this.slide('prev')
1466
+ }
1467
+
1468
+ , slide: function (type, next) {
1469
+ var $active = this.$element.find('.active')
1470
+ , $next = next || $active[type]()
1471
+ , isCycling = this.interval
1472
+ , direction = type == 'next' ? 'left' : 'right'
1473
+ , fallback = type == 'next' ? 'first' : 'last'
1474
+ , that = this
1475
+ , e = $.Event('slide')
1476
+
1477
+ this.sliding = true
1478
+
1479
+ isCycling && this.pause()
1480
+
1481
+ $next = $next.length ? $next : this.$element.find('.item')[fallback]()
1482
+
1483
+ if ($next.hasClass('active')) return
1484
+
1485
+ if ($.support.transition && this.$element.hasClass('slide')) {
1486
+ this.$element.trigger(e)
1487
+ if (e.isDefaultPrevented()) return
1488
+ $next.addClass(type)
1489
+ $next[0].offsetWidth // force reflow
1490
+ $active.addClass(direction)
1491
+ $next.addClass(direction)
1492
+ this.$element.one($.support.transition.end, function () {
1493
+ $next.removeClass([type, direction].join(' ')).addClass('active')
1494
+ $active.removeClass(['active', direction].join(' '))
1495
+ that.sliding = false
1496
+ setTimeout(function () { that.$element.trigger('slid') }, 0)
1497
+ })
1498
+ } else {
1499
+ this.$element.trigger(e)
1500
+ if (e.isDefaultPrevented()) return
1501
+ $active.removeClass('active')
1502
+ $next.addClass('active')
1503
+ this.sliding = false
1504
+ this.$element.trigger('slid')
1505
+ }
1506
+
1507
+ isCycling && this.cycle()
1508
+
1509
+ return this
1510
+ }
1511
+
1512
+ }
1513
+
1514
+
1515
+ /* CAROUSEL PLUGIN DEFINITION
1516
+ * ========================== */
1517
+
1518
+ $.fn.carousel = function (option) {
1519
+ return this.each(function () {
1520
+ var $this = $(this)
1521
+ , data = $this.data('carousel')
1522
+ , options = $.extend({}, $.fn.carousel.defaults, typeof option == 'object' && option)
1523
+ if (!data) $this.data('carousel', (data = new Carousel(this, options)))
1524
+ if (typeof option == 'number') data.to(option)
1525
+ else if (typeof option == 'string' || (option = options.slide)) data[option]()
1526
+ else if (options.interval) data.cycle()
1527
+ })
1528
+ }
1529
+
1530
+ $.fn.carousel.defaults = {
1531
+ interval: 5000
1532
+ , pause: 'hover'
1533
+ }
1534
+
1535
+ $.fn.carousel.Constructor = Carousel
1536
+
1537
+
1538
+ /* CAROUSEL DATA-API
1539
+ * ================= */
1540
+
1541
+ $(function () {
1542
+ $('body').on('click.carousel.data-api', '[data-slide]', function ( e ) {
1543
+ var $this = $(this), href
1544
+ , $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7
1545
+ , options = !$target.data('modal') && $.extend({}, $target.data(), $this.data())
1546
+ $target.carousel(options)
1547
+ e.preventDefault()
1548
+ })
1549
+ })
1550
+
1551
+ }(window.jQuery);
1552
+ /* =============================================================
1553
+ * bootstrap-typeahead.js v2.0.4
1554
+ * http://twitter.github.com/bootstrap/javascript.html#typeahead
1555
+ * =============================================================
1556
+ * Copyright 2012 Twitter, Inc.
1557
+ *
1558
+ * Licensed under the Apache License, Version 2.0 (the "License");
1559
+ * you may not use this file except in compliance with the License.
1560
+ * You may obtain a copy of the License at
1561
+ *
1562
+ * http://www.apache.org/licenses/LICENSE-2.0
1563
+ *
1564
+ * Unless required by applicable law or agreed to in writing, software
1565
+ * distributed under the License is distributed on an "AS IS" BASIS,
1566
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1567
+ * See the License for the specific language governing permissions and
1568
+ * limitations under the License.
1569
+ * ============================================================ */
1570
+
1571
+
1572
+ !function($){
1573
+
1574
+ "use strict"; // jshint ;_;
1575
+
1576
+
1577
+ /* TYPEAHEAD PUBLIC CLASS DEFINITION
1578
+ * ================================= */
1579
+
1580
+ var Typeahead = function (element, options) {
1581
+ this.$element = $(element)
1582
+ this.options = $.extend({}, $.fn.typeahead.defaults, options)
1583
+ this.matcher = this.options.matcher || this.matcher
1584
+ this.sorter = this.options.sorter || this.sorter
1585
+ this.highlighter = this.options.highlighter || this.highlighter
1586
+ this.updater = this.options.updater || this.updater
1587
+ this.$menu = $(this.options.menu).appendTo('body')
1588
+ this.source = this.options.source
1589
+ this.shown = false
1590
+ this.listen()
1591
+ }
1592
+
1593
+ Typeahead.prototype = {
1594
+
1595
+ constructor: Typeahead
1596
+
1597
+ , select: function () {
1598
+ var val = this.$menu.find('.active').attr('data-value')
1599
+ this.$element
1600
+ .val(this.updater(val))
1601
+ .change()
1602
+ return this.hide()
1603
+ }
1604
+
1605
+ , updater: function (item) {
1606
+ return item
1607
+ }
1608
+
1609
+ , show: function () {
1610
+ var pos = $.extend({}, this.$element.offset(), {
1611
+ height: this.$element[0].offsetHeight
1612
+ })
1613
+
1614
+ this.$menu.css({
1615
+ top: pos.top + pos.height
1616
+ , left: pos.left
1617
+ })
1618
+
1619
+ this.$menu.show()
1620
+ this.shown = true
1621
+ return this
1622
+ }
1623
+
1624
+ , hide: function () {
1625
+ this.$menu.hide()
1626
+ this.shown = false
1627
+ return this
1628
+ }
1629
+
1630
+ , lookup: function (event) {
1631
+ var that = this
1632
+ , items
1633
+ , q
1634
+
1635
+ this.query = this.$element.val()
1636
+
1637
+ if (!this.query) {
1638
+ return this.shown ? this.hide() : this
1639
+ }
1640
+
1641
+ items = $.grep(this.source, function (item) {
1642
+ return that.matcher(item)
1643
+ })
1644
+
1645
+ items = this.sorter(items)
1646
+
1647
+ if (!items.length) {
1648
+ return this.shown ? this.hide() : this
1649
+ }
1650
+
1651
+ return this.render(items.slice(0, this.options.items)).show()
1652
+ }
1653
+
1654
+ , matcher: function (item) {
1655
+ return ~item.toLowerCase().indexOf(this.query.toLowerCase())
1656
+ }
1657
+
1658
+ , sorter: function (items) {
1659
+ var beginswith = []
1660
+ , caseSensitive = []
1661
+ , caseInsensitive = []
1662
+ , item
1663
+
1664
+ while (item = items.shift()) {
1665
+ if (!item.toLowerCase().indexOf(this.query.toLowerCase())) beginswith.push(item)
1666
+ else if (~item.indexOf(this.query)) caseSensitive.push(item)
1667
+ else caseInsensitive.push(item)
1668
+ }
1669
+
1670
+ return beginswith.concat(caseSensitive, caseInsensitive)
1671
+ }
1672
+
1673
+ , highlighter: function (item) {
1674
+ var query = this.query.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, '\\$&')
1675
+ return item.replace(new RegExp('(' + query + ')', 'ig'), function ($1, match) {
1676
+ return '<strong>' + match + '</strong>'
1677
+ })
1678
+ }
1679
+
1680
+ , render: function (items) {
1681
+ var that = this
1682
+
1683
+ items = $(items).map(function (i, item) {
1684
+ i = $(that.options.item).attr('data-value', item)
1685
+ i.find('a').html(that.highlighter(item))
1686
+ return i[0]
1687
+ })
1688
+
1689
+ items.first().addClass('active')
1690
+ this.$menu.html(items)
1691
+ return this
1692
+ }
1693
+
1694
+ , next: function (event) {
1695
+ var active = this.$menu.find('.active').removeClass('active')
1696
+ , next = active.next()
1697
+
1698
+ if (!next.length) {
1699
+ next = $(this.$menu.find('li')[0])
1700
+ }
1701
+
1702
+ next.addClass('active')
1703
+ }
1704
+
1705
+ , prev: function (event) {
1706
+ var active = this.$menu.find('.active').removeClass('active')
1707
+ , prev = active.prev()
1708
+
1709
+ if (!prev.length) {
1710
+ prev = this.$menu.find('li').last()
1711
+ }
1712
+
1713
+ prev.addClass('active')
1714
+ }
1715
+
1716
+ , listen: function () {
1717
+ this.$element
1718
+ .on('blur', $.proxy(this.blur, this))
1719
+ .on('keypress', $.proxy(this.keypress, this))
1720
+ .on('keyup', $.proxy(this.keyup, this))
1721
+
1722
+ if ($.browser.webkit || $.browser.msie) {
1723
+ this.$element.on('keydown', $.proxy(this.keypress, this))
1724
+ }
1725
+
1726
+ this.$menu
1727
+ .on('click', $.proxy(this.click, this))
1728
+ .on('mouseenter', 'li', $.proxy(this.mouseenter, this))
1729
+ }
1730
+
1731
+ , keyup: function (e) {
1732
+ switch(e.keyCode) {
1733
+ case 40: // down arrow
1734
+ case 38: // up arrow
1735
+ break
1736
+
1737
+ case 9: // tab
1738
+ case 13: // enter
1739
+ if (!this.shown) return
1740
+ this.select()
1741
+ break
1742
+
1743
+ case 27: // escape
1744
+ if (!this.shown) return
1745
+ this.hide()
1746
+ break
1747
+
1748
+ default:
1749
+ this.lookup()
1750
+ }
1751
+
1752
+ e.stopPropagation()
1753
+ e.preventDefault()
1754
+ }
1755
+
1756
+ , keypress: function (e) {
1757
+ if (!this.shown) return
1758
+
1759
+ switch(e.keyCode) {
1760
+ case 9: // tab
1761
+ case 13: // enter
1762
+ case 27: // escape
1763
+ e.preventDefault()
1764
+ break
1765
+
1766
+ case 38: // up arrow
1767
+ if (e.type != 'keydown') break
1768
+ e.preventDefault()
1769
+ this.prev()
1770
+ break
1771
+
1772
+ case 40: // down arrow
1773
+ if (e.type != 'keydown') break
1774
+ e.preventDefault()
1775
+ this.next()
1776
+ break
1777
+ }
1778
+
1779
+ e.stopPropagation()
1780
+ }
1781
+
1782
+ , blur: function (e) {
1783
+ var that = this
1784
+ setTimeout(function () { that.hide() }, 150)
1785
+ }
1786
+
1787
+ , click: function (e) {
1788
+ e.stopPropagation()
1789
+ e.preventDefault()
1790
+ this.select()
1791
+ }
1792
+
1793
+ , mouseenter: function (e) {
1794
+ this.$menu.find('.active').removeClass('active')
1795
+ $(e.currentTarget).addClass('active')
1796
+ }
1797
+
1798
+ }
1799
+
1800
+
1801
+ /* TYPEAHEAD PLUGIN DEFINITION
1802
+ * =========================== */
1803
+
1804
+ $.fn.typeahead = function (option) {
1805
+ return this.each(function () {
1806
+ var $this = $(this)
1807
+ , data = $this.data('typeahead')
1808
+ , options = typeof option == 'object' && option
1809
+ if (!data) $this.data('typeahead', (data = new Typeahead(this, options)))
1810
+ if (typeof option == 'string') data[option]()
1811
+ })
1812
+ }
1813
+
1814
+ $.fn.typeahead.defaults = {
1815
+ source: []
1816
+ , items: 8
1817
+ , menu: '<ul class="typeahead dropdown-menu"></ul>'
1818
+ , item: '<li><a href="#"></a></li>'
1819
+ }
1820
+
1821
+ $.fn.typeahead.Constructor = Typeahead
1822
+
1823
+
1824
+ /* TYPEAHEAD DATA-API
1825
+ * ================== */
1826
+
1827
+ $(function () {
1828
+ $('body').on('focus.typeahead.data-api', '[data-provide="typeahead"]', function (e) {
1829
+ var $this = $(this)
1830
+ if ($this.data('typeahead')) return
1831
+ e.preventDefault()
1832
+ $this.typeahead($this.data())
1833
+ })
1834
+ })
1835
+
1836
+ }(window.jQuery);