Archive for the ‘firefox’ Category

Taking your webapp offline

Sunday, August 21st, 2011

I’ve recently done a few things that would benefit from having an offline mode. Empowered by Appcache Facts I tried to make the newly published La Vuelta 2011 results page an offline-capable app.

Goal

The goal of this exercise is twofold:

  1. To force caching of resources that slow down the loading of your page.
  2. To actually be able to use the app when offline.

Solution

It’s as simple as writing a cache manifest. It pays to name it [something].manifest, as Apache already serves the correct header with that suffix. What you do is list all the files you want cached, add stuff you allow on the network (check Appcache Facts and Dive Into HTML5 – Offline Web Applications) and it all works. Except it doesn’t.

CACHE MANIFEST
# version 1

CACHE:
resource.js

NETWORK:
*
http://*
https://*

AJAX stuff

If you’re using AJAX to get data from a server using jsonp/script, your framework of choice (jQuery in my case) will probably default to using a no-cache approach to loading it. This will mean that it will request the file + some suffix to prevent browser caching. This will mean that the resource will not be available if you’re actually online.

You can use navigator.onLine to switch cache on/off, but I suggest you first try requesting the no-cache resource and if it errors out, request the cached resource. The benefit is that even if you are online but the server is not, the users will still see the data / use the app.

$.ajax({
	dataType: 'script',
	url: 'resource.js',
	cache: false,
	success: successHandler,
	error: function () {
		$.ajax({
			dataType: 'script',
			url: 'resource.js',
			cache: true,
			success: successHandler
		});
	}
});

iPad issues

Fixing the AJAX meant that it worked properly on the desktop (test with Firefox that has offline mode) and in Safari on the iPad. The trouble started when I added the app to Home Screen – data failed to load. It was the same app as in Safari and it should have worked.

After some debugging I found out that the data actually was loaded but the eval failed (I was using $.getScript). Some weird testing showed that the problem was a newline character in the data. As I really liked the newline there I added some code to the error handling that removed the newline and evaled the data, then ran success. And it worked!

$.ajax({
	dataType: 'script',
	url: 'resource.js',
	cache: false,
	success: successHandler,
	error: function () {
		$.ajax({
			dataType: 'script',
			url: 'resource.js',
			cache: true,
			success: successHandler,
			error: function (xhr) {
				eval(xhr.textResponse.replace(/\n/g, ''));
				successHandler();
			}
		});
	}
});

Debugging

It’s somewhat hard to debug offline stuff. I suggest using a clearly visible version indicator in the file to make sure you know which version of the file you’re looking at. Also remember that the first time you load the app after changing the file & cache manifest it is served from cache. At the same time the manifest is checked and on the iPad the files are downloaded after everything else is done (app finished loading and rendering).

It works!

After these problems were solved I used the aforementioned navigator.onLine to hide stuff that normally comes from the network but is not relevant to the offline app (banners, share links, like/+1 buttons) and you can now check the La Vuelta 2011 results page.

Fluid searchbox

Sunday, October 4th, 2009

There’s been a lot of fluid layouts recently. When you use a fluid layout it’s hard to make everything fluid as you need to stretch certain elements and have other elements fixed.

I was approached some time ago by a designer who was working on a fluid design but was having problems with a HTML/CSS only solution for a fluid searchbox. The idea to create a searchbox that grows when the window grows is simple, but becomes a tad more difficult when you add stuff to the left and right of it, some being fixed width (width in px or em) and some fluid width (width in %).

As I like challenges I took it on and produced a sample that worked on most modern browsers in a single evening. They didn’t like it because it didn’t work in IE7 (cause I never checked it) even though the fix for IE (it was only IE7 that didn’t work) was trivial. After a while I went back and checked it out again, changed the code a bit and I think it’s much better now.

The simple form

Creating a fluid search box when you only have a single element next to it is trivial. What you do is wrap the input in an element and use padding to create space for the fixed element, then position the fixed element absolutely (or relatively) in the space created by the padding.

HTML:
<fieldset>
	<div>
		<input type="text" name="q" value="" />
	</div>
	<input class="s" type="submit" value="Search" />
</fieldset>
CSS:
fieldset {position:relative;padding:0;}
div {padding-right:6em;}
div input {width:100%;}
input.s {width:5em;font-size:1em;position:absolute;right:0;top:0;}
Sample

You could target the input with input[type=submit] but that wouldn’t work in older browsers.

A complex form

The complex form from the intro includes a title, a search type drop-down (select element), the input box and a submit button. This gives us four elements, two of which are fixed and two fluid – and more stuff to hack around.

HTML
<fieldset>
	<div class="l">
		<span>Find</span>
		<select name="type">
			<option>in Books</option>
			<option>in DVDs</option>
		</select>
	</div>
	<div class="c">
		<input type="text" value="" name="q" />
	</div>
	<div class="r">
		<input type="submit" value="Search" />
	</div>
