Hi, I'm Benedikt Deicke, and I'm a freelance web and software developer. I'm mainly building user focused web applications using Ruby on Rails and JavaScript. Additionally I'm currently studying for my master's degree and enjoying photography in my spare time. Feel free to get in touch with me, I'm available for hire!

June 24th, 2010
Multitouch Inspector for iPad

During the last couple weeks I’ve been playing around with the iPad and Mobile Safari. I built a little tool to familiarize myself with the Multitouch JavaScript API provided by Mobile Safari as well as web applications for the iPad in general. I named the result Multitouch Inspector because that’s what it does: Inspect the TouchEvents fired by the JavaScript API. ;-) Today I decided to rewrite the tool to drop the dependency on Prototype.js and I published it on GitHub.

Using Multitouch Events from JavaScript

There are four events that are related to touch: TouchStart, TouchMove, TouchEnd and TouchCancel. I’m not sure about what situation would trigger TouchCancel so I decided to skip it for now. Working with the touch events is straight forward:

   1  document.addEventListener('touchstart', function(event) {
   2    /* Do whatever you'd like to do with the event */
   3  }, false);

Of course you can add the listener to any element just like you would with Click or MouseOver events. The function gets passed an object of type TouchEvent. There are several properties on this object, but the most interesting ones are touches, changedTouches and targetTouches. They all are of type TouchList and contain several Touch objects. The touches property lists all touches currently on the screen. The changedTouches list contains the touches that changed and caused the event to fire. The touches in the targetTouches list are those that are currently within the target element.

Every Touch has an identifier property as well as pageX and pageY properties. As you might have guessed already, the pageX and pageY properties include the touch’s position on the screen. The identifier property provides an unique integer for this touch. It stays the the same for this touch as long it is on the screen. This is particularly useful as removing one finger will trigger a TouchEnd event that implies that all fingers were removed, immediately followed by a TouchStart event including the remaining fingers. Luckily the identifier property stays the same for those fingers that weren’t removed from the screen.

Offline Application Caching

In order to use the application without having an active internet connection or simply while the development server isn’t running I’m using HTML5 Offline Application Caching. It works by defining a manifest file and referencing it in the html-tag:

   1  <!DOCTYPE html>
   2  <html manifest="application.manifest">

The manifest file itself looks like this and defines what files are required to view the application while offline:

   1  CACHE MANIFEST
   2  
   3  # c94640e9114e05f16e189605e5b65ba2357117712c949cae92cc29bc1bbd3c47
   4  /images/background.png
   5  /images/icon.png
   6  /index.html
   7  /javascripts/application.js
   8  /stylesheets/application.css

You might wonder about the random string at the top. As the browser will reload everything when it can’t find one file in it’s cache, I’m using this string to force a reload during development. I built a small Sinatra app (see the listing below this paragraph) that generates the manifest and resets this string for every request. As a result, the browser reloads everything while online but falls back to the cached files when offline.

   1  require 'sinatra'
   2  require 'digest/sha2'
   3  require 'pathname'
   4  
   5  # ...
   6  
   7  get '/application.manifest' do
   8    content_type 'text/cache-manifest'
   9  
  10    manifest = "CACHE MANIFEST\n\n"
  11    manifest << "# " << Digest::SHA2.hexdigest(Time.now.to_s + Time.now.usec.to_s) << "\n"
  12  
  13    root = Pathname.new(settings.public)
  14    Pathname.glob(File.join(root, "**", "*")).each do |p|
  15      manifest << "/" << p.relative_path_from(root) << "\n" if p.file?
  16    end
  17  
  18    manifest
  19  end

Issues

There are some issues that I couldn’t resolve while building the application. The startup image will only work while in portrait orientation and its dimension has to be exactly 1004×768. Currently there isn’t a way to define a startup image for horizontal orientation.

While the tracking of the touches works on the iPhone (with iOS 4.0) as well for some reason it isn’t possible to press the buttons in the toolbar. At the moment I have no explanation for this rather strange behavior, but I might take another look at it in the future.

Screenshot & Demo

Now that you have some insights on the internals of the application, here’s a screenshot as well as a link on it to a demo:

Fork it on GitHub

I published the source code on GitHub. Feel free to fork it!

Further reading

  1. Safari Web Content Guide: Handling Events
  2. Making an iPad HTML5 App & making it really fast
Posted by benediktFiled in Articles, Javascript

July 24th, 2008
Script.aculo.us should have Effect.Emerge

