bootstrap.js 56.8 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
317
  Carousel.DEFAULTS = {
    interval: 5000
  , pause: 'hover'
  }
318

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

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

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

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

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

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

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

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

fat's avatar
fat committed
344
345
346
347
348
    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]))
  }
349

fat's avatar
fat committed
350
351
352
353
354
355
  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)
356
357
    }

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

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

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

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

fat's avatar
fat committed
373
374
375
376
377
378
379
  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
380

fat's avatar
fat committed
381
    this.sliding = true
382

fat's avatar
fat committed
383
    isCycling && this.pause()
fat's avatar
fat committed
384

fat's avatar
fat committed
385
    $next = $next.length ? $next : this.$element.find('.item')[fallback]()
386

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

fat's avatar
fat committed
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
    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
406
      $active
407
408
409
410
411
412
413
        .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
414
415
416
417
418
419
420
    } else {
      this.$element.trigger(e)
      if (e.isDefaultPrevented()) return
      $active.removeClass('active')
      $next.addClass('active')
      this.sliding = false
      this.$element.trigger('slid')
421
422
    }

fat's avatar
fat committed
423
424
425
    isCycling && this.cycle()

    return this
426
427
428
  }


fat's avatar
fat committed
429
430
  // CAROUSEL PLUGIN DEFINITION
  // ==========================
431

432
433
  var old = $.fn.carousel

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

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

  $.fn.carousel.Constructor = Carousel


fat's avatar
fat committed
451
452
  // CAROUSEL NO CONFLICT
  // ====================
453
454
455
456
457
458

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

fat's avatar
fat committed
459

fat's avatar
fat committed
460
461
  // CAROUSEL DATA-API
  // =================
462

463
  $(document).on('click.bs.carousel.data-api', '[data-slide], [data-slide-to]', function (e) {
fat's avatar
fat committed
464
    var $this   = $(this), href
fat's avatar
fat committed
465
466
    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
467
468
    var slideIndex = $this.attr('data-slide-to')
    if (slideIndex) options.interval = false
469

470
    $target.carousel(options)
471
472

    if (slideIndex = $this.attr('data-slide-to')) {
fat's avatar
fat committed
473
      $target.data('bs.carousel').to(slideIndex)
474
475
    }

476
    e.preventDefault()
477
478
  })

fat's avatar
fat committed
479
480
481
482
483
484
485
  $(window).on('load', function () {
    $('[data-ride="carousel"]').each(function () {
      var $carousel = $(this)
      $carousel.carousel($carousel.data())
    })
  })

Mark Otto's avatar
Mark Otto committed
486
}(window.jQuery);
487

488
/* ========================================================================
fat's avatar
fat committed
489
 * Bootstrap: collapse.js v3.0.0
Chris Rebert's avatar
Chris Rebert committed
490
 * http://twbs.github.com/bootstrap/javascript.html#collapse
491
 * ========================================================================
492
493
494
495
496
497
498
499
500
501
502
503
504
 * 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.
505
 * ======================================================================== */
506
507


508
+function ($) { "use strict";
509

510
511
  // COLLAPSE PUBLIC CLASS DEFINITION
  // ================================
512
513

  var Collapse = function (element, options) {
514
515
516
    this.$element      = $(element)
    this.options       = $.extend({}, Collapse.DEFAULTS, options)
    this.transitioning = null
517

518
519
520
521
522
523
524
    if (this.options.parent) this.$parent = $(this.options.parent)
    if (this.options.toggle) this.toggle()
  }

  Collapse.DEFAULTS = {
    toggle: true
  }
525

526
527
528
  Collapse.prototype.dimension = function () {
    var hasWidth = this.$element.hasClass('width')
    return hasWidth ? 'width' : 'height'
529
530
  }

531
532
  Collapse.prototype.show = function () {
    if (this.transitioning || this.$element.hasClass('in')) return
533

fat's avatar
fat committed
534
535
536
537
    var startEvent = $.Event('show.bs.collapse')
    this.$element.trigger(startEvent)
    if (startEvent.isDefaultPrevented()) return

Mark Otto's avatar
Mark Otto committed
538
    var actives = this.$parent && this.$parent.find('> .accordion-group > .in')
539

540
    if (actives && actives.length) {
fat's avatar
fat committed
541
      var hasData = actives.data('bs.collapse')
542
543
      if (hasData && hasData.transitioning) return
      actives.collapse('hide')
fat's avatar
fat committed
544
      hasData || actives.data('bs.collapse', null)
545
546
    }

547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
    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('-'))
568

569
570
571
572
    this.$element
      .one($.support.transition.end, $.proxy(complete, this))
      .emulateTransitionEnd(350)
      [dimension](this.$element[0][scrollSize])
573
  }
