captured sparks

Archive for 2010

Favourtweets

Just a short note to publicise the launch of Favourtweets. This new service from captured sparks, allows you to tag and organise your favourite tweets.

No login is needed as it connects directly to Twitter. Let me know what you think.

Text shadow bug in Safari 4.0.5

It looks like Safari 4.0.5 has introduced a bug in its rendering of the text-shadow property. This image is from my site as rendered in Chrome (and also as rendered in Safari 4.0.4):

Chrome screenshot showing text shadow rendering


This image is now my site rendered in Safari 4.0.5:

Screenshot of text shadow rendering in Safari


Has anybody else come across this?

Sharerplane

I’d just like to announce the launch of my new website, Sharerplane. It enables people who share an aircraft to book and reserve the aircraft using an easy calendar interface.

Lessons from my first video tutorial

So, I’ve now posted my two-part video tutorial on building a todo list application with Rails 3 (Part 1 and Part 2). What have I learned?

Firstly, increase the text size in everything – TextMate, Terminal and the browser. Whilst easily legible on my screen, it is not so good when encoded and compressed at a smaller resolution. Thankfully, the code is still legible (just) but I don’t want my viewers to be squinting.

Secondly, Snapz Pro X, the MacBook’s built in microphone and iMovie are fine for recording video tutorials. I don’t think it’s necessary to invest in a separate microphone at the moment.

Finally, have a rough idea of what you will say, when you will say it and how much time you will need to say it. On a couple of occasions, I found myself needing more time to explain something and on other occasions, having too much time. Whilst a complete script might not be necessary, you might want to consider what particular areas need a detailed level of exposition and ensure you leave enough time to do so.

Building a todo list with Rails 3 – Part One

EDIT: The source code is now on Github.

In this video tutorial, we’ll be building a todo list application in Rails 3 that allows the user to have multiple todo lists with multiple tasks. Part 1 will cover setting up the lists and part 2 will deal with adding tasks to those lists and completing tasks.

This is my first video tutorial so please leave constructive comments. If there is anything you’d like to see me cover, let me know. Further reading material is after the video.

Pure CSS3 Buttons

If you need to produce stunning buttons for use in modern browsers, use Pure CSS3 buttons.

They are designed to work in Safari 4, Chrome and Firefox 3.6. WebKit browsers also get transition effects on the hover state.

Why not check them out?

Quick debugging of validations with Rails

In an application I’m building, I have a tricky validation that needs to ensure that a booking created by the user:

  1. is not entirely within an existing booking
  2. does not have a start time within an existing booking
  3. does not have an end time within an existing booking
  4. does not span an existing booking

While testing the validation, it was really useful to add the following to the validation code:

existing_bookings.each do |b|
  Rails.logger.debug("#{b.id} - #{b.from} - #{b.to}")
end

This was valuable in identifying what bookings my AR query was pulling out during the validation.

Building an AJAX style calendar with Rails and Prototype

In this tutorial, I’m going to show you how to build an AJAX style multi-day calendar with Ruby on Rails and Prototype. The code assumes that you have a number of multi-day bookings or events that you need to display on a calendar. The final result looks like this:

Screenshot of calendar

We’ll start with the code for the controller. I’ve removed some of the code where I create the @hours variable. In my case, the calendar is displaying bookings relating to a particular aircraft:

def index
  @plane = Plane.find(params[:plane_id])
  @booking = @plane.bookings.new
  @hours = ["06:00","07:00","08:00"...]
  @date = Time.parse("#{params[:start_date]} || Time.now.utc")
  @start_date = Date.new(@date.year, @date.month, @date.day)
  @bookings = @plane.bookings.where('bookings.from BETWEEN ? and ? OR bookings.to BETWEEN ? and ?', @start_date, @start_date + 1, @start_date, @start_date + 1).order('bookings.from ASC').all
  if params[:start_date] && request.xhr?
    render :json => @bookings
  end
end

This retrieves all bookings for a particular aircraft on a given day: either today or the day passed in as a query string. The following HTML is used to display the calendar:

<section id="calendar">

  <ul id="dates-menu">
    <% for date in @start_date..@start_date + 6 %>
      <li><a href="/planes/<%= @plane.id %>/bookings?start_date=<%= Date.new(date.year,date.month,date.day) %>" class="dates-link"><%= date.strftime("%d %B") %></a></li>
    <% end %>
  </ul><!-- #dates-menu -->

  <br class="clear" />

  <div class="day">
    <div id="bookings">
      <img src="/images/ajax-loader.gif" id="ajax-loader"/>
    </div><!-- #bookings -->
    <div id="hours">
      <% @hours.each do |hour| %>
        <div class="hour"><%= hour %></div>
      <% end %>
    </div><!-- #hours -->
  </div><!-- .day -->
</section>

You’ll notice that the div with the id of bookings is populated with an AJAX-style loader.