Script.aculo.us includes a nice effect called Effect.DropOut, which let’s the element fall in an “invisible trap” underneath. Surprisingly there isn’t an opposite effect. Calling Effect.DropOut with Effect.Transitions.reverse as transition, doesn’t work either. So what to do? Effect.Emerge to the rescue!

   1  
   2  Effect.Emerge = function(element) {
   3    element = $(element);
   4    var oldStyle = {
   5      top: element.getStyle('top'),
   6      left: element.getStyle('left') };
   7    var position = element.positionedOffset();
   8    return new Effect.Parallel(
   9      [ new Effect.Move(element, {x: 0, y: -100, sync: true }), 
  10        new Effect.Opacity(element, { sync: true, from: 0.0, to: 1.0 }) ],
  11      Object.extend(
  12        { duration: 0.5,
  13          beforeSetup: function(effect) {
  14            effect.effects[0].element.show().makePositioned().setStyle( { top: (position.top + 100) + 'px' }); 
  15          },
  16          afterFinishInternal: function(effect) {
  17            effect.effects[0].element.undoPositioned().setStyle(oldStyle);
  18          } 
  19        }, arguments[1] || { }));
  20  };

Basically it’s just a modified version of Effect.DropOut to reverse the effect. Try it in compination with Effect.multiple ... :-)

Posted by benediktFiled in Javascript

February 14th, 2008
Extended: Forms with widgets

There is a great article by Jason Long on Vitamin called ‘Streamline your forms with widgets’. In his article Jason Long describes a nice looking way to clean up a lot of checkboxes into multiple dropdown widgets. What I really liked was the idea to have some summary about the selected items next to the title of the dropdown widgets. Unfortunately he didn’t implement the updating function but just mentioned it as a possible extension. In addition he pointed out that “Any Fuel” would be much easier to read than “Fuel (Gasoline, Diesel, Alternative)”. As I was in the right mood for some Javascript I implemented the missing functionality.

At first I added four little lines to the top of the toggleDropdown() function. This little snippet checks weather the panel is currently visible (so the function was toggled to hide the panel again) and calls the updateTitle() function.

   1  function toggleDropdown(panel) 
   2  {
   3    panel = $(panel);
   4    if(panel.visible()) {
   5      updateTitle(panel);
   6    }
   7  
   8    // toggle the requested one
   9    Element.toggle(panel);
  10       
  11    // then hide all of the others so that only
  12    // one (at most) is open at a time
  13    $$('body .dd_option_panel').each(function(node){
  14      if (node != $(panel)) {
  15        Element.hide(node);
  16      }
  17    });  
  18  }

To do the actual updating of the title I used Prototype’s nifty little DOM traversal toolkit. It provides methods such as Element#select(), Element#up(), Element#down(), Element#previous() and Element#next(). All of can be supplied with a selector, similar to those in CSS.

First I select all child elements of type “input” and check their value. If the value matches “on” the checkbox is selected and I travel down to the next “label”-element to push it’s content into an array. Afterwards I check the size of this array and decide how to change the title. If none of the checkboxes are selected I add “No ” to the title and don’t display the list of the selected values. Accordingly if all are selected I prepend “Any ”. Otherwise I leave the title as it is and update the list behind it by joining the elements of the array into a string. To prevent titles such as “Any Any No Any Fuel” I clean up the title by removing either Any or No in front of the title using String#gsub().

   1  function updateTitle(panel)
   2  {
   3    selected = new Array();
   4    panel.select('input').each(function(box){
   5      if(box.getValue() == 'on') {
   6        selected.push(box.next('label').innerHTML);
   7      }
   8    });
   9       
  10    inner = panel.previous(".inner");
  11    title = inner.innerHTML.gsub(/^([Any|No])/, '');
  12    
  13    if(selected.length == 0) {
  14      inner.update('No ' + title);
  15      inner.down(".light").update('');
  16    } else if(selected.length == panel.select('label').length) {
  17      inner.update('Any ' + title);
  18      inner.down('.light').update('');
  19    } else {
  20      inner.update(title);
  21      inner.down('.light').update('(' + selected.join(', ') + ')');
  22    }
  23  }

In order to get correct titles right from the beginning I update all titles after the page loaded.

   1  Event.observe(window, 'load', function(event) {
   2    $$('body .dd_option_panel').each(function(panel) {
   3      updateTitle(panel);
   4    });
   5  });

That’s it! Click here to see the changed example.

Of course all the credits for the original implementation, graphics, and idea go to Jason Long.

Posted by benediktFiled in Articles, Javascript