574

575
576
  Collapse.prototype.hide = function () {
    if (this.transitioning || !this.$element.hasClass('in')) return
fat's avatar
fat committed
577
578
579
580
581

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

582
    var dimension = this.dimension()
583

584
585
586
    this.$element
      [dimension](this.$element[dimension]())
      [0].offsetHeight
587

588
    this.$element
589
      .addClass('collapsing')
590
      .removeClass('collapse')
591
      .removeClass('in')
592

593
    this.transitioning = 1
594

595
    var complete = function () {
596
597
598
599
600
      this.transitioning = 0
      this.$element
        .trigger('hidden.bs.collapse')
        .removeClass('collapsing')
        .addClass('collapse')
601
602
    }

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

605
606
607
608
    this.$element
      [dimension](0)
      .one($.support.transition.end, $.proxy(complete, this))
      .emulateTransitionEnd(350)
609
  }
610

611
612
  Collapse.prototype.toggle = function () {
    this[this.$element.hasClass('in') ? 'hide' : 'show']()
613
614
615
  }


616
617
  // COLLAPSE PLUGIN DEFINITION
  // ==========================
618
619

  var old = $.fn.collapse
620
621
622

  $.fn.collapse = function (option) {
    return this.each(function () {
623
      var $this   = $(this)
fat's avatar
fat committed
624
      var data    = $this.data('bs.collapse')
625
626
      var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option)

fat's avatar
fat committed
627
      if (!data) $this.data('bs.collapse', (data = new Collapse(this, options)))
628
629
630
631
632
633
634
      if (typeof option == 'string') data[option]()
    })
  }

  $.fn.collapse.Constructor = Collapse


635
636
  // COLLAPSE NO CONFLICT
  // ====================
637

638
639
640
641
642
643
  $.fn.collapse.noConflict = function () {
    $.fn.collapse = old
    return this
  }


644
645
  // COLLAPSE DATA-API
  // =================
646

647
  $(document).on('click.bs.collapse.data-api', '[data-toggle=collapse]', function (e) {
648
649
    var $this   = $(this), href
    var target  = $this.attr('data-target')
650
651
        || e.preventDefault()
        || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7
652
653
654
655
    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
656
    var $parent = parent && $(parent)
657

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

663
    $target.collapse(option)
664
665
  })

Mark Otto's avatar
Mark Otto committed
666
}(window.jQuery);
667

668
/* ========================================================================
fat's avatar
fat committed
669
 * Bootstrap: dropdown.js v3.0.0
Chris Rebert's avatar
Chris Rebert committed
670
 * http://twbs.github.com/bootstrap/javascript.html#dropdowns
671
 * ========================================================================
672
673
674
675
676
677
678
679
680
681
682
683
684
 * 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.
685
 * ======================================================================== */
686
687


688
+function ($) { "use strict";
689

690
691
  // DROPDOWN CLASS DEFINITION
  // =========================
692

693
694
695
  var backdrop = '.dropdown-backdrop'
  var toggle   = '[data-toggle=dropdown]'
  var Dropdown = function (element) {
696
    var $el = $(element).on('click.bs.dropdown', this.toggle)
697
  }
698

699
700
  Dropdown.prototype.toggle = function (e) {
    var $this = $(this)
701

702
    if ($this.is('.disabled, :disabled')) return
703

704
705
    var $parent  = getParent($this)
    var isActive = $parent.hasClass('open')
706

707
    clearMenus()
fat's avatar
fat committed
708

709
    if (!isActive) {
fat's avatar
fat committed
710
711
      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
712
        $('<div class="dropdown-backdrop"/>').insertAfter($(this)).on('click', clearMenus)
fat's avatar
fat committed
713
      }
714
715
716
717
718
719
720
721

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

      if (e.isDefaultPrevented()) return

      $parent
        .toggleClass('open')
        .trigger('shown.bs.dropdown')
722
723
    }

724
    $this.focus()
725

726
727
    return false
  }
728

729
730
  Dropdown.prototype.keydown = function (e) {
    if (!/(38|40|27)/.test(e.keyCode)) return
731

732
    var $this = $(this)
733

734
735
    e.preventDefault()
    e.stopPropagation()
736

737
    if ($this.is('.disabled, :disabled')) return
738

739
740
    var $parent  = getParent($this)
    var isActive = $parent.hasClass('open')
741

742
743
744
745
    if (!isActive || (isActive && e.keyCode == 27)) {
      if (e.which == 27) $parent.find(toggle).focus()
      return $this.click()
    }
746

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

749
    if (!$items.length) return
750

751
    var index = $items.index($items.filter(':focus'))
752

753
754
755
    if (e.keyCode == 38 && index > 0)                 index--                        // up
    if (e.keyCode == 40 && index < $items.length - 1) index++                        // down
    if (!~index)                                      index=0
756

757
    $items.eq(index).focus()
758
759
  }

