Showing posts with label icons. Show all posts
Showing posts with label icons. Show all posts

Wednesday, 27 November 2013

Link: loading-icon generator

Load info is a neat website that lets you generate your own loading icon.

The first page has a hypnotising array of load-icons to choose. Click on one and it'll bring up a box that lets you choose the size and colours you want and it'll generate you a customised animated gif you can use.

Tuesday, 29 July 2008

icon_button_to_remote

Following from my earlier post on making icon buttons, I needed to add AJAXy goodness to the edit actions on one of our index pages.... but I still wanted cute little icons to make them look pretty.

So I've updated the code to incorporate an icon_button_to_remote method. Note that icon_button_to has also been modified, but it still depends upon the get_icon_path and fixed_button_to methods from the previous post.

  # generates appropriate image-buttons, given an "icon type" and the usual
  # button options.
  def icon_button_to(icon_type, icon_label, form_opts = nil, button_opts = {})
    unless form_opts.blank?
      button_opts.merge!(:type => 'image', :src => get_icon_path(icon_type), 
                       :alt => icon_label, :title => icon_label)
      the_icon = fixed_button_to(icon_label, form_opts, button_opts)
    else
      # no form was passed in - we want a non-linked icon.
      the_icon = image_tag(get_icon_path(icon_type), :width => 16, :height => '16', 
                       :alt => icon_label, :title => icon_label)
    end
    content_tag 'div', the_icon, :class => 'icon_button'
  end
  # add a remote AJAX-linked icon button
  def icon_button_to_remote(icon_type, icon_label, remote_options = {}, button_options = {})
    link_to_remote(icon_button_to(icon_type, icon_label, nil, button_options), remote_options)
  end

The example would be for an index page with a list of Widgets. Each one has an "edit" button using the code below. The page also has a section for entering a new widget - which would be replaced by the "edit this widget" template when you click on the icon.

<!-- In the template at the top of the list -->
<%= w_path = new_widget_path() # url_for is slow
    icon_button_to_remote(
         :new, 'Add new widget', 
         :update => 'new_widget_div',
         :url => w_path,
         :method => :get,
         :html => {:href => w_path},
         :complete => "Element.hide('edit_widget_div'); 
                          Element.show('new_widget_div'); 
                          new Effect.Highlight('new_widget_div');"
        ) -%>

<!-- and next to each widget -->
<%= ew_path = edit_widget_path(@widget) # url_for is slow
    icon_button_to_remote(
         :edit, 'Edit this widget', 
         :update => 'edit_widget_div',
         :url => ew_path,
         :method => :get,
         :html => {:href => ew_path},
         :complete => "Element.hide('new_widget_div'); 
                          Element.show('edit_widget_div'); 
                          new Effect.Highlight('edit_widget_div');"
        ) -%>

<!-- Later in the template... -->
<div id="new_widget_div">New widget form would go here</div>

<div id="edit_widget_div" style="display:none;">Edit widget form will be populated here</div>

You also have to update your Controller code for the new and edit actions to accept js and respond with no layout - otherwise your div gets populated with the entire edit/new page :P

The best way is to move the meat of the page into a partial (which can also be loaded in the edit.rhtml template) callable from the action thus:

  def edit
    respond_to do |format|
      format.js { return render(:partial => 'edit', :layout => false) }
      format.html # edit.rhtml
    end
  end

Monday, 21 April 2008

icon buttons

We're all pretty used to the CRUD-based scaffold-ful of actions on a resource index page - such things as "show", "edit" and "delete". But adding a few columns and a few extra actions, causes a swiftly increasing footprint which gets real ugly, real fast.

Buttons stack on top of one another, or they wrap in random ways, or they take up half the width of the screen and squish up all the other data.

The soluion, of course, is to make nifty little icon-buttons. But how do we make this RESTful and DRY?

fixed_button_to

Standard button_to is a wonder - it does practically everything a button needs, and you can override anything...

Well, almost - as I discovered when I first tried to make an image-based button. The "type" is set to submit every time. The following line of code is the culprit:

html_options.merge!("type" => "submit", "value" => name)

So even from the get-go, we need to monkey-patch button_to

You can override the method, or rename it to something else - whatever you like... but sadly you'll need to actually copy the whole button_to code and replace it. So I just created a newly named method. Drop the following into environment.rb (or similar) for buttony joy:

module ActionView::Helpers::UrlHelper
  def fixed_button_to(name, options = {}, html_options = {})
    html_options = html_options.stringify_keys
    convert_boolean_attributes!(html_options, %w( disabled ))

    method_tag = ''
    if (method = html_options.delete('method')) && %w{put delete}.include?(method.to_s)
      method_tag = tag('input', :type => 'hidden', :name => '_method', :value => method.to_s)
    end

    form_method = method.to_s == 'get' ? 'get' : 'post'
   
    request_token_tag = ''
    if form_method == 'post' && respond_to?(:protect_against_forgery?) && protect_against_forgery? 
      request_token_tag = tag(:input, :type => "hidden", :name => request_forgery_protection_token.to_s, 
:value => form_authenticity_token)
    end
    
    if confirm = html_options.delete("confirm")
      html_options["onclick"] = "return #{confirm_javascript_function(confirm)};"
    end

    url = options.is_a?(String) ? options : self.url_for(options)
    name ||= url

    html_options = {"type" => "submit", "value" => name}.merge(html_options)

    "<form method=\"#{form_method}\" action=\"#{escape_once url}\" class=\"button-to\"><div>" +      
method_tag + tag("input", html_options) + request_token_tag + "</div></form>"
  end
end

Those with an unhealthy familiarity with the minutiae of the Rails source will also notice that I added a respond_to?(:protect_against_forgery?) check in there too. My site doesn't use that, and it kept breaking without the check (there must be some magic place its set in a normal Controller/Helper, but it doesn't get in there from here).

icon_button_to

Next up is to write our nifty icon_button_to helper. I use the following:

  # quick and  dodgy icon path-generator
  def get_icon_path(icon_type = 'default')
    icon_name = ACTION_ICONS.include?(icon_type.to_s) ? icon_type : 'default'
    "/images/icons/#{icon_name}.png"
  end

  # generates appropriate image-buttons, given an "icon type" and the usual
  # button options.
  def icon_button_to(icon_type, icon_label, form_path, button_opts = {})
    button_opts.merge!('type' => 'image', :src => get_icon_path(icon_type), 
                       :alt => icon_label, :title => icon_label)
    content_tag 'div', fixed_button_to(icon_label, form_path, button_opts), 
      :class => 'icon_button'
  end

Note that each icon is confined within a div classed icon_button. This allows us to neatly style each button thus:

.icon_button {
  float: left;
  padding: 0 5px 0 0; /* each icon needs a small gap between */
  margin: 0;
}

Iconography

Using the above is simple. It's the same as a normal button_to., but you add the icon_type to the front... and make sure you actually have an icon named after that type sitting in the appropriate image directory. Examples follow:


<%= icon_button_to(:edit, 'Edit order', order_path(order.id), :method => :get) -%>
<%= icon_button_to(:show, 'See order', order_path(order), :method => :get) -%>
<%= icon_button_to(:submit, 'Submit order for processing', submit_order_path(order), 
  :method => :put,  :confirm => 'This will submit the order for processing. Are you sure?') if order.valid_to_submit? -%>
<%= icon_button_to(:delete, 'Delete this order', order_path(order),
  :method => :delete,  :confirm => 'This will delete this order permanently! Are you sure?') unless order.submitted? -%>