Good news: Online shopping not as scary anymore

Thijs van der Vossen, 05 Oct 2007, 09:32 in web (edit).

Newspaper with header ‘Online shopping: not as scary anymore’

1 comment

Why fake a link?

Thijs van der Vossen, 03 Jul 2007, 10:05 in web and broken (edit).

In Google Analytics there are a lot of tables where you can click a link to see content details. These links only work if you left-click. If you right-click to open the link in a new tab or window, you’ll end up opening the current Google Analytics screen again.

Screenshot showing a link that's not really a link in Google Analytics

I find this extremely annoying because this is precisely the usage scenario where browser tabs are really handy. If you’re looking at an overview with links to additional details, you really need to be able to open them in multiple new tabs of windows so that you can quickly look through them instead of having to wait for each page to load when you go back and forth between the overview list and the details pages.

Here’s the html source for the example above.

<a href="" onclick="window.PageTable._drillDown(2); return false;">
/2007/06/flex-can-t-do-rest</a>

I’m wondering why people do this? What’s the reason for using JavaScript here? Why not just use a real link instead of a fake one?

7 comments

Accepting regional information

Manfred Stienstra, 26 Feb 2007, 23:57 in web and broken (edit).

Bittorrent.com, the first endeavor in legalizing Bittorrent, launched recently. I was pleasantly surprised that they didn’t put a really large badge on the frontpage saying, “if you’re not in the US, please leave.”

Following the example of the ever successful iTunes Store most, maybe all, of the purchasable video content is marked ‘US only’. Alas. Not deferred by the tag I tried to purchase something by clicking one of the big red ‘Buy’ buttons. Then I found out how they secured the shop against non-US customers.

Screenshot showing bittorrent.com asking for a 5 digit zipcode

I could really see myself renting Clockwork Orange for 3 bucks, I hope they fix the form validation when they start selling content to the rest of the world. And when they’re done fixing the validation they might also want to look into the other slight problem.

8 comments

Dynamic forms with the repetition model

Manfred Stienstra, 25 Jan 2007, 12:06 in ruby on rails, javascript, and web (edit).

I’m sure we’ve all been there; trying to save a list of associated objects together with the instance they belong to. Fortunately with the right tools this can be really simple.

Let’s assume we have a question in a questionnaire and need to specify an arbitrary number of options to this question. We could construct the following database schema.

create_table :questions do |t|
  t.column :stem,        :text
end

create_table :options do |t|
  t.column :question_id, :integer
  t.column :label,       :text
  t.column :feedback,    :text
  t.column :correct,     :boolean, :default => false
end

There are basically three ways I know about to assign multiple options to a question from one page. The first option is to create a Question instance in the database before rendering the form so we can use remote_form to send an Ajax request and directly associate the Option instance. An advantage of this solution is that all data is directly saved to the database, which makes losing any data less likely. Another advantage is that the functionality is spread nicely over the responsible controllers. First you perform a create on the QuestionsController, after that you perform multiple creates on the OptionsController. The disadvantage is that you have to create a Question with default values or by circumventing the initial validation. This could generate some ‘blank’ Question instances in the database which you will have to garbage collect.

The second option is a slight variation on the first option. Instead of creating a Question to link the Options to you keep all the generated Option id’s in the session and link them to the Question after validation. This solution also benefits from nice separation of concern in the controllers, but on the downside it also leaves you with unlinked Option objects you will have to garbage collect.

The third option is to keep all the information about the Questions and Options in the DOM tree of your from and post it all at once. This used to be hard, requiring a lot of custom JavaScript and browser tricks. Fortunately WHATWG is here to help; Web Forms 2.0 defines a repetition model for repeating form controls. Browser support for these interaction models is years away (except for Opera 9, which has an experimental implementation), that’s why there’s a JavaScript library to accelerate the adaptation.

It’s really easy to use the library in your Rails application. Download the repetitionmodel library, extract the zipfile and put the javascript files in public/javascripts. When you’re done with that we can get back to coding our application. Include the JavaScript file somewhere in your views.

<%= javascript_include_tag 'repetition-model-p' %>

We just mentioned that we want to send the entire form at once, we can use validates_associated to make sure the Question is never saved when the options aren’t valid. This allows you to easily validate all the information from the form at once. The models to go with the database look something like this.

class Question < ActiveRecord::Base
  has_many :options, :dependent => :delete
  validates_presence_of :stem
  validates_associated :options