Mark Otto's avatar
Mark Otto committed
760
  function clearMenus() {
761
    $(backdrop).remove()
762
    $(toggle).each(function (e) {
763
764
765
766
767
768
      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')
    })
769
770
771
772
773
774
775
  }

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

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

779
    var $parent = selector && $(selector)
780

781
    return $parent && $parent.length ? $parent : $this.parent()
782
783
784
  }


785
786
  // DROPDOWN PLUGIN DEFINITION
  // ==========================
787

788
789
  var old = $.fn.dropdown

790
791
792
  $.fn.dropdown = function (option) {
    return this.each(function () {
      var $this = $(this)
793
794
      var data  = $this.data('dropdown')

795
796
797
798
799
800
801
802
      if (!data) $this.data('dropdown', (data = new Dropdown(this)))
      if (typeof option == 'string') data[option].call($this)
    })
  }

  $.fn.dropdown.Constructor = Dropdown


803
804
  // DROPDOWN NO CONFLICT
  // ====================
805
806
807
808
809
810
811

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


812
813
814
  // APPLY TO STANDARD DROPDOWN ELEMENTS
  // ===================================

815
  $(document)
816
817
818
819
    .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)
820

fat's avatar
fat committed
821
}(window.jQuery);
822

823
/* ========================================================================
fat's avatar
fat committed
824
 * Bootstrap: modal.js v3.0.0
Chris Rebert's avatar
Chris Rebert committed
825
 * http://twbs.github.com/bootstrap/javascript.html#modals
826
 * ========================================================================
827
828
829
830
831
832
833
834
835
836
837
838
839
 * 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.
840
 * ======================================================================== */
841
842


843
+function ($) { "use strict";
844

fat's avatar
fat committed
845
846
  // MODAL CLASS DEFINITION
  // ======================
847

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

fat's avatar
fat committed
854
855
    if (this.options.remote) this.$element.find('.modal-body').load(this.options.remote)
  }
856

fat's avatar
fat committed
857
858
859
860
861
  Modal.DEFAULTS = {
      backdrop: true
    , keyboard: true
    , show: true
  }
862

Jacob Thornton's avatar
Jacob Thornton committed
863
864
  Modal.prototype.toggle = function (_relatedTarget) {
    return this[!this.isShown ? 'show' : 'hide'](_relatedTarget)
fat's avatar
fat committed
865
  }
866

