├── .gitignore ├── .gitmodules ├── Gemfile ├── README.md ├── Rakefile ├── app └── assets │ ├── fonts │ └── twitter │ │ ├── glyphicons-halflings-regular.eot │ │ ├── glyphicons-halflings-regular.svg │ │ ├── glyphicons-halflings-regular.ttf │ │ └── glyphicons-halflings-regular.woff │ ├── javascripts │ └── twitter │ │ ├── bootstrap.js │ │ └── bootstrap │ │ ├── affix.js │ │ ├── alert.js │ │ ├── button.js │ │ ├── carousel.js │ │ ├── collapse.js │ │ ├── dropdown.js │ │ ├── modal.js │ │ ├── popover.js │ │ ├── scrollspy.js │ │ ├── tab.js │ │ ├── tooltip.js │ │ └── transition.js │ └── stylesheets │ └── twitter │ ├── bootstrap.scss │ └── bootstrap │ ├── _alerts.scss │ ├── _badges.scss │ ├── _bootstrap.scss │ ├── _breadcrumbs.scss │ ├── _button-groups.scss │ ├── _buttons.scss │ ├── _carousel.scss │ ├── _close.scss │ ├── _code.scss │ ├── _component-animations.scss │ ├── _dropdowns.scss │ ├── _forms.scss │ ├── _glyphicons.scss │ ├── _grid.scss │ ├── _input-groups.scss │ ├── _jumbotron.scss │ ├── _labels.scss │ ├── _list-group.scss │ ├── _media.scss │ ├── _mixins.scss │ ├── _modals.scss │ ├── _navbar.scss │ ├── _navs.scss │ ├── _normalize.scss │ ├── _pager.scss │ ├── _pagination.scss │ ├── _panels.scss │ ├── _popovers.scss │ ├── _print.scss │ ├── _progress-bars.scss │ ├── _responsive-utilities.scss │ ├── _scaffolding.scss │ ├── _tables.scss │ ├── _theme.scss │ ├── _thumbnails.scss │ ├── _tooltip.scss │ ├── _type.scss │ ├── _utilities.scss │ ├── _variables.scss │ └── _wells.scss ├── bootstrap-rails.gemspec ├── lib ├── bootstrap-rails.rb └── bootstrap-rails │ ├── engine.rb │ ├── railtie.rb │ └── version.rb ├── test └── test_helper.rb └── vendor └── assets └── javascripts └── holder.js /.gitignore: -------------------------------------------------------------------------------- 1 | *.gem 2 | *.rbc 3 | .bundle 4 | .config 5 | .yardoc 6 | Gemfile.lock 7 | InstalledFiles 8 | _yardoc 9 | coverage 10 | doc/ 11 | lib/bundler/man 12 | pkg 13 | rdoc 14 | spec/reports 15 | test/tmp 16 | test/version_tmp 17 | tmp 18 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "bootstrap"] 2 | path = bootstrap 3 | url = https://github.com/yury/bootstrap.git 4 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'http://rubygems.org' 2 | 3 | # Specify your gem's dependencies in bootstrap-rails.gemspec 4 | gemspec 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Deprecated 2 | 3 | Please use official [bootstrap-sass](https://github.com/twbs/bootstrap-sass) gem. 4 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env rake 2 | require 'bundler/gem_tasks' 3 | require 'rake/testtask' 4 | 5 | namespace :twitter do 6 | 7 | desc "Pulls Bootstrap Scss" 8 | task :pull do 9 | if !system "cd bootstrap && git pull" 10 | abort "...." 11 | end 12 | end 13 | 14 | BS_FONTS = FileList["bootstrap/fonts/*.*"] 15 | ASSETS_FONTS = BS_FONTS.pathmap("app/assets/fonts/twitter/%f") 16 | ASSETS_FONTS.zip(BS_FONTS).each do |target, source| 17 | file target => [source] { cp source, target, verbose: true } 18 | end 19 | 20 | BS_JS = FileList["bootstrap/js/*.*"] 21 | ASSETS_JS = BS_JS.pathmap("app/assets/javascripts/twitter/bootstrap/%f") 22 | ASSETS_JS.zip(BS_JS).each do |target, source| 23 | file target => [source] { cp source, target, verbose: true } 24 | end 25 | 26 | BS_SCSS = FileList["bootstrap/scss/*.*"] 27 | ASSETS_SCSS = BS_SCSS.pathmap("app/assets/stylesheets/twitter/bootstrap/_%f") 28 | ASSETS_SCSS.zip(BS_SCSS).each do |target, source| 29 | target.gsub!(/__/, '_') 30 | file target => [source] { cp source, target, verbose: true } 31 | end 32 | 33 | desc "Update Bootstrap Fonts" 34 | task :fonts => ASSETS_FONTS 35 | 36 | desc "Update Bootstrap JS" 37 | task :js => ASSETS_JS do 38 | js = {} 39 | ASSETS_JS.pathmap("%f").each { |f| js[f] = 1 } 40 | 41 | # dependencies 42 | order = %w{transition.js alert.js button.js carousel.js collapse.js dropdown.js modal.js tooltip.js popover.js scrollspy.js tab.js affix.js} 43 | order.each_with_index {|o, i| js[o] = i } 44 | 45 | list = js.to_a.sort {|a,b| a[1] <=> b[1]}.map{|p| "twitter/bootstrap/#{p[0]}"} 46 | File.write "app/assets/javascripts/twitter/bootstrap.js", list.map {|f| "//= require #{f}"}.join("\n") 47 | end 48 | 49 | desc "Update Bootstrap Glyphicons icons" 50 | task :icons do 51 | vars_path = 'app/assets/stylesheets/twitter/bootstrap/_variables.scss' 52 | variables = File.read vars_path 53 | variables.sub!(/^\$icon-font-path:\s+".*"\s!default;/, "$icon-font-path: \"twitter/\" !default;") 54 | File.write(vars_path, variables) 55 | 56 | icons_path = 'app/assets/stylesheets/twitter/bootstrap/_glyphicons.scss' 57 | icons = File.read icons_path 58 | icons.gsub!(/url\(/, "font-url(") 59 | File.write(icons_path, icons) 60 | end 61 | 62 | desc "Update Bootstrap SCSS" 63 | task :scss => ASSETS_SCSS do 64 | File.write "app/assets/stylesheets/twitter/bootstrap.scss", '@import "twitter/bootstrap/bootstrap";' 65 | end 66 | 67 | desc "Clean gem assets files" 68 | task :clean do 69 | FileUtils.rm_rf 'app/assets' 70 | FileUtils.mkpath 'app/assets/fonts/twitter' 71 | FileUtils.mkpath 'app/assets/javascripts/twitter/bootstrap' 72 | FileUtils.mkpath 'app/assets/stylesheets/twitter/bootstrap' 73 | end 74 | 75 | desc "Update Bootstrap Assets" 76 | task :assets => [:pull, :clean, :fonts, :scss, :js, :icons] 77 | 78 | end 79 | 80 | Rake::TestTask.new do |t| 81 | t.libs << "test" 82 | t.test_files = FileList['test/*_test.rb'] 83 | t.verbose = true 84 | end 85 | -------------------------------------------------------------------------------- /app/assets/fonts/twitter/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anjlab/bootstrap-rails/54b165183fdccc4feb451416d1a46ecae496d6be/app/assets/fonts/twitter/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /app/assets/fonts/twitter/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anjlab/bootstrap-rails/54b165183fdccc4feb451416d1a46ecae496d6be/app/assets/fonts/twitter/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /app/assets/fonts/twitter/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anjlab/bootstrap-rails/54b165183fdccc4feb451416d1a46ecae496d6be/app/assets/fonts/twitter/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /app/assets/javascripts/twitter/bootstrap.js: -------------------------------------------------------------------------------- 1 | //= require twitter/bootstrap/transition.js 2 | //= require twitter/bootstrap/alert.js 3 | //= require twitter/bootstrap/button.js 4 | //= require twitter/bootstrap/carousel.js 5 | //= require twitter/bootstrap/collapse.js 6 | //= require twitter/bootstrap/dropdown.js 7 | //= require twitter/bootstrap/modal.js 8 | //= require twitter/bootstrap/tooltip.js 9 | //= require twitter/bootstrap/popover.js 10 | //= require twitter/bootstrap/scrollspy.js 11 | //= require twitter/bootstrap/tab.js 12 | //= require twitter/bootstrap/affix.js -------------------------------------------------------------------------------- /app/assets/javascripts/twitter/bootstrap/affix.js: -------------------------------------------------------------------------------- 1 | /* ======================================================================== 2 | * Bootstrap: affix.js v3.0.3 3 | * http://getbootstrap.com/javascript/#affix 4 | * ======================================================================== 5 | * Copyright 2013 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 | * ======================================================================== */ 19 | 20 | 21 | +function ($) { "use strict"; 22 | 23 | // AFFIX CLASS DEFINITION 24 | // ====================== 25 | 26 | var Affix = function (element, options) { 27 | this.options = $.extend({}, Affix.DEFAULTS, options) 28 | this.$window = $(window) 29 | .on('scroll.bs.affix.data-api', $.proxy(this.checkPosition, this)) 30 | .on('click.bs.affix.data-api', $.proxy(this.checkPositionWithEventLoop, this)) 31 | 32 | this.$element = $(element) 33 | this.affixed = 34 | this.unpin = null 35 | 36 | this.checkPosition() 37 | } 38 | 39 | Affix.RESET = 'affix affix-top affix-bottom' 40 | 41 | Affix.DEFAULTS = { 42 | offset: 0 43 | } 44 | 45 | Affix.prototype.checkPositionWithEventLoop = function () { 46 | setTimeout($.proxy(this.checkPosition, this), 1) 47 | } 48 | 49 | Affix.prototype.checkPosition = function () { 50 | if (!this.$element.is(':visible')) return 51 | 52 | var scrollHeight = $(document).height() 53 | var scrollTop = this.$window.scrollTop() 54 | var position = this.$element.offset() 55 | var offset = this.options.offset 56 | var offsetTop = offset.top 57 | var offsetBottom = offset.bottom 58 | 59 | if (typeof offset != 'object') offsetBottom = offsetTop = offset 60 | if (typeof offsetTop == 'function') offsetTop = offset.top() 61 | if (typeof offsetBottom == 'function') offsetBottom = offset.bottom() 62 | 63 | var affix = this.unpin != null && (scrollTop + this.unpin <= position.top) ? false : 64 | offsetBottom != null && (position.top + this.$element.height() >= scrollHeight - offsetBottom) ? 'bottom' : 65 | offsetTop != null && (scrollTop <= offsetTop) ? 'top' : false 66 | 67 | if (this.affixed === affix) return 68 | if (this.unpin) this.$element.css('top', '') 69 | 70 | this.affixed = affix 71 | this.unpin = affix == 'bottom' ? position.top - scrollTop : null 72 | 73 | this.$element.removeClass(Affix.RESET).addClass('affix' + (affix ? '-' + affix : '')) 74 | 75 | if (affix == 'bottom') { 76 | this.$element.offset({ top: document.body.offsetHeight - offsetBottom - this.$element.height() }) 77 | } 78 | } 79 | 80 | 81 | // AFFIX PLUGIN DEFINITION 82 | // ======================= 83 | 84 | var old = $.fn.affix 85 | 86 | $.fn.affix = function (option) { 87 | return this.each(function () { 88 | var $this = $(this) 89 | var data = $this.data('bs.affix') 90 | var options = typeof option == 'object' && option 91 | 92 | if (!data) $this.data('bs.affix', (data = new Affix(this, options))) 93 | if (typeof option == 'string') data[option]() 94 | }) 95 | } 96 | 97 | $.fn.affix.Constructor = Affix 98 | 99 | 100 | // AFFIX NO CONFLICT 101 | // ================= 102 | 103 | $.fn.affix.noConflict = function () { 104 | $.fn.affix = old 105 | return this 106 | } 107 | 108 | 109 | // AFFIX DATA-API 110 | // ============== 111 | 112 | $(window).on('load', function () { 113 | $('[data-spy="affix"]').each(function () { 114 | var $spy = $(this) 115 | var data = $spy.data() 116 | 117 | data.offset = data.offset || {} 118 | 119 | if (data.offsetBottom) data.offset.bottom = data.offsetBottom 120 | if (data.offsetTop) data.offset.top = data.offsetTop 121 | 122 | $spy.affix(data) 123 | }) 124 | }) 125 | 126 | }(jQuery); 127 | -------------------------------------------------------------------------------- /app/assets/javascripts/twitter/bootstrap/alert.js: -------------------------------------------------------------------------------- 1 | /* ======================================================================== 2 | * Bootstrap: alert.js v3.0.3 3 | * http://getbootstrap.com/javascript/#alerts 4 | * ======================================================================== 5 | * Copyright 2013 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 | * ======================================================================== */ 19 | 20 | 21 | +function ($) { "use strict"; 22 | 23 | // ALERT CLASS DEFINITION 24 | // ====================== 25 | 26 | var dismiss = '[data-dismiss="alert"]' 27 | var Alert = function (el) { 28 | $(el).on('click', dismiss, this.close) 29 | } 30 | 31 | Alert.prototype.close = function (e) { 32 | var $this = $(this) 33 | var selector = $this.attr('data-target') 34 | 35 | if (!selector) { 36 | selector = $this.attr('href') 37 | selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7 38 | } 39 | 40 | var $parent = $(selector) 41 | 42 | if (e) e.preventDefault() 43 | 44 | if (!$parent.length) { 45 | $parent = $this.hasClass('alert') ? $this : $this.parent() 46 | } 47 | 48 | $parent.trigger(e = $.Event('close.bs.alert')) 49 | 50 | if (e.isDefaultPrevented()) return 51 | 52 | $parent.removeClass('in') 53 | 54 | function removeElement() { 55 | $parent.trigger('closed.bs.alert').remove() 56 | } 57 | 58 | $.support.transition && $parent.hasClass('fade') ? 59 | $parent 60 | .one($.support.transition.end, removeElement) 61 | .emulateTransitionEnd(150) : 62 | removeElement() 63 | } 64 | 65 | 66 | // ALERT PLUGIN DEFINITION 67 | // ======================= 68 | 69 | var old = $.fn.alert 70 | 71 | $.fn.alert = function (option) { 72 | return this.each(function () { 73 | var $this = $(this) 74 | var data = $this.data('bs.alert') 75 | 76 | if (!data) $this.data('bs.alert', (data = new Alert(this))) 77 | if (typeof option == 'string') data[option].call($this) 78 | }) 79 | } 80 | 81 | $.fn.alert.Constructor = Alert 82 | 83 | 84 | // ALERT NO CONFLICT 85 | // ================= 86 | 87 | $.fn.alert.noConflict = function () { 88 | $.fn.alert = old 89 | return this 90 | } 91 | 92 | 93 | // ALERT DATA-API 94 | // ============== 95 | 96 | $(document).on('click.bs.alert.data-api', dismiss, Alert.prototype.close) 97 | 98 | }(jQuery); 99 | -------------------------------------------------------------------------------- /app/assets/javascripts/twitter/bootstrap/button.js: -------------------------------------------------------------------------------- 1 | /* ======================================================================== 2 | * Bootstrap: button.js v3.0.3 3 | * http://getbootstrap.com/javascript/#buttons 4 | * ======================================================================== 5 | * Copyright 2013 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 | * ======================================================================== */ 19 | 20 | 21 | +function ($) { "use strict"; 22 | 23 | // BUTTON PUBLIC CLASS DEFINITION 24 | // ============================== 25 | 26 | var Button = function (element, options) { 27 | this.$element = $(element) 28 | this.options = $.extend({}, Button.DEFAULTS, options) 29 | } 30 | 31 | Button.DEFAULTS = { 32 | loadingText: 'loading...' 33 | } 34 | 35 | Button.prototype.setState = function (state) { 36 | var d = 'disabled' 37 | var $el = this.$element 38 | var val = $el.is('input') ? 'val' : 'html' 39 | var data = $el.data() 40 | 41 | state = state + 'Text' 42 | 43 | if (!data.resetText) $el.data('resetText', $el[val]()) 44 | 45 | $el[val](data[state] || this.options[state]) 46 | 47 | // push to event loop to allow forms to submit 48 | setTimeout(function () { 49 | state == 'loadingText' ? 50 | $el.addClass(d).attr(d, d) : 51 | $el.removeClass(d).removeAttr(d); 52 | }, 0) 53 | } 54 | 55 | Button.prototype.toggle = function () { 56 | var $parent = this.$element.closest('[data-toggle="buttons"]') 57 | var changed = true 58 | 59 | if ($parent.length) { 60 | var $input = this.$element.find('input') 61 | if ($input.prop('type') === 'radio') { 62 | // see if clicking on current one 63 | if ($input.prop('checked') && this.$element.hasClass('active')) 64 | changed = false 65 | else 66 | $parent.find('.active').removeClass('active') 67 | } 68 | if (changed) $input.prop('checked', !this.$element.hasClass('active')).trigger('change') 69 | } 70 | 71 | if (changed) this.$element.toggleClass('active') 72 | } 73 | 74 | 75 | // BUTTON PLUGIN DEFINITION 76 | // ======================== 77 | 78 | var old = $.fn.button 79 | 80 | $.fn.button = function (option) { 81 | return this.each(function () { 82 | var $this = $(this) 83 | var data = $this.data('bs.button') 84 | var options = typeof option == 'object' && option 85 | 86 | if (!data) $this.data('bs.button', (data = new Button(this, options))) 87 | 88 | if (option == 'toggle') data.toggle() 89 | else if (option) data.setState(option) 90 | }) 91 | } 92 | 93 | $.fn.button.Constructor = Button 94 | 95 | 96 | // BUTTON NO CONFLICT 97 | // ================== 98 | 99 | $.fn.button.noConflict = function () { 100 | $.fn.button = old 101 | return this 102 | } 103 | 104 | 105 | // BUTTON DATA-API 106 | // =============== 107 | 108 | $(document).on('click.bs.button.data-api', '[data-toggle^=button]', function (e) { 109 | var $btn = $(e.target) 110 | if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn') 111 | $btn.button('toggle') 112 | e.preventDefault() 113 | }) 114 | 115 | }(jQuery); 116 | -------------------------------------------------------------------------------- /app/assets/javascripts/twitter/bootstrap/carousel.js: -------------------------------------------------------------------------------- 1 | /* ======================================================================== 2 | * Bootstrap: carousel.js v3.0.3 3 | * http://getbootstrap.com/javascript/#carousel 4 | * ======================================================================== 5 | * Copyright 2013 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 | * ======================================================================== */ 19 | 20 | 21 | +function ($) { "use strict"; 22 | 23 | // CAROUSEL CLASS DEFINITION 24 | // ========================= 25 | 26 | var Carousel = function (element, options) { 27 | this.$element = $(element) 28 | this.$indicators = this.$element.find('.carousel-indicators') 29 | this.options = options 30 | this.paused = 31 | this.sliding = 32 | this.interval = 33 | this.$active = 34 | this.$items = null 35 | 36 | this.options.pause == 'hover' && this.$element 37 | .on('mouseenter', $.proxy(this.pause, this)) 38 | .on('mouseleave', $.proxy(this.cycle, this)) 39 | } 40 | 41 | Carousel.DEFAULTS = { 42 | interval: 5000 43 | , pause: 'hover' 44 | , wrap: true 45 | } 46 | 47 | Carousel.prototype.cycle = function (e) { 48 | e || (this.paused = false) 49 | 50 | this.interval && clearInterval(this.interval) 51 | 52 | this.options.interval 53 | && !this.paused 54 | && (this.interval = setInterval($.proxy(this.next, this), this.options.interval)) 55 | 56 | return this 57 | } 58 | 59 | Carousel.prototype.getActiveIndex = function () { 60 | this.$active = this.$element.find('.item.active') 61 | this.$items = this.$active.parent().children() 62 | 63 | return this.$items.index(this.$active) 64 | } 65 | 66 | Carousel.prototype.to = function (pos) { 67 | var that = this 68 | var activeIndex = this.getActiveIndex() 69 | 70 | if (pos > (this.$items.length - 1) || pos < 0) return 71 | 72 | if (this.sliding) return this.$element.one('slid.bs.carousel', function () { that.to(pos) }) 73 | if (activeIndex == pos) return this.pause().cycle() 74 | 75 | return this.slide(pos > activeIndex ? 'next' : 'prev', $(this.$items[pos])) 76 | } 77 | 78 | Carousel.prototype.pause = function (e) { 79 | e || (this.paused = true) 80 | 81 | if (this.$element.find('.next, .prev').length && $.support.transition.end) { 82 | this.$element.trigger($.support.transition.end) 83 | this.cycle(true) 84 | } 85 | 86 | this.interval = clearInterval(this.interval) 87 | 88 | return this 89 | } 90 | 91 | Carousel.prototype.next = function () { 92 | if (this.sliding) return 93 | return this.slide('next') 94 | } 95 | 96 | Carousel.prototype.prev = function () { 97 | if (this.sliding) return 98 | return this.slide('prev') 99 | } 100 | 101 | Carousel.prototype.slide = function (type, next) { 102 | var $active = this.$element.find('.item.active') 103 | var $next = next || $active[type]() 104 | var isCycling = this.interval 105 | var direction = type == 'next' ? 'left' : 'right' 106 | var fallback = type == 'next' ? 'first' : 'last' 107 | var that = this 108 | 109 | if (!$next.length) { 110 | if (!this.options.wrap) return 111 | $next = this.$element.find('.item')[fallback]() 112 | } 113 | 114 | this.sliding = true 115 | 116 | isCycling && this.pause() 117 | 118 | var e = $.Event('slide.bs.carousel', { relatedTarget: $next[0], direction: direction }) 119 | 120 | if ($next.hasClass('active')) return 121 | 122 | if (this.$indicators.length) { 123 | this.$indicators.find('.active').removeClass('active') 124 | this.$element.one('slid.bs.carousel', function () { 125 | var $nextIndicator = $(that.$indicators.children()[that.getActiveIndex()]) 126 | $nextIndicator && $nextIndicator.addClass('active') 127 | }) 128 | } 129 | 130 | if ($.support.transition && this.$element.hasClass('slide')) { 131 | this.$element.trigger(e) 132 | if (e.isDefaultPrevented()) return 133 | $next.addClass(type) 134 | $next[0].offsetWidth // force reflow 135 | $active.addClass(direction) 136 | $next.addClass(direction) 137 | $active 138 | .one($.support.transition.end, function () { 139 | $next.removeClass([type, direction].join(' ')).addClass('active') 140 | $active.removeClass(['active', direction].join(' ')) 141 | that.sliding = false 142 | setTimeout(function () { that.$element.trigger('slid.bs.carousel') }, 0) 143 | }) 144 | .emulateTransitionEnd(600) 145 | } else { 146 | this.$element.trigger(e) 147 | if (e.isDefaultPrevented()) return 148 | $active.removeClass('active') 149 | $next.addClass('active') 150 | this.sliding = false 151 | this.$element.trigger('slid.bs.carousel') 152 | } 153 | 154 | isCycling && this.cycle() 155 | 156 | return this 157 | } 158 | 159 | 160 | // CAROUSEL PLUGIN DEFINITION 161 | // ========================== 162 | 163 | var old = $.fn.carousel 164 | 165 | $.fn.carousel = function (option) { 166 | return this.each(function () { 167 | var $this = $(this) 168 | var data = $this.data('bs.carousel') 169 | var options = $.extend({}, Carousel.DEFAULTS, $this.data(), typeof option == 'object' && option) 170 | var action = typeof option == 'string' ? option : options.slide 171 | 172 | if (!data) $this.data('bs.carousel', (data = new Carousel(this, options))) 173 | if (typeof option == 'number') data.to(option) 174 | else if (action) data[action]() 175 | else if (options.interval) data.pause().cycle() 176 | }) 177 | } 178 | 179 | $.fn.carousel.Constructor = Carousel 180 | 181 | 182 | // CAROUSEL NO CONFLICT 183 | // ==================== 184 | 185 | $.fn.carousel.noConflict = function () { 186 | $.fn.carousel = old 187 | return this 188 | } 189 | 190 | 191 | // CAROUSEL DATA-API 192 | // ================= 193 | 194 | $(document).on('click.bs.carousel.data-api', '[data-slide], [data-slide-to]', function (e) { 195 | var $this = $(this), href 196 | var $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7 197 | var options = $.extend({}, $target.data(), $this.data()) 198 | var slideIndex = $this.attr('data-slide-to') 199 | if (slideIndex) options.interval = false 200 | 201 | $target.carousel(options) 202 | 203 | if (slideIndex = $this.attr('data-slide-to')) { 204 | $target.data('bs.carousel').to(slideIndex) 205 | } 206 | 207 | e.preventDefault() 208 | }) 209 | 210 | $(window).on('load', function () { 211 | $('[data-ride="carousel"]').each(function () { 212 | var $carousel = $(this) 213 | $carousel.carousel($carousel.data()) 214 | }) 215 | }) 216 | 217 | }(jQuery); 218 | -------------------------------------------------------------------------------- /app/assets/javascripts/twitter/bootstrap/collapse.js: -------------------------------------------------------------------------------- 1 | /* ======================================================================== 2 | * Bootstrap: collapse.js v3.0.3 3 | * http://getbootstrap.com/javascript/#collapse 4 | * ======================================================================== 5 | * Copyright 2013 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 | * ======================================================================== */ 19 | 20 | 21 | +function ($) { "use strict"; 22 | 23 | // COLLAPSE PUBLIC CLASS DEFINITION 24 | // ================================ 25 | 26 | var Collapse = function (element, options) { 27 | this.$element = $(element) 28 | this.options = $.extend({}, Collapse.DEFAULTS, options) 29 | this.transitioning = null 30 | 31 | if (this.options.parent) this.$parent = $(this.options.parent) 32 | if (this.options.toggle) this.toggle() 33 | } 34 | 35 | Collapse.DEFAULTS = { 36 | toggle: true 37 | } 38 | 39 | Collapse.prototype.dimension = function () { 40 | var hasWidth = this.$element.hasClass('width') 41 | return hasWidth ? 'width' : 'height' 42 | } 43 | 44 | Collapse.prototype.show = function () { 45 | if (this.transitioning || this.$element.hasClass('in')) return 46 | 47 | var startEvent = $.Event('show.bs.collapse') 48 | this.$element.trigger(startEvent) 49 | if (startEvent.isDefaultPrevented()) return 50 | 51 | var actives = this.$parent && this.$parent.find('> .panel > .in') 52 | 53 | if (actives && actives.length) { 54 | var hasData = actives.data('bs.collapse') 55 | if (hasData && hasData.transitioning) return 56 | actives.collapse('hide') 57 | hasData || actives.data('bs.collapse', null) 58 | } 59 | 60 | var dimension = this.dimension() 61 | 62 | this.$element 63 | .removeClass('collapse') 64 | .addClass('collapsing') 65 | [dimension](0) 66 | 67 | this.transitioning = 1 68 | 69 | var complete = function () { 70 | this.$element 71 | .removeClass('collapsing') 72 | .addClass('in') 73 | [dimension]('auto') 74 | this.transitioning = 0 75 | this.$element.trigger('shown.bs.collapse') 76 | } 77 | 78 | if (!$.support.transition) return complete.call(this) 79 | 80 | var scrollSize = $.camelCase(['scroll', dimension].join('-')) 81 | 82 | this.$element 83 | .one($.support.transition.end, $.proxy(complete, this)) 84 | .emulateTransitionEnd(350) 85 | [dimension](this.$element[0][scrollSize]) 86 | } 87 | 88 | Collapse.prototype.hide = function () { 89 | if (this.transitioning || !this.$element.hasClass('in')) return 90 | 91 | var startEvent = $.Event('hide.bs.collapse') 92 | this.$element.trigger(startEvent) 93 | if (startEvent.isDefaultPrevented()) return 94 | 95 | var dimension = this.dimension() 96 | 97 | this.$element 98 | [dimension](this.$element[dimension]()) 99 | [0].offsetHeight 100 | 101 | this.$element 102 | .addClass('collapsing') 103 | .removeClass('collapse') 104 | .removeClass('in') 105 | 106 | this.transitioning = 1 107 | 108 | var complete = function () { 109 | this.transitioning = 0 110 | this.$element 111 | .trigger('hidden.bs.collapse') 112 | .removeClass('collapsing') 113 | .addClass('collapse') 114 | } 115 | 116 | if (!$.support.transition) return complete.call(this) 117 | 118 | this.$element 119 | [dimension](0) 120 | .one($.support.transition.end, $.proxy(complete, this)) 121 | .emulateTransitionEnd(350) 122 | } 123 | 124 | Collapse.prototype.toggle = function () { 125 | this[this.$element.hasClass('in') ? 'hide' : 'show']() 126 | } 127 | 128 | 129 | // COLLAPSE PLUGIN DEFINITION 130 | // ========================== 131 | 132 | var old = $.fn.collapse 133 | 134 | $.fn.collapse = function (option) { 135 | return this.each(function () { 136 | var $this = $(this) 137 | var data = $this.data('bs.collapse') 138 | var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option) 139 | 140 | if (!data) $this.data('bs.collapse', (data = new Collapse(this, options))) 141 | if (typeof option == 'string') data[option]() 142 | }) 143 | } 144 | 145 | $.fn.collapse.Constructor = Collapse 146 | 147 | 148 | // COLLAPSE NO CONFLICT 149 | // ==================== 150 | 151 | $.fn.collapse.noConflict = function () { 152 | $.fn.collapse = old 153 | return this 154 | } 155 | 156 | 157 | // COLLAPSE DATA-API 158 | // ================= 159 | 160 | $(document).on('click.bs.collapse.data-api', '[data-toggle=collapse]', function (e) { 161 | var $this = $(this), href 162 | var target = $this.attr('data-target') 163 | || e.preventDefault() 164 | || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7 165 | var $target = $(target) 166 | var data = $target.data('bs.collapse') 167 | var option = data ? 'toggle' : $this.data() 168 | var parent = $this.attr('data-parent') 169 | var $parent = parent && $(parent) 170 | 171 | if (!data || !data.transitioning) { 172 | if ($parent) $parent.find('[data-toggle=collapse][data-parent="' + parent + '"]').not($this).addClass('collapsed') 173 | $this[$target.hasClass('in') ? 'addClass' : 'removeClass']('collapsed') 174 | } 175 | 176 | $target.collapse(option) 177 | }) 178 | 179 | }(jQuery); 180 | -------------------------------------------------------------------------------- /app/assets/javascripts/twitter/bootstrap/dropdown.js: -------------------------------------------------------------------------------- 1 | /* ======================================================================== 2 | * Bootstrap: dropdown.js v3.0.3 3 | * http://getbootstrap.com/javascript/#dropdowns 4 | * ======================================================================== 5 | * Copyright 2013 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 | * ======================================================================== */ 19 | 20 | 21 | +function ($) { "use strict"; 22 | 23 | // DROPDOWN CLASS DEFINITION 24 | // ========================= 25 | 26 | var backdrop = '.dropdown-backdrop' 27 | var toggle = '[data-toggle=dropdown]' 28 | var Dropdown = function (element) { 29 | $(element).on('click.bs.dropdown', this.toggle) 30 | } 31 | 32 | Dropdown.prototype.toggle = function (e) { 33 | var $this = $(this) 34 | 35 | if ($this.is('.disabled, :disabled')) return 36 | 37 | var $parent = getParent($this) 38 | var isActive = $parent.hasClass('open') 39 | 40 | clearMenus() 41 | 42 | if (!isActive) { 43 | if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) { 44 | // if mobile we use a backdrop because click events don't delegate 45 | $('
').insertAfter($(this)).on('click', clearMenus) 46 | } 47 | 48 | $parent.trigger(e = $.Event('show.bs.dropdown')) 49 | 50 | if (e.isDefaultPrevented()) return 51 | 52 | $parent 53 | .toggleClass('open') 54 | .trigger('shown.bs.dropdown') 55 | 56 | $this.focus() 57 | } 58 | 59 | return false 60 | } 61 | 62 | Dropdown.prototype.keydown = function (e) { 63 | if (!/(38|40|27)/.test(e.keyCode)) return 64 | 65 | var $this = $(this) 66 | 67 | e.preventDefault() 68 | e.stopPropagation() 69 | 70 | if ($this.is('.disabled, :disabled')) return 71 | 72 | var $parent = getParent($this) 73 | var isActive = $parent.hasClass('open') 74 | 75 | if (!isActive || (isActive && e.keyCode == 27)) { 76 | if (e.which == 27) $parent.find(toggle).focus() 77 | return $this.click() 78 | } 79 | 80 | var $items = $('[role=menu] li:not(.divider):visible a', $parent) 81 | 82 | if (!$items.length) return 83 | 84 | var index = $items.index($items.filter(':focus')) 85 | 86 | if (e.keyCode == 38 && index > 0) index-- // up 87 | if (e.keyCode == 40 && index < $items.length - 1) index++ // down 88 | if (!~index) index=0 89 | 90 | $items.eq(index).focus() 91 | } 92 | 93 | function clearMenus() { 94 | $(backdrop).remove() 95 | $(toggle).each(function (e) { 96 | var $parent = getParent($(this)) 97 | if (!$parent.hasClass('open')) return 98 | $parent.trigger(e = $.Event('hide.bs.dropdown')) 99 | if (e.isDefaultPrevented()) return 100 | $parent.removeClass('open').trigger('hidden.bs.dropdown') 101 | }) 102 | } 103 | 104 | function getParent($this) { 105 | var selector = $this.attr('data-target') 106 | 107 | if (!selector) { 108 | selector = $this.attr('href') 109 | selector = selector && /#/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7 110 | } 111 | 112 | var $parent = selector && $(selector) 113 | 114 | return $parent && $parent.length ? $parent : $this.parent() 115 | } 116 | 117 | 118 | // DROPDOWN PLUGIN DEFINITION 119 | // ========================== 120 | 121 | var old = $.fn.dropdown 122 | 123 | $.fn.dropdown = function (option) { 124 | return this.each(function () { 125 | var $this = $(this) 126 | var data = $this.data('bs.dropdown') 127 | 128 | if (!data) $this.data('bs.dropdown', (data = new Dropdown(this))) 129 | if (typeof option == 'string') data[option].call($this) 130 | }) 131 | } 132 | 133 | $.fn.dropdown.Constructor = Dropdown 134 | 135 | 136 | // DROPDOWN NO CONFLICT 137 | // ==================== 138 | 139 | $.fn.dropdown.noConflict = function () { 140 | $.fn.dropdown = old 141 | return this 142 | } 143 | 144 | 145 | // APPLY TO STANDARD DROPDOWN ELEMENTS 146 | // =================================== 147 | 148 | $(document) 149 | .on('click.bs.dropdown.data-api', clearMenus) 150 | .on('click.bs.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() }) 151 | .on('click.bs.dropdown.data-api' , toggle, Dropdown.prototype.toggle) 152 | .on('keydown.bs.dropdown.data-api', toggle + ', [role=menu]' , Dropdown.prototype.keydown) 153 | 154 | }(jQuery); 155 | -------------------------------------------------------------------------------- /app/assets/javascripts/twitter/bootstrap/modal.js: -------------------------------------------------------------------------------- 1 | /* ======================================================================== 2 | * Bootstrap: modal.js v3.0.3 3 | * http://getbootstrap.com/javascript/#modals 4 | * ======================================================================== 5 | * Copyright 2013 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 | * ======================================================================== */ 19 | 20 | 21 | +function ($) { "use strict"; 22 | 23 | // MODAL CLASS DEFINITION 24 | // ====================== 25 | 26 | var Modal = function (element, options) { 27 | this.options = options 28 | this.$element = $(element) 29 | this.$backdrop = 30 | this.isShown = null 31 | 32 | if (this.options.remote) this.$element.load(this.options.remote) 33 | } 34 | 35 | Modal.DEFAULTS = { 36 | backdrop: true 37 | , keyboard: true 38 | , show: true 39 | } 40 | 41 | Modal.prototype.toggle = function (_relatedTarget) { 42 | return this[!this.isShown ? 'show' : 'hide'](_relatedTarget) 43 | } 44 | 45 | Modal.prototype.show = function (_relatedTarget) { 46 | var that = this 47 | var e = $.Event('show.bs.modal', { relatedTarget: _relatedTarget }) 48 | 49 | this.$element.trigger(e) 50 | 51 | if (this.isShown || e.isDefaultPrevented()) return 52 | 53 | this.isShown = true 54 | 55 | this.escape() 56 | 57 | this.$element.on('click.dismiss.modal', '[data-dismiss="modal"]', $.proxy(this.hide, this)) 58 | 59 | this.backdrop(function () { 60 | var transition = $.support.transition && that.$element.hasClass('fade') 61 | 62 | if (!that.$element.parent().length) { 63 | that.$element.appendTo(document.body) // don't move modals dom position 64 | } 65 | 66 | that.$element.show() 67 | 68 | if (transition) { 69 | that.$element[0].offsetWidth // force reflow 70 | } 71 | 72 | that.$element 73 | .addClass('in') 74 | .attr('aria-hidden', false) 75 | 76 | that.enforceFocus() 77 | 78 | var e = $.Event('shown.bs.modal', { relatedTarget: _relatedTarget }) 79 | 80 | transition ? 81 | that.$element.find('.modal-dialog') // wait for modal to slide in 82 | .one($.support.transition.end, function () { 83 | that.$element.focus().trigger(e) 84 | }) 85 | .emulateTransitionEnd(300) : 86 | that.$element.focus().trigger(e) 87 | }) 88 | } 89 | 90 | Modal.prototype.hide = function (e) { 91 | if (e) e.preventDefault() 92 | 93 | e = $.Event('hide.bs.modal') 94 | 95 | this.$element.trigger(e) 96 | 97 | if (!this.isShown || e.isDefaultPrevented()) return 98 | 99 | this.isShown = false 100 | 101 | this.escape() 102 | 103 | $(document).off('focusin.bs.modal') 104 | 105 | this.$element 106 | .removeClass('in') 107 | .attr('aria-hidden', true) 108 | .off('click.dismiss.modal') 109 | 110 | $.support.transition && this.$element.hasClass('fade') ? 111 | this.$element 112 | .one($.support.transition.end, $.proxy(this.hideModal, this)) 113 | .emulateTransitionEnd(300) : 114 | this.hideModal() 115 | } 116 | 117 | Modal.prototype.enforceFocus = function () { 118 | $(document) 119 | .off('focusin.bs.modal') // guard against infinite focus loop 120 | .on('focusin.bs.modal', $.proxy(function (e) { 121 | if (this.$element[0] !== e.target && !this.$element.has(e.target).length) { 122 | this.$element.focus() 123 | } 124 | }, this)) 125 | } 126 | 127 | Modal.prototype.escape = function () { 128 | if (this.isShown && this.options.keyboard) { 129 | this.$element.on('keyup.dismiss.bs.modal', $.proxy(function (e) { 130 | e.which == 27 && this.hide() 131 | }, this)) 132 | } else if (!this.isShown) { 133 | this.$element.off('keyup.dismiss.bs.modal') 134 | } 135 | } 136 | 137 | Modal.prototype.hideModal = function () { 138 | var that = this 139 | this.$element.hide() 140 | this.backdrop(function () { 141 | that.removeBackdrop() 142 | that.$element.trigger('hidden.bs.modal') 143 | }) 144 | } 145 | 146 | Modal.prototype.removeBackdrop = function () { 147 | this.$backdrop && this.$backdrop.remove() 148 | this.$backdrop = null 149 | } 150 | 151 | Modal.prototype.backdrop = function (callback) { 152 | var that = this 153 | var animate = this.$element.hasClass('fade') ? 'fade' : '' 154 | 155 | if (this.isShown && this.options.backdrop) { 156 | var doAnimate = $.support.transition && animate 157 | 158 | this.$backdrop = $('') 159 | .appendTo(document.body) 160 | 161 | this.$element.on('click.dismiss.modal', $.proxy(function (e) { 162 | if (e.target !== e.currentTarget) return 163 | this.options.backdrop == 'static' 164 | ? this.$element[0].focus.call(this.$element[0]) 165 | : this.hide.call(this) 166 | }, this)) 167 | 168 | if (doAnimate) this.$backdrop[0].offsetWidth // force reflow 169 | 170 | this.$backdrop.addClass('in') 171 | 172 | if (!callback) return 173 | 174 | doAnimate ? 175 | this.$backdrop 176 | .one($.support.transition.end, callback) 177 | .emulateTransitionEnd(150) : 178 | callback() 179 | 180 | } else if (!this.isShown && this.$backdrop) { 181 | this.$backdrop.removeClass('in') 182 | 183 | $.support.transition && this.$element.hasClass('fade')? 184 | this.$backdrop 185 | .one($.support.transition.end, callback) 186 | .emulateTransitionEnd(150) : 187 | callback() 188 | 189 | } else if (callback) { 190 | callback() 191 | } 192 | } 193 | 194 | 195 | // MODAL PLUGIN DEFINITION 196 | // ======================= 197 | 198 | var old = $.fn.modal 199 | 200 | $.fn.modal = function (option, _relatedTarget) { 201 | return this.each(function () { 202 | var $this = $(this) 203 | var data = $this.data('bs.modal') 204 | var options = $.extend({}, Modal.DEFAULTS, $this.data(), typeof option == 'object' && option) 205 | 206 | if (!data) $this.data('bs.modal', (data = new Modal(this, options))) 207 | if (typeof option == 'string') data[option](_relatedTarget) 208 | else if (options.show) data.show(_relatedTarget) 209 | }) 210 | } 211 | 212 | $.fn.modal.Constructor = Modal 213 | 214 | 215 | // MODAL NO CONFLICT 216 | // ================= 217 | 218 | $.fn.modal.noConflict = function () { 219 | $.fn.modal = old 220 | return this 221 | } 222 | 223 | 224 | // MODAL DATA-API 225 | // ============== 226 | 227 | $(document).on('click.bs.modal.data-api', '[data-toggle="modal"]', function (e) { 228 | var $this = $(this) 229 | var href = $this.attr('href') 230 | var $target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, ''))) //strip for ie7 231 | var option = $target.data('modal') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data()) 232 | 233 | e.preventDefault() 234 | 235 | $target 236 | .modal(option, this) 237 | .one('hide', function () { 238 | $this.is(':visible') && $this.focus() 239 | }) 240 | }) 241 | 242 | $(document) 243 | .on('show.bs.modal', '.modal', function () { $(document.body).addClass('modal-open') }) 244 | .on('hidden.bs.modal', '.modal', function () { $(document.body).removeClass('modal-open') }) 245 | 246 | }(jQuery); 247 | -------------------------------------------------------------------------------- /app/assets/javascripts/twitter/bootstrap/popover.js: -------------------------------------------------------------------------------- 1 | /* ======================================================================== 2 | * Bootstrap: popover.js v3.0.3 3 | * http://getbootstrap.com/javascript/#popovers 4 | * ======================================================================== 5 | * Copyright 2013 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 | * ======================================================================== */ 19 | 20 | 21 | +function ($) { "use strict"; 22 | 23 | // POPOVER PUBLIC CLASS DEFINITION 24 | // =============================== 25 | 26 | var Popover = function (element, options) { 27 | this.init('popover', element, options) 28 | } 29 | 30 | if (!$.fn.tooltip) throw new Error('Popover requires tooltip.js') 31 | 32 | Popover.DEFAULTS = $.extend({} , $.fn.tooltip.Constructor.DEFAULTS, { 33 | placement: 'right' 34 | , trigger: 'click' 35 | , content: '' 36 | , template: '