Script.aculo.us - Effect.Appear display: and background: solutions 36

Posted by Bart Mon, 18 Sep 2006 15:57:00 GMT

There’s bit of a bug with Effect.Appear and IE. There’s a discussion open on it here.

Basically there are 2 issues discussed with Effect.Appear:

  1. doesn’t work if the display: property is not set to ‘none‘
  2. if the :background property is not set, the text is bolded while appearing, then switches to the chosen weight

The obvious remedy to both 1) and 2) is to set display: none; and background: #hex; before calling Effect.Appear. The problem with 2) occurs when you’re background is an image.

For my use, I needed to repeatedly call Effect.Appear using the Rails AJAX method periodically_call_remote. I’ve setup the following JavaScript function to handle 1) and 2). It can be used as a one time call before calling Appear, or repeated calls as in my use. See the quote fading in after a few seconds on the w2wwp implementation of my Simple CMS Rails app.

=> RHTML
  :complete => "myAppear('myDiv', '#ccc')" 

=> JavaScript
  function myAppear( mydiv, bckgrd)
  { 
    el = document.getElementById(mydiv); 
    el.style.background = bckgrd; 
    el.style.display = 'none'; 
    new Effect.Appear(mydiv);
  }

Protoype Effects with CSS and Tables 175

Posted by Bart Tue, 08 Aug 2006 22:48:00 GMT

One thing I’ve been struggling with the last day was how to incorporate Prototypes Effects into an HTML table. I need a well formatted list of records, something easily done with a <table>, but something that will take advantage of AJAXian effects. Here's the final product. Read on to see how I got it.


The problem is that IE doesn’t remove a table’s elements out of the DOM, and as of recently, Firefox doesn’t either, unless you walk through the DOM. There’s a great description of how to delete records through the DOM using JavaScript here. So to avoid tables, and for example use Effect.Fade to remove a record on deletion, I’d have to use pure CSS and struggle with the cross-browser inconsistencies. Searching the web, I found some great techniques for dealing with these issues, but not being a CSS god, I needed a simpler solution. Another great tool for record handling is SortTables from script.aculo.us. It allows you to move the records around. But still, not what I’m looking for.


So to only use Prototype (actually Effect.Fade is script.aculo.us, which is built on top of Prototype), I found that a combination of CSS and tables does the trick. What you need is a CSS Record id, and a CSS Column class element. Then create a table for each row in your database, assigning the entire table to your CSS Record id. You can equally wrap the entire table into a div. Next, set each <td>’s class to your Column Class. The key is to set the columns width: property in order to have a uniform layout. If each column’s width is the same, you only need one of these defined in CSS. For my example below, each column is different, so I defined 4 different column classes.


Here, I list User objects, with the option to Delete each record. I use link_to_remote with Effect.Fade to delete the record from the database, then fade the record out from the DOM.


If you’re using scaffold, here’s what you need:

CSS content

File: scaffold.css

#cssRecord{
  width: 700px;
  border-top:   1px solid #000000;
  border-left:  1px solid #000000;
  border-right: 1px solid #000000;
  background:   #ffffff;
}

#cssRecord th { 
  background: #dddddd; 
  font-size: 14px; 
  vertical-align: top; 
  text-align: left; 
}

#cssRecord td { 
  background: #eeeeee; 
  font-size: 12px; 
  vertical-align: top; 
  text-align: left; 
}

/** you’ll need a new set of these for each table type  **/
#cssRecord .cssUserCol1 { width: 15%; }
#cssRecord .cssUserCol2 { width: 15%; }
#cssRecord .cssUserCol3 { width: 60%; }
#cssRecord .cssUserCol4 { width: 10%; text-align: center; }

RHMTL Content

– see below for explanation of split_str method.

File: list.rhmtl

<h1>Listing users</h1>
  <table id="cssRecord" cellpadding="2" cellspacing="2"><tr>
    <th class="cssUserCol1">Name</th>
    <th class="cssUserCol2">Date</th>
    <th class="cssUserCol3">Description</th>
    <th class="cssUserCol4"></th>
  </tr></table>

  <% for user in @users -%>
  <div id="userObject<%= user.id %>">
    <table id="cssRecord" cellpadding="2" cellspacing="2"><tr>
      <td class="cssUserCol1"><%= link_to h(split_str(user.name), 10), 
           :action => 'show', :id => user, :controller => 'admin' -%></td>
      <td class="cssUserCol2"><%=h split_str(user.created_on.strftime("%d %B %Y"), 10) 
           -%></td>
      <td class="cssUserCol3"><%=h split_str(user.description, 50) -%></td>

      <td class="cssUserCol4"><%= link_to_remote 'Delete', 
                       :complete => "new Effect.Fade('userObject#{user.id}')",
                       :url => {:action => 'fake_destroy',
                          		:controller => 'admin',
                          		:id => user}, 
                        :confirm => 'Are you sure?', :post => true  
                    -%>
      </td>
    </tr></table>
  </div>
  <% end -%>

If your field content doesn’t wrap within the length you chose, it will realign the columns for that row only, which is messy and defeats the purpose. To remedy this, I created a method to split longer strings. It’s not the best way I’m sure, but works quite well. Just put it into your *_helper.rb file, and pass the object to it. I used it for the cssUserCol2 and cssUserCol3.


File: *_helper.rb

def split_str(str=nil, len=10, char=" ")
 work_str = str.to_s.split(//) if str
  return_str = ""
  i = 0
  if work_str
    work_str.each do |s|
      if (s == char || i == len)
        return_str += char
        return_str += s if s != char
        i = 0
      else
        return_str += s
        i += 1
      end
    end
  end
  return_str
end