</fieldset>
CSS
fieldset {margin:0;padding:0;position:relative;border:0;}
fieldset .l {height:0;}
fieldset .l span {width:3em;display:inline-block;}
fieldset .l select {width:10%;}
fieldset .c {margin:0 60px 0 4em;padding:0 .7em 0 10%;}
fieldset .c input {width:100%;}
fieldset .r {position:absolute;right:0;top:0;}
fieldset .r input {width:60px;}
* html fieldset .l {float:left;width:100%;margin-right:-100%;}

The basics

I created three elements that help me align elements. I’m using classes l for left, c for center and r for right. The left element includes the title and the type, the central element includes the search box and the right element includes the submit button.

fieldset .l {height:0;}
fieldset .r {position:absolute;right:0;top:0;}

The left element has its height set to 0 so it seemingly doesn’t take any space. The central element includes the input and needs no special positioning, while the right element is positioned similar to the simple solution – absolute and set to right.

The surrounding elements

You can set the width of these elements in any unit you like. I set the width for the span element in em, type drop-down in % to make it fluid and submit button in px.

fieldset .l span {width:3em;display:inline-block;}
fieldset .l select {width:10%;}
fieldset .r input {width:60px;}

The only thing you need to do in CSS is set the width to these elements. You need to set the display property on the span element to work around the fact that inline elements don’t allow setting of width.

The fluid input

fieldset .c {margin:0 60px 0 4em;padding:0 .7em 0 10%;}
fieldset .c input {width:100%;}

The input needs its width set to 100% so it will stretch the whole available width of the parent. That happens due to the fact that block-level elements will grow to 100% automatically and the margin and padding will “shrink” its contents. This allows setting the spacing in two different units – one for margin and one for padding. If you look at the CSS rule, you’ll see that the widths are similar to those set for the surrounding elements – of course with some spacing added.

  • Right: 60px margin (width of the submit button), .7em padding (spacing)
  • Left: 4em margin (3em for the title + spacing), 10% padding (type select width)

The browsers

You can check out a sample page with the complex form. Working on Windows I’ve tested it in these browsers:

  • Firefox: 2.0, 3.0, 3.5
  • Opera: 10
  • Safari: 4
  • Google Chrome: 3
  • Internet Explorer: 8 (with its rendering of IE7 Standards and Quirks)

As always at least one browser had to fail – IE6 did. The problem was height:0; as IE6 will render elements as high as their content. We can work around this by changing the way we make it zero width/height so it doesn’t affect the central element.

* html fieldset .l {float:left;width:100%;margin-right:-100%;}

I’m using the IE6 CSS filter to target IE6, you can use conditional comments or whatever you like best. The rule floats the element left, making it 100% wide, but resets the position by setting the right margin to -100%.

As I’m using display:inline-block; this will work a bit different on browsers that don’t support inline-block. In Firefox 2.0 you can use display:-moz-inline-box; in the rule for the span, but make sure you put it before the inline-block.

fieldset .l span {width:3em;display:-moz-inline-box;display:inline-block;}

Last words

You might want to fix some stuff in some browsers so everything aligns nice. The techinque used is derived from the multi-unit any-order column layout by Eric Meyer as it opens your mind on how to use multiple units in a single layout without fuss. I’ve tried all the browsers I have on my dev machine and I’m not saying it works everywhere. If you find a browser where it doesn’t post a comment; if you find a better way of doing things also post a comment.

Reblog this post [with Zemanta]

Essential Firefox add-ons

Tuesday, April 7th, 2009

I’ve recently had to install a Firefox on the new iMac which lead me to ponder what add-ons do you really need.

Image representing Firefox as depicted in Crun...Image via CrunchBase

This is the list I compiled:

Infrastructure

These add-ons will enhance the capabilities of your browser. You might not need them right away, but it’s smart to have them installed for when you need them (and I’m sure you will).

  1. Google Gears allows you to use off-line Gmail and makes a lot of web applications faster.
  2. Greasemonkey lets you install user scripts that will make pages nicer, give them additional features and other kinky stuff.
  3. Operator will expose microformated content so you can easily use it.

Developer

If you’re the dedicated support guy for this specific installation (people will call you when things go wrong) you should install these now – they’ll help you fix stuff later.

  1. Firebug will let you inspect pages and see what’s wrong and why.
  2. Html Validator validates the code on the page so it’s easier to spot why something looks weird on screen.
  3. Web developer toolbar adds a lot of useful features for debugging pages to a handy toolbar.

Interface

These are just a few I like that make the browsing experience a bit nicer.

  1. Cooliris makes searching for images a lot friendlier.
  2. FoxTab helps when you have lots of tabs open. Unfortunately it isn’t supported on Mac OS X 10.5.6 yet
  3. Inquisitor is a nice search add-on that will enhance the search box.
  4. Fission moves the progress bar into the address bar (Safari style).

Sharing

To make your social networking and blogging a bit easier.

  1. Delicious is a great add-on if you use their social bookmarking service.
  2. Fotofox lets you upload photos to a bunch of photo sites easily.
  3. Zemanta integrates with your blogging platform and recommends images, videos, links, articles and tags.
  4. (Shameless plug) Tweecious is great for people who use Twitter and Delicious – it takes twittered links and posts them to Delicious.

