#coding: utf-8 module BootstrapComponentHelper extend ActiveSupport::Concern include BootstrapHelper # Dropdown menus 未实现 # Button groups # 就是一个div, 里面的btn还是自己写 # opts: # type: vertical 默认为空,竖着排。。。诡异 def btn_group(opts={}, &block) class_str = 'btn-group' class_str << ' btn-group-vertical' if opts.delete(:type) == 'vertical' div(merge_predef_class(class_str, opts), &block) end alias_method :bg, :btn_group # 可以组合多个btn group def btn_toolbar(opts={}, &block) div(merge_predef_class('btn-toolbar', opts), &block) end alias_method :bt, :btn_toolbar # Button dropdown menus 未实现 # Split button dropdowns 未实现 # Dropup menus 未实现 # Nav : tabs, pills, and lists # bootstrap navs def nav(*args, &block) default_options = {class: 'nav'} options = args.extract_options! current_class = options.delete(:class) || '' options.reverse_merge!(default_options)[:class] << " #{current_class}" list(*(args << options), &block) end # Navbar # # options - # fix: top, bottom # static: top, bottom # fluid: true, false default: true # inverse: true, false default: false # &block ,navbar的内容 def navbar(options={}, &block) default_options = {fluid: true, inverse: false} options.reverse_merge!(default_options) fluid = options.delete(:fluid) result = '' navbar_class = 'navbar' case options.delete(:fix) when 'top' navbar_class << ' navbar-fixed-top' result << javascript_tag do raw <<-JS $(function(){ if ($('.navbar-fixed-top').css('position') != 'static') $('body').css('padding-top','40px'); }); JS end when 'bottom' navbar_class << ' navbar-fixed-bottom' result << javascript_tag do raw <<-JS $(function(){ if ($('.navbar-fixed-top').css('position') != 'static') $('body').css('padding-bottom','40px'); }); JS end end case options.delete(:static) when 'top' navbar_class << ' navbar-static-top' when 'bottom' navbar_class << ' navbar-static-bottom' end navbar_class << ' navbar-inverse' if options.delete(:inverse) options[:class] ||= '' options[:class] << " #{navbar_class}" result << div(options) do div(class: 'navbar-inner') do if fluid capture(&block) if block_given? else div(class: 'container') do capture(&block) if block_given? end end end end result.html_safe end # Breadcrumbs 未实现 # Pagination supported in table # Labels and badges # type: success, warning, important, info, inverse def label(text, type='default') content_tag('span', text, class: "label label-#{type.to_s}") end alias_method :l, :label def badge(text, type='default') content_tag('span', text, class: "badge badge-#{type.to_s}") end alias_method :b, :badge # Typographic components # # title - hero unit's title, presented as h1 # description - description of hero unit, presented as p # options - any html options that can be accepted by div def hero_unit(*args, &block) options = args.extract_options! title = args.try(:first) description = args.try(:second) div(merge_predef_class('hero-unit', options)) do content = [] content << content_tag('h1', title) unless title.blank? content << content_tag('p', description) unless description.blank? content << capture(&block) if block_given? content.compact.join.html_safe end end alias_method :hu, :hero_unit # Page header components # # title - hero unit's title, presented as h1 # description - description of hero unit, presented as p # options - any html options that can be accepted by div def page_header(*args, &block) options = args.extract_options! title = args.try(:first) description = args.try(:second) div(merge_predef_class('page-header', options)) do if block_given? capture(&block) else content_tag('h1') do [title, (content_tag('small', description) unless description.blank?) ].compact.join(' ').html_safe end unless title.blank? end end end alias_method :ph, :page_header # Thumbnails Grids of images, videos, text, and more # options - any options that can be accepted by ul def thumbnails(options={}, &block) options[:class] ||= '' options[:class] << ' thumbnails' content_tag('ul', nil, options) do capture(&block) end end # Thumbnail element # span - width of thumbnail, 1-12 # title - title of thumbnail, h5 # description - description of thumbnail, p # li_options - any options that can be accepted by li # tn_options - thumbnail options # tag: :div default. # any options that can be accepted by the tag def thumbnail(span=12, *options, &block) tn_options = options.extract_options! li_options = options.first || {} li_options, tn_options = tn_options, {} if li_options.empty? li_options[:class] ||= '' li_options[:class] << " span#{span}" tn_options[:class] ||= '' tn_options[:class] << ' thumbnail' tn_options.reverse_merge!({tag: :div}) content_tag('li', nil, li_options) do content_tag(tn_options.delete(:tag), nil, tn_options) do capture(&block) end end end alias_method :tns, :thumbnails alias_method :tn, :thumbnail # Alerts, comfirms and prompts for success, warning, and error messages # see bootbox-rails gem # Alerts, Styles for success, warning, and error messages # # message - the message of alert # options - # type - type of alerts: error, warning, success, info. default: warning # block: true, false, add padding to alert component. default: false # closable: true, false, add a close button to alert. default: true # the other options that can be accepted by div def f(message=nil, options={}, &block) message, options = nil, message if message.is_a?(Hash) default_options = {closable: true, block: false} options.reverse_merge!(default_options) flash_class = %w(alert) flash_class << "alert-#{options.delete(:type).to_s}" if options[:type] flash_class << 'alert-block' if options.delete(:block) flash_class << "#{options.delete(:class)}" closable = options.delete(:closable) content_tag(:div, nil, options.merge!(class: flash_class)) do content = [] content << '×' if closable content << message if message content << capture(&block) if block_given? content.join.html_safe end end # Progress bars # # the first parameter is a hash: # active - true, false. it's the active style of the bar. # striped - true, false. it's the striped style of the bar. # in_table - true, false. If progress is in a table, set the margin-bottom to zero. # the other options that can be acctpted by div # # bar_options - hash or array. the bar options. If it is a stacked bar, options will be a hash, or will be an array # type - bar's type: success, warning, danger, info # percentage - the bar's percentage # content - bar content # the other options that can be acctpted by div def progress(*args) options = args.shift bar_options = args.flatten bar_options, options = [options], {} if bar_options.empty? progress_class = "progress #{options.delete(:striped) ? 'progress-striped' : ''} #{options.delete(:active) ? 'active' : ''}" progress_class << " #{options.delete(:class)}" if options[:class] progress_style = options.delete(:in_table) ? 'margin-bottom: 0;' : '' progress_style << " #{options.delete(:style)}" if options[:style] div(options.merge!({class: progress_class, style: progress_style})) do content = [] bar_options.each do |opts| content << progress_bar(opts) end content.join.html_safe end end alias_method :pg, :progress def progress_bar(options={}) bar_class = "bar #{options[:type] ? 'bar-' + options[:type].to_s : ''}" bar_class << " #{options.delete(:class)}" if options[:class] bar_style = "width: #{options[:percentage].to_i}%;" bar_style << " #{options.delete(:style)}" if options[:style] content_tag('div', options[:content], options.merge!({class: bar_class, style: bar_style})) end # Media object # Miscellaneous Lightweight utility components # bootstrap modal # see bootstrap-modal-rails gem # # options - # header - header of modal, replace default header. # footer_text - text of footer, default: Close # footer - footer of modal, replace default footer. # width - numbers # static - true, false. default: true # fullwidth - true, false, default: false # long - true, false, default: false def modal(id, header_text, options={}, &block) default_options = { header: "

