<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DZone Snippets: Sporkyy's Code Snippets</title>
    <link>http://snippets.dzone.com/posts</link>
    <pubDate>Thu, 22 May 2008 19:49:31 GMT</pubDate>
    <description>DZone Snippets: Sporkyy's Code Snippets</description>
    <item>
      <title>Rails helpers for A List Apart No. 256</title>
      <link>http://snippets.dzone.com/posts/show/5435</link>
      <description>I cooked up some Ruby on Rails helpers for testing the techniques in the article &lt;a href="http://www.alistapart.com/articles/accessibledatavisualization"&gt;Accessible Data Visualization with Web Standards&lt;/a&gt; from A List Apart &lt;a href="http://www.alistapart.com/issues/256"&gt;No. 256&lt;/a&gt;. If you want to know more about Rails, check out &lt;a href="http://www.alistapart.com/issues/257"&gt;No. 257&lt;/a&gt;. If you want to be smarter, read &lt;a href="http://www.alistapart.com/"&gt;A List Apart every week&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;code&gt;def chartlist(data)&lt;br /&gt;  total = data.inject(0.0) { |sum, datum| sum + datum[:count] }&lt;br /&gt;  bars = ''&lt;br /&gt;&lt;br /&gt;  data.each do |datum|&lt;br /&gt;    link  = content_tag 'a', datum[:name], :href =&gt; datum[:href]&lt;br /&gt;    count = content_tag 'span', datum[:count], :class =&gt; 'count'&lt;br /&gt;    index = content_tag 'span', "(#{(datum[:count]/total*100).to_i}%)", :class =&gt; 'index', :style =&gt; "width: #{(datum[:count]/total*100).to_i}%"&lt;br /&gt;    bars &lt;&lt; content_tag('li', link &lt;&lt; count &lt;&lt; index)&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;  content_tag 'ul', bars, :class =&gt; 'chartlist'&lt;br /&gt;end&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Sample data for a chartlist (&lt;a href="http://www.alistapart.com/d/accessibledata/example-barchart.html"&gt;example&lt;/a&gt;)&lt;br /&gt;&lt;br /&gt;&lt;code&gt;data = [{ :name =&gt; 'Apples',   :count =&gt; 420, :href =&gt; 'http://www.example.com/fruits/apples/' },&lt;br /&gt;        { :name =&gt; 'Bananas',  :count =&gt; 280, :href =&gt; 'http://www.example.com/fruits/bananas/' },&lt;br /&gt;        { :name =&gt; 'Cherries', :count =&gt; 200, :href =&gt; 'http://www.example.com/fruits/cherries/' },&lt;br /&gt;        { :name =&gt; 'Dates',    :count =&gt; 100, :href =&gt; 'http://www.example.com/fruits/dates/' }]&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;code&gt;def sparkline(data)&lt;br /&gt;  max = data.sort.last.to_f&lt;br /&gt;  sparklines = ''&lt;br /&gt;&lt;br /&gt;  data.each_with_index do |datum, index|&lt;br /&gt;    count_string = datum.to_s&lt;br /&gt;    '(' &lt;&lt; count_string if index == 0&lt;br /&gt;    count_string &lt;&lt; ',' if index != data.length&lt;br /&gt;    count_string &lt;&lt; ')' if index == data.length&lt;br /&gt;    count = content_tag 'span', count_string, :class =&gt; 'count', :style =&gt; "height: #{(datum/max*100).to_i}%"&lt;br /&gt;    index = content_tag 'span', count &lt;&lt; ' ', :class =&gt; 'index'&lt;br /&gt;    sparklines &lt;&lt; index&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;  content_tag('span', sparklines, :class =&gt; 'sparkline')&lt;br /&gt;end&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Sample data for sparklines (&lt;a href="http://www.alistapart.com/d/accessibledata/example-sparklines.html"&gt;example&lt;/a&gt;)&lt;br /&gt;&lt;br /&gt;&lt;code&gt;data = [60, 220, 140, 80, 110, 90, 180, 140, 120, 160, 175, 225, 175, 125]&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;code&gt;def timeline(data)&lt;br /&gt;  max = data.sort { |a, b| a[:count] &lt;=&gt; b[:count] }.last[:count]&lt;br /&gt;  bars = ''&lt;br /&gt;&lt;br /&gt;  data.each do |datum|&lt;br /&gt;    label = content_tag 'span', datum[:label], :class =&gt; 'label'&lt;br /&gt;    count = content_tag 'span', "(#{datum[:count]})", :class =&gt; 'count', :style =&gt; "height: #{(datum[:count]/max.to_f*100).to_i}%"&lt;br /&gt;    link  = content_tag 'a', label &lt;&lt; count, :href =&gt; datum[:href], :title =&gt; "#{datum[:label]}: #{datum[:count]}"&lt;br /&gt;    bars &lt;&lt; content_tag('li', link, :style =&gt; "width: #{(100.0/data.length).to_i}%")&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;  content_tag 'ul', bars, :class =&gt; 'timeline'&lt;br /&gt;end&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Sample data for a timeline (&lt;a href="http://www.alistapart.com/d/accessibledata/example-timeline.html"&gt;example&lt;/a&gt;)&lt;br /&gt;&lt;br /&gt;&lt;code&gt;data = [{ :date =&gt; '2007-12-01', :count =&gt;  40, label =&gt; '1' },&lt;br /&gt;        { :date =&gt; '2007-12-02', :count =&gt; 100, label =&gt; '2' },&lt;br /&gt;        { :date =&gt; '2007-12-03', :count =&gt; 150, label =&gt; '3' }]&lt;/code&gt;</description>
      <pubDate>Sun, 27 Apr 2008 23:01:52 GMT</pubDate>
      <guid>http://snippets.dzone.com/posts/show/5435</guid>
      <author>sporkyy (Todd Sayre)</author>
    </item>
    <item>
      <title>Blueprint CSS forms extension</title>
      <link>http://snippets.dzone.com/posts/show/5010</link>
      <description>Changes the widths of form elements so they fit into smaller columns created using the &lt;a href="http://code.google.com/p/blueprintcss/"&gt;Blueprint CSS framework&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;code&gt;div.span-1 input.text, div.span-1 input.title { width:  30px; }&lt;br /&gt;div.span-2 input.text, div.span-2 input.title { width:  50px; }&lt;br /&gt;div.span-3 input.text, div.span-3 input.title { width:  90px; }&lt;br /&gt;div.span-4 input.text, div.span-4 input.title { width: 130px; }&lt;br /&gt;div.span-5 input.text, div.span-5 input.title { width: 170px; }&lt;br /&gt;div.span-6 input.text, div.span-6 input.title { width: 210px; }&lt;br /&gt;div.span-7 input.text, div.span-7 input.title { width: 250px; }&lt;br /&gt;div.span-8 input.text, div.span-8 input.title { width: 290px; }&lt;br /&gt;&lt;br /&gt;div.span-1 select { width:  30px; }&lt;br /&gt;div.span-2 select { width:  50px; }&lt;br /&gt;div.span-3 select { width:  90px; }&lt;br /&gt;div.span-4 select { width: 130px; }&lt;br /&gt;div.span-5 select { width: 170px; }&lt;br /&gt;&lt;br /&gt;div.span-1  textarea { width:  30px; height:  25px; }&lt;br /&gt;div.span-2  textarea { width:  50px; height:  50px; }&lt;br /&gt;div.span-3  textarea { width:  90px; height:  75px; }&lt;br /&gt;div.span-4  textarea { width: 130px; height: 100px; }&lt;br /&gt;div.span-5  textarea { width: 170px; height: 125px; }&lt;br /&gt;div.span-6  textarea { width: 210px; height: 150px; }&lt;br /&gt;div.span-7  textarea { width: 250px; height: 175px; }&lt;br /&gt;div.span-8  textarea { width: 290px; height: 200px; }&lt;br /&gt;div.span-9  textarea { width: 330px; height: 225px; }&lt;br /&gt;div.span-10 textarea { width: 370px; height: 250px; }&lt;/code&gt;</description>
      <pubDate>Sat, 19 Jan 2008 17:00:14 GMT</pubDate>
      <guid>http://snippets.dzone.com/posts/show/5010</guid>
      <author>sporkyy (Todd Sayre)</author>
    </item>
    <item>
      <title>Collapse ranges in arrays</title>
      <link>http://snippets.dzone.com/posts/show/4099</link>
      <description>Takes an Array and turns consecutive integers into Range objects.&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;class Array&lt;br /&gt;    def collapse_ranges&lt;br /&gt;        return self if self.length &lt;= 2&lt;br /&gt;        self.uniq!&lt;br /&gt;        self.sort! rescue nil&lt;br /&gt;        temp_array, return_array = [], []&lt;br /&gt;        self.each_with_index do |item, i|&lt;br /&gt;            if item.respond_to?(:next)&lt;br /&gt;                temp_array.push item&lt;br /&gt;                if item.next != self[i + 1]&lt;br /&gt;                    return_array.concat 3 &lt;= temp_array.length ?&lt;br /&gt;                        [temp_array.first..temp_array.last] :&lt;br /&gt;                         temp_array&lt;br /&gt;                    temp_array.clear&lt;br /&gt;                end&lt;br /&gt;            else&lt;br /&gt;                return_array.concat 3 &lt;= temp_array.length ?&lt;br /&gt;                    [temp_array.first..temp_array.last] :&lt;br /&gt;                     temp_array&lt;br /&gt;                temp_array.clear&lt;br /&gt;                return_array.push item&lt;br /&gt;            end&lt;br /&gt;        end&lt;br /&gt;        return return_array&lt;br /&gt;    end&lt;br /&gt;end&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;&gt;&gt; [1, 3, 4, 5, 7, 8].collapse_ranges.join(', ')&lt;br /&gt;=&gt; 1, 3..5, 7, 8&lt;br /&gt;&gt;&gt; %w(a c d e g i j).collapse_ranges.join(', ')&lt;br /&gt;=&gt; a, c..e, g, i, j&lt;br /&gt;&gt;&gt; [1, 2.5, 3, 4, 5].collapse_ranges.join(', ')&lt;br /&gt;=&gt; 1, 2.5, 3..5&lt;br /&gt;&gt;&gt; [1, 2, 3, 4, {:test =&gt; 'value'}, 5].collapse_ranges.join(', ')&lt;br /&gt;=&gt; 1..4, testvalue, 5&lt;br /&gt;&lt;/code&gt;</description>
      <pubDate>Sun, 03 Jun 2007 17:59:53 GMT</pubDate>
      <guid>http://snippets.dzone.com/posts/show/4099</guid>
      <author>sporkyy (Todd Sayre)</author>
    </item>
    <item>
      <title>Find missing array items</title>
      <link>http://snippets.dzone.com/posts/show/3322</link>
      <description>This works fine for integers and letters.  It should work for anything though, so long as Ruby can form an range from the first and last array items.&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;class Array&lt;br /&gt;    def missing_items&lt;br /&gt;        return [] if self.length &lt;= 1&lt;br /&gt;        self.uniq!&lt;br /&gt;        self.sort! rescue nil&lt;br /&gt;        begin&lt;br /&gt;            (self.first..self.last).to_a - self&lt;br /&gt;        rescue&lt;br /&gt;            []&lt;br /&gt;        end&lt;br /&gt;    end&lt;br /&gt;end&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;&gt;&gt; [1, 3, 4, 10].missing_items.join(', ')&lt;br /&gt;=&gt; 2, 5, 6, 7, 8, 9&lt;br /&gt;&gt;&gt; [1, 2, 7, 7.5, 8.2].missing_items.join(', ')&lt;br /&gt;=&gt; 3, 4, 5, 6, 8&lt;br /&gt;&gt;&gt; %w(a b c f g j).missing_items.join(', ')&lt;br /&gt;=&gt; d, e, h, i&lt;br /&gt;&gt;&gt; [2.5, {:test =&gt; 'value'}].missing_items.join(', ')&lt;br /&gt;=&gt;&lt;br /&gt;&lt;/code&gt;</description>
      <pubDate>Thu, 18 Jan 2007 08:15:54 GMT</pubDate>
      <guid>http://snippets.dzone.com/posts/show/3322</guid>
      <author>sporkyy (Todd Sayre)</author>
    </item>
    <item>
      <title>Javascript Rails-like inflector</title>
      <link>http://snippets.dzone.com/posts/show/3205</link>
      <description>I was using Ajax to do some DOM manipulation in a Rails app I was working on.  None of what I was doing needed to involve a round trip to server, the only reason I hit the server at all was to take advantage of Rails' (well, ActiveSupport's) pluralize function.  Also, this technique required an extra action that I decided to eliminate as I try to move to a more RESTful architecture.&lt;br /&gt;&lt;br /&gt;The only part of ActiveSupport's Inflector class I implemented are the ones I needed.  I implemented even fewer of Rails' Inflector-based functions.&lt;br /&gt;&lt;br /&gt;Stick all this in a file, such as "inflector.js".&lt;br /&gt;&lt;code&gt;/*&lt;br /&gt; * This script depends on no outside libraries.&lt;br /&gt; */&lt;br /&gt;&lt;br /&gt;Inflector = {&lt;br /&gt;    /*&lt;br /&gt;     * The order of all these lists has been reversed from the way &lt;br /&gt;     * ActiveSupport had them to keep the correct priority.&lt;br /&gt;     */&lt;br /&gt;    Inflections: {&lt;br /&gt;        plural: [&lt;br /&gt;            [/(quiz)$/i,               "$1zes"  ],&lt;br /&gt;            [/^(ox)$/i,                "$1en"   ],&lt;br /&gt;            [/([m|l])ouse$/i,          "$1ice"  ],&lt;br /&gt;            [/(matr|vert|ind)ix|ex$/i, "$1ices" ],&lt;br /&gt;            [/(x|ch|ss|sh)$/i,         "$1es"   ],&lt;br /&gt;            [/([^aeiouy]|qu)y$/i,      "$1ies"  ],&lt;br /&gt;            [/(hive)$/i,               "$1s"    ],&lt;br /&gt;            [/(?:([^f])fe|([lr])f)$/i, "$1$2ves"],&lt;br /&gt;            [/sis$/i,                  "ses"    ],&lt;br /&gt;            [/([ti])um$/i,             "$1a"    ],&lt;br /&gt;            [/(buffal|tomat)o$/i,      "$1oes"  ],&lt;br /&gt;            [/(bu)s$/i,                "$1ses"  ],&lt;br /&gt;            [/(alias|status)$/i,       "$1es"   ],&lt;br /&gt;            [/(octop|vir)us$/i,        "$1i"    ],&lt;br /&gt;            [/(ax|test)is$/i,          "$1es"   ],&lt;br /&gt;            [/s$/i,                    "s"      ],&lt;br /&gt;            [/$/,                      "s"      ]&lt;br /&gt;        ],&lt;br /&gt;        singular: [&lt;br /&gt;            [/(quiz)zes$/i,                                                    "$1"     ],&lt;br /&gt;            [/(matr)ices$/i,                                                   "$1ix"   ],&lt;br /&gt;            [/(vert|ind)ices$/i,                                               "$1ex"   ],&lt;br /&gt;            [/^(ox)en/i,                                                       "$1"     ],&lt;br /&gt;            [/(alias|status)es$/i,                                             "$1"     ],&lt;br /&gt;            [/(octop|vir)i$/i,                                                 "$1us"   ],&lt;br /&gt;            [/(cris|ax|test)es$/i,                                             "$1is"   ],&lt;br /&gt;            [/(shoe)s$/i,                                                      "$1"     ],&lt;br /&gt;            [/(o)es$/i,                                                        "$1"     ],&lt;br /&gt;            [/(bus)es$/i,                                                      "$1"     ],&lt;br /&gt;            [/([m|l])ice$/i,                                                   "$1ouse" ],&lt;br /&gt;            [/(x|ch|ss|sh)es$/i,                                               "$1"     ],&lt;br /&gt;            [/(m)ovies$/i,                                                     "$1ovie" ],&lt;br /&gt;            [/(s)eries$/i,                                                     "$1eries"],&lt;br /&gt;            [/([^aeiouy]|qu)ies$/i,                                            "$1y"    ],&lt;br /&gt;            [/([lr])ves$/i,                                                    "$1f"    ],&lt;br /&gt;            [/(tive)s$/i,                                                      "$1"     ],&lt;br /&gt;            [/(hive)s$/i,                                                      "$1"     ],&lt;br /&gt;            [/([^f])ves$/i,                                                    "$1fe"   ],&lt;br /&gt;            [/(^analy)ses$/i,                                                  "$1sis"  ],&lt;br /&gt;            [/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/i, "$1$2sis"],&lt;br /&gt;            [/([ti])a$/i,                                                      "$1um"   ],&lt;br /&gt;            [/(n)ews$/i,                                                       "$1ews"  ],&lt;br /&gt;            [/s$/i,                                                            ""       ]&lt;br /&gt;        ],&lt;br /&gt;        irregular: [&lt;br /&gt;            ['move',   'moves'   ],&lt;br /&gt;            ['sex',    'sexes'   ],&lt;br /&gt;            ['child',  'children'],&lt;br /&gt;            ['man',    'men'     ],&lt;br /&gt;            ['person', 'people'  ]&lt;br /&gt;        ],&lt;br /&gt;        uncountable: [&lt;br /&gt;            "sheep",&lt;br /&gt;            "fish",&lt;br /&gt;            "series",&lt;br /&gt;            "species",&lt;br /&gt;            "money",&lt;br /&gt;            "rice",&lt;br /&gt;            "information",&lt;br /&gt;            "equipment"&lt;br /&gt;        ]&lt;br /&gt;    },&lt;br /&gt;    ordinalize: function(number) {&lt;br /&gt;        if (11 &lt;= parseInt(number) % 100 &amp;&amp; parseInt(number) % 100 &lt;= 13) {&lt;br /&gt;            return number + "th";&lt;br /&gt;        } else {&lt;br /&gt;            switch (parseInt(number) % 10) {&lt;br /&gt;                case  1: return number + "st";&lt;br /&gt;                case  2: return number + "nd";&lt;br /&gt;                case  3: return number + "rd";&lt;br /&gt;                default: return number + "th";&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;    },&lt;br /&gt;    pluralize: function(word) {&lt;br /&gt;        for (var i = 0; i &lt; Inflector.Inflections.uncountable.length; i++) {&lt;br /&gt;            var uncountable = Inflector.Inflections.uncountable[i];&lt;br /&gt;            if (word.toLowerCase == uncountable) {&lt;br /&gt;                return uncountable;&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;        for (var i = 0; i &lt; Inflector.Inflections.irregular.length; i++) {&lt;br /&gt;            var singular = Inflector.Inflections.irregular[i][0];&lt;br /&gt;            var plural   = Inflector.Inflections.irregular[i][1];&lt;br /&gt;            if ((word.toLowerCase == singular) || (word == plural)) {&lt;br /&gt;                return plural;&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;        for (var i = 0; i &lt; Inflector.Inflections.plural.length; i++) {&lt;br /&gt;            var regex          = Inflector.Inflections.plural[i][0];&lt;br /&gt;            var replace_string = Inflector.Inflections.plural[i][1];&lt;br /&gt;            if (regex.test(word)) {&lt;br /&gt;                return word.replace(regex, replace_string);&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;function ordinalize(number) {&lt;br /&gt;    return Inflector.ordinalize(number);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;/*&lt;br /&gt; * Javascript doesn't have optional parameters or overloading so I had to use&lt;br /&gt; * the ever popular pseudo options hash object technique.&lt;br /&gt; * required properties:&lt;br /&gt; *     count    Number of objects to pluralize&lt;br /&gt; *     singular Singular noun for the objects&lt;br /&gt; * optional property:&lt;br /&gt; *     plural   Plural (probably irregular) noun for the objects&lt;br /&gt; * examples:&lt;br /&gt; *      pluralize({ count: total_count, singular: "Issue" })&lt;br /&gt; *      pluralize({ count: total_count, singular: "Goose", plural: "Geese" })&lt;br /&gt; */&lt;br /&gt;function pluralize(options) {&lt;br /&gt;    return options.count + " " + (1 == parseInt(options.count) ?&lt;br /&gt;        options.singular :&lt;br /&gt;        options.plural || Inflector.pluralize(options.singular));&lt;br /&gt;}&lt;/code&gt;</description>
      <pubDate>Tue, 26 Dec 2006 07:37:50 GMT</pubDate>
      <guid>http://snippets.dzone.com/posts/show/3205</guid>
      <author>sporkyy (Todd Sayre)</author>
    </item>
    <item>
      <title>Array percentages of the maximum</title>
      <link>http://snippets.dzone.com/posts/show/3204</link>
      <description>Returns an array whose elements are the percentage of each element compared to the maximum element in the array.&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&gt;&gt; [25, 150, 200, 5, 75, 125].percentages_of_maximum&lt;br /&gt;=&gt; [12, 75, 100, 2, 37, 62]&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;If you're using Rails, stick this in your "environment.rb" script in the "config" directory:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;class Array&lt;br /&gt;    def percentages_of_maximum&lt;br /&gt;        self.collect{ |i| ((i.to_f / self.sort.last.to_f) * 100).to_i }&lt;br /&gt;    end&lt;br /&gt;end&lt;/code&gt;</description>
      <pubDate>Tue, 26 Dec 2006 07:16:14 GMT</pubDate>
      <guid>http://snippets.dzone.com/posts/show/3204</guid>
      <author>sporkyy (Todd Sayre)</author>
    </item>
    <item>
      <title>FirstLast (real classes for Ajaxability)</title>
      <link>http://snippets.dzone.com/posts/show/2707</link>
      <description>I know CSS has the :first-child and :last-child pseudo classes.  But :first-child is a part of CSS 2 and has poor browsers support and :last-child is a part of CSS 3 and that's not worth thinking about using yet.  The idea is sound though, so I worked up this JavaScript method of getting the same effect.&lt;br /&gt;&lt;br /&gt;One advantage of doing this in JavaScript rather than using CSS is that the classes will change if you reorder the child nodes with more JavaScript.  In my case I'm using &lt;a href="http://wiki.script.aculo.us/scriptaculous/show/Sortables"&gt;Scriptaculous sortables&lt;/a&gt;.  Or to be more specific, I'm using a &lt;a href="http://api.rubyonrails.com/"&gt;Ruby on Rails&lt;/a&gt; helper method to make something sortable through Scriptaculous:&lt;br /&gt;&lt;code&gt;&lt;%= sortable_element 'image-list',&lt;br /&gt;    :constraint =&gt; false,&lt;br /&gt;    :url =&gt; { :action =&gt; 'sort', :issue_id =&gt; params[:issue_id] }&lt;br /&gt;-%&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;I've chosen to not make this script run unobtrusively.  Most of it can go into a file and be included in the header or added to your own common JavaScript include file.  To get it to run on a page you will need to include something like the below in each page.&lt;br /&gt;&lt;code&gt;&lt;script type="text/javascript"&gt;&lt;br /&gt;//&lt;![CDATA[&lt;br /&gt;    Event.onDOMReady(function(){FirstLast.go("image-list")});&lt;br /&gt;    Ajax.Responders.register({&lt;br /&gt;        onComplete: function(){FirstLast.go("image-list");}&lt;br /&gt;   });&lt;br /&gt;//]]&gt;&lt;br /&gt;&lt;/script&gt;&lt;/code&gt;&lt;br /&gt;I use the &lt;a href="http://www.vivabit.com/bollocks/2006/06/21/a-dom-ready-extension-for-prototype"&gt;DOMReady extension&lt;/a&gt; for Prototype's Event object, but you can use any loader you want.  The Ajax.Responders.register part reruns the script after a drag-and-drop operation (or any Ajax operation really).&lt;br /&gt;&lt;br /&gt;&lt;a href="http://script.aculo.us/downloads"&gt;Download Scriptaculous and Prototype.&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;code&gt;var FirstLast = {&lt;br /&gt;    go: function(el) {&lt;br /&gt;        el = $(el);&lt;br /&gt;&lt;br /&gt;        // Whitespace nodes need to be cleaned to get the intended effect&lt;br /&gt;        var children = Element.cleanWhitespace(el).childNodes;&lt;br /&gt;&lt;br /&gt;        // Return if there are not any children&lt;br /&gt;        if (0 == children.length) return&lt;br /&gt;        &lt;br /&gt;        if (1 == children.length) {&lt;br /&gt;            // Cheap shortcut if there is only 1 child node&lt;br /&gt;            children[0].addClassName(this._firstChildClassName);&lt;br /&gt;            children[0].addClassName(this._lastChildClassName);&lt;br /&gt;        } else {&lt;br /&gt;            for (var i = 0; i &lt; children.length; i++) {&lt;br /&gt;                switch (i) {&lt;br /&gt;                    // First child&lt;br /&gt;                    case 0:&lt;br /&gt;                        children[i].addClassName(this._firstChildClassName);&lt;br /&gt;                        children[i].removeClassName(this._lastChildClassName);&lt;br /&gt;                        break;&lt;br /&gt;                    // Last child&lt;br /&gt;                    case children.length - 1:&lt;br /&gt;                        children[i].removeClassName(this._firstChildClassName);&lt;br /&gt;                        children[i].addClassName(this._lastChildClassName);&lt;br /&gt;                        break;&lt;br /&gt;                    // Every child other than the first or last&lt;br /&gt;                    default:&lt;br /&gt;                        children[i].removeClassName(this._firstChildClassName);&lt;br /&gt;                        children[i].removeClassName(this._lastChildClassName);&lt;br /&gt;                        break;  // I know it is unnecessary&lt;br /&gt;                }&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;    },&lt;br /&gt;    // Pseudo Private methods and attributes&lt;br /&gt;    _firstChildClassName: "first",&lt;br /&gt;    _lastChildClassName: "last"&lt;br /&gt;};&lt;/code&gt;</description>
      <pubDate>Sun, 24 Sep 2006 19:16:32 GMT</pubDate>
      <guid>http://snippets.dzone.com/posts/show/2707</guid>
      <author>sporkyy (Todd Sayre)</author>
    </item>
    <item>
      <title>Number to Currency with Cents</title>
      <link>http://snippets.dzone.com/posts/show/2581</link>
      <description>A slight alteration to the default Rails currency formatting helper to show numbers in cents if the number is less than $1.00.  For example $0.99 would instead become 99&amp;cent;.&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;def number_to_currency_with_cents(number, options = {})&lt;br /&gt;    options = options.stringify_keys&lt;br /&gt;    precision = options.delete('precision') { 2 }&lt;br /&gt;    unit = options.delete('unit') { '$' }&lt;br /&gt;    fractional_unit = options.delete('fractional_unit') { '&amp;cent;' }&lt;br /&gt;    separator = options.delete('separator') { '.' }&lt;br /&gt;    delimiter = options.delete('delimiter') { ',' }&lt;br /&gt;    separator = '' unless precision &gt; 0&lt;br /&gt;    begin&lt;br /&gt;        fraction = number.abs % 1.0&lt;br /&gt;        body = number.floor&lt;br /&gt;        if body != 0 || body == 0 &amp;&amp; fraction == 0 then&lt;br /&gt;            parts = number_with_precision(number, precision).split('.')&lt;br /&gt;            unit + number_with_delimiter(parts[0], delimiter) + separator + parts[1].to_s&lt;br /&gt;        else&lt;br /&gt;            (fraction * 100).to_i.to_s + fractional_unit&lt;br /&gt;        end&lt;br /&gt;    rescue&lt;br /&gt;        number&lt;br /&gt;    end&lt;br /&gt;end&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;I'm really tempted to go through and replace that whole thing with my own code, but it works, so I'm happy.</description>
      <pubDate>Mon, 11 Sep 2006 05:58:03 GMT</pubDate>
      <guid>http://snippets.dzone.com/posts/show/2581</guid>
      <author>sporkyy (Todd Sayre)</author>
    </item>
    <item>
      <title>Gmail Date Format Helper</title>
      <link>http://snippets.dzone.com/posts/show/2580</link>
      <description>I needed a short and intuitive way of showing dates, so rather than just making something up I decided to steal Google's short date format from Gmail.  I'm sure they did usability studies and whatnot.&lt;br /&gt;&lt;br /&gt;&lt;code&gt;ActiveSupport::CoreExtensions::Time::Conversions::DATE_FORMATS.merge!(&lt;br /&gt;  :gmail =&gt; lambda { |date|&lt;br /&gt;    Time.now.beginning_of_day &lt;= date ?&lt;br /&gt;    "#{date.strftime('%I').to_i}:#{date.strftime('%M')} #{date.strftime('%p').downcase}" :&lt;br /&gt;    Time.now.beginning_of_year &lt;= date ?&lt;br /&gt;    "#{date.strftime('%b')} #{date.day}" :&lt;br /&gt;    "#{date.month}/#{date.day}/#{date.strftime('%y')}"&lt;br /&gt;  }&lt;br /&gt;)&lt;br /&gt;&lt;br /&gt;ActiveSupport::CoreExtensions::Date::Conversions::DATE_FORMATS.merge!(&lt;br /&gt;  :gmail =&gt; lambda { |date|&lt;br /&gt;    Time.now.beginning_of_day &lt;= date ?&lt;br /&gt;    "#{date.strftime('%I').to_i}:#{date.strftime('%M')} #{date.strftime('%p').downcase}" :&lt;br /&gt;    Time.now.beginning_of_year &lt;= date ?&lt;br /&gt;    "#{date.strftime('%b')} #{date.day}" :&lt;br /&gt;    "#{date.month}/#{date.day}/#{date.strftime('%y')}"&lt;br /&gt;  }&lt;br /&gt;)&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Put this code in your "environmen.rb" file in your "RAILS_ROOT/config" directory or make a new Ruby script file containing it in your "RAILS_ROOT/config/initializers" directory.</description>
      <pubDate>Mon, 11 Sep 2006 05:47:42 GMT</pubDate>
      <guid>http://snippets.dzone.com/posts/show/2580</guid>
      <author>sporkyy (Todd Sayre)</author>
    </item>
    <item>
      <title>ZebraStripes</title>
      <link>http://snippets.dzone.com/posts/show/2380</link>
      <description>&lt;code&gt;&lt;br /&gt;/*&lt;br /&gt; * This script requires:&lt;br /&gt; *   1. Prototype version 1.5 or greater&lt;br /&gt; *     - Homepage: http://prototype.conio.net/&lt;br /&gt; *     - Download: http://script.aculo.us/downloads&lt;br /&gt; *   2. DomReady addon for Prototype&lt;br /&gt; *     - Homepage: http://www.vivabit.com/bollocks/2006/06/21/a-dom-ready-extension-for-prototype&lt;br /&gt; *     - Download: http://www.vivabit.com/code/domready/domready.js&lt;br /&gt; */&lt;br /&gt;&lt;br /&gt;/*&lt;br /&gt; * I needed something capable of not just unobtrusively running when a page&lt;br /&gt; * was loaded but also easily being called at my whim as a part of an Ajax&lt;br /&gt; * transaction.&lt;br /&gt; */&lt;br /&gt;var ZebraStripes = {&lt;br /&gt;    /*&lt;br /&gt;     * Call this function when you want something striped.  It will figure out&lt;br /&gt;     * how to stripe the element.&lt;br /&gt;     */&lt;br /&gt;    stripe: function(el) {&lt;br /&gt;        el = $(el);&lt;br /&gt;        switch (el.tagName) {&lt;br /&gt;            case "TABLE":&lt;br /&gt;                this._stripeTable(el);&lt;br /&gt;                break;&lt;br /&gt;            case "OL":&lt;br /&gt;            case "UL":&lt;br /&gt;                this._stripeNormalList(el);&lt;br /&gt;                break;&lt;br /&gt;            case "DL":&lt;br /&gt;                this._stripeDefinitionList(el);&lt;br /&gt;                break;&lt;br /&gt;        }&lt;br /&gt;    },&lt;br /&gt;    /***************************************************************************&lt;br /&gt;     * Everything below here is psuedo-private&lt;br /&gt;     **************************************************************************/&lt;br /&gt;    /*&lt;br /&gt;     * This class name will be applied to the odd numbered elements&lt;br /&gt;     */&lt;br /&gt;    _altClassName: "alt",&lt;br /&gt;    /*&lt;br /&gt;     * This property persists the data that tells the object whether&lt;br /&gt;     * to stripe (_isEven == false) or unstripe (_isEven == true) an element&lt;br /&gt;     */&lt;br /&gt;    _isEven: true,&lt;br /&gt;    /*&lt;br /&gt;     * Cycles the _isEven property of this object between true and false&lt;br /&gt;     */&lt;br /&gt;    _cycle: function() {&lt;br /&gt;        this._isEven = ! this._isEven;&lt;br /&gt;    },&lt;br /&gt;    /*&lt;br /&gt;     * As a part of the Ajax-friendliness, it is important that we remove the&lt;br /&gt;     * alt class from elements as well as add it.&lt;br /&gt;     */&lt;br /&gt;    _stripeElement: function(el) {&lt;br /&gt;        el = $(el);&lt;br /&gt;        if (this._isEven) {&lt;br /&gt;            el.removeClassName(this._altClassName);&lt;br /&gt;        } else {&lt;br /&gt;            el.addClassName(this._altClassName);&lt;br /&gt;        }&lt;br /&gt;    },&lt;br /&gt;    /*&lt;br /&gt;     * This works to stripe the child nodes of TABLE, TBODY, OL and UL elements.&lt;br /&gt;     */&lt;br /&gt;    _stripeElements: function(els) {&lt;br /&gt;        els = $(els);&lt;br /&gt;        if (els.length == 0) {&lt;br /&gt;            return&lt;br /&gt;        }&lt;br /&gt;        var parent = els[0].parentNode;&lt;br /&gt;        this._isEven = true;&lt;br /&gt;        for (var i = 0; i &lt; els.length; i++ ) {&lt;br /&gt;            if ((parent == els[i].parentNode) &amp;&amp; (els[i].visible)) {&lt;br /&gt;                this._stripeElement(els[i]);&lt;br /&gt;                this._cycle();&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;    },&lt;br /&gt;    /*&lt;br /&gt;     * TBODY is not necessary, but I recommend it.  I debated about striping&lt;br /&gt;     * THEAD and TFOOT, but chose not to.  Might be added later.&lt;br /&gt;     */&lt;br /&gt;    _stripeTable: function(table) {&lt;br /&gt;        table = $(table);&lt;br /&gt;        if (table.getElementsByTagName("tbody")) {&lt;br /&gt;            var tableBodies = table.getElementsByTagName("tbody");&lt;br /&gt;            for (var i = 0; i &lt; tableBodies.length; i++) {&lt;br /&gt;                this._stripeElements(tableBodies[i].getElementsByTagName("tr"));&lt;br /&gt;            }&lt;br /&gt;        } else {&lt;br /&gt;            this._stripeElements(table.getElementsByTagName("tr"));&lt;br /&gt;        }&lt;br /&gt;    },&lt;br /&gt;    /*&lt;br /&gt;     * This stripes OL and UL since they both have LI and only LI child nodes.&lt;br /&gt;     */&lt;br /&gt;    _stripeNormalList: function(list) {&lt;br /&gt;        list = $(list);&lt;br /&gt;        this._stripeElements(list.getElementsByTagName("li"));&lt;br /&gt;    },&lt;br /&gt;    /*&lt;br /&gt;     * I have seen other function out there that can stripe DL, but they all&lt;br /&gt;     * assumed that each DT would have only one DD following it.  That is not&lt;br /&gt;     * always the case, and not the case in the project that spawned this&lt;br /&gt;     * javascript.&lt;br /&gt;     */&lt;br /&gt;    _stripeDefinitionList: function(list) {&lt;br /&gt;        list = $(list);&lt;br /&gt;        Element.cleanWhitespace(list);&lt;br /&gt;        var children = list.childNodes;&lt;br /&gt;        var previousDt;&lt;br /&gt;        for (var i = 0; i &lt; children.length; i++) {&lt;br /&gt;            switch (children[i].tagName) {&lt;br /&gt;                case "DT":&lt;br /&gt;                    if (children[i].visible) {&lt;br /&gt;                        this._stripeElement(children[i]);&lt;br /&gt;                        this._cycle();&lt;br /&gt;                    }&lt;br /&gt;                    previousDt = children[i];&lt;br /&gt;                    break;&lt;br /&gt;                case "DD":&lt;br /&gt;                    if (previousDt.visible) {&lt;br /&gt;                        this._stripeElement(children[i]);&lt;br /&gt;                    }&lt;br /&gt;                    break;&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;/*&lt;br /&gt; * This function will go ahead and stripe all the elligible elements on the&lt;br /&gt; * page when the page first loads.&lt;br /&gt; */&lt;br /&gt;function initZebraStripes() {&lt;br /&gt;    var toStripe = $$("dl.striped")&lt;br /&gt;        .concat($$("ol.striped"))&lt;br /&gt;        .concat($$("table.striped"))&lt;br /&gt;        .concat($$("ul.striped"));&lt;br /&gt;&lt;br /&gt;    toStripe.each(&lt;br /&gt;        function(el) {&lt;br /&gt;            ZebraStripes.stripe(el);&lt;br /&gt;        }&lt;br /&gt;    );&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;Event.onDOMReady(initZebraStripes);&lt;br /&gt;// Or you could substitute a different loader:&lt;br /&gt;//Event.observe(window, 'load', initZebraStripes)&lt;br /&gt;&lt;/code&gt;</description>
      <pubDate>Tue, 08 Aug 2006 17:32:12 GMT</pubDate>
      <guid>http://snippets.dzone.com/posts/show/2380</guid>
      <author>sporkyy (Todd Sayre)</author>
    </item>
  </channel>
</rss>