You might also want to install dictionaries for the languages you use when writing in Firefox. You can get some more ideas at Fashion your Firefox.

Reblog this post [with Zemanta]

Speaking about the web of data

Wednesday, February 25th, 2009

Today at 19:00 CET I’ll be speaking at a local web meet-up about the web of data. There’ll be a live feed of the talk available and since I’ll be speaking in English you can tune it. This is a quick translation of the abstract posted on Slovenian sites:

Numerous services are emerging on the web that provide data in a computer friendly form through APIs, microformats, feeds,… Even your blog is actually a database as it syndicates its content via feeds and new posts trigger a ping you can subscribe to.

This fact opens new ways of collaboration – so called mash-ups, but this isn’t really a new concept. What’s new about it is the fact that we don’t use this word anymore as all the new services are some sort of a mash-up leveraging existing services. But accessing data is not the only way to leveraging these services – it’s becoming increasingly easy to create an application that lives in other applications without their approval through browser extensions and bookmarklets.

Marko Mrdjenovič from Zemanta will talk about what you can do to make your site more mash-up friendly and why that’s becoming increasingly important. As a developer I’ll also present what options you have and give a few tips on what to do and what to avoid when developing these kind of apps.

If you have any questions during the talk use twitter to tell me and I’ll try to answer them. Or put them in the comments.

Update: The video is now online. It’s in English so go watch it and tell me what you think.

Reblog this post [with Zemanta]

jQuery.readyOrDone

Thursday, February 19th, 2009

There’s a really small probability that someone might need something like this but I did and I’d like to share it.

At Zemanta we have a few different ways of loading our scripts and we cannot always control when they do. The Firefox extension will load the scripts on DOM ready, WordPress plugin will load them somewhere in the middle of the HTML, Drupal and MovableType plugins will load them in the head and IE extension will load them sometime while loading the page.

This all means that we have to delay some of our code execution to when DOM is ready and scripts are loaded. Which is where the problem kicks in.

jQuery has this nice way of doing this with $(document).ready(fn) or short $(fn) which waits until the document is ready and executes the passed fn function. If the document is ready it will execute the function immediately. Our issue lies in what “document is ready” means to jQuery – it means different thing in different browsers.

In browsers that support DOMContentLoaded (Firefox, Webkit, Opera – let’s call them modern browsers) “document is ready” means that either DOMContentLoaded event fired on the document or the load event fired on its window. On IE “document is ready” means that either onreadystatechange fired with readyState === 'complete' on the document or document.documentElement.doScroll("left") is successful (Diego Perini hack). To make this short – if you load jQuery after all the events fired in modern browsers jQuery will never know that the document is ready.

To get around this (we really don’t like having our own hacked version of jQuery) I wrote this little plugin:

(function ($) {
$.readyOrDone = function (fn) {
	var s = document.readyState;
	if (s === 'complete') {
		$.ready();
	}
	$(fn);
};
})(jQuery);

As you can see this will check if document is in a “complete” state and fire the ready method on jQuery which usually fires when DOM is ready – if it fired before it will do nothing. It will then add the function to the ready queue which also has this nice feature of firing immediately if DOM is ready.

All you have to do is change your $(fn) calls to $.readyOrDone(fn) and you have a bulletproof solution for executing functions when DOM is ready even if jQuery was late to the party and has no idea if the document is really ready.

Update: Filed a bug and hoping for the best.

Update 2: I found out that not all browsers provide the readyState property – Firefox on Ubuntu for example. Devised a new version that tries to smartly handle such cases:

(function ($) {
	var time = setTimeout(function () {}, 0),
		lastelm = null;
	$.readyOrDone = function (fn) {
		var s = document.readyState, getLast = function () {
			var elms = document.getElementsByTagName('*');
			return elms[elms.length - 1];
		};
		if (s === 'complete') {
			$.ready();
		} else if (typeof s === 'undefined') {
			lastelm = getLast();
			clearTimeout(time);
			time = setTimeout(function () {
				if (getLast() === lastelm && typeof document.readyState === 'undefined') {
					 $.ready();
				}
			}, 1000);
		}
		$(fn);
	};
})($);
Reblog this post [with Zemanta]

jQuery window.name transport is out…

Wednesday, October 1st, 2008
JQuery intermediate site

Image by Phillie Casablanca via Flickr

After a week of mostly testing and fine-tuning the code I finally released the windowName transport plugin for jQuery. You can get the plugin here but I suggest you first check the plugin page.

I need help testing

If you have an obscure browser / OS combination that is supported by jQuery I urge you to test the plugin. There are no good test pages yet so my temporary test page will have to do. The test page POSTs the querystring passed to it to a nonlocal domain and should open a JavaScript alert with the same querystring plus php=true.

On a sidenote – I figured out that the page looks better without the background images. So I changed the theme – let me know what you think.

Reblog this post [with Zemanta]