<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	>

<channel>
	<title>Graceful Exits &#187; standards</title>
	<atom:link href="http://www.jpstacey.info/blog/category/standards/www.jpstacey.info/blog/category/standards/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.jpstacey.info/blog</link>
	<description>Garbage collection, in a very real sense</description>
	<pubDate>Thu, 01 Jan 2009 23:18:29 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.6.3</generator>
	<language>en</language>
			<item>
		<title>The multiple magics of Drupal search</title>
		<link>http://www.jpstacey.info/blog/2008/12/24/the-multiple-magics-of-drupal-search/</link>
		<comments>http://www.jpstacey.info/blog/2008/12/24/the-multiple-magics-of-drupal-search/#comments</comments>
		<pubDate>Wed, 24 Dec 2008 20:02:55 +0000</pubDate>
		<dc:creator>jps</dc:creator>
		
		<category><![CDATA[framework]]></category>

		<category><![CDATA[layers]]></category>

		<category><![CDATA[standards]]></category>

		<category><![CDATA[api]]></category>

		<category><![CDATA[drupal]]></category>

		<category><![CDATA[fapi]]></category>

		<category><![CDATA[form]]></category>

		<category><![CDATA[hook]]></category>

		<category><![CDATA[hook_form_alter]]></category>

		<category><![CDATA[module]]></category>

		<category><![CDATA[redirect]]></category>

		<category><![CDATA[search]]></category>

		<category><![CDATA[submission]]></category>

		<category><![CDATA[submit]]></category>

		<category><![CDATA[validate]]></category>

		<guid isPermaLink="false">http://www.jpstacey.info/blog/?p=424</guid>
		<description><![CDATA[Form API is magical; core Drupal search is a twist on that magic; hooking onto that twist puts your code on yet another level of weird.]]></description>
			<content:encoded><![CDATA[<p>Drupal&#8217;s Form API handles so much work for you that you&#8217;d be a fool not to use it as much as possible. This code snippet:</p>
<blockquote class="code"><p>
function myform_some_form($form_state) {<br />
&nbsp;&nbsp;$form['text'] = array(<br />
&nbsp;&nbsp;&nbsp;&nbsp;&#8217;#type&#8217; => &#8216;textfield&#8217;,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&#8217;#title&#8217; => t(&#8217;Your submission&#8217;),<br />
&nbsp;&nbsp;&nbsp;&nbsp;&#8217;#default_value&#8217; => t(&#8217;Enter some text&#8217;),<br />
&nbsp;&nbsp;&nbsp;&nbsp;&#8217;#description&#8217; => t(&#8217;Please use this field to submit some text&#8217;),<br />
&nbsp;&nbsp;&nbsp;&nbsp;&#8217;#required&#8217; => TRUE,<br />
&nbsp;&nbsp;);<br />
&nbsp;&nbsp;return $form;<br />
}
</p></blockquote>
<p>creats a form with:</p>
<ul>
<li>A single <strong>textfield element</strong></li>
<li><strong>Accessible XHTML</strong> with form labels</li>
<li>Potentially <strong>localized</strong> labels, translated into any number of languages</li>
<li>A bit of similarly localized <strong>help text</strong> below the element</li>
<li><strong>Validation</strong> of the form submission, with the field content marked as required</li>
</ul>
<p>That&#8217;s a separate item of form functionality for each array key. And as long as you use Form API, Drupal handles validation and input sanitization for you, thus massively reducing the risk of attack by SQL injection or <abbr title="cross-site scripting" >XSS</abbr>. </p>
<h3>Bookmarkable search URLs with POSTed search terms</h3>
<p>But there&#8217;s a catch. To encourage best practice in terms of form submission and friendly URLs, Form API defaults to HTTP POST. If site searching used Form API (which it does) then what impact would that have? Successful searches could never be bookmarked, because the URL on its own doesn&#8217;t capture the POST submission.</p>
<p>The search module tackles this by adding an extra twist to Form API. At the end of submission processing are the following two actions:</p>
<ul>
<li>Call either the function named in <code>$form['#submit']</code> or <code>$ID_submit</code>, where <code>$ID</code> is typically the name of the original form creation function (&#8221;myform_some_form&#8221; above)</li>
<li>Finally, either return to the original action page of the form, or redirect to any URL specified in <code>$form['redirect']</code></li>
</ul>
<p>The search module therefore uses a function called <a href="http://api.drupal.org/api/function/search_form_submit" ><code>search_form_submit</code></a> to grab the POSTed search terms, and redirect the user to <code>search/$SEARCH_TYPE/$SEARCH_TERMS</code>. <code>$SEARCH_TYPE</code> is &#8220;node&#8221; for Drupal&#8217;s out-of-box textual node searching, but if you install some other search module e.g. <a href="http://lucene.apache.org/solr/" >Apache Solr</a> then it&#8217;ll be e.g. &#8220;apachesolr_search&#8221; instead. Result: bookmarkable search URLs.</p>
<h3>Writing your own module to handle searches</h3>
<p>This has important ramifications if you&#8217;re trying to piggyback off core search somehow: if, say, you&#8217;re still using core search or a third-party module for the actual result-finding, but then you want a page other than core search to display the results. </p>
<p>If you want the main site search form to redirect to your own pages, for example, then you have to (a) add your own <code>$form['#submit']</code> function to the stack and then (b) use that to change the core search&#8217;s <code>$form['redirect']</code>:</p>
<blockquote class="code"><p>
// Implementation of hook_form_alter(), adding an extra submit callback to<br />
// search forms identified by their existing callback<br />
function mysearch_form_alter(&#038;$form, $form_state, $form_id) {<br />
&nbsp;&nbsp;$submits = array(<br />
&nbsp;&nbsp;&nbsp;&nbsp;&#8217;box&#8217; => &#8217;search_box_form_submit&#8217;,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&#8217;form&#8217; => &#8217;search_form_submit&#8217;,<br />
&nbsp;&nbsp;);<br />
&nbsp;&nbsp;if (is_array($form['#submit'])) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;$which = array_intersect($submits, $form['#submit']);<br />
&nbsp;&nbsp;&nbsp;&nbsp;$which &#038;&#038; ($form['#submit'][] = &#8216;mysearch_form_mysubmit&#8217;);<br />
&nbsp;&nbsp;}<br />
}<br />
// Submit callback, which changes the redirect using a regular-expression replace<br />
function mysearch_form_mysubmit(&#038;$form, $form_state) {<br />
&nbsp;&nbsp;$form_state['redirect'] = preg_replace(&#8217;/^search\/[^\/]+/&#8217;, &#8217;search/my_special_search&#8217;,<br />
&nbsp;&nbsp;&nbsp;&nbsp;$form_state['redirect']);<br />
}
</p></blockquote>
<p>Now you&#8217;ve got all your site search forms redirecting to a bookmarkable page at <code>search/my_special_search/$SEARCH_TERMS</code>. All you have to do now is write a menu callback for that page: from here on in you&#8217;re on your own for now.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jpstacey.info/blog/2008/12/24/the-multiple-magics-of-drupal-search/feed/</wfw:commentRss>
		</item>
		<item>
		<title>UK government demonstrates lack of comprehension of web standards</title>
		<link>http://www.jpstacey.info/blog/2008/09/10/uk-government-demonstrates-lack-of-comprehension-of-web-standards/</link>
		<comments>http://www.jpstacey.info/blog/2008/09/10/uk-government-demonstrates-lack-of-comprehension-of-web-standards/#comments</comments>
		<pubDate>Wed, 10 Sep 2008 13:20:20 +0000</pubDate>
		<dc:creator>jps</dc:creator>
		
		<category><![CDATA[culture]]></category>

		<category><![CDATA[enterprise]]></category>

		<category><![CDATA[intent]]></category>

		<category><![CDATA[standards]]></category>

		<category><![CDATA[coi]]></category>

		<category><![CDATA[consultation]]></category>

		<category><![CDATA[cross-browser]]></category>

		<category><![CDATA[fail]]></category>

		<category><![CDATA[government]]></category>

		<category><![CDATA[guidelines]]></category>

		<category><![CDATA[it]]></category>

		<category><![CDATA[proposal]]></category>

		<category><![CDATA[top-down]]></category>

		<category><![CDATA[uk]]></category>

		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://www.jpstacey.info/blog/?p=205</guid>
		<description><![CDATA[Top-down-first governmental web guidelines unsurprisingly full of FAIL.]]></description>
			<content:encoded><![CDATA[<p>The UK government’s Central Office of Information (COI) has produced a <a href="http://www.coi.gov.uk/guidance.php?page=200" >draft report on governmental departments&#8217; adherence to browser standards</a> and asked for feedback. Depressingly, the report is not available in a web friendly format even though there&#8217;s no real reason for it to be only released as Word and PDF.</p>
<p>You can read <a href="http://www.webstandards.org/2008/09/08/uk-government-draft-browser-guidance-is-daft-browser-guidance/" >a breakdown of the worst bits on The Web Standards Project</a>, but here&#8217;s the feedback I just emailed <a href="mailto:webguidelines@coi.gsi.gov.uk" >webguidelines@coi.gsi.gov.uk</a>:</p>
<blockquote><p>
Hi,</p>
<p>I appreciate the COI&#8217;s desire to provide roadmaps for cross-browser support, but I&#8217;m otherwise dismayed at the recent publication&#8217;s back-to-front emphasis regarding browser standards support. It feels like the publication has been put together by people who are remote from the current thinking on web standards and how best to both promote them and take advantage of them.</p>
<p>As a web developer I&#8217;ve had a reasonable amount of experience in developing sites cross-browser, and generally the quickest and cheapest site creation (and the least patronising or inconveniencing to the eventual end users) is effected by developing first on the most standards-compliant browser available, regardless of its user base. Then, once the site is stable and well-built according to the standards (which are there for reasons other than semantic fussiness), one can use *freely* *available* frameworks to compensate for browsers which do not follow the standards (which may be more popular). It involves more effort at the start in exchange for a much smoother site construction later on.</p>
<p>Let me repeat that: building sites according to web standards, then accommodating bad browser behaviour, is CHEAPER, QUICKER and MORE ROBUST than what you implicitly propose i.e. building with bad-but-popular browsers in mind, and then looking at shoe-horning in browser-specific fixes for the others.</p>
<p>If you inconvenience the users of good browsers because there aren&#8217;t many of them, you are taking us back to the bad old days of 1990s browsing. I haven&#8217;t seen the phrase &#8220;We advise you to upgrade your browser version&#8221; (which I take verbatim from p4 of your report) on any site I respect and trust for almost ten years. Ask any decent web developer: it&#8217;s no longer necessary, and frankly it reveals far more about the mindset of the site designers than about the state of web technology.</p>
<p>Like the proposal&#8217;s guidelines, its consultation is happening the wrong way round, and highlights a top-down mentality behind composing such documents. Sharp, savvy developers recruited from any of the vibrant UK web conferences&#8212;dConstruct, OpenTech, Barcamps&#8212;would have been glad to have helped the COI out before this fundamental missing of the point was published, were they to have been asked. It would certainly have saved both COI and the web community at large a lot of heat, friction and wasted effort.</p>
<p>Yours faithfully,</p>
<p>J-P Stacey</p>
<p>PS: I was originally going to send this via your website&#8217;s feedback form. After having read your proposals for building good sites I decided to email it instead, just in case.
</p></blockquote>
<p>You&#8217;ve got a month to comment yourself, if you&#8217;re a UK or European developer. Feel free to use the above template, only I&#8217;d recommend changing the name at the bottom.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jpstacey.info/blog/2008/09/10/uk-government-demonstrates-lack-of-comprehension-of-web-standards/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Improving REST performance is all about negotiation</title>
		<link>http://www.jpstacey.info/blog/2008/09/04/improving-rest-performance-is-all-about-negotiation/</link>
		<comments>http://www.jpstacey.info/blog/2008/09/04/improving-rest-performance-is-all-about-negotiation/#comments</comments>
		<pubDate>Thu, 04 Sep 2008 09:31:50 +0000</pubDate>
		<dc:creator>jps</dc:creator>
		
		<category><![CDATA[efficiency]]></category>

		<category><![CDATA[formats]]></category>

		<category><![CDATA[layers]]></category>

		<category><![CDATA[network]]></category>

		<category><![CDATA[quickies]]></category>

		<category><![CDATA[standards]]></category>

		<category><![CDATA[architecture]]></category>

		<category><![CDATA[resource]]></category>

		<category><![CDATA[rest]]></category>

		<category><![CDATA[royfielding]]></category>

		<category><![CDATA[roytfielding]]></category>

		<category><![CDATA[state]]></category>

		<category><![CDATA[understandable]]></category>

		<guid isPermaLink="false">http://www.jpstacey.info/blog/?p=200</guid>
		<description><![CDATA[Ceci n'est pas un obj&#233;t... nécessairement.]]></description>
			<content:encoded><![CDATA[<blockquote><p>
Web architects must understand that resources are just consistent mappings from an identifier to some set of views on server-side state. If one view doesn’t suit your needs, then feel free to create a different resource that provides a better view (for any definition of “better”). These views need not have anything to do with how the information is stored on the server, or even what kind of state it ultimately reflects. It just needs to be understandable (and actionable) by the recipient.
</p></blockquote>
<p>&#8212; Roy Fielding on <a href="http://roy.gbiv.com/untangled/2008/paper-tigers-and-hidden-dragons" >creating new resources for REST architectures</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jpstacey.info/blog/2008/09/04/improving-rest-performance-is-all-about-negotiation/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Trailing commas and unfeasibly high line numbers</title>
		<link>http://www.jpstacey.info/blog/2008/07/08/trailing-commas-and-unfeasibly-high-line-numbers/</link>
		<comments>http://www.jpstacey.info/blog/2008/07/08/trailing-commas-and-unfeasibly-high-line-numbers/#comments</comments>
		<pubDate>Tue, 08 Jul 2008 13:04:12 +0000</pubDate>
		<dc:creator>jps</dc:creator>
		
		<category><![CDATA[diagnostics]]></category>

		<category><![CDATA[standards]]></category>

		<category><![CDATA[big]]></category>

		<category><![CDATA[comma]]></category>

		<category><![CDATA[excessive]]></category>

		<category><![CDATA[firefox]]></category>

		<category><![CDATA[high]]></category>

		<category><![CDATA[highlinenumber]]></category>

		<category><![CDATA[huge]]></category>

		<category><![CDATA[ie6]]></category>

		<category><![CDATA[ie7]]></category>

		<category><![CDATA[javascript]]></category>

		<category><![CDATA[jslint]]></category>

		<category><![CDATA[line]]></category>

		<category><![CDATA[number]]></category>

		<category><![CDATA[parser]]></category>

		<category><![CDATA[syntax]]></category>

		<category><![CDATA[trailing]]></category>

		<guid isPermaLink="false">http://www.jpstacey.info/blog/?p=179</guid>
		<description><![CDATA[Bursting IE's Javascript parser, or: generating bizarre error messages through subprocess apoptosis]]></description>
			<content:encoded><![CDATA[<p>In Javascript, trailing commas are to be considered harmful. Strictly speaking, they&#8217;re not allowed by the syntax, but this wouldn&#8217;t be such a problem were it not for the fact that some browsers (including Firefox) will quietly ignore them, pretending briefly that Javascript&#8217;s syntax is Pythonic or, um, Rubric. The safest route to take is to avoid trailing commas wherever possible. <a href="http://www.jpstacey.info/blog/2006/10/03/how-to-write-a-javascript-file/" >I&#8217;ve mentioned the general problem before</a>, and the hard core among you would probably go so far as to <a href="http://www.bofh.org.uk/articles/2008/04/16/a-quick-javascript-formatting-tip" >change their formatting to highlight trailing commas</a>.</p>
<p>But what makes it all far, far worse is that IE6 and IE7 can sometimes produce error messages which, as is usual for those browsers, contain no useful information whatsoever.</p>
<p>Here&#8217;s a recent example:</p>
<blockquote><p>
 Line: 64432871<br />
 Char: 2<br />
 Error: Expected identifier, string or number
</p></blockquote>
<p>See that impossibly high line number? That&#8217;s a result of the parser being struck soundly on the head by the syntax error, and consequently dribbling its way past the end of the Javascript file. IE&#8217;s incomprehensible &#8220;English&#8221; error message conspires with circumstance to make the whole report of no help at all.</p>
<p>Something like <a href="http://www.jslint.com/" >JSLint</a>, on the other hand, is of tremendous help, and we&#8217;ll be running as much Javascript through it as possible in future. JSLint is just as unforgiving, but as it&#8217;s reliably unforgiving and incredibly communicative with it then that&#8217;s a bonus rather than a detriment. </p>
<p>It&#8217;s sometimes a little too strict to be useful, complaining about implicit global variables (even when that variable is called <code>window</code>). My suggestion is to ignore those reports, though; but <em>watch those commas!</em></p>
]]></content:encoded>
			<wfw:commentRss>http://www.jpstacey.info/blog/2008/07/08/trailing-commas-and-unfeasibly-high-line-numbers/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Drupal, licensing and the GPL</title>
		<link>http://www.jpstacey.info/blog/2008/06/30/drupal-licensing-and-the-gpl/</link>
		<comments>http://www.jpstacey.info/blog/2008/06/30/drupal-licensing-and-the-gpl/#comments</comments>
		<pubDate>Mon, 30 Jun 2008 14:15:11 +0000</pubDate>
		<dc:creator>jps</dc:creator>
		
		<category><![CDATA[culture]]></category>

		<category><![CDATA[law]]></category>

		<category><![CDATA[standards]]></category>

		<category><![CDATA[subtleties]]></category>

		<category><![CDATA[drupal]]></category>

		<category><![CDATA[foss]]></category>

		<category><![CDATA[gpl]]></category>

		<category><![CDATA[legal]]></category>

		<category><![CDATA[licence]]></category>

		<category><![CDATA[license]]></category>

		<category><![CDATA[practice]]></category>

		<category><![CDATA[sflc]]></category>

		<category><![CDATA[software]]></category>

		<category><![CDATA[theory]]></category>

		<guid isPermaLink="false">http://www.jpstacey.info/blog/?p=175</guid>
		<description><![CDATA[If you're about to start programming under the GPL, and you want to read just one article about it, then: don't read this; read the Drupal licensing FAQ instead.]]></description>
			<content:encoded><![CDATA[<p>Lurking in a dry, legalistic and apparently quite specific page on the Drupal website, is the commendable result of a lot of hard work, both from the the <a href="http://www.softwarefreedom.org/" >Software Freedom</a> Law Center and from the Drupal community.</p>
<p>Drupal.org have produced a <a href="http://drupal.org/licensing/faq">Licensing FAQ</a> to explain some of the subtler aspects of licensing under the GPL. The questions themselves are Drupal-oriented, but the FAQ itself has been prepared by the SFLC, an independent body, so the answers are broader than that.</p>
<p>I&#8217;ve noticed from the slightly confused sidelines that Drupalers have been niggling away at these issues for ages. Their heated exchanges and occasional quarrels are the fuel that has kept this wagon moving, and they&#8217;ve finally rolled it into town with a GPL-in-practice primer that&#8217;s worth reading, whatever you&#8217;re working on, and especially if you&#8217;re integrating with web services or third-party libraries. Well done to all involved.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jpstacey.info/blog/2008/06/30/drupal-licensing-and-the-gpl/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Open Knowledge Conference: OKCon, Saturday 15 March</title>
		<link>http://www.jpstacey.info/blog/2008/03/06/open-knowledge-conference-okcon-saturday-15-march/</link>
		<comments>http://www.jpstacey.info/blog/2008/03/06/open-knowledge-conference-okcon-saturday-15-march/#comments</comments>
		<pubDate>Thu, 06 Mar 2008 17:06:05 +0000</pubDate>
		<dc:creator>jps</dc:creator>
		
		<category><![CDATA[conferences]]></category>

		<category><![CDATA[culture]]></category>

		<category><![CDATA[standards]]></category>

		<category><![CDATA[conference]]></category>

		<category><![CDATA[knowledge]]></category>

		<category><![CDATA[london]]></category>

		<category><![CDATA[ogn5]]></category>

		<category><![CDATA[okfn]]></category>

		<category><![CDATA[open]]></category>

		<category><![CDATA[rufuspollock]]></category>

		<guid isPermaLink="false">http://www.jpstacey.info/blog/2008/03/06/open-knowledge-conference-okcon-saturday-15-march/</guid>
		<description><![CDATA[If you're going to a conference on open knowledge, it's only fair you tell everyone that.]]></description>
			<content:encoded><![CDATA[<p>The <a href="http://www.okfn.org/okcon/">Open Knowledge Conference</a> takes place in London the weekend after this. Rufus Pollock, who gave a keynote at <a href="http://oxford.geeknights.net/2008/feb-6th" />OGN5, will be introducing <a href="http://www.okfn.org/okcon/programme/">a packed programme</a> which covers the principles of free and open information access applied to diverse areas such as education, the environment, transport and academia.</p>
<p>I&#8217;m realy looking forward to it, especially in the light of one of our clients wanting to implement the <a href="http://www.openarchives.org/">OAI-PMH</a> protocol in the next month or two. I&#8217;ll have to toss a coin, though, to see if I dare stay in London late enough to miss the last bus out from Oxford to Eynsham&#8230;.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jpstacey.info/blog/2008/03/06/open-knowledge-conference-okcon-saturday-15-march/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Last.fm on Ubuntu Gutsy: smooth as rabbit fur</title>
		<link>http://www.jpstacey.info/blog/2008/02/03/lastfm-on-ubuntu-gutsy-smooth-as-rabbit-fur/</link>
		<comments>http://www.jpstacey.info/blog/2008/02/03/lastfm-on-ubuntu-gutsy-smooth-as-rabbit-fur/#comments</comments>
		<pubDate>Sun, 03 Feb 2008 18:28:33 +0000</pubDate>
		<dc:creator>jps</dc:creator>
		
		<category><![CDATA[business]]></category>

		<category><![CDATA[formats]]></category>

		<category><![CDATA[non-programming]]></category>

		<category><![CDATA[software]]></category>

		<category><![CDATA[standards]]></category>

		<category><![CDATA[aptitude]]></category>

		<category><![CDATA[bittorrent]]></category>

		<category><![CDATA[carbon]]></category>

		<category><![CDATA[CDs]]></category>

		<category><![CDATA[climate change]]></category>

		<category><![CDATA[download]]></category>

		<category><![CDATA[foss]]></category>

		<category><![CDATA[free]]></category>

		<category><![CDATA[gutsy]]></category>

		<category><![CDATA[lastfm]]></category>

		<category><![CDATA[linux]]></category>

		<category><![CDATA[management]]></category>

		<category><![CDATA[music]]></category>

		<category><![CDATA[package]]></category>

		<category><![CDATA[radio]]></category>

		<category><![CDATA[subscription]]></category>

		<category><![CDATA[synaptic]]></category>

		<category><![CDATA[ubuntu]]></category>

		<guid isPermaLink="false">http://www.jpstacey.info/blog/2008/02/03/lastfm-on-ubuntu-gutsy-smooth-as-rabbit-fur/</guid>
		<description><![CDATA[One of my resolutions this year is to try to cut down on the carbon I spend on music. Notwithstanding my purchase of the In Rainbows discbox, I&#8217;ve amassed an awful number of discs of metallized plastic in barely-recyclable containers. (I say &#8220;barely&#8221; because K. got me a pencil for Christmas made out of old [...]]]></description>
			<content:encoded><![CDATA[<p>One of my resolutions this year is to try to cut down on the carbon I spend on music. Notwithstanding <a href="/blog/2007/12/10/working-out-chaotic-things/">my purchase of the <cite>In Rainbows</cite> discbox</a>, I&#8217;ve amassed an awful number of discs of metallized plastic in barely-recyclable containers. (I say &#8220;barely&#8221; because K. got me a pencil for Christmas made out of old CD boxes, and a pen from dead car parts. But there&#8217;s only so many pencils the world can use.) </p>
<p>As I spend the scraps and offcuts of January and February evenings ripping and filing my 2007&#8217;s CDs&#8212;some of which I won&#8217;t listen to very often once they&#8217;re fossilized in the collection&#8212;I&#8217;m aware of a tremendous weight of <em>madeness</em> and invested time and energy on the part of the manufacturers, and of a sort of casual luxuriating in my first-world lifestyle on my own part. <i>You prepare a playlist before me in the presence of my enemies. You anoint my tapeheads with crude oil; my CD tray overflows.</i> So in 2008 I hope to buy as few CDs as possible (none is the target) while also avoiding DRM-crippled music and staying legal.</p>
<p>To this end I&#8217;ve been seeking free and semi-free online music&#8212;free as in beer, semi-free as in of limited choice&#8212;since the new year. So far, outside of bittorrenting (which is obviously of variable legality, depending on what you&#8217;re downloading), I&#8217;m having some success with <a href="http://last.fm/">Last.fm</a>. Until recently they offered a sort of customized &#8220;radio station&#8221;, where your input into the of the next track was limited to an intelligent deduction by Last.fm based on what you told it you enjoyed in the past. Now, alongside this potluck service, they&#8217;ve just started offering <a href="http://www.pcadvisor.co.uk/news/index.cfm?RSS&#38;NewsID=11947">three free streamings of any explicitly chosen track</a> before requiring you to buy the track from  a commercial partner.</p>
<p>I&#8217;ve yet to try the former service (I think you might have to subscribe to be on the beta wagon: I&#8217;ll look into that later), but the latter has so far provided our house with unlimited, free access to a radio station for our very own target market. While such slightly sinister profiling might make it harder for me to discover <em>truly</em> new music, it does at least permit me to expand the boundaries of my comfort zone slowly, and cast a critical eye over my friends&#8217; music preferences, while at the same time giving artists their due and most importantly avoiding physical recordings unless I really want them.</p>
<p>Most commercial support for Linux distributions still consists of monolithic installations, wrapped up with checksums to prevent you tampering with them, and installing themselves on your computer in whatever location and potentially harmful fashion they fancy. Until upgrading to Gutsy this was largely my experience (painfully and often repeated) with such packages as nVidia and wireless drivers, and interesting software that barely gave a second thought to existing Feisty users. </p>
<p>After a spot of Googling I was expecting to have to go through <a href="http://rolandog.com/archives/2006/07/27/lastfm-linux-client-available/">the same palaver with Last.fm&#8217;s client</a>, and crossed my fingers that nothing would go horribly wrong. But I needn&#8217;t have worried: the Linux client for Last.fm is</p>
<ol type="A">
<li>free of cost, as in beer</li>
<li>free of restrictions, as in open source</li>
<li>free of hard work, as in a no-sweat installation utilizing the Debian packages and apt package management that&#8217;s core to Ubuntu</li>
</ol>
<p>To install it on Gutsy, you first want to add the GPG key for the repository for security reasons. At a command line, type:</p>
<blockquote class="code"><p>wget -q http://apt.last.fm/last.fm.repo.gpg -O- | sudo apt-key add -</p>
</blockquote>
<p>You&#8217;ll be asked by <code>sudo</code> for your password. Then, open Synaptic Package Manager (under &#8220;System &gt; Administration&#8221; in the GNOME menus); then, via &#8220;Settings &gt; Repositories&#8221;, add the following new third-party repository:</p>
<blockquote class="code"><p>deb http://apt.last.fm/ debian stable</p>
</blockquote>
<p>You can then search for the Last.fm widget&#8217;s package in the manager (hint: it&#8217;s called lastfm) and install it. When you first run it after installation it&#8217;ll ask for your Last.fm account, so best have one of those in advance. And that&#8217;s it: you&#8217;ve now got Last.fm&#8217;s widget on your Ubuntu PC.</p>
<p>All of the above is explained briefly on <a href="http://apt.last.fm/">the very URL of the apt repository</a>. Not only that, but they have a free bonus photo of a very cute bunny in case all the apt stuff bores you rigid. Like a TV licence for the <a href="http://www.bbc.co.uk/iplayer">Flash version of the BBC iPlayer</a>, all of this is practically worth a subscription alone. As I type, my mouse sits over the very location of the link to do so in a separate tab. I just need to know first: how many more rabbits do I get when I join?</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jpstacey.info/blog/2008/02/03/lastfm-on-ubuntu-gutsy-smooth-as-rabbit-fur/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Pretending that Javascript is XSL, part 3: hCard to vCard</title>
		<link>http://www.jpstacey.info/blog/2007/12/20/pretending-that-javascript-is-xsl-part-3-hcard-to-vcard/</link>
		<comments>http://www.jpstacey.info/blog/2007/12/20/pretending-that-javascript-is-xsl-part-3-hcard-to-vcard/#comments</comments>
		<pubDate>Thu, 20 Dec 2007 21:07:55 +0000</pubDate>
		<dc:creator>jps</dc:creator>
		
		<category><![CDATA[hacking]]></category>

		<category><![CDATA[paradigms]]></category>

		<category><![CDATA[software]]></category>

		<category><![CDATA[standards]]></category>

		<category><![CDATA[browser]]></category>

		<category><![CDATA[client]]></category>

		<category><![CDATA[conversion]]></category>

		<category><![CDATA[functional]]></category>

		<category><![CDATA[hcard]]></category>

		<category><![CDATA[javascript]]></category>

		<category><![CDATA[microformats]]></category>

		<category><![CDATA[suda]]></category>

		<category><![CDATA[tree]]></category>

		<category><![CDATA[vcard]]></category>

		<category><![CDATA[x2v]]></category>

		<category><![CDATA[xsl]]></category>

		<guid isPermaLink="false">http://www.jpstacey.info/blog/2007/12/20/pretending-that-javascript-is-xsl-part-3-hcard-to-vcard/</guid>
		<description><![CDATA[In previous posts (part 1, part 2) I established the possibility that there were advantages to making Javascript more functional, to bring it in line with CSS and XSL. I didn&#8217;t say what these were, particularly, but I then provided a few bits and pieces on top of jQuery to make Javascript just that: functional [...]]]></description>
			<content:encoded><![CDATA[<p>In previous posts (<a href="/blog/?p=109">part 1</a>, <a href="/blog/?p=110">part 2</a>) I established the possibility that there were advantages to making Javascript more functional, to bring it in line with CSS and XSL. I didn&#8217;t say what these were, particularly, but I then provided a few bits and pieces on top of jQuery to make Javascript just that: functional and quasi-XSL in its behaviour.</p>
<p>Now I&#8217;d like to start exploiting that behaviour, and I&#8217;m going to use the <a href="http://microformats.org/wiki/hcard">hCard microformat</a> to illuminate its use. Briefly: a microformat is a set of agreed HTML classes used to invisibly encode structured semantic data in HTML; hCard is the implementation in HTML of the <a href="http://www.ietf.org/rfc/rfc2426.txt">vCard</a> specification for &#8220;virtual business card&#8221; files, using microformat classes. If you mark up people&#8217;s addresses using the hCard classes, then it&#8217;s possible to automate the conversion from hCard-enabled HTML to vCards, meaning you can click on buttons on webpages and have a vCard served up to you containing the contact information present in the webpage, verbatim, in a format you can put into your address book of choice.</p>
<p>One of the most-used conversion methods&#8212;<a href="http://suda.co.uk/projects/X2V/">Brian Suda&#8217;s X2V</a>, a web service which converts XHTML with hCard markup into vCards and then presents them to the site visitor&#8212;uses XSL. In fact, that was what got me thinking about this whole system. Brian&#8217;s work is neat, although his own server takes a hit every time someone uses the web service (and it only works on XHTML, not non-XML HTML. What if, I thought, we could get the browser to do it instead; if we could implement template-like functional Javascript? </p>
<p>Anyway, below we find a couple of <a href="http://microformats.org/wiki/hcard">hCards</a>, culled more or less directly from the <a href="http://microformats.org/wiki/hcard-examples">Microformats examples page</a>. </p>
<blockquote>
<div class="vcard">
	<a class="url fn" href="http://home.earthlink.net/~fdawson">Frank Dawson</a></p>
<div class="org">Lotus Development Corporation</div>
<div class="adr">
		<span class="type">work</span> address 	(<abbr class="type" title="postal">mail</abbr> and <abbr class="type" title="parcel">packages</abbr>):</p>
<div class="street-address">6544 Battleford Drive</div>
<p>		<span class="locality">Raleigh</span> <span class="region">NC</span> <span class="postal-code">27613-3502</span></p>
<div class="country-name">U.S.A.</div>
</div>
<div class="tel">
		<span class="value">+1-919-676-9515</span> (<abbr class="type" title="WORK">w</abbr>, <abbr class="type" title="VOICE">v</abbr><abbr class="type" title="MSG">m</abbr>)
	</div>
<div class="tel">
		<span class="value">+1-919-676-9564</span> (<abbr class="type" title="WORK">w</abbr><abbr class="type" title="FAX">f</abbr>)
	</div>
<p>	<a class="email" href="mailto:Frank_Dawson@Lotus.com">Frank_Dawson@Lotus.com</a> <span class="email"><abbr class="type" title="VOICE">alt</abbr>ernative email <em>fdawson@earthlink.net</em></span>
</p>
</div>
<div class="vcard">
	<a class="email fn" href="mailto:howes@netscape.com">Tim Howes</a></p>
<div class="org">Netscape Communications Corp.</div>
<div class="adr">
		<span class="type">work</span> address:</p>
<div class="street-address">501 E. Middlefield Rd.</div>
<p>		<span class="locality">Mountain View</span>, <span class="region">CA</span> <span class="postal-code">94043</span></p>
<div class="country-name">U.S.A.</div>
</div>
<div class="tel">
		<span class="value">+1-415-937-3419</span> (<abbr class="type" title="WORK">w</abbr>, <abbr class="type" title="VOICE">v</abbr><abbr class="type" title="MSG">m</abbr>)
	</div>
<div class="tel">
		<span class="value">+1-415-528-4164</span> (<abbr class="type" title="WORK">w</abbr><abbr class="type" title="FAX">f</abbr>)
	</div>
</div>
</blockquote>
<p>They look like slightly unstructured HTML, don&#8217;t they? That&#8217;s sort of the point. But hidden in the HTML are vCard classes. How do we tease them out with Javascript?</p>
<p>Well, there&#8217;s a question to be asked before that, I suppose, which is: why would we follow your method, and not someone else&#8217;s? What&#8217;s so good about functional Javascript? Good question. Well, if every hCard looked like the above, then you could write some completely procedural Javascript to turn it into a vCard. No problem.</p>
<p>But what if the order of the content was changed? The hCard&#8212;indeed, microformats in general&#8212;has quite a malleable structure, with some classes sometimes appearing on elements inside other elements, and sometimes not. What if there were more telephone numbers and email addresses, and what if they turned up in all sorts of different orders? These are just HTML classes, after all. With procedural Javascript you could start writing <code>switch</code>/<code>case</code> statements to cover every opportunity, and essentially come up with one big unavoidably recursive function. It&#8217;ll be hard to structure, hard to maintain and completely unmodular.  A document-driven method of extracting the vCard, on the other hand, doesn&#8217;t need to worry about all the various different combinations of nested elements: it would just keep one eye on context and process whatever it found. Also, the development cycle could be faster, because templates could be overridden without breaking existing behaviour: just use the <code>template()</code> command to override existing behaviour.</p>
<p>Let&#8217;s instead assume you&#8217;re following my every word. For this next bit, you&#8217;ll need Firefox and Firebug, or to stuff all these instructions into a single file. Otherwise, you&#8217;ll have to take my word for it. Firstly, I&#8217;ve included jQuery on every page of my blog, so if you&#8217;ve got the &#8216;bug then you don&#8217;t have to resort to my <a href="http://www.jpstacey.info/blog/2007/12/10/insert-any-javascript-bookmarklet/">insert-JS bookmarklet</a> to squirt it in. </p>
<p>So: first, create the <code>treewalker()</code> and <code>template()</code> functions from part 2. Next, assign <code>treewalker()</code> to <code>body</code> and everything below it:</p>
<blockquote class="code"><p>
template(&quot;body, body *&quot;, treewalker);<br />
template(&quot;body, body *&quot;, treewalker, &quot;default&quot;);
</p>
</blockquote>
<p>You could restrict this assignment to everything within the <code>.vcard</code> elements, by giving the relevant CSS specifier instead, if there were a lot of content outside the hCards. It would speed up the initial setup phase, but it does complicate the demonstration so I&#8217;ve left that refinement out.</p>
<p>Remember we ran the treewalking before? Do that now:</p>
<blockquote class="code"><p>var result = document.body.treewalk();</p>
</blockquote>
<p>All being well, you should get a blank string back. Now it&#8217;s time to start adding some alternative rules with <code>template()</code>. Try this:</p>
<blockquote class="code"><p>
template(&quot;.vcard&quot;, function() { return &quot;BEGIN:VCARDn&quot; + this.default() + &quot;END:VCARDn&quot; });
</p>
</blockquote>
<p>Now run the treewalker again. Oh, each hCard has just given you a vCard! An&#8230; empty vCard. Isn&#8217;t that great? Um. We can add to that, though:</p>
<blockquote class="code"><p>
template(&quot;.vcard .fn&quot;, function() { return &quot;FN:&quot; + $(this).text() + &quot;n&quot; + this.default(); });<br />
template(&quot;.vcard .org&quot;, function() { return &quot;ORG:&quot; + $(this).text() + &quot;n&quot; + this.default(); });
</p>
</blockquote>
<p>Now <code>document.body.treewalk()</code> doesn&#8217;t just return a vCard for every hCard, but it knows about names and organisations. Also, because we keep including the call to <code>this.default()</code> in our overrides, we still treewalk into any element inside the FN or ORG containers.</p>
<p>What about emails? Well, in the source we can spot an <code>a.email</code> element up there, so let&#8217;s give the following a whirl:</p>
<blockquote class="code"><p>
template(&quot;.vcard .email&quot;, function() { return &quot;EMAIL;TYPE=internet:&quot; + this.href.replace(/mailto:/, &quot;&quot;) + &quot;n&quot; + this.default(); });
</p>
</blockquote>
<p>Try running <code>document.body.treewalk()</code> again. Hm. I don&#8217;t know about you, but I&#8217;m getting an error from that. Ah, wait: sometimes we have <code>span.email</code> rather than <code>a.email</code>. Spans don&#8217;t have <code>@href</code> attributes. Well, we could change the above rule and immediately reapply it using <code>template()</code> with no ill effects. But instead let&#8217;s keep it in place, and use a more specific specifier to override it <em>just on spans</em>:</p>
<blockquote class="code"><p>
template(&quot;.vcard span.email&quot;, function() { return &quot;EMAIL;TYPE=internet:&quot; + $(this).find(&quot;.value&quot;).text() + &quot;n&quot; + this.default(); });
</p>
</blockquote>
<p>Re-run the treewalker. It now finds all email hCard elements and brings them out into the vCards!</p>
<p>I&#8217;ll leave you with one more demonstration, for the slightly more complex TELephone field. As you can see above, there are lots of &#8220;types&#8221; for this field (Work, VoiceMail, etc.) and these sit in child elements of the telephone element. So we need to assign overrides to both the telephone element and its children.</p>
<p>Here&#8217;s a rule for the TELephone container:</p>
<blockquote class="code"><p>
template(&quot;.vcard .tel&quot;, function() {<br />
&nbsp;&nbsp;var t = &quot;TEL&quot;;<br />
&nbsp;&nbsp;// Run defaults to get types where appropriate<br />
&nbsp;&nbsp;t += this.default().replace(/,/, &quot;;&quot;) + &quot;:&quot;;<br />
&nbsp;&nbsp;// See if we&#8217;ve got a &#8220;value&#8221; child<br />
&nbsp;&nbsp;var val = $(this).find(&quot;.value&quot;);<br />
&nbsp;&nbsp;return t + (val.length ? val.text() : $(this).text()) + &quot;n&quot;;<br />
});
</p>
</blockquote>
<p>This method is a bit more complex because we need <code>default()</code> to just get the <code>.type</code> children, and then we reach down to get. Maybe if we could give specifier argument to the default behaviour e.g. <code>default('.type')</code> first, then <code>default('.value')</code>&#8230; But that&#8217;s a project for another day, I think. Right now, let&#8217;s assign a rule to the types children and then run our treewalker:</p>
<blockquote class="code"><p>
template(&quot;.vcard .tel .type&quot;, function() {<br />
&nbsp;&nbsp;var jQ = $(this);<br />
&nbsp;&nbsp;return &quot;,&quot; + (jQ.attr(&quot;title&quot;) ? jQ.attr(&quot;title&quot;) : jQ.text());<br />
});
</p>
</blockquote>
<p>Result? You should now have Javascript which can produce vCards (currently without geographical address support, as I don&#8217;t have time and you might get bored) from the hCard microformat. It&#8217;s easy to extend, easy to maintain and, in my opinion, fairly concise. Here&#8217;s the whole shebang, less the two framework functions from my previous posts:</p>
<blockquote class="code"><p>
// Start with body<br />
template(&quot;body, body *&quot;, treewalker);<br />
template(&quot;body, body *&quot;, treewalker, &quot;default&quot;);<br />
// vCard wrapper<br />
template(&quot;.vcard&quot;, function() { return &quot;BEGIN:VCARDn&quot; + this.default() + &quot;END:VCARDn&quot; });<br />
// FN and ORG<br />
template(&quot;.vcard .fn&quot;, function() { return &quot;FN:&quot; + $(this).text() + &quot;n&quot; + this.default(); });<br />
template(&quot;.vcard .org&quot;, function() { return &quot;ORG:&quot; + $(this).text() + &quot;n&quot; + this.default(); });<br />
// Email - A and SPAN tags<br />
template(&quot;.vcard .email&quot;, function() { return &quot;EMAIL;TYPE=internet:&quot; + this.href.replace(/mailto:/, &quot;&quot;) + &quot;n&quot; + this.default(); });<br />
template(&quot;.vcard span.email&quot;, function() { return &quot;EMAIL;TYPE=internet:&quot; + $(this).find(&quot;.value&quot;).text() + &quot;n&quot; + this.default(); });<br />
// TEL<br />
template(&quot;.vcard .tel&quot;, function() {<br />
&nbsp;&nbsp;var t = &quot;TEL&quot;;<br />
&nbsp;&nbsp;// Run defaults to get types where appropriate<br />
&nbsp;&nbsp;t += this.default().replace(/,/, &quot;;&quot;) + &quot;:&quot;;<br />
&nbsp;&nbsp;// See if we&#8217;ve got a &#8220;value&#8221; child<br />
&nbsp;&nbsp;var val = $(this).find(&quot;.value&quot;);<br />
&nbsp;&nbsp;return t + (val.length ? val.text() : $(this).text()) + &quot;n&quot;;<br />
});<br />
// TEL types<br />
template(&quot;.vcard .tel .type&quot;, function() {<br />
&nbsp;&nbsp;var jQ = $(this);<br />
&nbsp;&nbsp;return &quot;,&quot; + (jQ.attr(&quot;title&quot;) ? jQ.attr(&quot;title&quot;) : jQ.text());<br />
});
</p>
</blockquote>
<p>And that&#8217;s it. I hope the approach comes in useful. By next year, you&#8217;ll have hCard-enabled pages, with vCard conversion in the browser. Happy Christmas!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jpstacey.info/blog/2007/12/20/pretending-that-javascript-is-xsl-part-3-hcard-to-vcard/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Pretending that Javascript is XSL, part 2: jQuery++</title>
		<link>http://www.jpstacey.info/blog/2007/12/19/pretending-that-javascript-is-xsl-part-2-jquery/</link>
		<comments>http://www.jpstacey.info/blog/2007/12/19/pretending-that-javascript-is-xsl-part-2-jquery/#comments</comments>
		<pubDate>Wed, 19 Dec 2007 09:23:08 +0000</pubDate>
		<dc:creator>jps</dc:creator>
		
		<category><![CDATA[hacking]]></category>

		<category><![CDATA[paradigms]]></category>

		<category><![CDATA[software]]></category>

		<category><![CDATA[standards]]></category>

		<category><![CDATA[css]]></category>

		<category><![CDATA[dom]]></category>

		<category><![CDATA[foreach]]></category>

		<category><![CDATA[functional]]></category>

		<category><![CDATA[html]]></category>

		<category><![CDATA[implicit]]></category>

		<category><![CDATA[javascript]]></category>

		<category><![CDATA[jquery]]></category>

		<category><![CDATA[traversing]]></category>

		<category><![CDATA[tree]]></category>

		<category><![CDATA[walking]]></category>

		<category><![CDATA[xsl]]></category>

		<guid isPermaLink="false">http://www.jpstacey.info/blog/2007/12/19/pretending-that-javascript-is-xsl-part-2-jquery/</guid>
		<description><![CDATA[If you&#8217;re here, then you probably came from here, and you want to make Javascript more functional. If you didn&#8217;t come from there&#8212;and this is getting a bit like a Choose-Your-Own-Adventure book, isn&#8217;t it?&#8212;then you might want to go there first, to see if you want to be here.
So: functional Javascript. Not just functional, but [...]]]></description>
			<content:encoded><![CDATA[<p>If you&#8217;re here, then you probably came from <a href="/blog/?p=109">here</a>, and you want to make Javascript more functional. If you didn&#8217;t come from there&#8212;and this is getting a bit like a Choose-Your-Own-Adventure book, isn&#8217;t it?&#8212;then you might want to go there first, to see if you want to be here.</p>
<p>So: functional Javascript. Not just functional, but with all the automation of XSL transformations and CSS applications, where you can set it all running and it&#8217;ll produce <em>something</em> and hopefully throw no errors. Let&#8217;s start with jQuery.</p>
<p>jQuery provides Javascript with a functional framework. Here&#8217;s the equivalent of the examples in XSL and CSS, supported by the inclusion of <code>jquery.js</code>:</p>
<blockquote class="code"><p>jQuery(&quot;p.intro&quot;).each(<br />
&nbsp;&nbsp;function() { this.style.color = green; }<br />
);</p>
</blockquote>
<p>I hope the similarities are clear, and not too strained. Now all three languages do implicit looping over sets of element nodes, and no longer require checks for missing elements; that&#8217;s evidence that it&#8217;s starting to behave functionally. There&#8217;s still a few pieces missing, though. We&#8217;d like to be able to iterate over the tree with a set of default rules, and also replace the default rules with our own where necessary. </p>
<p>What would the default rule look like? Well, we can pass around all sorts of objects&#8212;this being an object-oriented language&#8212;but for now let&#8217;s play it safe and follow XSL&#8217;s lead, and have each node return the concatenated text returned by all its child nodes. That means that, by default, the whole HTML document would return an empty string. It might be nice to return an array of equivalent objects, or even some transformed tree, but let&#8217;s remain old-skool. Anyway, we can always serialize any HTML elements we want to include as text, and then stick them back into the DOM later. There&#8217;s probably a way of doing some of these tasks with core jQuery, but as we&#8217;re also passing result data around as well as input data, I&#8217;m going to step outside the framework (its extension model typically takes a jQuery object in, and returns a modified jQuery object, which isn&#8217;t quite what we&#8217;re after).</p>
<p>Here&#8217;s a default rule: it says &#8220;call the default rule (i.e. me) on all my children&#8221;. We&#8217;ll call this rule <code>treewalker</code>, because that&#8217;s what it does. We&#8217;ll also assume that we&#8217;re going to assign this function as the <code>.treewalk</code> method on each element:</p>
<blockquote class="code"><p>
var treewalker = function(i) {<br />
&nbsp;&nbsp;var t = &quot;&quot;;<br />
&nbsp;&nbsp;$(this).children().each(function(i) { t += this.treewalk(); } );<br />
&nbsp;&nbsp;return t;<br />
}
</p>
</blockquote>
<p>And here&#8217;s a way of assigning rules to elements. It&#8217;ll assign the rule as the <code>.treewalk</code> method unless we specify otherwise. </p>
<blockquote class="code"><p>
var template = function(specifier, fn, property) {<br />
&nbsp;&nbsp;if (typeof property == &quot;undefined&quot;) property = &quot;treewalk&quot;;<br />
&nbsp;&nbsp;$(specifier).each(function(i) { this[property] = fn; });<br />
}
</p>
</blockquote>
<p>It looks a bit clunky, because falling back on the default property means we have to have an if-exists check. That&#8217;s to be avoided where possible in functional programming, but bear in mind that we&#8217;re still looking under the bonnet (or &#8220;hood&#8221; if you like), not at the actual functional code. We&#8217;ll get to the fully-functional bit shortly.</p>
<p>We&#8217;ve got one last bit and we&#8217;re done. We want to put the default rule on every element within a certain scope: we&#8217;ll assume for now that the whole HTML document body is to be treated; that might be computationally heavy for big documents, but we could change that. We&#8217;ve already defined a way of putting rules onto things, so let&#8217;s use that to put the treewalker function in as both <code>.treewalk</code> and <code>.default</code>. That way, we have a copy of the method hanging around, that we can fall back on if we overwrite it:</p>
<blockquote class="code"><p>
template(&quot;body, body *&quot;, treewalker);<br />
template(&quot;body, body *&quot;, treewalker, &quot;default&quot;);
</p>
</blockquote>
<p>That&#8217;s it. We&#8217;re now ready to pretend our Javascript is XSL. Here&#8217;s how we run it:</p>
<blockquote class="code"><p>var result = document.body.treewalk();</p>
</blockquote>
<p>Try it. &#8220;But that&#8217;s just an empty string!&#8221; you might, if you were feeling ungrateful, complain. Are you never satisfied? <a href="/blog/?p=114">More on this later</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jpstacey.info/blog/2007/12/19/pretending-that-javascript-is-xsl-part-2-jquery/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Pretending that Javascript is XSL, part 1: XSL, CSS and JS side by side</title>
		<link>http://www.jpstacey.info/blog/2007/12/18/pretending-that-javascript-is-xsl-part-1-xsl-css-and-js-side-by-side/</link>
		<comments>http://www.jpstacey.info/blog/2007/12/18/pretending-that-javascript-is-xsl-part-1-xsl-css-and-js-side-by-side/#comments</comments>
		<pubDate>Tue, 18 Dec 2007 10:26:57 +0000</pubDate>
		<dc:creator>jps</dc:creator>
		
		<category><![CDATA[hacking]]></category>

		<category><![CDATA[paradigms]]></category>

		<category><![CDATA[software]]></category>

		<category><![CDATA[standards]]></category>

		<category><![CDATA[css]]></category>

		<category><![CDATA[dom]]></category>

		<category><![CDATA[functional]]></category>

		<category><![CDATA[html]]></category>

		<category><![CDATA[javascript]]></category>

		<category><![CDATA[object-oriented]]></category>

		<category><![CDATA[xhtml]]></category>

		<category><![CDATA[xsl]]></category>

		<guid isPermaLink="false">http://www.jpstacey.info/blog/2007/12/18/pretending-that-javascript-is-xsl-part-1-xsl-css-and-js-side-by-side/</guid>
		<description><![CDATA[There are three main technologies that your browser employs to present HTML for you: XSL, CSS and Javascript. The first two of these are functional: that is, they turn your incoming (X)HTML documents into a set of functions, or behaviours if you like. Because CSS isn&#8217;t generally considered a language, let alone a functional one, [...]]]></description>
			<content:encoded><![CDATA[<p>There are three main technologies that your browser employs to present HTML for you: XSL, CSS and Javascript. The first two of these are <em>functional</em>: that is, they turn your incoming (X)HTML documents into a set of functions, or behaviours if you like. Because CSS isn&#8217;t generally considered a language, let alone a functional one, then it&#8217;s worth seeing an example in both languages. Here&#8217;s the CSS:</p>
<blockquote class="code"><p>p.intro { color: green; }</p>
</blockquote>
<p>And here&#8217;s a sort-of XSL equivalent:</p>
<blockquote class="code"><p>
&lt;xsl:template match=&quot;p[@class=&apos;intro&apos;]&quot;&gt;<br />
&nbsp;&nbsp;&lt;p color=&quot;green&quot;&gt;&lt;xsl:apply-templates /&gt;&lt;/p&gt;<br />
&lt;/xsl:template&gt;
</p>
</blockquote>
<p>They both take place in the context of some generic processor, which rattles through the document executing default rules (XSL: strip out all but text nodes; CSS: apply the plain styles of your browser) unless <em>your</em> program&#8212;a list of disconnected rules, really&#8212;tells it differently. The combination of (XSL/CSS)+(X)HTML+defaults is thus turned into an explicit script for the browser to run.</p>
<p>So far, so reasonable. But what about the third technology, Javascript? Well, plain Javascript is an object-oriented procedural language. It orders the browser around for a bit, and then when you want to do something to the current page, Javascript manipulates the (X)HTML tree by grasping hold of it with both hands and giving it a tug, using DOM methods like <code>.getElementById(id)</code> and attributes like <code>.parentNode</code>. This procedural approach expects the tree to have a certain structure, or at the very least has to keep checking if the structure has changed and coping with that. This means that the programmer generally has to construct a lot of loops over, say, child elements, and also check for existence a lot. There&#8217;s a slight anomaly, in that you could think of the event-driven aspect of Javascript as being functional&#8212;it turns the user&#8217;s input through clicks, mouse movement and keypresses into browser behaviour, remaining otherwise dormant&#8212;but by and large Javascript&#8217;s meat is procedural.</p>
<p>There&#8217;s two routes you can take at this point. You can either say that, because Javascript is meant to be object-oriented, then the best way to work with it is to augment its functionality and simplify object construction, but ultimately leave it as that: if it weren&#8217;t functional, then it wouldn&#8217;t be Javascript. Or you can say that, given the advantages that XSL and CSS gain by being functional&#8212;a kind of &#8220;safety&#8221;, some scaleability, and document-driven processing&#8212;Javascript might want to have a piece of that too, while sacrificing some of its object orientation.</p>
<p>The first route is entirely laudable, because some problems are object-shaped and some are function-shaped. But, in the spirit of adventure, let&#8217;s investigate the second route for a while: pack some sandwiches and get some stout shoes on, and I&#8217;ll meet you in <a href="/blog/?p=110">my next blog post</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jpstacey.info/blog/2007/12/18/pretending-that-javascript-is-xsl-part-1-xsl-css-and-js-side-by-side/feed/</wfw:commentRss>
		</item>
	</channel>
</rss>
