class BettertabsBuilder

Constants

TAB_TYPES

Public Class Methods

new(bettertabs_id, template, selected_tab_id = nil, options = {}) click to toggle source
# File lib/bettertabs/bettertabs_builder.rb, line 6
def initialize(bettertabs_id, template, selected_tab_id = nil, options = {})
  @bettertabs_id = bettertabs_id
  @template = template
  @selected_tab_id = selected_tab_id
  @list_html_options = options.delete(:list_html_options) # sets html_options on the :ul element
  @list_item_html_options = options.delete(:list_item_html_options) # sets html_options on the :li elements
  @render_only_active_content = options.delete(:render_only_active_content) # used in ajax calls
  @wrapper_html_options = options

  @tabs = []
  @contents = []
end

Public Instance Methods

ajax(tab_id, *args, &block) click to toggle source

Ajax tabs generator

# File lib/bettertabs/bettertabs_builder.rb, line 32
def ajax(tab_id, *args, &block)
  get_options(args)[:tab_type] = :ajax
  self.for(tab_id, *args, &block)
end
for(tab_id, *args, &block) click to toggle source

Generic tab and content generator

# File lib/bettertabs/bettertabs_builder.rb, line 48
def for(tab_id, *args, &block)
  # Initialize vars and options
  options = get_options(args)
  tab_id = tab_id.to_s
  tab_text = get_tab_text(tab_id, args)
  raise "Bettertabs: #{tab_html_id_for(tab_id)} error. Used :partial option and a block of content at the same time." if block_given? and options[:partial]
  partial = options.delete(:partial) || tab_id.to_s unless block_given?
  raise "Bettertabs: #{tab_html_id_for(tab_id)} error. Used :locals option and a block of content at the same time." if block_given? and options[:locals]
  locals = options.delete(:locals) unless block_given?
  url = options.delete(:url) || @template.params.merge(:"#{@bettertabs_id}_selected_tab" => tab_id)
  tab_type = (options.delete(:tab_type) || :static).to_sym
  raise "Bettertabs: #{tab_type.inspect} tab type not supported. Use one of #{TAB_TYPES.inspect} instead." unless TAB_TYPES.include?(tab_type)
  ajax_url = options.delete(:ajax_url) || url_for_ajax(url) if tab_type == :ajax
  @selected_tab_id ||= tab_id # defaults to first tab

  if @render_only_active_content
    if active?(tab_id)
      @only_active_content = block_given? ? @template.capture(&block) : @template.render(:partial => partial, :locals => locals)
    end
  else
    # Tabs
    tab_html_options = options # any other option will be used as tab html_option
    @tabs << { tab_id: tab_id, text: tab_text, url: url, ajax_url: ajax_url, html_options: tab_html_options, tab_type: tab_type, active: active?(tab_id) }

    # Content
    content_html_options = { id: content_html_id_for(tab_id), class: "content #{active?(tab_id) ? 'active' : 'hidden'}" }
    if active?(tab_id) or tab_type == :static # Only render content for selected tab (static content is always rendered).
      content = block_given? ? @template.capture(&block) : @template.render(:partial => partial, :locals => locals)
    else
      content = ''
    end
    @contents << { tab_id: tab_id, tab_text: tab_text, content: content, html_options: content_html_options, tab_type: tab_type, active: active?(tab_id) }
  end
  nil # returning nil allows the user to call this using <%= tab.for :xxx %> or <% tab.for :xxx %>
end
only_content_block(options = {}, &block) click to toggle source

No tab generator, to add only content

# File lib/bettertabs/bettertabs_builder.rb, line 38
def only_content_block(options = {}, &block)
  content_html_options = {class: 'content content-only-block'}
  unless @render_only_active_content
    content = block_given? ? @template.capture(&block) : @template.render(:partial => options[:partial], :locals => options[:locals])
    @contents << { content: content, html_options: content_html_options, tab_type: :only_content_block }
  end
  nil # returning nil allows the user to call this using <%= tab.only_content_block %> or <% tab.only_content_block %>
end
render() click to toggle source

Renders the bettertabs markup. The following instance variables are available:

  • @tabs: list of tabs. Each one is a hash with the followin keys:

    • :tab_id => symbol identifier of the tab

    • :text => text to show in the rendered tab

    • :url => string with the tab url

    • :html_options => for use in the tab markup (included ‘data-tab-type’).

    • :tab_type => One of TAB_TYPES

    • :active => true if this is the selected tab

  • @contents: list of contents asociated with each tab. Each one is a hash with the following keys:

    • :tab_id => symbol identifier of the tab

    • :tab_text => text that is used in the corresponding tab

    • :content => string with the content inside

    • :html_options => for use in the container markup

    • :tab_type => One of TAB_TYPES

    • :active => true if this is the selected content

  • @selected_tab_id: String with the selected tab id (to match against each tab)

  • @wrapper_html_options: hash with the html options used in the bettertabs container

  • @bettertabs_id: id of the bettertabs widget

