omf_web 0.9.7 → 0.9.8

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 (62) hide show
  1. data/.gitignore +1 -0
  2. data/README.md +1 -1
  3. data/bin/omf_web_demo +3 -0
  4. data/bin/omf_web_demo.sh +0 -0
  5. data/doc/tutorial/tut01/hello_world.rb +27 -0
  6. data/doc/tutorial/tut02/hello_graph.rb +85 -0
  7. data/doc/tutorial/tut03/hello_database.rb +69 -0
  8. data/doc/tutorial/tut03/nmetric.sq3 +0 -0
  9. data/example/bridge/config.ru +2 -1
  10. data/example/demo/data_sources/downloads.csv +96 -1
  11. data/example/demo/demo_viz_server.rb +46 -28
  12. data/example/openflow-gec15/README.md +2 -0
  13. data/example/openflow-gec15/doc/gec15_topo.png +0 -0
  14. data/example/openflow-gec15/exp_source.rb +48 -9
  15. data/example/openflow-gec15/of_viz_server.rb +1 -1
  16. data/example/openflow-gec15/repository/of-exp.rb +117 -12
  17. data/example/openflow-gec15/repository/trema-ctl6.rb +2 -2
  18. data/example/simple/README.md +29 -1
  19. data/example/simple/data_sources/ping_source.rb +2 -2
  20. data/lib/irods4r/directory.rb +49 -0
  21. data/lib/irods4r/file.rb +53 -0
  22. data/lib/irods4r/icommands.rb +63 -0
  23. data/lib/irods4r.rb +34 -0
  24. data/lib/omf-web/content/content_proxy.rb +14 -5
  25. data/lib/omf-web/content/file_repository.rb +36 -75
  26. data/lib/omf-web/content/git_repository.rb +39 -35
  27. data/lib/omf-web/content/irods_repository.rb +191 -0
  28. data/lib/omf-web/content/repository.rb +84 -21
  29. data/lib/omf-web/content/static_repository.rb +61 -0
  30. data/lib/omf-web/data_source_proxy.rb +3 -3
  31. data/lib/omf-web/rack/session_authenticator.rb +67 -35
  32. data/lib/omf-web/rack/tab_mapper.rb +2 -1
  33. data/lib/omf-web/rack/websocket_handler.rb +49 -10
  34. data/lib/omf-web/session_store.rb +9 -8
  35. data/lib/omf-web/theme/bright/page.rb +1 -1
  36. data/lib/omf-web/thin/runner.rb +18 -5
  37. data/lib/omf-web/version.rb +1 -1
  38. data/lib/omf-web/widget/text/maruku/output/to_html.rb +8 -2
  39. data/lib/omf_web.rb +17 -2
  40. data/omf_web.gemspec +0 -1
  41. data/share/htdocs/graph/js/abstract_widget.js +3 -1
  42. data/share/htdocs/graph/js/barchart_brush.js +240 -0
  43. data/share/htdocs/js/data_source2.js +4 -1
  44. data/share/htdocs/js/mustache.js +17 -11
  45. data/share/htdocs/theme/bright/css/bright.css +1 -1
  46. data/share/htdocs/vendor/{bootstrap-2.1.1 → bootstrap-2.3.1}/css/bootstrap-responsive.css +56 -5
  47. data/share/htdocs/vendor/bootstrap-2.3.1/css/bootstrap-responsive.min.css +9 -0
  48. data/share/htdocs/vendor/{bootstrap-2.1.1 → bootstrap-2.3.1}/css/bootstrap.css +856 -472
  49. data/share/htdocs/vendor/bootstrap-2.3.1/css/bootstrap.min.css +9 -0
  50. data/share/htdocs/vendor/{bootstrap-2.1.1 → bootstrap-2.3.1}/img/glyphicons-halflings-white.png +0 -0
  51. data/share/htdocs/vendor/{bootstrap-2.1.1 → bootstrap-2.3.1}/img/glyphicons-halflings.png +0 -0
  52. data/share/htdocs/vendor/{bootstrap-2.1.1 → bootstrap-2.3.1}/js/bootstrap.js +427 -178
  53. data/share/htdocs/vendor/bootstrap-2.3.1/js/bootstrap.min.js +6 -0
  54. data/share/htdocs/vendor/jquery-tipsy/css/tipsy.css +25 -0
  55. data/share/htdocs/vendor/jquery-tipsy/js/jquery.tipsy.js +258 -0
  56. metadata +27 -14
  57. data/bin/omf-web-basic +0 -235
  58. data/share/htdocs/vendor/.DS_Store +0 -0
  59. data/share/htdocs/vendor/bootstrap-2.1.1/css/bootstrap-responsive.min.css +0 -9
  60. data/share/htdocs/vendor/bootstrap-2.1.1/css/bootstrap.min.css +0 -9
  61. data/share/htdocs/vendor/bootstrap-2.1.1/js/bootstrap.min.js +0 -6
  62. data/share/htdocs/vendor/jquery-ui-1.8.23/index.html +0 -383
@@ -1,5 +1,5 @@
1
1
  /* ===================================================
2
- * bootstrap-transition.js v2.1.1
2
+ * bootstrap-transition.js v2.3.1
3
3
  * http://twitter.github.com/bootstrap/javascript.html#transitions
4
4
  * ===================================================
5
5
  * Copyright 2012 Twitter, Inc.
@@ -20,13 +20,13 @@
20
20
 
21
21
  !function ($) {
22
22
 
23
- $(function () {
23
+ "use strict"; // jshint ;_;
24
24
 
25
- "use strict"; // jshint ;_;
26
25
 
26
+ /* CSS TRANSITION SUPPORT (http://www.modernizr.com/)
27
+ * ======================================================= */
27
28
 
