bootstrap.js 56.9 KB
Newer Older
1
2
3
4
5
/**
* bootstrap.js v3.0.0 by @fat and @mdo
* Copyright 2013 Twitter Inc.
* http://www.apache.org/licenses/LICENSE-2.0
*/
6
7
if (!jQuery) { throw new Error("Bootstrap requires jQuery") }

8
/* ========================================================================
9
10
 * Bootstrap: transition.js v3.0.0
 * http://twbs.github.com/bootstrap/javascript.html#transitions
11
 * ========================================================================
12
 * Copyright 2013 Twitter, Inc.
13
14
15
16
17
18
19
20
21
22
23
24
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
25
 * ======================================================================== */
26
27


28
+function ($) { "use strict";
29

30
31
  // CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/)
  // ============================================================
32

33
34
  function transitionEnd() {
    var el = document.createElement('bootstrap')
35

36
37
38
39
40
    var transEndEventNames = {
      'WebkitTransition' : 'webkitTransitionEnd'
    , 'MozTransition'    : 'transitionend'
    , 'OTransition'      : 'oTransitionEnd otransitionend'
    , 'transition'       : 'transitionend'
fat's avatar
fat committed
41
    }
42

43
44
45
46
47
    for (var name in transEndEventNames) {
      if (el.style[name] !== undefined) {
        return { end: transEndEventNames[name] }
      }
    }
48
49
  }

50
51
52
  // http://blog.alexmaccaw.com/css-transitions
  $.fn.emulateTransitionEnd = function (duration) {
    var called = false, $el    = this
liuyl's avatar
liuyl committed
53
54
    $(this).one($.support.transition.end, function () { called = true })
    var callback = function () { if (!called) $($el).trigger($.support.transition.end) }
55
    setTimeout(callback, duration)
56
    return this
57
58
  }

59
60
  $(function () {
    $.support.transition = transitionEnd()
fat's avatar
fat committed
61
  })
62

Mark Otto's avatar
Mark Otto committed
63
}(window.jQuery);
64

65
/* ========================================================================
fat's avatar
fat committed
66
 * Bootstrap: alert.js v3.0.0
Chris Rebert's avatar
Chris Rebert committed
67
 * http://twbs.github.com/bootstrap/javascript.html#alerts
68
 * ========================================================================
fat's avatar
fat committed
69
 * Copyright 2013 Twitter, Inc.
70
71
72
73
74
75
76
77
78
79
80
81
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
82
 * ======================================================================== */
83
84


85
+function ($) { "use strict";
86

fat's avatar
fat committed
87
88
  // ALERT CLASS DEFINITION
  // ======================
89
90

  var dismiss = '[data-dismiss="alert"]'
fat's avatar
fat committed
91
92
93
  var Alert   = function (el) {
    $(el).on('click', dismiss, this.close)
  }
94
95

  Alert.prototype.close = function (e) {
fat's avatar
fat committed
96
97
    var $this    = $(this)
    var selector = $this.attr('data-target')
98
99
100

    if (!selector) {
      selector = $this.attr('href')
fat's avatar
fat committed
101
      selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
102
103
    }

fat's avatar
fat committed
104
    var $parent = $(selector)
105

fat's avatar
fat committed
106
    if (e) e.preventDefault()
107

fat's avatar
fat committed
108
109
110
    if (!$parent.length) {
      $parent = $this.hasClass('alert') ? $this : $this.parent()
    }
111

Mark Otto's avatar
Mark Otto committed
112
    $parent.trigger(e = $.Event('close.bs.alert'))
113
114
115
116
117
118

    if (e.isDefaultPrevented()) return

    $parent.removeClass('in')

    function removeElement() {
Mark Otto's avatar
Mark Otto committed
119
      $parent.trigger('closed.bs.alert').remove()
120
121
122
    }

    $.support.transition && $parent.hasClass('fade') ?
123
124
125
      $parent
        .one($.support.transition.end, removeElement)
        .emulateTransitionEnd(150) :
126
127
128
129
      removeElement()
  }


fat's avatar
fat committed
130
131
  // ALERT PLUGIN DEFINITION
  // =======================
132

133
134
  var old = $.fn.alert

135
136
137
  $.fn.alert = function (option) {
    return this.each(function () {
      var $this = $(this)
Mark Otto's avatar
Mark Otto committed
138
      var data  = $this.data('bs.alert')
fat's avatar
fat committed
139

Mark Otto's avatar
Mark Otto committed
140
      if (!data) $this.data('bs.alert', (data = new Alert(this)))
141
142
143
144
145
146
147
      if (typeof option == 'string') data[option].call($this)
    })
  }

  $.fn.alert.Constructor = Alert


fat's avatar
fat committed
148
149
  // ALERT NO CONFLICT
  // =================
150
151
152
153
154
155
156

  $.fn.alert.noConflict = function () {
    $.fn.alert = old
    return this
  }


fat's avatar
fat committed
157
  // ALERT DATA-API
fat's avatar
fat committed
158
  // ==============
159

Mark Otto's avatar
Mark Otto committed
160
  $(document).on('click.bs.alert.data-api', dismiss, Alert.prototype.close)
161

Mark Otto's avatar
Mark Otto committed
162
}(window.jQuery);
163

164
/* ========================================================================
fat's avatar
fat committed
165
 * Bootstrap: button.js v3.0.0
Chris Rebert's avatar
Chris Rebert committed
166
 * http://twbs.github.com/bootstrap/javascript.html#buttons
167
 * ========================================================================
fat's avatar
fat committed
168
 * Copyright 2013 Twitter, Inc.
169
170
171
172
173
174
175
176
177
178
179
180
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
181
 * ======================================================================== */
182
183


184
+function ($) { "use strict";
185

fat's avatar
fat committed
186
187
  // BUTTON PUBLIC CLASS DEFINITION
  // ==============================
188
189
190

  var Button = function (element, options) {
    this.$element = $(element)
fat's avatar
fat committed
191
192
193
194
195
    this.options  = $.extend({}, Button.DEFAULTS, options)
  }

  Button.DEFAULTS = {
    loadingText: 'loading...'
196
197
198
  }

  Button.prototype.setState = function (state) {
fat's avatar
fat committed
199
200
201
202
    var d    = 'disabled'
    var $el  = this.$element
    var val  = $el.is('input') ? 'val' : 'html'
    var data = $el.data()
203
204

    state = state + 'Text'
fat's avatar
fat committed
205
206

    if (!data.resetText) $el.data('resetText', $el[val]())
207
208
209
210
211
212
213

    $el[val](data[state] || this.options[state])

    // push to event loop to allow forms to submit
    setTimeout(function () {
      state == 'loadingText' ?
        $el.addClass(d).attr(d, d) :
fat's avatar
fat committed
214
        $el.removeClass(d).removeAttr(d);
215
216
217
218
    }, 0)
  }

  Button.prototype.toggle = function () {
219
    var $parent = this.$element.closest('[data-toggle="buttons"]')
220

221
    if ($parent.length) {
fat's avatar
fat committed
222
223
224
      var $input = this.$element.find('input')
        .prop('checked', !this.$element.hasClass('active'))
        .trigger('change')
225
      if ($input.prop('type') === 'radio') $parent.find('.active').removeClass('active')
fat's avatar
fat committed
226
    }
227
228
229
230
231

    this.$element.toggleClass('active')
  }


fat's avatar
fat committed
232
233
  // BUTTON PLUGIN DEFINITION
  // ========================
234

235
236
  var old = $.fn.button

237
238
  $.fn.button = function (option) {
    return this.each(function () {
fat's avatar
fat committed
239
      var $this   = $(this)
fat's avatar
fat committed
240
      var data    = $this.data('bs.button')
fat's avatar
fat committed
241
242
      var options = typeof option == 'object' && option

Mark Otto's avatar
Mark Otto committed
243
      if (!data) $this.data('bs.button', (data = new Button(this, options)))
fat's avatar
fat committed
244

245
246
247
248
249
250
251
252
      if (option == 'toggle') data.toggle()
      else if (option) data.setState(option)
    })
  }

  $.fn.button.Constructor = Button


fat's avatar
fat committed
253
254
  // BUTTON NO CONFLICT
  // ==================
255
256
257
258
259
260
261

  $.fn.button.noConflict = function () {
    $.fn.button = old
    return this
  }


fat's avatar
fat committed
262
263
  // BUTTON DATA-API
  // ===============
264

Mark Otto's avatar
Mark Otto committed
265
  $(document).on('click.bs.button.data-api', '[data-toggle^=button]', function (e) {
266
267
268
    var $btn = $(e.target)
    if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn')
    $btn.button('toggle')
269
    e.preventDefault()
270
271
  })

Mark Otto's avatar
Mark Otto committed
272
}(window.jQuery);
273

