In a little wiki I’ve been playing with I’ve been trying out little ideas that I’ve had but haven’t had a place to actually implement them. One is how notification messages work. I’m sure other people have done the same thing, but I thought I’d describe it anyway.
A common pattern is to accept a POST request and then redirect the user to some page, setting a status message. Typically the status message is either set in a cookie or in the session, then the standard template for the application has some code to check for a message and display it.
The problem with this is that this breaks all caching — at any time any page can have some message injected into it, basically for no reason at all. So I thought: why not do the whole thing in Javascript? The server will set a cookie, but only Javascript will read it.
The code goes like this; on the server (easily translated into any framework):
resp.set_cookie('flash_message', urllib.quote(msg))
I quote the message because it can contain characters unsafe for cookies, and URL quoting is a particularly easy quoting to apply.
Then I have this Javascript (using jQuery):
$(function () {
// Anything in $(function...) is run on page load
var flashMsg = readCookie('flash_message');
if (flashMsg) {
flashMsg = unescape(flashMsg);
var el = $('<div id="flash-message">'+
'<div id="flash-message-close">'+
'<a title="dismiss this message" '+
'id="flash-message-button" href="#">X</a></div>'+
flashMsg + '</div>');
$('a#flash-message-button', el).bind(
'click', function () {
$(this.parentNode.parentNode).remove();
});
$('#body').prepend(el);
eraseCookie('flash_message');
}
});
Note that I’ve decided to treat the flash message as HTML. I don’t see a strong risk of injection attack in this case, though I must admit I’m a little unclear about what the normal policies are for cross-domain cookie setting.
I use these cookie functions because oddly I can’t find cookie handling functions in jQuery. It’s always weird to me how primitive document.cookie is. Anyway, CSS looks like this:
#flash-message {
margin: 0.5em;
border: 2px solid #000;
background-color: #9f9;
-moz-border-radius: 4px;
text-align: center;
}
#flash-message-close {
float: right;
font-size: 70%;
margin: 2px;
}
a#flash-message-button {
text-decoration: none;
color: #000;
border: 1px solid #9f9;
}
a#flash-message-button:hover {
border: 1px solid #000;
background-color: #009;
color: #fff;
}
This doesn’t have non-Javascript fallback, but I think that’s okay. This isn’t something that a spider would ever see (since spiders shouldn’t be submitting forms that result in update messages). Accessible browsers generally implement Javascript so that’s also not particularly a problem, though there may be additional hints I could give in CSS or Javascript to help make this more readable (if there’s a message, it should probably be the first thing read on the page).
Another common component of pages that varies separate from the page itself is logged-in status, but that’s more heavily connected to your application. Get both into Javascript and you might be able to turn caching way up on a lot of your pages.
Automatically generated list of related posts:
- Javascript on the server AND the client is not a big deal All the cool kids love Node.js. I’ve used it a...
- Atompub & OpenID One of the thinmgs I would like to do is...
Hi Ian,
Cookie handling in JQuery is handled through a plugin. In the past, I’ve used this one with success: http://plugins.jquery.com/project/Cookie
I have been trying to solve this in my current Django project in strange ways. This one is obvious and easy… Thanks a lot.
This technique works very well. I’ve been using it in some personal projects for a while. A few years ago my friend Kragen blew my mind by putting forth the opinion that web applications will someday have no server-side code execution at all. I’ve increasingly been of the opinion that web applications should be entirely static files plus requests for JSON (or XML or whatever) documents via Javascript, although I think it will still be quite a while before the world is ready for this approach.
I even did an experimental templating library in Javascript a while back.
Ian, spiders and “accessible” browsers aren’t the only ones with javascript potentially disabled. Anybody surfing with [NoScript](http://noscript.net/) (the third most popular FF extension behind Adblock and Video Download Helper) too, it defaults to (a very sensible) “default untrust” disabling JS everywhere. I use it and I only whitelist (completely) the websites I frequent often and when javascript brings some definite improvements.
Most websites I visit are never whitelisted, and never see their JS executed.
Note: I said “accessible” browsers usually HAVE JAVASCRIPT ENABLED.
Perhaps people who use this should add:
Then at least if you have the option to turn on Javascript, you’ll know that it’ll help. For the application I’ve been making it would not work well without Javascript (though for reading the wiki it wouldn’t matter, only for editing content).
This is one of those techniques you look at and say, “Why didn’t I think of that?” I may just use it. Status messages aren’t usually critical, so I think it could be justified to use this in certain environments despite the lack of accessibility for folks w/out JavaScript (which in addition to the other cases discussed above includes many mobile clients).
I still stick to the premise that applications should be usable without JavaScript, but usability enhanced when you ARE using JavaScript. Unfortunately I’d rate this kind of status message as something that is required to make the site usable at all. I’d love a better solution to this problem though.
On principle I used to feel strongly that applications shouldn’t require Javascript. Then at some time I realized it was just principle, and not real reasons, so I’ve become much more lax. As a reader you should never need Javascript, but as a writer (i.e., editor, commenter, interacter) I don’t see the motivation anymore.
“”" As a reader you should never need Javascript, but as a writer (i.e., editor, commenter, interacter) I don’t see the motivation anymore. “”"
OTHO, using “whole page” caching on the writer interface seems a bit weird. There might indeed be the case of a post handler redirecting to the reader interface after a successfull modification (edit, comment, whatever), but then you obviously want to invalidate the cache to take the modification into account.
This being said, I’m not personnaly dogmatic on “requiring javascript” or not, nor on how to best use it – it really depends on the kind of application and the target audience. So I wouldn’t comment on your design decision to use js for notification here – I just don’t have enough context !-)
@donovan
you should check out jugl for templating or the javascript db written in javascript. ok… it’s still server side.
re: about how sites should work with javascript
I think this is what separates web applications from websites (or maybe a particular kind of web application from websites in general).
It’s a bit like saying “All gui applications should have a command line interface that is as good as the gui or I’m going home”. especially in the mobile realm, this simply doesn’t make any sense at all anymore.
for better or worse, people are building web application and sometimes even browser implementations for solving specific problems with almost no or severely circumscribed regard to cross browser compatibility. For web sites this would be inaccessible and flippant.
But for web applications, the audience is the market, not the browser. Javascript is being allowed to access some seriously deep things that html and form encoding can’t touch. combined with html5 persistence, and literally the web application is nothing but an easily updatable set of instructions.
In the past I’ve handled flash messages and caching by not caching the whole page, just segments / data. The result was any cached url still contained some minimal business logic. This approach allowed me to display dynamic user data and still have the main database heavy content cached. The benefits of this are its accessible.
In fact the only data I returned from the database when I hit a cached page was the users session data. This provided me an easy way to have dynamic content such as logged in status, flash messages and still have the benefits of a cache.
Ummm, I don’t get it. If you use cookies for this sort of message-passing, what happens if the user has two windows open? I can see all sorts of race conditions happening this way. And since we’re talking Internet, with unpredictable packet drops and reordering, it’s not so unlikely to happen (think about mobile or third-world countries).
Example:
It’s not clear to me whether the onload check happens for every page or just for /c. But even in the latter case, the race is still possible.
Hi Ian,
Just a quick FYI. I’ve implemented a small python module + js code for TG2 heavily inspired by this article (http://pypi.python.org/pypi/WebFlash/). If using python 2.6 it has no dependency outside the stdlib (else simplejson), JS part has no dependency at all. Thanks for the inspiration!
Alberto
Why not add an accessible iframe?
eg
where /show-flash is uncached and reads the cookie through HTTP.
Sorry that should be
<noscript> <iframe src=”/show-flash” /> </noscript>