<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss 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" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">

<channel>
	<title>Ajax Bestiary</title>
	
	<link>http://www.ajaxbestiary.com</link>
	<description>AJAX Development, News, Techniques &amp; More</description>
	<lastBuildDate>Wed, 21 Oct 2009 01:25:43 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.4</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<image><link>http://www.ajaxbestiary.com</link><url>http://www.ajaxbestiary.com/logoblock.png</url><title>Ajax Bestiary Logo</title></image><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" href="http://feeds.feedburner.com/AjaxBestiary" type="application/rss+xml" /><feedburner:emailServiceId>AjaxBestiary</feedburner:emailServiceId><feedburner:feedburnerHostname>http://feedburner.google.com</feedburner:feedburnerHostname><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com" /><item>
		<title>Cross Site Scripting – the new old way</title>
		<link>http://feedproxy.google.com/~r/AjaxBestiary/~3/mZoE7ggH8GQ/</link>
		<comments>http://www.ajaxbestiary.com/2009/10/20/cross-site-scripting-the-new-old-way/#comments</comments>
		<pubDate>Tue, 20 Oct 2009 23:02:35 +0000</pubDate>
		<dc:creator>Dave Mahon</dc:creator>
				<category><![CDATA[Article]]></category>
		<category><![CDATA[Tutorial]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[DOM]]></category>
		<category><![CDATA[XHTML]]></category>
		<category><![CDATA[XSS]]></category>

		<guid isPermaLink="false">http://www.ajaxbestiary.com/?p=361</guid>
		<description><![CDATA[

Cross Site Scripting (XSS) is a big security no-no. It’s never supposed to happen, because as we all know, any script operating within your page has full access to the entire DOM of the page.
Then again, there is so much functionality that we want to implement without reinventing the wheel. Marketing departments want to use [...]]]></description>
			<content:encoded><![CDATA[
<!-- google_ad_section_start -->
<p>Cross Site Scripting (XSS) is a big security no-no. It’s never supposed to happen, because as we all know, any script operating within your page has full access to the entire DOM of the page.</p>
<p>Then again, there is so much functionality that we want to implement without reinventing the wheel. Marketing departments want to use third-party tracking tools. The IT folks want to distribute the load for our network heavy site across the third-level domains www.domain.com, static.domain.com and data.domain.com. And users want more functionality than we can hope to provide on our own.</p>
<p>So resigned to the reality that XSS is a legitimate necessity, we need a way to do it. The old way (as far back as the mid-90’s, in fact) was straightforward:</p>
<p><code></p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;">document.<span style="color: #000066; font-weight: bold;">write</span><span style="color: #009900;">&#40;</span>‘<span style="color: #339933;">&lt;</span>script language<span style="color: #339933;">=</span>”JavaScript” type<span style="color: #339933;">=</span>”text<span style="color: #339933;">/</span>javascript” src<span style="color: #339933;">=</span>”http<span style="color: #339933;">:</span><span style="color: #006600; font-style: italic;">//data.domain.com/myscript.js”&gt;&lt;/script&gt;’);</span></pre></div></div>

<p></code></p>
<p>This is of course problematic as it treats DOM nodes improperly and may not even get processed by modern browsers. Instead, jQuery provides access to JSONP which will do the same thing – insert a new script node in the DOM – but do it in an XHTML compliant way.</p>
<p>Accessing JSONP is pretty straightforward:</p>
<p><code</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;">$.<span style="color: #660066;">getJSON</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;http://data.domain.com/myscript&amp;callback=?”, inPageFunction);</span></pre></div></div>

<p></code></p>
<p>The key bit is &amp;callback=? – this causes jQuery to insert a script node into the DOM, which is then immediately executed and returned to the callback function, inPageFunction, like so:</p>
<p><code></p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;">inPageFunction<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#123;</span>data<span style="color: #339933;">:</span><span style="color: #3366CC;">&quot;foo&quot;</span><span style="color: #339933;">;</span><span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span></pre></div></div>

<p></code></p>
<p>If you forget &amp;callback=? you’ll get the error Access to restricted URI denied. And yes, since we’re inserting a script node, we’re limited to GET requests. And if the call fails, you’ll simply get nothing back – no useful error messages.</p>
<p>Further, the next generation of browsers is coming out with integrated support for cross site XMLHttpRequest, but since when have we not had to code to support multiple versions of browsers?</p>
<p>There are loads of good guides to expand your knowledge:</p>
<ul>
<li><a href="http://www.insideria.com/2009/03/what-in-the-heck-is-jsonp-and.html">What the heck is JSONP and why should you use it?</a></li>
<li><a href="http://niryariv.wordpress.com/2009/05/05/jsonp-quickly/">JSONP, Quickly</a></li>
<li><a href="http://www.ibm.com/developerworks/library/wa-aj-jsonp1/">Cross-domain communications with JSONP</a>, Part 1</li>
<li><a href="http://www.ibm.com/developerworks/web/library/wa-aj-jsonp2/index.html">Cross-domain communications with JSONP</a>, Part 2</li>
</ul>
<p><img src="http://www.ajaxbestiary.com/?voyeur=1"></p>
<!-- google_ad_section_end -->
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/AjaxBestiary?a=mZoE7ggH8GQ:cHFV_heMU-s:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/AjaxBestiary?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/AjaxBestiary?a=mZoE7ggH8GQ:cHFV_heMU-s:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/AjaxBestiary?d=7Q72WNTAKBA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/AjaxBestiary?a=mZoE7ggH8GQ:cHFV_heMU-s:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/AjaxBestiary?i=mZoE7ggH8GQ:cHFV_heMU-s:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/AjaxBestiary?a=mZoE7ggH8GQ:cHFV_heMU-s:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/AjaxBestiary?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/AjaxBestiary?a=mZoE7ggH8GQ:cHFV_heMU-s:l6gmwiTKsz0"><img src="http://feeds.feedburner.com/~ff/AjaxBestiary?d=l6gmwiTKsz0" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/AjaxBestiary?a=mZoE7ggH8GQ:cHFV_heMU-s:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/AjaxBestiary?i=mZoE7ggH8GQ:cHFV_heMU-s:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/AjaxBestiary/~4/mZoE7ggH8GQ" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.ajaxbestiary.com/2009/10/20/cross-site-scripting-the-new-old-way/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		<feedburner:origLink>http://www.ajaxbestiary.com/2009/10/20/cross-site-scripting-the-new-old-way/</feedburner:origLink></item>
		<item>
		<title>Using the jQuery data method as a local datastore</title>
		<link>http://feedproxy.google.com/~r/AjaxBestiary/~3/pPgznsLc5fs/</link>
		<comments>http://www.ajaxbestiary.com/2009/10/15/using-the-jquery-data-method-as-a-local-datastore/#comments</comments>
		<pubDate>Thu, 15 Oct 2009 23:37:37 +0000</pubDate>
		<dc:creator>Dave Mahon</dc:creator>
				<category><![CDATA[Article]]></category>
		<category><![CDATA[Tutorial]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[Development]]></category>

		<guid isPermaLink="false">http://www.ajaxbestiary.com/?p=346</guid>
		<description><![CDATA[

At some point, we all have to store datasets on the client. We can clutter the namespace with ever more variables and try really hard to avoid collisions. We can cram variables into some local object that we’re using in the normal execution of our script anyway. We can attach custom attributes to HTML nodes, [...]]]></description>
			<content:encoded><![CDATA[
<!-- google_ad_section_start -->
<p>At some point, we all have to store datasets on the client. We can clutter the namespace with ever more variables and try really hard to avoid collisions. We can cram variables into some local object that we’re using in the normal execution of our script anyway. We can attach custom attributes to HTML nodes, violating the sacrosanct purity of XHTML.</p>
<p>Or we can attach the document-specific variables, in script (thus keeping those automated validators happy), to the document itself. This fairly intuitive approach has not been given the notice it deserves.</p>
<p>Some advantages:</p>
<ol>
<li><span style="color: #333333;">Arbitrary value names can be assigned and we can basically assign as many of these variables as we want.</span></li>
<li><span style="color: #333333;">They can be applied to anything jQuery can access, meaning that we can rapidly assign values to entire sets of DOM nodes without having to add CSS classes or clutter the markup.</span></li>
<li><span style="color: #333333;">They can be dynamically added, accessed, changed and removed at will, without network transfers.</span></li>
</ol>
<p><span style="color: #333333;">There is the disadvantage that they are not persistent across page loads, but we’ve lived with that problem for a long, long time, haven’t we?</span></p>
<p>So how do we use this handy method? <a href="http://docs.jquery.com/Internals/jQuery.data">The documentation</a> is pretty clear cut, but I’ll give a slightly more grounded example:</p>
<p>My HTML is very simplistic in this example:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
</pre></td><td class="code"><pre class="html4strict" style="font-family:monospace;"><span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">body</span>&gt;</span>
 <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">div</span>&gt;</span>
  <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">span</span> <span style="color: #000066;">id</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;stats&quot;</span>&gt;&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">span</span>&gt;</span>
  <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">button</span> <span style="color: #000066;">id</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;add&quot;</span>&gt;</span>Add Data Point<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">button</span>&gt;</span>
  <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">button</span> <span style="color: #000066;">id</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;reset&quot;</span>&gt;</span>Reset Set<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">button</span>&gt;</span>
 <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">div</span>&gt;</span>
 <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">div</span> <span style="color: #000066;">id</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;data&quot;</span>&gt;&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">div</span>&gt;</span>
<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">body</span>&gt;</span></pre></td></tr></table></div>

<p>The JavaScript is similarly intuitive:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
</pre></td><td class="code"><pre class="javascript" style="font-family:monospace;">appExample <span style="color: #339933;">=</span> <span style="color: #009900;">&#123;</span>
 addDataPoint<span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
  <span style="color: #003366; font-weight: bold;">var</span> dat <span style="color: #339933;">=</span> <span style="color: #000066; font-weight: bold;">this</span>.<span style="color: #660066;">getDataSet</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  dat<span style="color: #009900;">&#91;</span>dat.<span style="color: #660066;">length</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> Math.<span style="color: #660066;">floor</span><span style="color: #009900;">&#40;</span>Math.<span style="color: #660066;">random</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">*</span><span style="color: #CC0000;">101</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  $<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'#data'</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">data</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'points'</span><span style="color: #339933;">,</span> dat<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
 <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span>
 resetDataSet<span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
  $<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'#data'</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">removeData</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'points'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
 <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span>
 dataSize<span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
  <span style="color: #003366; font-weight: bold;">var</span> dat <span style="color: #339933;">=</span> <span style="color: #000066; font-weight: bold;">this</span>.<span style="color: #660066;">getDataSet</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #000066; font-weight: bold;">return</span> dat.<span style="color: #660066;">length</span><span style="color: #339933;">;</span>
 <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span>
 getDataSet<span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
  <span style="color: #003366; font-weight: bold;">var</span> dat <span style="color: #339933;">=</span> $<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'#data'</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">data</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'points'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>undefined <span style="color: #339933;">==</span> dat<span style="color: #009900;">&#41;</span> <span style="color: #000066; font-weight: bold;">return</span> <span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
  <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>Array <span style="color: #339933;">!=</span> dat.<span style="color: #660066;">constructor</span><span style="color: #009900;">&#41;</span> <span style="color: #000066; font-weight: bold;">return</span> <span style="color: #009900;">&#91;</span>dat<span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
  <span style="color: #000066; font-weight: bold;">return</span> dat<span style="color: #339933;">;</span>
 <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span>
 updateDisplay<span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
  $<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'#stats'</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">text</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'Data Points: '</span> <span style="color: #339933;">+</span> <span style="color: #009900;">&#40;</span>lim <span style="color: #339933;">=</span> <span style="color: #000066; font-weight: bold;">this</span>.<span style="color: #660066;">dataSize</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #003366; font-weight: bold;">var</span> tmp <span style="color: #339933;">=</span> <span style="color: #3366CC;">''</span><span style="color: #339933;">;</span>
  <span style="color: #003366; font-weight: bold;">var</span> dat <span style="color: #339933;">=</span> <span style="color: #000066; font-weight: bold;">this</span>.<span style="color: #660066;">getDataSet</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #000066; font-weight: bold;">for</span> <span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">var</span> i <span style="color: #339933;">=</span> <span style="color: #CC0000;">0</span><span style="color: #339933;">;</span> i <span style="color: #339933;">&lt;</span> lim<span style="color: #339933;">;</span> i<span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
   tmp <span style="color: #339933;">+=</span> dat<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
   <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>i <span style="color: #339933;">&lt;</span> lim <span style="color: #339933;">-</span> <span style="color: #CC0000;">1</span><span style="color: #009900;">&#41;</span> tmp <span style="color: #339933;">+=</span> <span style="color: #3366CC;">','</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
  $<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'#data'</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">text</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'['</span> <span style="color: #339933;">+</span> tmp <span style="color: #339933;">+</span> <span style="color: #3366CC;">']'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
 <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
$<span style="color: #009900;">&#40;</span>document<span style="color: #009900;">&#41;</span>.<span style="color: #660066;">ready</span><span style="color: #009900;">&#40;</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
 appExample.<span style="color: #660066;">updateDisplay</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
 $<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'#add'</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">bind</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'click'</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>e<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
  appExample.<span style="color: #660066;">addDataPoint</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  appExample.<span style="color: #660066;">updateDisplay</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
 <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
 $<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'#reset'</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">bind</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'click'</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>e<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
  appExample.<span style="color: #660066;">resetDataSet</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  appExample.<span style="color: #660066;">updateDisplay</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
 <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></td></tr></table></div>

<p>In this case, I’m storing everything as an array in points. While I’m storing randomly generated integers, you can just as easily store entire objects, opening the possibility of a JSON solution.</p>
<p>Note that we can identify those objects lacking the chosen dynamic attribute by <em>calling it</em> and testing for undefined.</p>
<p><img src="http://www.ajaxbestiary.com/?voyeur=1"></p>
<!-- google_ad_section_end -->
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/AjaxBestiary?a=pPgznsLc5fs:ECT1iqAr_Ro:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/AjaxBestiary?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/AjaxBestiary?a=pPgznsLc5fs:ECT1iqAr_Ro:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/AjaxBestiary?d=7Q72WNTAKBA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/AjaxBestiary?a=pPgznsLc5fs:ECT1iqAr_Ro:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/AjaxBestiary?i=pPgznsLc5fs:ECT1iqAr_Ro:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/AjaxBestiary?a=pPgznsLc5fs:ECT1iqAr_Ro:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/AjaxBestiary?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/AjaxBestiary?a=pPgznsLc5fs:ECT1iqAr_Ro:l6gmwiTKsz0"><img src="http://feeds.feedburner.com/~ff/AjaxBestiary?d=l6gmwiTKsz0" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/AjaxBestiary?a=pPgznsLc5fs:ECT1iqAr_Ro:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/AjaxBestiary?i=pPgznsLc5fs:ECT1iqAr_Ro:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/AjaxBestiary/~4/pPgznsLc5fs" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.ajaxbestiary.com/2009/10/15/using-the-jquery-data-method-as-a-local-datastore/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.ajaxbestiary.com/2009/10/15/using-the-jquery-data-method-as-a-local-datastore/</feedburner:origLink></item>
		<item>
		<title>The future of Ajax Bestiary</title>
		<link>http://feedproxy.google.com/~r/AjaxBestiary/~3/JMvQ-jp2Bu8/</link>
		<comments>http://www.ajaxbestiary.com/2009/10/07/the-future-of-ajax-bestiary/#comments</comments>
		<pubDate>Thu, 08 Oct 2009 02:41:34 +0000</pubDate>
		<dc:creator>Don Albrecht</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[Meta]]></category>
		<category><![CDATA[Update]]></category>

		<guid isPermaLink="false">http://www.ajaxbestiary.com/?p=344</guid>
		<description><![CDATA[

One of my colleagues pointed out the rather high ranking of Ajax Bestiary in his Net News Wire Dinosaur Report today.  While 2nd place isn&#8217;t the worst possible ranking, It demonstrates that I haven&#8217;t posted anything in quite a while.
I&#8217;ve had the best of intentions to resume blogging, but time concerns and the high level [...]]]></description>
			<content:encoded><![CDATA[
<!-- google_ad_section_start -->
<p>One of my colleagues pointed out the rather high ranking of Ajax Bestiary in his Net News Wire Dinosaur Report today.  While 2nd place isn&#8217;t the worst possible ranking, It demonstrates that I haven&#8217;t posted anything in quite a while.</p>
<p>I&#8217;ve had the best of intentions to resume blogging, but time concerns and the high level of secrecy around my current projects have both pushed me away from regular blog updates.  I&#8217;ll be making a bigger effort in the future, but I&#8217;ve also recruited a second author for the blog.  David Mahon is a talented front-end web developer who has agreed to produce regular content for AB.</p>
<p>You can expect Dave&#8217;s first post sometime in the next few days.</p>
<p><img src="http://www.ajaxbestiary.com/?voyeur=1"></p>
<!-- google_ad_section_end -->
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/AjaxBestiary?a=JMvQ-jp2Bu8:fm4mwGFTgiE:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/AjaxBestiary?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/AjaxBestiary?a=JMvQ-jp2Bu8:fm4mwGFTgiE:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/AjaxBestiary?d=7Q72WNTAKBA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/AjaxBestiary?a=JMvQ-jp2Bu8:fm4mwGFTgiE:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/AjaxBestiary?i=JMvQ-jp2Bu8:fm4mwGFTgiE:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/AjaxBestiary?a=JMvQ-jp2Bu8:fm4mwGFTgiE:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/AjaxBestiary?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/AjaxBestiary?a=JMvQ-jp2Bu8:fm4mwGFTgiE:l6gmwiTKsz0"><img src="http://feeds.feedburner.com/~ff/AjaxBestiary?d=l6gmwiTKsz0" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/AjaxBestiary?a=JMvQ-jp2Bu8:fm4mwGFTgiE:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/AjaxBestiary?i=JMvQ-jp2Bu8:fm4mwGFTgiE:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/AjaxBestiary/~4/JMvQ-jp2Bu8" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.ajaxbestiary.com/2009/10/07/the-future-of-ajax-bestiary/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		<feedburner:origLink>http://www.ajaxbestiary.com/2009/10/07/the-future-of-ajax-bestiary/</feedburner:origLink></item>
		<item>
		<title>Converting Between Wiki Markup &amp; HTML with Prototype: Part 2 ListsAt</title>
		<link>http://feedproxy.google.com/~r/AjaxBestiary/~3/YBZ_877eA04/</link>
		<comments>http://www.ajaxbestiary.com/2008/12/19/converting-between-wiki-markup-html-with-prototype-part-2-listsat/#comments</comments>
		<pubDate>Fri, 19 Dec 2008 15:00:26 +0000</pubDate>
		<dc:creator>Don Albrecht</dc:creator>
				<category><![CDATA[Article]]></category>
		<category><![CDATA[Tutorial]]></category>
		<category><![CDATA[prototype]]></category>
		<category><![CDATA[Convert]]></category>
		<category><![CDATA[Curry]]></category>
		<category><![CDATA[Wiki]]></category>

		<guid isPermaLink="false">http://www.ajaxbestiary.com/?p=337</guid>
		<description><![CDATA[

At the end of part 1 of the series, the system could easily handle direct replacement of certain html entities with their wiki markup counterparts.  Unfortunately this was a pretty limited implementation that could only handle those entities that had a direct, symmetrical relationship with html.  In the case of lists, we have to keep track of [...]]]></description>
			<content:encoded><![CDATA[
<!-- google_ad_section_start -->
<p>At the end of part 1 of the series, the system could easily handle direct replacement of certain html entities with their wiki markup counterparts.  Unfortunately this was a pretty limited implementation that could only handle those entities that had a direct, symmetrical relationship with html.  In the case of lists, we have to keep track of depth and better cleanup the input text.  We also need to enforce default behavior on the input stream.</p>
<p>Since lists are dependent on dedicated whitespace as part of their markup, we need to clear out all unnecessary white space from the html before processing it.  To do this, we simply replace all whitespace characters with an innocuous single space to remove any extra new lines.</p>
<p><code>$(textNode).innerHTML = $(textNode).innerHTML.gsub( '\s', '' );</code></p>
<p>Next we need to cleanup the recursion.  Since we need to know significantly more about the given node to properly assess it.  We can replace the Prototype templates with simple curried function calls and migrate the recursion to the curried methods.<br />
<code><br />
var ConverterTable = {<br />
strong: Converter.curry("'''", null, true),<br />
b:  Converter.curry("'''" , null, true),<br />
em: Converter.curry( "''"  , null, true ),<br />
i:  Converter.curry( "''"  , null, true ),<br />
h1: Converter.curry( '='  , null, false ),<br />
h2: Converter.curry( '=='  , null, false ),<br />
h3: Converter.curry( '==='  , null, false ),<br />
h4: Converter.curry( '===='  , null, false ),<br />
h5: Converter.curry( '====='  , null, false ),<br />
h6: Converter.curry( '======' , null, false ),<br />
ul: Converter.curry('', {li:Converter.curry(['* ', ''], null, false)}, false),<br />
ol: Converter.curry('', {li:Converter.curry(['# ', ''], null, false)}, false),<br />
p:  Converter.curry(['','\n'], null, false)<br />
};<br />
</code><br />
The parameters passed into the individual rules are<br />
The Markup String or an array of strings for start and end tags<br />
An optional library of child rules.  These rules will be applied to any children of the given node before the default rules are applied.<br />
An indication as to the ‘inline-ability’ of the given tag.  This controls the bracketing of the resulting markup with ‘\n’ characters.</p>
<p>The modified Converter now looks to apply rules in the following order<br />
If the node is marked as a stopping point, no recursion proceeds on the branch.<br />
If any over-ridden child rules exist for the given tag, those rules are applied and a memo is passed on to child nodes to denote the depth of the recursion.<br />
Any default rules are processed as per the earlier versions of the code.  Note.  A prototype template is no longer used in favor of simple string construction.<br />
The node itself is removed from the DOM.</p>
<p><code>function Converter( markupString, nestedRules, inline, textNode, memo ){</code></p>
<p>var startString, endString;<br />
inline = inline ? &#8221; : &#8216;\n&#8217;;<br />
memo = memo ? memo : &#8221;;<br />
var children =  textNode.childElements();</p>
<p>if( typeof markupString == &#8216;object&#8217;){<br />
startString = inline + markupString[0];<br />
endString = markupString[1] + inline;<br />
} else {<br />
startString = inline + markupString;<br />
endString = markupString + inline;<br />
}</p>
<p>for( i in children){<br />
if( typeof children[i] != &#8216;function&#8217;){<br />
if( nestedRules &amp;&amp; typeof nestedRules[children[i].tagName.toLowerCase()] == &#8216;function&#8217;){<br />
startString =  memo.strip() + startString;<br />
nestedRules[ children[i].tagName.toLowerCase() ]( children[i], startString);<br />
} else if( typeof ConverterTable[children[i].tagName.toLowerCase()] == &#8216;function&#8217;){<br />
ConverterTable[children[i].tagName.toLowerCase() ](children[i]);<br />
} else { Converter( &#8221;, nestedRules, true, children[i]), memo }<br />
}<br />
}<br />
textNode.replace(  startString + textNode.innerHTML + endString  );<br />
}</p>
<p><img src="http://www.ajaxbestiary.com/?voyeur=1"></p>
<!-- google_ad_section_end -->
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/AjaxBestiary?a=YBZ_877eA04:nmpu79hqyKc:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/AjaxBestiary?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/AjaxBestiary?a=YBZ_877eA04:nmpu79hqyKc:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/AjaxBestiary?d=7Q72WNTAKBA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/AjaxBestiary?a=YBZ_877eA04:nmpu79hqyKc:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/AjaxBestiary?i=YBZ_877eA04:nmpu79hqyKc:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/AjaxBestiary?a=YBZ_877eA04:nmpu79hqyKc:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/AjaxBestiary?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/AjaxBestiary?a=YBZ_877eA04:nmpu79hqyKc:l6gmwiTKsz0"><img src="http://feeds.feedburner.com/~ff/AjaxBestiary?d=l6gmwiTKsz0" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/AjaxBestiary?a=YBZ_877eA04:nmpu79hqyKc:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/AjaxBestiary?i=YBZ_877eA04:nmpu79hqyKc:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/AjaxBestiary/~4/YBZ_877eA04" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.ajaxbestiary.com/2008/12/19/converting-between-wiki-markup-html-with-prototype-part-2-listsat/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		<feedburner:origLink>http://www.ajaxbestiary.com/2008/12/19/converting-between-wiki-markup-html-with-prototype-part-2-listsat/</feedburner:origLink></item>
		<item>
		<title>Converting Between Wiki Markup &amp; HTML with Prototype</title>
		<link>http://feedproxy.google.com/~r/AjaxBestiary/~3/upCeDoXewuI/</link>
		<comments>http://www.ajaxbestiary.com/2008/12/18/converting-between-wiki-markup-html-with-prototype/#comments</comments>
		<pubDate>Thu, 18 Dec 2008 15:00:07 +0000</pubDate>
		<dc:creator>Don Albrecht</dc:creator>
				<category><![CDATA[Article]]></category>
		<category><![CDATA[Tools]]></category>
		<category><![CDATA[Tutorial]]></category>
		<category><![CDATA[prototype]]></category>
		<category><![CDATA[Conversion]]></category>
		<category><![CDATA[Wiki]]></category>

		<guid isPermaLink="false">http://www.ajaxbestiary.com/?p=334</guid>
		<description><![CDATA[

Wiki&#8217;s are amazing and powerful tools, unfortunately their dependence on specialized markup creates a huge barrier to their general adoption in many organizations.  This is a first step at building a wysiwyg editor for wiki markup.  While I will be focussing on the syntax unique to the popular MediaWiki platform, these techniques should be applicable [...]]]></description>
			<content:encoded><![CDATA[
<!-- google_ad_section_start -->
<p>Wiki&#8217;s are amazing and powerful tools, unfortunately their dependence on specialized markup creates a huge barrier to their general adoption in many organizations.  This is a first step at building a wysiwyg editor for wiki markup.  While I will be focussing on the syntax unique to the popular MediaWiki platform, these techniques should be applicable to any wiki system.</p>
<p>The general flow of the converter is as follows:</p>
<ol>
<li>Converter is passed the root node of an html fragment to translate.</li>
<li>Converter recurses through each of the child nodes and converts them.</li>
<li>Root node tag is replaced with wiki markup.</li>
</ol>
<p>There&#8217;s really only 2 key components involved in this first pass. A converter object and the recursive method.</p>
<h3>The Converter Object</h3>
<p>The converter object is little more than a collection of name value pairs.  The name corresponds to an html tag.  The value is a Prototype template to use in the direct replacement of the given node. By convention we&#8217;ll write all of the tag names for the converter object in lower case.<br />
<code><br />
var Converter = {<br />
strong: new Template("'''#{body}'''"),<br />
b:  new Template("'''#{body}'''"),<br />
em: new Template("''#{body}''"),<br />
i:  new Template("''#{body}''"),<br />
h1: new Template('=#{body}='),<br />
h2: new Template('===#{body}=='),</code><br />
h3: new Template(&#8217;===#{body}===&#8217;),<br />
h4: new Template(&#8217;====#{body}====&#8217;),<br />
h5: new Template(&#8217;=====#{body}=====&#8217;),<br />
h6: new Template(&#8217;======#{body}======&#8217;)  }</p>
<h3>The Converter Function</h3>
<p>The Converter function always performs 2 checks before attempting to convert a given node.  First it ensures that the node is in fact a node and not a stray function from the Prototype enhanced object.  Next it verifies that a converter exists for the tag.  The toLowerCase() on the tagName is necessary due to the inconsistent behavior browsers demonstrate with this attribute.  While all browsers return the variable in all caps for traditional html, they are not reliable about returning lower case values for xhtml markup.</p>
<p><code>function convertToWiki( textNode ){<br />
//make sure textNode isn't a function on the object<br />
if( typeof textNode != 'function'){</code></p>
<p><code>//provide a way to stop execution on select sub trees<br />
if( !textNode.hasClassName( 'stop')){<br />
$(textNode).childElements().each( convertToWiki );<br />
}</code></p>
<p><code>//make sure a converter exists for the given tag<br />
if( liteConverter[ textNode.tagName.toLowerCase() ] ){</code></p>
<p><code> </code></p>
<p><code>//replace the text node with a converted version of itself<br />
textNode.replace(	liteConverter[textNode.tagName.toLowerCase()]<br />
.evaluate({body:textNode.innerHTML}));<br />
} } }</code></p>
<p><img src="http://www.ajaxbestiary.com/?voyeur=1"></p>
<!-- google_ad_section_end -->
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/AjaxBestiary?a=upCeDoXewuI:6CLKBqzi7KA:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/AjaxBestiary?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/AjaxBestiary?a=upCeDoXewuI:6CLKBqzi7KA:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/AjaxBestiary?d=7Q72WNTAKBA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/AjaxBestiary?a=upCeDoXewuI:6CLKBqzi7KA:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/AjaxBestiary?i=upCeDoXewuI:6CLKBqzi7KA:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/AjaxBestiary?a=upCeDoXewuI:6CLKBqzi7KA:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/AjaxBestiary?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/AjaxBestiary?a=upCeDoXewuI:6CLKBqzi7KA:l6gmwiTKsz0"><img src="http://feeds.feedburner.com/~ff/AjaxBestiary?d=l6gmwiTKsz0" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/AjaxBestiary?a=upCeDoXewuI:6CLKBqzi7KA:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/AjaxBestiary?i=upCeDoXewuI:6CLKBqzi7KA:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/AjaxBestiary/~4/upCeDoXewuI" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.ajaxbestiary.com/2008/12/18/converting-between-wiki-markup-html-with-prototype/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.ajaxbestiary.com/2008/12/18/converting-between-wiki-markup-html-with-prototype/</feedburner:origLink></item>
		<item>
		<title>A Fast &amp; Easy Prototype Based Curry</title>
		<link>http://feedproxy.google.com/~r/AjaxBestiary/~3/RHsR_SoXzoY/</link>
		<comments>http://www.ajaxbestiary.com/2008/12/17/a-fast-easy-prototype-based-curry/#comments</comments>
		<pubDate>Wed, 17 Dec 2008 15:44:20 +0000</pubDate>
		<dc:creator>Don Albrecht</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://www.ajaxbestiary.com/?p=338</guid>
		<description><![CDATA[

in Javascript the Good Parts, Douglas Crockford presents a simple method to curry functions.  It&#8217;s a great tool that allows you to build functions with arguments predefined in them dynamically.  In his implementation Array.splice &#38; an indirect method declaration is used.  In my version, I use prototype&#8217;s enhanced Array object &#38; a direct call to [...]]]></description>
			<content:encoded><![CDATA[
<!-- google_ad_section_start -->
<p>in <span style="text-decoration: underline;">Javascript the Good Parts</span>, Douglas Crockford presents a simple method to curry functions.  It&#8217;s a great tool that allows you to build functions with arguments predefined in them dynamically.  In his implementation Array.splice &amp; an indirect method declaration is used.  In my version, I use prototype&#8217;s enhanced Array object &amp; a direct call to the Function object to the same effect.</p>
<p>Function.curry = function() {<br />
var args = $A(arguments), that = this;<br />
return function() {<br />
return that.apply( null, args.concat(arguments));<br />
};<br />
};</p>
<p>I&#8217;ve been using this method for a few months now in both its prototype &amp; jquery forms and find it invaluable, especially when faced with a need to manipulate a large number of similar objects.</p>
<p><img src="http://www.ajaxbestiary.com/?voyeur=1"></p>
<!-- google_ad_section_end -->
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/AjaxBestiary?a=RHsR_SoXzoY:JoWRL3wEdMc:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/AjaxBestiary?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/AjaxBestiary?a=RHsR_SoXzoY:JoWRL3wEdMc:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/AjaxBestiary?d=7Q72WNTAKBA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/AjaxBestiary?a=RHsR_SoXzoY:JoWRL3wEdMc:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/AjaxBestiary?i=RHsR_SoXzoY:JoWRL3wEdMc:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/AjaxBestiary?a=RHsR_SoXzoY:JoWRL3wEdMc:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/AjaxBestiary?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/AjaxBestiary?a=RHsR_SoXzoY:JoWRL3wEdMc:l6gmwiTKsz0"><img src="http://feeds.feedburner.com/~ff/AjaxBestiary?d=l6gmwiTKsz0" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/AjaxBestiary?a=RHsR_SoXzoY:JoWRL3wEdMc:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/AjaxBestiary?i=RHsR_SoXzoY:JoWRL3wEdMc:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/AjaxBestiary/~4/RHsR_SoXzoY" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.ajaxbestiary.com/2008/12/17/a-fast-easy-prototype-based-curry/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.ajaxbestiary.com/2008/12/17/a-fast-easy-prototype-based-curry/</feedburner:origLink></item>
		<item>
		<title>WysiHat Prototype Based Rich Text Editor</title>
		<link>http://feedproxy.google.com/~r/AjaxBestiary/~3/WhqebMfp18k/</link>
		<comments>http://www.ajaxbestiary.com/2008/10/21/wysihat-prototype-based-rich-text-editor/#comments</comments>
		<pubDate>Tue, 21 Oct 2008 19:59:31 +0000</pubDate>
		<dc:creator>Don Albrecht</dc:creator>
				<category><![CDATA[prototype]]></category>
		<category><![CDATA[Editor]]></category>
		<category><![CDATA[WYSIWYG]]></category>

		<guid isPermaLink="false">http://www.ajaxbestiary.com/?p=330</guid>
		<description><![CDATA[

37 Signals has recently announced a new open source rich text editor built on protoype.
It&#8217;s a unique take on the Rich Text Editor that focuses on developers over the kitchen sink.
WysiHat is a WYSIWYG JavaScript framework that provides an extensible foundation to design your own rich text editor. WysiHat stays out of your way and leaves the [...]]]></description>
			<content:encoded><![CDATA[
<!-- google_ad_section_start -->
<p>37 Signals has recently announced a new open source rich text editor built on protoype.</p>
<p>It&#8217;s a unique take on the Rich Text Editor that focuses on developers over the kitchen sink.</p>
<blockquote><p>WysiHat is a <span>WYSIWYG</span> JavaScript framework that provides an extensible foundation to design your own rich text editor. WysiHat stays out of your way and leaves the UI design to you. Although WysiHat lets you get up and running with a few lines of code, the focus is on letting you customize it.</p></blockquote>
<p>Check it out here:<br />
<a href="http://github.com/37signals/wysihat/tree/master"> http://github.com/37signals/wysihat/tree/master</a></p>
<p>And Read the announcement here:<br />
<a href="http://www.37signals.com/svn/posts/1330-introducing-wysihat-an-eventually-better-open-source-wysiwyg-editor">Introducing WysiHat: An eventually better open source WYSIWYG editor</a></p>
<p><img src="http://www.ajaxbestiary.com/?voyeur=1"></p>
<!-- google_ad_section_end -->
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/AjaxBestiary?a=WhqebMfp18k:rVA6jNnYhVI:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/AjaxBestiary?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/AjaxBestiary?a=WhqebMfp18k:rVA6jNnYhVI:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/AjaxBestiary?d=7Q72WNTAKBA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/AjaxBestiary?a=WhqebMfp18k:rVA6jNnYhVI:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/AjaxBestiary?i=WhqebMfp18k:rVA6jNnYhVI:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/AjaxBestiary?a=WhqebMfp18k:rVA6jNnYhVI:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/AjaxBestiary?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/AjaxBestiary?a=WhqebMfp18k:rVA6jNnYhVI:l6gmwiTKsz0"><img src="http://feeds.feedburner.com/~ff/AjaxBestiary?d=l6gmwiTKsz0" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/AjaxBestiary?a=WhqebMfp18k:rVA6jNnYhVI:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/AjaxBestiary?i=WhqebMfp18k:rVA6jNnYhVI:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/AjaxBestiary/~4/WhqebMfp18k" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.ajaxbestiary.com/2008/10/21/wysihat-prototype-based-rich-text-editor/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		<feedburner:origLink>http://www.ajaxbestiary.com/2008/10/21/wysihat-prototype-based-rich-text-editor/</feedburner:origLink></item>
		<item>
		<title>YUI Calendar Popup from Text Input</title>
		<link>http://feedproxy.google.com/~r/AjaxBestiary/~3/YbxtwPyYI9Y/</link>
		<comments>http://www.ajaxbestiary.com/2008/10/19/yui-calendar-popup-from-text-input/#comments</comments>
		<pubDate>Mon, 20 Oct 2008 01:05:20 +0000</pubDate>
		<dc:creator>Don Albrecht</dc:creator>
				<category><![CDATA[Widget]]></category>
		<category><![CDATA[YUI]]></category>
		<category><![CDATA[calendar]]></category>

		<guid isPermaLink="false">http://www.ajaxbestiary.com/?p=327</guid>
		<description><![CDATA[

I needed a way to provide my users with a date picker that was automatically provided when a text area received focus.  I was eager to use the excellent YUI calendar as a starting point, but the provided documentation didn&#8217;t provide a solid example for this type of implementation.
Dav Glass has provided a solid example [...]]]></description>
			<content:encoded><![CDATA[
<!-- google_ad_section_start -->
<p>I needed a way to provide my users with a date picker that was automatically provided when a text area received focus.  I was eager to use the excellent <a title="Yui Calendar Documentation" href="http://developer.yahoo.com/yui/calendar/">YUI calendar</a> as a starting point, but the provided documentation didn&#8217;t provide a solid example for this type of implementation.</p>
<p>Dav Glass has provided a solid example of the<a href="http://blog.davglass.com/files/yui/cal2/"> Calendar tied to a text input</a>. But, his example is highly dependent on the text input having specific ids.  This doesn&#8217;t take advantage of YUI&#8217;s excellent Selector library really didn&#8217;t meet my need for a simple universal solution.</p>
<h2><span style="font-weight: normal;">K</span>ey Requirements:</h2>
<ol>
<li>Progressive Enhancement (No inline javascript)</li>
<li>Yui based</li>
<li>Universal implementation across all pages in a site.</li>
<li>Support for multiple date inputs on a page.</li>
</ol>
<h2>Getting Started:</h2>
<div>The bulk of the code used is pretty solidly Dav&#8217;s I&#8217;ve simply replaced all of the hard coded references to dynamically generated targets and moved from hard coded ID&#8217;s for the target fields to a css class.  Lastly, I&#8217;ve added a &#8220;activeCal&#8221; class to the currently active target input so that one calendar can be recycled across multiple text areas on the page.</div>
<h2>Source:</h2>
<p><code></p>
<div>var cal1;</div>
<div>var over_cal = false;</div>
<div>function transmogCals() {</div>
<div>    cal1 = new YAHOO.widget.Calendar("cal1","cal1Container");</div>
<div>    cal1.selectEvent.subscribe(getDate, cal1, true);</div>
<div>    cal1.renderEvent.subscribe(setupListeners, cal1, true);</div>
<div>    var pickers =  YAHOO.util.Selector.query('.date-picker'); </div>
<div>for( i in pickers){</div>
<div>    YAHOO.util.Event.addListener(pickers[i], 'focus', showCal);</div>
<div>    YAHOO.util.Event.addListener(pickers[i], 'blur', hideCal);</div>
<div>    }</div>
<div>cal1.render();</div>
<div>}</div>
<div>function setupListeners() {</div>
<div>    YAHOO.util.Event.addListener('cal1Container', 'mouseover', overCal);</div>
<div>    YAHOO.util.Event.addListener('cal1Container', 'mouseout', outCal);</div>
<div>}</div>
<div>function getDate() {</div>
<div>        var calDate = this.getSelectedDates()[0];</div>
<div>        calDate = (calDate.getMonth() + 1) + '/' + calDate.getDate() + '/' + calDate.getFullYear();</div>
<div>        YAHOO.util.Selector.query('.activeCal')[0].value = calDate;</div>
<div>        over_cal = false;</div>
<div>        hideCal();</div>
<div>}</div>
<div>function showCal(e, targ) {</div>
<div>    var xy = YAHOO.util.Dom.getXY(this);</div>
<div>    var el = new YAHOO.util.Element(this); </div>
<div>    el.addClass('activeCal');</div>
<div>    var date = this.value;</div>
<div>    if (date) {</div>
<div>        cal1.cfg.setProperty('selected', date);</div>
<div>        cal1.cfg.setProperty('pagedate', new Date(date), true);</div>
<div>        cal1.render();</div>
<div>    }</div>
<div>    YAHOO.util.Dom.setStyle('cal1Container', 'display', 'block');</div>
<div>    xy[1] = xy[1] + 20;</div>
<div>    YAHOO.util.Dom.setXY('cal1Container', xy);</div>
<div>}</div>
<div>function hideCal() {</div>
<div>    if (!over_cal) {</div>
<div>         var el = new YAHOO.util.Element(this); </div>
<div>        el.removeClass('activeCal');</div>
<div>        YAHOO.util.Dom.setStyle('cal1Container', 'display', 'none');</div>
<div>    }</div>
<div>}</div>
<div>function overCal() {</div>
<div>    over_cal = true;</div>
<div>}</div>
<div>function outCal() {</div>
<div>    over_cal = false;</div>
<div>}</div>
<div>YAHOO.util.Event.addListener(window, 'load', transmogCals);</div>
<p></code></p>
<p> </p>
<h2>Adding it to your page</h2>
<p>Integrating the code into the page is VERY easy.</p>
<p>In the header of the page add the following css includes.</p>
<pre>&lt;link rel="stylesheet" type="text/css" href="http://yui.yahooapis.com/combo?2.6.0/build/calendar/assets/skins/sam/calendar.css"&gt;</pre>
<div><span>In the footer add the following script include and include the date-picker.js file</span></div>
<div>
<table class="dp-xml" border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td class="line2"><span class="tag">&lt;</span><span>script </span><span class="attribute">type</span><span>=</span><span class="attribute-value">&#8220;text/javascript&#8221;</span><span> </span><span class="attribute">src</span><span>=</span><span class="attribute-value">&#8220;http://yui.yahooapis.com/combo?2.6.0/build/yahoo-dom-event/yahoo-dom-event.js&amp;2.6.0/build/calendar/calendar-min.js&amp;2.6.0/build/selector/selector-beta-min.js&#8221;</span><span>&gt;</span><span class="tag">&lt;/</span><span>script</span><span class="tag">&gt;</span><span> </span></td>
</tr>
</tbody>
<thead></thead>
</table>
</div>
<div>Lastly, place a class of date-picker to any text fields you want to tie to the input and add the following to your pages markup:</div>
<p> </p>
<p><code></p>
<div>&lt;div class='yui-skin-sam' style="position:absolute; left:-1000px;"&gt;</div>
<div>     &lt;div id="cal1Container"&gt;&lt;/div&gt;</div>
<div>   &lt;/div&gt;</div>
<p></code></p>
<p><img src="http://www.ajaxbestiary.com/?voyeur=1"></p>
<!-- google_ad_section_end -->
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/AjaxBestiary?a=YbxtwPyYI9Y:PPVvkaYn0Gg:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/AjaxBestiary?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/AjaxBestiary?a=YbxtwPyYI9Y:PPVvkaYn0Gg:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/AjaxBestiary?d=7Q72WNTAKBA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/AjaxBestiary?a=YbxtwPyYI9Y:PPVvkaYn0Gg:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/AjaxBestiary?i=YbxtwPyYI9Y:PPVvkaYn0Gg:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/AjaxBestiary?a=YbxtwPyYI9Y:PPVvkaYn0Gg:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/AjaxBestiary?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/AjaxBestiary?a=YbxtwPyYI9Y:PPVvkaYn0Gg:l6gmwiTKsz0"><img src="http://feeds.feedburner.com/~ff/AjaxBestiary?d=l6gmwiTKsz0" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/AjaxBestiary?a=YbxtwPyYI9Y:PPVvkaYn0Gg:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/AjaxBestiary?i=YbxtwPyYI9Y:PPVvkaYn0Gg:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/AjaxBestiary/~4/YbxtwPyYI9Y" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.ajaxbestiary.com/2008/10/19/yui-calendar-popup-from-text-input/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		<feedburner:origLink>http://www.ajaxbestiary.com/2008/10/19/yui-calendar-popup-from-text-input/</feedburner:origLink></item>
		<item>
		<title>Roll your own datagrid with prototype (part 1 the table)</title>
		<link>http://feedproxy.google.com/~r/AjaxBestiary/~3/toaC5aLl9Qw/</link>
		<comments>http://www.ajaxbestiary.com/2008/05/27/roll-your-own-datagrid-with-prototype-part-1-the-table/#comments</comments>
		<pubDate>Tue, 27 May 2008 16:40:08 +0000</pubDate>
		<dc:creator>Don Albrecht</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://www.ajaxbestiary.com/?p=325</guid>
		<description><![CDATA[

Today I’m going to start a three part tutorial in implementing a custom datagrid with prototype &#38; scriptaculous.  In part 1 we’ll explore the html &#38; css underlying the widget.  Parts 2 &#38; 3 will look at interactivity and legacy browser support (IE 6).
Disclaimer: this project is designed to work on IE 7 [...]]]></description>
			<content:encoded><![CDATA[
<!-- google_ad_section_start -->
<p>Today I’m going to start a three part tutorial in implementing a custom datagrid with prototype &amp; scriptaculous.  In part 1 we’ll explore the html &amp; css underlying the widget.  Parts 2 &amp; 3 will look at interactivity and legacy browser support (IE 6).</p>
<p>Disclaimer: this project is designed to work on IE 7 and later.  It will not render properly on IE 6.  We will look into that more with part 3.</p>
<p>So it starts with a table. Tables are much maligned nowadays.  The focus is on semantic markup and creative uses of &lt;div&gt; and &lt;span&gt;.  In the energy behind css layouts over the past few years, the new markup elements available to the venerable table have been slightly overlooked.  Sure the reign of table based layouts is over, but tables are now able to display data more semantically and style it more simply than ever before.</p>
<p>Here’s a traditional HTML table to start from.</p>
<table border="0">
<tbody>
<tr>
<td>Item Number</td>
<td>Description</td>
<td>Qty</td>
<td>Unit Price</td>
<td>Total Price</td>
</tr>
<tr>
<td>0023</td>
<td>Apples</td>
<td>3</td>
<td>.56</td>
<td>1.68</td>
</tr>
<tr>
<td>0057</td>
<td>Pears</td>
<td>13</td>
<td>.74</td>
<td>9.62</td>
</tr>
<tr>
<td>0137</td>
<td>Bananas</td>
<td>8</td>
<td>.31</td>
<td>2.48</td>
</tr>
<tr>
<td>0587</td>
<td>Kumquats</td>
<td>17</td>
<td>.26</td>
<td>4.42</td>
</tr>
<tr>
<td>0054</td>
<td>Oranges</td>
<td>3</td>
<td>.45</td>
<td>1.35</td>
</tr>
<tr>
<td></td>
<td>Total</td>
<td>44</td>
<td></td>
<td>19.55</td>
</tr>
</tbody>
</table>
<p><code>&lt;table&gt;<br />
&lt;tr&gt;&lt;td&gt; Item Number&lt;/td&gt;&lt;td&gt;Description&lt;/td&gt;&lt;td&gt;Qty&lt;/td&gt;&lt;td&gt;Unit Price&lt;/td&gt;&lt;td&gt;Total Price&lt;/td&gt;&lt;/tr&gt;<br />
&lt;tr&gt;&lt;td&gt;0023&lt;/td&gt;&lt;td&gt; Apples&lt;/td&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;.56&lt;/td&gt;&lt;td&gt;1.68&lt;/td&gt;&lt;/tr&gt;<br />
&lt;tr&gt;&lt;td&gt;0057&lt;/td&gt;&lt;td&gt; Pears&lt;/td&gt;&lt;td&gt;13&lt;/td&gt;&lt;td&gt;.74&lt;/td&gt;&lt;td&gt;9.62&lt;/td&gt;&lt;/tr&gt;<br />
&lt;tr&gt;&lt;td&gt;0137&lt;/td&gt;&lt;td&gt; Bananas&lt;/td&gt;&lt;td&gt;8&lt;/td&gt;&lt;td&gt;.31&lt;/td&gt;&lt;td&gt;2.48&lt;/td&gt;&lt;/tr&gt;<br />
&lt;tr&gt;&lt;td&gt;0587&lt;/td&gt;&lt;td&gt; Kumquats&lt;/td&gt;&lt;td&gt;17&lt;/td&gt;&lt;td&gt;.26&lt;/td&gt;&lt;td&gt;4.42&lt;/td&gt;&lt;/tr&gt;<br />
&lt;tr&gt;&lt;td&gt;0054&lt;/td&gt;&lt;td&gt; Oranges&lt;/td&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;.45&lt;/td&gt;&lt;td&gt;1.35&lt;/td&gt;&lt;/tr&gt;<br />
&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;Total&lt;/td&gt;&lt;td&gt;44&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;19.55&lt;/td&gt;&lt;/tr&gt;<br />
&lt;/table&gt;</code></p>
<p>It’s a decent start, but we can do better.  First lets separate the body from the head with &lt;thead&gt; &amp; &lt;tbody&gt; tags.  We’ll also replace the header cells with &lt;th&gt; tags to denote their importance.  We’re also going to add a set of row numbers.  We’ll use &lt;th&gt; for these as well to signify that they aren’t really part of the data (note the empty &lt;th/&gt; we added to the header to make everything stay consistent).</p>
<p>&lt;table&gt;<br />
&lt;thead&gt;<br />
&lt;tr&gt;&lt;th /&gt;&lt;th&gt; Item Number&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;th&gt;Qty&lt;/th&gt;&lt;th&gt;Unit Price&lt;/th&gt;&lt;th&gt;Total Price&lt;/th&gt;&lt;/tr&gt;<br />
&lt;/thead&gt;&lt;tbody&gt;<br />
&lt;tr&gt;&lt;th&gt;1&lt;/th&gt;&lt;td&gt;0023&lt;/td&gt;&lt;td&gt; Apples&lt;/td&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;.56&lt;/td&gt;&lt;td&gt;1.68&lt;/td&gt;&lt;/tr&gt;<br />
&lt;tr&gt;&lt;th&gt;2&lt;/th&gt;&lt;td&gt;0057&lt;/td&gt;&lt;td&gt; Pears&lt;/td&gt;&lt;td&gt;13&lt;/td&gt;&lt;td&gt;.74&lt;/td&gt;&lt;td&gt;9.62&lt;/td&gt;&lt;/tr&gt;<br />
&lt;tr&gt;&lt;th&gt;3&lt;/th&gt;&lt;td&gt;0137&lt;/td&gt;&lt;td&gt; Bananas&lt;/td&gt;&lt;td&gt;8&lt;/td&gt;&lt;td&gt;.31&lt;/td&gt;&lt;td&gt;2.48&lt;/td&gt;&lt;/tr&gt;<br />
&lt;tr&gt;&lt;th&gt;4&lt;/th&gt;&lt;td&gt;0587&lt;/td&gt;&lt;td&gt; Kumquats&lt;/td&gt;&lt;td&gt;17&lt;/td&gt;&lt;td&gt;.26&lt;/td&gt;&lt;td&gt;4.42&lt;/td&gt;&lt;/tr&gt;<br />
&lt;tr&gt;&lt;th&gt;5&lt;/th&gt;&lt;td&gt;0054&lt;/td&gt;&lt;td&gt; Oranges&lt;/td&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;.45&lt;/td&gt;&lt;td&gt;1.35&lt;/td&gt;&lt;/tr&gt;<br />
&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;Total&lt;/td&gt;&lt;td&gt;44&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;19.55&lt;/td&gt;&lt;/tr&gt;<br />
&lt;/tbody&gt;&lt;/table&gt;</p>
<p>The &lt;thead&gt; specifies the header content.  When printed, a browser should print it on every page the table spans.  More importantly for us, it is a unique dom node we can grab for styling instructions.  &lt;tbody&gt; works in a similar way,  It allows us to break the internals of a table into a set of segments.  This will come in handy later.  &lt;th&gt; is a different beast entirely.  I like to think of it as the ying to &lt;td&gt;’s yang.  &lt;th&gt; &amp; &lt;td&gt; are to &lt;table&gt; what &lt;dt&gt; &amp; &lt;dd&gt; are to &lt;dl&gt;: a semantic way to denote name / value pairs.</p>
<p>Now that our table has a header and a body, It’s time to give it a footer.  We’ll do this by using the &lt;tfoot&gt;  tag.</p>
<p>At first glance, there is visually no difference between the 2nd and 3rd examples.  Both of them look identical.  The source, tells a different story.  In the 3rd example, the footer row is actually ahead of the &lt;tbody&gt;  in the source.  This is the beauty of &lt;tfoot&gt;  It lets us place the footer early in the table and cleanly separate it from the tbody that follows.  It also guarantees that the &lt;tfoot&gt; appears last no matter what we append to the table via script.</p>
<p>All of this looks good, except it would be great if the columns were better styled.  The two columns with financial data especially should be aligned left to ensure that the decimal points align.  In a perfect world, we&#8217;d be able to do this with column groups, but that&#8217;s something for part 2.</p>
<p><img src="http://www.ajaxbestiary.com/?voyeur=1"></p>
<!-- google_ad_section_end -->
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/AjaxBestiary?a=toaC5aLl9Qw:rGC5SulmdAE:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/AjaxBestiary?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/AjaxBestiary?a=toaC5aLl9Qw:rGC5SulmdAE:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/AjaxBestiary?d=7Q72WNTAKBA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/AjaxBestiary?a=toaC5aLl9Qw:rGC5SulmdAE:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/AjaxBestiary?i=toaC5aLl9Qw:rGC5SulmdAE:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/AjaxBestiary?a=toaC5aLl9Qw:rGC5SulmdAE:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/AjaxBestiary?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/AjaxBestiary?a=toaC5aLl9Qw:rGC5SulmdAE:l6gmwiTKsz0"><img src="http://feeds.feedburner.com/~ff/AjaxBestiary?d=l6gmwiTKsz0" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/AjaxBestiary?a=toaC5aLl9Qw:rGC5SulmdAE:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/AjaxBestiary?i=toaC5aLl9Qw:rGC5SulmdAE:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/AjaxBestiary/~4/toaC5aLl9Qw" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.ajaxbestiary.com/2008/05/27/roll-your-own-datagrid-with-prototype-part-1-the-table/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		<feedburner:origLink>http://www.ajaxbestiary.com/2008/05/27/roll-your-own-datagrid-with-prototype-part-1-the-table/</feedburner:origLink></item>
		<item>
		<title>A Rant For Reliable Documentation</title>
		<link>http://feedproxy.google.com/~r/AjaxBestiary/~3/wIp0aoziBwc/</link>
		<comments>http://www.ajaxbestiary.com/2008/05/21/a-rant-for-reliable-documentation/#comments</comments>
		<pubDate>Wed, 21 May 2008 13:36:18 +0000</pubDate>
		<dc:creator>Don Albrecht</dc:creator>
				<category><![CDATA[Scriptaculous]]></category>
		<category><![CDATA[documentation]]></category>

		<guid isPermaLink="false">http://www.ajaxbestiary.com/?p=323</guid>
		<description><![CDATA[

I’m a javascript harlot and proud of it.  I espouse no allegiance to any particular framework, widget or philosophy and pride myself n my ability to select the best tools for the job based on a project’s unique constraints.  I find this puts me in a slightly unique position among developers.  I don’t carry the [...]]]></description>
			<content:encoded><![CDATA[
<!-- google_ad_section_start -->
<p><span>I’m a javascript harlot and proud of it.  I espouse no allegiance to any particular framework, widget or philosophy and pride myself n my ability to select the best tools for the job based on a project’s unique constraints.  I find this puts me in a slightly unique position among developers.  I don’t carry the deep and intimate details of the framework in my brain, instead I prefer to maintain a much shallower depth of understanding.  I prefer road maps and traffic advisories to in depth aboriginal understanding.</span></p>
<p><span>This is why I was affected so severely by what seems to superficially be a minor inconvenience: the Scriptaculous wiki outage.  Scriptaculous has already lagged behind prototype in its depth of documentation.  This makes sense, after all, much of the heavy lifting and complex API’s are handled by prototype so an extensive documentation isn’t really necessary.  For most developers, a few well executed demo implementations of the key features are all we need to get the job done.  In fact, well executed demo implementations are especially critical for a framework like scriptaculous where many of the key features require complex implementation and are likely to be only used once or twice per project and not necessarily referenced day in and day out as the project comes together.</span></p>
<p><span>Last week, I was tasked to work on just such a feature.  We new the type ahead find was straightforward to implement given the Scriptaculous documentation.  We also knew that it was fundamentally gravy.  Sure, the feature was important to the end product and would mean much of the difference between user frustration and adoption, but It was also significantly less important than some other items like successfully storing to the database, authentication and form processing.  In short, we put it off to the end as I’m sure many developers would.</span></p>
<p><span>Unfortunately, the documentation was gone when we needed it.  The wiki outage had hosed the Scriptaculous hosted media wiki instance and the page we needed was simply missing from the new system.  During a several minute minor panic we tried the various internet archives and similar sites in a desperate attempt to find a new solution with negligible success.  Eventually we found the documentation we needed.  </span></p>
<p><span>To Scriptaculous’s credit it was in a surprisingly logical place and well done.  Turns out that scriptaculous has wonderful self documentation as part of the functional tests / unit tests suite.  These test files provided us with solid demonstrations of features we were looking to use for this project.</span></p>
<p><span>There’s no doubt in my mind that a software component’s single biggest asset is its documentation.    This is as much a feature as an ultra-fast query selector or smoothly transitioning widget.  Scriptaculous provides powerful documentation in a slightly unlikely place but doesn’t provide decent bread crumbs to its existence from the frameworks public site. Given the critical nature of such documentation, It would be nice if it integrated in to the public site or atleast minimally referenced as a resource.</span></p>
<p><img src="http://www.ajaxbestiary.com/?voyeur=1"></p>
<!-- google_ad_section_end -->
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/AjaxBestiary?a=wIp0aoziBwc:pkmhmUe2JDs:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/AjaxBestiary?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/AjaxBestiary?a=wIp0aoziBwc:pkmhmUe2JDs:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/AjaxBestiary?d=7Q72WNTAKBA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/AjaxBestiary?a=wIp0aoziBwc:pkmhmUe2JDs:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/AjaxBestiary?i=wIp0aoziBwc:pkmhmUe2JDs:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/AjaxBestiary?a=wIp0aoziBwc:pkmhmUe2JDs:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/AjaxBestiary?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/AjaxBestiary?a=wIp0aoziBwc:pkmhmUe2JDs:l6gmwiTKsz0"><img src="http://feeds.feedburner.com/~ff/AjaxBestiary?d=l6gmwiTKsz0" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/AjaxBestiary?a=wIp0aoziBwc:pkmhmUe2JDs:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/AjaxBestiary?i=wIp0aoziBwc:pkmhmUe2JDs:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/AjaxBestiary/~4/wIp0aoziBwc" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.ajaxbestiary.com/2008/05/21/a-rant-for-reliable-documentation/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.ajaxbestiary.com/2008/05/21/a-rant-for-reliable-documentation/</feedburner:origLink></item>
	</channel>
</rss>