274
/* ========================================================================
fat's avatar
fat committed
275
 * Bootstrap: carousel.js v3.0.0
Chris Rebert's avatar
Chris Rebert committed
276
 * http://twbs.github.com/bootstrap/javascript.html#carousel
277
 * ========================================================================
278
279
280
281
282
283
284
285
286
287
288
289
290
 * Copyright 2012 Twitter, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
291
 * ======================================================================== */
292
293


294
+function ($) { "use strict";
295

fat's avatar
fat committed
296
297
  // CAROUSEL CLASS DEFINITION
  // =========================
298
299

  var Carousel = function (element, options) {
fat's avatar
fat committed
300
    this.$element    = $(element)
fat's avatar
fat committed
301
    this.$indicators = this.$element.find('.carousel-indicators')
fat's avatar
fat committed
302
303
304
305
306
307
308
    this.options     = options
    this.paused      =
    this.sliding     =
    this.interval    =
    this.$active     =
    this.$items      = null

309
310
311
312
313
    this.options.pause == 'hover' && this.$element
      .on('mouseenter', $.proxy(this.pause, this))
      .on('mouseleave', $.proxy(this.cycle, this))
  }

fat's avatar
fat committed
314
315
316
  Carousel.DEFAULTS = {
    interval: 5000
  , pause: 'hover'
Jacob Thornton's avatar
Jacob Thornton committed
317
  , wrap: true
fat's avatar
fat committed
318
  }
319

fat's avatar
fat committed
320
321
  Carousel.prototype.cycle =  function (e) {
    e || (this.paused = false)
322

fat's avatar
fat committed
323
    this.interval && clearInterval(this.interval)
fat's avatar
fat committed
324

fat's avatar
fat committed
325
326
327
    this.options.interval
      && !this.paused
      && (this.interval = setInterval($.proxy(this.next, this), this.options.interval))
328

fat's avatar
fat committed
329
330
    return this
  }
331

fat's avatar
fat committed
332
333
334
  Carousel.prototype.getActiveIndex = function () {
    this.$active = this.$element.find('.item.active')
    this.$items  = this.$active.parent().children()
335

fat's avatar
fat committed
336
337
    return this.$items.index(this.$active)
  }
338

fat's avatar
fat committed
339
340
341
  Carousel.prototype.to = function (pos) {
    var that        = this
    var activeIndex = this.getActiveIndex()
342

fat's avatar
fat committed
343
    if (pos > (this.$items.length - 1) || pos < 0) return
344

fat's avatar
fat committed
345
346
347
348
349
    if (this.sliding)       return this.$element.one('slid', function () { that.to(pos) })
    if (activeIndex == pos) return this.pause().cycle()

    return this.slide(pos > activeIndex ? 'next' : 'prev', $(this.$items[pos]))
  }
350

fat's avatar
fat committed
351
352
353
354
355
356
  Carousel.prototype.pause = function (e) {
    e || (this.paused = true)

    if (this.$element.find('.next, .prev').length && $.support.transition.end) {
      this.$element.trigger($.support.transition.end)
      this.cycle(true)
357
358
    }

fat's avatar
fat committed
359
    this.interval = clearInterval(this.interval)
360

fat's avatar
fat committed
361
362
    return this
  }
363

fat's avatar
fat committed
364
365
366
367
  Carousel.prototype.next = function () {
    if (this.sliding) return
    return this.slide('next')
  }
368

fat's avatar
fat committed
369
370
371
372
  Carousel.prototype.prev = function () {
    if (this.sliding) return
    return this.slide('prev')
  }
373

fat's avatar
fat committed
374
375
376
377
378
379
380
  Carousel.prototype.slide = function (type, next) {
    var $active   = this.$element.find('.item.active')
    var $next     = next || $active[type]()
    var isCycling = this.interval
    var direction = type == 'next' ? 'left' : 'right'
    var fallback  = type == 'next' ? 'first' : 'last'
    var that      = this
Jacob Thornton's avatar
Jacob Thornton committed
381

Jacob Thornton's avatar
Jacob Thornton committed
382
383
384
385
386
    if (!$next.length) {
      if (!this.options.wrap) return
      $next = this.$element.find('.item')[fallback]()
    }

fat's avatar
fat committed
387
    this.sliding = true
388

fat's avatar
fat committed
389
    isCycling && this.pause()
fat's avatar
fat committed
390

Mark Otto's avatar
Mark Otto committed
391
    var e = $.Event('slide.bs.carousel', { relatedTarget: $next[0], direction: direction })
392

fat's avatar
fat committed
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
    if ($next.hasClass('active')) return

    if (this.$indicators.length) {
      this.$indicators.find('.active').removeClass('active')
      this.$element.one('slid', function () {
        var $nextIndicator = $(that.$indicators.children()[that.getActiveIndex()])
        $nextIndicator && $nextIndicator.addClass('active')
      })
    }

    if ($.support.transition && this.$element.hasClass('slide')) {
      this.$element.trigger(e)
      if (e.isDefaultPrevented()) return
      $next.addClass(type)
      $next[0].offsetWidth // force reflow
      $active.addClass(direction)
      $next.addClass(direction)
Jacob Thornton's avatar
Jacob Thornton committed
410
      $active
411
412
413
414
415
416
417
        .one($.support.transition.end, function () {
          $next.removeClass([type, direction].join(' ')).addClass('active')
          $active.removeClass(['active', direction].join(' '))
          that.sliding = false
          setTimeout(function () { that.$element.trigger('slid') }, 0)
        })
        .emulateTransitionEnd(600)
fat's avatar
fat committed
418
419
420
421
422
423
424
    } else {
      this.$element.trigger(e)
      if (e.isDefaultPrevented()) return
      $active.removeClass('active')
      $next.addClass('active')
      this.sliding = false
      this.$element.trigger('slid')
425
426
    }

fat's avatar
fat committed
427
428
429
    isCycling && this.cycle()

    return this
430
431
432
  }


fat's avatar
fat committed
433
434
  // CAROUSEL PLUGIN DEFINITION
  // ==========================
435

436
437
  var old = $.fn.carousel

438
439
  $.fn.carousel = function (option) {
    return this.each(function () {
fat's avatar
fat committed
440
      var $this   = $(this)
Mark Otto's avatar
Mark Otto committed
441
      var data    = $this.data('bs.carousel')
Jacob Thornton's avatar
Jacob Thornton committed
442
      var options = $.extend({}, Carousel.DEFAULTS, $this.data(), typeof option == 'object' && option)
fat's avatar
fat committed
443
444
      var action  = typeof option == 'string' ? option : options.slide

Mark Otto's avatar
Mark Otto committed
445
      if (!data) $this.data('bs.carousel', (data = new Carousel(this, options)))
446
      if (typeof option == 'number') data.to(option)
Jacob Thornton's avatar
Jacob Thornton committed
447
      else if (action) data[action]()
Mark Otto's avatar
Mark Otto committed
448
      else if (options.interval) data.pause().cycle()
449
450
451
452
453
454
    })
  }

  $.fn.carousel.Constructor = Carousel


fat's avatar
fat committed
455
456
  // CAROUSEL NO CONFLICT
  // ====================
457
458
459
460
461
462

  $.fn.carousel.noConflict = function () {
    $.fn.carousel = old
    return this
  }

fat's avatar
fat committed
463

fat's avatar
fat committed
464
465
  // CAROUSEL DATA-API
  // =================
466

467
  $(document).on('click.bs.carousel.data-api', '[data-slide], [data-slide-to]', function (e) {
fat's avatar
fat committed
468
    var $this   = $(this), href
fat's avatar
fat committed
469
470
    var $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7
    var options = $.extend({}, $target.data(), $this.data())
fat's avatar
fat committed
471
472
    var slideIndex = $this.attr('data-slide-to')
    if (slideIndex) options.interval = false
473

474
    $target.carousel(options)
475
476

    if (slideIndex = $this.attr('data-slide-to')) {
fat's avatar
fat committed
477
      $target.data('bs.carousel').to(slideIndex)
478
479
    }

480
    e.preventDefault()
481
482
  })

fat's avatar
fat committed
483
484
485
486
487
488
489
  $(window).on('load', function () {
    $('[data-ride="carousel"]').each(function () {
      var $carousel = $(this)
      $carousel.carousel($carousel.data())
    })
  })

Mark Otto's avatar
Mark Otto committed
490
}(window.jQuery);
491

492
/* ========================================================================
fat's avatar
fat committed
493
 * Bootstrap: collapse.js v3.0.0
Chris Rebert's avatar
Chris Rebert committed
494
 * http://twbs.github.com/bootstrap/javascript.html#collapse
495
 * ========================================================================
496
497
498
499
500
501
502
503
504
505
506
507
508
 * Copyright 2012 Twitter, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
509
 * ======================================================================== */
