update Bootstrap from v2.1.1 to v2.2.1
[mygpo.git] / htdocs / media / js / bootstrap.js
bloba535f36507d25631490670a52d07d8b36cb2f29e
1 /* ===================================================
2  * bootstrap-transition.js v2.2.1
3  * http://twitter.github.com/bootstrap/javascript.html#transitions
4  * ===================================================
5  * Copyright 2012 Twitter, Inc.
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ========================================================== */
21 !function ($) {
23   "use strict"; // jshint ;_;
26   /* CSS TRANSITION SUPPORT (http://www.modernizr.com/)
27    * ======================================================= */
29   $(function () {
31     $.support.transition = (function () {
33       var transitionEnd = (function () {
35         var el = document.createElement('bootstrap')
36           , transEndEventNames = {
37                'WebkitTransition' : 'webkitTransitionEnd'
38             ,  'MozTransition'    : 'transitionend'
39             ,  'OTransition'      : 'oTransitionEnd otransitionend'
40             ,  'transition'       : 'transitionend'
41             }
42           , name
44         for (name in transEndEventNames){
45           if (el.style[name] !== undefined) {
46             return transEndEventNames[name]
47           }
48         }
50       }())
52       return transitionEnd && {
53         end: transitionEnd
54       }
56     })()
58   })
60 }(window.jQuery);
61 /* =========================================================
62  * bootstrap-modal.js v2.2.1
63  * http://twitter.github.com/bootstrap/javascript.html#modals
64  * =========================================================
65  * Copyright 2012 Twitter, Inc.
66  *
67  * Licensed under the Apache License, Version 2.0 (the "License");
68  * you may not use this file except in compliance with the License.
69  * You may obtain a copy of the License at
70  *
71  * http://www.apache.org/licenses/LICENSE-2.0
72  *
73  * Unless required by applicable law or agreed to in writing, software
74  * distributed under the License is distributed on an "AS IS" BASIS,
75  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
76  * See the License for the specific language governing permissions and
77  * limitations under the License.
78  * ========================================================= */
81 !function ($) {
83   "use strict"; // jshint ;_;
86  /* MODAL CLASS DEFINITION
87   * ====================== */
89   var Modal = function (element, options) {
90     this.options = options
91     this.$element = $(element)
92       .delegate('[data-dismiss="modal"]', 'click.dismiss.modal', $.proxy(this.hide, this))
93     this.options.remote && this.$element.find('.modal-body').load(this.options.remote)
94   }
96   Modal.prototype = {
98       constructor: Modal
100     , toggle: function () {
101         return this[!this.isShown ? 'show' : 'hide']()
102       }
104     , show: function () {
105         var that = this
106           , e = $.Event('show')
108         this.$element.trigger(e)
110         if (this.isShown || e.isDefaultPrevented()) return
112         this.isShown = true
114         this.escape()
116         this.backdrop(function () {
117           var transition = $.support.transition && that.$element.hasClass('fade')
119           if (!that.$element.parent().length) {
120             that.$element.appendTo(document.body) //don't move modals dom position
121           }
123           that.$element
124             .show()
126           if (transition) {
127             that.$element[0].offsetWidth // force reflow
128           }
130           that.$element
131             .addClass('in')
132             .attr('aria-hidden', false)
134           that.enforceFocus()
136           transition ?
137             that.$element.one($.support.transition.end, function () { that.$element.focus().trigger('shown') }) :
138             that.$element.focus().trigger('shown')
140         })
141       }
143     , hide: function (e) {
144         e && e.preventDefault()
146         var that = this
148         e = $.Event('hide')
150         this.$element.trigger(e)
152         if (!this.isShown || e.isDefaultPrevented()) return
154         this.isShown = false
156         this.escape()
158         $(document).off('focusin.modal')
160         this.$element
161           .removeClass('in')
162           .attr('aria-hidden', true)
164         $.support.transition && this.$element.hasClass('fade') ?
165           this.hideWithTransition() :
166           this.hideModal()
167       }
169     , enforceFocus: function () {
170         var that = this
171         $(document).on('focusin.modal', function (e) {
172           if (that.$element[0] !== e.target && !that.$element.has(e.target).length) {
173             that.$element.focus()
174           }
175         })
176       }
178     , escape: function () {
179         var that = this
180         if (this.isShown && this.options.keyboard) {
181           this.$element.on('keyup.dismiss.modal', function ( e ) {
182             e.which == 27 && that.hide()
183           })
184         } else if (!this.isShown) {
185           this.$element.off('keyup.dismiss.modal')
186         }
187       }
189     , hideWithTransition: function () {
190         var that = this
191           , timeout = setTimeout(function () {
192               that.$element.off($.support.transition.end)
193               that.hideModal()
194             }, 500)
196         this.$element.one($.support.transition.end, function () {
197           clearTimeout(timeout)
198           that.hideModal()
199         })
200       }
202     , hideModal: function (that) {
203         this.$element
204           .hide()
205           .trigger('hidden')
207         this.backdrop()
208       }
210     , removeBackdrop: function () {
211         this.$backdrop.remove()
212         this.$backdrop = null
213       }
215     , backdrop: function (callback) {
216         var that = this
217           , animate = this.$element.hasClass('fade') ? 'fade' : ''
219         if (this.isShown && this.options.backdrop) {
220           var doAnimate = $.support.transition && animate
222           this.$backdrop = $('<div class="modal-backdrop ' + animate + '" />')
223             .appendTo(document.body)
225           this.$backdrop.click(
226             this.options.backdrop == 'static' ?
227               $.proxy(this.$element[0].focus, this.$element[0])
228             : $.proxy(this.hide, this)
229           )
231           if (doAnimate) this.$backdrop[0].offsetWidth // force reflow
233           this.$backdrop.addClass('in')
235           doAnimate ?
236             this.$backdrop.one($.support.transition.end, callback) :
237             callback()
239         } else if (!this.isShown && this.$backdrop) {
240           this.$backdrop.removeClass('in')
242           $.support.transition && this.$element.hasClass('fade')?
243             this.$backdrop.one($.support.transition.end, $.proxy(this.removeBackdrop, this)) :
244             this.removeBackdrop()
246         } else if (callback) {
247           callback()
248         }
249       }
250   }
253  /* MODAL PLUGIN DEFINITION
254   * ======================= */
256   $.fn.modal = function (option) {
257     return this.each(function () {
258       var $this = $(this)
259         , data = $this.data('modal')
260         , options = $.extend({}, $.fn.modal.defaults, $this.data(), typeof option == 'object' && option)
261       if (!data) $this.data('modal', (data = new Modal(this, options)))
262       if (typeof option == 'string') data[option]()
263       else if (options.show) data.show()
264     })
265   }
267   $.fn.modal.defaults = {
268       backdrop: true
269     , keyboard: true
270     , show: true
271   }
273   $.fn.modal.Constructor = Modal
276  /* MODAL DATA-API
277   * ============== */
279   $(document).on('click.modal.data-api', '[data-toggle="modal"]', function (e) {
280     var $this = $(this)
281       , href = $this.attr('href')
282       , $target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, ''))) //strip for ie7
283       , option = $target.data('modal') ? 'toggle' : $.extend({ remote:!/#/.test(href) && href }, $target.data(), $this.data())
285     e.preventDefault()
287     $target
288       .modal(option)
289       .one('hide', function () {
290         $this.focus()
291       })
292   })
294 }(window.jQuery);
296 /* ============================================================
297  * bootstrap-dropdown.js v2.2.1
298  * http://twitter.github.com/bootstrap/javascript.html#dropdowns
299  * ============================================================
300  * Copyright 2012 Twitter, Inc.
302  * Licensed under the Apache License, Version 2.0 (the "License");
303  * you may not use this file except in compliance with the License.
304  * You may obtain a copy of the License at
306  * http://www.apache.org/licenses/LICENSE-2.0
308  * Unless required by applicable law or agreed to in writing, software
309  * distributed under the License is distributed on an "AS IS" BASIS,
310  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
311  * See the License for the specific language governing permissions and
312  * limitations under the License.
313  * ============================================================ */
316 !function ($) {
318   "use strict"; // jshint ;_;
321  /* DROPDOWN CLASS DEFINITION
322   * ========================= */
324   var toggle = '[data-toggle=dropdown]'
325     , Dropdown = function (element) {
326         var $el = $(element).on('click.dropdown.data-api', this.toggle)
327         $('html').on('click.dropdown.data-api', function () {
328           $el.parent().removeClass('open')
329         })
330       }
332   Dropdown.prototype = {
334     constructor: Dropdown
336   , toggle: function (e) {
337       var $this = $(this)
338         , $parent
339         , isActive
341       if ($this.is('.disabled, :disabled')) return
343       $parent = getParent($this)
345       isActive = $parent.hasClass('open')
347       clearMenus()
349       if (!isActive) {
350         $parent.toggleClass('open')
351         $this.focus()
352       }
354       return false
355     }
357   , keydown: function (e) {
358       var $this
359         , $items
360         , $active
361         , $parent
362         , isActive
363         , index
365       if (!/(38|40|27)/.test(e.keyCode)) return
367       $this = $(this)
369       e.preventDefault()
370       e.stopPropagation()
372       if ($this.is('.disabled, :disabled')) return
374       $parent = getParent($this)
376       isActive = $parent.hasClass('open')
378       if (!isActive || (isActive && e.keyCode == 27)) return $this.click()
380       $items = $('[role=menu] li:not(.divider) a', $parent)
382       if (!$items.length) return
384       index = $items.index($items.filter(':focus'))
386       if (e.keyCode == 38 && index > 0) index--                                        // up
387       if (e.keyCode == 40 && index < $items.length - 1) index++                        // down
388       if (!~index) index = 0
390       $items
391         .eq(index)
392         .focus()
393     }
395   }
397   function clearMenus() {
398     $(toggle).each(function () {
399       getParent($(this)).removeClass('open')
400     })
401   }
403   function getParent($this) {
404     var selector = $this.attr('data-target')
405       , $parent
407     if (!selector) {
408       selector = $this.attr('href')
409       selector = selector && /#/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
410     }
412     $parent = $(selector)
413     $parent.length || ($parent = $this.parent())
415     return $parent
416   }
419   /* DROPDOWN PLUGIN DEFINITION
420    * ========================== */
422   $.fn.dropdown = function (option) {
423     return this.each(function () {
424       var $this = $(this)
425         , data = $this.data('dropdown')
426       if (!data) $this.data('dropdown', (data = new Dropdown(this)))
427       if (typeof option == 'string') data[option].call($this)
428     })
429   }
431   $.fn.dropdown.Constructor = Dropdown
434   /* APPLY TO STANDARD DROPDOWN ELEMENTS
435    * =================================== */
437   $(document)
438     .on('click.dropdown.data-api touchstart.dropdown.data-api', clearMenus)
439     .on('click.dropdown touchstart.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() })
440     .on('click.dropdown.data-api touchstart.dropdown.data-api'  , toggle, Dropdown.prototype.toggle)
441     .on('keydown.dropdown.data-api touchstart.dropdown.data-api', toggle + ', [role=menu]' , Dropdown.prototype.keydown)
443 }(window.jQuery);
444 /* =============================================================
445  * bootstrap-scrollspy.js v2.2.1
446  * http://twitter.github.com/bootstrap/javascript.html#scrollspy
447  * =============================================================
448  * Copyright 2012 Twitter, Inc.
450  * Licensed under the Apache License, Version 2.0 (the "License");
451  * you may not use this file except in compliance with the License.
452  * You may obtain a copy of the License at
454  * http://www.apache.org/licenses/LICENSE-2.0
456  * Unless required by applicable law or agreed to in writing, software
457  * distributed under the License is distributed on an "AS IS" BASIS,
458  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
459  * See the License for the specific language governing permissions and
460  * limitations under the License.
461  * ============================================================== */
464 !function ($) {
466   "use strict"; // jshint ;_;
469  /* SCROLLSPY CLASS DEFINITION
470   * ========================== */
472   function ScrollSpy(element, options) {
473     var process = $.proxy(this.process, this)
474       , $element = $(element).is('body') ? $(window) : $(element)
475       , href
476     this.options = $.extend({}, $.fn.scrollspy.defaults, options)
477     this.$scrollElement = $element.on('scroll.scroll-spy.data-api', process)
478     this.selector = (this.options.target
479       || ((href = $(element).attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7
480       || '') + ' .nav li > a'
481     this.$body = $('body')
482     this.refresh()
483     this.process()
484   }
486   ScrollSpy.prototype = {
488       constructor: ScrollSpy
490     , refresh: function () {
491         var self = this
492           , $targets
494         this.offsets = $([])
495         this.targets = $([])
497         $targets = this.$body
498           .find(this.selector)
499           .map(function () {
500             var $el = $(this)
501               , href = $el.data('target') || $el.attr('href')
502               , $href = /^#\w/.test(href) && $(href)
503             return ( $href
504               && $href.length
505               && [[ $href.position().top, href ]] ) || null
506           })
507           .sort(function (a, b) { return a[0] - b[0] })
508           .each(function () {
509             self.offsets.push(this[0])
510             self.targets.push(this[1])
511           })
512       }
514     , process: function () {
515         var scrollTop = this.$scrollElement.scrollTop() + this.options.offset
516           , scrollHeight = this.$scrollElement[0].scrollHeight || this.$body[0].scrollHeight
517           , maxScroll = scrollHeight - this.$scrollElement.height()
518           , offsets = this.offsets
519           , targets = this.targets
520           , activeTarget = this.activeTarget
521           , i
523         if (scrollTop >= maxScroll) {
524           return activeTarget != (i = targets.last()[0])
525             && this.activate ( i )
526         }
528         for (i = offsets.length; i--;) {
529           activeTarget != targets[i]
530             && scrollTop >= offsets[i]
531             && (!offsets[i + 1] || scrollTop <= offsets[i + 1])
532             && this.activate( targets[i] )
533         }
534       }
536     , activate: function (target) {
537         var active
538           , selector
540         this.activeTarget = target
542         $(this.selector)
543           .parent('.active')
544           .removeClass('active')
546         selector = this.selector
547           + '[data-target="' + target + '"],'
548           + this.selector + '[href="' + target + '"]'
550         active = $(selector)
551           .parent('li')
552           .addClass('active')
554         if (active.parent('.dropdown-menu').length)  {
555           active = active.closest('li.dropdown').addClass('active')
556         }
558         active.trigger('activate')
559       }
561   }
564  /* SCROLLSPY PLUGIN DEFINITION
565   * =========================== */
567   $.fn.scrollspy = function (option) {
568     return this.each(function () {
569       var $this = $(this)
570         , data = $this.data('scrollspy')
571         , options = typeof option == 'object' && option
572       if (!data) $this.data('scrollspy', (data = new ScrollSpy(this, options)))
573       if (typeof option == 'string') data[option]()
574     })
575   }
577   $.fn.scrollspy.Constructor = ScrollSpy
579   $.fn.scrollspy.defaults = {
580     offset: 10
581   }
584  /* SCROLLSPY DATA-API
585   * ================== */
587   $(window).on('load', function () {
588     $('[data-spy="scroll"]').each(function () {
589       var $spy = $(this)
590       $spy.scrollspy($spy.data())
591     })
592   })
594 }(window.jQuery);
595 /* ========================================================
596  * bootstrap-tab.js v2.2.1
597  * http://twitter.github.com/bootstrap/javascript.html#tabs
598  * ========================================================
599  * Copyright 2012 Twitter, Inc.
601  * Licensed under the Apache License, Version 2.0 (the "License");
602  * you may not use this file except in compliance with the License.
603  * You may obtain a copy of the License at
605  * http://www.apache.org/licenses/LICENSE-2.0
607  * Unless required by applicable law or agreed to in writing, software
608  * distributed under the License is distributed on an "AS IS" BASIS,
609  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
610  * See the License for the specific language governing permissions and
611  * limitations under the License.
612  * ======================================================== */
615 !function ($) {
617   "use strict"; // jshint ;_;
620  /* TAB CLASS DEFINITION
621   * ==================== */
623   var Tab = function (element) {
624     this.element = $(element)
625   }
627   Tab.prototype = {
629     constructor: Tab
631   , show: function () {
632       var $this = this.element
633         , $ul = $this.closest('ul:not(.dropdown-menu)')
634         , selector = $this.attr('data-target')
635         , previous
636         , $target
637         , e
639       if (!selector) {
640         selector = $this.attr('href')
641         selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
642       }
644       if ( $this.parent('li').hasClass('active') ) return
646       previous = $ul.find('.active:last a')[0]
648       e = $.Event('show', {
649         relatedTarget: previous
650       })
652       $this.trigger(e)
654       if (e.isDefaultPrevented()) return
656       $target = $(selector)
658       this.activate($this.parent('li'), $ul)
659       this.activate($target, $target.parent(), function () {
660         $this.trigger({
661           type: 'shown'
662         , relatedTarget: previous
663         })
664       })
665     }
667   , activate: function ( element, container, callback) {
668       var $active = container.find('> .active')
669         , transition = callback
670             && $.support.transition
671             && $active.hasClass('fade')
673       function next() {
674         $active
675           .removeClass('active')
676           .find('> .dropdown-menu > .active')
677           .removeClass('active')
679         element.addClass('active')
681         if (transition) {
682           element[0].offsetWidth // reflow for transition
683           element.addClass('in')
684         } else {
685           element.removeClass('fade')
686         }
688         if ( element.parent('.dropdown-menu') ) {
689           element.closest('li.dropdown').addClass('active')
690         }
692         callback && callback()
693       }
695       transition ?
696         $active.one($.support.transition.end, next) :
697         next()
699       $active.removeClass('in')
700     }
701   }
704  /* TAB PLUGIN DEFINITION
705   * ===================== */
707   $.fn.tab = function ( option ) {
708     return this.each(function () {
709       var $this = $(this)
710         , data = $this.data('tab')
711       if (!data) $this.data('tab', (data = new Tab(this)))
712       if (typeof option == 'string') data[option]()
713     })
714   }
716   $.fn.tab.Constructor = Tab
719  /* TAB DATA-API
720   * ============ */
722   $(document).on('click.tab.data-api', '[data-toggle="tab"], [data-toggle="pill"]', function (e) {
723     e.preventDefault()
724     $(this).tab('show')
725   })
727 }(window.jQuery);
728 /* ===========================================================
729  * bootstrap-tooltip.js v2.2.1
730  * http://twitter.github.com/bootstrap/javascript.html#tooltips
731  * Inspired by the original jQuery.tipsy by Jason Frame
732  * ===========================================================
733  * Copyright 2012 Twitter, Inc.
735  * Licensed under the Apache License, Version 2.0 (the "License");
736  * you may not use this file except in compliance with the License.
737  * You may obtain a copy of the License at
739  * http://www.apache.org/licenses/LICENSE-2.0
741  * Unless required by applicable law or agreed to in writing, software
742  * distributed under the License is distributed on an "AS IS" BASIS,
743  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
744  * See the License for the specific language governing permissions and
745  * limitations under the License.
746  * ========================================================== */
749 !function ($) {
751   "use strict"; // jshint ;_;
754  /* TOOLTIP PUBLIC CLASS DEFINITION
755   * =============================== */
757   var Tooltip = function (element, options) {
758     this.init('tooltip', element, options)
759   }
761   Tooltip.prototype = {
763     constructor: Tooltip
765   , init: function (type, element, options) {
766       var eventIn
767         , eventOut
769       this.type = type
770       this.$element = $(element)
771       this.options = this.getOptions(options)
772       this.enabled = true
774       if (this.options.trigger == 'click') {
775         this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this))
776       } else if (this.options.trigger != 'manual') {
777         eventIn = this.options.trigger == 'hover' ? 'mouseenter' : 'focus'
778         eventOut = this.options.trigger == 'hover' ? 'mouseleave' : 'blur'
779         this.$element.on(eventIn + '.' + this.type, this.options.selector, $.proxy(this.enter, this))
780         this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this))
781       }
783       this.options.selector ?
784         (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) :
785         this.fixTitle()
786     }
788   , getOptions: function (options) {
789       options = $.extend({}, $.fn[this.type].defaults, options, this.$element.data())
791       if (options.delay && typeof options.delay == 'number') {
792         options.delay = {
793           show: options.delay
794         , hide: options.delay
795         }
796       }
798       return options
799     }
801   , enter: function (e) {
802       var self = $(e.currentTarget)[this.type](this._options).data(this.type)
804       if (!self.options.delay || !self.options.delay.show) return self.show()
806       clearTimeout(this.timeout)
807       self.hoverState = 'in'
808       this.timeout = setTimeout(function() {
809         if (self.hoverState == 'in') self.show()
810       }, self.options.delay.show)
811     }
813   , leave: function (e) {
814       var self = $(e.currentTarget)[this.type](this._options).data(this.type)
816       if (this.timeout) clearTimeout(this.timeout)
817       if (!self.options.delay || !self.options.delay.hide) return self.hide()
819       self.hoverState = 'out'
820       this.timeout = setTimeout(function() {
821         if (self.hoverState == 'out') self.hide()
822       }, self.options.delay.hide)
823     }
825   , show: function () {
826       var $tip
827         , inside
828         , pos
829         , actualWidth
830         , actualHeight
831         , placement
832         , tp
834       if (this.hasContent() && this.enabled) {
835         $tip = this.tip()
836         this.setContent()
838         if (this.options.animation) {
839           $tip.addClass('fade')
840         }
842         placement = typeof this.options.placement == 'function' ?
843           this.options.placement.call(this, $tip[0], this.$element[0]) :
844           this.options.placement
846         inside = /in/.test(placement)
848         $tip
849           .detach()
850           .css({ top: 0, left: 0, display: 'block' })
851           .insertAfter(this.$element)
853         pos = this.getPosition(inside)
855         actualWidth = $tip[0].offsetWidth
856         actualHeight = $tip[0].offsetHeight
858         switch (inside ? placement.split(' ')[1] : placement) {
859           case 'bottom':
860             tp = {top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2}
861             break
862           case 'top':
863             tp = {top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2}
864             break
865           case 'left':
866             tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth}
867             break
868           case 'right':
869             tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width}
870             break
871         }
873         $tip
874           .offset(tp)
875           .addClass(placement)
876           .addClass('in')
877       }
878     }
880   , setContent: function () {
881       var $tip = this.tip()
882         , title = this.getTitle()
884       $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title)
885       $tip.removeClass('fade in top bottom left right')
886     }
888   , hide: function () {
889       var that = this
890         , $tip = this.tip()
892       $tip.removeClass('in')
894       function removeWithAnimation() {
895         var timeout = setTimeout(function () {
896           $tip.off($.support.transition.end).detach()
897         }, 500)
899         $tip.one($.support.transition.end, function () {
900           clearTimeout(timeout)
901           $tip.detach()
902         })
903       }
905       $.support.transition && this.$tip.hasClass('fade') ?
906         removeWithAnimation() :
907         $tip.detach()
909       return this
910     }
912   , fixTitle: function () {
913       var $e = this.$element
914       if ($e.attr('title') || typeof($e.attr('data-original-title')) != 'string') {
915         $e.attr('data-original-title', $e.attr('title') || '').removeAttr('title')
916       }
917     }
919   , hasContent: function () {
920       return this.getTitle()
921     }
923   , getPosition: function (inside) {
924       return $.extend({}, (inside ? {top: 0, left: 0} : this.$element.offset()), {
925         width: this.$element[0].offsetWidth
926       , height: this.$element[0].offsetHeight
927       })
928     }
930   , getTitle: function () {
931       var title
932         , $e = this.$element
933         , o = this.options
935       title = $e.attr('data-original-title')
936         || (typeof o.title == 'function' ? o.title.call($e[0]) :  o.title)
938       return title
939     }
941   , tip: function () {
942       return this.$tip = this.$tip || $(this.options.template)
943     }
945   , validate: function () {
946       if (!this.$element[0].parentNode) {
947         this.hide()
948         this.$element = null
949         this.options = null
950       }
951     }
953   , enable: function () {
954       this.enabled = true
955     }
957   , disable: function () {
958       this.enabled = false
959     }
961   , toggleEnabled: function () {
962       this.enabled = !this.enabled
963     }
965   , toggle: function (e) {
966       var self = $(e.currentTarget)[this.type](this._options).data(this.type)
967       self[self.tip().hasClass('in') ? 'hide' : 'show']()
968     }
970   , destroy: function () {
971       this.hide().$element.off('.' + this.type).removeData(this.type)
972     }
974   }
977  /* TOOLTIP PLUGIN DEFINITION
978   * ========================= */
980   $.fn.tooltip = function ( option ) {
981     return this.each(function () {
982       var $this = $(this)
983         , data = $this.data('tooltip')
984         , options = typeof option == 'object' && option
985       if (!data) $this.data('tooltip', (data = new Tooltip(this, options)))
986       if (typeof option == 'string') data[option]()
987     })
988   }
990   $.fn.tooltip.Constructor = Tooltip
992   $.fn.tooltip.defaults = {
993     animation: true
994   , placement: 'top'
995   , selector: false
996   , template: '<div class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>'
997   , trigger: 'hover'
998   , title: ''
999   , delay: 0
1000   , html: false
1001   }
1003 }(window.jQuery);
1004 /* ===========================================================
1005  * bootstrap-popover.js v2.2.1
1006  * http://twitter.github.com/bootstrap/javascript.html#popovers
1007  * ===========================================================
1008  * Copyright 2012 Twitter, Inc.
1010  * Licensed under the Apache License, Version 2.0 (the "License");
1011  * you may not use this file except in compliance with the License.
1012  * You may obtain a copy of the License at
1014  * http://www.apache.org/licenses/LICENSE-2.0
1016  * Unless required by applicable law or agreed to in writing, software
1017  * distributed under the License is distributed on an "AS IS" BASIS,
1018  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1019  * See the License for the specific language governing permissions and
1020  * limitations under the License.
1021  * =========================================================== */
1024 !function ($) {
1026   "use strict"; // jshint ;_;
1029  /* POPOVER PUBLIC CLASS DEFINITION
1030   * =============================== */
1032   var Popover = function (element, options) {
1033     this.init('popover', element, options)
1034   }
1037   /* NOTE: POPOVER EXTENDS BOOTSTRAP-TOOLTIP.js
1038      ========================================== */
1040   Popover.prototype = $.extend({}, $.fn.tooltip.Constructor.prototype, {
1042     constructor: Popover
1044   , setContent: function () {
1045       var $tip = this.tip()
1046         , title = this.getTitle()
1047         , content = this.getContent()
1049       $tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title)
1050       $tip.find('.popover-content > *')[this.options.html ? 'html' : 'text'](content)
1052       $tip.removeClass('fade top bottom left right in')
1053     }
1055   , hasContent: function () {
1056       return this.getTitle() || this.getContent()
1057     }
1059   , getContent: function () {
1060       var content
1061         , $e = this.$element
1062         , o = this.options
1064       content = $e.attr('data-content')
1065         || (typeof o.content == 'function' ? o.content.call($e[0]) :  o.content)
1067       return content
1068     }
1070   , tip: function () {
1071       if (!this.$tip) {
1072         this.$tip = $(this.options.template)
1073       }
1074       return this.$tip
1075     }
1077   , destroy: function () {
1078       this.hide().$element.off('.' + this.type).removeData(this.type)
1079     }
1081   })
1084  /* POPOVER PLUGIN DEFINITION
1085   * ======================= */
1087   $.fn.popover = function (option) {
1088     return this.each(function () {
1089       var $this = $(this)
1090         , data = $this.data('popover')
1091         , options = typeof option == 'object' && option
1092       if (!data) $this.data('popover', (data = new Popover(this, options)))
1093       if (typeof option == 'string') data[option]()
1094     })
1095   }
1097   $.fn.popover.Constructor = Popover
1099   $.fn.popover.defaults = $.extend({} , $.fn.tooltip.defaults, {
1100     placement: 'right'
1101   , trigger: 'click'
1102   , content: ''
1103   , template: '<div class="popover"><div class="arrow"></div><div class="popover-inner"><h3 class="popover-title"></h3><div class="popover-content"><p></p></div></div></div>'
1104   })
1106 }(window.jQuery);
1107 /* ==========================================================
1108  * bootstrap-affix.js v2.2.1
1109  * http://twitter.github.com/bootstrap/javascript.html#affix
1110  * ==========================================================
1111  * Copyright 2012 Twitter, Inc.
1113  * Licensed under the Apache License, Version 2.0 (the "License");
1114  * you may not use this file except in compliance with the License.
1115  * You may obtain a copy of the License at
1117  * http://www.apache.org/licenses/LICENSE-2.0
1119  * Unless required by applicable law or agreed to in writing, software
1120  * distributed under the License is distributed on an "AS IS" BASIS,
1121  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1122  * See the License for the specific language governing permissions and
1123  * limitations under the License.
1124  * ========================================================== */
1127 !function ($) {
1129   "use strict"; // jshint ;_;
1132  /* AFFIX CLASS DEFINITION
1133   * ====================== */
1135   var Affix = function (element, options) {
1136     this.options = $.extend({}, $.fn.affix.defaults, options)
1137     this.$window = $(window)
1138       .on('scroll.affix.data-api', $.proxy(this.checkPosition, this))
1139       .on('click.affix.data-api',  $.proxy(function () { setTimeout($.proxy(this.checkPosition, this), 1) }, this))
1140     this.$element = $(element)
1141     this.checkPosition()
1142   }
1144   Affix.prototype.checkPosition = function () {
1145     if (!this.$element.is(':visible')) return
1147     var scrollHeight = $(document).height()
1148       , scrollTop = this.$window.scrollTop()
1149       , position = this.$element.offset()
1150       , offset = this.options.offset
1151       , offsetBottom = offset.bottom
1152       , offsetTop = offset.top
1153       , reset = 'affix affix-top affix-bottom'
1154       , affix
1156     if (typeof offset != 'object') offsetBottom = offsetTop = offset
1157     if (typeof offsetTop == 'function') offsetTop = offset.top()
1158     if (typeof offsetBottom == 'function') offsetBottom = offset.bottom()
1160     affix = this.unpin != null && (scrollTop + this.unpin <= position.top) ?
1161       false    : offsetBottom != null && (position.top + this.$element.height() >= scrollHeight - offsetBottom) ?
1162       'bottom' : offsetTop != null && scrollTop <= offsetTop ?
1163       'top'    : false
1165     if (this.affixed === affix) return
1167     this.affixed = affix
1168     this.unpin = affix == 'bottom' ? position.top - scrollTop : null
1170     this.$element.removeClass(reset).addClass('affix' + (affix ? '-' + affix : ''))
1171   }
1174  /* AFFIX PLUGIN DEFINITION
1175   * ======================= */
1177   $.fn.affix = function (option) {
1178     return this.each(function () {
1179       var $this = $(this)
1180         , data = $this.data('affix')
1181         , options = typeof option == 'object' && option
1182       if (!data) $this.data('affix', (data = new Affix(this, options)))
1183       if (typeof option == 'string') data[option]()
1184     })
1185   }
1187   $.fn.affix.Constructor = Affix
1189   $.fn.affix.defaults = {
1190     offset: 0
1191   }
1194  /* AFFIX DATA-API
1195   * ============== */
1197   $(window).on('load', function () {
1198     $('[data-spy="affix"]').each(function () {
1199       var $spy = $(this)
1200         , data = $spy.data()
1202       data.offset = data.offset || {}
1204       data.offsetBottom && (data.offset.bottom = data.offsetBottom)
1205       data.offsetTop && (data.offset.top = data.offsetTop)
1207       $spy.affix(data)
1208     })
1209   })
1212 }(window.jQuery);
1213 /* ==========================================================
1214  * bootstrap-alert.js v2.2.1
1215  * http://twitter.github.com/bootstrap/javascript.html#alerts
1216  * ==========================================================
1217  * Copyright 2012 Twitter, Inc.
1219  * Licensed under the Apache License, Version 2.0 (the "License");
1220  * you may not use this file except in compliance with the License.
1221  * You may obtain a copy of the License at
1223  * http://www.apache.org/licenses/LICENSE-2.0
1225  * Unless required by applicable law or agreed to in writing, software
1226  * distributed under the License is distributed on an "AS IS" BASIS,
1227  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1228  * See the License for the specific language governing permissions and
1229  * limitations under the License.
1230  * ========================================================== */
1233 !function ($) {
1235   "use strict"; // jshint ;_;
1238  /* ALERT CLASS DEFINITION
1239   * ====================== */
1241   var dismiss = '[data-dismiss="alert"]'
1242     , Alert = function (el) {
1243         $(el).on('click', dismiss, this.close)
1244       }
1246   Alert.prototype.close = function (e) {
1247     var $this = $(this)
1248       , selector = $this.attr('data-target')
1249       , $parent
1251     if (!selector) {
1252       selector = $this.attr('href')
1253       selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
1254     }
1256     $parent = $(selector)
1258     e && e.preventDefault()
1260     $parent.length || ($parent = $this.hasClass('alert') ? $this : $this.parent())
1262     $parent.trigger(e = $.Event('close'))
1264     if (e.isDefaultPrevented()) return
1266     $parent.removeClass('in')
1268     function removeElement() {
1269       $parent
1270         .trigger('closed')
1271         .remove()
1272     }
1274     $.support.transition && $parent.hasClass('fade') ?
1275       $parent.on($.support.transition.end, removeElement) :
1276       removeElement()
1277   }
1280  /* ALERT PLUGIN DEFINITION
1281   * ======================= */
1283   $.fn.alert = function (option) {
1284     return this.each(function () {
1285       var $this = $(this)
1286         , data = $this.data('alert')
1287       if (!data) $this.data('alert', (data = new Alert(this)))
1288       if (typeof option == 'string') data[option].call($this)
1289     })
1290   }
1292   $.fn.alert.Constructor = Alert
1295  /* ALERT DATA-API
1296   * ============== */
1298   $(document).on('click.alert.data-api', dismiss, Alert.prototype.close)
1300 }(window.jQuery);
1301 /* ============================================================
1302  * bootstrap-button.js v2.2.1
1303  * http://twitter.github.com/bootstrap/javascript.html#buttons
1304  * ============================================================
1305  * Copyright 2012 Twitter, Inc.
1307  * Licensed under the Apache License, Version 2.0 (the "License");
1308  * you may not use this file except in compliance with the License.
1309  * You may obtain a copy of the License at
1311  * http://www.apache.org/licenses/LICENSE-2.0
1313  * Unless required by applicable law or agreed to in writing, software
1314  * distributed under the License is distributed on an "AS IS" BASIS,
1315  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1316  * See the License for the specific language governing permissions and
1317  * limitations under the License.
1318  * ============================================================ */
1321 !function ($) {
1323   "use strict"; // jshint ;_;
1326  /* BUTTON PUBLIC CLASS DEFINITION
1327   * ============================== */
1329   var Button = function (element, options) {
1330     this.$element = $(element)
1331     this.options = $.extend({}, $.fn.button.defaults, options)
1332   }
1334   Button.prototype.setState = function (state) {
1335     var d = 'disabled'
1336       , $el = this.$element
1337       , data = $el.data()
1338       , val = $el.is('input') ? 'val' : 'html'
1340     state = state + 'Text'
1341     data.resetText || $el.data('resetText', $el[val]())
1343     $el[val](data[state] || this.options[state])
1345     // push to event loop to allow forms to submit
1346     setTimeout(function () {
1347       state == 'loadingText' ?
1348         $el.addClass(d).attr(d, d) :
1349         $el.removeClass(d).removeAttr(d)
1350     }, 0)
1351   }
1353   Button.prototype.toggle = function () {
1354     var $parent = this.$element.closest('[data-toggle="buttons-radio"]')
1356     $parent && $parent
1357       .find('.active')
1358       .removeClass('active')
1360     this.$element.toggleClass('active')
1361   }
1364  /* BUTTON PLUGIN DEFINITION
1365   * ======================== */
1367   $.fn.button = function (option) {
1368     return this.each(function () {
1369       var $this = $(this)
1370         , data = $this.data('button')
1371         , options = typeof option == 'object' && option
1372       if (!data) $this.data('button', (data = new Button(this, options)))
1373       if (option == 'toggle') data.toggle()
1374       else if (option) data.setState(option)
1375     })
1376   }
1378   $.fn.button.defaults = {
1379     loadingText: 'loading...'
1380   }
1382   $.fn.button.Constructor = Button
1385  /* BUTTON DATA-API
1386   * =============== */
1388   $(document).on('click.button.data-api', '[data-toggle^=button]', function (e) {
1389     var $btn = $(e.target)
1390     if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn')
1391     $btn.button('toggle')
1392   })
1394 }(window.jQuery);
1395 /* =============================================================
1396  * bootstrap-collapse.js v2.2.1
1397  * http://twitter.github.com/bootstrap/javascript.html#collapse
1398  * =============================================================
1399  * Copyright 2012 Twitter, Inc.
1401  * Licensed under the Apache License, Version 2.0 (the "License");
1402  * you may not use this file except in compliance with the License.
1403  * You may obtain a copy of the License at
1405  * http://www.apache.org/licenses/LICENSE-2.0
1407  * Unless required by applicable law or agreed to in writing, software
1408  * distributed under the License is distributed on an "AS IS" BASIS,
1409  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1410  * See the License for the specific language governing permissions and
1411  * limitations under the License.
1412  * ============================================================ */
1415 !function ($) {
1417   "use strict"; // jshint ;_;
1420  /* COLLAPSE PUBLIC CLASS DEFINITION
1421   * ================================ */
1423   var Collapse = function (element, options) {
1424     this.$element = $(element)
1425     this.options = $.extend({}, $.fn.collapse.defaults, options)
1427     if (this.options.parent) {
1428       this.$parent = $(this.options.parent)
1429     }
1431     this.options.toggle && this.toggle()
1432   }
1434   Collapse.prototype = {
1436     constructor: Collapse
1438   , dimension: function () {
1439       var hasWidth = this.$element.hasClass('width')
1440       return hasWidth ? 'width' : 'height'
1441     }
1443   , show: function () {
1444       var dimension
1445         , scroll
1446         , actives
1447         , hasData
1449       if (this.transitioning) return
1451       dimension = this.dimension()
1452       scroll = $.camelCase(['scroll', dimension].join('-'))
1453       actives = this.$parent && this.$parent.find('> .accordion-group > .in')
1455       if (actives && actives.length) {
1456         hasData = actives.data('collapse')
1457         if (hasData && hasData.transitioning) return
1458         actives.collapse('hide')
1459         hasData || actives.data('collapse', null)
1460       }
1462       this.$element[dimension](0)
1463       this.transition('addClass', $.Event('show'), 'shown')
1464       $.support.transition && this.$element[dimension](this.$element[0][scroll])
1465     }
1467   , hide: function () {
1468       var dimension
1469       if (this.transitioning) return
1470       dimension = this.dimension()
1471       this.reset(this.$element[dimension]())
1472       this.transition('removeClass', $.Event('hide'), 'hidden')
1473       this.$element[dimension](0)
1474     }
1476   , reset: function (size) {
1477       var dimension = this.dimension()
1479       this.$element
1480         .removeClass('collapse')
1481         [dimension](size || 'auto')
1482         [0].offsetWidth
1484       this.$element[size !== null ? 'addClass' : 'removeClass']('collapse')
1486       return this
1487     }
1489   , transition: function (method, startEvent, completeEvent) {
1490       var that = this
1491         , complete = function () {
1492             if (startEvent.type == 'show') that.reset()
1493             that.transitioning = 0
1494             that.$element.trigger(completeEvent)
1495           }
1497       this.$element.trigger(startEvent)
1499       if (startEvent.isDefaultPrevented()) return
1501       this.transitioning = 1
1503       this.$element[method]('in')
1505       $.support.transition && this.$element.hasClass('collapse') ?
1506         this.$element.one($.support.transition.end, complete) :
1507         complete()
1508     }
1510   , toggle: function () {
1511       this[this.$element.hasClass('in') ? 'hide' : 'show']()
1512     }
1514   }
1517  /* COLLAPSIBLE PLUGIN DEFINITION
1518   * ============================== */
1520   $.fn.collapse = function (option) {
1521     return this.each(function () {
1522       var $this = $(this)
1523         , data = $this.data('collapse')
1524         , options = typeof option == 'object' && option
1525       if (!data) $this.data('collapse', (data = new Collapse(this, options)))
1526       if (typeof option == 'string') data[option]()
1527     })
1528   }
1530   $.fn.collapse.defaults = {
1531     toggle: true
1532   }
1534   $.fn.collapse.Constructor = Collapse
1537  /* COLLAPSIBLE DATA-API
1538   * ==================== */
1540   $(document).on('click.collapse.data-api', '[data-toggle=collapse]', function (e) {
1541     var $this = $(this), href
1542       , target = $this.attr('data-target')
1543         || e.preventDefault()
1544         || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7
1545       , option = $(target).data('collapse') ? 'toggle' : $this.data()
1546     $this[$(target).hasClass('in') ? 'addClass' : 'removeClass']('collapsed')
1547     $(target).collapse(option)
1548   })
1550 }(window.jQuery);
1551 /* ==========================================================
1552  * bootstrap-carousel.js v2.2.1
1553  * http://twitter.github.com/bootstrap/javascript.html#carousel
1554  * ==========================================================
1555  * Copyright 2012 Twitter, Inc.
1557  * Licensed under the Apache License, Version 2.0 (the "License");
1558  * you may not use this file except in compliance with the License.
1559  * You may obtain a copy of the License at
1561  * http://www.apache.org/licenses/LICENSE-2.0
1563  * Unless required by applicable law or agreed to in writing, software
1564  * distributed under the License is distributed on an "AS IS" BASIS,
1565  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1566  * See the License for the specific language governing permissions and
1567  * limitations under the License.
1568  * ========================================================== */
1571 !function ($) {
1573   "use strict"; // jshint ;_;
1576  /* CAROUSEL CLASS DEFINITION
1577   * ========================= */
1579   var Carousel = function (element, options) {
1580     this.$element = $(element)
1581     this.options = options
1582     this.options.slide && this.slide(this.options.slide)
1583     this.options.pause == 'hover' && this.$element
1584       .on('mouseenter', $.proxy(this.pause, this))
1585       .on('mouseleave', $.proxy(this.cycle, this))
1586   }
1588   Carousel.prototype = {
1590     cycle: function (e) {
1591       if (!e) this.paused = false
1592       this.options.interval
1593         && !this.paused
1594         && (this.interval = setInterval($.proxy(this.next, this), this.options.interval))
1595       return this
1596     }
1598   , to: function (pos) {
1599       var $active = this.$element.find('.item.active')
1600         , children = $active.parent().children()
1601         , activePos = children.index($active)
1602         , that = this
1604       if (pos > (children.length - 1) || pos < 0) return
1606       if (this.sliding) {
1607         return this.$element.one('slid', function () {
1608           that.to(pos)
1609         })
1610       }
1612       if (activePos == pos) {
1613         return this.pause().cycle()
1614       }
1616       return this.slide(pos > activePos ? 'next' : 'prev', $(children[pos]))
1617     }
1619   , pause: function (e) {
1620       if (!e) this.paused = true
1621       if (this.$element.find('.next, .prev').length && $.support.transition.end) {
1622         this.$element.trigger($.support.transition.end)
1623         this.cycle()
1624       }
1625       clearInterval(this.interval)
1626       this.interval = null
1627       return this
1628     }
1630   , next: function () {
1631       if (this.sliding) return
1632       return this.slide('next')
1633     }
1635   , prev: function () {
1636       if (this.sliding) return
1637       return this.slide('prev')
1638     }
1640   , slide: function (type, next) {
1641       var $active = this.$element.find('.item.active')
1642         , $next = next || $active[type]()
1643         , isCycling = this.interval
1644         , direction = type == 'next' ? 'left' : 'right'
1645         , fallback  = type == 'next' ? 'first' : 'last'
1646         , that = this
1647         , e
1649       this.sliding = true
1651       isCycling && this.pause()
1653       $next = $next.length ? $next : this.$element.find('.item')[fallback]()
1655       e = $.Event('slide', {
1656         relatedTarget: $next[0]
1657       })
1659       if ($next.hasClass('active')) return
1661       if ($.support.transition && this.$element.hasClass('slide')) {
1662         this.$element.trigger(e)
1663         if (e.isDefaultPrevented()) return
1664         $next.addClass(type)
1665         $next[0].offsetWidth // force reflow
1666         $active.addClass(direction)
1667         $next.addClass(direction)
1668         this.$element.one($.support.transition.end, function () {
1669           $next.removeClass([type, direction].join(' ')).addClass('active')
1670           $active.removeClass(['active', direction].join(' '))
1671           that.sliding = false
1672           setTimeout(function () { that.$element.trigger('slid') }, 0)
1673         })
1674       } else {
1675         this.$element.trigger(e)
1676         if (e.isDefaultPrevented()) return
1677         $active.removeClass('active')
1678         $next.addClass('active')
1679         this.sliding = false
1680         this.$element.trigger('slid')
1681       }
1683       isCycling && this.cycle()
1685       return this
1686     }
1688   }
1691  /* CAROUSEL PLUGIN DEFINITION
1692   * ========================== */
1694   $.fn.carousel = function (option) {
1695     return this.each(function () {
1696       var $this = $(this)
1697         , data = $this.data('carousel')
1698         , options = $.extend({}, $.fn.carousel.defaults, typeof option == 'object' && option)
1699         , action = typeof option == 'string' ? option : options.slide
1700       if (!data) $this.data('carousel', (data = new Carousel(this, options)))
1701       if (typeof option == 'number') data.to(option)
1702       else if (action) data[action]()
1703       else if (options.interval) data.cycle()
1704     })
1705   }
1707   $.fn.carousel.defaults = {
1708     interval: 5000
1709   , pause: 'hover'
1710   }
1712   $.fn.carousel.Constructor = Carousel
1715  /* CAROUSEL DATA-API
1716   * ================= */
1718   $(document).on('click.carousel.data-api', '[data-slide]', function (e) {
1719     var $this = $(this), href
1720       , $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7
1721       , options = $.extend({}, $target.data(), $this.data())
1722     $target.carousel(options)
1723     e.preventDefault()
1724   })
1726 }(window.jQuery);
1727 /* =============================================================
1728  * bootstrap-typeahead.js v2.2.1
1729  * http://twitter.github.com/bootstrap/javascript.html#typeahead
1730  * =============================================================
1731  * Copyright 2012 Twitter, Inc.
1733  * Licensed under the Apache License, Version 2.0 (the "License");
1734  * you may not use this file except in compliance with the License.
1735  * You may obtain a copy of the License at
1737  * http://www.apache.org/licenses/LICENSE-2.0
1739  * Unless required by applicable law or agreed to in writing, software
1740  * distributed under the License is distributed on an "AS IS" BASIS,
1741  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1742  * See the License for the specific language governing permissions and
1743  * limitations under the License.
1744  * ============================================================ */
1747 !function($){
1749   "use strict"; // jshint ;_;
1752  /* TYPEAHEAD PUBLIC CLASS DEFINITION
1753   * ================================= */
1755   var Typeahead = function (element, options) {
1756     this.$element = $(element)
1757     this.options = $.extend({}, $.fn.typeahead.defaults, options)
1758     this.matcher = this.options.matcher || this.matcher
1759     this.sorter = this.options.sorter || this.sorter
1760     this.highlighter = this.options.highlighter || this.highlighter
1761     this.updater = this.options.updater || this.updater
1762     this.$menu = $(this.options.menu).appendTo('body')
1763     this.source = this.options.source
1764     this.shown = false
1765     this.listen()
1766   }
1768   Typeahead.prototype = {
1770     constructor: Typeahead
1772   , select: function () {
1773       var val = this.$menu.find('.active').attr('data-value')
1774       this.$element
1775         .val(this.updater(val))
1776         .change()
1777       return this.hide()
1778     }
1780   , updater: function (item) {
1781       return item
1782     }
1784   , show: function () {
1785       var pos = $.extend({}, this.$element.offset(), {
1786         height: this.$element[0].offsetHeight
1787       })
1789       this.$menu.css({
1790         top: pos.top + pos.height
1791       , left: pos.left
1792       })
1794       this.$menu.show()
1795       this.shown = true
1796       return this
1797     }
1799   , hide: function () {
1800       this.$menu.hide()
1801       this.shown = false
1802       return this
1803     }
1805   , lookup: function (event) {
1806       var items
1808       this.query = this.$element.val()
1810       if (!this.query || this.query.length < this.options.minLength) {
1811         return this.shown ? this.hide() : this
1812       }
1814       items = $.isFunction(this.source) ? this.source(this.query, $.proxy(this.process, this)) : this.source
1816       return items ? this.process(items) : this
1817     }
1819   , process: function (items) {
1820       var that = this
1822       items = $.grep(items, function (item) {
1823         return that.matcher(item)
1824       })
1826       items = this.sorter(items)
1828       if (!items.length) {
1829         return this.shown ? this.hide() : this
1830       }
1832       return this.render(items.slice(0, this.options.items)).show()
1833     }
1835   , matcher: function (item) {
1836       return ~item.toLowerCase().indexOf(this.query.toLowerCase())
1837     }
1839   , sorter: function (items) {
1840       var beginswith = []
1841         , caseSensitive = []
1842         , caseInsensitive = []
1843         , item
1845       while (item = items.shift()) {
1846         if (!item.toLowerCase().indexOf(this.query.toLowerCase())) beginswith.push(item)
1847         else if (~item.indexOf(this.query)) caseSensitive.push(item)
1848         else caseInsensitive.push(item)
1849       }
1851       return beginswith.concat(caseSensitive, caseInsensitive)
1852     }
1854   , highlighter: function (item) {
1855       var query = this.query.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, '\\$&')
1856       return item.replace(new RegExp('(' + query + ')', 'ig'), function ($1, match) {
1857         return '<strong>' + match + '</strong>'
1858       })
1859     }
1861   , render: function (items) {
1862       var that = this
1864       items = $(items).map(function (i, item) {
1865         i = $(that.options.item).attr('data-value', item)
1866         i.find('a').html(that.highlighter(item))
1867         return i[0]
1868       })
1870       items.first().addClass('active')
1871       this.$menu.html(items)
1872       return this
1873     }
1875   , next: function (event) {
1876       var active = this.$menu.find('.active').removeClass('active')
1877         , next = active.next()
1879       if (!next.length) {
1880         next = $(this.$menu.find('li')[0])
1881       }
1883       next.addClass('active')
1884     }
1886   , prev: function (event) {
1887       var active = this.$menu.find('.active').removeClass('active')
1888         , prev = active.prev()
1890       if (!prev.length) {
1891         prev = this.$menu.find('li').last()
1892       }
1894       prev.addClass('active')
1895     }
1897   , listen: function () {
1898       this.$element
1899         .on('blur',     $.proxy(this.blur, this))
1900         .on('keypress', $.proxy(this.keypress, this))
1901         .on('keyup',    $.proxy(this.keyup, this))
1903       if (this.eventSupported('keydown')) {
1904         this.$element.on('keydown', $.proxy(this.keydown, this))
1905       }
1907       this.$menu
1908         .on('click', $.proxy(this.click, this))
1909         .on('mouseenter', 'li', $.proxy(this.mouseenter, this))
1910     }
1912   , eventSupported: function(eventName) {
1913       var isSupported = eventName in this.$element
1914       if (!isSupported) {
1915         this.$element.setAttribute(eventName, 'return;')
1916         isSupported = typeof this.$element[eventName] === 'function'
1917       }
1918       return isSupported
1919     }
1921   , move: function (e) {
1922       if (!this.shown) return
1924       switch(e.keyCode) {
1925         case 9: // tab
1926         case 13: // enter
1927         case 27: // escape
1928           e.preventDefault()
1929           break
1931         case 38: // up arrow
1932           e.preventDefault()
1933           this.prev()
1934           break
1936         case 40: // down arrow
1937           e.preventDefault()
1938           this.next()
1939           break
1940       }
1942       e.stopPropagation()
1943     }
1945   , keydown: function (e) {
1946       this.suppressKeyPressRepeat = !~$.inArray(e.keyCode, [40,38,9,13,27])
1947       this.move(e)
1948     }
1950   , keypress: function (e) {
1951       if (this.suppressKeyPressRepeat) return
1952       this.move(e)
1953     }
1955   , keyup: function (e) {
1956       switch(e.keyCode) {
1957         case 40: // down arrow
1958         case 38: // up arrow
1959         case 16: // shift
1960         case 17: // ctrl
1961         case 18: // alt
1962           break
1964         case 9: // tab
1965         case 13: // enter
1966           if (!this.shown) return
1967           this.select()
1968           break
1970         case 27: // escape
1971           if (!this.shown) return
1972           this.hide()
1973           break
1975         default:
1976           this.lookup()
1977       }
1979       e.stopPropagation()
1980       e.preventDefault()
1981   }
1983   , blur: function (e) {
1984       var that = this
1985       setTimeout(function () { that.hide() }, 150)
1986     }
1988   , click: function (e) {
1989       e.stopPropagation()
1990       e.preventDefault()
1991       this.select()
1992     }
1994   , mouseenter: function (e) {
1995       this.$menu.find('.active').removeClass('active')
1996       $(e.currentTarget).addClass('active')
1997     }
1999   }
2002   /* TYPEAHEAD PLUGIN DEFINITION
2003    * =========================== */
2005   $.fn.typeahead = function (option) {
2006     return this.each(function () {
2007       var $this = $(this)
2008         , data = $this.data('typeahead')
2009         , options = typeof option == 'object' && option
2010       if (!data) $this.data('typeahead', (data = new Typeahead(this, options)))
2011       if (typeof option == 'string') data[option]()
2012     })
2013   }
2015   $.fn.typeahead.defaults = {
2016     source: []
2017   , items: 8
2018   , menu: '<ul class="typeahead dropdown-menu"></ul>'
2019   , item: '<li><a href="#"></a></li>'
2020   , minLength: 1
2021   }
2023   $.fn.typeahead.Constructor = Typeahead
2026  /*   TYPEAHEAD DATA-API
2027   * ================== */
2029   $(document).on('focus.typeahead.data-api', '[data-provide="typeahead"]', function (e) {
2030     var $this = $(this)
2031     if ($this.data('typeahead')) return
2032     e.preventDefault()
2033     $this.typeahead($this.data())
2034   })
2036 }(window.jQuery);