Modal Dialog JQuery Plugin

This has been a while coming, but I made a little “yet another modal dialog lightbox JQuery plugin” thing this week.

Demo and Download for Modal Dialog – JQuery Plugin

It was driven by TiddlyDocs, but I’ve been wanting one anyway for a while. Mostly because lightbox libraries generally do some hocus-pocus on page load, like applying to everything marked rel=”lightbox”, but don’t let you dynamically produce the lightbox yourself. That’s fine for pages that are just a static image gallery, but not useful to someone building a dynamic web app.

I’ve subsequently used nyromodal, on good advice, but wanted something smalller and with a simple API for my main use case, which is just showing some text.

The plugin also simplifies work by not requiring you to install a separate CSS file. Doing that, and linking to it, as well as installing any images, is something that always slows me down when I want to start using a graphical client. In keeping with the “happy path” You-Aint-Gonna-Need-It (YAGNI) mantra, I’d rather keep a library to a single Javascript file – be evil and do styling in the library by default, but still support users who want to put custom CSS in a stylesheet.

Towards A Single Page Application Framework

Tonight, I was thinking of making a Twitter app to manage my various accounts (I have ~dormant accounts related to projects like @webwait and @listoftweets). The app would be holding username and password details for each of these accounts, so it made sense to build it as a Single Page Application (SPA). This way, a more paranoid user could always keep the app in their local file system, while a less paranoid user could always stick the file on a protected server somewhere, having configured all the username-password details.

TiddlyWiki is a framework for developing SPAs. One might say it’s the framework for developing SPAs, since there are no prominent alternatives. So my obvious choice was a TiddlyWiki. However, not too long ago, the TiddlyWiki core guys extracted out the secret sauce for SPAs: the ingenius bit of code that saves files without requiring any browser extensions. (I’ve tried to explain this to people and it always leaves even the most brilliant minds a little dumbstruck, but yes TiddlyWiki demonstrates there are pragmatic hacks that can be used to read a file into the browser and then write it out again.) I was keen to explore this saving mechanism, so experimentation ensued.

The file management techniques ship conveniently in a JQuery plugin, jQuery.twFile. There is a basic demo which lets you edit the entire text and save it. The demo confused me at first – because it was editing the entire body of the file, I wasn’t sure how to translate that info into what I, as an application developer needed. The demo is useful for framework developers understanding the plugin, but less so for application developers. So I extracted it into a demo that is still minimalistic, but closer to the kind of thing you’d do in an application.

The SPA demo is here.

Once I did that, I realised what’s required is a SPA framework. In practice, most developers using twFile will be keeping all the HTML, CSS, and Javascript in a single file, so it’s possible to build a higher-level abstraction on twFile, so that developers can focus only on the content. I built the demo in a way that distinguished what was boilerplate framework code and what was application-specific HTML, CSS, and Javascript.

It was all still in one file, and that’s fine for many developers – you can give the developer the file, tell them “edit these bits”, and they can come up with something functional. I decided to extract things further though, and found the Jinja templating framework to be useful here. Jinja has a concept of template inheritance, so you can easily build up an “include” system. The net effect is I was able to encapsulate SPA logic in a single file, which was passed through a Jinja processor to produce the executable HTML document.