510
511


512
+function ($) { "use strict";
513

514
515
  // COLLAPSE PUBLIC CLASS DEFINITION
  // ================================
516
517

  var Collapse = function (element, options) {
518
519
520
    this.$element      = $(element)
    this.options       = $.extend({}, Collapse.DEFAULTS, options)
    this.transitioning = null
521

522
523
524
525
526
527
528
    if (this.options.parent) this.$parent = $(this.options.parent)
    if (this.options.toggle) this.toggle()
  }

  Collapse.DEFAULTS = {
    toggle: true
  }
529

530
531
532
  Collapse.prototype.dimension = function () {
    var hasWidth = this.$element.hasClass('width')
    return hasWidth ? 'width' : 'height'
533
534
  }

535
536
  Collapse.prototype.show = function () {
    if (this.transitioning || this.$element.hasClass('in')) return
537

fat's avatar
fat committed
538
539
540
541
    var startEvent = $.Event('show.bs.collapse')
    this.$element.trigger(startEvent)
    if (startEvent.isDefaultPrevented()) return

Mark Otto's avatar
Mark Otto committed
542
    var actives = this.$parent && this.$parent.find('> .panel > .in')
543

544
    if (actives && actives.length) {
fat's avatar
fat committed
545
      var hasData = actives.data('bs.collapse')
546
547
      if (hasData && hasData.transitioning) return
      actives.collapse('hide')
fat's avatar
fat committed
548
      hasData || actives.data('bs.collapse', null)
549
550
    }

551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
    var dimension = this.dimension()

    this.$element
      .removeClass('collapse')
      .addClass('collapsing')
      [dimension](0)

    this.transitioning = 1

    var complete = function () {
      this.$element
        .removeClass('collapsing')
        .addClass('in')
        [dimension]('auto')
      this.transitioning = 0
      this.$element.trigger('shown.bs.collapse')
    }

    if (!$.support.transition) return complete.call(this)

    var scrollSize = $.camelCase(['scroll', dimension].join('-'))
572

573
574
575
576
    this.$element
      .one($.support.transition.end, $.proxy(complete, this))
      .emulateTransitionEnd(350)
      [dimension](this.$element[0][scrollSize])
577
  }
578

579
580
  Collapse.prototype.hide = function () {
    if (this.transitioning || !this.$element.hasClass('in')) return
fat's avatar
fat committed
581
582
583
584
585

    var startEvent = $.Event('hide.bs.collapse')
    this.$element.trigger(startEvent)
    if (startEvent.isDefaultPrevented()) return

586
    var dimension = this.dimension()
587

588
589
590
    this.$element
      [dimension](this.$element[dimension]())
      [0].offsetHeight
591

592
    this.$element
593
      .addClass('collapsing')
594
      .removeClass('collapse')
595
      .removeClass('in')
596

597
    this.transitioning = 1
598

599
    var complete = function () {
600
601
602
603
604
      this.transitioning = 0
      this.$element
        .trigger('hidden.bs.collapse')
        .removeClass('collapsing')
        .addClass('collapse')
605
606
    }

607
    if (!$.support.transition) return complete.call(this)
608

609
610
611
612
    this.$element
      [dimension](0)
      .one($.support.transition.end, $.proxy(complete, this))
      .emulateTransitionEnd(350)
613
  }
614

615
616
  Collapse.prototype.toggle = function () {
    this[this.$element.hasClass('in') ? 'hide' : 'show']()
617
618
619
  }


620
621
  // COLLAPSE PLUGIN DEFINITION
  // ==========================
622
623

  var old = $.fn.collapse
624
625
626

  $.fn.collapse = function (option) {
    return this.each(function () {
627
      var $this   = $(this)
fat's avatar
fat committed
628
      var data    = $this.data('bs.collapse')
629
630
      var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option)

fat's avatar
fat committed
631
      if (!data) $this.data('bs.collapse', (data = new Collapse(this, options)))
632
633
634
635
636
637
638
      if (typeof option == 'string') data[option]()
    })
  }

  $.fn.collapse.Constructor = Collapse


639
640
  // COLLAPSE NO CONFLICT
  // ====================
641

642
643
644
645
646
647
  $.fn.collapse.noConflict = function () {
    $.fn.collapse = old
    return this
  }


648
649
  // COLLAPSE DATA-API
  // =================
650

651
  $(document).on('click.bs.collapse.data-api', '[data-toggle=collapse]', function (e) {
652
653
    var $this   = $(this), href
    var target  = $this.attr('data-target')
654
655
        || e.preventDefault()
        || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7
656
657
658
659
    var $target = $(target)
    var data    = $target.data('bs.collapse')
    var option  = data ? 'toggle' : $this.data()
    var parent  = $this.attr('data-parent')
Mark Otto's avatar
Mark Otto committed
660
    var $parent = parent && $(parent)
661

fat's avatar
fat committed
662
    if (!data || !data.transitioning) {
663
      if ($parent) $parent.find('[data-toggle=collapse][data-parent="' + parent + '"]').not($this).addClass('collapsed')
664
      $this[$target.hasClass('in') ? 'addClass' : 'removeClass']('collapsed')
fat's avatar
fat committed
665
666
    }

667
    $target.collapse(option)
668
669
  })

Mark Otto's avatar
Mark Otto committed
670
}(window.jQuery);
671

672
/* ========================================================================
fat's avatar
fat committed
673
 * Bootstrap: dropdown.js v3.0.0
Chris Rebert's avatar
Chris Rebert committed
674
 * http://twbs.github.com/bootstrap/javascript.html#dropdowns
675
 * ========================================================================
676
677
678
679
680
681
682
683
684
685
686
687
688
 * Copyright 2012 Twitter, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
689
 * ======================================================================== */
690
691