Jacob Thornton's avatar
Jacob Thornton committed
867
  Modal.prototype.show = function (_relatedTarget) {
fat's avatar
fat committed
868
    var that = this
Jacob Thornton's avatar
Jacob Thornton committed
869
    var e    = $.Event('show.bs.modal', { relatedTarget: _relatedTarget })
870

fat's avatar
fat committed
871
    this.$element.trigger(e)
872

fat's avatar
fat committed
873
    if (this.isShown || e.isDefaultPrevented()) return
874

fat's avatar
fat committed
875
    this.isShown = true
876

fat's avatar
fat committed
877
    this.escape()
878

fat's avatar
fat committed
879
880
    this.backdrop(function () {
      var transition = $.support.transition && that.$element.hasClass('fade')
881

fat's avatar
fat committed
882
      if (!that.$element.parent().length) {
Jacob Thornton's avatar
Jacob Thornton committed
883
        that.$element.appendTo(document.body) // don't move modals dom position
fat's avatar
fat committed
884
      }
885

fat's avatar
fat committed
886
      that.$element.show()
887

fat's avatar
fat committed
888
889
890
      if (transition) {
        that.$element[0].offsetWidth // force reflow
      }
891

fat's avatar
fat committed
892
893
894
      that.$element
        .addClass('in')
        .attr('aria-hidden', false)
895

fat's avatar
fat committed
896
      that.enforceFocus()
897

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

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

fat's avatar
fat committed
910
  Modal.prototype.hide = function (e) {
fat's avatar
fat committed
911
    if (e) e.preventDefault()
912

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

fat's avatar
fat committed
915
    this.$element.trigger(e)
916

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

fat's avatar
fat committed
919
    this.isShown = false
920

fat's avatar
fat committed
921
    this.escape()
922

Mark Otto's avatar
Mark Otto committed
923
    $(document).off('focusin.bs.modal')
924

fat's avatar
fat committed
925
926
927
    this.$element
      .removeClass('in')
      .attr('aria-hidden', true)
928

fat's avatar
fat committed
929
    $.support.transition && this.$element.hasClass('fade') ?
930
931
932
      this.$element
        .one($.support.transition.end, $.proxy(this.hideModal, this))
        .emulateTransitionEnd(300) :
fat's avatar
fat committed
933
934
      this.hideModal()
  }
935

fat's avatar
fat committed
936
  Modal.prototype.enforceFocus = function () {
Jacob Thornton's avatar
Jacob Thornton committed
937
938
    $(document)
      .off('focusin.bs.modal') // guard against infinite focus loop
fat's avatar
fat committed
939
940
941
942
943
      .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
944
  }
945

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

fat's avatar
fat committed
956
957
958
959
960
  Modal.prototype.hideModal = function () {
    var that = this
    this.$element.hide()
    this.backdrop(function () {
      that.removeBackdrop()
Mark Otto's avatar
Mark Otto committed
961
      that.$element.trigger('hidden.bs.modal')
fat's avatar
fat committed
962
963
    })
  }
964

fat's avatar
fat committed
965
966
967
968
  Modal.prototype.removeBackdrop = function () {
    this.$backdrop && this.$backdrop.remove()
    this.$backdrop = null
  }
969

fat's avatar
fat committed
970
971
972
  Modal.prototype.backdrop = function (callback) {
    var that    = this
    var animate = this.$element.hasClass('fade') ? 'fade' : ''
973

fat's avatar
fat committed
974
975
    if (this.isShown && this.options.backdrop) {
      var doAnimate = $.support.transition && animate
976

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

fat's avatar
fat committed
980
981
982
983
984
985
      this.$element.on('click', $.proxy(function (e) {
        if (e.target !== e.currentTarget) return
        this.options.backdrop == 'static'
          ? this.$element[0].focus.call(this.$element[0])
          : this.hide.call(this)
      }, this))
986

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

fat's avatar
fat committed
989
      this.$backdrop.addClass('in')
990

fat's avatar
fat committed
991
      if (!callback) return
992

fat's avatar
fat committed
993
      doAnimate ?
994
995
996
        this.$backdrop
          .one($.support.transition.end, callback)
          .emulateTransitionEnd(150) :
fat's avatar
fat committed
997
        callback()
998

fat's avatar
fat committed
999
1000
    } else if (!this.isShown && this.$backdrop) {
      this.$backdrop.removeClass('in')
1001

fat's avatar
fat committed
1002
      $.support.transition && this.$element.hasClass('fade')?
1003
1004
1005
        this.$backdrop
          .one($.support.transition.end, callback)
          .emulateTransitionEnd(150) :
fat's avatar
fat committed
1006
        callback()
1007

fat's avatar
fat committed
1008
1009
1010
    } else if (callback) {
      callback()
    }
1011
1012
1013
  }


fat's avatar
fat committed
1014
1015
  // MODAL PLUGIN DEFINITION
  // =======================
1016

1017
1018
  var old = $.fn.modal

Jacob Thornton's avatar
Jacob Thornton committed
1019
  $.fn.modal = function (option, _relatedTarget) {
1020
    return this.each(function () {
fat's avatar
fat committed
1021
      var $this   = $(this)
Mark Otto's avatar
Mark Otto committed
1022
      var data    = $this.data('bs.modal')
fat's avatar
fat committed
1023
1024
      var options = $.extend({}, Modal.DEFAULTS, $this.data(), typeof option == 'object' && option)

Mark Otto's avatar
Mark Otto committed
1025
      if (!data) $this.data('bs.modal', (data = new Modal(this, options)))
Jacob Thornton's avatar
Jacob Thornton committed
1026
1027
      if (typeof option == 'string') data[option](_relatedTarget)
      else if (options.show) data.show(_relatedTarget)
1028
1029
1030
1031
1032
1033
    })
  }

  $.fn.modal.Constructor = Modal


fat's avatar
fat committed
1034
1035
  // MODAL NO CONFLICT
  // =================
1036
1037
1038
1039
1040
1041
1042

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


fat's avatar
fat committed
1043
1044
  // MODAL DATA-API
  // ==============
1045

Mark Otto's avatar
Mark Otto committed
1046
  $(document).on('click.bs.modal.data-api', '[data-toggle="modal"]', function (e) {
fat's avatar
fat committed
1047
1048
1049
    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
1050
    var option  = $target.data('modal') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data())
1051

1052
    e.preventDefault()
1053

1054
    $target
Jacob Thornton's avatar
Jacob Thornton committed
1055
      .modal(option, this)
1056
      .one('hide', function () {
1057
        $this.is(':visible') && $this.focus()
1058
      })
Jacob Thornton's avatar
Jacob Thornton committed
1059
  })
1060

Jacob Thornton's avatar
Jacob Thornton committed
1061
1062
1063
1064
1065
  $(function () {
    var $body = $(document.body)
      .on('shown.bs.modal',  '.modal', function () { $body.addClass('modal-open') })
      .on('hidden.bs.modal', '.modal', function () { $body.removeClass('modal-open') })
  })
1066

1067
}(window.jQuery);
1068

1069
/* ========================================================================
1070
1071
1072
 * Bootstrap: tooltip.js v3.0.0
 * http://twbs.github.com/bootstrap/javascript.html#affix
 * Inspired by the original jQuery.tipsy by Jason Frame
1073
 * ========================================================================
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
 * 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.
1087
 * ======================================================================== */
1088
1089


1090
+function ($) { "use strict";
1091

1092
  // TOOLTIP PUBLIC CLASS DEFINITION
fat's avatar
fat committed
1093
  // ===============================
1094

1095
1096
1097
1098
1099
1100
1101
  var Tooltip = function (element, options) {
    this.type       =
    this.options    =
    this.enabled    =
    this.timeout    =
    this.hoverState =
    this.$element   = null
1102

1103
1104
    this.init('tooltip', element, options)
  }
1105

1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
  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
  }
1117

1118
1119
1120
1121
1122
  Tooltip.prototype.init = function (type, element, options) {
    this.enabled  = true
    this.type     = type
    this.$element = $(element)
    this.options  = this.getOptions(options)
1123

1124
    var triggers = this.options.trigger.split(' ')
1125

1126
1127
    for (var i = triggers.length; i--;) {
      var trigger = triggers[i]
fat's avatar
fat committed
1128

1129
1130
1131
1132
1133
      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'
1134

1135
1136
1137
1138
        this.$element.on(eventIn + '.' + this.type, this.options.selector, $.proxy(this.enter, this))
        this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this))
      }
    }