The basic SPA logic is shown below:

  1. {% extends "spa-template.html" %}
  2. {% block title %}JQuery SPA demo{% endblock %}
  3. {% block css %}
  4.   etc etc
  5.   body { background: black; padding: 0; margin: 0; font-family: Gill Sans, sans-serif; }
  6.   h1 { background: white; color: black; padding: 10px 10px 0; margin: 0; height: 52px; }
  7. {% endblock %}
  8. {% block html %}
  9.   <h1>
  10.   <img id="logo" src="data:image/jpeg,%FFetc etc"/>
  11.     <span id="title">JQuery-SPA Demo</span>
  12.   </h1>
  13.  
  14.   <div id="main">
  15.  
  16.     <ol>
  17.       <li>Save this file to your local file system and open your local copy in the browser (using a file:/// URI). The browser might ask for special permission for this document, and you will need to grant it.</li>
  18.  
  19.       <li>Type your message: <input id="message" value="change me"></input></li>
  20.  
  21.       <li>Save this page: <input id="saveButton" value="Save" type="button"></li>
  22.  
  23.       <li>Hit shift-reload to perform a clean reload the page and observe that your message has been saved.</li>
  24.     </ol>
  25.  
  26.     <h3>What is this?</h3>
  27.  
  28.     <p>This is a demo of an experimental Single Page Application I am building atop <a href="http://jquery.tiddlywiki.org/twFile.html">jQuery.twFile</a>, the file saving plugin extracted from TiddlyWiki. Forked from <a href="http://jquery.tiddlywiki.org/twFileDemo.html">this twFile Demo</a>. Only tested on Firefox for now.</p>
  29.  
  30.   </div>
  31. {% endblock %}
  32. {% block javascript %}
  33.     $.spa.save = function(text) {
  34.       return text.replace(/<input id="message".*?></input>/,
  35.               '<input id="message" value="'+$("#message").val()+'"></input>');
  36.     }
  37. {% endblock %}

So it contains separate HTML/CSS/Javascript blocks. Probably not a good engineering practice (though it doesn’t impact on the end-user experience, which is always a single file), but it’s convenient for now. The key SPA logic is here:

  1. <li>Type your message: <input id="message" value="change me"></input></li>
  2.       ....
  3.     $.spa.save = function(text) {
  4.       return text.replace(/<input id="message".*?></input>/,
  5.               '<input id="message" value="'+$("#message").val()+'"></input>');
  6.     }

As an app developer, all you have to do is override $.spa.save (which in retrospect should be renamed as it doesn’t actually perform the save). This function receives the text of the file as it was stored on disk when the page loaded. It must then return the text that should be saved to disk. Thus, it must store application state in HTML, probably by performing some kind of substitution.

Having put this together, I’m keen to proceed with the envisioned Twitter app. It’s not yet clear if there’s any mileage here over a regular TiddlyWiki, but as someone who is more familiar with starting apps from a blank HTML page (or a simple Project Deploy* template), it might end up being a more familiar way to kick an app off. Watch this space.

ColourLovers API – JSON Demos

About a year ago, I was excited to discover ColourLovers had an API. There is some great data about colours and palettes on that site, and some great possibilities for mashups – some as general-purpose art projects, and some as tools for designers.

However, I noticed there was no JSON-P interface, so there was no way to write a pure browser-based mashup. I got in touch with them, and heard back from Chris Williams, who to my pleasant surprise was willing to introduce JSON-P. And so we had some email discussion about the various options for the API interface (e.g. do you call it “jsonp” versus “callback”; do you use “real JSONP” versus just a callback function; do you hardcode the name of the callback function versus let the caller specify it as a parameter), and ultimately Chris went ahead and implemented it a short time later and published the API on January 26, 2009. Fantastic!

I offered to make some demos illustrating code usage, and did around that time, but never got around to publishing them until now. I’ve released the demos here. There’s a couple of JQuery demos, and one raw Javascript demo. I had fun making them and have plans to do a lot more with this API.

WebWait Two Point Oh

I’m pleased to announce a major upgrade to WebWait, the first big upgrade since I launched the site 2.5 years ago. It’s based on watching how people are using it, talking about it, and sending me direct feedback about it. Thanks to all who have provided feedback.

The new features are:

  • Multiple sites You can keep typing in new URLs and hitting “Add”. This will put them in a queue of sites to eventually be benchmarked. (I decided against a big textarea where you could type in all URLs at once; this would be confusing to the majority of WebWait users, who are casual visitors wanting to check out the time for their own site.)
  • Stats Average, median, and standard deviation for each website, in a summary table. Indeed, the summary table is the cultural centre for all these new features – when you queue up a site, it’s immediately added to the table.
  • Export The export feature seems to be popular in List Of Tweets. I took the same UI concept and applied it here, so you can export data in plain text, HTML, and CSV format. The CSV is especially interesting as one of the people who’ve given me feedback is a statistician who’s planning to run analysis on some data.
  • Call Data View times for each individual call.
  • Expand/Collapse Call Data You can choose whether to show call data or not. Collapsing call data gives you a neat overview of stats for each domain.
  • Delete You can delete individual call data, or delete an entire website record. This is useful for outlier data; for example, you can see how fast the site loads from your browser cache, by turning browser cache on and deleting just the first call in the sequence.
  • Stats Average, median, and standard deviation for each website.
  • Browser compatibility. WebWait didn’t work upon launch in Safari, but it does now work in recent versions of Safari (I think a change in 3.0 made it work again :)), and works fine in Chrome too. This is important for users testing how their website loads in different browsers.