# File lib/bettertabs/bettertabs_builder.rb, line 103
def render
  if @render_only_active_content
    @only_active_content.html_safe
  else

    # Wrapper
    @wrapper_html_options ||= {}
    @wrapper_html_options[:"data-initial-active-tab-id"] = tab_html_id_for @selected_tab_id
    content_tag(:div, @wrapper_html_options) do

      # Tabs list
      @list_html_options ||= {}
      @list_html_options[:class] ||= ''
      @list_html_options[:class] += @list_html_options[:class].empty? ? 'tabs' : ' tabs'

      @list_item_html_options ||= {}
      @list_item_html_options[:class] ||= ''
      @list_item_html_options[:class] += @list_item_html_options[:class].empty? ? 'tab' : ' tab'

      content_tag(:ul, @list_html_options) do
        @tabs.map do |tab|
          content_tag(:li, tab_li_options(tab)) do
            tab[:html_options][:"data-tab-type"] ||= tab[:tab_type] # for javascript: change click behavior depending on type :static, :link or :ajax
            tab[:html_options][:"data-show-content-id"] ||= content_html_id_for(tab[:tab_id]) # for javascript: element id to show when select this tab
            tab[:html_options][:"data-ajax-url"] ||= tab[:ajax_url] if tab[:tab_type] == :ajax # for javascript: url to make ajax call
            tab[:html_options][:class] ||= ''
            tab[:html_options][:class] += 'active' if tab[:active]
            @template.link_to(tab[:text], tab[:url], tab[:html_options])
          end
        end.join.html_safe
      end +

       # Content sections
       @contents.map do |content|
         content_tag(:div, content[:html_options]) do
           content[:content] # this should be blank unless content[:active] or content[:tab_type] == :static
         end
       end.join.html_safe
    end.html_safe

  end
end
static(tab_id, *args, &block) click to toggle source

Static tabs generator

# File lib/bettertabs/bettertabs_builder.rb, line 20
def static(tab_id, *args, &block)
  get_options(args)[:tab_type] = :static
  self.for(tab_id, *args, &block)
end

Private Instance Methods

active?(tab_id) click to toggle source

Check if this tab_id is the same as @selected_tab_id

# File lib/bettertabs/bettertabs_builder.rb, line 161
def active?(tab_id)
  @selected_tab_id.to_s == tab_id.to_s
end
content_html_id_for(tab_id) click to toggle source

Content html id

# File lib/bettertabs/bettertabs_builder.rb, line 171
def content_html_id_for(tab_id)
  "#{tab_id}_#{@bettertabs_id}_content"
end
content_tag(name, content_or_options_with_block = nil, options = nil, escape = true, &block) click to toggle source

Delegate @template.content_tag

# File lib/bettertabs/bettertabs_builder.rb, line 176
def content_tag(name, content_or_options_with_block = nil, options = nil, escape = true, &block)
  @template.content_tag(name, content_or_options_with_block, options, escape, &block)
end
get_options(args) click to toggle source

Get the options hash from an array of args. If options are not present, create them and initialize to {}

# File lib/bettertabs/bettertabs_builder.rb, line 150
def get_options(args)
  args << {} unless args.last.is_a?(Hash)
  args.last
end
get_tab_text(tab_id, args) click to toggle source

Get the default name of the tab, from the args list.

# File lib/bettertabs/bettertabs_builder.rb, line 156
def get_tab_text(tab_id, args)
  String === args.first ? args.first : tab_id.to_s.titleize
end
tab_html_id_for(tab_id) click to toggle source

Tab html id

# File lib/bettertabs/bettertabs_builder.rb, line 166
def tab_html_id_for(tab_id)
  "#{tab_id}_#{@bettertabs_id}_tab"
end
tab_li_options(tab) click to toggle source

Gets the the html_options for the tab list_item element

# File lib/bettertabs/bettertabs_builder.rb, line 198
def tab_li_options(tab)
  options = @list_item_html_options.clone
  options[:class] += ' active' if tab[:active]
  options[:id] = tab_html_id_for(tab[:tab_id])
  options
end
url_for_ajax(options) click to toggle source

Uses @template.url_for() to create the string url, and then URI.parse to add the ajax=true extra param. This “ajax=true” extra param is important for two reasons:

* It makes easier from the controller to know when a request is ajax or not.
* It prevents the browser cache to be populated with the ajax response in the same URL as the complete page,
  otherwhise when the user makes an ajax call, goes to another page and click the back button they see only the ajax response (browsers bug?).
# File lib/bettertabs/bettertabs_builder.rb, line 185
def url_for_ajax(options)
  original_url = @template.url_for(options)
  begin
    ajax_param = 'ajax=true'
    uri = URI.parse original_url # URI from ruby standard library
    uri.query = uri.query.blank? ? ajax_param : "#{uri.query}&#{ajax_param}".html_safe
    uri.to_s
  rescue URI::InvalidURIError
    original_url
  end
end