1139

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

1145
1146
  Tooltip.prototype.getDefaults = function () {
    return Tooltip.DEFAULTS
1147
  }
1148

1149
1150
  Tooltip.prototype.getOptions = function (options) {
    options = $.extend({}, this.getDefaults(), this.$element.data(), options)
1151

1152
1153
1154
1155
1156
1157
    if (options.delay && typeof options.delay == 'number') {
      options.delay = {
        show: options.delay
      , hide: options.delay
      }
    }
1158

1159
    return options
1160
  }
Jacob Thornton's avatar
Jacob Thornton committed
1161

1162
1163
1164
  Tooltip.prototype.enter = function (obj) {
    var defaults = this.getDefaults()
    var options  = {}
1165

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

1170
1171
    var self = obj instanceof this.constructor ?
      obj : $(obj.currentTarget)[this.type](options).data('bs.' + this.type)
1172

1173
    clearTimeout(self.timeout)
1174

1175
    if (!self.options.delay || !self.options.delay.show) return self.show()
1176

1177
1178
1179
1180
    self.hoverState = 'in'
    self.timeout    = setTimeout(function () {
      if (self.hoverState == 'in') self.show()
    }, self.options.delay.show)
1181
  }
1182

1183
1184
1185
  Tooltip.prototype.leave = function (obj) {
    var self = obj instanceof this.constructor ?
      obj : $(obj.currentTarget)[this.type](this._options).data('bs.' + this.type)
1186

1187
    clearTimeout(self.timeout)
fat's avatar
fat committed
1188

1189
    if (!self.options.delay || !self.options.delay.hide) return self.hide()
1190

1191
1192
1193
1194
    self.hoverState = 'out'
    self.timeout    = setTimeout(function () {
      if (self.hoverState == 'out') self.hide()
    }, self.options.delay.hide)
1195
  }
1196

1197
1198
  Tooltip.prototype.show = function () {
    var e = $.Event('show.bs.'+ this.type)
1199

1200
1201
    if (this.hasContent() && this.enabled) {
      this.$element.trigger(e)
1202

1203
      if (e.isDefaultPrevented()) return
1204

1205
      var $tip = this.tip()
fat's avatar
fat committed
1206

1207
      this.setContent()
fat's avatar
fat committed
1208

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

1211
1212
1213
      var placement = typeof this.options.placement == 'function' ?
        this.options.placement.call(this, $tip[0], this.$element[0]) :
        this.options.placement
1214

1215
1216
1217
      var autoToken = /\s?auto?\s?/i
      var autoPlace = autoToken.test(placement)
      if (autoPlace) placement = placement.replace(autoToken, '') || 'top'
1218

1219
1220
1221
1222
      $tip
        .detach()
        .css({ top: 0, left: 0, display: 'block' })
        .addClass(placement)
1223

1224
      this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element)
1225

1226
1227
1228
      var pos          = this.getPosition()
      var actualWidth  = $tip[0].offsetWidth
      var actualHeight = $tip[0].offsetHeight
fat's avatar
fat committed
1229

1230
1231
      if (autoPlace) {
        var $parent = this.$element.parent()
1232

1233
1234
1235
1236
1237
        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
1238

1239
1240
1241
1242
1243
        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
1244

1245
1246
1247
1248
1249
        $tip
          .removeClass(orgPlacement)
          .addClass(placement)
      }

1250
      var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight)