692
+function ($) { "use strict";
693

694
695
  // DROPDOWN CLASS DEFINITION
  // =========================
696

697
698
699
  var backdrop = '.dropdown-backdrop'
  var toggle   = '[data-toggle=dropdown]'
  var Dropdown = function (element) {
700
    var $el = $(element).on('click.bs.dropdown', this.toggle)
701
  }
702

703
704
  Dropdown.prototype.toggle = function (e) {
    var $this = $(this)
705

706
    if ($this.is('.disabled, :disabled')) return
707

708
709
    var $parent  = getParent($this)
    var isActive = $parent.hasClass('open')
710

711
    clearMenus()
fat's avatar
fat committed
712

713
    if (!isActive) {
fat's avatar
fat committed
714
715
      if ('ontouchstart' in document.documentElement) {
        // if mobile we we use a backdrop because click events don't delegate
Jacob Thornton's avatar
Jacob Thornton committed
716
        $('<div class="dropdown-backdrop"/>').insertAfter($(this)).on('click', clearMenus)
fat's avatar
fat committed
717
      }
718
719
720
721
722
723
724
725

      $parent.trigger(e = $.Event('show.bs.dropdown'))

      if (e.isDefaultPrevented()) return

      $parent
        .toggleClass('open')
        .trigger('shown.bs.dropdown')
726
727
    }

728
    $this.focus()
729

730
731
    return false
  }
732

733
734
  Dropdown.prototype.keydown = function (e) {
    if (!/(38|40|27)/.test(e.keyCode)) return
735

736
    var $this = $(this)
737

738
739
    e.preventDefault()
    e.stopPropagation()
740

741
    if ($this.is('.disabled, :disabled')) return
742

743
744
    var $parent  = getParent($this)
    var isActive = $parent.hasClass('open')
745

746
747
748
749
    if (!isActive || (isActive && e.keyCode == 27)) {
      if (e.which == 27) $parent.find(toggle).focus()
      return $this.click()
    }
750

751
    var $items = $('[role=menu] li:not(.divider):visible a', $parent)
752

753
    if (!$items.length) return
754

755
    var index = $items.index($items.filter(':focus'))
756

757
758
759
    if (e.keyCode == 38 && index > 0)                 index--                        // up
    if (e.keyCode == 40 && index < $items.length - 1) index++                        // down
    if (!~index)                                      index=0
760

761
    $items.eq(index).focus()
762
763
  }

Mark Otto's avatar
Mark Otto committed
764
  function clearMenus() {
765
    $(backdrop).remove()
766
    $(toggle).each(function (e) {
767
768
769
770
771
772
      var $parent = getParent($(this))
      if (!$parent.hasClass('open')) return
      $parent.trigger(e = $.Event('hide.bs.dropdown'))
      if (e.isDefaultPrevented()) return
      $parent.removeClass('open').trigger('hidden.bs.dropdown')
    })
773
774
775
776
777
778
779
  }

  function getParent($this) {
    var selector = $this.attr('data-target')

    if (!selector) {
      selector = $this.attr('href')
780
      selector = selector && /#/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
781
782
    }

783
    var $parent = selector && $(selector)
784

785
    return $parent && $parent.length ? $parent : $this.parent()
786
787
788
  }


789
790
  // DROPDOWN PLUGIN DEFINITION
  // ==========================
791

792
793
  var old = $.fn.dropdown

794
795
796
  $.fn.dropdown = function (option) {
    return this.each(function () {
      var $this = $(this)
797
798
      var data  = $this.data('dropdown')

799
800
801
802
803
804
805
806
      if (!data) $this.data('dropdown', (data = new Dropdown(this)))
      if (typeof option == 'string') data[option].call($this)
    })
  }

  $.fn.dropdown.Constructor = Dropdown


807
808
  // DROPDOWN NO CONFLICT
  // ====================
809
810
811
812
813
814
815

  $.fn.dropdown.noConflict = function () {
    $.fn.dropdown = old
    return this
  }


816
817
818
  // APPLY TO STANDARD DROPDOWN ELEMENTS
  // ===================================

819
  $(document)
820
821
822
823
    .on('click.bs.dropdown.data-api', clearMenus)
    .on('click.bs.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() })
    .on('click.bs.dropdown.data-api'  , toggle, Dropdown.prototype.toggle)
    .on('keydown.bs.dropdown.data-api', toggle + ', [role=menu]' , Dropdown.prototype.keydown)
824

fat's avatar
fat committed
825
}(window.jQuery);
826

827
/* ========================================================================
fat's avatar
fat committed
828
 * Bootstrap: modal.js v3.0.0
Chris Rebert's avatar
Chris Rebert committed
829
 * http://twbs.github.com/bootstrap/javascript.html#modals
830
 * ========================================================================
831
832
833
834
835
836
837
838
839
840
841
842
843
 * Copyright 2012 Twitter, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
844
 * ======================================================================== */
845
846


847
+function ($) { "use strict";
848

fat's avatar
fat committed
849
850
  // MODAL CLASS DEFINITION
  // ======================
851

Jacob Thornton's avatar
Jacob Thornton committed
852
  var Modal = function (element, options) {
fat's avatar
fat committed
853
    this.options   = options
fat's avatar
fat committed
854
    this.$element  = $(element).on('click.dismiss.modal', '[data-dismiss="modal"]', $.proxy(this.hide, this))
fat's avatar
fat committed
855
856
    this.$backdrop =
    this.isShown   = null
857

Jacob Thornton's avatar
Jacob Thornton committed
858
    if (this.options.remote) this.$element.load(this.options.remote)
fat's avatar
fat committed
859
  }
860

fat's avatar
fat committed
861
862
863
864
865
  Modal.DEFAULTS = {
      backdrop: true
    , keyboard: true
    , show: true
  }
866

Jacob Thornton's avatar
Jacob Thornton committed
867
868
  Modal.prototype.toggle = function (_relatedTarget) {
    return this[!this.isShown ? 'show' : 'hide'](_relatedTarget)
fat's avatar
fat committed
869
  }
870

Jacob Thornton's avatar
Jacob Thornton committed
871
  Modal.prototype.show = function (_relatedTarget) {
fat's avatar
fat committed
872
    var that = this
Jacob Thornton's avatar
Jacob Thornton committed
873
    var e    = $.Event('show.bs.modal', { relatedTarget: _relatedTarget })
874

fat's avatar
fat committed
875
    this.$element.trigger(e)
876

fat's avatar
fat committed
877
    if (this.isShown || e.isDefaultPrevented()) return
878

fat's avatar
fat committed
879
    this.isShown = true
880

fat's avatar
fat committed
881
    this.escape()
882

fat's avatar
fat committed
883
884
    this.backdrop(function () {
      var transition = $.support.transition && that.$element.hasClass('fade')
885

fat's avatar
fat committed
886
      if (!that.$element.parent().length) {
Jacob Thornton's avatar
Jacob Thornton committed
887
        that.$element.appendTo(document.body) // don't move modals dom position
fat's avatar
fat committed
888
      }
889

fat's avatar
fat committed
890
      that.$element.show()
891

fat's avatar
fat committed
892
893
894
      if (transition) {
        that.$element[0].offsetWidth // force reflow
      }
895

fat's avatar
fat committed
896
897
898
      that.$element
        .addClass('in')
        .attr('aria-hidden', false)
899

fat's avatar
fat committed
900
      that.enforceFocus()
901

Jacob Thornton's avatar
Jacob Thornton committed
902
903
      var e = $.Event('shown.bs.modal', { relatedTarget: _relatedTarget })

fat's avatar
fat committed
904
      transition ?
905
906
        that.$element
          .one($.support.transition.end, function () {
Jacob Thornton's avatar
Jacob Thornton committed
907
            that.$element.focus().trigger(e)
908
909
          })
          .emulateTransitionEnd(300) :
Jacob Thornton's avatar
Jacob Thornton committed
910
        that.$element.focus().trigger(e)
fat's avatar
fat committed
911
912
    })
  }
913

fat's avatar
fat committed
914
  Modal.prototype.hide = function (e) {
fat's avatar
fat committed
915
    if (e) e.preventDefault()
916

Mark Otto's avatar
Mark Otto committed
917
    e = $.Event('hide.bs.modal')
918

fat's avatar
fat committed
919
    this.$element.trigger(e)
920

fat's avatar
fat committed
921
    if (!this.isShown || e.isDefaultPrevented()) return
922

fat's avatar
fat committed
923
    this.isShown = false
924

fat's avatar
fat committed
925
    this.escape()
926

Mark Otto's avatar
Mark Otto committed
927
    $(document).off('focusin.bs.modal')
928

fat's avatar
fat committed
929
930
931
    this.$element
      .removeClass('in')
      .attr('aria-hidden', true)
Jacob Thornton's avatar
Jacob Thornton committed
932
      .off('click.dismiss.modal')
933

fat's avatar
fat committed
934
    $.support.transition && this.$element.hasClass('fade') ?
935
936
937
      this.$element
        .one($.support.transition.end, $.proxy(this.hideModal, this))
        .emulateTransitionEnd(300) :
fat's avatar
fat committed
938
939
      this.hideModal()
  }
940

fat's avatar
fat committed
941
  Modal.prototype.enforceFocus = function () {
Jacob Thornton's avatar
Jacob Thornton committed
942
943
    $(document)
      .off('focusin.bs.modal') // guard against infinite focus loop
fat's avatar
fat committed
944
945
946
947
948
      .on('focusin.bs.modal', $.proxy(function (e) {
        if (this.$element[0] !== e.target && !this.$element.has(e.target).length) {
          this.$element.focus()
        }
      }, this))
fat's avatar
fat committed
949
  }
950

fat's avatar
fat committed
951
952
  Modal.prototype.escape = function () {
    if (this.isShown && this.options.keyboard) {
fat's avatar
fat committed
953
      this.$element.on('keyup.dismiss.bs.modal', $.proxy(function (e) {
fat's avatar
fat committed
954
        e.which == 27 && this.hide()
fat's avatar
fat committed
955
      }, this))
fat's avatar
fat committed
956
    } else if (!this.isShown) {
Mark Otto's avatar
Mark Otto committed
957
      this.$element.off('keyup.dismiss.bs.modal')
fat's avatar
fat committed
958
959
    }
  }
960

fat's avatar
fat committed
961
962
963
964
965
  Modal.prototype.hideModal = function () {
    var that = this
    this.$element.hide()
    this.backdrop(function () {
      that.removeBackdrop()
Mark Otto's avatar
Mark Otto committed
966
      that.$element.trigger('hidden.bs.modal')
fat's avatar
fat committed
967
968
    })
  }
969

fat's avatar
fat committed
970
971
972
973
  Modal.prototype.removeBackdrop = function () {
    this.$backdrop && this.$backdrop.remove()
    this.$backdrop = null
  }
974

fat's avatar
fat committed
975
976
977
  Modal.prototype.backdrop = function (callback) {
    var that    = this
    var animate = this.$element.hasClass('fade') ? 'fade' : ''
978

fat's avatar
fat committed
979
980
    if (this.isShown && this.options.backdrop) {
      var doAnimate = $.support.transition && animate
981

fat's avatar
fat committed
982
983
      this.$backdrop = $('<div class="modal-backdrop ' + animate + '" />')
        .appendTo(document.body)
984

Jacob Thornton's avatar
Jacob Thornton committed
985
      this.$element.on('click.dismiss.modal', $.proxy(function (e) {
fat's avatar
fat committed
986
987
988
989
990
        if (e.target !== e.currentTarget) return
        this.options.backdrop == 'static'
          ? this.$element[0].focus.call(this.$element[0])
          : this.hide.call(this)
      }, this))
991

fat's avatar
fat committed
992
      if (doAnimate) this.$backdrop[0].offsetWidth // force reflow
993

fat's avatar
fat committed
994
      this.$backdrop.addClass('in')
995

fat's avatar
fat committed
996
      if (!callback) return
997

fat's avatar
fat committed
998
      doAnimate ?
999
1000
1001
        this.$backdrop
          .one($.support.transition.end, callback)
          .emulateTransitionEnd(150) :
fat's avatar
fat committed
1002
        callback()
1003

fat's avatar
fat committed
1004
1005
    } else if (!this.isShown && this.$backdrop) {
      this.$backdrop.removeClass('in')
1006

fat's avatar
fat committed
1007
      $.support.transition && this.$element.hasClass('fade')?
1008
1009
1010
        this.$backdrop
          .one($.support.transition.end, callback)
          .emulateTransitionEnd(150) :
fat's avatar
fat committed
1011
        callback()
1012

fat's avatar
fat committed
1013
1014
1015
    } else if (callback) {
      callback()
    }
1016
1017
1018
  }


fat's avatar
fat committed
1019
1020
  // MODAL PLUGIN DEFINITION
  // =======================
1021

1022
1023
  var old = $.fn.modal

Jacob Thornton's avatar
Jacob Thornton committed
1024
  $.fn.modal = function (option, _relatedTarget) {
1025
    return this.each(function () {
fat's avatar
fat committed
1026
      var $this   = $(this)
Mark Otto's avatar
Mark Otto committed
1027
      var data    = $this.data('bs.modal')
fat's avatar
fat committed
1028
1029
      var options = $.extend({}, Modal.DEFAULTS, $this.data(), typeof option == 'object' && option)

Mark Otto's avatar
Mark Otto committed
1030
      if (!data) $this.data('bs.modal', (data = new Modal(this, options)))
Jacob Thornton's avatar
Jacob Thornton committed
1031
1032
      if (typeof option == 'string') data[option](_relatedTarget)
      else if (options.show) data.show(_relatedTarget)
1033
1034
1035
1036
1037
1038
    })
  }

  $.fn.modal.Constructor = Modal


fat's avatar
fat committed
1039
1040
  // MODAL NO CONFLICT
  // =================
1041
1042
1043
1044
1045
1046
1047

  $.fn.modal.noConflict = function () {
    $.fn.modal = old
    return this
  }


fat's avatar
fat committed
1048
1049
  // MODAL DATA-API
  // ==============
1050

Mark Otto's avatar
Mark Otto committed
1051
  $(document).on('click.bs.modal.data-api', '[data-toggle="modal"]', function (e) {
fat's avatar
fat committed
1052
1053
1054
    var $this   = $(this)
    var href    = $this.attr('href')
    var $target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, ''))) //strip for ie7
Jacob Thornton's avatar
Jacob Thornton committed
1055
    var option  = $target.data('modal') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data())
