lib/mir_extensions.rb in mir_extensions-0.2.0 vs lib/mir_extensions.rb in mir_extensions-1.0.0
- old
+ new
@@ -1,11 +1,11 @@
require 'singleton'
-require File.expand_path(File.dirname(__FILE__) + '/core_ext/core_ext')
require 'friendly_id'
+require 'core_ext/core_ext'
module MirExtensions
-
+
# Constants ======================================================================================
MONTHS = {0 => "JAN", 1 => "FEB", 2 => "MAR", 3 => "APR", 4 => "MAY", 5 => "JUN", 6 => "JUL", 7 => "AUG", 8 => "SEP", 9 => "OCT", 10 => "NOV", 11 => "DEC"}
STATE_CODES = { 'Alabama' => 'AL', 'Alaska' => 'AK', 'Arizona' => 'AZ', 'Arkansas' => 'AR', 'California' => 'CA', 'Colorado' => 'CO', 'Connecticut' => 'CT', 'Delaware' => 'DE', 'Florida' => 'FL', 'Georgia' => 'GA', 'Hawaii' => 'HI', 'Idaho' => 'ID', 'Illinois' => 'IL', 'Indiana' => 'IN', 'Iowa' => 'IA', 'Kansas' => 'KS', 'Kentucky' => 'KY', 'Louisiana' => 'LA', 'Maine' => 'ME', 'Maryland' => 'MD', 'Massachusetts' => 'MA', 'Michigan' => 'MI', 'Minnesota' => 'MN', 'Mississippi' => 'MS', 'Missouri' => 'MO', 'Montana' => 'MT', 'Nebraska' => 'NE', 'Nevada' => 'NV', 'New Hampshire' => 'NH', 'New Jersey' => 'NJ', 'New Mexico' => 'NM', 'New York' => 'NY', 'North Carolina' => 'NC', 'North Dakota' => 'ND', 'Ohio' => 'OH', 'Oklahoma' => 'OK', 'Oregon' => 'OR', 'Pennsylvania' => 'PA', 'Puerto Rico' => 'PR', 'Rhode Island' => 'RI', 'South Carolina' => 'SC', 'South Dakota' => 'SD', 'Tennessee' => 'TN', 'Texas' => 'TX', 'Utah' => 'UT', 'Vermont' => 'VT', 'Virginia' => 'VA', 'Washington' => 'WA', 'Washington DC' => 'DC', 'West Virginia' => 'WV', 'Wisconsin' => 'WI', 'Wyoming' => 'WY', 'Alberta' => 'AB', 'British Columbia' => 'BC', 'Manitoba' => 'MB', 'New Brunswick' => 'NB', 'Newfoundland and Labrador' => 'NL', 'Northwest Territories' => 'NT', 'Nova Scotia' => 'NS', 'Nunavut' => 'NU', 'Ontario' => 'ON', 'Prince Edward Island' => 'PE', 'Quebec' => 'QC', 'Saskatchewan' => 'SK', 'Yukon' => 'YT' }
@@ -31,7 +31,391 @@
end
def self.state_name_for(abbreviation)
STATE_CODES.invert[abbreviation]
end
+
+ module HelperExtensions
+ def action?( expression )
+ !! ( expression.class == Regexp ? controller.action_name =~ expression : controller.action_name == expression )
+ end
+
+ # Formats an array with HTML line breaks, or the specified delimiter.
+ def array_to_lines(array, delimiter = '<br />')
+ array.blank? ? nil : array * delimiter
+ end
+
+ def checkmark
+ %{<div class="checkmark"></div>}.html_safe
+ end
+
+ def controller?( expression )
+ !! ( expression.class == Regexp ? controller.controller_name =~ expression : controller.controller_name == expression )
+ end
+
+ # Display CRUD icons or links, according to setting in use_crud_icons method.
+ #
+ # In application_helper.rb:
+ #
+ # def use_crud_icons
+ # true
+ # end
+ #
+ # Then use in index views like this:
+ #
+ # <td class="crud_links"><%= crud_links(my_model, 'my_model', [:show, :edit, :delete]) -%></td>
+ #
+ def crud_links(model, instance_name, actions, args={})
+ _html = ""
+ _options = args.keys.empty? ? '' : ", #{args.map{|k,v| ":#{k} => #{v}"}}"
+
+ if use_crud_icons
+ if actions.include?(:show)
+ _html << eval("link_to image_tag('/images/icons/view.png', :class => 'crud_icon'), model, :title => 'View'#{_options}")
+ end
+ if actions.include?(:edit)
+ _html << eval("link_to image_tag('/images/icons/edit.png', :class => 'crud_icon'), edit_#{instance_name}_path(model), :title => 'Edit'#{_options}")
+ end
+ if actions.include?(:delete)
+ _html << eval("link_to image_tag('/images/icons/delete.png', :class => 'crud_icon'), model, :confirm => 'Are you sure? This action cannot be undone.', :method => :delete, :title => 'Delete'#{_options}")
+ end
+ else
+ if actions.include?(:show)
+ _html << eval("link_to 'View', model, :title => 'View', :class => 'crud_link'#{_options}")
+ end
+ if actions.include?(:edit)
+ _html << eval("link_to 'Edit', edit_#{instance_name}_path(model), :title => 'Edit', :class => 'crud_link'#{_options}")
+ end
+ if actions.include?(:delete)
+ _html << eval("link_to 'Delete', model, :confirm => 'Are you sure? This action cannot be undone.', :method => :delete, :title => 'Delete', :class => 'crud_link'#{_options}")
+ end
+ end
+ _html
+ end
+
+ # Display CRUD icons or links, according to setting in use_crud_icons method.
+ # This method works with nested resources.
+ # Use in index views like this:
+ #
+ # <td class="crud_links"><%= crud_links_for_nested_resource(@my_model, my_nested_model, 'my_model', 'my_nested_model', [:show, :edit, :delete]) -%></td>
+ #
+ def crud_links_for_nested_resource(model, nested_model, model_instance_name, nested_model_instance_name, actions, args={})
+ _html = ""
+ if use_crud_icons
+ if actions.include?(:show)
+ _html << eval("link_to image_tag('/images/icons/view.png', :class => 'crud_icon'), #{model_instance_name}_#{nested_model_instance_name}_path(model, nested_model), :title => 'View'")
+ end
+
+ if actions.include?(:edit)
+ _html << eval("link_to image_tag('/images/icons/edit.png', :class => 'crud_icon'), edit_#{model_instance_name}_#{nested_model_instance_name}_path(model, nested_model), :title => 'Edit'")
+ end
+
+ if actions.include?(:delete)
+ _html << eval("link_to image_tag('/images/icons/delete.png', :class => 'crud_icon'), #{model_instance_name}_#{nested_model_instance_name}_path(model, nested_model), :method => :delete, :confirm => 'Are you sure? This action cannot be undone.', :title => 'Delete'")
+ end
+ end
+ _html
+ end
+
+ # DRY way to return a legend tag that renders correctly in all browsers. This variation allows
+ # for more "stuff" inside the legend tag, e.g. expand/collapse controls, without having to worry
+ # about escape sequences.
+ #
+ # Sample usage:
+ #
+ # <%- legend_block do -%>
+ # <span id="hide_or_show_backlinks" class="show_link" style="background-color: #999999;
+ # border: 1px solid #999999;" onclick="javascript:hide_or_show('backlinks');"></span>Backlinks (<%=
+ # @google_results.size -%>)
+ # <%- end -%>
+ #
+ def legend_block(&block)
+ concat content_tag(:div, capture(&block), :class => "faux_legend")
+ end
+
+ # DRY way to return a legend tag that renders correctly in all browsers
+ def legend_tag(text, args={})
+ _html = %{<div id="#{args[:id]}" class="faux_legend">#{text}</div>\r}
+ _html.gsub!(/ id=""/,'')
+ _html.gsub!(/ class=""/,'')
+ _html
+ end
+
+ def meta_description(content=nil)
+ content_for(:meta_description) { content } unless content.blank?
+ end
+
+ def meta_keywords(content=nil)
+ content_for(:meta_keywords) { content } unless content.blank?
+ end
+
+ def models_for_select( models, label = 'name' )
+ models.map{ |m| [m[label], m.id] }.sort_by{ |e| e[0] }
+ end
+
+ def options_for_array( a, selected = nil, prompt = select_prompt )
+ "<option value=''>#{prompt}</option>" + a.map{ |_e| _flag = _e[0].to_s == selected ? 'selected="1"' : ''; _e.is_a?(Array) ? "<option value=\"#{_e[0]}\" #{_flag}>#{_e[1]}</option>" : "<option>#{_e}</option>" }.to_s
+ end
+
+ # Create a link that is opaque to search engine spiders.
+ def obfuscated_link_to(path, image, label, args={})
+ _html = %{<form action="#{path}" method="get" class="obfuscated_link">}
+ _html << %{ <fieldset><input alt="#{label}" src="#{image}" type="image" /></fieldset>}
+ args.each{ |k,v| _html << %{ <div><input id="#{k.to_s}" name="#{k}" type="hidden" value="#{v}" /></div>} }
+ _html << %{</form>}
+ _html
+ end
+
+ # Wraps the given HTML in Rails' default style to highlight validation errors, if any.
+ def required_field_helper( model, element, html )
+ if model && ! model.errors.empty? && element.is_required
+ return content_tag( :div, html, :class => 'fieldWithErrors' )
+ else
+ return html
+ end
+ end
+
+ def select_prompt
+ "Select..."
+ end
+
+ def select_prompt_option
+ "<option value=''>#{select_prompt}</option>"
+ end
+
+ # Use on index pages to create dropdown list of filtering criteria.
+ # Populate the filter list using a constant in the model corresponding to named scopes.
+ #
+ # Usage:
+ #
+ # - item.rb:
+ #
+ # scope :active, :conditions => { :is_active => true }
+ # scope :inactive, :conditions => { :is_active => false }
+ #
+ # FILTERS = [
+ # {:scope => "all", :label => "All"},
+ # {:scope => "active", :label => "Active Only"},
+ # {:scope => "inactive", :label => "Inactive Only"}
+ # ]
+ #
+ # - items/index.html.erb:
+ #
+ # <%= select_tag_for_filter("items", @filters, params) -%>
+ #
+ # - items_controller.rb:
+ #
+ # def index
+ # @filters = Item::FILTERS
+ # if params[:show] && params[:show] != "all" && @filters.collect{|f| f[:scope]}.include?(params[:show])
+ # @items = eval("@items.#{params[:show]}.order_by(params[:by], params[:dir])")
+ # else
+ # @items = @items.order_by(params[:by], params[:dir])
+ # end
+ # ...
+ # end
+ #
+ def select_tag_for_filter(model, nvpairs, params)
+ return unless model && nvpairs && ! nvpairs.empty?
+ options = { :query => params[:query] }
+ _url = url_for(eval("#{model}_url(options)"))
+ _html = %{<label for="show">Show:</label><br />}
+ _html << %{<select name="show" id="show" onchange="window.location='#{_url}' + '?show=' + this.value">}
+ nvpairs.each do |pair|
+ _html << %{<option value="#{pair[:scope]}"}
+ if params[:show] == pair[:scope] || ((params[:show].nil? || params[:show].empty?) && pair[:scope] == "all")
+ _html << %{ selected="selected"}
+ end
+ _html << %{>#{pair[:label]}}
+ _html << %{</option>}
+ end
+ _html << %{</select>}
+ end
+
+ # Returns a link_to tag with sorting parameters that can be used with ActiveRecord.order_by.
+ #
+ # To use standard resources, specify the resources as a plural symbol:
+ # sort_link(:users, 'email', params)
+ #
+ # To use resources aliased with :as (in routes.rb), specify the aliased route as a string.
+ # sort_link('users_admin', 'email', params)
+ #
+ # You can override the link's label by adding a labels hash to your params in the controller:
+ # params[:labels] = {'user_id' => 'User'}
+ def sort_link(model, field, params, html_options={})
+ if (field.to_sym == params[:by] || field == params[:by]) && params[:dir] == "ASC"
+ classname = "arrow-asc"
+ dir = "DESC"
+ elsif (field.to_sym == params[:by] || field == params[:by])
+ classname = "arrow-desc"
+ dir = "ASC"
+ else
+ dir = "ASC"
+ end
+
+ options = {
+ :anchor => html_options[:anchor] || nil,
+ :by => field,
+ :dir => dir,
+ :query => params[:query],
+ :show => params[:show]
+ }
+
+ options[:show] = params[:show] unless params[:show].blank? || params[:show] == 'all'
+
+ html_options = {
+ :class => "#{classname} #{html_options[:class]}",
+ :style => "color: white; font-weight: #{params[:by] == field ? "bold" : "normal"}; #{html_options[:style]}",
+ :title => "Sort by this field"
+ }
+
+ field_name = params[:labels] && params[:labels][field] ? params[:labels][field] : field.titleize
+
+ _link = model.is_a?(Symbol) ? eval("#{model}_url(options)") : "/#{model}?#{options.to_params}"
+ link_to(field_name, _link, html_options)
+ end
+
+ # Tabbed interface helpers =======================================================================
+
+ # Returns formatted tabs with appropriate JS for activation. Use in conjunction with tab_body.
+ #
+ # Usage:
+ #
+ # <%- tabset do -%>
+ # <%= tab_tag :id => 'ppc_ads', :label => 'PPC Ads', :state => 'active' %>
+ # <%= tab_tag :id => 'budget' %>
+ # <%= tab_tag :id => 'geotargeting' %>
+ # <%- end -%>
+ #
+ def tabset(&proc)
+ concat %{
+ <div class="jump_links">
+ <ul>
+ }
+ yield
+ concat %{
+ </ul>
+ </div>
+ <br style="clear: both;" /><br />
+ <input type="hidden" id="show_tab" />
+ <script type="text/javascript">
+ function hide_all_tabs() { $$('.tab_block').invoke('hide'); }
+ function activate_tab(tab) {
+ $$('.tab_control').each(function(elem){ elem.className = 'tab_control'});
+ $('show_' + tab).className = 'tab_control active';
+ hide_all_tabs();
+ $(tab).toggle();
+ $('show_tab').value = tab
+ }
+ function sticky_tab() { if (location.hash) { activate_tab(location.hash.gsub('#','')); } }
+ Event.observe(window, 'load', function() { sticky_tab(); });
+ </script>
+ }
+ end
+
+ # Returns a tab body corresponding to tabs in a tabset. Make sure that the id of the tab_body
+ # matches the id provided to the tab_tag in the tabset block.
+ #
+ # Usage:
+ #
+ # <%- tab_body :id => 'ppc_ads', :label => 'PPC Ad Details' do -%>
+ # PPC ads form here.
+ # <%- end -%>
+ #
+ # <%- tab_body :id => 'budget' do -%>
+ # Budget form here.
+ # <%- end -%>
+ #
+ # <%- tab_body :id => 'geotargeting' do -%>
+ # Geotargeting form here.
+ # <%- end -%>
+ #
+ def tab_body(args, &proc)
+ concat %{<div id="#{args[:id]}" class="tab_block form_container" style="display: #{args[:display] || 'none'};">}
+ concat %{#{legend_tag args[:label] || args[:id].titleize }}
+ concat %{<a name="#{args[:id]}"></a><br />}
+ yield
+ concat %{</div>}
+ end
+
+ # Returns the necessary HTML for a particular tab. Use inside a tabset block.
+ # Override the default tab label by specifying a :label parameter.
+ # Indicate that the tab should be active by setting its :state to 'active'.
+ # (NOTE: You must define a corresponding CSS style for active tabs.)
+ #
+ # Usage:
+ #
+ # <%= tab_tag :id => 'ppc_ads', :label => 'PPC Ads', :state => 'active' %>
+ #
+ def tab_tag(args, *css_class)
+ %{<li id="show_#{args[:id]}" class="tab_control #{args[:state]}" onclick="window.location='##{args[:id]}'; activate_tab('#{args[:id]}');">#{args[:label] || args[:id].to_s.titleize}</li>}
+ end
+
+ # ================================================================================================
+
+ def tag_for_collapsible_row(obj, params)
+ _html = ""
+ if obj && obj.respond_to?(:parent) && obj.parent
+ _html << %{<tr class="#{obj.class.name.downcase}_#{obj.parent.id} #{params[:class]}" style="display: none; #{params[:style]}">}
+ else
+ _html << %{<tr class="#{params[:class]}" style="#{params[:style]}">}
+ end
+ _html
+ end
+
+ def tag_for_collapsible_row_control(obj)
+ _base_id = "#{obj.class.name.downcase}_#{obj.id}"
+ _html = %{<div id="hide_or_show_#{_base_id}" class="show_link" style="background-color: #999999; border: 1px solid #999999;" onclick="javascript:hide_or_show('#{_base_id}');"></div>}
+ end
+
+ # Create a set of tags for displaying a field label with inline help.
+ # Field label text is appended with a ? icon, which responds to a click
+ # by showing or hiding the provided help text.
+ #
+ # Sample usage:
+ #
+ # <%= tag_for_label_with_inline_help 'Relative Frequency', 'rel_frequency', 'Relative frequency of search traffic for this keyword across multiple search engines, as measured by WordTracker.' %>
+ #
+ # Yields:
+ #
+ # <label for="rel_frequency">Relative Frequency: <%= image_tag "/images/help_icon.png", :onclick => "$('rel_frequency_help').toggle();", :class => 'inline_icon' %></label><br />
+ # <div class="inline_help" id="rel_frequency_help" style="display: none;">
+ # <p>Relative frequency of search traffic for this keyword across multiple search engines, as measured by WordTracker.</p>
+ # </div>
+ def tag_for_label_with_inline_help( label_text, field_id, help_text )
+ _html = ""
+ _html << %{<label for="#{field_id}">#{label_text}}
+ _html << %{<img src="/images/icons/help_icon.png" onclick="$('#{field_id}_help').toggle();" class='inline_icon' />}
+ _html << %{</label><br />}
+ _html << %{<div class="inline_help" id="#{field_id}_help" style="display: none;">}
+ _html << %{<p>#{help_text}</p>}
+ _html << %{</div>}
+ _html
+ end
+
+ # Create a set of tags for displaying a field label followed by instructions.
+ # The instructions are displayed on a new line following the field label.
+ #
+ # Usage:
+ #
+ # <%= tag_for_label_with_instructions 'Status', 'is_active', 'Only active widgets will be visible to the public.' %>
+ #
+ # Yields:
+ #
+ # <label for="is_active">
+ # Status<br />
+ # <span class="instructions">Only active widgets will be visible to the public.</span>
+ # <label><br />
+ def tag_for_label_with_instructions( label_text, field_id, instructions )
+ _html = ""
+ _html << %{<label for="#{field_id}">#{label_text}}
+ _html << %{<span class="instructions">#{instructions}</span>}
+ _html << %{</label><br />}
+ _html
+ end
+
+ end
+
end
+
+ActionView::Base.send :include, MirExtensions::HelperExtensions