Thanks for reading. As always, let us know what you think of the site and anything else you’d like to see.

Table with expanded results:

Table with collapsed results:

Export results data (text):

Export results data (HTML):

Export results data (CSV):

Scrumptious Update: Open ID Support, UI Enhancements

I’ve released a new version of Scrumptious. Main change is it now supports Open ID. You can click a “login” link to comment by Open ID. It’s optional by default, though a Scrumptious site operator could easily make it mandatory for read, write, or both by just changing a couple of words in the “policy” config files. Similar to other CMSs like WordPress, non logged in users can indicate their name and URL when they submit a comment.

There are also UI enhancements – the design is cleaner and looks closer to the original original TiddlyWiki comments plugin. Interestingly, I retained almost identical markup, so I was able to cut-and-paste the original CSS for the comments plugin and it mostly worked. I also now include the default TiddlyWiki stylesheets as well. It’s not just look-and-feel which is closer to the original plugin, but the content – you now have info like modifier, modified date, and a permalink available.

I also added something I always wanted to add on the original plugin, which is some animation, e.g. when you add a new reply, the page scrolls to that reply, and a yellow fade effect highlights it. This is a genuinely useful feature as I was finding it difficult to see which reply I’d just added, when there are a lot of comments around.

I’ve also begun work on a Comments Report showing recent comments. Obvious related enhancement is to take the TiddlyWeb Atom plugin and make a comments feed.

Right now, all this is only tested on Firefox (the original was tested on all browsers, at least the full website view); my next priority is to work on browser compatibility, and after that, extract a modular JQuery comments plugin.

Implementation Notes

Regarding the implementation, TiddlyWeb ships with Open ID by default (Open ID is one of two default challengers, the other being the usual simple user-pass key pair config). The most challenging thing here was getting the UI right for both anonymous users and logged in users, as well as handling a redirect in the popup after a successful login; but at the back end, Open ID “just works”.

In summary, I added Open ID support as follows:

  • Add a “login” link to the TiddlyWeb OpenID challenger UI, using a “target” attribute so the challenger opens in a popup.
  • The challenger URL in that link also contains a redirect param, which I redirected to a new static page. This static page shows the user their login ID (by inspecting the “tiddlyweb_user” cookie value), calls a callback “onLogin” method on the original page, and closes itself.
  • The “onLogin” callback updates the login display to show the logged in user and a logout link; the logout link simply runs some Javascript to remove the cookie. The callback also updates any forms that are open prompting for bio info; it hides this info and in its place, shows the current user ID (read-only).

Thanks to Ben and Chris for pointing me in the right direction on TiddlyWeb’s Open ID support.

PS I discovered late in the day (literally) that TiddlyWeb lets the client specify whatever modifier they want

Scrumptious: Conversations About Websites (and other resources)

Scrumptious is a web framework I’ve begun working on at Osmosoft. It’s a web app and web service for sharing bookmarks and comments about websites, and pretty much anything else with a unique URL. Things it is related to: Delicious (bookmarking), Digg (threaded comments), JS-Kit and Disqus (embedded comments with common identity across multiple sites).