end

class Option < ActiveRecord::Base
  belongs_to :question
  validates_presence_of :label
end

Build the new and edit forms for the QuestionController like you would normally do. A the bottom of the form we will add the HTML to edit the options.

<h2>Options</h2>
<ol id="options">
  <%= render :partial => 'options/option', :collection => @question.options %>
  <%= render :partial => 'options/option', :object => Option.new,
    :locals => {:option_counter => '[option]'} %>
</ol>
<p><button type="add" template="option">New option</button></p>

The first render is for all the existing options, the second render is for what the repetition model calls a template, the template should always be the last in the list of controls.

In app/views/options/_option.rhtml we put the following. This partial doubles as a template for new controls and as a partial for existing options in the database.

<% if option_counter == '[option]' -%>
<li id="option" repeat="template" repeat-start="0">
<% else -%>
<li repeat="<%= option_counter %>">
<% end -%>
  <div>
    <div><label>Label</label></div>
    <%= text_area_tag "options[#{option_counter}][label]", option.label,
      :rows => 1, :cols => 40 %>
  </div>
  <div>
    <div><label>Feedback</label></div>
    <%= text_area_tag "options[#{option_counter}][feedback]", option.feedback,
      :rows => 1, :cols => 40 %>
  </div>
  <div>
    <label><%= radio_button_tag "options[correct]", option_counter, option.correct?,
      :id => "options_correct_#{option_counter}" %> Correct</label>
  </div>
  <div>
    <button type="remove">Delete option</button>
  </div>
</li>

In the HTML you see some extra attributes used by the JavaScript to determine what to do with them. When the partial is rendered with an new Option, the template is flagged by setting the repeat attribute to template. The id of this element is used as a handle for our controls, in our case this is ‘option’. The repeat-start attribute tells the javascript how many empty controls to generate initially from the template, we don’t want any so we’ve set it to 0. Note that we explicitly set the option_counter to ‘[option]’, this is the variable notation for the repetition model. When a new control is instanciated from the template this variable is replaced by the the index of the new control. The first control gets index 0, the second gets index 1 and so forth.

When the partial is rendered with a collection, the magic variable option_counter is set to the index of the collection every time the partial is rendered. We use this index to set the repeat attribute of the list item, this signals to the JavaScript that this is an already instantiated control. The JavaScript will start counting from the largest index when it instantiates a new control.

Finally we want the user to add and remove option controls in our page, this is done with the ‘New option’ and ‘Delete option’ buttons. Their type attribute signals what we want the JavaScript to do with the repetition blocks. In case of the ‘New option’ button the template attribute tells the JavaScript which template to instantiate.

In addition to managing the controls and template in the DOM tree, the JavaScript also takes care of disabling buttons on appropriate times and setting the CSS display property of the template to none. They really thought of everything.

The advantage of this solution is that you can use all the standard Rails tricks to keep your database clean. The biggest disadvantage is that the create method in your QuestionsController becomes a lot more complex.

Let’s hope native browser implementations follow quickly.

6 comments

Obama makes me want to listen

Thijs van der Vossen, 22 Jan 2007, 10:41 in web and video (edit).

Both Hillary Clinton and Barack Obama use web video to announce their exploratory committees.

Screenshot showing both Hillary Clinton and Barack Obama’s announcement video on the web

Obama is publishing video through Brightcove. This means you can easily email, link to, or embed the video. You also get a channel you can subscribe to using RSS.

Hillary is using her ‘own’ player which means there’s none of this nice stuff.

Another smart touch on the Obama website is the low-bandwidth download for people on dailup and a link to the transcript.

It’s also interesting to compare the production. In the Hillary video the camera is panning from left to right and back all the time. Apart from making you seasick this increases the size of the video file because there’s a lot more information that needs to be encoded.

The Obama video uses a single fixed head-and-shoulders shot. This seems to work very well for these kind of messages on the web; he’s close enough to make it feel like he’s talking to you directly, but not so close that it’s uncomfortable. Hillary is too far away over there on the couch in the first part of the video, and then a little too close and personal when they switch to close-up.

The sound is way better in the Hillary video. Obama sounds thin and ‘canned’, probably because of too much compression.

To me, the Obama video appears to be serious and personal. The Hillary video somehow made me feel I was watching a life insurance commercial. What do you think?

3 comments

REST for toddlers

Thijs van der Vossen, 07 Dec 2006, 20:23 in web (edit).

