<?xml version="1.0" encoding="UTF-8"?>
<!-- generator="wordpress/2.1.2" -->
<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/"
	>

<channel>
	<title>Left Logic</title>
	<link>http://leftlogic.com/lounge</link>
	<description>Left Logic articles and news / Left Logic is a Brighton based web development and design consultancy</description>
	<pubDate>Wed, 14 Nov 2007 12:28:10 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.1.2</generator>
	<language>en</language>
			<item>
		<title>Bookmarklet Coding</title>
		<link>http://leftlogic.com/lounge/articles/bookmarklet-coding/</link>
		<comments>http://leftlogic.com/lounge/articles/bookmarklet-coding/#comments</comments>
		<pubDate>Wed, 14 Nov 2007 10:07:34 +0000</pubDate>
		<dc:creator>Remy Sharp</dc:creator>
		
		<category><![CDATA[Articles]]></category>
<category>bookmarklet</category><category>javascript</category><category>microformats</category><category>tutorial</category>
		<guid isPermaLink="false">http://leftlogic.com/lounge/articles/bookmarklet-coding/</guid>
		<description><![CDATA[If you're familiar with my work, then you'll know I'm an avid user of bookmarklets.  

They can be little snippets of code, or more complex applications such as the Microformats or the Speech Bubble bookmarklets that entirely hijack the web page for a new function.

Here I'll share my experience writing bookmarklets and offer some [...]]]></description>
			<content:encoded><![CDATA[<p>If you're familiar with my work, then you'll know I'm an avid user of <a href="http://en.wikipedia.org/wiki/Bookmarklets" title="Wikipedia Entry: Bookmarklet">bookmarklets</a>.  </p>

<p>They can be little snippets of code, or more complex applications such as the <a href="http://leftlogic.com/lounge/articles/microformats_bookmarklet/" title="Microformats Bookmarklet">Microformats</a> or the <a href="http://leftlogic.com/lounge/articles/speech-bubbles/" title="Speech Bubbles">Speech Bubble</a> bookmarklets that entirely hijack the web page for a new function.</p>

<p>Here I'll share my experience writing bookmarklets and offer some tips for development.</p>

<p><a class="more" id="more-18"></a></p>

<h3 id="code">Think BIG, code small</h3>

<p>The majority of bookmarklets are tiny pieces of JavaScript, succinctly written for a single task.  A few others will be more complicated and rely on a much larger library behind the scenes.  Either way, developing your bookmarklet you will be faced with a series of limitations.</p>

<h4>Limitations</h4>

<p>First and foremost, if you want your bookmarklet to work in all browsers, it has to adhere to length limits:</p>

<ul>
<li>IE 5 - 2084 bytes</li>
<li>IE 6 - 508 bytes</li>
<li>IE 6 SP 2 - <strong>488 bytes</strong></li>
<li>IE 7 - 2084 bytes</li>
<li>Firefox + Safari - > 2000 bytes</li>
</ul>

<p>IE6 has the smallest length, and that includes the <code>javascript:</code> pseudo protocol.</p>

<h4>Don't quote me</h4>

<p>Avoid the double quote character (").  Since the user is going to install your bookmarklet from a link, it will be wrapped with quotes (assuming xhtml).  If you absolutely require quotes, try using the entity: <code>%22</code></p>

<h4>Optimise to be short</h4>

<p>When you declare your variable, do it all at once. i.e.:</p>

<pre><code class="prettyprint">var ctr, doc, loc = window.location, max = 23, user = "remy";</code></pre>

<p>This should be taken as far as possible.  You can also consider whether you want to reuse variables to reduce the number you have to declare (watch out for inadvertently obfuscating your own code!).</p>

<h4>Minify is your friend</h4>

<p>Minify your code, and compare the benefit of Base62 encoding over shrinking variables.  I highly recommend <a href="http://dean.edwards.name/packer/" title="/packer/">Dean Edwards' Packer</a>.</p>

<h4>If it just doesn't fit...</h4>

<p>If you simply can't meet the length restrictions, you can load your bookmarklet externally (<a href="#injection">see below</a>).  However, if you do, make sure that you let your users see the source if they want to because your bookmarklet will have to act responsibly.</p>

<h3 id="installation">Installation</h3>

<p>Most browsers will allow the user to drag the bookmarklet to their bookmark bar - however, IE is slightly different.  To install in IE, you will need to right click on the link (that holds the bookmarklet) and add to favourites.  </p>

<h3 id="play_nice">Play Nice</h3>

<p>If you want your bookmarklet to interact with the existing page (rather than just redirecting off elsewhere), think about variable scope, in particular you may need to be careful not to overwrite existing variables.</p>

<h4>Encapsulate</h4>

<p>Rather than using <code>void</code> to run your bookmarklet, use the following:</p>

<pre><code class="prettyprint">javascript:(function(){ /* bookmarklet code */ })()</code></pre>

<p>Then when you declare your variables, they'll be within the private scope of the anonymous function.</p>

<h4>Style injection</h4>

<p>If supporting IE6, and you need to apply new styles, you'll have to set them directly on the element, rather than injecting a <code>link</code> tag. i.e.</p>

<pre><code class="prettyprint">element.style.display = 'none';</code></pre>

<h3 id="injection">Script Injection</h3>

<p>Using script injection is a perfectly legitimate way to get your code to run on the page when it's longer than 488 bytes.  </p>

<p>However, if your bookmarklet depends on external libraries (e.g. <a href="http://jquery.com">jQuery</a> or <a href="http://prototypejs.org">Prototype</a>) you need to be wary of race conditions if your code relies on these being in place <em>first</em>.</p>

<p>In this case, you need to use a test &amp; callback/load combo as shown below in <a href="#multiscript">multi-script inject</a>.</p>

<h4>Single script injection</h4>

<p>If you're only loading a single script that will execute or offer functionality when loaded, then the following will do fine (obviously all on one line):</p>

<pre><code class="prettyprint">javascript:(function () {
  var s=document.createElement('script');
  s.src='http://www.mysite.com/js/script.js';
  document.body.appendChild(s);
})();</code></pre>

<p>There's some argument to insert the script in to the <code>head</code> tag.  I disagree.  With bookmarklets like these, we're hijacking the web page, so perfect and semantic html doesn't have such a big play. I'd like to hear other people's thought on this.</p>

<h4 id="multiscript">Multi-script injection</h4>

<p>The following function is the best way I've found to inject an external script and continue once it's confirmed to have been loaded.</p>

<p><small>Note: this is the server side bookmarklet code.</small></p>

<pre><code class="prettyprint">function MyBookmarklet() {
  console.log('Testing whether jQuery is loaded (' + !!(typeof jQuery == 'function') + ')');

  if (waitingForScript('http://jquery.com/src/jquery-latest.js', 'jQuery')) return;

  console.log('Do some action with jQuery');
}

/**
* Only returns true when the external script has been loaded
* in to the DOM.  It uses arguments.callee.caller to work out
* which function is the callback.
*
* @param url {String} URL of external script
* @param obj {String} The name of a function or variable within
* the external script to test for.
* @license: Creative Commons License - 
*   ShareAlike http://creativecommons.org/licenses/by-sa/3.0/
* @author Remy Sharp / leftlogic.com
*/
function waitingForScript(url, obj) {
  function lateLoader(u,id,test,fn){            
    var d = document;
    if (!d.getElementById(i)) {
      var s = d.createElement('script');
      s.src = u;
      s.id = id;
      d.body.appendChild(s);
    }

    var timer = setInterval(function (){
      var ok = false;
      try {
        ok = t.call();
      } catch(e) {}

      if (ok) {
        clearInterval(timer);
        fn.call();
      }
    }, 10);
  }

  var callback = arguments.callee.caller;

  if ((typeof window[obj] == 'undefined') &amp;&amp; !window['loading' + obj]) {
    window['loading' + obj] = true;
    lateLoader(url, '_' + obj, function () {
      return (typeof window[obj] != 'undefined');
    }, callback);
    return true;
  } else if (typeof window[obj] == 'undefined') {
    return true;
  } else {
    return false;
  }
}</code></pre>

<h3 id="examples">Bookmarklet Examples</h3>

<p>Some personal favourites:</p>

<ul>
<li><a href="http://leftlogic.com/lounge/articles/microformats_bookmarklet/">Microformats</a> - displays Microformats on the page and allows individual download (IE, FF &amp; Safari)</li>
<li><a href="javascript:(function(){var q=document.createElement('script');q.setAttribute('src', 'http://jquery.com/src/jquery-latest.js');document.body.appendChild(q)})()">jQueryify</a> - loads jQuery for console debugging</li>
<li><a href="javascript:(function(){var q=document.createElement('script');q.setAttribute('src', 'http://prototypejs.org/javascripts/prototype.js');document.body.appendChild(q)})()">Prototypeify</a> - loads Prototype for console debugging</li>
<li><a href="javascript:javascript:location.href='http://del.icio.us/post?v=4;url='+encodeURIComponent(location.href)+';title='+encodeURIComponent(document.title)">del.icio.us</a> - bookmarks a page on del.icio.us</li>
<li><a href="javascript:(function(){var%20h=document.getElementsByTagName('html');h[0].setAttribute('debug','true');if(!document.getElementById('_fb')){h=document.createElement('script');h.setAttribute('id','_fb');h.setAttribute('src','http://remysharp.com/wp-content/uploads/2007/03/firebug.js');document.body.appendChild(h);void(h);}else{void(window.console.open());}})()">Firebug</a> - dynamically loads Firebug Lite (IE + Safari)</li>
<li><a href="javascript:(function(){var a={},b=[],d=document,e,f,i,w=window,g={},v=(prompt('Ignore filter (comma sep)?','')||'').split(','),i=v.length,f=d.createElement('iframe');while(i--){g[v[i]]=1}for(v in window){a[v]={'type':typeof window[v],'val':window[v]}}f.style.display='none';d.body.appendChild(f);f.src='about:blank';f=f.contentWindow||f.contentDocument;for(v in a){if(typeof f[v] != 'undefined')delete a[v];else if(g[a[v].type])delete a[v]}e='addEventListener,document,location,navigator,window'.split(',');i=e.length;while(--i){delete a[e[i]]}console.dir(a)})()">Globals</a> - dumps global variables in Firebug console (FF only)</li>
<li><a href="javascript:s=window.getSelection().toString();window.location='http://wikipedia.com/wiki/'+s">Wikipedia</a> - takes a selection on the page and loads the wiki entry for it.</li>
</ul>
<a href="http://leftlogic.com/lounge/tag/bookmarklet" rel="tag">bookmarklet</a>, <a href="http://leftlogic.com/lounge/tag/javascript" rel="tag">javascript</a>, <a href="http://leftlogic.com/lounge/tag/microformats" rel="tag">microformats</a>, <a href="http://leftlogic.com/lounge/tag/tutorial" rel="tag">tutorial</a>]]></content:encoded>
			<wfw:commentRss>http://leftlogic.com/lounge/articles/bookmarklet-coding/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Speech Bubbles</title>
		<link>http://leftlogic.com/lounge/articles/speech-bubbles/</link>
		<comments>http://leftlogic.com/lounge/articles/speech-bubbles/#comments</comments>
		<pubDate>Fri, 06 Jul 2007 07:23:11 +0000</pubDate>
		<dc:creator>Remy Sharp</dc:creator>
		
		<category><![CDATA[Articles]]></category>
<category>fun</category><category>javascript</category><category>jquery</category><category>speech bubbles</category>
		<guid isPermaLink="false">http://leftlogic.com/lounge/articles/speech-bubbles/</guid>
		<description><![CDATA[How many times have you looked at a photo on the Internet and wanted to add your own commentary with a speech bubble?

Now you can, to any picture on the Internet - and you can share it with friends, or even start your own competition if you like.



How to install &#38; demonstration

The following short video [...]]]></description>
			<content:encoded><![CDATA[<p>How many times have you looked at a photo on the Internet and wanted to add your own commentary with a speech bubble?</p>

<p>Now you can, to <strong>any</strong> picture on the Internet - and you can share it with friends, or even start your own competition if you like.</p>

<p><a class="more" id="more-15"></a></p>

<h3 id="how">How to install &amp; demonstration</h3>

<p>The following short video shows how to easily install speech bubbles, and how they work.  Once you've copied the link, you can then email the speech bubbles to your friends.</p>

<p class="centre">
<object width="528" height="330" type="application/x-shockwave-flash" data="/downloads/flvplayer.swf">
<param name="bgcolor" value="#FFFFFF" />
<param name="flashvars" value="file=/downloads/speech-bubble-demo.flv&#038;image=/images/articles/bubble-demo.jpg"/>
<param name="allowfullscreen" value="true"/>
</object>
</p>

<h3 id="install">Install speech bubbles</h3>

<p>To install, in Firefox and Safari, drag the link below to your bookmarks bar.  In Internet Explorer, right click and 'Add to favourites' and select 'Links'.</p>

<p style="font-size: 150%;" class="centre">&raquo; <a href="javascript:function ls(src,id,t,cb){if(!document.getElementById(id)){var s=document.createElement('script');s.src=src;s.id=id;document.body.appendChild(s)}var ct=setInterval(function(){var call=false;try{call=t.call()}catch(e){}if(call){clearInterval(ct);cb.call()}},100)}function ljq(cb){ls('http://jquery.com/src/jquery-latest.js','_jq',function(){return!!(typeof jQuery=='function')},cb)}function lb(cb){ls('http://leftlogic.com/js/bubble/bubble.js','_bubble',function(){return!!(typeof Bubbles=='function')},cb)}(function(){ljq(function(){lb(function(){var b=new Bubbles();b.create()})})})();">Speech Bubbles</a> &laquo;</p>

<p>Please note that currently, we are <strong>not</strong> storing the speech bubbles that are created.  The web sites that the bubble is created on could replicate the speech bubble (by checking through their referrer logs), but with larger web sites like <a href="http://flickr.com">Flickr</a> and <a href="http://facebook.com">Facebook</a> it would be extremely unlikely.</p>

<p>There are plans in the future to allow you to save a history of speech bubbles.</p>

<h3 id="usage">Usage</h3>

<p>The speech bubbles are very easy to use.  </p>

<ol>
<li>Click on the bookmarked link (from above) on the page you wish to add the speech bubble on to.</li>
<li>Move the speech bubble to the right place, by clicking and dragging.</li>
<li>Enter your text.</li>
<li>To share either click the 'copy' link and a link to the speech bubble is automatically created and copied to your clipboard - or - right click on the 'copy' link and manually copy to your clipboard.</li>
<li>To close, click the 'x'.</li>
</ol>

<p class="centre"><a href="http://tinyurl.com/2x3sw9"><img src="/images/articles/bubble-example.jpg" alt="Speech bubble example" height="139" width="517" /></a></p>

<h3 id="how-does-it-work">How does it work?</h3>

<p>The speech bubble is broken in to two sections.  The bookmarklet and the public speech bubble.</p>

<h4>Bookmarklet</h4>

<p>The bookmarklet firstly loads in <a href="http://jquery.com">jQuery</a> for simplified DOM access, then loads in the <a href="/js/bubble/bubble.js">speech bubble code</a>.  Once loaded it fires the creation function within the bubble code.</p>

<p>There are some security concerns that loading an external library could be considered a bad idea from the browsers point of view.  Originally I had designed the whole bubble code as a bookmarklet, but IE being the browser it is, doesn't support long strings as locations (lending weight to the idea that browsers just aren't supposed to do this kind of stuff).  </p>

<p>Anyone is welcome to host the <a href="/js/bubble/bubble.js">bubble.js</a> on their own server and change the link in the bookmarklet.</p>

<p>However, the natural upside of the file being loaded from Left Logic's servers, is that you will receive an automatic upgrade as features are extended or bugs are fixed.</p>

<h4>Public Speech Bubble</h4>

<p>Using the information in the URL, we load one large iframe containing the source URL, then load over the bubble, creating the effect that allows us to run our script on another web site.</p>

<h3 id="browsers">Compatibility</h3>

<p>The speech bubbles supports the latest versions of Internet Explorer, Safari, Firefox and Opera.</p>

<p>Internet Explorer 6 is not currently supported as it doesn't appear to load in the external scripts when required.  On going testing and development will aim to include IE6 if possible.</p>
<a href="http://leftlogic.com/lounge/tag/fun" rel="tag">fun</a>, <a href="http://leftlogic.com/lounge/tag/javascript" rel="tag">javascript</a>, <a href="http://leftlogic.com/lounge/tag/jquery" rel="tag">jquery</a>, <a href="http://leftlogic.com/lounge/tag/speech-bubbles" rel="tag">speech bubbles</a>]]></content:encoded>
			<wfw:commentRss>http://leftlogic.com/lounge/articles/speech-bubbles/feed/</wfw:commentRss>
		</item>
		<item>
		<title>HTML Entity Character Lookup</title>
		<link>http://leftlogic.com/lounge/articles/entity-lookup/</link>
		<comments>http://leftlogic.com/lounge/articles/entity-lookup/#comments</comments>
		<pubDate>Thu, 31 May 2007 12:02:53 +0000</pubDate>
		<dc:creator>Remy Sharp</dc:creator>
		
		<category><![CDATA[Articles]]></category>
<category>dashboard</category><category>html</category><category>javascript</category><category>mac</category><category>tool</category><category>widget</category>
		<guid isPermaLink="false">http://leftlogic.com/lounge/articles/entity-lookup/</guid>
		<description><![CDATA[Using HTML entities is the right way to ensure all the characters on your page are validated.  However, often finding the right entity code requires scanning through 250 rows of characters.



This lookup allows you to quickly find the entity based on how it looks, e.g. like an &#60; or the letter c.

HTML Entity Lookup


 [...]]]></description>
			<content:encoded><![CDATA[<p>Using <abbr title="Hyper Text Markup Languge">HTML</abbr> entities is the right way to ensure all the characters on your page are <a href="http://validator.w3.org/check/referrer">validated</a>.  However, often finding the right entity code requires scanning through 250 rows of characters.</p>

<p><a class="more" id="more-12"></a></p>

<p>This lookup allows you to quickly find the entity based on how it looks, e.g. like an <a href="?q=&lt;" rel="&lt;" class="lookupExample">&lt;</a> or the letter <a href="?q=c" rel="c" class="lookupExample">c</a>.</p>

<h3 id="html_entity_lookup">HTML Entity Lookup</h3>

<form action="" id="lookupForm">
  <fieldset>
    <legend>Lookup</legend>
    <div class="floatL">
      <label for="s">HTML entities like, space separate for more:</label>
      <input type="text" name="s" value="" id="s" style="width: 360px;" />
    </div>
    <fieldset class="floatR">
      <legend>Options</legend>
      <input type="checkbox" name="compressChk" value="" id="compress" /> <label class="inline" for="compress">Small output</label>
      <div class="clear"></div>
      <input type="checkbox" name="extendedChk" value="" id="extended" /> <label class="inline" title="Include extended character sets in search" for="extended">Incl. extended</label>
      <!-- <label for="related" class="inline">Show related symbols?</label>
      <input type="checkbox" name="relatedChk" value="" id="related" /> -->
    </fieldset>
    <div class="clear"></div>
  </fieldset>
</form>

<div id="results"></div>

<script src="/js/entity-lookup/entities.js" type="text/javascript" charset="utf-8"></script>
<script src="/js/entity-lookup/entity.data.js" type="text/javascript" charset="utf-8"></script>
<script src="/js/highlightFade.js" type="text/javascript" charset="utf-8"></script>
<script src="/js/entity-lookup/entity-lookup.js" type="text/javascript" charset="utf-8"></script>

<h3 id="widget">Dashboard Widget</h3>

<p><img src="/images/articles/entity-lookup.jpg" height="215" width="284" style="padding: 0 0 2px 0;" alt="Dashboard Widget Screenshot" title="HTML entity lookup widget" class="floatR" /></p>

<p>The HTML entity lookup is also available as a <a href="http://www.apple.com/macosx/dashboard/">Dashboard</a> widget.</p>

<p>The widget works in the same way the web version does, and does not require an Internet connection to function.</p>

<p>Clicking on the particular row will copy the html entity code to the clipboard.</p>

<p><a href="/downloads/entities.zip">Download the dashboard Entity Lookup widget</a></p>

<div class="clear"></div>

<h3 id="features">Features</h3>

<ul>
<li>Search for entity characters based on how they look (taken from the <a href="http://www.w3.org/TR/html401/sgml/entities.html">W3C list of entities</a>)</li>
<li>Switch between standard and compressed views</li>
<li>Copy the HTML entity to the clipboard</li>
<li>Add your own keyword terms and characters to entities</li>
<li>Settings stored in a browser cookie</li>
<li>Available to be <a class="searchPluginLink" href="/downloads/html-character-codes.xml">installed as a search plugin</a></li>
<li>Available as a <a href="http://www.yining.org/2007/07/26/html-entity-char-lookup-firefox-extension/">Firefox plugin</a> - thanks to <a href="#comment-1332">Yining</a></li>
</ul>

<script type="text/javascript" charset="utf-8">
<!--
$(function () {
    $('a.searchPluginLink').click(function () {
        try {
            window.external.AddSearchProvider('http://leftlogic.com/downloads/html-character-codes.xml');
        } catch (e) {
            alert("You need to be using IE7 or Firefox2 to add a search engine\r\nYou can also install search plugins by using the drop down menu to the right of the search box.");
        }
        return false;
    });
});
-->
</script>

<p>To reset the keywords, clear your cookies for this page and the default keyword dictionary.</p>

<h3 id="howitworks">How it Works</h3>

<p>The lookup searches the html entities for matches to the searched character based on how your character looks. For instance, the letter <a href="?q=c" rel="c" class="lookupExample">c</a> would match &copy; and &cent; entity, because of the way they look.</p>

<p>There's no clever logic behind this, only the most powerful computer known to man - man's own brain.</p>

<p>Each entity has had a list of 'like' matches added to them by hand and eye.  This is stored in a local dictionary file and loaded in during start-up (since it's so small there's no point in using an AJAX like solution).</p>

<p>The entity lookup also supports word searches and multiple searches space separated, such as <a rel="copy and cent" href="?q=copy%20and%20cent" class="lookupExample">copy and cent</a>.</p>

<p>Comments, feedback and suggestions are welcome.</p>
<a href="http://leftlogic.com/lounge/tag/dashboard" rel="tag">dashboard</a>, <a href="http://leftlogic.com/lounge/tag/html" rel="tag">html</a>, <a href="http://leftlogic.com/lounge/tag/javascript" rel="tag">javascript</a>, <a href="http://leftlogic.com/lounge/tag/mac" rel="tag">mac</a>, <a href="http://leftlogic.com/lounge/tag/tool" rel="tag">tool</a>, <a href="http://leftlogic.com/lounge/tag/widget" rel="tag">widget</a>]]></content:encoded>
			<wfw:commentRss>http://leftlogic.com/lounge/articles/entity-lookup/feed/</wfw:commentRss>
		</item>
		<item>
		<title>del.icio.us-like Text Grow</title>
		<link>http://leftlogic.com/lounge/articles/auto_grow_text/</link>
		<comments>http://leftlogic.com/lounge/articles/auto_grow_text/#comments</comments>
		<pubDate>Tue, 28 Nov 2006 07:00:13 +0000</pubDate>
		<dc:creator>Remy Sharp</dc:creator>
		
		<category><![CDATA[Articles]]></category>
<category>del.icio.us</category><category>javascript</category><category>jquery</category><category>plugin</category>
		<guid isPermaLink="false">http://offline.leftlogic.com/info/articles/delicious-like-text-grow/</guid>
		<description><![CDATA[If you're familiar with the del.icio.us tag search box, then you'll know it will grow with the length of the content you enter.

This is particularly useful for search boxes or tagging entry boxes, though the only downfall (I think) of del.icio.us's entry box is that it can grow to become wider than the entire page [...]]]></description>
			<content:encoded><![CDATA[<p>If you're familiar with the <a href="http://del.icio.us/remy.sharp">del.icio.us</a> tag search box, then you'll know it will grow with the length of the content you enter.</p>

<p>This is particularly useful for search boxes or tagging entry boxes, though the only downfall (I think) of del.icio.us's entry box is that it can grow to become wider than the entire page width.</p>

<p><a class="more" id="more-5"></a></p>

<p>I've written a <a href="http://jquery.com">jQuery</a> <a href="http://jquery.com/plugins">plugin</a> that plugs the same functionality in to any text box - but also includes the max-width limiting functionality.</p>

<p><a href="http://leftlogic.com/jquery/textgrow.js">Download textGrow</a></p>

<h3 id="example">Example</h3>

<script charset="utf-8" type="text/javascript" src="http://leftlogic.com/jquery/textgrow.js"></script>

<script charset="utf-8" type="text/javascript"> 
    $(function(){ jQuery("input.ctlTextGrowExample").textGrow({ pad: 25 }); }) 
</script>

<p>Search web site: <input type="text" class="ctlTextGrowExample" name="s" style="min-width: 25px; max-width: 250px; width: 25px;"/></p>

<h3 id="usage">Usage</h3>

<pre><code class="prettyprint">jQuery('input').textGrow({
  pad: 25, min_width: 25, max_width: 300
});</code></pre>

<ul>
<li>pad: trailing padding in pixels - default 25</li>
<li>min_width: minimum width of the text box in pixels</li>
<li>max_width: maximum width of the text box in pixels</li>
</ul>

<p>However, you don't need to pass the min and max width via the JavaScript, to offer even more flexibility this can be read through the <abbr title="Cascading Style Sheets">CSS</abbr> (and itâ€™s legal CSS too). This will be read from the style attribute, or the class definitions in the CSS.</p>

<p>You can use min-width and max-width to apply specific control to text boxes, for example:</p>

<pre><code class="prettyprint">&lt;input type=&quot;text&quot; 
  <b>style=&quot;min-width: 25px; max-width: 300px&quot;</b>
  name=&quot;s&quot; /&gt;</code></pre>

<h3 id="howitworks">How it Works</h3>

<p>Following in del.icio.us's example, when you type in to the text input box, behind the scenes an invisible (rather than hidden) is matching the content.</p>

<p>The width of that DIV is read in pixels and used to style the width of the input box.</p>

<p>If you have any comments, bugs or suggestions please drop me a comment below.</p>
<a href="http://leftlogic.com/lounge/tag/del.icio.us" rel="tag">del.icio.us</a>, <a href="http://leftlogic.com/lounge/tag/javascript" rel="tag">javascript</a>, <a href="http://leftlogic.com/lounge/tag/jquery" rel="tag">jquery</a>, <a href="http://leftlogic.com/lounge/tag/plugin" rel="tag">plugin</a>]]></content:encoded>
			<wfw:commentRss>http://leftlogic.com/lounge/articles/auto_grow_text/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Quick and Dirty Intro to Perl Objects</title>
		<link>http://leftlogic.com/lounge/articles/perl_objects/</link>
		<comments>http://leftlogic.com/lounge/articles/perl_objects/#comments</comments>
		<pubDate>Sat, 18 Nov 2006 10:41:54 +0000</pubDate>
		<dc:creator>Remy Sharp</dc:creator>
		
		<category><![CDATA[Articles]]></category>
<category>beginner</category><category>object</category><category>OOP</category><category>perl</category>
		<guid isPermaLink="false">http://offline.leftlogic.com/info/articles/quick-and-dirty-intro-to-perl-objects/</guid>
		<description><![CDATA[Although I've been writing Perl for a long time, OO Perl (also known as Poop!) has been remained somewhat of a mystery to me.

On first inspection it doesn't resemble any typical OO language, but if you scratch a little under the surface, you'll see there's nothing really to them.



This tutorial assumes you have an understanding [...]]]></description>
			<content:encoded><![CDATA[<p>Although I've been writing Perl for a long time, OO Perl (also known as Poop!) has been remained somewhat of a mystery to me.</p>

<p>On first inspection it doesn't resemble any typical OO language, but if you scratch a little under the surface, you'll see there's nothing really to them.</p>

<p><a class="more" id="more-4"></a></p>

<p>This tutorial assumes you have an understanding of Perl and have a basic grasp of object orientated programming, but want a quick step introduction to Perl objects.</p>

<h3>Example Class</h3>

<p>If you know a little about OO, then you'll recognise pretty much all of this code with the exception of the new function.</p>

<pre><code class="prettyprint">use strict; # strict error handling

package MyClass; # the class name

sub new
{
  # get a reference to the object
  # class from the implicit @_ variable
  my $class = shift;

  # collect the parameters passed in via a hash
  my %params = @_;

  # bind the class methods and attributes
  # to $self using bless
  my $self = {};
  bless $self, $class;

  # arbitrary start up functions - always referring
  # to $self to change the state of our object
  $self-&gt;setValue(%params{&#39;value&#39;} || &#39;13&#39;);

  # return the reference to the object
  return $self;
}

# class methods
sub setValue
{
  my $self = shift; # reference to object instance
  $self-&gt;{&#39;my_value&#39;} = shift;
}

sub timesTen
{
  my $self = shift;
  return $self-&gt;{&#39;my_value&#39;} * 10;
}</code></pre>

<h3>Example Usage</h3>

<pre><code class="prettyprint">#!/usr/local/bin/perl
use strict;

# create a new instance of &#39;MyClass&#39;
my $obj = MyClass-&gt;new(value =&gt; 13);

# simple example of method execution
print $obj-&gt;timesTen();
print &quot; &quot;;

$obj-&gt;setValue(35);
print $obj-&gt;timesTen();
print &quot; &quot;;

# Output of script:
# &gt; 130
# &gt; 350</code></pre>

<h3>Conventions</h3>

<p>There's a few conventions used by Perl OO.</p>

<ol>
<li>Packages (aka class names) are written in title case with no underscores, e.g. MyReallyCoolClass. If the class resides in a sub directory, the naming conventions follow and the paths are separated by '::', e.g. GenericClasses::MyReallyCoolClass.</li>
<li>Perl uses $self as the reference that most people will know as 'this'.</li>
<li>To create a new object the call is generally:
<code>my $obj = MyClass-&gt;new();</code> rather than <code>my $obj = new MyClass;</code></li>
</ol>

<h3>Further Reading</h3>

<ul>
<li>Perl Objects on search.cpan.org</li>
<li>Perl function list by category</li>
<li>Object-oriented tutorial for perl: from the command line, type: perldoc perltoot</li>
</ul>
<a href="http://leftlogic.com/lounge/tag/beginner" rel="tag">beginner</a>, <a href="http://leftlogic.com/lounge/tag/object" rel="tag">object</a>, <a href="http://leftlogic.com/lounge/tag/oop" rel="tag">OOP</a>, <a href="http://leftlogic.com/lounge/tag/perl" rel="tag">perl</a>]]></content:encoded>
			<wfw:commentRss>http://leftlogic.com/lounge/articles/perl_objects/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Upgraded jQuery Spy</title>
		<link>http://leftlogic.com/lounge/articles/jquery_spy2/</link>
		<comments>http://leftlogic.com/lounge/articles/jquery_spy2/#comments</comments>
		<pubDate>Sat, 30 Sep 2006 14:30:34 +0000</pubDate>
		<dc:creator>Remy Sharp</dc:creator>
		
		<category><![CDATA[Articles]]></category>
<category>digg</category><category>javascript</category><category>jquery</category><category>plugin</category><category>spy</category>
		<guid isPermaLink="false">http://offline.leftlogic.com/info/articles/jquery_spy2/</guid>
		<description><![CDATA[Following many requests, I have upgraded the jQuery spy code to support multiple items returned from the AJAX response and custom timestamp functions - so that requests can be completely tailored.

Download the latest jQuery spy



Examples

Import the plug-in, and call the code on the spy container div (assuming you've imported jQuery already).

&#60;script type="text/javascript" src="spy.js"&#62;&#60;/script&#62;
&#60;script type="text/javascript"&#62;
  [...]]]></description>
			<content:encoded><![CDATA[<p>Following many requests, I have upgraded the <a href="http://jquery.com">jQuery</a> spy code to support <strong>multiple items</strong> returned from the <abbr title="Asynchronous JavaScript And XML">AJAX</abbr> response and <strong>custom timestamp</strong> functions - so that requests can be completely tailored.</p>

<p><strong><a href="/jquery/spy.js">Download the latest jQuery spy</a></strong></p>

<p><a class="more" id="more-6"></a></p>

<h3 id="examples">Examples</h3>

<p>Import the plug-in, and call the code on the spy container div (assuming you've imported jQuery already).</p>

<pre><code class="prettyprint">&lt;script type="text/javascript" src="spy.js"&gt;&lt;/script&gt;
&lt;script type="text/javascript"&gt;
  $(function() {
    /* returns a selection of HTML DIVs to be inserted in to 
        the #spyContainer in a spy-style */
    $('#spyContainer').spy({'ajax': '/ajax/news.php'}); 
  });
&lt;/script&gt;
&lt;div id="spyContainer"&gt;&lt;/div&gt;</code></pre>

<h4 id="working_examples">Working Examples</h4>

<ul>
<li>Example <a href="/jquery/spy.html">spy with dummy data</a></li>
<li>The <a href="/jquery/out.php">AJAX URL</a> being used to return the dummy data (view the source of the page)</li>
<li><a href="/jquery/out.php.txt">Source code</a> to the HTML example</li>
<li>Same example as above, except using a <a href="/jquery/spy_json.html">JSON driven spy</a></li>
<li><a href="/jquery/out_json.php.txt">Source code</a> to the JSON example</li>
<li>Real life example on <a href="http://www.arsenal-mania.com">Arsenal</a> web site: <a href="http://www.arsenal-mania.com/?page=spy&amp;spy=articles&amp;clean=1">Arsenal news spy</a></li>
</ul>

<h3 id="support">Support</h3>

<ul>
<li>Multiple items from AJAX request and shows one at a time, reducing the load on your servers</li>
<li><a href="#custom_timestamp">Custom timestamp</a> function available upon AJAX request to control the content appearing in the spy</li>
<li><a href="#custom_isdupe">Custom is duplicate</a> function to allow better handling on JSON objects from the server</li>
</ul>

<h3 id="prerequisites">Prerequisites</h3>

<p>You must be using the latest stable version of <a href="http://jquery.com">jQuery</a>.</p>

<p>If you return <abbr title="JavaScript Object Notation">JSON</abbr> content, then you must provide the following:</p>

<ul>
<li>Method: 'json'</li>
<li><a href="#custom_push">Custom push</a> function</li>
<li><a href="#custom_isdupe">Custom isDupe</a> function (if you don't want duplicates sitting next to each other)</li>
</ul>

<p>These are explained below.</p>

<h3 id="usage">Usage</h3>

<h4>Simple Parameters</h4>

<ul>
<li><strong>ajax</strong> - required - the URL to server side script that will return the content</li>
<li><strong>limit</strong> - default 10 - the total number of rows to show</li>
<li><strong>fadeLast</strong> - default 5 - the number of rows to fade out, i.e. the last 5 rows</li>
<li><strong>fadeInSpeed</strong> - default 'slow' (600) - the speed, in milliseconds to use for the first row to fade in with</li>
<li><strong>timeout</strong> - default 3000 (3 seconds) - the time in milliseconds between <strong>showing</strong> a new row</li>
<li><strong>method</strong> - default to HTML - should be the AJAX response type, valid values are: <abbr title="Hyper Text Markup Language">HTML</abbr> or JSON</li>
</ul>

<p>For example:</p>

<pre><code class="prettyprint">$(function() {
  $('#spyContainer').spy({
      &#39;ajax&#39;: &#39;/jquery_spy/out.php&#39;,  // return type is HTML
      &#39;fadeInSpeed&#39;: &#39;1400&#39;, // crawl
      &#39;timeout&#39;: 2000 // new item every 2 seconds
  });
});</code></pre>

<h4>Custom Functionality</h4>

<ul>
<li><strong>push</strong> - custom push on function, this must be customised if using JSON</li>
<li><strong>timestamp</strong> - custom timestamp function, defaults to return seconds from 1978.</li>
<li><strong>isDupe</strong> - custom duplicate check function.  This will work if not specified for HTML, but not JSON.</li>
<li><strong>pushTimeout</strong> - control the time between individual items being pushed on to the spy stack.</li>
</ul>

<h4 id="custom_push">Custom Push</h4>

<p>If you don't want to return HTML to the spy, you can write your own push method.</p>

<p>Your custom method will have access to 'this' which is the DOM element (i.e. the contain div) and 'response' which is the response in plain text.</p>

<p>Here is an example using JSON:</p>

<pre><code class="prettyprint">$(function() { 
  $('#spyContainer').spy({
    'ajax': '/jquery_spy/out_json.php', 
    'push': custom_push });
});

function custom_push(response) {
  eval("var json = " + response); // convert to JSON

  // I'm being lazy here, but you get the idea:
  // Build the HTML
  var html = '&lt;div style="display:none"&gt;'
  html += '&lt;span class="ctr"&gt;' + json.num;
  html += '&lt;/span&gt;&lt;span class="content"&gt;';
  html += json.string + '&lt;/span&gt;&lt;/div&gt;';
  // Prepend the HTML inside the container
  $('#' + this.id).prepend(html);
}</code></pre>

<p>See the an <a href="/jquery/spy_json.html">example JSON push</a> in action.</p>

<h4 id="custom_timestamp">Custom timestamp</h4>

<p>Most developers have their own system for tracking the latest items, so I had this in to it's own pass in function.  The example should explain the usage.  The return value from the 'timestamp' value will be what is passed in to the AJAX request via the 'timestamp' posted value.</p>

<pre><code class="prettyprint">$(function() { 
  $(&#39;#spyContainer&#39;).spy({
    &#39;limit&#39;: 25,
    &#39;fadeLast&#39;: 3,
    &#39;ajax&#39;: &#39;/jquery_spy/out.php&#39;, 
    &#39;fadeInSpeed&#39;: &#39;slow&#39;,
    &#39;timeout&#39;: 3000,
    &#39;timestamp&#39; : myTimestamp }; 
});

function myTimestamp() {
  var d = new Date();
  // formated as yyyy-mm-dd HH:MM:ss
  return d.getFullYear() + &#39;-&#39; +
    pad(d.getMonth()+1) + &#39;-&#39; + // because month starts at zero
    pad(d.getDate()) + &#39; &#39; +
    pad(d.getHours()) + &#39;:&#39; +
    pad(d.getMinutes()) + &#39;:&#39; +
    pad(d.getSeconds());
}

function pad(n) {
  n = n.toString();
  return n.length == 1 ? &#39;0&#39; + n : n;
}</code></pre>

<h4 id="custom_isdupe">Custom isDupe</h4>

<p>This function allows you compare the latest item against the last item to flag for a duplicate.  This customisation really comes in to it's own if you're using JSON.  If give the JSON object an ID, then you can compare the ID between the latest and the last items and chose not to show it.</p>

<p>Continuing in the <a href="http://digg.com/spy">Digg spy</a> fashion, this spy does allow duplicates to appear in the list, but not next to each other.</p>

<p>If the return value is <strong>true</strong> the latest item is not shown.  If the return value is <strong>false</strong>, the item is shown.</p>

<p>The function takes two parameters: latest item and last item.</p>

<p>Here's an example using JSON (assuming our JSON output object has an ID attribute):</p>

<pre><code class="prettyprint">$(function() { 
  $(&#39;#spyContainer&#39;).spy({
    &#39;limit&#39;: 25,
    &#39;fadeLast&#39;: 3,
    &#39;ajax&#39;: &#39;/jquery_spy/out_json.php&#39;, 
    &#39;fadeInSpeed&#39;: &#39;slow&#39;,
    &#39;timeout&#39;: 3000,
    &#39;method&#39;: &#39;json&#39;,   // JSON output
    &#39;isDupe&#39;: myIsDupe };
});

function myIsDupe(latest, last) {
  return !!(latest.id == last.id); // return boolean
}</code></pre>

<h4 id="pushTimeout">Custom pushTimeout</h4>

<p>The custom pustTimeout is particularly useful if you want to show all the items returned from the Ajax call to be pushed on to the stack straight away (rather than evenly one at a time).</p>

<p>The best way to do this is:</p>

<pre><code class="prettyprint">$(function () {
  $('spyContainer').spy({
    ... normal settings ...
    'pushTimeout': 1 // gives the appearance of all coming in at once
  });
});</code></pre>

<h3 id="play_and_pause">Pause and Play Buttons</h3>

<p>Included in the plug-in are pause: pauseSpy() and play: playSpy() functions.</p>

<p>These will, as the digg spy does, pause the flow of new content and start it up again. You can see these in use in the simple example</p>

<h3 id="usability">Usability</h3>

<p>I touched on this before, but I would strongly recommend that you think about those users that will have JavaScript disabled for whatever reason.  Your spy page should still work.</p>

<p>Here's what I would recommend:</p>

<ol>
<li>Pre-populate the page.  If you are going to limit to 10 items in the spy, start off with 10 items on the page.</li>
<li>Use a meta refresh in a <code>&lt;noscript&gt;</code> tag to automatically have the page reload.</li>
</ol>

<p>Here's an example:</p>

<pre><code class="prettyprint">&lt;script type=&quot;text/javascript&quot;&gt;
  // the index starts at zero - so fade down all 
  // the divs after the 5th one
  $(function() { 
  $(&#39;#spyContainer &gt; div:gt(4)&#39;).fadeEachDown(); // initial fade
  $(&#39;#spyContainer&#39;).spy({
    &#39;limit&#39;: 8,
    &#39;fadeLast&#39;: 3,
    &#39;ajax&#39;: &#39;/jquery_spy/out.php&#39;, 
    &#39;fadeInSpeed&#39;: 1400,
    &#39;timeout&#39;: 3500 };
  });
&lt;/script&gt;

&lt;noscript&gt;
  This browser does not support JavaScript - 
  which is used to automatically update the content.
  Therefore this page will automatically refresh
  every 1 minute.
  &lt;meta http-equiv=&quot;refresh&quot; content=&quot;60&quot; /&gt;
&lt;/noscript&gt;</code></pre>
<a href="http://leftlogic.com/lounge/tag/digg" rel="tag">digg</a>, <a href="http://leftlogic.com/lounge/tag/javascript" rel="tag">javascript</a>, <a href="http://leftlogic.com/lounge/tag/jquery" rel="tag">jquery</a>, <a href="http://leftlogic.com/lounge/tag/plugin" rel="tag">plugin</a>, <a href="http://leftlogic.com/lounge/tag/spy" rel="tag">spy</a>]]></content:encoded>
			<wfw:commentRss>http://leftlogic.com/lounge/articles/jquery_spy2/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Microformats Bookmarklet</title>
		<link>http://leftlogic.com/lounge/articles/microformats_bookmarklet/</link>
		<comments>http://leftlogic.com/lounge/articles/microformats_bookmarklet/#comments</comments>
		<pubDate>Mon, 25 Sep 2006 11:34:23 +0000</pubDate>
		<dc:creator>Remy Sharp</dc:creator>
		
		<category><![CDATA[Articles]]></category>
<category>bookmarklet</category><category>javascript</category><category>microformats</category>
		<guid isPermaLink="false">http://offline.leftlogic.com/info/articles/microformats_bookmarklet/</guid>
		<description><![CDATA[Inspired by John Hicks microformats Safari mock, it was quickly apparent that this (or a version of this) functionality was possible through a bookmarklet.



Bookmarklet

To use the bookmarklet, drag the link below on to your bookmark toolbar:

Microformats

Originally I had intended for the entire logic behind the Microformats overlay to be within the bookmarklet.  However, it&#8217;s [...]]]></description>
			<content:encoded><![CDATA[<p>Inspired by <a href="http://www.hicksdesign.co.uk">John Hicks</a> <a href="http://microformats.org">microformats</a> <a href="http://www.hicksdesign.co.uk/journal/a-proposal-for-a-safari-microformats-plugin">Safari mock</a>, it was quickly apparent that this (or a version of this) functionality was possible through a bookmarklet.</p>

<p><a class="more" id="more-7"></a></p>

<h3 id="bookmarklet">Bookmarklet</h3>

<p>To use the bookmarklet, drag the link below on to your bookmark toolbar:</p>

<p style="font-size: 150%;" ><a href="javascript:(function(){function%20l(u,i,t,b){var%20d=document;if(!d.getElementById(i)){var s=d.createElement('script');s.src=u;s.id=i;d.body.appendChild(s)}s=setInterval(function(){u=0;try{u=t.call()}catch(i){}if(u){clearInterval(s);b.call()}},200)}l('http://leftlogic.com/js/microformats.js','MF_loader',function(){return!!(typeof MicroformatsBookmarklet=='function')}, function(){MicroformatsBookmarklet()})})();">Microformats</a></p>

<p>Originally I had intended for the entire logic behind the Microformats overlay to be within the bookmarklet.  However, it&#8217;s particularly difficult to get all the code on one line, and this more simplistic bookmarklet means upgrades will take automatic effect.</p>

<h3 id="usage">Usage</h3>

<p>The bookmarklet has been primarily been designed for Safari, as Firefox has <a href="https://addons.mozilla.org/firefox/2240/">Tails</a>.  However, the Microformats Bookmarklet supports Safari, Firefox and IE (both 6 and 7).</p>

<p>Click on the bookmarklet once it has been saved, to bring up an overlay window of all the <a href="http://microformats.org/wiki/hcard">hCards</a> and <a href="http://microformats.org/wiki/hcalendar">hCalendars</a> within the current page.</p>

<p><img src="/images/articles/mac_microformat.jpg" alt="Example of Microformats bookmarklet running" title="" /></p>

<p>To save an individual item, click on the item heading and it will automatically (if you&#8217;re using Safari) save the <abbr title="vCard format">.vcf</abbr> or <abbr title="iCal format">.ics</abbr> files and import them in to Address Book or iCal.</p>

<p>If you are saving your vcard or vevent in IE, it will prompt you to save an HTML file - make sure that when you save, you name it appropriately so that you can import it properly.</p>

<p>To close the overlay, click anywhere outside of the window (i.e. in the darkened area).</p>

<h3 id="the_logic">The Logic</h3>

<p>If anyone is interested, here&#8217;s roughly what is happening behind the scenes for the bookmarklet to work:</p>

<ol>
<li>Load external module: <a href="http://jquery.com">jQuery</a><sup>&dagger;</sup>.</li>
<li>Load second external module: microformats.js (the main module).</li>
<li>Apply a new inline <abbr title="Cascading Style Sheets">CSS</abbr> styles (because IE doesn't support CSS style sheet injection).</li>
<li>Load the new <abbr title="Hyper Text Markup Language">HTML</abbr> for the overlay.</li>
<li>Search for vCard and vCalendar classes and capture all the information according to the guidelines laid out by <a href="http://microformats.org">Microformats</a><sup>&dagger;&dagger;</sup>.</li>
</ol>

<p class="smaller">&dagger; Because jQuery saves so much coding time, and it&#8217;s a superb library to use.</p>

<p class="smaller">&dagger;&dagger; The bookmarklet currently only supports hCards and hCalendars, but should be straight forward to support more formats where appropriate.</p>

<h3 id="known_issues">Known Issues</h3>

<p>A lot of cross site testing took place for this bookmarklet, so I do know of a few places it doesn&#8217;t work.</p>

<p>I&#8217;ve seen a problem where the overlay simply doesn&#8217;t appear.  I think this <em>may</em> be due to the site also using <a href="http://prototype.conio.net/">Prototype</a> (since I&#8217;m using jQuery which may be conflicting).  I have only seen this occur on <a href="http://www.multipack.co.uk/members/">Multipack members page</a>.</p>

<p>Since hCards and hCalendars are defined using classes, a page with a lot of markup can take a number of seconds to parse all the information.</p>

<p>I have tried to parse all the different fields in the hCards and hCalendars, but I may have missed a few, particularly in the hCard.  All sites I tested had all the information correctly imported.</p>

<p>If you see any other issues or have any suggestions, or just feedback, please feel free to leave a comment below.</p>
<a href="http://leftlogic.com/lounge/tag/bookmarklet" rel="tag">bookmarklet</a>, <a href="http://leftlogic.com/lounge/tag/javascript" rel="tag">javascript</a>, <a href="http://leftlogic.com/lounge/tag/microformats" rel="tag">microformats</a>]]></content:encoded>
			<wfw:commentRss>http://leftlogic.com/lounge/articles/microformats_bookmarklet/feed/</wfw:commentRss>
		</item>
		<item>
		<title>How to create a Digg-like spy with no work at all</title>
		<link>http://leftlogic.com/lounge/articles/jquery_spy/</link>
		<comments>http://leftlogic.com/lounge/articles/jquery_spy/#comments</comments>
		<pubDate>Mon, 14 Aug 2006 13:53:56 +0000</pubDate>
		<dc:creator>Remy Sharp</dc:creator>
		
		<category><![CDATA[Articles]]></category>
<category>digg</category><category>javascript</category><category>jquery</category><category>plugin</category><category>spy</category>
		<guid isPermaLink="false">http://leftlogic.com/lounge/articles/jquery_spy/</guid>
		<description><![CDATA[The jQuery spy has now been superseded by the upgraded jQuery spy.  Please see the upgraded jQuery spy article for details.

Yes, that's right kids, you know you love that Digg spy effect.  The real time news, as it rolls in, and how cool does it look? It looks pretty cool, that's how.



Now there [...]]]></description>
			<content:encoded><![CDATA[<p class="highlight">The jQuery spy has now been superseded by the upgraded jQuery spy.  Please see the upgraded <a href="/info/articles/jquery_spy2">jQuery spy</a> article for details.</p>

<p>Yes, that's right kids, you know you love that <a href="http://digg.com/spy">Digg spy</a> effect.  The real time news, as it rolls in, and how cool does it look? It looks pretty cool, that's how.</p>

<p><a class="more" id="more-9"></a></p>

<p>Now there is a plug-in for <a target="_blank" href="http://jquery.com">jQuery</a> that means you can have your very own spy, for <b>anything</b>, with only a few lines of JavaScript<sup>&dagger;</sup>.</p>

<p class="smaller">&dagger; Obviously you'll need something on the server side to respond to the <abbr title="Asynchronous JavaScript And XML">AJAX</abbr> request, but really it's still kinda only a few lines...</p>

<p><a href="/jquery_spy/spy.js">Download the jQuery spy plug-in</a></p>

<p><a target="_blank" href="/jquery_spy/spy.html">See the jQuery spy example</a></p>

<h3 id="Prerequisites">Prerequisites</h3>

<p>Okay campers, here's what you'll need to make this work:</p>

<ol>
    <li>A container div to hold your 'spy' - this can be pre-filled or empty</li>
    <li>A server side script that returns the <abbr title="Hyper Text Markup Language">HTML</abbr> of your spied content (article or what have you) - note that this can only be one row at a time <i>(something I may work to upgrade)</i></li>
    <li>A single div <b>must</b> wrap the content returned from the AJAX (or <abbr title="Asyncronous JavaScript And HTML">AJAH</abbr>) - and it should contain a style attribute of 'display: none;' - this is explained in <a href="#Spy_Detail">more detail</a> later</li>

</ol>

<h3 id="The_Examples">The Examples</h3>

<p>Import the plug-in, and call the code on the spy contain div (I'm assuming you've imported jQuery already).</p>

<p>Simple eh?</p>

<pre><code class="prettyprint">&lt;script type="text/javascript" src="spy.js"&gt;&lt;/script&gt;
&lt;script type="text/javascript"&gt;
  $(document).ready(function() {
    $('#spyContainer').spy({'ajax': '/ajax/news.php'})
  });
&lt;/script&gt;
&lt;div id="spyContainer"&gt;&lt;/div&gt;</code></pre>

<p>Here are a couple of examples of the spy in action.</p>

<ul>
    <li>Example <a target="_blank" href="/jquery_spy/spy.html">spy with dummy data</a></li>
    <li>The <a target="_blank" href="/jquery_spy/out.php">AJAX URL</a> being used to return the dummy data (view the source of the page)</li>

    <li>Real life example on <a target="_blank" href="http://www.arsenal-now.com/spy/Articles.html">Arsenal-Now.com</a></li>
</ul>

<h3 id="Usage">Usage</h3>

<p>Now you've seen the examples, I can hear some of you thinking: "that's all well and good, but what if I don't want to return the HTML, what if I want to return <acronym title="JavaScript Object Notation">JSON</acronym>?". No problem, use a <a href="#Custom_Push">custom push</a> method.</p>

<h4>Simple Parameters</h4>

<p>All the parameters (the few that there are) are passed in via object notation (i.e. with curly brackets).</p>

<ul>
    <li><b>limit</b> - default 10 - the total number of rows to show</li>
    <li><b>fadeLast</b> - default 5 - the number of rows to fade out, i.e. the last 5 rows</li>
    <li><b>ajax</b> - required - the URL to server side script that will return the content</li>
    <li><b>fadeInSpeed</b> - default 'slow' - the speed, in jQuery notation to use for the first row to fade in with (currently: crawl, xslow, slow, medium, fast, xfast, normal - though note that the pre-version 1 jQuery only currently supports slow, normal and fast)</li>

    <li><b>timeout</b> - default 3000 - the time in milliseconds between requests for a new row</li>
</ul>

<p>For example:</p>

<pre><code class="prettyprint">$(document).ready(function() {
  $('#spyContainer').spy(
    { 'limit': 25,
      'fadeLast': 3,
      'ajax': '/jquery_spy/out_json.php',
      'fadeInSpeed': 'slow',
      'timeout': 3000 }) // 3 seconds
});</code></pre>

<h4 id="Custom_Push">Custom Push</h4>

<p>If you don't want to return HTML to the spy, you can write your own <b>push</b> method.</p>

<p>Your custom method will have access to 'this' which is the <acronym title="Document Object Model">DOM</acronym> element (i.e. the contain div) and 'r' which is the response in plain text.</p>

<p>Here is an example using JSON:</p>

<pre><code class="prettyprint">$(document).ready(function() { 
  $('#spyContainer').spy(
    { 'ajax': '/jquery_spy/out_json.php', 
      'push': custom_push });
});

function custom_push(r) {
  eval("var json = " + r); // convert to JSON

  // I'm being lazy here, but you get the idea:
  // Build the HTML
  var html = '&lt;div style="display:none"&gt;'
  html += '&lt;span class="ctr"&gt;' + json.num;

  html += '&lt;/span&gt;&lt;span class="content"&gt;';
  html += json.string + '&lt;/span&gt;&lt;/div&gt;';
  // Prepend the HTML inside the container
  $('#' + this.id).prepend(html);
}</code></pre>

<p>See the <a target="_blank" href="/jquery_spy/spy_json.html">custom JSON push in action</a>.</p>

<h3 id="Pause_Play">Pause &amp; Play Buttons</h3>

<p>Included in the plug-in are pause: <span class="pseudocode">pauseSpy()</span> and play: <span class="pseudocode">playSpy()</span> functions.</p>

<p>These will, as the digg spy does, pause the flow of new content and start it up again.  You can see these in use in the <a target="_blank" href="/jquery_spy/spy.html">simple example</a></p>

<h3 id="Spy_Detail">Spy Detail</h3>

<p>This section is a bunch of quick bullet points to help explain a few key points.</p>

<ul>
    <li>Each new row should be wrapped in a single DIV with the style coded inline to 'display:none;'</li>
    <li>The plug-in is specifically searching for the child div elements to the container to correctly limit and fade the rows away</li>
    <li>The 'display: none' is required to fade the new row in properly, otherwise you might see some strange flashing effects</li>
    <li>The spy only supports one row at a time.  If I get requests to upgrade this, I'll take a look</li>

    <li>The AJAX request is made using a POST</li>
    <li>The AJAX request is posted one variable: timestamp - note that this is not the current time, and in fact the time of the last request - so that you may grab the latest row in a database after the timestamp</li>
    <li>If the same content appears more than once in sequence, it is ignored, i.e. don't show the same row twice</li>
    <li>I have purposely tried to keep this plug-in simple and easy to use, as this is the fun nature behind jQuery (<i>that I interpreted</i>)</li>
</ul>

<p>For accessibility, I would recommend loading the page you plan to use the spy on, with the limit number of rows (e.g. 10 news stories), and detect whether JavaScript is enabled.  If it is not, using a noscript tag, insert a 'meta refresh' tag and display a message explaining the page will auto-refresh to offer the latest content.</p>

<p>If you plan to pre-load the page with the rows, you can apply the fade down effect, as shown in the code example below.</p>

<pre><code class="prettyprint">&lt;script type="text/javascript"&gt;
  // the index starts at zero - so fade down all
  // the divs after the 5th one
  $('#spyContainer &gt; div:gt(4)').fadeEachDown();
&lt;/script&gt;
&lt;noscript&gt;

This browser does not support JavaScript - 
which is used to automatically update the content.
Therefore this page will automatically refresh every 1 minute.
&lt;meta http-equiv="refresh" content="60" /&gt;
&lt;/noscript&gt;</code></pre>

<p>Feel free to add comments, suggestions, ask questions, point out any errors - and I will try my best to get back to you.</p>
<a href="http://leftlogic.com/lounge/tag/digg" rel="tag">digg</a>, <a href="http://leftlogic.com/lounge/tag/javascript" rel="tag">javascript</a>, <a href="http://leftlogic.com/lounge/tag/jquery" rel="tag">jquery</a>, <a href="http://leftlogic.com/lounge/tag/plugin" rel="tag">plugin</a>, <a href="http://leftlogic.com/lounge/tag/spy" rel="tag">spy</a>]]></content:encoded>
			<wfw:commentRss>http://leftlogic.com/lounge/articles/jquery_spy/feed/</wfw:commentRss>
		</item>
		<item>
		<title>From PC to Mac - stuff you should know</title>
		<link>http://leftlogic.com/lounge/articles/mac_newbie_tips/</link>
		<comments>http://leftlogic.com/lounge/articles/mac_newbie_tips/#comments</comments>
		<pubDate>Thu, 20 Jul 2006 13:37:05 +0000</pubDate>
		<dc:creator>Remy Sharp</dc:creator>
		
		<category><![CDATA[Articles]]></category>
<category>beginners</category><category>mac</category><category>tips</category>
		<guid isPermaLink="false">http://offline.leftlogic.com/info/articles/mac_newbie_tips/</guid>
		<description><![CDATA[Having moved from a PC to an Apple Mac in the last 3 years, I found that the migration process was a little slow, and a little painful, for example, I only recently learnt what this symbol:  meant!

So, 3 years later, I've taught myself those basics, and I thought it would be worth sharing [...]]]></description>
			<content:encoded><![CDATA[<p>Having moved from a <abbr title="Personal Computer">PC</abbr> to an Apple Mac in the last 3 years, I found that the migration process was a little slow, and a little painful, for example, I only recently learnt what this symbol: <img src="/images/articles/mac_escape.gif" alt="Curious Symbol" title="Curious Symbol" /> meant!</p>

<p>So, 3 years later, I've taught myself those basics, and I thought it would be worth sharing my Mac tips.</p>

<p><a class="more" id="more-11"></a></p>

<p class="smaller">Note come disclaimer: this article isn't intended as comprehensive, just a starting point to help answer some questions you may have in your migration to your new Mac.</p>

<h3 id="Symbols">Symbols</h3>

<p>Apple have different names and symbols for the keys, so here's a quick intro:</p>

<ol class="small_gap">
    <li><span class="command">ctrl</span> is called <b>Control</b>, and the symbol is <img class="middle" src="/images/articles/mac_ctrl.gif" alt="Carot (^)" height="12" width="9" /></li>
<li><span class="command">alt</span> is called <b>Option</b>, and the symbol is <img src="/images/articles/mac_alt.gif" alt="like a tall Z with a dash in the top right" height="11" width="12" /></li>

<li>The 'apple key' is called <b>Command</b> (<abbr title="Command">cmd</abbr>), and the symbol is <img class="middle" src="/images/articles/mac_command.gif" alt="a square with circles on each corner" height="12" width="12" /></li>
<li><span class="command">shift</span> is called <b>Shift</b>, and the symbol is <img class="middle" src="/images/articles/mac_shift.gif" alt="clear upward arrow" height="12" width="12" /></li>
<li>The backspace key is called <b>Reset</b>, and the symbol is <img src="/images/articles/mac_reset.gif" alt="a left arrow with a cross inside" height="11" width="15" /></li>

<li><span class="command">esc</span> is called <b>Escape</b>, and the symbol is <img class="middle" src="/images/articles/mac_escape.gif" alt="a square with circles with an arrow pointing to the top left" height="12" width="12" /></li>
</ol>

<h3 id="The_Operating_System">The Operating System</h3>

<div class="figure">
    <img src="/images/articles/mac_dock.jpg" height="31" width="173" alt=" " />
    <p>Example dock with open apps</p>
</div>

<ul>
<li>The hash (<span class="command">#</span>) is <span class="command">alt + 3</span>.<p class="smaller"><i>Editor's note: yeah: random, I know.</i></p></li>
<li>The ticks under the icons on the dock mean the application is open.</li>
<li>Finder is always open (it's what the desktop runs through for example).</li>
<li>iCal's default icon is July 17th - it only changes when it's open!</li>
</ul>

<h3 id="Keyboard_Navigation">Keyboard Navigation &amp; Shortcuts</h3>

<p>Since this article is for PC users, I'm going to keep this simple and refer to the keys in PC talk rather than Mac.</p>

<p><span class="command">apple + tab</span>: cycle open programs - not open windows.</p>

<p><span class="command">apple + `</span> (backtick): cycle open windows within a program.</p>

<p><span class="command">apple + shift + 3</span>: capture the screen to a file (saved to the desktop).</p>

<p><span class="command">apple + shift + 4</span>: capture a selected area of the screen.</p>

<p><span class="command">apple + down</span> in Finder: open the selected file or folder.</p>

<p><span class="command">apple + up</span> in Finder: go to the parent folder.</p>

<p><span class="command">alt + left (or right)</span>: move the cursor left or right one word at a time (add <span class="command">shift</span> to select).</p>

<p><span class="command">up</span> and <span class="command">down</span>, or <span class="command">apple + left</span> and <span class="command">apple + right</span> in a text field: put the cursor at the start or end of a field respectively, i.e. equivalent to the <span class="command">home</span> and <span class="command">end</span> PC keys.</p>

<p><span class="command">space</span> and <span class="command">shift + space</span> in Safari or Mail (and others): page up or down respectively.</p>

<h3 id="Drag_n_Drop">Drag &amp; Drop</h3>

<div class="figure">
    <img src="/images/articles/mac_drag.jpg" width="85" height="65" alt=" " />
    <p>Drag and copy</p>

</div>

<p>By default dragging and dropping a file moves the file.</p>

<p>To drag and copy a file, hold the <span class="command">alt</span> key down.</p>

<p>To create a shortcut to the file, hold down <span class="command">apple + alt</span> keys.</p>
<a href="http://leftlogic.com/lounge/tag/beginners" rel="tag">beginners</a>, <a href="http://leftlogic.com/lounge/tag/mac" rel="tag">mac</a>, <a href="http://leftlogic.com/lounge/tag/tips" rel="tag">tips</a>]]></content:encoded>
			<wfw:commentRss>http://leftlogic.com/lounge/articles/mac_newbie_tips/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Auto-selecting navigation</title>
		<link>http://leftlogic.com/lounge/articles/auto-selecting_navigation/</link>
		<comments>http://leftlogic.com/lounge/articles/auto-selecting_navigation/#comments</comments>
		<pubDate>Sat, 17 Jun 2006 14:00:52 +0000</pubDate>
		<dc:creator>Remy Sharp</dc:creator>
		
		<category><![CDATA[Articles]]></category>
<category>beginners</category><category>javascript</category><category>jquery</category><category>tutorial</category>
		<guid isPermaLink="false">http://offline.leftlogic.com/info/articles/auto-selecting_navigation/</guid>
		<description><![CDATA[This article offers an alternative to the laborious task of coding up which &#60;li&#62; or &#60;a&#62; navigation tags need the 'selected' class (or however you concoct the solution).



The Problem

Any web developer, or designer that wants to offer some visual indication which page the we are on, they will probably use a combination of 'selected' and [...]]]></description>
			<content:encoded><![CDATA[<p>This article offers an alternative to the laborious task of coding up which &lt;li&gt; or &lt;a&gt; navigation tags need the 'selected' class (or however you concoct the solution).</p>

<p><a class="more" id="more-10"></a></p>

<h3 id="the_problem">The Problem</h3>

<p>Any web developer, or designer that wants to offer some visual indication which page the we are on, they will probably use a combination of 'selected' and possibly 'unselected' classed on the link or tab.</p>

<p>The developer's task is to ensure that the right link or tab is highlighted when we are viewing the page.</p>

<h3 id="old_problem">The Old Solution</h3>

<p>The way that I have solved this problem in the past (being a developer), either using Perl or <abbr title="PHP: Hypertext Preprocessor">PHP</abbr>, would be to use a hash to track which page is selected, and when I print each link or tab, I would reference the hash with the key value of the current element name.</p>

<p>For example (<a href="#example_in_php" onclick="javscript:show_example('php'); return false;">in PHP</a>, <a href="#example_in_perl" onclick="javscript:show_example('perl'); return false;">in Perl</a>):</p>

<script  type="text/javascript">
<!--
function show_example(lang)
{
    $('code#example_in_perl').hide();
    $('code#example_in_php').hide();
    $('code#example_in_' + lang).show();
}

$(document).ready(function() { $('code#example_in_perl').hide() });
//-->
</script>

<pre><code class="prettyprint" id="example_in_php">$selected = Array('articles' =&gt; ' class="selected"');

foreach ($links as $link) 
{
  echo '&lt;a href="' . $link-&gt;href . '" ' . 
    $selected[$link-&gt;name] . '&gt;' . 
    $link-&gt;name . '&lt;/a&gt;';
}</code></pre>

<noscript>
    <div class="gap"></div>
</noscript>

<pre><code class="prettyprint" id="example_in_perl">my $selected = { articles =&gt; ' class="selected"'};

foreach my $link (@links)
{
  print qq{&lt;a href="$link-&gt;{'href'}" 
    $selected-&gt;{$link-&gt;{'name'}}&gt;$link-&gt;{'name'}&lt;/a&gt;};
}</code></pre>

<h3 id="new_solution">The New Solution</h3>

<p>The new solution really comes about, because as a developer I really want to avoid doing the dull work, and separating the layout code from the application code is what we all really want to do.</p>

<p>In this solution, you create all the <abbr title="Hyper Text Markup Language">HTML</abbr>, either through static files, or as you like, and add some JavaScript seasoning to make the the navigation automatically highlight itself.</p>

<h4>Prerequisites</h4>

<ol>
<li>You are happy that when we don't have JavaScript enabled, the navigation doesn't highlight.  I justify this by the simple fact as users, we're more interested in the page content, than which page link is highlighted.</li>
<li>The navigation sits cleanly in one DIV under one ID.</li>
</ol>

<h4>The Code</h4>

<p>Notice that this is we've done away with our backend solution altogether.</p>

<pre><code class="prettyprint">&lt;h3&gt;Info&lt;/h3&gt;
&lt;ul id="sidebar_content"&gt;
  &lt;li&gt;&lt;a href="/info/news"&gt;News&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="/info/articles"&gt;Articles&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="/info/resources"&gt;Resources&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="/info/about"&gt;About&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</code></pre>

<p>Now we add our dash of JavaScript spice...</p>

<pre><code class="prettyprint">function select_nav() {
  var nav_links = document.getElementById('sidebar_content').getElementsByTagName('a');
  var selected = location.pathname;

  for (var i = 0; i &lt; nav_links.length; i++) {
    var link = nav_links[i].pathname;
    if (link.substring(0, 1) != '/') link = '/' + link; // fiddle IE's view of the link
    if (link == selected) nav_links[i].setAttribute(cattr, 'selected');
  }
}

window.onload = function() {
  select_nav();
};</code></pre>

<p>...and Bob's your father's brother.  The link will automatically select itself.</p>

<p>For those of you using <a target="_blank" href="http://www.jquery.com">jQuery</a>, here's the same solution, but on a lot less lines (you've got hand it to those jQuery chaps):</p>

<pre><code class="prettyprint">$(function(){ if (location.pathname.substring(1))
  $('#sidebar_content a[@href$="' + location.pathname.substring(1) + '"]')
    .attr('class', 'selected')
});</code></pre>

<p class="smaller">Updated 25th Sep '06 - with thanks to Kevin, Fallo and Steve.</p>

<p>Note: the <code>a[@href$=</code> part is saying that any anchor tag whose "href" attribute value ends exactly with the string <code>location.pathname.substring(1)</code>.</p>

<p>Feel free to add comments, suggestions, ask questions, point out any errors or suggest a better alternative.</p>
<a href="http://leftlogic.com/lounge/tag/beginners" rel="tag">beginners</a>, <a href="http://leftlogic.com/lounge/tag/javascript" rel="tag">javascript</a>, <a href="http://leftlogic.com/lounge/tag/jquery" rel="tag">jquery</a>, <a href="http://leftlogic.com/lounge/tag/tutorial" rel="tag">tutorial</a>]]></content:encoded>
			<wfw:commentRss>http://leftlogic.com/lounge/articles/auto-selecting_navigation/feed/</wfw:commentRss>
		</item>
	</channel>
</rss>