1251

fat's avatar
fat committed
1252
      this.applyPlacement(calculatedOffset, placement)
1253
      this.$element.trigger('shown.bs.' + this.type)
fat's avatar
fat committed
1254
    }
1255
  }
fat's avatar
fat committed
1256

1257
1258
1259
1260
1261
  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
1262

1263
    // manually read margins because getBoundingClientRect includes difference
fat's avatar
fat committed
1264
1265
1266
1267
1268
1269
1270
1271
1272
    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
1273

1274
1275
1276
    $tip
      .offset(offset)
      .addClass('in')
fat's avatar
fat committed
1277

fat's avatar
fat committed
1278
    // check to see if placing tip in new offset caused the tip to resize itself
1279
1280
    var actualWidth  = $tip[0].offsetWidth
    var actualHeight = $tip[0].offsetHeight
fat's avatar
fat committed
1281

1282
1283
    if (placement == 'top' && actualHeight != height) {
      replace = true
fat's avatar
fat committed
1284
      offset.top = offset.top + height - actualHeight
fat's avatar
fat committed
1285
1286
    }

fat's avatar
fat committed
1287
    if (/bottom|top/.test(placement)) {
1288
      var delta = 0
1289

fat's avatar
fat committed
1290
      if (offset.left < 0) {
1291
1292
        delta       = offset.left * -2
        offset.left = 0
fat's avatar
fat committed
1293

1294
        $tip.offset(offset)
1295

1296
1297
1298
        actualWidth  = $tip[0].offsetWidth
        actualHeight = $tip[0].offsetHeight
      }
1299

1300
1301
1302
1303
      this.replaceArrow(delta - width + actualWidth, actualWidth, 'left')
    } else {
      this.replaceArrow(actualHeight - height, actualHeight, 'top')
    }
1304

1305
    if (replace) $tip.offset(offset)
1306
  }
1307

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

1312
1313
1314
  Tooltip.prototype.setContent = function () {
    var $tip  = this.tip()
    var title = this.getTitle()
1315

1316
1317
1318
    $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title)
    $tip.removeClass('fade in top bottom left right')
  }
1319

1320
1321
1322
1323
  Tooltip.prototype.hide = function () {
    var that = this
    var $tip = this.tip()
    var e    = $.Event('hide.bs.' + this.type)
1324

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

1327
    this.$element.trigger(e)
1328

1329
    if (e.isDefaultPrevented()) return
1330

1331
    $tip.removeClass('in')
1332

1333
1334
    $.support.transition && this.$tip.hasClass('fade') ?
      $tip
Jacob Thornton's avatar
Jacob Thornton committed
1335
        .one($.support.transition.end, complete)
1336
        .emulateTransitionEnd(150) :
Jacob Thornton's avatar
Jacob Thornton committed
1337
      complete()
1338

1339
    this.$element.trigger('hidden.bs.' + this.type)
1340

1341
    return this
1342
1343
  }

1344
1345
1346
1347
  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', '')
1348
    }
1349
  }
1350

1351
1352
1353
  Tooltip.prototype.hasContent = function () {
    return this.getTitle()
  }
1354

1355
1356
1357
1358
1359
1360
1361
  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())
  }
1362

1363
  Tooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight) {
fat's avatar
fat committed
1364
1365
1366
1367
1368
1369
    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   }
  }

1370
1371
1372
1373
  Tooltip.prototype.getTitle = function () {
    var title
    var $e = this.$element
    var o  = this.options
1374

1375
1376
    title = $e.attr('data-original-title')
      || (typeof o.title == 'function' ? o.title.call($e[0]) :  o.title)
1377

1378
    return title
1379
  }
1380

1381
1382
1383
  Tooltip.prototype.tip = function () {
    return this.$tip = this.$tip || $(this.options.template)
  }
1384

Mark Otto's avatar
Mark Otto committed
1385
  Tooltip.prototype.arrow = function () {
fat's avatar
fat committed
1386
    return this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow')
1387
  }
1388

1389
1390
1391
1392
1393
1394
1395
  Tooltip.prototype.validate = function () {
    if (!this.$element[0].parentNode) {
      this.hide()
      this.$element = null
      this.options  = null
    }
  }
1396

1397
1398
1399
  Tooltip.prototype.enable = function () {
    this.enabled = true
  }
1400

1401
1402
1403
  Tooltip.prototype.disable = function () {
    this.enabled = false
  }
1404