No comments yet

UnSpun encoding problems

Manfred Stienstra, 07 Dec 2006, 12:44 in ruby on rails, web, broken, and unicode (edit).

A few weeks ago Amazon launched UnSpun, a web application to collectively manage lists of all sorts.

During signup I was presented with the following.

Screenshot of UnSpun with a broken letter

I know Internet Explorer fixes a lot of broken encoding by guessing the true encoding for just about everything, maybe that’s why they never noticed during development?

I’ve had this problem myself on a few occasions. Because geographical information is commonly extracted from text files and loaded into a database you always have to be really careful to transcode any data extracted from text files to the same encoding as the database. In the case of ISO-8859-1/15, which is commonly used in west-european countries, there is a really simple oneliner to transcode to utf-8.

source.unpack('C*').pack('U*')

3 comments

Getting Real, the book now free

Thijs van der Vossen, 26 Oct 2006, 09:11 in web, practices, and design (edit).

Getting Real, the book, self-published in PDF format this march by 37signals, is now also available as a paperback and in a free html version.

I never finished reading the pdf version because I find reading PDF documents on a computer screen really annoying.

Reading a well-designed html document from screen is a much, much better user experience; it’s easy to change font size, the position and width of page elements changes to fit the browser window and you can just scroll down and keep on reading without being interrupted by page boundaries.

For reading from screen, the html version of Getting Real just works better.

One thing is driving my crazy though; why on earth haven’t they used curved quotation marks in the html version? Proper punctuation just doesn’t matter anymore?

2 comments

A very nice Microformats bookmarklet

Thijs van der Vossen, 27 Sep 2006, 20:17 in web and design (edit).

Remy Sharp has created a very nice Microformats bookmarklet based on Jon Hicks’ proposal for a Safari Microformats plugin.

Fingertips contact information in the Microformats bookmarklet

Via Tobias Lütke, who gives a good example of what you should be able to do with Microformats:

[…] In other words you will finally be able to drag drop a web page with contact information onto your Address software and it should “just work”.

No comments yet

HTTP Digest Authentication

Manfred Stienstra, 04 Sep 2006, 23:13 in web and broken (edit).

For traditional sites cookie based authentication was often the best choice, especially because the application has complete control of the session which allows for automated logouts and other freaky stuff. Over the last year I’ve implemented quite a few authenticated applications and a large number of them has feeds or a webservice interface of some sort. But feedreaders and REST clients don’t really like cookie based authentication. HTTP Authentication is an obvious alternative, so we started using it.

In a lot of todo lists under the header ‘in the distant future’ there was an item: implement digest authentication. So I decided to bite the bullet and read RFC 2617.

I implemented the protocol for both sides, client and server. I sincerely believe that’s the best way to implement a protocol. That way you can always test the partially implemented client on the partially implemented server and bootstrap until everything is done. The best thing is that client and server implementations share a lot of algorithms, working on both makes your implementation orthogonal by default.

Implementing the specs went well, until I tried to talk to other implementations. Already in the first week I discovered four problems:

  1. Apache doesn’t send the required ‘nextnonce’ directive in it’s Authentication-Info header.
  2. Safari quotes algorithm and qop directives in the Authorization header. These directives shouldn’t be quoted.
  3. IE quotes algorithm and qop directives just like Safari does.
  4. IE computes the digest only over the path part of the URI instead of over the path and query part. (From the apache documentation of mod_auth_digest)

This brings up quite a few questions. Did Safari copy the quoting behaviour from IE instead of reading the RFC themselves? Is implementing standards too hard? Should standards be replaced by reference implementations?

I willing to tackle the last question because it’s so easy to answer. RFC 2617 happens to provide a reference implementation for computing Authorize headers, so that can’t be the problem. So are standards just too hard? RFC 2617 is a pretty complicated pieces of header prose, but it’s not as long and threaded as the HTTP specs. And way way easier than SOAP specs. So there must be something else.

Let’s assume for a moment that standards are completely unambiguous and well written. Given that premise, I believe that the quality of the implementation is a direct result of the determination and vigilance of the programmer. Or better yet, group of programmers. Two pairs of eyes see more that one, and a whole open source community sees more that just one annoyed corporate programmer.

I think digest authentication implementations haven’t received the level of scrutiny that other protocols have and that this resulted in a number of bugs in the various implementations. On that note I would like you to check out my own implementation: HTTP Authentication for Ruby. You can find the API documentation on Rubyforge. There is also a gem, which you can install the usual way:

gem install httpauth

This is still early beta and there are bugs and limitations.

4 comments

Ajaxload

Thijs van der Vossen, 13 Aug 2006, 10:58 in web and design (edit).

Build your own with the Web 2.0 ajax loading gif generator service.

No comments yet

Web Content Accessibility Guidelines

Thijs van der Vossen, 18 Jul 2006, 09:03 in web (edit).

Sigh:

[…] are you actually, without even knowing it, an author authoring authored units to be used in authored components in programmatically-determined web units that can be parsed unambiguously?

It will take only a few large organisations stupid enough to start requiring WCAG 2 conformance for accessibility consultancy to become a booming business.

2 comments

Discussing Unicode for Ruby

Thijs van der Vossen, 21 Jun 2006, 13:15 in ruby on rails, web, and unicode (edit).

The Unicode roadmap thread on the Ruby Lang mailing list is now almost 100 messages long.

Yukihiro Matsumoto (matz):

I am too optimized for Ruby string operations using Regexp.

Tim Bray:

Julian ‘Julik’ Tarkhanov:

I think this thread is going to end the same as the one in 2002 did.

Read the whole damn thing if you want to know more about the gritty details. In case it makes your head hurt, go read On the Goodness of Unicode, Characters vs. Bytes and The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!) first.

12 comments

An excellent and pragmatic proposal for easier Unicode support in Rails

Thijs van der Vossen, 16 Jun 2006, 10:45 in ruby on rails, web, and unicode (edit).

The current Ruby version has no Unicode String class like in Python or Java. This makes it hard for Rails to support multibyte encodings.

The following code snippet from the truncate helper is a good example:

if $KCODE == "NONE"
  text.length > length ? text[0...l] + truncate_string : text