1056

1057
    e.preventDefault()
1058

1059
    $target
Jacob Thornton's avatar
Jacob Thornton committed
1060
      .modal(option, this)
1061
      .one('hide', function () {
1062
        $this.is(':visible') && $this.focus()
1063
      })
Jacob Thornton's avatar
Jacob Thornton committed
1064
  })
1065

Jacob Thornton's avatar
Jacob Thornton committed
1066
  $(document)
fat's avatar
fat committed
1067
    .on('show.bs.modal',  '.modal', function () { $(document.body).addClass('modal-open') })
Jacob Thornton's avatar
Jacob Thornton committed
1068
    .on('hidden.bs.modal', '.modal', function () { $(document.body).removeClass('modal-open') })
1069

1070
}(window.jQuery);
1071

1072
/* ========================================================================
1073
 * Bootstrap: tooltip.js v3.0.0
Jacob Thornton's avatar
Jacob Thornton committed
1074
 * http://twbs.github.com/bootstrap/javascript.html#tooltip
1075
 * Inspired by the original jQuery.tipsy by Jason Frame
1076
 * ========================================================================
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
 * Copyright 2012 Twitter, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
1090
 * ======================================================================== */
1091
1092


1093
+function ($) { "use strict";
1094

1095
  // TOOLTIP PUBLIC CLASS DEFINITION
fat's avatar
fat committed
1096
  // ===============================
1097

1098
1099
1100
1101
1102
1103
1104
  var Tooltip = function (element, options) {
    this.type       =
    this.options    =
    this.enabled    =
    this.timeout    =
    this.hoverState =
    this.$element   = null
1105

1106
1107
    this.init('tooltip', element, options)
  }
1108

1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
  Tooltip.DEFAULTS = {
    animation: true
  , placement: 'top'
  , selector: false
  , template: '<div class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>'
  , trigger: 'hover focus'
  , title: ''
  , delay: 0
  , html: false
  , container: false
  }
1120

1121
1122
1123
1124
1125
  Tooltip.prototype.init = function (type, element, options) {
    this.enabled  = true
    this.type     = type
    this.$element = $(element)
    this.options  = this.getOptions(options)
1126

1127
    var triggers = this.options.trigger.split(' ')
1128

1129
1130
    for (var i = triggers.length; i--;) {
      var trigger = triggers[i]
fat's avatar
fat committed
1131

1132
1133
1134
1135
1136
      if (trigger == 'click') {
        this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this))
      } else if (trigger != 'manual') {
        var eventIn  = trigger == 'hover' ? 'mouseenter' : 'focus'
        var eventOut = trigger == 'hover' ? 'mouseleave' : 'blur'
1137

Jacob Thornton's avatar
Jacob Thornton committed
1138
        this.$element.on(eventIn  + '.' + this.type, this.options.selector, $.proxy(this.enter, this))
1139
1140
1141
        this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this))
      }
    }
1142

1143
1144
1145
    this.options.selector ?
      (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) :
      this.fixTitle()
fat's avatar
fat committed
1146
  }
1147

1148
1149
  Tooltip.prototype.getDefaults = function () {
    return Tooltip.DEFAULTS
1150
  }
1151

1152
1153
  Tooltip.prototype.getOptions = function (options) {
    options = $.extend({}, this.getDefaults(), this.$element.data(), options)
1154

1155
1156
1157
1158
1159
1160
    if (options.delay && typeof options.delay == 'number') {
      options.delay = {
        show: options.delay
      , hide: options.delay
      }
    }
1161

1162
    return options
1163
  }
Jacob Thornton's avatar
Jacob Thornton committed
1164

Jacob Thornton's avatar
Jacob Thornton committed
1165
  Tooltip.prototype.getDelegateOptions = function () {
1166
    var options  = {}
Jacob Thornton's avatar
Jacob Thornton committed
1167
    var defaults = this.getDefaults()
1168

1169
1170
1171
    this._options && $.each(this._options, function (key, value) {
      if (defaults[key] != value) options[key] = value
    })
fat's avatar
rebuild    
fat committed
1172

Jacob Thornton's avatar
Jacob Thornton committed
1173
1174
1175
1176
    return options
  }

  Tooltip.prototype.enter = function (obj) {
1177
    var self = obj instanceof this.constructor ?
Jacob Thornton's avatar
Jacob Thornton committed
1178
      obj : $(obj.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type)
1179

1180
    clearTimeout(self.timeout)
1181

1182
    if (!self.options.delay || !self.options.delay.show) return self.show()
1183

1184
1185
1186
1187
    self.hoverState = 'in'
    self.timeout    = setTimeout(function () {
      if (self.hoverState == 'in') self.show()
    }, self.options.delay.show)
1188
  }
1189

1190
1191
  Tooltip.prototype.leave = function (obj) {
    var self = obj instanceof this.constructor ?
Jacob Thornton's avatar
Jacob Thornton committed
1192
      obj : $(obj.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type)
1193

1194
    clearTimeout(self.timeout)
fat's avatar
fat committed
1195

1196
    if (!self.options.delay || !self.options.delay.hide) return self.hide()
1197

1198
1199
1200
1201
    self.hoverState = 'out'
    self.timeout    = setTimeout(function () {
      if (self.hoverState == 'out') self.hide()
    }, self.options.delay.hide)
1202
  }
1203