28
- /* CSS TRANSITION SUPPORT (http://www.modernizr.com/)
29
- * ======================================================= */
29
+ $(function () {
30
30
 
31
31
  $.support.transition = (function () {
32
32
 
@@ -58,7 +58,7 @@
58
58
  })
59
59
 
60
60
  }(window.jQuery);/* ==========================================================
61
- * bootstrap-alert.js v2.1.1
61
+ * bootstrap-alert.js v2.3.1
62
62
  * http://twitter.github.com/bootstrap/javascript.html#alerts
63
63
  * ==========================================================
64
64
  * Copyright 2012 Twitter, Inc.
@@ -127,6 +127,8 @@
127
127
  /* ALERT PLUGIN DEFINITION
128
128
  * ======================= */
129
129
 
130
+ var old = $.fn.alert
131
+
130
132
  $.fn.alert = function (option) {
131
133
  return this.each(function () {
132
134
  var $this = $(this)
@@ -139,15 +141,22 @@
139
141
  $.fn.alert.Constructor = Alert
140
142
 
141
143
 
144
+ /* ALERT NO CONFLICT
145
+ * ================= */
146
+
147
+ $.fn.alert.noConflict = function () {
148
+ $.fn.alert = old
149
+ return this
150
+ }
151
+
152
+
142
153
  /* ALERT DATA-API
143
154
  * ============== */
144
155
 
145
- $(function () {
146
- $('body').on('click.alert.data-api', dismiss, Alert.prototype.close)
147
- })
156
+ $(document).on('click.alert.data-api', dismiss, Alert.prototype.close)
148
157
 
149
158
  }(window.jQuery);/* ============================================================
150
- * bootstrap-button.js v2.1.1
159
+ * bootstrap-button.js v2.3.1
151
160
  * http://twitter.github.com/bootstrap/javascript.html#buttons
152
161
  * ============================================================
153
162
  * Copyright 2012 Twitter, Inc.
@@ -212,6 +221,8 @@
212
221
  /* BUTTON PLUGIN DEFINITION
213
222
  * ======================== */
214
223
 
224
+ var old = $.fn.button
225
+
215
226
  $.fn.button = function (option) {
216
227
  return this.each(function () {
217
228
  var $this = $(this)
@@ -230,19 +241,26 @@
230
241
  $.fn.button.Constructor = Button
231
242
 
232
243
 
244
+ /* BUTTON NO CONFLICT
245
+ * ================== */
246
+
247
+ $.fn.button.noConflict = function () {
248
+ $.fn.button = old
249
+ return this
250
+ }
251
+
252
+
233
253
  /* BUTTON DATA-API
234
254
  * =============== */
235
255
 
236
- $(function () {
237
- $('body').on('click.button.data-api', '[data-toggle^=button]', function ( e ) {
238
- var $btn = $(e.target)
239
- if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn')
240
- $btn.button('toggle')
241
- })
256
+ $(document).on('click.button.data-api', '[data-toggle^=button]', function (e) {
257
+ var $btn = $(e.target)
258
+ if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn')
259
+ $btn.button('toggle')
242
260
  })
243
261
 
244
262
  }(window.jQuery);/* ==========================================================
245
- * bootstrap-carousel.js v2.1.1
263
+ * bootstrap-carousel.js v2.3.1
246
264
  * http://twitter.github.com/bootstrap/javascript.html#carousel
247
265
  * ==========================================================
248
266
  * Copyright 2012 Twitter, Inc.
@@ -271,8 +289,8 @@
271
289
 
272
290
  var Carousel = function (element, options) {
273
291
  this.$element = $(element)
292
+ this.$indicators = this.$element.find('.carousel-indicators')
274
293
  this.options = options
275
- this.options.slide && this.slide(this.options.slide)
276
294
  this.options.pause == 'hover' && this.$element
277
295
  .on('mouseenter', $.proxy(this.pause, this))
278
296
  .on('mouseleave', $.proxy(this.cycle, this))
@@ -282,19 +300,24 @@
282
300
 
283
301
  cycle: function (e) {
284
302
  if (!e) this.paused = false
303
+ if (this.interval) clearInterval(this.interval);
285
304
  this.options.interval
286
305
  && !this.paused
287
306
  && (this.interval = setInterval($.proxy(this.next, this), this.options.interval))
288
307
  return this
289
308
  }
290
309
 
310
+ , getActiveIndex: function () {
311
+ this.$active = this.$element.find('.item.active')
312
+ this.$items = this.$active.parent().children()
313
+ return this.$items.index(this.$active)
314
+ }
315
+
291
316
  , to: function (pos) {
292
- var $active = this.$element.find('.item.active')
293
- , children = $active.parent().children()
294
- , activePos = children.index($active)
317
+ var activeIndex = this.getActiveIndex()
295
318
  , that = this
296
319
 
297
- if (pos > (children.length - 1) || pos < 0) return
320
+ if (pos > (this.$items.length - 1) || pos < 0) return
298
321
 
299
322
  if (this.sliding) {
300
323
  return this.$element.one('slid', function () {
@@ -302,18 +325,18 @@
302
325
  })
303
326
  }
304
327
 
305
- if (activePos == pos) {
328
+ if (activeIndex == pos) {
306
329
  return this.pause().cycle()
307
330
  }
308
331
 
309
- return this.slide(pos > activePos ? 'next' : 'prev', $(children[pos]))
332
+ return this.slide(pos > activeIndex ? 'next' : 'prev', $(this.$items[pos]))
310
333
  }
311
334
 
312
335
  , pause: function (e) {
313
336
  if (!e) this.paused = true
314
337
  if (this.$element.find('.next, .prev').length && $.support.transition.end) {
315
338
  this.$element.trigger($.support.transition.end)
316
- this.cycle()
339
+ this.cycle(true)
317
340
  }
318
341
  clearInterval(this.interval)
319
342
  this.interval = null
@@ -337,9 +360,7 @@
337
360
  , direction = type == 'next' ? 'left' : 'right'
338
361
  , fallback = type == 'next' ? 'first' : 'last'
339
362
  , that = this
340
- , e = $.Event('slide', {
341
- relatedTarget: $next[0]
342
- })
363
+ , e
343
364
 
344
365
  this.sliding = true
345
366
 
@@ -347,8 +368,21 @@
347
368
 
348
369
  $next = $next.length ? $next : this.$element.find('.item')[fallback]()
349
370
 
371
+ e = $.Event('slide', {
372
+ relatedTarget: $next[0]
373
+ , direction: direction
374
+ })
375
+
350
376
  if ($next.hasClass('active')) return
351
377
 
378
+ if (this.$indicators.length) {
379
+ this.$indicators.find('.active').removeClass('active')
380
+ this.$element.one('slid', function () {
381
+ var $nextIndicator = $(that.$indicators.children()[that.getActiveIndex()])
382
+ $nextIndicator && $nextIndicator.addClass('active')
383
+ })
384
+ }
385
+
352
386
  if ($.support.transition && this.$element.hasClass('slide')) {
353
387
  this.$element.trigger(e)
354
388
  if (e.isDefaultPrevented()) return
@@ -382,6 +416,8 @@
382
416
  /* CAROUSEL PLUGIN DEFINITION
383
417
  * ========================== */
384
418
 
419
+ var old = $.fn.carousel
420
+
385
421
  $.fn.carousel = function (option) {
386
422
  return this.each(function () {
387
423
  var $this = $(this)
@@ -391,7 +427,7 @@
391
427
  if (!data) $this.data('carousel', (data = new Carousel(this, options)))
392
428
  if (typeof option == 'number') data.to(option)
393
429
  else if (action) data[action]()
394
- else if (options.interval) data.cycle()
430
+ else if (options.interval) data.pause().cycle()
395
431
  })
396
432
  }
397
433
 
@@ -403,21 +439,34 @@
403
439
  $.fn.carousel.Constructor = Carousel
404
440
 
405
441
 
442
+ /* CAROUSEL NO CONFLICT
443
+ * ==================== */
444
+
445
+ $.fn.carousel.noConflict = function () {
446
+ $.fn.carousel = old
447
+ return this
448
+ }
449
+
406
450
  /* CAROUSEL DATA-API
407
451
  * ================= */
408
452
 
409
- $(function () {
410
- $('body').on('click.carousel.data-api', '[data-slide]', function ( e ) {
411
- var $this = $(this), href
412
- , $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7
413
- , options = !$target.data('modal') && $.extend({}, $target.data(), $this.data())
414
- $target.carousel(options)
415
- e.preventDefault()
416
- })
453
+ $(document).on('click.carousel.data-api', '[data-slide], [data-slide-to]', function (e) {
454
+ var $this = $(this), href
455
+ , $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7
456
+ , options = $.extend({}, $target.data(), $this.data())
457
+ , slideIndex
458
+
459
+ $target.carousel(options)
460
+
461
+ if (slideIndex = $this.attr('data-slide-to')) {
462
+ $target.data('carousel').pause().to(slideIndex).cycle()
463
+ }
464
+
465
+ e.preventDefault()
417
466
  })
418
467
 
419
468
  }(window.jQuery);/* =============================================================
420
- * bootstrap-collapse.js v2.1.1
469
+ * bootstrap-collapse.js v2.3.1
421
470
  * http://twitter.github.com/bootstrap/javascript.html#collapse
422
471
  * =============================================================
423
472
  * Copyright 2012 Twitter, Inc.
@@ -470,7 +519,7 @@
470
519
  , actives
471
520
  , hasData
472
521
 
473
- if (this.transitioning) return
522
+ if (this.transitioning || this.$element.hasClass('in')) return
474
523
 
475
524
  dimension = this.dimension()
476
525
  scroll = $.camelCase(['scroll', dimension].join('-'))
@@ -490,7 +539,7 @@
490
539
 
491
540
  , hide: function () {
492
541
  var dimension
493
- if (this.transitioning) return
542
+ if (this.transitioning || !this.$element.hasClass('in')) return
494
543
  dimension = this.dimension()
495
544
  this.reset(this.$element[dimension]())
496
545
  this.transition('removeClass', $.Event('hide'), 'hidden')
@@ -538,14 +587,16 @@
538
587
  }
539
588
 
540
589
 
541
- /* COLLAPSIBLE PLUGIN DEFINITION
542
- * ============================== */
590
+ /* COLLAPSE PLUGIN DEFINITION
591
+ * ========================== */
592
+
593
+ var old = $.fn.collapse
543
594
 
544
595
  $.fn.collapse = function (option) {
545
596
  return this.each(function () {
546
597
  var $this = $(this)
547
598
  , data = $this.data('collapse')
548
- , options = typeof option == 'object' && option
599
+ , options = $.extend({}, $.fn.collapse.defaults, $this.data(), typeof option == 'object' && option)
549
600
  if (!data) $this.data('collapse', (data = new Collapse(this, options)))
550
601
  if (typeof option == 'string') data[option]()
551
602
  })
@@ -558,23 +609,30 @@
558
609
  $.fn.collapse.Constructor = Collapse
559
610
 
560
611
 
561
- /* COLLAPSIBLE DATA-API
612
+ /* COLLAPSE NO CONFLICT
562
613
  * ==================== */
563
614
 
564
- $(function () {
565
- $('body').on('click.collapse.data-api', '[data-toggle=collapse]', function (e) {
566
- var $this = $(this), href
567
- , target = $this.attr('data-target')
568
- || e.preventDefault()
569
- || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7
570
- , option = $(target).data('collapse') ? 'toggle' : $this.data()
571
- $this[$(target).hasClass('in') ? 'addClass' : 'removeClass']('collapsed')
572
- $(target).collapse(option)
573
- })
615
+ $.fn.collapse.noConflict = function () {
616
+ $.fn.collapse = old
617
+ return this
618
+ }
619
+
620
+
621
+ /* COLLAPSE DATA-API
622
+ * ================= */
623
+
624
+ $(document).on('click.collapse.data-api', '[data-toggle=collapse]', function (e) {
625
+ var $this = $(this), href
626
+ , target = $this.attr('data-target')
627
+ || e.preventDefault()
628
+ || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7
629
+ , option = $(target).data('collapse') ? 'toggle' : $this.data()
630
+ $this[$(target).hasClass('in') ? 'addClass' : 'removeClass']('collapsed')
631
+ $(target).collapse(option)
574
632
  })
575
633
 
576
634
  }(window.jQuery);/* ============================================================
577
- * bootstrap-dropdown.js v2.1.1
635
+ * bootstrap-dropdown.js v2.3.1
578
636
  * http://twitter.github.com/bootstrap/javascript.html#dropdowns
579
637
  * ============================================================
580
638
  * Copyright 2012 Twitter, Inc.
@@ -628,9 +686,10 @@
628
686
 
629
687
  if (!isActive) {
630
688
  $parent.toggleClass('open')
631
- $this.focus()
632
689
  }
633
690
 
691
+ $this.focus()
692
+
634
693
  return false
635
694
  }
636
695
 
@@ -655,9 +714,12 @@
655
714
 
656
715
  isActive = $parent.hasClass('open')
657
716
 
658
- if (!isActive || (isActive && e.keyCode == 27)) return $this.click()
717
+ if (!isActive || (isActive && e.keyCode == 27)) {
718
+ if (e.which == 27) $parent.find(toggle).focus()
719
+ return $this.click()
720
+ }
659
721
 
660
- $items = $('[role=menu] li:not(.divider) a', $parent)
722
+ $items = $('[role=menu] li:not(.divider):visible a', $parent)
661
723
 
662
724
  if (!$items.length) return
663
725
 
@@ -675,8 +737,9 @@
675
737
  }
676
738
 
677
739
  function clearMenus() {
678
- getParent($(toggle))
679
- .removeClass('open')
740
+ $(toggle).each(function () {
741
+ getParent($(this)).removeClass('open')
742
+ })
680
743
  }
681
744
 
682
745
  function getParent($this) {
@@ -688,8 +751,9 @@
688
751
  selector = selector && /#/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
689
752
  }
690
753
 
691
- $parent = $(selector)
692
- $parent.length || ($parent = $this.parent())
754
+ $parent = selector && $(selector)
755
+
756
+ if (!$parent || !$parent.length) $parent = $this.parent()
693
757
 
694
758
  return $parent
695
759
  }
@@ -698,6 +762,8 @@
698
762
  /* DROPDOWN PLUGIN DEFINITION
699
763
  * ========================== */
700
764
 
765
+ var old = $.fn.dropdown
766
+
701
767
  $.fn.dropdown = function (option) {
702
768
  return this.each(function () {
703
769
  var $this = $(this)
@@ -710,20 +776,28 @@
710
776
  $.fn.dropdown.Constructor = Dropdown
711
777
 
712
778
 
779
+ /* DROPDOWN NO CONFLICT
780
+ * ==================== */
781
+
782
+ $.fn.dropdown.noConflict = function () {
783
+ $.fn.dropdown = old
784
+ return this
785
+ }
786
+
787
+
713
788
  /* APPLY TO STANDARD DROPDOWN ELEMENTS
714
789
  * =================================== */
715
790
 
716
- $(function () {
717
- $('html')
718
- .on('click.dropdown.data-api touchstart.dropdown.data-api', clearMenus)
719
- $('body')
720
- .on('click.dropdown touchstart.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() })
721
- .on('click.dropdown.data-api touchstart.dropdown.data-api' , toggle, Dropdown.prototype.toggle)
722
- .on('keydown.dropdown.data-api touchstart.dropdown.data-api', toggle + ', [role=menu]' , Dropdown.prototype.keydown)
723
- })
791
+ $(document)
792
+ .on('click.dropdown.data-api', clearMenus)
793
+ .on('click.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() })
794
+ .on('click.dropdown-menu', function (e) { e.stopPropagation() })
795
+ .on('click.dropdown.data-api' , toggle, Dropdown.prototype.toggle)
796
+ .on('keydown.dropdown.data-api', toggle + ', [role=menu]' , Dropdown.prototype.keydown)
724
797
 
725
- }(window.jQuery);/* =========================================================
726
- * bootstrap-modal.js v2.1.1
798
+ }(window.jQuery);
799
+ /* =========================================================
800
+ * bootstrap-modal.js v2.3.1
727
801
  * http://twitter.github.com/bootstrap/javascript.html#modals
728
802
  * =========================================================
729
803
  * Copyright 2012 Twitter, Inc.
@@ -773,8 +847,6 @@
773
847
 
774
848
  if (this.isShown || e.isDefaultPrevented()) return
775
849
 
776
- $('body').addClass('modal-open')
777
-
778
850
  this.isShown = true
779
851
 
780
852
  this.escape()
@@ -786,8 +858,7 @@
786
858
  that.$element.appendTo(document.body) //don't move modals dom position
787
859
  }
788
860
 
789
- that.$element
790
- .show()
861
+ that.$element.show()
791
862
 
792
863
  if (transition) {
793
864
  that.$element[0].offsetWidth // force reflow
@@ -796,13 +867,12 @@
796
867
  that.$element
797
868
  .addClass('in')
798
869
  .attr('aria-hidden', false)
799
- .focus()
800
870
 
801
871
  that.enforceFocus()
802
872
 
803
873
  transition ?
804
- that.$element.one($.support.transition.end, function () { that.$element.trigger('shown') }) :
805
- that.$element.trigger('shown')
874
+ that.$element.one($.support.transition.end, function () { that.$element.focus().trigger('shown') }) :
875
+ that.$element.focus().trigger('shown')
806
876
 
807
877
  })
808
878
  }
@@ -820,8 +890,6 @@
820
890
 
821
891
  this.isShown = false
822
892
 
823
- $('body').removeClass('modal-open')
824
-
825
893
  this.escape()
826
894
 
827
895
  $(document).off('focusin.modal')
@@ -868,16 +936,17 @@
868
936
  })
869
937
  }
870
938
 
871
- , hideModal: function (that) {
872
- this.$element
873
- .hide()
874
- .trigger('hidden')
875
-
876
- this.backdrop()
939
+ , hideModal: function () {
940
+ var that = this
941
+ this.$element.hide()
942
+ this.backdrop(function () {
943
+ that.removeBackdrop()
944
+ that.$element.trigger('hidden')
945
+ })
877
946
  }
878
947
 
879
948
  , removeBackdrop: function () {
880
- this.$backdrop.remove()
949
+ this.$backdrop && this.$backdrop.remove()
881
950
  this.$backdrop = null
882
951
  }
883
952
 
@@ -891,14 +960,18 @@
891
960
  this.$backdrop = $('<div class="modal-backdrop ' + animate + '" />')
892
961
  .appendTo(document.body)
893
962
 
894
- if (this.options.backdrop != 'static') {
895
- this.$backdrop.click($.proxy(this.hide, this))
896
- }
963
+ this.$backdrop.click(
964
+ this.options.backdrop == 'static' ?
965
+ $.proxy(this.$element[0].focus, this.$element[0])
966
+ : $.proxy(this.hide, this)
967
+ )
897
968
 
898
969
  if (doAnimate) this.$backdrop[0].offsetWidth // force reflow
899
970
 
900
971
  this.$backdrop.addClass('in')
901
972
 
973
+ if (!callback) return
974
+
902
975
  doAnimate ?
903
976
  this.$backdrop.one($.support.transition.end, callback) :
904
977
  callback()
@@ -907,8 +980,8 @@
907
980
  this.$backdrop.removeClass('in')
908
981
 
909
982
  $.support.transition && this.$element.hasClass('fade')?
910
- this.$backdrop.one($.support.transition.end, $.proxy(this.removeBackdrop, this)) :
911
- this.removeBackdrop()
983
+ this.$backdrop.one($.support.transition.end, callback) :
984
+ callback()
912
985
 
913
986
  } else if (callback) {
914
987
  callback()
@@ -920,6 +993,8 @@
920
993
  /* MODAL PLUGIN DEFINITION
921
994
  * ======================= */
922
995
 
996
+ var old = $.fn.modal
997
+
923
998
  $.fn.modal = function (option) {
924
999
  return this.each(function () {
925
1000
  var $this = $(this)
@@ -940,28 +1015,36 @@
940
1015
  $.fn.modal.Constructor = Modal
941
1016
 
942
1017
 
1018
+ /* MODAL NO CONFLICT
1019
+ * ================= */
1020
+
1021
+ $.fn.modal.noConflict = function () {
1022
+ $.fn.modal = old
1023
+ return this
1024
+ }
1025
+
1026
+
943
1027
  /* MODAL DATA-API
944
1028
  * ============== */
945
1029
 
946
- $(function () {
947
- $('body').on('click.modal.data-api', '[data-toggle="modal"]', function ( e ) {
948
- var $this = $(this)
949
- , href = $this.attr('href')
950
- , $target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, ''))) //strip for ie7
951
- , option = $target.data('modal') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data())
1030
+ $(document).on('click.modal.data-api', '[data-toggle="modal"]', function (e) {
1031
+ var $this = $(this)
1032
+ , href = $this.attr('href')
1033
+ , $target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, ''))) //strip for ie7
1034
+ , option = $target.data('modal') ? 'toggle' : $.extend({ remote:!/#/.test(href) && href }, $target.data(), $this.data())
952
1035
 
953
- e.preventDefault()
1036
+ e.preventDefault()
954
1037
 
955
- $target
956
- .modal(option)
957
- .one('hide', function () {
958
- $this.focus()
959
- })
960
- })
1038
+ $target
1039
+ .modal(option)
1040
+ .one('hide', function () {
1041
+ $this.focus()
1042
+ })
961
1043
  })
962
1044
 
963
- }(window.jQuery);/* ===========================================================
964
- * bootstrap-tooltip.js v2.1.1
1045
+ }(window.jQuery);
1046
+ /* ===========================================================
1047
+ * bootstrap-tooltip.js v2.3.1
965
1048
  * http://twitter.github.com/bootstrap/javascript.html#tooltips
966
1049
  * Inspired by the original jQuery.tipsy by Jason Frame
967
1050
  * ===========================================================
@@ -1000,19 +1083,27 @@
1000
1083
  , init: function (type, element, options) {
1001
1084
  var eventIn
1002
1085
  , eventOut
1086
+ , triggers
1087
+ , trigger
1088
+ , i
1003
1089
 
1004
1090
  this.type = type
1005
1091
  this.$element = $(element)
1006
1092
  this.options = this.getOptions(options)
1007
1093
  this.enabled = true
1008
1094
 
1009
- if (this.options.trigger == 'click') {
1010
- this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this))
1011
- } else if (this.options.trigger != 'manual') {
1012
- eventIn = this.options.trigger == 'hover' ? 'mouseenter' : 'focus'
1013
- eventOut = this.options.trigger == 'hover' ? 'mouseleave' : 'blur'
1014
- this.$element.on(eventIn + '.' + this.type, this.options.selector, $.proxy(this.enter, this))
1015
- this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this))
1095
+ triggers = this.options.trigger.split(' ')
1096
+
1097
+ for (i = triggers.length; i--;) {
1098
+ trigger = triggers[i]
1099
+ if (trigger == 'click') {
1100
+ this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this))
1101
+ } else if (trigger != 'manual') {
1102
+ eventIn = trigger == 'hover' ? 'mouseenter' : 'focus'
1103
+ eventOut = trigger == 'hover' ? 'mouseleave' : 'blur'
1104
+ this.$element.on(eventIn + '.' + this.type, this.options.selector, $.proxy(this.enter, this))
1105
+ this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this))
1106
+ }
1016
1107
  }
1017
1108
 
1018
1109
  this.options.selector ?
@@ -1021,7 +1112,7 @@
1021
1112
  }
1022
1113
 
1023
1114
  , getOptions: function (options) {
1024
- options = $.extend({}, $.fn[this.type].defaults, options, this.$element.data())
1115
+ options = $.extend({}, $.fn[this.type].defaults, this.$element.data(), options)
1025
1116
 
1026
1117
  if (options.delay && typeof options.delay == 'number') {
1027
1118
  options.delay = {
@@ -1034,7 +1125,15 @@
1034
1125
  }
1035
1126
 
1036
1127
  , enter: function (e) {
1037
- var self = $(e.currentTarget)[this.type](this._options).data(this.type)
1128
+ var defaults = $.fn[this.type].defaults
1129
+ , options = {}
1130
+ , self
1131
+
1132
+ this._options && $.each(this._options, function (key, value) {
1133
+ if (defaults[key] != value) options[key] = value
1134
+ }, this)
1135
+
1136
+ self = $(e.currentTarget)[this.type](options).data(this.type)
1038
1137
 
1039
1138
  if (!self.options.delay || !self.options.delay.show) return self.show()
1040
1139
 
@@ -1059,14 +1158,16 @@
1059
1158
 
1060
1159
  , show: function () {
1061
1160
  var $tip
1062
- , inside
1063
1161
  , pos
1064
1162
  , actualWidth
1065
1163
  , actualHeight
1066
1164
  , placement
1067
1165
  , tp
1166
+ , e = $.Event('show')
1068
1167
 
1069
1168
  if (this.hasContent() && this.enabled) {
1169
+ this.$element.trigger(e)
1170
+ if (e.isDefaultPrevented()) return
1070
1171
  $tip = this.tip()
1071
1172
  this.setContent()
1072
1173
 
@@ -1078,19 +1179,18 @@
1078
1179
  this.options.placement.call(this, $tip[0], this.$element[0]) :
1079
1180
  this.options.placement
1080
1181
 
1081
- inside = /in/.test(placement)
1082
-
1083
1182
  $tip
1084
- .remove()
1183
+ .detach()
1085
1184
  .css({ top: 0, left: 0, display: 'block' })
1086
- .appendTo(inside ? this.$element : document.body)
1087
1185
 
1088
- pos = this.getPosition(inside)
1186
+ this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element)
1187
+
1188
+ pos = this.getPosition()
1089
1189
 
1090
1190
  actualWidth = $tip[0].offsetWidth
1091
1191
  actualHeight = $tip[0].offsetHeight
1092
1192
 
1093
- switch (inside ? placement.split(' ')[1] : placement) {
1193
+ switch (placement) {
1094
1194
  case 'bottom':
1095
1195
  tp = {top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2}
1096
1196
  break
@@ -1105,11 +1205,56 @@
1105
1205
  break
1106
1206
  }
1107
1207
 
1108
- $tip
1109
- .css(tp)
1110
- .addClass(placement)
1111
- .addClass('in')
1208
+ this.applyPlacement(tp, placement)
1209
+ this.$element.trigger('shown')
1210
+ }
1211
+ }
1212
+
1213
+ , applyPlacement: function(offset, placement){
1214
+ var $tip = this.tip()
1215
+ , width = $tip[0].offsetWidth
1216
+ , height = $tip[0].offsetHeight
1217
+ , actualWidth
1218
+ , actualHeight
1219
+ , delta
1220
+ , replace
1221
+
1222
+ $tip
1223
+ .offset(offset)
1224
+ .addClass(placement)
1225
+ .addClass('in')
1226
+
1227
+ actualWidth = $tip[0].offsetWidth
1228
+ actualHeight = $tip[0].offsetHeight
1229
+
1230
+ if (placement == 'top' && actualHeight != height) {
1231
+ offset.top = offset.top + height - actualHeight
1232
+ replace = true
1233
+ }
1234
+
1235
+ if (placement == 'bottom' || placement == 'top') {
1236
+ delta = 0
1237
+
1238
+ if (offset.left < 0){
1239
+ delta = offset.left * -2
1240
+ offset.left = 0
1241
+ $tip.offset(offset)
1242
+ actualWidth = $tip[0].offsetWidth
1243
+ actualHeight = $tip[0].offsetHeight
1244
+ }
1245
+
1246
+ this.replaceArrow(delta - width + actualWidth, actualWidth, 'left')
1247
+ } else {
1248
+ this.replaceArrow(actualHeight - height, actualHeight, 'top')
1112
1249
  }
1250
+
1251
+ if (replace) $tip.offset(offset)
1252
+ }
1253
+
1254
+ , replaceArrow: function(delta, dimension, position){
1255
+ this
1256
+ .arrow()
1257
+ .css(position, delta ? (50 * (1 - delta / dimension) + "%") : '')
1113
1258
  }
1114
1259
 
1115
1260
  , setContent: function () {
@@ -1123,23 +1268,29 @@
1123
1268
  , hide: function () {
1124
1269
  var that = this
1125
1270
  , $tip = this.tip()
1271
+ , e = $.Event('hide')
1272
+
1273
+ this.$element.trigger(e)
1274
+ if (e.isDefaultPrevented()) return
1126
1275
 
1127
1276
  $tip.removeClass('in')
1128
1277
 
1129
1278
  function removeWithAnimation() {
1130
1279
  var timeout = setTimeout(function () {
1131
- $tip.off($.support.transition.end).remove()
1280
+ $tip.off($.support.transition.end).detach()
1132
1281
  }, 500)
1133
1282
 
1134
1283
  $tip.one($.support.transition.end, function () {
1135
1284
  clearTimeout(timeout)
1136
- $tip.remove()
1285
+ $tip.detach()
1137
1286
  })
1138
1287
  }
1139
1288
 
1140
1289
  $.support.transition && this.$tip.hasClass('fade') ?
1141
1290
  removeWithAnimation() :
1142
- $tip.remove()
1291
+ $tip.detach()
1292
+
1293
+ this.$element.trigger('hidden')
1143
1294
 
1144
1295
  return this
1145
1296
  }
@@ -1147,7 +1298,7 @@
1147
1298
  , fixTitle: function () {
1148
1299
  var $e = this.$element
1149
1300
  if ($e.attr('title') || typeof($e.attr('data-original-title')) != 'string') {
1150
- $e.attr('data-original-title', $e.attr('title') || '').removeAttr('title')
1301
+ $e.attr('data-original-title', $e.attr('title') || '').attr('title', '')
1151
1302
  }
1152
1303
  }
1153
1304
 
@@ -1155,11 +1306,12 @@
1155
1306
  return this.getTitle()
1156
1307
  }
1157
1308
 
1158
- , getPosition: function (inside) {
1159
- return $.extend({}, (inside ? {top: 0, left: 0} : this.$element.offset()), {
1160
- width: this.$element[0].offsetWidth
1161
- , height: this.$element[0].offsetHeight
1162
- })
1309
+ , getPosition: function () {
1310
+ var el = this.$element[0]
1311
+ return $.extend({}, (typeof el.getBoundingClientRect == 'function') ? el.getBoundingClientRect() : {
1312
+ width: el.offsetWidth
1313
+ , height: el.offsetHeight
1314
+ }, this.$element.offset())
1163
1315
  }
1164
1316
 
1165
1317
  , getTitle: function () {
@@ -1177,6 +1329,10 @@
1177
1329
  return this.$tip = this.$tip || $(this.options.template)
1178
1330
  }
1179
1331
 
1332
+ , arrow: function(){
1333
+ return this.$arrow = this.$arrow || this.tip().find(".tooltip-arrow")
1334
+ }
1335
+
1180
1336
  , validate: function () {
1181
1337
  if (!this.$element[0].parentNode) {
1182
1338
  this.hide()
@@ -1197,8 +1353,9 @@
1197
1353
  this.enabled = !this.enabled
1198
1354
  }
1199
1355
 
1200
- , toggle: function () {
1201
- this[this.tip().hasClass('in') ? 'hide' : 'show']()
1356
+ , toggle: function (e) {
1357
+ var self = e ? $(e.currentTarget)[this.type](this._options).data(this.type) : this
1358
+ self.tip().hasClass('in') ? self.hide() : self.show()
1202
1359
  }
1203
1360
 
1204
1361
  , destroy: function () {
@@ -1211,6 +1368,8 @@
1211
1368
  /* TOOLTIP PLUGIN DEFINITION
1212
1369
  * ========================= */
1213
1370
 
1371
+ var old = $.fn.tooltip
1372
+
1214
1373
  $.fn.tooltip = function ( option ) {
1215
1374
  return this.each(function () {
1216
1375
  var $this = $(this)
@@ -1228,15 +1387,25 @@
1228
1387
  , placement: 'top'
1229
1388
  , selector: false
1230
1389
  , template: '<div class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>'
1231
- , trigger: 'hover'
1390
+ , trigger: 'hover focus'
1232
1391
  , title: ''
1233
1392
  , delay: 0
1234
- , html: true
1393
+ , html: false
1394
+ , container: false
1395
+ }
1396
+
1397
+
1398
+ /* TOOLTIP NO CONFLICT
1399
+ * =================== */
1400
+
1401
+ $.fn.tooltip.noConflict = function () {
1402
+ $.fn.tooltip = old
1403
+ return this
1235
1404
  }
1236
1405
 
1237
1406
  }(window.jQuery);
1238
1407
  /* ===========================================================
1239
- * bootstrap-popover.js v2.1.1
1408
+ * bootstrap-popover.js v2.3.1
1240
1409
  * http://twitter.github.com/bootstrap/javascript.html#popovers
1241
1410
  * ===========================================================
1242
1411
  * Copyright 2012 Twitter, Inc.
@@ -1281,7 +1450,7 @@
1281
1450
  , content = this.getContent()
1282
1451
 
1283
1452
  $tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title)
1284
- $tip.find('.popover-content > *')[this.options.html ? 'html' : 'text'](content)
1453
+ $tip.find('.popover-content')[this.options.html ? 'html' : 'text'](content)
1285
1454
 
1286
1455
  $tip.removeClass('fade top bottom left right in')
1287
1456
  }
@@ -1295,8 +1464,8 @@
1295
1464
  , $e = this.$element
1296
1465
  , o = this.options
1297
1466
 
1298
- content = $e.attr('data-content')
1299
- || (typeof o.content == 'function' ? o.content.call($e[0]) : o.content)
1467
+ content = (typeof o.content == 'function' ? o.content.call($e[0]) : o.content)
1468
+ || $e.attr('data-content')
1300
1469
 
1301
1470
  return content
1302
1471
  }
@@ -1318,6 +1487,8 @@
1318
1487
  /* POPOVER PLUGIN DEFINITION
1319
1488
  * ======================= */
1320
1489
 
1490
+ var old = $.fn.popover
1491
+
1321
1492
  $.fn.popover = function (option) {
1322
1493
  return this.each(function () {
1323
1494
  var $this = $(this)
@@ -1334,11 +1505,21 @@
1334
1505
  placement: 'right'
1335
1506
  , trigger: 'click'
1336
1507
  , content: ''
1337
- , 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>'
1508
+ , template: '<div class="popover"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'
1338
1509
  })
1339
1510
 
1340
- }(window.jQuery);/* =============================================================
1341
- * bootstrap-scrollspy.js v2.1.1
1511
+
1512
+ /* POPOVER NO CONFLICT
1513
+ * =================== */
1514
+
1515
+ $.fn.popover.noConflict = function () {
1516
+ $.fn.popover = old
1517
+ return this
1518
+ }
1519
+
1520
+ }(window.jQuery);
1521
+ /* =============================================================
1522
+ * bootstrap-scrollspy.js v2.3.1
1342
1523
  * http://twitter.github.com/bootstrap/javascript.html#scrollspy
1343
1524
  * =============================================================
1344
1525
  * Copyright 2012 Twitter, Inc.
@@ -1398,7 +1579,7 @@
1398
1579
  , $href = /^#\w/.test(href) && $(href)
1399
1580
  return ( $href
1400
1581
  && $href.length
1401
- && [[ $href.position().top, href ]] ) || null
1582
+ && [[ $href.position().top + (!$.isWindow(self.$scrollElement.get(0)) && self.$scrollElement.scrollTop()), href ]] ) || null
1402
1583
  })
1403
1584
  .sort(function (a, b) { return a[0] - b[0] })
1404
1585
  .each(function () {
@@ -1460,6 +1641,8 @@
1460
1641
  /* SCROLLSPY PLUGIN DEFINITION
1461
1642
  * =========================== */
1462
1643
 
1644
+ var old = $.fn.scrollspy
1645
+
1463
1646
  $.fn.scrollspy = function (option) {
1464
1647
  return this.each(function () {
1465
1648
  var $this = $(this)
@@ -1477,6 +1660,15 @@
1477
1660
  }
1478
1661
 
1479
1662
 
1663
+ /* SCROLLSPY NO CONFLICT
1664
+ * ===================== */
1665
+
1666
+ $.fn.scrollspy.noConflict = function () {
1667
+ $.fn.scrollspy = old
1668
+ return this
1669
+ }
1670
+
1671
+
1480
1672
  /* SCROLLSPY DATA-API
1481
1673
  * ================== */
1482
1674
 
@@ -1488,7 +1680,7 @@
1488
1680
  })
1489
1681
 
1490
1682
  }(window.jQuery);/* ========================================================
1491
- * bootstrap-tab.js v2.1.1
1683
+ * bootstrap-tab.js v2.3.1
1492
1684
  * http://twitter.github.com/bootstrap/javascript.html#tabs
1493
1685
  * ========================================================
1494
1686
  * Copyright 2012 Twitter, Inc.
@@ -1538,7 +1730,7 @@
1538
1730
 
1539
1731
  if ( $this.parent('li').hasClass('active') ) return
1540
1732
 
1541
- previous = $ul.find('.active a').last()[0]
1733
+ previous = $ul.find('.active:last a')[0]
1542
1734
 
1543
1735
  e = $.Event('show', {
1544
1736
  relatedTarget: previous
@@ -1599,6 +1791,8 @@
1599
1791
  /* TAB PLUGIN DEFINITION
1600
1792
  * ===================== */
1601
1793
 
1794
+ var old = $.fn.tab
1795
+
1602
1796
  $.fn.tab = function ( option ) {
1603
1797
  return this.each(function () {
1604
1798
  var $this = $(this)
@@ -1611,18 +1805,25 @@
1611
1805
  $.fn.tab.Constructor = Tab
1612
1806
 
1613
1807
 
1808
+ /* TAB NO CONFLICT
1809
+ * =============== */
1810
+
1811
+ $.fn.tab.noConflict = function () {
1812
+ $.fn.tab = old
1813
+ return this
1814
+ }
1815
+
1816
+
1614
1817
  /* TAB DATA-API
1615
1818
  * ============ */
1616
1819
 
1617
- $(function () {
1618
- $('body').on('click.tab.data-api', '[data-toggle="tab"], [data-toggle="pill"]', function (e) {
1619
- e.preventDefault()
1620
- $(this).tab('show')
1621
- })
1820
+ $(document).on('click.tab.data-api', '[data-toggle="tab"], [data-toggle="pill"]', function (e) {
1821
+ e.preventDefault()
1822
+ $(this).tab('show')
1622
1823
  })
1623
1824
 
1624
1825
  }(window.jQuery);/* =============================================================
1625
- * bootstrap-typeahead.js v2.1.1
1826
+ * bootstrap-typeahead.js v2.3.1
1626
1827
  * http://twitter.github.com/bootstrap/javascript.html#typeahead
1627
1828
  * =============================================================
1628
1829
  * Copyright 2012 Twitter, Inc.
@@ -1656,8 +1857,8 @@
1656
1857
  this.sorter = this.options.sorter || this.sorter
1657
1858
  this.highlighter = this.options.highlighter || this.highlighter
1658
1859
  this.updater = this.options.updater || this.updater
1659
- this.$menu = $(this.options.menu).appendTo('body')
1660
1860
  this.source = this.options.source
1861
+ this.$menu = $(this.options.menu)
1661
1862
  this.shown = false
1662
1863
  this.listen()
1663
1864
  }
@@ -1679,16 +1880,18 @@
1679
1880
  }
1680
1881
 
1681
1882
  , show: function () {
1682
- var pos = $.extend({}, this.$element.offset(), {
1883
+ var pos = $.extend({}, this.$element.position(), {
1683
1884
  height: this.$element[0].offsetHeight
1684
1885
  })
1685
1886
 
1686
- this.$menu.css({
1687
- top: pos.top + pos.height
1688
- , left: pos.left
1689
- })
1887
+ this.$menu
1888
+ .insertAfter(this.$element)
1889
+ .css({
1890
+ top: pos.top + pos.height
1891
+ , left: pos.left
1892
+ })
1893
+ .show()
1690
1894
 
1691
- this.$menu.show()
1692
1895
  this.shown = true
1693
1896
  return this
1694
1897
  }
@@ -1793,17 +1996,28 @@
1793
1996
 
1794
1997
  , listen: function () {
1795
1998
  this.$element
1999
+ .on('focus', $.proxy(this.focus, this))
1796
2000
  .on('blur', $.proxy(this.blur, this))
1797
2001
  .on('keypress', $.proxy(this.keypress, this))
1798
2002
  .on('keyup', $.proxy(this.keyup, this))
1799
2003
 
1800
- if ($.browser.chrome || $.browser.webkit || $.browser.msie) {
2004
+ if (this.eventSupported('keydown')) {
1801
2005
  this.$element.on('keydown', $.proxy(this.keydown, this))
1802
2006
  }
1803
2007
 
1804
2008
  this.$menu
1805
2009
  .on('click', $.proxy(this.click, this))
1806
2010
  .on('mouseenter', 'li', $.proxy(this.mouseenter, this))
2011
+ .on('mouseleave', 'li', $.proxy(this.mouseleave, this))
2012
+ }
2013
+
2014
+ , eventSupported: function(eventName) {
2015
+ var isSupported = eventName in this.$element
2016
+ if (!isSupported) {
2017
+ this.$element.setAttribute(eventName, 'return;')
2018
+ isSupported = typeof this.$element[eventName] === 'function'
2019
+ }
2020
+ return isSupported
1807
2021
  }
1808
2022
 
1809
2023
  , move: function (e) {
@@ -1831,7 +2045,7 @@
1831
2045
  }
1832
2046
 
1833
2047
  , keydown: function (e) {
1834
- this.suppressKeyPressRepeat = !~$.inArray(e.keyCode, [40,38,9,13,27])
2048
+ this.suppressKeyPressRepeat = ~$.inArray(e.keyCode, [40,38,9,13,27])
1835
2049
  this.move(e)
1836
2050
  }
1837
2051
 
@@ -1844,6 +2058,9 @@
1844
2058
  switch(e.keyCode) {
1845
2059
  case 40: // down arrow
1846
2060
  case 38: // up arrow
2061
+ case 16: // shift
2062
+ case 17: // ctrl
2063
+ case 18: // alt
1847
2064
  break
1848
2065
 
1849
2066
  case 9: // tab
@@ -1865,28 +2082,41 @@
1865
2082
  e.preventDefault()
1866
2083
  }
1867
2084
 
2085
+ , focus: function (e) {
2086
+ this.focused = true
2087
+ }
2088
+
1868
2089
  , blur: function (e) {
1869
- var that = this
1870
- setTimeout(function () { that.hide() }, 150)
2090
+ this.focused = false
2091
+ if (!this.mousedover && this.shown) this.hide()
1871
2092
  }
1872
2093
 
1873
2094
  , click: function (e) {
1874
2095
  e.stopPropagation()
1875
2096
  e.preventDefault()
1876
2097
  this.select()
2098
+ this.$element.focus()
1877
2099
  }
1878
2100
 
1879
2101
  , mouseenter: function (e) {
2102
+ this.mousedover = true
1880
2103
  this.$menu.find('.active').removeClass('active')
1881
2104
  $(e.currentTarget).addClass('active')
1882
2105
  }
1883
2106
 
2107
+ , mouseleave: function (e) {
2108
+ this.mousedover = false
2109
+ if (!this.focused && this.shown) this.hide()
2110
+ }
2111
+
1884
2112
  }
1885
2113
 
1886
2114
 
1887
2115
  /* TYPEAHEAD PLUGIN DEFINITION
1888
2116
  * =========================== */
1889
2117
 
2118
+ var old = $.fn.typeahead
2119
+
1890
2120
  $.fn.typeahead = function (option) {
1891
2121
  return this.each(function () {
1892
2122
  var $this = $(this)
@@ -1908,21 +2138,27 @@
1908
2138
  $.fn.typeahead.Constructor = Typeahead
1909
2139
 
1910
2140
 
1911
- /* TYPEAHEAD DATA-API
2141
+ /* TYPEAHEAD NO CONFLICT
2142
+ * =================== */
2143
+
2144
+ $.fn.typeahead.noConflict = function () {
2145
+ $.fn.typeahead = old
2146
+ return this
2147
+ }
2148
+
2149
+
2150
+ /* TYPEAHEAD DATA-API
1912
2151
  * ================== */
1913
2152
 
1914
- $(function () {
1915
- $('body').on('focus.typeahead.data-api', '[data-provide="typeahead"]', function (e) {
1916
- var $this = $(this)
1917
- if ($this.data('typeahead')) return
1918
- e.preventDefault()
1919
- $this.typeahead($this.data())
1920
- })
2153
+ $(document).on('focus.typeahead.data-api', '[data-provide="typeahead"]', function (e) {
2154
+ var $this = $(this)
2155
+ if ($this.data('typeahead')) return
2156
+ $this.typeahead($this.data())
1921
2157
  })
1922
2158
 
1923
2159
  }(window.jQuery);
1924
2160
  /* ==========================================================
1925
- * bootstrap-affix.js v2.1.1
2161
+ * bootstrap-affix.js v2.3.1
1926
2162
  * http://twitter.github.com/bootstrap/javascript.html#affix
1927
2163
  * ==========================================================
1928
2164
  * Copyright 2012 Twitter, Inc.
@@ -1951,7 +2187,9 @@
1951
2187
 
1952
2188
  var Affix = function (element, options) {
1953
2189
  this.options = $.extend({}, $.fn.affix.defaults, options)
1954
- this.$window = $(window).on('scroll.affix.data-api', $.proxy(this.checkPosition, this))
2190
+ this.$window = $(window)
2191
+ .on('scroll.affix.data-api', $.proxy(this.checkPosition, this))
2192
+ .on('click.affix.data-api', $.proxy(function () { setTimeout($.proxy(this.checkPosition, this), 1) }, this))
1955
2193
  this.$element = $(element)
1956
2194
  this.checkPosition()
1957
2195
  }
@@ -1989,6 +2227,8 @@
1989
2227
  /* AFFIX PLUGIN DEFINITION
1990
2228
  * ======================= */
1991
2229
 
2230
+ var old = $.fn.affix
2231
+
1992
2232
  $.fn.affix = function (option) {
1993
2233
  return this.each(function () {
1994
2234
  var $this = $(this)
@@ -2006,6 +2246,15 @@
2006
2246
  }
2007
2247
 
2008
2248
 
2249
+ /* AFFIX NO CONFLICT
2250
+ * ================= */
2251
+
2252
+ $.fn.affix.noConflict = function () {
2253
+ $.fn.affix = old
2254
+ return this
2255
+ }
2256
+
2257
+
2009
2258
  /* AFFIX DATA-API
2010
2259
  * ============== */
2011
2260