else
  chars = text.split(//)
  chars.length > length ? chars[0...l].join + truncate_string : text
end

This was added to make the helper work with multibyte characters, but it is far from beautiful.

A few days ago, Julian proposed to add a proxy to the string class for accessing characters instead of bytes. I think this is an excellent and very nice solution.

You access the proxy with the char method on a string object. You can for example get the number of characters with:

text.chars.length

The char method is aliased as u, so you can also write:

text.u.length

Which to me looks even nicer.

Using the proxy, you could replace the six lines of code from the truncate helper with:

text.chars.length > length ? text.chars[0...l] + truncate_string : text

That’s a whole lot more obvious. And don’t be fooled, this is just as fast as the longer version because the proxy only uses the multibyte safe methods when $KODE is set.

Apart from making the Rails code easier to understand and maintain, the proxy can also save application developers a lot of work.

The proxy and the patches to the Rails code are currently in development as a plugin you can get from Subversion. Even though the plugin is called ‘Unicode hacks’ for historical reasons, it’s actually a very clean solution by now. There’s also a proposed patch to the Rails source.

Please try this one out and give your feedback.

11 comments

Embedding applications with Javascript

Manfred Stienstra, 06 Jun 2006, 10:53 in javascript and web (edit).

RightCart is a cool service that allows you to embed a shopping cart into your webpage. It looks great, but I think it should be a little bit easier to set up.

When you create an account, you get a small piece of HTML to add to your web page (I’ve added formatting for clarity):

<div class='rightcart_div'>
  <script type='text/javascript'>rightcart_pid='1'</script>
  <script type='text/javascript' src='http://rightcart.com/static/rightcart_display.js'></script>
</div>

Above the code is the following text:

“Simply add the three lines of code below to your web page and your RightCart will appear on your site. It’s that easy.”

But why three lines? Let’s look at the information this application needs. I see a div with a the class ‘rightcart_div’, followed by a variable ‘rightcart_pid’ and after that an URL for a piece of JavaScript. In Rhubarb we do the same with a single line of code:

<script type="text/javascript" src="http://rhubarb/inline/58"></script>

So why is this shorter? We don’t need a named div because our javascript adds it to the page. We don’t need to set a user id of some sort because it’s in the URL. That leaves a single script tag.

Even better, the full code contains a link to a full-page version of the same content for when JavaScript is not available:

<script type="text/javascript" src="http://rhubarb.fngtps.com/inline/58"></script> 
<noscript>
  <p><a href="http://rhubarb.fngtps.com/58">Aksie!</a></p>
</noscript>

It can be dangerous to add HTML to other pages like this. The injected HTML could end up in biggest case of tagsoup you’ve ever seen, completely breaking your layout.

That’s why we offer four different ways to publish an appeal with Rhubarb: a regular page, embedded on another page inside an iframe, embedded inline and embedded with a nice lightbox effect.

This way you can choose the delivery type that best fits your site while keeping everything accessible.

No comments yet

Embracing and extending the feed icon

Thijs van der Vossen, 31 May 2006, 09:52 in web and design (edit).

Khoi Vinh’s group at the NY Times is thinking about embracing and extending the Firefox and IE7 feed icon. One of their designers proposed the following modifications:

Really very nicely done. What I don’t get is how the ‘RSS 2.0’, ‘ATOM FEED’, and ‘XML’ labels are going to make things clearer. And what the hell is ‘XML VIDEO’? Some experimental new XML-based video format?

The whole point of the new feed icon was to eliminate the confusion brought on by all these different acronyms. There’s really no reason to offer the exact same content in different feed formats.

The problem with the NY Times podcasts page is not that it offers the same content in different feed formats, but that it allows you to subscribe to the same content with different tools.

You can click the pod subscribe button to add the subscription to your default feed reader, you can click the iTunes button to add the subscription to your podcasts in iTunes and you can click the My Yahoo button to add it to your My Yahoo page.

Want to make this less confusing? Here’s how:

Subscribe (default)
Subscribe in iTunes
Add to your My Yahoo page

No comments yet

Call it what it is

Thijs van der Vossen, 26 May 2006, 13:56 in web (edit).

Mark started the naming game again, then Sam and Simon quickly joined in.

Why not just call it ’web’?

No comments yet

Basic Authentication for Camping

Manfred Stienstra, 19 May 2006, 17:35 in tools and web (edit).

This week I wrote a small web tool in Camping but when I wanted to secure it a little bit I noticed that there was no default way to do HTTP basic authentication. So I wrote some code to do just that. Actually I wrote a lot of documentation and a little bit of code.

With just some downloading and three simple steps you can add basic authentication to you application.

Download the basic_authentication.rb file.

  1. require 'basic_authentication'
  2. Mixin the BasicAuth module:
    module Blog
      include Camping::BasicAuth
    end
  3. Define how you want to authenticate users:
    module Blog
      def authenticate(u, p)
        [u,p] == ['admin','secret']
      end
      module_function :authenticate
    end

And you’re ready to start not letting people into you application. If anyone has a better idea on how and where to define the authenticate method, please drop me a line.

You can use this code under the same restrictions as the Camping framework. Now let’s just hope Why doesn’t sue me for using the Camping module (:

Update: Thijs found a bug in the header handling. The link above has been updated. I will try to give this code a home somewhere and some proper version information when I have some time.

9 comments

Just a contractor

Thijs van der Vossen, 14 Apr 2006, 20:34 in web (edit).

David’s slide really made my day. If you don’t get the title, check out the comments for an explanation.

I really don’t think we’re ever going to need all this WS-* insanity. If you’re looking for a reliable, simple, scalable and proven standards-based infrastructure please go read Architecture of the World Wide Web for a great overview, the Atom Publishing Protocol for a fine example and the HTTP/1.0 and HTTP/1.1 RFCs for the basic specs. Everything we need for web services is already here and it works just fine, thank you.

No comments yet

Handheld stylesheet

Thijs van der Vossen, 23 Mar 2006, 12:29 in web and design (edit).

One of the advantages of designing with web standards is that it doesn’t take much effort to create a mobile version of your website. It took me just a little more than an hour to add a stylesheet to Rijnboutt van der Vossen Rijnboutt that optimizes the layout for handheld devices.

No comments yet

Zeldman just made me smile

Thijs van der Vossen, 17 Jan 2006, 21:04 in web (edit).

Read all about Web 3.0 on A List Apart:

To you who are toiling over an AJAX- and Ruby-powered social software product, good luck, God bless, and have fun. Remember that 20 other people are working on the same idea. So keep it simple, and ship it before they do, and maintain your sense of humor whether you get rich or go broke. Especially if you get rich. Nothing is more unsightly than a solemn multi-millionaire.

To you who feel like failures because you spent last year honing your web skills and serving clients, or running a business, or perhaps publishing content, you are special and lovely, so hold that pretty head high, and never let them see the tears.

1 comment