more cracked-out scaffolding: Element.twisty
Courtenay : February 2nd, 2006
For anyone following this, I'm slowly building you up to a fully-featured sortable, filtered scaffold helper library.
You may recall we already built filtering with SELECT dropdowns. I'm going to add an input box and some sorting to that.
First, though, we need a little sumthin sumthin to simplify the UI: the twisty!
The twisty is the proper name for that little triangly ► which turns into a ▼ when you click it, revealing some more information (maybe a tree node, or more options).
We're going to extend prototype's Element object to create Element.twisty. It'll all make sense later, I promise. First, here's the functionality we're heading for:
You're probably going to want some signifier of order (ascending, descending) so we'll use the unicode characters ▲ and ▼ I'm going to make this one a helper method, so our code looks nicer.
explanation
The code simply toggles a hidden div, and depending on the visibility, changes the little arrow to match. Things to look out for in this code: returns false, so you can return Element.twisty and it won't jump to the top of the page; takes a string or a DOM node; uses unicode for the twisties; requires a SPAN element in your A.
you know I can't leave it alone
Why stop there? Let's set up a default box for the twisty to show/hide.. and while we're at it, if the twisty <a> doesn't have a SPAN in it, we'll generate one automagically.
Object.extend(Element, {
twisty: function(element, _next) {
element = $(element);
var span = element.getElementsByTagName('SPAN');
// automatically generate that SPAN if she doesn't exist
if (span.length == 0) {
span = document.createElement('span');
span.className = 'twisty';
element.appendChild(span);
}
else span = span[0];
// use a default action to find the node to hide/show
if (!_next) _next = findParent(element, 'li').nextSibling;
span.innerHTML = (_next.style.display == 'none') ? '▼' : '►'
Element.toggle(_next);
return false;
}
});
This way, it will apply automatically to a UL by hiding or showing the next LI, unless you override _next. so <a onclick='return Element.twisty(this)' href='#' > will work. Of course you can modify this yourself.
(FYI, this example won't quite work as published, you need to Element.cleanWhitespace the parent UL in firefox, but I'm trying to keep it simple)
OK, so we have a twisty
Let's add sorting to our filterable table header. To keep the UI nice and simple, we're going to hide the filter boxes and make the TH clickable for sorting.
monkey
foo
Non-sortable
filter
monkey one
something
sample data
hint: click 'filter'
| monkey | foo | Non-sortable | filter ► |
|---|---|---|---|
| monkey one | something | sample data | |
| monkey two | somethin else | jaket sux |
You're probably going to want some signifier of order (ascending, descending) so we'll use the unicode characters ▲ and ▼ I'm going to make this one a helper method, so our code looks nicer.
def table_sorting_header(fieldname, options = { :default => false })
params[:order] ||= "#{fieldname} asc" if options[:default] == true
if params[:order] == "#{fieldname} asc"
"#{fieldname}" +
"▲"
elsif params[:order] == "#{fieldname} desc"
"#{fieldname}" +
"▼"
else
"#{fieldname}"
end
end
Call it like <%= table_sorting_header 'monkey' %> or if you sort one of the columns by default, <%= table_sorting_header 'id', { :default => true } %> on that column.
There's the view done.. hook it up!
Open up the controller and fire away.. You'll need the revised Hash#to_sql that converts '%' queries to 'LIKE'.
def list
@order = params[:order].gsub(/^(\w)\s/, "LOWER ($1) ") if params[:order] =~ /^(monkey|foo|id) (asc|desc)$/
@conditions[:monkey] = "%#{params[:monkey]}%" } if params[:monkey]
@conditions[:foo] = "%#{params[:foo]}%" if params[:foo]
@monkey_pages, @monkeys = paginate :monkey, :per_page => 20, :order => @order, :conditions => @conditions.to_sql
end
As always, fire away with your comments and questions..
3 Responses to “more cracked-out scaffolding: Element.twisty”
Sorry, comments are closed for this article.
February 3rd, 2006 at 12:32 AM This is rad. I like where this is going. I've already dabbled in setting up something like this: Ruby on Rails Grid Control RoR Grid Control Part II I am definitely going to incorporate your ideas to improve it... Now if we could just make it look like this (clean refined look, scrollable data, fixed headers, resizable columns) And work like this (no paging, just scrolling, with ajax) One can dream. :)
February 3rd, 2006 at 01:56 AM Aww, sweet. But why put the arrow _after_ the text? It looks so much nicer before it...
February 6th, 2006 at 04:12 PM I believe in Mac UI parlance, this is called the Disclosure Triangle.