#{header_text}

", footer: "", fullwidth: false, long: false, static: true } options = default_options.merge(options) footer = options.delete(:footer) header = options.delete(:header) options.merge!({'data-backdrop' => 'static', 'data-keyboard' => 'false'}) if options.delete(:static) options.merge!({'data-replace' => 'true'}) if options.delete(:long) options.merge!({'data-width' => options.delete(:width)}) if options[:width] div(merge_predef_class("modal hide fade #{options.delete(:fullwidth) ? 'container' : ''}", options).merge!(id: id)) do content = '' content << div(class: 'modal-header') do header.html_safe end content << div(class: 'modal-body') do capture(&block) if block_given? end content << div(class: 'modal-footer') do footer.html_safe end content.html_safe end end # options: # type - a or b, a is link, b is button. default: a # icon - glyph icon of trigger def modal_trigger(id, value, options={}) default_options = {name: "trigger-#{id}", id: "trigger-#{id}", 'data-toggle' => 'modal', type: 'a'} options = default_options.merge(options) merge_predef_class('btn', options) if options.delete(:type) == 'b' link_to("##{id}", options) do content = '' content << glyph_icon(options.delete(:icon)) if options[:icon] content << value content.html_safe end end def modal_with_trigger(id, header_text, trigger_value, options={}, trigger_options={}, &block) modal(id, header_text, options, &block) + modal_trigger(id, trigger_value, trigger_options) end end