Scrumptious is open source, under the BSD license (meaning you can do just about anything you like with it). There are already many open-source clones of this sort of thing, so why make a new one? There are a few reasons:

  • Adherence to RESTful principles – Scrumptious is backed by TiddlyWeb, a RESTful data service.
  • A non-TiddlyWiki TiddlyWeb client – So far, people who have used TiddlyWeb as a server have used TiddlyWiki as a client. They do play nicely together, but TiddlyWeb is a powerful RESTful framework on its own. Part of the motivation for Scrumptious was to port the TiddlyWiki nest comments plugin to a generic JQuery plugin that could be used on any web page. (Comments are indeed implemented as a plugin right now, but more work needs to be done to extract it into something truly modular and reusable; for example, the plugin right now assumes comments are about a web page; also, they are tied to TiddlyWeb. Nevertheless, the app still does achieve the main purpose of demonstrating TiddlyWeb is a fine data service for generic web apps.)
  • Demonstrating the power of URLs – In evangelising web standards, a very practical piece of advice is simply to associate a unique URL with each distinct resource. That’s REST 101, but it’s something lacking in many web apps. With a tool like Scrumptious, you get a comment system “for free” as long as each resource in your system has a unique URL. We’ll be developing a similar framework for URL Trails in the future, and the same principle applies: use unique URLs, and people can put your stuff in trails “for free”.
  • Flexible security model – Again, TiddlyWeb offers flexible permissioning, so you can use the app in different ways. e.g. a private conversation between colleagues; a public conversation (as with the demo), a publicly readable conversation where only certain individuals can contribute, etc. Likewise, TiddlyWeb offers flexible authentication, so you could hook into an organisation’s LDAP system, use open ID, simple user-password pairs, or any other form of authentication you wish to use.

Scrumptious is still at an early stage. Future work includes:

  • Bookmarking – for now, there is only commenting rather than social bookmarking per se.
  • Nested comments UI needs work to give it the same kind of UI as in the TiddlyWiki comments UI. e.g. show info like creator and creation data, and use suitable rendering and indenting.
  • Graceful degradation – It would be possible to provide a basic system not requiring Javascript. This would be probably be done using TiddlyWeb plugins, though I’d also be interested in running the JQuery-powered web app on the server, using server-side Javascript.
  • TiddlyWiki comments plugin harmonisation – As TiddlyWiki now ships with JQuery, it would be ideal if there was a single code base for the comments plugin, running in and out of TiddlyWiki. Indeed, I hope TiddlyWiki moves towards a general microkernel architecture, in which all plugins are useful outside TiddlyWiki. This is certainly becoming the case, with generic JQuery plugins being extracted for core activities like file saving, CSS applying, and wikifying.
  • Browser extensions – instead of a bookmarklet, use a browser extension to show, for each page, if comments are available, as well as bookmarking info. (Similar to the StumbleUpon or Delicious Firefox extensions.) A good opportunity to get my hands dirty with JetPack.
  • Login and identity management – while TiddlyWeb already provides the security and permissioning model, work is required to handle this at the UI level. For example, let anonymous users enter their email address and homepage, and/or register.
  • User admin – for situations where users must be authenticated, some form of user management would be handy. Again, TiddlyWeb provides a good model for this – a “bag” of tiddlers has its permission specified in JSON, which may include a list of users for each access type, so you simply need to PUT and GET this if you are sufficiently permissioned (ie an admin). What’s missing right now is a UI (in TiddlyWiki too, let alone standalone web apps).

Scrumptious Screencast:

<

p>Scrumptious from Michael Mahemoff on Vimeo.

What’s the Maximum Z-Index?

Z-index is the CSS property governing how high in the stack an element is, if you visualise the elements as appearing in a 3D stack coming out of the page. The actual value of an element’s z-index doesn’t matter; just its value relative to other elements on the page. Elements with higher z-indexes appear on top of elements of lower z-indexes.

I was just designing a bookmark for Scrumptious (a TiddlyWeb powered tool to have discussions around websites; I’ll talk about it in a future article). And with a bookmarklet, I need it to appear above everything else on the page. So it needs a higher z-index than everything else. Maybe not the highest z-index possible, since there might be apps that need to sit above my app’s bookmarklet (Design For Extensibility). But I still need to know the maximum z-index.

It would be nice if the standards publshed the maximum allowed z-index. Every reference always makes a comment like “there’s no real limit”. For good reason too, since the W3C standards don’t really cover this. The CSS Spec (2.1) goes so far as to include an “Elaborate description of Stacking Contexts”, and it’s even called “zindex.html”, but even here, omits to pin down the max z-index value.

A handy summary was stated on StackOverflow (which has fast become the central resource for programming FAQs and a site I have quickly come to adore for its clear mission, clean design, and community feel):