1405
1406
1407
  Tooltip.prototype.toggleEnabled = function () {
    this.enabled = !this.enabled
  }
Mark Otto's avatar
Mark Otto committed
1408

1409
1410
1411
1412
  Tooltip.prototype.toggle = function (e) {
    var self = e ? $(e.currentTarget)[this.type](this._options).data('bs.' + this.type) : this
    self.tip().hasClass('in') ? self.leave(self) : self.enter(self)
  }
1413

1414
1415
  Tooltip.prototype.destroy = function () {
    this.hide().$element.off('.' + this.type).removeData('bs.' + this.type)
fat's avatar
fat committed
1416
  }
1417
1418


1419
1420
  // TOOLTIP PLUGIN DEFINITION
  // =========================
1421

1422
  var old = $.fn.tooltip
1423

1424
  $.fn.tooltip = function (option) {
1425
    return this.each(function () {
1426
1427
1428
      var $this   = $(this)
      var data    = $this.data('bs.tooltip')
      var options = typeof option == 'object' && option
fat's avatar
fat committed
1429

1430
      if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options)))
1431
1432
1433
1434
      if (typeof option == 'string') data[option]()
    })
  }

1435
  $.fn.tooltip.Constructor = Tooltip
1436

1437

1438
1439
  // TOOLTIP NO CONFLICT
  // ===================
1440

1441
1442
  $.fn.tooltip.noConflict = function () {
    $.fn.tooltip = old
1443
1444
1445
    return this
  }

Mark Otto's avatar
Mark Otto committed
1446
}(window.jQuery);
1447

1448
/* ========================================================================
1449
1450
 * Bootstrap: popover.js v3.0.0
 * http://twbs.github.com/bootstrap/javascript.html#popovers
1451
 * ========================================================================
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
 * 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.
1465
 * ======================================================================== */
1466
1467


1468
+function ($) { "use strict";
1469

1470
  // POPOVER PUBLIC CLASS DEFINITION
1471
  // ===============================
fat's avatar
fat committed
1472

1473
1474
  var Popover = function (element, options) {
    this.init('popover', element, options)
1475
1476
  }

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

1479
1480
1481
1482
1483
1484
  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>'
  })
1485

fat's avatar
fat committed
1486

1487
1488
  // NOTE: POPOVER EXTENDS tooltip.js
  // ================================
fat's avatar
fat committed
1489

1490
  Popover.prototype = $.extend({}, $.fn.tooltip.Constructor.prototype)
1491

1492
  Popover.prototype.constructor = Popover
fat's avatar
fat committed
1493

1494
1495
1496
  Popover.prototype.getDefaults = function () {
    return Popover.DEFAULTS
  }
1497

1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
  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')

1508
1509
1510
1511
1512
1513
1514
    // Hide empty titles
    //
    // IE8 doesn't accept hiding via the `:empty` pseudo selector, we have to do
    // this manually by checking the contents.
    if ($tip.find('.popover-title').html() === '') {
      $tip.find('.popover-title').hide();
    }
1515
1516
  }

1517
1518
  Popover.prototype.hasContent = function () {
    return this.getTitle() || this.getContent()
1519
1520
  }

1521
1522
1523
  Popover.prototype.getContent = function () {
    var $e = this.$element
    var o  = this.options
1524

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

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

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

1540

1541
1542
  // POPOVER PLUGIN DEFINITION
  // =========================
1543

1544
  var old = $.fn.popover
1545

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

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

1557
  $.fn.popover.Constructor = Popover
fat's avatar
fat committed
1558

1559

1560
1561
  // POPOVER NO CONFLICT
  // ===================
1562

1563
1564
1565
1566
  $.fn.popover.noConflict = function () {
    $.fn.popover = old
    return this
  }
1567

1568
}(window.jQuery);
1569

1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
/* ========================================================================
 * 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.
 * ======================================================================== */
1588
1589


1590
+function ($) { "use strict";
1591

1592
1593
  // SCROLLSPY CLASS DEFINITION
  // ==========================
1594

1595
1596
1597
  function ScrollSpy(element, options) {
    var href
    var process  = $.proxy(this.process, this)
1598

fat's avatar
fat committed
1599
    this.$element       = $(element).is('body') ? $(window) : $(element)
1600
    this.$body          = $('body')
fat's avatar
fat committed
1601
    this.$scrollElement = this.$element.on('scroll.bs.scroll-spy.data-api', process)
1602
1603
1604
1605
1606
1607
1608
    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
1609

1610
1611
1612
    this.refresh()
    this.process()
  }
1613

1614
1615
1616
  ScrollSpy.DEFAULTS = {
    offset: 10
  }
1617

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

1621
1622
    this.offsets = $([])
    this.targets = $([])
1623

1624
1625
1626
1627
1628
1629
1630
    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)