Moving on to the javascript. I am no Javascript expert so it may be possible to refactor some of this to make it leaner. The first part of the code applies an active class to the first li element in the dates menu.

if ($('dates-menu')) {
  $('dates-menu').down(1).addClassName('active');
  var firstLink = $('dates-menu').down(1);
  if (firstLink.hasClassName('active')) {
    grabBookings(firstLink);
  };
};

The grabBookings function gets the bookings for a particular day using Prototype’s Ajax.Request.

function grabBookings(date) {
  $$(".booking").each(function(b) {
    b.remove();
  });
  if (!$('ajax-loader')) {
    $('bookings').insert("<img src='/images/ajax-loader.gif' id='ajax-loader' />");
  }
  new Ajax.Request(date.readAttribute("href"), {method:"get", evalJS:true, onSuccess:function(transport) {
    var bookings = transport.responseJSON;
    $('ajax-loader').remove();
    bookings.each(function(b) {
      var item = "<a href='/planes/" + b.plane_id +"/bookings/" + b.id + "'<div id='booking-" + b.id + "' class='booking' style='height:" + calculateBookingHeight(b.from,b.to) + "px;top:" + calculateBookingPosition(b.from,b.to) + "px;'><p><strong>From: </strong>" + formatTime(b.from) + "</p><p><strong>To: </strong>" + formatTime(b.to) + "</p></div></a>";
    $('bookings').insert(item);
    });
  }});
}

I’ve added this as a gist. In summary, this obtains the bookings for a particular day and the controller returns the bookings in JSON format. I then iterate over each booking and insert it into the calendar. The two key functions used in the code are to calculate the position of the booking to ensure it aligns with the appropriate time and the height of the booking to ensure it covers the appropriate time period. Looking at the function to calculate the height first:

function calculateBookingHeight(from, to) {
  var today = new Date();
  var end = new Date(today.getUTCFullYear(),today.getUTCMonth(),today.getUTCDate(),23);
  var start = new Date(today.getUTCFullYear(),today.getUTCMonth(),today.getUTCDate(),6);
  var from = parseDate(from);
  var fromUTC = new Date(from[0],(from[1] - 1),from[2],from[3],from[4],from[5])
  var to = parseDate(to);
  var toUTC = new Date(to[0],(to[1] - 1),to[2],to[3],to[4],to[5])
  if (fromUTC > start && toUTC < end) {
    var difference = (toUTC - fromUTC) / 120000;
  } else if (fromUTC > start && toUTC > end) {
    var difference = (end - fromUTC) / 120000;
  } else if (fromUTC < start && toUTC < end) {
    var difference = (toUTC - start) / 120000
  } else {
    var difference = 510
  }
  return difference;
}

The key elements here are the use of the figure 120000 and the multiple if statements. The height of 1 hour on the calendar is 30px. Thus, if a booking is 1 hour long, that is equivalent to 3,600,000 milliseconds. When divided by 120000, this produces a result of 30 i.e. 30px. The if statement is to deal with the situation where bookings either take up the whole day or cross with the previous or next day. The height is adjusted accordingly.

function calculateBookingPosition(from, to) {
  var today = new Date();
  var today = new Date(today.getFullYear(),today.getMonth(),today.getDate(),6,0,0)
  var start = parseDate(from);
  var fromUTC = new Date(start[0],(start[1] - 1),start[2],start[3],start[4],start[5])
  var from_hours = (parseFloat(giveMeTime(from).split(":")[0]) - 6) * 30
  var from_minutes = (parseFloat(giveMeTime(from).split(":")[1]) / 60)
  var minutes = parseInt(from_minutes * 30)
  if (fromUTC > today) {
    var top = parseInt(from_hours + minutes)
  } else {
    var top = 0
  }
  return top
}

Again, based on the height of 30px per hour, this function calculates the absolute position from the top of the calendar at which the booking needs to be displayed.

You will note a number of functions within these 2 functions that are used to extract certain aspects of the date and time of the booking. Based on an input in the format of 2010-04-25T12:00Z, I use the following function to extract the time in format 12:00.

function giveMeTime(time) {
  var time = time.split("T")[1].gsub(/[A-Za-z]/,"")
  return time
}

Leave a comment if you spot any obvious flaws in my design or with suggestions for improving the code. I’m also considering releasing this as a plugin for Rails if there is any interest?

Moving your Wordpress database to production

When I moved to Wordpress, I manually imported all my existing blog posts from the custom database into Wordpress. This meant that when it came to moving to production, I had to import all posts into the production database. The steps I took to do this were:

  1. Install Wordpress as normal on your production server.
  2. From your development database, export all tables except the users and options tables.
  3. On your production database, drop all tables except users and options.
  4. Import your development sql file into your production database.

One caveat: If your blog has multiple authors, this method is unlikely to work. On my development machine, the posts were imported as admin and therefore matched the user setup on the production machine.

Next Page »