omf_web 0.9.7 → 0.9.8

Sign up to get free protection for your applications and to get access to all the features.
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