1204
1205
  Tooltip.prototype.show = function () {
    var e = $.Event('show.bs.'+ this.type)
1206

1207
1208
    if (this.hasContent() && this.enabled) {
      this.$element.trigger(e)
1209

1210
      if (e.isDefaultPrevented()) return
1211

1212
      var $tip = this.tip()
fat's avatar
fat committed
1213

1214
      this.setContent()
fat's avatar
fat committed
1215

1216
      if (this.options.animation) $tip.addClass('fade')
fat's avatar
fat committed
1217

1218
1219
1220
      var placement = typeof this.options.placement == 'function' ?
        this.options.placement.call(this, $tip[0], this.$element[0]) :
        this.options.placement
1221

1222
1223
1224
      var autoToken = /\s?auto?\s?/i
      var autoPlace = autoToken.test(placement)
      if (autoPlace) placement = placement.replace(autoToken, '') || 'top'
1225

1226
1227
1228
1229
      $tip
        .detach()
        .css({ top: 0, left: 0, display: 'block' })
        .addClass(placement)
1230

1231
      this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element)
1232

1233
1234
1235
      var pos          = this.getPosition()
      var actualWidth  = $tip[0].offsetWidth
      var actualHeight = $tip[0].offsetHeight
fat's avatar
fat committed
1236

1237
1238
      if (autoPlace) {
        var $parent = this.$element.parent()
1239

1240
1241
1242
1243
1244
        var orgPlacement = placement
        var docScroll    = document.documentElement.scrollTop || document.body.scrollTop
        var parentWidth  = this.options.container == 'body' ? window.innerWidth  : $parent.outerWidth()
        var parentHeight = this.options.container == 'body' ? window.innerHeight : $parent.outerHeight()
        var parentLeft   = this.options.container == 'body' ? 0 : $parent.offset().left
fat's avatar
fat committed
1245

1246
1247
1248
1249
1250
        placement = placement == 'bottom' && pos.top   + pos.height  + actualHeight - docScroll > parentHeight  ? 'top'    :
                    placement == 'top'    && pos.top   - docScroll   - actualHeight < 0                         ? 'bottom' :
                    placement == 'right'  && pos.right + actualWidth > parentWidth                              ? 'left'   :
                    placement == 'left'   && pos.left  - actualWidth < parentLeft                               ? 'right'  :
                    placement
fat's avatar
fat committed
1251

1252
1253
1254
1255
1256
        $tip
          .removeClass(orgPlacement)
          .addClass(placement)
      }

1257
      var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight)
1258

fat's avatar
fat committed
1259
      this.applyPlacement(calculatedOffset, placement)
1260
      this.$element.trigger('shown.bs.' + this.type)
fat's avatar
fat committed
1261
    }
1262
  }
fat's avatar
fat committed
1263

1264
1265
1266
1267
1268
  Tooltip.prototype.applyPlacement = function(offset, placement) {
    var replace
    var $tip   = this.tip()
    var width  = $tip[0].offsetWidth
    var height = $tip[0].offsetHeight
fat's avatar
fat committed
1269

1270
    // manually read margins because getBoundingClientRect includes difference
fat's avatar
fat committed
1271
1272
1273
1274
1275
1276
1277
1278
1279
    var marginTop = parseInt($tip.css('margin-top'), 10)
    var marginLeft = parseInt($tip.css('margin-left'), 10)

    // we must check for NaN for ie 8/9
    if (isNaN(marginTop))  marginTop  = 0
    if (isNaN(marginLeft)) marginLeft = 0

    offset.top  = offset.top  + marginTop
    offset.left = offset.left + marginLeft
fat's avatar
fat committed
1280

1281
1282
1283
    $tip
      .offset(offset)
      .addClass('in')
fat's avatar
fat committed
1284

fat's avatar
fat committed
1285
    // check to see if placing tip in new offset caused the tip to resize itself
1286
1287
    var actualWidth  = $tip[0].offsetWidth
    var actualHeight = $tip[0].offsetHeight
fat's avatar
fat committed
1288

1289
1290
    if (placement == 'top' && actualHeight != height) {
      replace = true
fat's avatar
fat committed
1291
      offset.top = offset.top + height - actualHeight
fat's avatar
fat committed
1292
1293
    }

fat's avatar
fat committed
1294
    if (/bottom|top/.test(placement)) {
1295
      var delta = 0
1296

fat's avatar
fat committed
1297
      if (offset.left < 0) {
1298
1299
        delta       = offset.left * -2
        offset.left = 0
fat's avatar
fat committed
1300

1301
        $tip.offset(offset)
1302

1303
1304
1305
        actualWidth  = $tip[0].offsetWidth
        actualHeight = $tip[0].offsetHeight
      }
1306

1307
1308
1309
1310
      this.replaceArrow(delta - width + actualWidth, actualWidth, 'left')
    } else {
      this.replaceArrow(actualHeight - height, actualHeight, 'top')
    }
1311

1312
    if (replace) $tip.offset(offset)
1313
  }
1314

1315
1316
  Tooltip.prototype.replaceArrow = function(delta, dimension, position) {
    this.arrow().css(position, delta ? (50 * (1 - delta / dimension) + "%") : '')
fat's avatar
fat committed
1317
  }
1318

1319
1320
1321
  Tooltip.prototype.setContent = function () {
    var $tip  = this.tip()
    var title = this.getTitle()
1322

1323
1324
1325
    $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title)
    $tip.removeClass('fade in top bottom left right')
  }
1326

1327
1328
1329
1330
  Tooltip.prototype.hide = function () {
    var that = this
    var $tip = this.tip()
    var e    = $.Event('hide.bs.' + this.type)
1331

Jacob Thornton's avatar
Jacob Thornton committed
1332
1333
    function complete() { $tip.detach() }

1334
    this.$element.trigger(e)
1335

1336
    if (e.isDefaultPrevented()) return
1337

1338
    $tip.removeClass('in')
1339

1340
1341
    $.support.transition && this.$tip.hasClass('fade') ?
      $tip
Jacob Thornton's avatar
Jacob Thornton committed
1342
        .one($.support.transition.end, complete)
1343
        .emulateTransitionEnd(150) :
Jacob Thornton's avatar
Jacob Thornton committed
1344
      complete()
1345

1346
    this.$element.trigger('hidden.bs.' + this.type)
1347

1348
    return this
1349
1350
  }

1351
1352
1353
1354
  Tooltip.prototype.fixTitle = function () {
    var $e = this.$element
    if ($e.attr('title') || typeof($e.attr('data-original-title')) != 'string') {
      $e.attr('data-original-title', $e.attr('title') || '').attr('title', '')
1355
    }
1356
  }
1357

1358
1359
1360
  Tooltip.prototype.hasContent = function () {
    return this.getTitle()
  }
1361

1362
1363
1364
1365
1366
1367
1368
  Tooltip.prototype.getPosition = function () {
    var el = this.$element[0]
    return $.extend({}, (typeof el.getBoundingClientRect == 'function') ? el.getBoundingClientRect() : {
      width: el.offsetWidth
    , height: el.offsetHeight
    }, this.$element.offset())
  }
1369

1370
  Tooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight) {
fat's avatar
fat committed
1371
1372
1373
1374
1375
1376
    return placement == 'bottom' ? { top: pos.top + pos.height,   left: pos.left + pos.width / 2 - actualWidth / 2  } :
           placement == 'top'    ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2  } :
           placement == 'left'   ? { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth } :
        /* placement == 'right' */ { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width   }
  }

1377
1378
1379
1380
  Tooltip.prototype.getTitle = function () {
    var title
    var $e = this.$element
    var o  = this.options
1381

1382
1383
    title = $e.attr('data-original-title')
      || (typeof o.title == 'function' ? o.title.call($e[0]) :  o.title)
1384

1385
    return title
1386
  }
1387

1388
1389
1390
  Tooltip.prototype.tip = function () {
    return this.$tip = this.$tip || $(this.options.template)
  }
1391

Mark Otto's avatar
Mark Otto committed
1392
  Tooltip.prototype.arrow = function () {
fat's avatar
fat committed
1393
    return this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow')
1394
  }
1395

1396
1397
1398
1399
1400
1401
1402
  Tooltip.prototype.validate = function () {
    if (!this.$element[0].parentNode) {
      this.hide()
      this.$element = null
      this.options  = null
    }
  }
1403

1404
1405
1406
  Tooltip.prototype.enable = function () {
    this.enabled = true
  }
1407

1408
1409
1410
  Tooltip.prototype.disable = function () {
    this.enabled = false
  }
1411

1412
1413
1414
  Tooltip.prototype.toggleEnabled = function () {
    this.enabled = !this.enabled
  }
Mark Otto's avatar
Mark Otto committed
1415

1416
  Tooltip.prototype.toggle = function (e) {
Jacob Thornton's avatar
Jacob Thornton committed
1417
    var self = e ? $(e.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type) : this
1418
1419
    self.tip().hasClass('in') ? self.leave(self) : self.enter(self)
  }
1420

1421
1422
  Tooltip.prototype.destroy = function () {
    this.hide().$element.off('.' + this.type).removeData('bs.' + this.type)
fat's avatar
fat committed
1423
  }