So basically there are no limitations for z-index value in the CSS standard, but I guess most browsers limit it to signed 32-bit values (−2147483648 to +2147483647) in practice (64 would be a little off the top, and it doesn’t make sense to use anything less than 32 bits these days)

Looking further, I came across the most comprehensive summary of the situation, published recently. It also highlights the fact that it’s not just the maximum value we want, but what happens if we exceed it.

I made a simple test page to find these limits and figure out what happens when you exceed them.

Browser Max z-index value When exceeded, value changes to:
Internet Explorer 6 2147483647 2147483647
Internet Explorer 7 2147483647 2147483647
Internet Explorer 8 2147483647 2147483647
Firefox 2 2147483647 *element disappears*
Firefox 3 2147483647 0
Safari 3 16777271 16777271
Safari 4 2147483647 2147483647
Opera 9 2147483647 2147483647

So the best way would be to use browser detection and pick the max from there. But if not, use 2147483647.

Google IO Keynote, 2009

I’m here at Google’s London office, where they’re streaming the IO keynote.

Eric Schmidt talks about Ajax, always-on, simplicity, and how it’s improved life.

Vic Gundotra’s on. We spent too long not fully using XML, CSS, etc., i.e mid-late ’90s they were there, but really started using them to the max around ~2005. Let’s not wait so long for the current technologies.

Now we’re talking about five things that excite Google. (He doesn’t identify the 5 things.)

Canvas. Includes a demo of Bespin – nice one Dion, Ben, and Joe :).

3d graphics – keen to work with people on APIs for this. Good demo, but it’s a plugin, so still needs work!

Video. Shows YouTube.

Address from Firefox VP.

Firefox 3.5. As well as canvas and video, …

Great performance boosts since 3.0 and ?10 times since 2.0.

Support for Geo-Location.

Support for offline.

Support for web workers.

A geo-location demo. Browser gathers signal strengths of nearby hotspots and worked out lat/longs. If cellphone, towers. Or GPS if it’s there. Users will be able to download add-ons to choose the functionality. (Very Fire Eagle).

Back to Vic

And Apple have also implemented W3C Location API, so it’s there in Google Maps on iPhone 3.0 OS.

Demo-ing a simple offline app, and then showing GMail on Android and iPhone, Google’s first major HTML 5 app.

Palm Address

Michael ?? from Palm. Showing how HTML5 is used – e.g. CSS transformations for animation.

Shake, orientation, acceleration – all these are available in Javascript in Palm…and would like to see them introduced to HTML5. window.addEventListener("shakestart", beginShaking, true);

Back to Vic

Talking about performance – impressive web workers demo. Followed by a more impressive demo of motion detection within Javascript, analysing a video.

App Engine and GWT Talks

Meh

Google Web Elements

Inspired by embedding videos etc.

It’s bascally widgets 12.0. Just a much cleaner way of grabbing gadgets and putting them on your page – get some cut and paste HTML, which is an iframe rather than the usual script tag.

Ready now at http://www.google.com/webelements

I’ll embed one here:

Text-To-Speech API

As part of Android, there will be an open source text-to-speech available. (How about a public one for any web developer?)

Fin

He gives away 4000 Android phones, one per person. In London, we get pizza and soft drinks. But then, a small detail – the SF attendees actually paid for to be there! We just left the St James office and rocked up, so a decent event all things considered. Thanks to Google for hosting it and hopefully the same next year.

The URL Shortener as a Cloud Database

On URL Shorteners