1631

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

1643
1644
1645
1646
1647
1648
1649
1650
  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
1651

1652
1653
1654
    if (scrollTop >= maxScroll) {
      return activeTarget != (i = targets.last()[0]) && this.activate(i)
    }
1655

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

1664
1665
  ScrollSpy.prototype.activate = function (target) {
    this.activeTarget = target
1666

1667
1668
1669
    $(this.selector)
      .parents('.active')
      .removeClass('active')
1670

1671
1672
1673
    var selector = this.selector
      + '[data-target="' + target + '"],'
      + this.selector + '[href="' + target + '"]'
1674

1675
1676
1677
    var active = $(selector)
      .parents('li')
      .addClass('active')
1678

1679
1680
1681
1682
    if (active.parent('.dropdown-menu').length)  {
      active = active
        .closest('li.dropdown')
        .addClass('active')
1683
    }
1684

1685
1686
    active.trigger('activate')
  }
1687
1688


1689
1690
  // SCROLLSPY PLUGIN DEFINITION
  // ===========================
1691

1692
  var old = $.fn.scrollspy
1693

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

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

1705
  $.fn.scrollspy.Constructor = ScrollSpy
1706
1707


1708
1709
1710
1711
1712
1713
  // SCROLLSPY NO CONFLICT
  // =====================

  $.fn.scrollspy.noConflict = function () {
    $.fn.scrollspy = old
    return this
1714
1715
1716
  }


1717
1718
  // SCROLLSPY DATA-API
  // ==================
1719

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

1727
}(window.jQuery);
1728

1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
/* ========================================================================
 * 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.
 * ======================================================================== */
1747

1748

1749
1750
1751
1752
1753
1754
1755
+function ($) { "use strict";

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

  var Tab = function (element) {
    this.element = $(element)
1756
  }
1757

1758
1759
1760
1761
1762
1763
1764
1765
  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
1766
    }
1767

1768
    if ($this.parent('li').hasClass('active')) return
1769

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

1775
    $this.trigger(e)
1776

1777
    if (e.isDefaultPrevented()) return
1778

1779
    var $target = $(selector)
1780

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

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

1796
1797
1798
1799
1800
    function next() {
      $active
        .removeClass('active')
        .find('> .dropdown-menu > .active')
        .removeClass('active')
1801

1802
      element.addClass('active')
1803

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

1811
1812
1813
      if (element.parent('.dropdown-menu')) {
        element.closest('li.dropdown').addClass('active')
      }
fat's avatar
fat committed
1814

1815
1816
      callback && callback()
    }
fat's avatar
fat committed
1817

1818
1819
1820
1821
1822
1823
1824
    transition ?
      $active
        .one($.support.transition.end, next)
        .emulateTransitionEnd(150) :
      next()

    $active.removeClass('in')
1825
1826
1827
  }


1828
1829
  // TAB PLUGIN DEFINITION
  // =====================
1830

1831
  var old = $.fn.tab
1832

1833
  $.fn.tab = function ( option ) {
1834
    return this.each(function () {
1835
1836
      var $this = $(this)
      var data  = $this.data('bs.tab')
fat's avatar
fat committed
1837

1838
      if (!data) $this.data('bs.tab', (data = new Tab(this)))
1839
1840
1841
1842
      if (typeof option == 'string') data[option]()
    })
  }

1843
  $.fn.tab.Constructor = Tab
1844
1845


1846
1847
  // TAB NO CONFLICT
  // ===============
1848

1849
1850
  $.fn.tab.noConflict = function () {
    $.fn.tab = old
1851
1852
1853
    return this
  }

1854
1855
1856
1857
1858
1859
1860
1861
1862

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

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

1863
}(window.jQuery);
1864

1865
/* ========================================================================
1866
1867
 * Bootstrap: affix.js v3.0.0
 * http://twbs.github.com/bootstrap/javascript.html#affix
1868
 * ========================================================================
1869
 * Copyright 2012 Twitter, Inc.
Mark Otto's avatar
Mark Otto committed
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
 *
 * 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.
1882
 * ======================================================================== */
Mark Otto's avatar
Mark Otto committed
1883
1884


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

1887
1888
  // AFFIX CLASS DEFINITION
  // ======================
Mark Otto's avatar
Mark Otto committed
1889

1890
1891
1892
1893
1894
  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
1895

1896
1897
1898
    this.$element = $(element)
    this.affixed  =
    this.unpin    = null
fat's avatar
fat committed
1899

1900
1901
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
    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() })
1941
    }
Mark Otto's avatar
Mark Otto committed
1942
1943
  }

1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958

  // 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]()
    })
1959
1960
  }

1961
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
  $.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
1988
1989
  })

1990
}(window.jQuery);