├── .gitignore ├── views ├── home.haml ├── article.haml ├── _article.haml ├── feed.haml ├── layout.haml └── stylesheets │ └── screen.sass ├── public ├── favicon.ico ├── images │ ├── booty.jpg │ └── ruby_art_and_all_things.png ├── assets │ └── jquery_toggler.html └── javascripts │ └── code_highlighter.js ├── Gemfile ├── Gemfile.lock ├── Readme.textile ├── articles ├── load_gems_in_test_rb.haml ├── railscamp_six.haml ├── active_record_association_methods.haml ├── gem_bundler.haml ├── homebrew_ruby_odbc.haml ├── thinking_sphinx_dreamhost.haml ├── enter_sinatra.haml ├── translate_legacy_attributes.haml ├── sinatra_on_dreamhost.haml ├── jquery_toggler.haml ├── tasteful_routes.haml └── date_range_string_conversions.haml ├── app.rb └── lib └── article.rb /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | deploy.yml 3 | config.ru 4 | tmp 5 | -------------------------------------------------------------------------------- /views/home.haml: -------------------------------------------------------------------------------- 1 | - for @article in @articles 2 | = haml(:_article, :layout => false) -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hughevans/hughevans.net/master/public/favicon.ico -------------------------------------------------------------------------------- /public/images/booty.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hughevans/hughevans.net/master/public/images/booty.jpg -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source :rubygems 2 | 3 | gem 'sinatra', '1.2.3' 4 | gem 'haml', '3.0.25' 5 | gem 'RedCloth', '4.2.7' 6 | -------------------------------------------------------------------------------- /public/images/ruby_art_and_all_things.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hughevans/hughevans.net/master/public/images/ruby_art_and_all_things.png -------------------------------------------------------------------------------- /views/article.haml: -------------------------------------------------------------------------------- 1 | = haml(:_article, :layout => false) 2 | 3 | #disqus_thread 4 | 5 | %script{:type => 'text/javascript', :src => 'http://disqus.com/forums/hughevans/embed.js'} -------------------------------------------------------------------------------- /views/_article.haml: -------------------------------------------------------------------------------- 1 | .article 2 | %h1.title 3 | - if @single_view 4 | = @article.title 5 | - else 6 | %a{:href => article_path(@article)} 7 | = @article.title 8 | .published 9 | Published: 10 | = @article.published.strftime("%B %d, %Y") 11 | = article_body(@article) -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: http://rubygems.org/ 3 | specs: 4 | RedCloth (4.2.7) 5 | haml (3.0.25) 6 | rack (1.2.2) 7 | sinatra (1.2.3) 8 | rack (~> 1.1) 9 | tilt (< 2.0, >= 1.2.2) 10 | tilt (1.2.2) 11 | 12 | PLATFORMS 13 | ruby 14 | 15 | DEPENDENCIES 16 | RedCloth (= 4.2.7) 17 | haml (= 3.0.25) 18 | sinatra (= 1.2.3) 19 | -------------------------------------------------------------------------------- /Readme.textile: -------------------------------------------------------------------------------- 1 | h1. hughevans.net 2 | 3 | _A Tiny Sinatra Blog_ 4 | 5 | My take on a tiny Sinatra blog, with inspiration (and a fair chunk of code) coming from "toolmantim":http://github.com/toolmantim/toolmantim/tree/master. 6 | 7 | h2. License 8 | 9 | MIT license except for the files found in: 10 | 11 | * @/articles/@ 12 | * @/public/images/@ 13 | 14 | They are copyright Hugh Evans. -------------------------------------------------------------------------------- /articles/load_gems_in_test_rb.haml: -------------------------------------------------------------------------------- 1 | -# title: Load Gems in test.rb 2 | -# published: 2009-03-01 3 | 4 | :textile 5 | Just a quick tip. Don't load gems that you only require for testing purposes in your Rails environment.rb. Put them in your test.rb instead, like so: 6 | 7 | %pre 8 | %code.ruby< 9 | :preserve 10 | config.gem 'thoughtbot-shoulda', :lib => 'shoulda', :source => 'http://gems.github.com' 11 | 12 | :textile 13 | This works fine and will give you the added advantage of shaving off a few fractions from your production startup time. 14 | 15 | :textile 16 | Startup time is something of which I have become very sensitive to lately due to way Dreamhost kills off idle Passenger processes rather quickly. So if you too are hosting with Passenger pay careful attention to the startup time of your application. -------------------------------------------------------------------------------- /articles/railscamp_six.haml: -------------------------------------------------------------------------------- 1 | -# title: Railscamp VI 2 | -# published: 2009-11-23 3 | 4 | :textile 5 | There is much to be said about the latest "railscamp":http://railscamps.com/ instalment. Simply, it rocked. From "international speakers":http://topfunky.com/ to "multiplayer zombie rampages":http://github.com/chrislloyd/brains/, railscamp hasn't lost any of it's mojo. And that's despite it doubling in size. So big props must go out to "Ben Schwarz":http://germanforblack.com/, "John Barton":http://whoisjohnbarton.com and "Pat Allen":http://freelancing-gods.com for bringing it all together. 6 | 7 | Then there was the hacking. "Ben Webster":http://plus2.com.au, "Matt Allen":http://allen.com.au and myself made an app which will be used to benefit charities, swinging ourselves "some booty":/images/booty.jpg. I'll post some more info when we are closer to pushing it out. It's rather exciting really. 8 | 9 | -------------------------------------------------------------------------------- /views/feed.haml: -------------------------------------------------------------------------------- 1 | !!! xml 2 | %feed(xmlns='http://www.w3.org/2005/Atom') 3 | 4 | %title @hughevans - Ruby, Art and All things... 5 | %link(href='http://hughevans.net' rel='self' hreflang='en' type='application/atom+xml') 6 | 7 | %author 8 | %name Hugh Evans 9 | %uri http://hughevans.net/ 10 | 11 | %updated= @articles.first.published.xmlschema 12 | %id= "tag:hughevans.net,#{@articles.first.published.strftime('%Y-%m-%d')}:#{article_path(@articles.first)}" 13 | 14 | - for article in @articles 15 | %entry 16 | %id= "tag:hughevans.net,#{article.published.strftime('%Y-%m-%d')}:#{article_path(article)}" 17 | %title= article.title 18 | %published= article.published.xmlschema 19 | %updated= article.last_modified.xmlschema 20 | %link(href="http://hughevans.net#{article_path(article)}" rel='alternate' hreflang='en' type='text/html') 21 | %content(type='xhtml' xml:lang='en' xml:base='http://hughevans.net/') 22 | %div(xmlns='http://www.w3.org/1999/xhtml')= absoluteify_links(article_body(article)) -------------------------------------------------------------------------------- /articles/active_record_association_methods.haml: -------------------------------------------------------------------------------- 1 | -# title: Active Record Association Methods 2 | -# published: 2009-03-06 3 | 4 | :textile 5 | I often forget that you can define methods for an Active Record associations in a block after the association declaration like so: 6 | 7 | %pre 8 | %code.ruby< 9 | :preserve 10 | class Order < ActiveRecord::Base 11 | has_many :items, :dependent => :destroy do 12 | def total 13 | inject(0) {|sum, s| sum += s.price} 14 | end 15 | end 16 | end 17 | 18 | %pre 19 | %code.ruby< 20 | :preserve 21 | >> @order = Order.last 22 | >> @order.items.total 23 | => 27.45 24 | 25 | :textile 26 | Most of the time this makes more sense than defining them as instance methods in the parent model and much more sense than class methods in the child because it will require the association to work anyhow (perhaps though I haven't chosen the best example to illustrate this as you could potentially use an Item.total method independently eg. Item.all.total, but you get the picture). 27 | 28 | 29 | -------------------------------------------------------------------------------- /app.rb: -------------------------------------------------------------------------------- 1 | require 'rubygems' 2 | require 'sinatra' 3 | require 'haml' 4 | require 'time' 5 | require './lib/article' 6 | 7 | Article.path = File.join(Sinatra::Application.root, 'articles') 8 | 9 | helpers do 10 | def article_body(article) 11 | haml(article.template, :layout => false) 12 | end 13 | 14 | def article_path(article) 15 | "/#{article.published.strftime("%Y/%m/%d")}/#{article.id}" 16 | end 17 | 18 | def absoluteify_links(html) 19 | html. 20 | gsub(/href=(["'])(\/.*?)(["'])/, 'href=\1http://hughevans.net\2\3'). 21 | gsub(/src=(["'])(\/.*?)(["'])/, 'src=\1http://hughevans.net\2\3') 22 | end 23 | end 24 | 25 | get '/' do 26 | @articles = Article.all.sort[0..10] 27 | haml :home 28 | end 29 | 30 | get '/:year/:month/:day/:id' do 31 | @article = Article[params[:id]] || raise(Sinatra::NotFound) 32 | @single_view = true 33 | haml :article 34 | end 35 | 36 | get '/articles.atom' do 37 | @articles = Article.all.sort 38 | content_type 'application/atom+xml' 39 | haml :feed, :layout => false 40 | end 41 | 42 | get '/:style.css' do 43 | content_type 'text/css', :charset => 'utf-8' 44 | sass :"stylesheets/#{params[:style]}" 45 | end 46 | 47 | module Haml::Filters::Preserve 48 | def render(text) 49 | Haml::Helpers.preserve(Haml::Helpers.html_escape(text)) 50 | end 51 | end -------------------------------------------------------------------------------- /articles/gem_bundler.haml: -------------------------------------------------------------------------------- 1 | -# title: Handling Deploys with Gem Bundler 2 | -# published: 2009-11-14 3 | 4 | :textile 5 | The best method of usage for "Gem Bundler":http://litanyagainstfear.com/blog/2009/10/14/gem-bundler-is-the-future/ we have found is to check in only your Gemfile and the gem cache dir, ignoring the rest in .gitignore: 6 | 7 | %pre 8 | %code< 9 | :preserve 10 | vendor/bundler_gems/environment.rb 11 | vendor/bundler_gems/gems 12 | vendor/bundler_gems/specifications 13 | 14 | :textile 15 | Now we have our known working .gem files checked in we can ensure that on deploy only these will be used on the server by passing Bundler the cached flag when deploying with Capistrano: 16 | 17 | %pre 18 | %code.ruby< 19 | :preserve 20 | after 'deploy:update_code', 'gems:bundle' 21 | 22 | namespace :gems do 23 | task :bundle, :roles => :app do 24 | run "cd \#{release_path} && gem bundle --cached" 25 | end 26 | end 27 | 28 | :textile 29 | Otherwise Bundler will look for updated gems and download them when you have not locked your Gemfile gems to specific versions. Stinging you big time, especially when APIs change on point releases.. 30 | 31 | :textile 32 | Anyhow, the reason you would want to do this as opposed to just checking in the whole vendor/bundler_gems dir is that you won't dirty up you history with thousand line commits when upgrading gems. 33 | -------------------------------------------------------------------------------- /articles/homebrew_ruby_odbc.haml: -------------------------------------------------------------------------------- 1 | -# title: Homebrew, FreeTDS and RubyODBC 2 | -# published: 2009-11-05 3 | 4 | :textile 5 | "Homebrew":http://github.com/mxcl/homebrew is awesome. On my new macbook I elected to use it in place of MacPorts and now I'm in love. I don't want to give you too much in the way of a sales pitch but all I'll say is that I feel I'm now that much closer to The Perfect Setup™ (Along with "RVM":http://rvm.beginrescueend.com, which is awesome as well). 6 | 7 | One thing I used Homebrew for was installing the packages required to get my Rails app talking to SQL Server. There already existed a formula for UnixODBC, but I had to write ones for FreeTDS and RubyODBC which was "simple":http://github.com/hughevans/homebrew/commit/acd8ccdb40f183d29e5e7c443d4d54fb04af4f3c "enough":http://github.com/hughevans/homebrew/commit/3387cd5a6c609d1ed24669adf4a0728c95befd5f (hopefully these will get pulled upstream soon). 8 | 9 | After this getting ODBC to work it was a simple matter of: 10 | 11 | %pre 12 | %code< 13 | :preserve 14 | brew install unixodbc 15 | brew install freetds 16 | brew install ruby-odbc 17 | 18 | Configure ~/.freetds.conf and ~/.odbc.ini 19 | 20 | :textile 21 | Combine this with the awesome "activerecord-sqlserver-adapter":http://github.com/rails-sqlserver/2000-2005-adapter/ and it all works a charm. I should also add that this is on Snow Leopard, hence the need for UnixODBC. -------------------------------------------------------------------------------- /views/layout.haml: -------------------------------------------------------------------------------- 1 | !!! Strict 2 | %html(xmlns='http://www.w3.org/1999/xhtml' xml:lang='en' lang='en') 3 | 4 | %head 5 | %meta(http-equiv='Content-Type' content='text/html; charset=utf-8') 6 | %title= "#{"#{@article.title} | " if @single_view }hughevans.net" 7 | %link(href='/screen.css' media='screen' rel='stylesheet' type='text/css') 8 | %link(rel='shortcut icon' href='/favicon.ico') 9 | %link(rel='alternate' href='/articles.atom' title='@hughevans - Ruby, Art and All things...' type='application/atom+xml') 10 | %link(href='http://fonts.googleapis.com/css?family=Copse|Lato|Droid+Sans+Mono' rel='stylesheet' type='text/css') 11 | %script(src='/javascripts/code_highlighter.js' type='text/javascript') 12 | %script(src='http://www.google-analytics.com/ga.js' type='text/javascript') 13 | 14 | %body 15 | #main 16 | .wrapper 17 | #header 18 | %h1 19 | %a(href='/') @hughevans 20 | = yield 21 | 22 | #footer 23 | .wrapper 24 | %strong 25 | my other stuff on the web 26 | %ul 27 | %li 28 | %a(href='http://twitter.com/hughevans') twitter 29 | %li 30 | %a(href='http://flickr.com/photos/hughevans/') flickr 31 | %li 32 | %a(href='http://github.com/hughevans') github 33 | 34 | :javascript 35 | try { 36 | var pageTracker = _gat._getTracker("UA-7674685-1"); 37 | pageTracker._trackPageview(); 38 | } catch(err) {}; 39 | -------------------------------------------------------------------------------- /articles/thinking_sphinx_dreamhost.haml: -------------------------------------------------------------------------------- 1 | -# title: Sphinx on Dreamhost 2 | -# published: 2009-03-10 3 | 4 | :textile 5 | If you wish to to install the "Sphinx":http://sphinxsearch.com/ search engine on Dreamhost, you can and it is really quite easy and painless. 6 | 7 | :textile 8 | The first step is to download, compile and install sphinx into your home directory (as you do not have permissions to install this elsewhere): 9 | 10 | %pre 11 | %code< 12 | :preserve 13 | cd ~/ 14 | mkdir -p local 15 | wget http://sphinxsearch.com/downloads/sphinx-0.9.8.1.tar.gz 16 | tar -xzf sphinx-0.9.8.1.tar.gz 17 | cd sphinx-0.9.8.1/ 18 | ./configure --prefix=$HOME/local/ --exec-prefix=$HOME/local/ 19 | make 20 | install 21 | 22 | :textile 23 | Now you simply need to modify your $PATH to include ~/local/bin: 24 | 25 | %pre 26 | %code< 27 | :preserve 28 | echo "export PATH=\"$PATH:~/local/bin\"" >> ~/.bash_profile 29 | source ~/.bash_profile 30 | 31 | :textile 32 | Now you should have a working searchd and your only remaining concern is how to keeping it running, as Dreamhost will kill off long running processes. My solution was to add it to crontab: 33 | 34 | %pre 35 | %code< 36 | :preserve 37 | * * * * * /home/you/local/bin/searchd --config /home/you/path/sphinx.conf 38 | 39 | :textile 40 | This appears to be "a grey area":http://blog.dreamhosters.com/kbase/index.cgi?area=2449 with Dreamhost, but I've never really seen sphinx use any real CPU or memory (on my sites at least) and personally I think they should make it available as part of their standard build. -------------------------------------------------------------------------------- /articles/enter_sinatra.haml: -------------------------------------------------------------------------------- 1 | -# title: Enter Sinatra 2 | -# published: 2009-02-21 3 | 4 | :textile 5 | "Sinatra":http://www.sinatrarb.com/, I absolutely love it. After watching "toolmantim":http://toolmantim.com/ present on the topic at the last RORO I borrowed some inspiration (and "some code":http://github.com/toolmantim/toolmantim/tree/master) and came up with the new "hughevans.net":http://hughevans.net. 6 | 7 | %pre 8 | %code.ruby< 9 | :preserve 10 | require 'rubygems' 11 | require 'sinatra' 12 | require 'haml' 13 | require 'time' 14 | require 'lib/article' 15 | 16 | Article.path = File.join(Sinatra::Application.root, 'articles') 17 | 18 | helpers do 19 | def article_body(article) 20 | haml(article.template, :layout => false) 21 | end 22 | 23 | def article_path(article) 24 | "/\#{article.published.strftime("%Y/%m/%d")}/\#{article.id}" 25 | end 26 | end 27 | 28 | get '/' do 29 | @articles = Article.all.sort[0..4] 30 | haml :home 31 | end 32 | 33 | get '/:year/:month/:day/:id' do 34 | @article = Article[params[:id]] || raise(Sinatra::NotFound) 35 | @single_view = true 36 | haml :article 37 | end 38 | 39 | get '/articles.atom' do 40 | @articles = Article.all.sort 41 | content_type 'application/atom+xml' 42 | haml :feed, :layout => false 43 | end 44 | 45 | get '/:style.css' do 46 | content_type 'text/css', :charset => 'utf-8' 47 | sass :"stylesheets/\#{params[:style]}" 48 | end 49 | 50 | :textile 51 | Nothing too clever, just simple clean ruby code. The full source is available on "GitHub":http://github.com/hughevans/hughevans.net/tree/master. -------------------------------------------------------------------------------- /lib/article.rb: -------------------------------------------------------------------------------- 1 | # Code originally from toolmantim: 2 | # http://github.com/toolmantim/toolmantim/blob/972372615c534916a3a1c8ae0f01e72626ca83e0/lib/article.rb 3 | class Article 4 | def self.path=(path) 5 | @path = path 6 | end 7 | 8 | def self.path(article_slug = nil) 9 | article_slug ? File.join(@path, "#{article_slug}.haml") : @path 10 | end 11 | 12 | def self.files 13 | Dir["#{File.expand_path(Article.path)}/*.haml"] 14 | end 15 | 16 | def self.all 17 | self.files.map {|f| new(f, File.read(f))} 18 | end 19 | 20 | def self.[](id) 21 | path = path(id.gsub('-', '_')) 22 | File.exist?(path) && new(path, File.read(path)) 23 | end 24 | 25 | def self.template_variable(text, name) 26 | text[/\-\s*#\s*#{name}:\s*(.+)/, 1] 27 | end 28 | 29 | def self.parse_date(date_string) 30 | date_string && Time.local(*date_string.split('-').map {|s| s.to_i}) 31 | end 32 | 33 | attr_reader :path, :template 34 | 35 | def initialize(file_path, file_contents) 36 | @path = file_path 37 | @template = file_contents 38 | end 39 | 40 | def slug 41 | File.basename(self.path, '.haml') 42 | end 43 | 44 | def id 45 | slug.gsub('_', '-') 46 | end 47 | 48 | def title 49 | template_variable('title') 50 | end 51 | 52 | def published 53 | @published ||= self.class.parse_date(template_variable('published')) 54 | end 55 | 56 | def updated 57 | @updated ||= self.class.parse_date(template_variable('updated')) 58 | end 59 | 60 | def last_modified 61 | updated || published 62 | end 63 | 64 | def template_variable(name) 65 | self.class.template_variable(self.template, name) 66 | end 67 | 68 | def <=>(other) 69 | [other.published.year, other.published.month, other.published.day] <=> [self.published.year, self.published.month, self.published.day] 70 | end 71 | end -------------------------------------------------------------------------------- /articles/translate_legacy_attributes.haml: -------------------------------------------------------------------------------- 1 | -# title: Translate Legacy Attribute Names 2 | -# published: 2009-08-20 3 | 4 | :textile 5 | Recently I've been working a lot with legacy databases, wrapping them with rails apps and exposing them to REST actions. One thing that annoyed me was the terribly inconsistent column naming conventions I came across. So I used *alias_attribute* to give them nicer names, but when it came to running *to_xml* on the models I found I needed to specify which attributes to leave out and use the alias's instead. Not so dry. So this is what I came up with: 6 | 7 | %pre 8 | %code.ruby< 9 | :preserve 10 | class Candidate < Legacy::Base 11 | set_table_name 'CandidateData' 12 | set_primary_key 'Fileno' 13 | 14 | @@translations = { 15 | 'Fileno' => 'id', 16 | 'Familyname' => 'last_name', 17 | 'GivenNames' => 'first_name', 18 | 'DOB' => 'date_of_birth', 19 | 'Emailaddr' => 'email', 20 | 'Address' => 'address', 21 | 'City' => 'city', 22 | 'State' => 'state', 23 | 'PostCode' => 'postal_code', 24 | 'PhoneHome' => 'phone_home', 25 | 'PhoneWork' => 'phone_work', 26 | 'mobile' => 'phone_mobile' 27 | } 28 | 29 | @@translations.each {|k,v| alias_attribute(v, k)} 30 | 31 | alias_method :ar_to_xml, :to_xml 32 | 33 | def to_xml(options = {}, &block) 34 | default_options = { 35 | :except => @@translations.keys, 36 | :methods => @@translations.values 37 | } 38 | self.ar_to_xml(options.merge(default_options), &block) 39 | end 40 | 41 | :textile 42 | Also you only have to translate the attributes that need it as they will come through to *to_xml* as normal if not included in the translation hash. -------------------------------------------------------------------------------- /articles/sinatra_on_dreamhost.haml: -------------------------------------------------------------------------------- 1 | -# title: Sinatra 0.9 on Dreamhost 2 | -# published: 2009-02-22 3 | 4 | :textile 5 | There is "lots":http://www.sinatrarb.com/book.html#deployment of "good":http://railstips.org/2008/12/15/deploying-sinatra-on-dreamhost-with-passenger information out there on how to deploy Sinatra apps to Dreamhost but they don't really cover off the Sinatara 0.9 release which unfortunately depends on a newer version of the Rack gem that dreamhost does not yet have installed. The "missing piece of the puzzle":http://brianc.me/blog/sinatra-on-dreamhost/ was that you can actually override the Rack that Passenger loads by vendoring Rack and requiring it in your config.ru file. 6 | 7 | %pre 8 | %code.ruby< 9 | :preserve 10 | require 'rubygems' 11 | require 'vendor/rack/lib/rack' 12 | require 'vendor/sinatra/lib/sinatra' 13 | 14 | disable :run 15 | 16 | set :app_file, 'yourapp.rb' 17 | set :views, '/full/path/views' 18 | 19 | require 'yourapp' 20 | run Sinatra::Application 21 | 22 | :textile 23 | Now just to tidy things up and prevent me from having junk in my repository I updated my Capistrano script to gem install Sinatra/Rack and unpack them to /vendor on deploy:setup. 24 | 25 | %pre 26 | %code.ruby< 27 | :preserve 28 | after 'deploy:setup', 'vendor_gems:install_and_unpack' 29 | after 'deploy:update_code', 'vendor_gems:symlink' 30 | 31 | namespace :vendor_gems do 32 | task :install_and_unpack do 33 | run 'gem install sinatra -v 0.9.0.4' # Also installs rack 0.9.1 34 | run "cd \#{shared_path}/system && gem unpack rack && mv rack-* rack" 35 | run "cd \#{shared_path}/system && gem unpack sinatra && mv sinatra-* sinatra" 36 | end 37 | 38 | task :symlink do 39 | run "mkdir -p \#{release_path}/vendor/" 40 | run "ln -nfs \#{shared_path}/system/rack \#{release_path}/vendor/rack" 41 | run "ln -nfs \#{shared_path}/system/sinatra \#{release_path}/vendor/sinatra" 42 | end 43 | end 44 | 45 | :textile 46 | Now I am a pretty happy camper as my move back to shared hosting seems to be going quite well so far. Thanks "Passenger":http://www.modrails.com/! 47 | 48 | :textile 49 | PS. If you're interested in trying Dreamhost you should know that they have a pretty generous affiliate program. You can use my "affiliate link":http://www.dreamhost.com/r.cgi?508625 or a friends, but either way you should make sure someone benefits from it when you signup. -------------------------------------------------------------------------------- /articles/jquery_toggler.haml: -------------------------------------------------------------------------------- 1 | -# title: jQuery Toggler 2 | -# published: 2008-05-28 3 | 4 | :textile 5 | I often like to have small form actions in my sidebar hidden away with javascript that are just a toggle away. Using jQuery to do this is quite easy but there are a few gotchas. Firstly we want both the always visible toggler link and a cancel button inside the toggled div to do the toggling. Next we want the first form input in the toggled div to become focused when we make it visible. It is important we don't try and do this when we are toggling the div off (hiding it) as Internet Explorer will bork when you try and focus on a hidden element. 6 | 7 | :textile 8 | Starting with our HTML: 9 | 10 | %pre 11 | %code.html< 12 | :preserve 13 |
169 | if (/MSIE/.test(navigator.appVersion) && stylableEls[i].parentNode.nodeName == 'PRE') {
170 | stylableEls[i] = stylableEls[i].parentNode;
171 |
172 | parsed = stylableEls[i].innerHTML.replace(/(]*>)([^<]*)<\/code>/i, function() {
173 | return arguments[1] + parse(arguments[2], styleSet.ignoreCase) + ""
174 | });
175 | parsed = parsed.replace(/\n( *)/g, function() {
176 | var spaces = "";
177 | for (var i = 0; i < arguments[1].length; i++) spaces+= " ";
178 | return "\n" + spaces;
179 | });
180 | parsed = parsed.replace(/\t/g, " ");
181 | parsed = parsed.replace(/\n(<\/\w+>)?/g, "
$1").replace(/
[\n\r\s]*
/g, "
");
182 |
183 | } else parsed = parse(stylableEls[i].innerHTML, styleSet.ignoreCase);
184 |
185 | stylableEls[i].innerHTML = parsed;
186 | }
187 | }
188 |
189 | // run highlighter on all stylesets
190 | for (var i=0; i < this.styleSets.length; i++) {
191 | highlightCode(this.styleSets[i]);
192 | }
193 | }
194 |
195 |
196 |
197 | CodeHighlighter.addStyle("css", {
198 | comment : {
199 | exp : /\/\*[^*]*\*+([^\/][^*]*\*+)*\//
200 | },
201 | keywords : {
202 | exp : /@\w[\w\s]*/
203 | },
204 | selectors : {
205 | exp : "([\\w-:\\[.#][^{};>]*)(?={)"
206 | },
207 | properties : {
208 | exp : "([\\w-]+)(?=\\s*:)"
209 | },
210 | units : {
211 | exp : /([0-9])(em|en|px|%|pt)\b/,
212 | replacement : "$1$2"
213 | },
214 | urls : {
215 | exp : /url\([^\)]*\)/
216 | }
217 | });
218 |
219 | CodeHighlighter.addStyle("ruby",{
220 | comment : {
221 | exp : /#[^\n]+/
222 | },
223 | brackets : {
224 | exp : /\(|\)/
225 | },
226 | string : {
227 | exp : /'[^']*'|"[^"]*"/
228 | },
229 | keywords : {
230 | exp : /\b(do|end|self|class|def|if|module|yield|then|else|for|until|unless|while|elsif|case|when|break|retry|redo|rescue|require|raise)\b/
231 | },
232 | /* Added by Shelly Fisher (shelly@agileevolved.com) */
233 | symbol : {
234 | exp : /([^:])(:[A-Za-z0-9_!?]+)/
235 | }
236 | });
237 |
238 | CodeHighlighter.addStyle("javascript",{
239 | comment : {
240 | exp : /(\/\/[^\n]*\n)|(\/\*[^*]*\*+([^\/][^*]*\*+)*\/)/
241 | },
242 | brackets : {
243 | exp : /\(|\)/
244 | },
245 | string : {
246 | exp : /'[^']*'|"[^"]*"/
247 | },
248 | keywords : {
249 | exp : /\b(arguments|break|case|continue|default|delete|do|else|false|for|function|if|in|instanceof|new|null|return|switch|this|true|typeof|var|void|while|with)\b/
250 | },
251 | global : {
252 | exp : /\b(toString|valueOf|window|element|prototype|constructor|document|escape|unescape|parseInt|parseFloat|setTimeout|clearTimeout|setInterval|clearInterval|NaN|isNaN|Infinity)\b/
253 | }
254 | });
255 |
256 | CodeHighlighter.addStyle("html", {
257 | comment : {
258 | exp: /<!\s*(--([^-]|[\r\n]|-[^-])*--\s*)>/
259 | },
260 | tag : {
261 | exp: /(<\/?)([a-zA-Z]+\s?)/,
262 | replacement: "$1$2"
263 | },
264 | string : {
265 | exp : /'[^']*'|"[^"]*"/
266 | },
267 | attribute : {
268 | exp: /\b([a-zA-Z-:]+)(=)/,
269 | replacement: "$1$2"
270 | },
271 | doctype : {
272 | exp: /<!DOCTYPE([^&]|&[^g]|&g[^t])*>/
273 | }
274 | });
275 |
276 | CodeHighlighter.addStyle("shell",{
277 | keywords : {
278 | exp: /(\$ ?)([^\n]+)/
279 | }
280 | });
--------------------------------------------------------------------------------