Thought I would share this hack.
The problem - you want to maintain some state on the client, but you don’t want to send this state on a pointless round-trip to the server with every request, as typically happens with Cookies.
There is a way around this though!
- add an hidden iframe to your page, with src=”/client-side-cookie/blank.html”
- from this directory, you serve a static empty HTML file, and, crucially, you serve this with Expires headers way into the future (see this Yahoo tip for some info about this technique)
- This file will not (typically) be re-requested before the time given in your Expire header
- Set cookies for the document in the iframe from your javascript code, with path=/client-side-cookie/, and with whatever expiry time you like. eg, iframe.contentDocument.cookie = ‘test=long_data_which_we_dont_want_to_send_to_the_server; path=/client-side-cookie/’
- When you want the data back in future - again, create the iframe (the HTML file will NOT be loaded from the server because of the Expires header, and so no cookies will be sent to the server). Then inspect iframe.contentDocument.cookie to get the data.
- Because you have restricted the path of the cookie, it will never be sent with requests for files outside of your special /client-side-cookie/ directory.
- Profit!
Problems:
- This can’t be relied on for security or privacy purposes not to send the data to server. The user could purge their browser cache, do a hard refresh on the file, etc.
- Even a far-future Expires header will expire eventually - and browsers may limit the length of Expires headers.
- So you should be prepared for the event that this data might, albeit very infrequently, get sent to the server.
- You are still limited to approx 4k per cookie (including key and value - google for detail on precisely what is supported cross-browser but it is at least very close to 4k)
- You are limited to 20 cookies per domain (in older IE versions at least, others allow more)
- So that caps it overall at about 80k, with some fiddling around to distribute the data between 20 separate cookies. Still, not to be sneezed at!
Just incase anyone else runs into this and Googles.
If you have a flash movie which mysteriously seems to reload itself during some fairly innocuous and un-connected Javascript execution - take note:
Dynamically setting document.body.style.background was the culprit for us. Don’t ask how I managed to identify this as the culprit, suffice to say it involved a lot of logging statements and patience. Doing this immediately caused the flash movie to reload itself, causing havoc in our case as we use it to play music and connect to a socket server.
You may find, like us, that setting separate background properties, eg document.body.style.backgroundImage, worked around the issue.
Anyone hazard a guess as to why the Flash runtime feels the need to implement this behaviour? Perhaps something related to wmode=transparent? (although we’re not using it)
We Playlouder developers are constantly working to improve our users experience of our product, and the regular activity of making hot drinks is often an unnecessary distraction from this. While we’ve certainly made great reductions in our refreshment-preparation time (I for instance discovered that the time it takes for a cup of tea to steep is the same as the time it takes to smoke a cigarette, so the two tasks can be run in parallel for greater efficiency), there’s still a lot of unnecessary to-and-fro-ing betweeen the Playlouder office and the kitchen when one forgets a colleagues hot drink preferences that could be factored out.
Therefore, in an attempt to maximise the amount of time available to us to bring you more exciting social-music-discovery tools (And in tribute to the wonderful Indexed), Myself and Matt both attempted to improve the efficiency of the tea-making process through the power of maths:
My attempt:

Matt’s Attempt: (Slightly simplified - as he points out, we really need a third dimension for ‘amount of tea’ as Matt doesn’t drink tea at all. He has an espresso machine on his desk, though, for the ultimate in caffeine-provision efficiency.)

Recently I’ve been working on a framework called ‘Brix’, which may interest those who saw my rather hastily-prepared LRUG talk last year. It’s another Ruby web framework - I know, I know - why yet another? Here’s an idea of the philosophy:
- Ruby needs a component-based web framework, to compete with the likes Tapestry, Seaside and WebObjects
- Separation, composability and loose coupling of components are more important for agile application development, than rigid separation of View and Controller
- Components have lives on the client-side as well as the server side, and the server-side needs to handle javascript and css includes, and the instantiation of client-side javascript objects, with the minimum of hassle. The client-side widget tree, in turn, needs to know how to update itself and manage its state.
-
- Components take parameters. Components may be nested inside other components. Components may be requested on their own (an Ajax update?) or as part of a bigger component tree. This has big implications for the routing component of a framework.
- Trying to adhere too religiously to what is typically a muddled interpretation of MVC, is often counter-productive
- REST is wonderful for APIs, but it is the wrong paradigm for modular web application user interfaces in general. (It copes OK for a CRUD-style UI structure which is closely coupled to the data model, but this isn’t typical of more dynamic web applications in my experience)
- The back button, and bookmarking, need to work!
- It would be nice if Google can spider the application, in addition to DHTML clients
The good news is that I’ve found that it’s been relatively easy to get started on, thanks to some of the great tools the Ruby community already has available. I’m only reinventing the parts of the wheel that were creaking badly - for the rest, I’m relying on:
- Haml (take the hour’s time to learn this, it’s really clean, and especially well suited to programmatic generation of small chunks of DOM tree)
- Rack ontop of Mongrel
- ActiveSupport
- for the time being, ActiveRecord (this is due for the chop once I find something closer to the relational model, or heck, something which can do Class Table Inheritance in something resembling an elegant fashion)
- Bits cheekily stolen from Merb. I was close to building this entirely ontop of Merb, but I ran into some nasty segfaults on Leopard, it didn’t seem to play well with ActiveSupport, its Router would have needed replacing, and Merb’s controllers, while more lightweight than rails, still got in the way of entirely component-based dispatch. But I’m still really impressed with Merb - It’s like Rails done right - leaner, faster, without the cruft, and with the benefit of hindsight. Easier to extend, too.)
Thanks to everyone who made it along to last Monday’s LRUG talk.
For those who didn’t, I’ve attached my slides [pdf]
A new Damascu Bite opened on Brick lane. They do rather tasty Syrian food. More amusingly though, their take-away menu features:
Mix Yalanjy (Staffed vine leafs, Baby corrugate, Baby aborigine)
Good news if you’ve been waiting years for the chance to tuck into minature native Australians…
In case anyone else runs into this:
Safari 2 will not return any innerText for an element which is display: none. Safari 3, however, has fixed this bug, which made it hard to track down after the Safari 3 beta install replaced my old copy of Safari 2.
I’ve now gotten the two running in parallel though - follow the instructions here and follow to the letter, including all the renaming. I found that unless I copied the old backed-up Safari to /Applications with the name Safari.app, there were some nasty issues with other apps loading the Webkit framework from the wrong place. In particular Drosera wouldn’t start, trying to use the old Webkit framework that was copied into the bastardized Webkit install, even when I overrode its DYLD_FRAMEWORK_PATH manually to use Safari 3’s. No Drosera rather defeats the whole point of having Safari 3 for me, so yeah. Watch out!