1424
1425


1426
1427
  // TOOLTIP PLUGIN DEFINITION
  // =========================
1428

1429
  var old = $.fn.tooltip
1430

1431
  $.fn.tooltip = function (option) {
1432
    return this.each(function () {
1433
1434
1435
      var $this   = $(this)
      var data    = $this.data('bs.tooltip')
      var options = typeof option == 'object' && option
fat's avatar
fat committed
1436

1437
      if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options)))
1438
1439
1440
1441
      if (typeof option == 'string') data[option]()
    })
  }

1442
  $.fn.tooltip.Constructor = Tooltip
1443

1444

1445
1446
  // TOOLTIP NO CONFLICT
  // ===================
1447

1448
1449
  $.fn.tooltip.noConflict = function () {
    $.fn.tooltip = old
1450
1451
1452
    return this
  }

Mark Otto's avatar
Mark Otto committed
1453
}(window.jQuery);
1454

1455
/* ========================================================================
1456
1457
 * Bootstrap: popover.js v3.0.0
 * http://twbs.github.com/bootstrap/javascript.html#popovers
1458
 * ========================================================================
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
 * Copyright 2012 Twitter, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
1472
 * ======================================================================== */
1473
1474


1475
+function ($) { "use strict";
1476

1477
  // POPOVER PUBLIC CLASS DEFINITION
1478
  // ===============================
fat's avatar
fat committed
1479

1480
1481
  var Popover = function (element, options) {
    this.init('popover', element, options)
1482
1483
  }

fat's avatar
fat committed
1484
1485
  if (!$.fn.tooltip) throw new Error('Popover requires tooltip.js')

1486
1487
1488
1489
1490
1491
  Popover.DEFAULTS = $.extend({} , $.fn.tooltip.Constructor.DEFAULTS, {
    placement: 'right'
  , trigger: 'click'
  , content: ''
  , template: '<div class="popover"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'
  })
1492

fat's avatar
fat committed
1493

1494
1495
  // NOTE: POPOVER EXTENDS tooltip.js
  // ================================
fat's avatar
fat committed
1496

1497
  Popover.prototype = $.extend({}, $.fn.tooltip.Constructor.prototype)
1498

1499
  Popover.prototype.constructor = Popover
fat's avatar
fat committed
1500

1501
1502
1503
  Popover.prototype.getDefaults = function () {
    return Popover.DEFAULTS
  }
1504

1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
  Popover.prototype.setContent = function () {
    var $tip    = this.tip()
    var title   = this.getTitle()
    var content = this.getContent()

    $tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title)
    $tip.find('.popover-content')[this.options.html ? 'html' : 'text'](content)

    $tip.removeClass('fade top bottom left right in')

1515
1516
    // IE8 doesn't accept hiding via the `:empty` pseudo selector, we have to do
    // this manually by checking the contents.
Jacob Thornton's avatar
Jacob Thornton committed
1517
    if (!$tip.find('.popover-title').html()) $tip.find('.popover-title').hide()
1518
1519
  }

1520
1521
  Popover.prototype.hasContent = function () {
    return this.getTitle() || this.getContent()
1522
1523
  }

1524
1525
1526
  Popover.prototype.getContent = function () {
    var $e = this.$element
    var o  = this.options
1527

1528
1529
1530
1531
1532
    return $e.attr('data-content')
      || (typeof o.content == 'function' ?
            o.content.call($e[0]) :
            o.content)
  }
1533

Mark Otto's avatar
Mark Otto committed
1534
  Popover.prototype.arrow = function () {
fat's avatar
fat committed
1535
1536
1537
    return this.$arrow = this.$arrow || this.tip().find('.arrow')
  }

1538
1539
1540
  Popover.prototype.tip = function () {
    if (!this.$tip) this.$tip = $(this.options.template)
    return this.$tip
fat's avatar
fat committed
1541
  }
1542

1543

1544
1545
  // POPOVER PLUGIN DEFINITION
  // =========================
1546

1547
  var old = $.fn.popover
1548

1549
1550
1551
1552
1553
  $.fn.popover = function (option) {
    return this.each(function () {
      var $this   = $(this)
      var data    = $this.data('bs.popover')
      var options = typeof option == 'object' && option
1554

1555
1556
1557
      if (!data) $this.data('bs.popover', (data = new Popover(this, options)))
      if (typeof option == 'string') data[option]()
    })
1558
1559
  }

1560
  $.fn.popover.Constructor = Popover
fat's avatar
fat committed
1561

1562

1563
1564
  // POPOVER NO CONFLICT
  // ===================
1565

1566
1567
1568
1569
  $.fn.popover.noConflict = function () {
    $.fn.popover = old
    return this
  }
1570

1571
}(window.jQuery);
1572

1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
/* ========================================================================
 * Bootstrap: scrollspy.js v3.0.0
 * http://twbs.github.com/bootstrap/javascript.html#scrollspy
 * ========================================================================
 * Copyright 2012 Twitter, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * ======================================================================== */
1591
1592