URL shorteners are enjoying their 15 minutes of fame right now. They’ve been around since 2002, but became flavour of the month as soon as half of the planet decided to compress their messages into pithy 140-character microblogs, and there is money in it, driving a massive amount of new players into the market, which will ultimately lead to a massive amount of URL shortener induced linkrot. [Update Dec 2011 – I note that the URL shortener I used for a while, 3.ly, is now indeed linkrot :(.]

In passing, I will note the irony that long domain names were the flavour of the month a year ago. Although, maybe it’s not so ironic, since they enjoy a symbiotic relationship with the URL shorteners when you think about it.

Now, I recently realised that URL shorteners could be used as a form of cloud database. The URL is a form of data. And the interesting thing about this is that they form a cloud database that can be accessed from any Ajax app, because they (a) can be created anonymously; (b) offer JSONP APIs, in some cases (and with third-party bootleg APIs available in others); (c) allow you to store relatively long strings. Before you can say, “violation of Terms and Conditions”, I will get to that later on.

Character Limits

On (c), just how long can these URLs be? I did a little digging – gave them some huge URLs to convert using just the homepage of each service. I chose the top services from Tweetmeme’s recent study, minus friendfeed’s internal shortener, to come up with the four most popular services – tinyurl.com, bit.ly (my candidate for the first URL shortener to appear on the cover of Rolling Stone magazine, in case you ever doubted a URL shortener could be the in thing), is.gd (the one I’ve been using since it was a wee thing spouting three-character shortcuts), and tweetburner aka trurl.nl.

I was expecting them all to truncate at around 2083 characters, the traditional limit for IE. Boy, was I wrong!

I started playing around adding really long URLs, and playing a “Price Is Right” higher, higher, lower, higher game until I found out roughly the capacity of each.

Note that Bit.ly and Twurl.nl both give the impression they are storing more than their limits, i.e. they don’t show an error message, but instead they silently truncate the URL. Is.Gd does the right thing by telling you what it’s done. Although, the limits are weird – you would think they’d go for IE’s 2083 character limit, or be all binary and go for 2048, rather than cutting off at 2000. I guess 2000 is a simpler number to tell humans about.

So the most interesting one here is TinyURL. However, the actual underlying URL doesn’t work for some reason – the most characters I found that would work was 8192. However, the entire URL is stored, as you can see at the preview page.

A Legitimate, Related, Use: Shortening an Ajax Unique URL (with Fragment ID Reflecting App State)

The thought of using URL shorteners might sound crazy, useless, and a violation of terms, but it came to me for an entirely legitimate application, which is well within the T’s and C’s I believe. I’m creating a web app right now (very incomplete) where the entire state is captured in the URL. (see Unique URL. This saves me from having to set up any storage and (in some respects) makes life easier for users, who don’t to manage yet another account, log in, etc etc. It certainly lowers the barriers for new users if they don’t have to register in order to save things.

Saving the entire state in a URL can lead to a long URL. So with all the hype around URL shorteners, I figured why don’t I just let the user save it to a short URL, if they do prefer a short URL for mailing or writing down, or memorising (since some of these services let you specify the key). And so I might choose to build into the app a little “get short URL for bookmarking and tweeting” button. (Funnily enough, I would have previously called it “bookmark this”, but that would mislead users into thinking that the long URL on top isn’t actually a valid bookmark. Now that everyone understands URL shorteners, I can be more explicit about the button’s purpose.)

The short URL is effectively a holder of the entire state of this user’s application. In fact, this seems like an entirely valid reason to use a URL shortener, so I doubt it’s a violation of anyone’s terms. Worth noting incidentally that there are plenty of free images where you can anonymously upload 100K or more, so I doubt a 10K URL is a big deal; and given that the service receives link love and some useful tracking data, it’s probably just as valuable financially as an image sent to an image host.

A Pure Cloud Database

You can see where this is going. An extension to this thought is to simply treat the URL shorteners as cloud databases. As long as it looks like a valid URL, you could store whatever you like there. Turns out you can even store an image or a short MP3 as a data:// URI. I have no plans to do this, and I suppose it actually would be a violation of terms in this case, but it’s an interesting idea.

And if the URL was too long, you could always use a linked list structure —- break it up into several short URLs, with the last few characters of each source URL pointing the previous short URL. (it’s backwards since you can then be sure what URL was allocated, and you would distribute the last URL in the series).

  • http://tinyurl.com/mark3 end of the message mark2 (this is the URL you distribute)
  • http://tinyurl.com/mark2 middle of the message mark1
  • http://tinyurl.com/mark1 end of the message

There is actually prior art on this concept, I discovered – some anon poster recently created a proof-of-concept cloud DB, with encryption to boot. There were no replies to that post and it seems to have gone unnoticed, which is unfortunate. So allow me to dig it out:

In almost obvious violation of their terms of service (maybe not entirely, they technically are urls, just with random data tacked onto it.) I’ve created a way to securely store arbitrarily length data on URL shortening services like tr.im, bit.ly, tinyurl, etc.

You have to pass both the message and a key. The key is SHA-1’d and then the message is encryped with the key by AES-256. The message is split to 200 byte chunks and it loops through them. For each one, a special salt variable exists for no particular reason, is mixed with the key and a packet identifier number (part 0 = 0, part 1 = 1, so amazingly complex) and all of that is again SHA-1’d. It’s trunkated to 14 digits. The part of the data is prepended with a pseudourl. and the url is passed to the url shortener API and the 14 digit string is used as the custom short URL. The last packet is appended with a special last-packet marker.

http://jsbin.com/ixuda

As We May Think

All this makes me think what kind of JSON-based cloud services there should be on the web, that would indeed be explicitly designed for this kind of purpose and be more suited to the purpose. I bet you could build something nice along those lines with TiddlyWeb server.

The biggest restriction with all this is that the services are write-once. e.g. if you make a pretty poster, tinyurl it, and send the link, you can never change the poster someone will see when they visit that link (because the link directly represents the composition of your poster, rather than being a pointer to the composition on the server). So this heavily limits applicability of the concept anyway, but if users are willing to live with that restriction, it’s a big benefit in terms of simplicity. You could also overcome the restriction using some of the newer URL shortening services that let you log in and maintain your shortcuts. But that would (a) defeat the purpose of simplicity; (b) defeat the purpose of working in Ajax apps, since it would require privileged JSON calls, and privileged JSON calls are wildly insecure.

SVG and VML in One Chameleon File

Why a Chameleon File?

While most browsers support SVG, IE’s unique brand of interopability does not extend that far; even the latest and greatest, incarnation v. 8 of IE, has no sign of SVG. And so, we citizens of the innernets are left with two vector graphics formats: VML for IE, SVG for standards-compliant browsers, which I will simply refer to as “Firefox” for concreteness.

There are tools like Project Draw capable of rendering both SVG and VML, and there are convertors like Vector Convertor as well. You can easily end up in a situation where you have two separate files for the same image. In one’s endless quest for a simple life of zen-like existence, this is troublesome. You will have to mail the two files around or host the two files somewhere. And if someone changes one, they probably won’t bother changing the other one.

One solution would be to convert to a raster/bitmap file, i.e. GIF or PNG, which will then render fine in IE and standards-compliant browsers as well as many other places too. However, this isn’t always the best option: (a) if you want to support further editing, you will need the original vector data; (b) it won’t scale as nicely; (c) in some cases, the bitmap size is bigger by orders of magnitude.

So a colleague asked me how one could share this type of data and I got thinking about a recent experiment. I need to blog it separately, but the premise is that a single file can be different things to different people. In this case, we did some work yesterday I’ll describe here – seeing how a single file can look like VML to something that works with VML (IE) and look like SVG to something that works with SVG (Firefox et al). In the general case, I call this pattern “Chameleon File” and the particular kind of chameleon described here I call a “Vector Graphics Chameleon File”.

Demo

The demo link is below – it shows an ellipse in any browser, using either VML or SVG, whichever is supported:

http://project.mahemoff.com/vector/ellipse.xhtml

IE users are better off using http://project.mahemoff.com/vector/ellipse.html as it won’t launch automatically in IE as Windows doesn’t recognise the xhtml extension, though it will still launch once you tell windows to open it with IE. The content is the same, the URL is different. I’ll explain more below in “Limitations”.

(The example is taken from Wikipedia’s VML page.)

How?

How does it work? Let’s look at the source:

  1. <html xmlns:v="VML">
  2. <!--[if IE]>
  3. <style>v:*{behavior:url(#default#VML);position:absolute}</style>
  4. <![endif]-->
  5. <body>
  6.  <v:oval style="left:0;top:0;width:100;height:50" fillcolor="blue" stroked="f"/>
  7.   <svg xmlns="http://www.w3.org/2000/svg" width="100" height="50">
  8.     <ellipse cx="50" cy="25" rx="50" ry="25" fill="blue" stroke="none" />
  9.   </svg>
  10. </body>
  11. </html>

From Firefox’s perspective, the file is valid XHTML thanks to the .xhtml suffix, meaning that the svg tag is fair game. We use the old “if IE” comment trick to get Firefox to ignore the style rule; otherwise it will still work, but it will render the style tag’s content (this is XML, not HTML, which would have it un-rendered). It ignores the body and VML v:oval tag, and faithfully renders the SVG. In short, it does what the pure SVG does:

  1. <html xmlns:v="VML">
  2.  <style>v:*{behavior:url(#default#VML);position:absolute}</style>
  3. <body>
  4.  <v:oval style="left:0;top:0;width:100;height:50" fillcolor="blue" stroked="f"/>
  5. </body>
  6. </html>

From IE’s perspective, this is just a normal VML file with an svg tag snuck in, which thankfully for our purposes, it ignores. So IE sees the file as just regular old VML:

  1. <?xml version="1.0"?>
  2. <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
  3.  "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
  4. <svg xmlns="http://www.w3.org/2000/svg" width="100" height="50">
  5.   <ellipse cx="50" cy="25" rx="50" ry="25" fill="blue" stroke="none" />
  6. </svg>

Limitations

Limitations, I have a couple of those.

File Extensions

The extension thing is really annoying (see also here). To get SVG working in Firefox, you need Firefox to see the file as XHTML. But to get VML working in IE, IE must see it as HTML. How do you make the browser “see the file” as something? You either set the MIME type in the HTTP header, or you set the file’s extension. In this case, we’re more interested in the file extension because we want to be able to just mail the file around – in which case there is no MIME type because there’s no HTTP header because there’s no HTTP because they’re viewing it off a file:/// URL – or we want to quickly stick it on a server and not bother faffing with .htaccess-fu and MIME types.

Now that being the case, what file extensions do we need? As far as I can tell, IE must have .html or .htm for the vanilla Windows operating system to open it.

As for Firefox, Firefox needs .svg or .xml or .xhtml as far as I can tell.

The problem here is there is no overlap – IE needs .html and .htm, Firefox needs .svg, .xml, .xhtml.

skitched-20090501-101849.jpg

I spent a while trying to coerce Firefox to see a .html file as XHTML using doctype and the like, but I can’t do it – any help here would be appreciated.

The consequence is that you have several possibilities: (a) call it .xhtml/.svg/.xml – it will run on Firefox and IE users will have to “open”, “choose application”, and set IE (and they can save that setting); (b) call it .html (or .htm but that’s just silly) and tell Firefox users to rename the file; (c) distribute two copies of the same file – defeats the purpose of simplicity to some extent, but since it’s still the same file, it’s not such a big deal; you can keep working with the one file until you’re ready to distribute it. Of (a) and (b), I prefer (a) because asking someone to “open with application X” is less onerous than asking someone to rename a file, which sounds a bit odd. On the other hand, in many enterprise situations, you have to optimise around IE users, in which case (b) may well be preferable. You could probably also ship the file with a little instruction to rename the file, targeted at non-IE users using CSS/Javascript hacks, which they will see on opening the file in its HTML guise.

SVG and VML Feature Sets

I haven’t experimented much with these, but I did find a larger SVG file that didn’t work properly. I’m hoping Project Draw will introduce an easy way to render both SVG and VML for the same file, which would let me script creation of SVG-VML chameleon files for experimentation; or I might just play aronud with a converter. Any data on this would be welcome.

The Chameleon File Pattern

… is rather interesting and useful. Some interesting analogies came up in discussion – one of them was the “old woman, young woman” optical illusion. I discovered it’s called a “Boring figure” after the experimental psychologist Edwin Boring. I thought “chameleon file” sounded more appropriate than “Boring file”!

Another analogy from Paul was the Rosetta Stone – same content in a different format. I think this is a good analogy, but at the same time, I guess the pattern could be used to contain different content too. That’s more the case with the JOSH Javascript-HTML Chameleon I’ll discuss later on.

It also reminds me of Zelig, an old Woody Allen flick about a “human chameleon” who tries to be all things to all people, although I think chameleon files have more of their own unique identity.

Chamelon File is a hammer, let’s go find some nails.

Thanks to my colleagues for ideas and inspiration.