1593
+function ($) { "use strict";
1594

1595
1596
  // SCROLLSPY CLASS DEFINITION
  // ==========================
1597

1598
1599
1600
  function ScrollSpy(element, options) {
    var href
    var process  = $.proxy(this.process, this)
1601

fat's avatar
fat committed
1602
    this.$element       = $(element).is('body') ? $(window) : $(element)
1603
    this.$body          = $('body')
fat's avatar
fat committed
1604
    this.$scrollElement = this.$element.on('scroll.bs.scroll-spy.data-api', process)
1605
1606
1607
1608
1609
1610
1611
    this.options        = $.extend({}, ScrollSpy.DEFAULTS, options)
    this.selector       = (this.options.target
      || ((href = $(element).attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7
      || '') + ' .nav li > a'
    this.offsets        = $([])
    this.targets        = $([])
    this.activeTarget   = null
1612

1613
1614
1615
    this.refresh()
    this.process()
  }
1616

1617
1618
1619
  ScrollSpy.DEFAULTS = {
    offset: 10
  }
1620

1621
  ScrollSpy.prototype.refresh = function () {
fat's avatar
fat committed
1622
1623
    var offsetMethod = this.$element[0] == window ? 'offset' : 'position'

1624
1625
    this.offsets = $([])
    this.targets = $([])
1626

1627
1628
1629
1630
1631
1632
1633
    var self     = this
    var $targets = this.$body
      .find(this.selector)
      .map(function () {
        var $el   = $(this)
        var href  = $el.data('target') || $el.attr('href')
        var $href = /^#\w/.test(href) && $(href)
1634

1635
1636
        return ($href
          && $href.length
fat's avatar
fat committed
1637
          && [[ $href[offsetMethod]().top + (!$.isWindow(self.$scrollElement.get(0)) && self.$scrollElement.scrollTop()), href ]]) || null
1638
1639
1640
1641
1642
1643
1644
      })
      .sort(function (a, b) { return a[0] - b[0] })
      .each(function () {
        self.offsets.push(this[0])
        self.targets.push(this[1])
      })
  }
1645

1646
1647
1648
1649
1650
1651
1652
1653
  ScrollSpy.prototype.process = function () {
    var scrollTop    = this.$scrollElement.scrollTop() + this.options.offset
    var scrollHeight = this.$scrollElement[0].scrollHeight || this.$body[0].scrollHeight
    var maxScroll    = scrollHeight - this.$scrollElement.height()
    var offsets      = this.offsets
    var targets      = this.targets
    var activeTarget = this.activeTarget
    var i
1654

1655
1656
1657
    if (scrollTop >= maxScroll) {
      return activeTarget != (i = targets.last()[0]) && this.activate(i)
    }
1658

1659
1660
1661
1662
1663
    for (i = offsets.length; i--;) {
      activeTarget != targets[i]
        && scrollTop >= offsets[i]
        && (!offsets[i + 1] || scrollTop <= offsets[i + 1])
        && this.activate( targets[i] )
1664
    }
1665
1666
  }

1667
1668
  ScrollSpy.prototype.activate = function (target) {
    this.activeTarget = target
1669

1670
1671
1672
    $(this.selector)
      .parents('.active')
      .removeClass('active')
1673

1674
1675
1676
    var selector = this.selector
      + '[data-target="' + target + '"],'
      + this.selector + '[href="' + target + '"]'
1677

1678
1679
1680
    var active = $(selector)
      .parents('li')
      .addClass('active')
1681

1682
1683
1684
1685
    if (active.parent('.dropdown-menu').length)  {
      active = active
        .closest('li.dropdown')
        .addClass('active')
1686
    }
1687

1688
1689
    active.trigger('activate')
  }
1690
1691


1692
1693
  // SCROLLSPY PLUGIN DEFINITION
  // ===========================
1694

1695
  var old = $.fn.scrollspy
1696

1697
1698
1699
1700
1701
  $.fn.scrollspy = function (option) {
    return this.each(function () {
      var $this   = $(this)
      var data    = $this.data('bs.scrollspy')
      var options = typeof option == 'object' && option
1702

1703
1704
1705
      if (!data) $this.data('bs.scrollspy', (data = new ScrollSpy(this, options)))
      if (typeof option == 'string') data[option]()
    })
1706
1707
  }

1708
  $.fn.scrollspy.Constructor = ScrollSpy
1709
1710


1711
1712
1713
1714
1715
1716
  // SCROLLSPY NO CONFLICT
  // =====================

  $.fn.scrollspy.noConflict = function () {
    $.fn.scrollspy = old
    return this
1717
1718
1719
  }


1720
1721
  // SCROLLSPY DATA-API
  // ==================
1722

1723
1724
1725
1726
1727
1728
  $(window).on('load', function () {
    $('[data-spy="scroll"]').each(function () {
      var $spy = $(this)
      $spy.scrollspy($spy.data())
    })
  })
1729

1730
}(window.jQuery);
1731

1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
/* ========================================================================
 * Bootstrap: tab.js v3.0.0
 * http://twbs.github.com/bootstrap/javascript.html#tabs
 * ========================================================================
 * Copyright 2012 Twitter, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * ======================================================================== */
1750

1751

1752
1753
1754
1755
1756
1757
1758
+function ($) { "use strict";

  // TAB CLASS DEFINITION
  // ====================

  var Tab = function (element) {
    this.element = $(element)
1759
  }
1760

1761
1762
1763
1764
1765
1766
1767
1768
  Tab.prototype.show = function () {
    var $this    = this.element
    var $ul      = $this.closest('ul:not(.dropdown-menu)')
    var selector = $this.attr('data-target')

    if (!selector) {
      selector = $this.attr('href')
      selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
1769
    }
1770

1771
    if ($this.parent('li').hasClass('active')) return
1772

1773
1774
1775
1776
    var previous = $ul.find('.active:last a')[0]
    var e        = $.Event('show.bs.tab', {
      relatedTarget: previous
    })
1777

1778
    $this.trigger(e)
1779

1780
    if (e.isDefaultPrevented()) return
1781

1782
    var $target = $(selector)
1783

1784
1785
1786
1787
1788
1789
1790
    this.activate($this.parent('li'), $ul)
    this.activate($target, $target.parent(), function () {
      $this.trigger({
        type: 'shown.bs.tab'
      , relatedTarget: previous
      })
    })
1791
  }
1792

1793
1794
1795
1796
1797
  Tab.prototype.activate = function (element, container, callback) {
    var $active    = container.find('> .active')
    var transition = callback
      && $.support.transition
      && $active.hasClass('fade')
1798

1799
1800
1801
1802
1803
    function next() {
      $active
        .removeClass('active')
        .find('> .dropdown-menu > .active')
        .removeClass('active')
1804

1805
      element.addClass('active')
1806

1807
1808
1809
1810
1811
1812
      if (transition) {
        element[0].offsetWidth // reflow for transition
        element.addClass('in')
      } else {
        element.removeClass('fade')
      }
1813

1814
1815
1816
      if (element.parent('.dropdown-menu')) {
        element.closest('li.dropdown').addClass('active')
      }
fat's avatar
fat committed
1817

1818
1819
      callback && callback()
    }
fat's avatar
fat committed
1820

1821
1822
1823
1824
1825
1826
1827
    transition ?
      $active
        .one($.support.transition.end, next)
        .emulateTransitionEnd(150) :
      next()

    $active.removeClass('in')
1828
1829
1830
  }


1831
1832
  // TAB PLUGIN DEFINITION
  // =====================
1833

1834
  var old = $.fn.tab
1835

1836
  $.fn.tab = function ( option ) {
1837
    return this.each(function () {
1838
1839
      var $this = $(this)
      var data  = $this.data('bs.tab')
fat's avatar
fat committed
1840

1841
      if (!data) $this.data('bs.tab', (data = new Tab(this)))
1842
1843
1844
1845
      if (typeof option == 'string') data[option]()
    })
  }

1846
  $.fn.tab.Constructor = Tab
1847
1848


1849
1850
  // TAB NO CONFLICT
  // ===============
1851

1852
1853
  $.fn.tab.noConflict = function () {
    $.fn.tab = old
1854
1855
1856
    return this
  }

1857
1858
1859
1860
1861
1862
1863
1864
1865

  // TAB DATA-API
  // ============

  $(document).on('click.bs.tab.data-api', '[data-toggle="tab"], [data-toggle="pill"]', function (e) {
    e.preventDefault()
    $(this).tab('show')
  })

1866
}(window.jQuery);
1867

1868
/* ========================================================================
1869
1870
 * Bootstrap: affix.js v3.0.0
 * http://twbs.github.com/bootstrap/javascript.html#affix
1871
 * ========================================================================
1872
 * Copyright 2012 Twitter, Inc.
Mark Otto's avatar
Mark Otto committed
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
1885
 * ======================================================================== */
Mark Otto's avatar
Mark Otto committed
1886
1887


1888
+function ($) { "use strict";
Mark Otto's avatar
Mark Otto committed
1889

1890
1891
  // AFFIX CLASS DEFINITION
  // ======================
Mark Otto's avatar
Mark Otto committed
1892

1893
1894
1895
1896
1897
  var Affix = function (element, options) {
    this.options = $.extend({}, Affix.DEFAULTS, options)
    this.$window = $(window)
      .on('scroll.bs.affix.data-api', $.proxy(this.checkPosition, this))
      .on('click.bs.affix.data-api',  $.proxy(this.checkPositionWithEventLoop, this))
fat's avatar
fat committed
1898

1899
1900
1901
    this.$element = $(element)
    this.affixed  =
    this.unpin    = null
fat's avatar
fat committed
1902

1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
    this.checkPosition()
  }

  Affix.RESET = 'affix affix-top affix-bottom'

  Affix.DEFAULTS = {
    offset: 0
  }

  Affix.prototype.checkPositionWithEventLoop = function () {
    setTimeout($.proxy(this.checkPosition, this), 1)
  }

  Affix.prototype.checkPosition = function () {
    if (!this.$element.is(':visible')) return

    var scrollHeight = $(document).height()
    var scrollTop    = this.$window.scrollTop()
    var position     = this.$element.offset()
    var offset       = this.options.offset
    var offsetTop    = offset.top
    var offsetBottom = offset.bottom

    if (typeof offset != 'object')         offsetBottom = offsetTop = offset
    if (typeof offsetTop == 'function')    offsetTop    = offset.top()
    if (typeof offsetBottom == 'function') offsetBottom = offset.bottom()

    var affix = this.unpin   != null && (scrollTop + this.unpin <= position.top) ? false :
                offsetBottom != null && (position.top + this.$element.height() >= scrollHeight - offsetBottom) ? 'bottom' :
                offsetTop    != null && (scrollTop <= offsetTop) ? 'top' : false

    if (this.affixed === affix) return
    if (this.unpin) this.$element.css('top', '')

    this.affixed = affix
    this.unpin   = affix == 'bottom' ? position.top - scrollTop : null

    this.$element.removeClass(Affix.RESET).addClass('affix' + (affix ? '-' + affix : ''))

    if (affix == 'bottom') {
      this.$element.offset({ top: document.body.offsetHeight - offsetBottom - this.$element.height() })
1944
    }
Mark Otto's avatar
Mark Otto committed
1945
1946
  }

1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961

  // AFFIX PLUGIN DEFINITION
  // =======================

  var old = $.fn.affix

  $.fn.affix = function (option) {
    return this.each(function () {
      var $this   = $(this)
      var data    = $this.data('bs.affix')
      var options = typeof option == 'object' && option

      if (!data) $this.data('bs.affix', (data = new Affix(this, options)))
      if (typeof option == 'string') data[option]()
    })
1962
1963
  }

1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
  $.fn.affix.Constructor = Affix


  // AFFIX NO CONFLICT
  // =================

  $.fn.affix.noConflict = function () {
    $.fn.affix = old
    return this
  }


  // AFFIX DATA-API
  // ==============

  $(window).on('load', function () {
    $('[data-spy="affix"]').each(function () {
      var $spy = $(this)
      var data = $spy.data()

      data.offset = data.offset || {}

      if (data.offsetBottom) data.offset.bottom = data.offsetBottom
      if (data.offsetTop)    data.offset.top    = data.offsetTop

      $spy.affix(data)
    })
Mark Otto's avatar
Mark Otto committed
1991
1992
  })

1993
}(window.jQuery);