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

<channel>
	<title>BlackFade.com &#187; Code</title>
	<atom:link href="http://www.blackfade.com/category/code/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.blackfade.com</link>
	<description>Rob Taylor - Web Developer, UK</description>
	<lastBuildDate>Wed, 18 Jan 2012 10:00:18 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>Opera, rewriting the Web one site at a time</title>
		<link>http://www.blackfade.com/2011/09/13/opera-web-rewrite/</link>
		<comments>http://www.blackfade.com/2011/09/13/opera-web-rewrite/#comments</comments>
		<pubDate>Tue, 13 Sep 2011 07:42:55 +0000</pubDate>
		<dc:creator>Rob</dc:creator>
				<category><![CDATA[BBC]]></category>
		<category><![CDATA[Browsers]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[Opera]]></category>
		<category><![CDATA[Work]]></category>
		<category><![CDATA[Hacks]]></category>
		<category><![CDATA[LinkedIn]]></category>

		<guid isPermaLink="false">http://www.blackfade.com/2011/09/13/opera-web-browser/</guid>
		<description><![CDATA[I work for the BBC and we work very hard to make sure anything that the public see is of the highest standard, and we&#8217;re always working to improve that methodology over time. Yes, like any live and evolving website, the occasional bug does slip through the net. We do our very best to prevent [...]]]></description>
			<content:encoded><![CDATA[<div id="attachment_544" class="wp-caption alignright" style="width: 160px"><a href="http://www.blackfade.com/wp-content/uploads/2011/09/Opera.png" class="highslide-image" onclick="return hs.expand(this);"><img class="size-thumbnail wp-image-544" title="Opera Web Browser" src="http://www.blackfade.com/wp-content/uploads/2011/09/Opera-150x150.png" alt="Opera Web Browser" width="150" height="150" /></a><p class="wp-caption-text">Opera Web Browser</p></div>
<p>I work for the BBC and we work very hard to make sure anything that the public see is of the highest standard, and we&#8217;re always working to improve that methodology over time. Yes, like any live and evolving website, the occasional bug does slip through the net. We do our very best to prevent it, having a dedicated team of User Experience and Functionality testers, along side a team of people writing automated tests and software. But bugs can occasionally happen.</p>
<p>When we do find a bug, especially with a new feature, we identify and fix the problem as quickly as possible. This is where I come in. As a developer, part of my job is to do the finding and fixing.</p>
<p>So I was handed a bug to look at. The video was not appearing for some Opera users. I talked over the situation with our QA manager, and discussed just how long the fix should take, how we&#8217;re going to roll it out and what impact it will have on users until then.</p>
<p>That having been sorted, I started work on my side of the problem. When I finished, I found my fix only served to create another problem. And another appeared. And another, and another.</p>
<p>By chance, I switched off a setting called &#8220;Browser JavaScript&#8221;. Suddenly, everything starts working. I just sat there stunned. &#8220;What just happened?&#8221; I started asking myself. I switch Browser JS back on, and it breaks again. So I started running around the office looking for anyone with Opera to test out this problem.</p>
<p>I found that roughly 50% of users are seeing the same results as I was. The other 50% haven&#8217;t got a problem.</p>
<p>So I start reading up about browser JS and start having a look at the file directly. Lo and behold, there is a direct mention of BBC iPlayer. They&#8217;re rewriting a core browser JS function. &#8220;What the hell?&#8221;, you could rightly ask.</p>
<pre class="prettyprint lang-js">} else if(hostname.indexOf('bbc.co.uk')&gt;-1 &amp;&amp; pathname.indexOf('/iplayer')&gt;-1){ // PATCH-426, Add to favourites fails on BBC iPlayer because of script loading/parsing timing issue
	document.getElementsByTagName=function(n){
		var elms=getElementsByTagName.call(this, n);
		if(elms.length==0 &amp;&amp; n=='body')return [document.documentElement];
		return elms;
	}
	if(self==top)postError.call(opera, 'Opera has modified the JavaScript on '+hostname+' (Add to favourites fails on BBC iPlayer because of script loading/parsing timing issue). See browser.js for details');</pre>
<p>They&#8217;re rewriting a core function, built into the browser, and it&#8217;s worth noting that this isn&#8217;t a problem with iPlayer that they&#8217;re fixing. It&#8217;s a problem with Opera that they&#8217;re working around for only iPlayer.</p>
<p>I did a little research and found this blog, <a title="Opera - Opera's site patching" href="http://my.opera.com/core/blog/show.dml/3130540" target="_blank">my.opera.com/core/blog/show.dml/3130540</a> (<strong>Update:</strong> Can anyone tell me why this only loads in Opera?) from Opera, stating:</p>
<blockquote><p>&#8220;Opera has more experience with site-specific patches than other browser vendors, since we&#8217;ve been patching the web since Opera 8.01. I believe our solution is also by far the most advanced one&#8221;.</p></blockquote>
<p>Did I just read that right?  Opera are better at developing websites that anyone? That&#8217;s an unbelievable statement to make.</p>
<p>What about GreaseMonkey, you might ask. GreaseMonkey is a great little tool for letting users add functionality to websites that they think is missing. Opera are taking that idea and forcing it onto their users by default. It&#8217;s not even opt in.</p>
<p><strong>Conclusion: </strong>I&#8217;ve met some of the Opera people before today. <a title="Bruce Lawson - Twitter" href="https://twitter.com/#!/brucel" target="_blank">Bruce Lawson</a> is a particularly fine chap. Which is why I&#8217;m confused why they would think that as a software development company, not only do they know web development better than web developers, but that they have a duty to edit those sites which fail in their browser.  The correct course of action, for me, would have been to contact us directly and report the issue.  I just hope they do this in future.</p>
<p><strong>Update:</strong> We got an apology <a title="Opera - Why we broke BBC iPlayer" href="http://my.opera.com/sitepatching/blog/2011/09/12/why-we-broke-2" target="_blank">my.opera.com/sitepatching/blog/2011/09/12/why-we-broke-2</a> from Opera which was extremely nice of them.</p>
<p><strong>Update:</strong> The apology managed to get to #10 on Hacker news <img src='http://www.blackfade.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://www.blackfade.com/2011/09/13/opera-web-rewrite/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Roundup</title>
		<link>http://www.blackfade.com/2010/07/18/roundup/</link>
		<comments>http://www.blackfade.com/2010/07/18/roundup/#comments</comments>
		<pubDate>Sun, 18 Jul 2010 08:03:59 +0000</pubDate>
		<dc:creator>Rob</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[Hardware]]></category>
		<category><![CDATA[Movies]]></category>
		<category><![CDATA[Rebuild]]></category>
		<category><![CDATA[Server]]></category>
		<category><![CDATA[Terry Pratchett]]></category>
		<category><![CDATA[Going Postal]]></category>
		<category><![CDATA[Last Airbender]]></category>
		<category><![CDATA[prince of persia]]></category>
		<category><![CDATA[sands of time]]></category>

		<guid isPermaLink="false">http://www.blackfade.com/?p=327</guid>
		<description><![CDATA[I&#8217;ve been pretty busy of late, so I thought I would just write a quick recap of whats been going on, and what happened with previous posts. Epic Server Rebuild – The Prelude This has almost stalled because of some MAJOR problems with the existing hardware. It&#8217;s all running again, but the server doesn&#8217;t have [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been pretty busy of late, so I thought I would just write a quick recap of whats been going on, and what happened with previous posts.</p>
<h3><a href='/2010/05/26/epic-server-rebuild-the-prelude/'>Epic Server Rebuild – The Prelude</a></h3>
<p>This has almost stalled because of some MAJOR problems with the existing hardware.  It&#8217;s all running again, but the server doesn&#8217;t have automated downloading right now, and the media center is currently running from my spare Acer Revo.</p>
<h3><a href='/2010/05/26/terry-pratchetts-going-postal-extended-trailer/'>Terry Pratchett’s Going Postal</a></h3>
<p>Now, much to my dissappointment, this was all in all a &#8220;Meh!&#8221; film.  I was far more impressed with Hogfather than Going Postal.  It felt like they were simply going through the motions.  The film had the essence of the book, but left out so much story, that they have to fabricate sections just to tie what was left together.</p>
<h3><a href='/2010/05/25/last-airbender-movie-trailer-2/'>Last Airbender Movie</a></h3>
<p>Oh dear LORD what did they do to my beloved Airbender?!  It was obvious that not one of the cast had watched even a single episode of the original show.  This was just, plain and simply, painful!  Sometimes I forget, what a powerful bender M. Night Shyamalan is.</p>
<h3><a href='/2010/04/07/prince-of-persia-movie-trailer-2/'>Prince Of Persia Movie</a></h3>
<p>Now, on the other hand, I liked this, simply because they managed to take the basic story of the prince of persia, and turn it into a good film.  Most people will hate this because it doesn&#8217;t follow the story of the game, but I personally think that game stories don&#8217;t work in movies.  I believe that this was a pretty good attempt.  Not the best, but certainly not the worst.</p>
<h2>Coming up</h2>
<p>I&#8217;ve added a new section to the site, Presentations, which I will be filling with any presentations I do for work, or at conferences, if I ever get the chance.  The first talk will be about &#8220;Internal Design&#8221;, and how disciplined coding principles will help yourself and others who work on the project. </p>
]]></content:encoded>
			<wfw:commentRss>http://www.blackfade.com/2010/07/18/roundup/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>JS Table Sorting for BBC Glow &#8211; v1.3 (Updated)</title>
		<link>http://www.blackfade.com/2010/04/01/js-table-sorting/</link>
		<comments>http://www.blackfade.com/2010/04/01/js-table-sorting/#comments</comments>
		<pubDate>Thu, 01 Apr 2010 10:43:02 +0000</pubDate>
		<dc:creator>Rob</dc:creator>
				<category><![CDATA[BBC Glow]]></category>
		<category><![CDATA[Code]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[LinkedIn]]></category>
		<category><![CDATA[Sorting]]></category>
		<category><![CDATA[Table]]></category>

		<guid isPermaLink="false">http://www.blackfade.com/?p=144</guid>
		<description><![CDATA[Morning all, I&#8217;ve recently started working for the BBC, and as such I&#8217;ve started working with the internal JavaScript framework, Glow. So this is my first attempt at writing to some code with it. I hope it&#8217;s useful to someone. It&#8217;s just a simple JavaScript table sort. The Introduction Just a bit of useful script [...]]]></description>
			<content:encoded><![CDATA[<p>Morning all, I&#8217;ve recently started working for the <acronym title="British Broadcasting Company" lang="en">BBC</acronym>, and as such I&#8217;ve started working with the internal JavaScript framework, <a href="http://www.bbc.co.uk/glow/">Glow</a>.</p>
<p>So this is my first attempt at writing to some code with it.  I hope it&#8217;s useful to someone.  It&#8217;s just a simple JavaScript table sort.</p>
<h3>The Introduction</h3>
<p>Just a bit of useful script for client side sorting of tables.  Simple click the headers of the columns, and it will arrange it in ascending order.  A second click will arrange it in descending order.</p>
<h3>As Seen On&#8230;</h3>
<p><strong>BBC News Common-Wealth Games Medals Table :</strong> <a href="http://news.bbc.co.uk/sport1/hi/commonwealth_games/delhi_2010/medals_table/">In English</a>, <a href="http://www.bbc.co.uk/urdu/sport/2010/10/101004_commonwealth_medalstable.shtml">In Urdu</a>, <a href="http://www.bbc.co.uk/hindi/sport/2010/10/101001_cwg_medaltally_va.shtml">In Hindi</a>, and <a href="http://www.bbc.co.uk/worldservice/sport/2010/10/101001_commonwealth_games_table.shtml">on BBC Worldwide</a></p>
<p><strong>UPDATE &#8211; 30th July 2010:</strong> After talking with a BBC colleague, it occurred to me that I could improve the code, so that it doesn&#8217;t rely on the class names for the ordering.  The class names are now purely for decoration, not functionality.</p>
<p><strong>UPDATE 2 &#8211; 30th July 2010:</strong> It was just pointed out by James (thanks man), that Glow/JS doesn&#8217;t handle number sorting brilliantly, so I&#8217;ve added a small patch to improve this.  Thanks to James for his suggestion.</p>
<p><strong>UPDATE 3 &#8211; 3rd August 2010:</strong> Some alterations to improve sorting of floats.</p>
<p><span id="more-144"></span></p>
<h3>The Demo</h3>
<table id="myTable">
<thead>
<tr>
<th class="col1">Integers</th>
<th class="col2">Floats</th>
<th class="col3">Strings</th>
</tr>
</thead>
<tbody>
<tr>
<td class="col1">3</td>
<td class="col2">5.32</td>
<td class="col3">Helen</td>
</tr>
<tr>
<td class="col1">2</td>
<td class="col2">8.28</td>
<td class="col3">Laura</td>
</tr>
<tr>
<td class="col1">4</td>
<td class="col2">4.84</td>
<td class="col3">Catherin</td>
</tr>
<tr>
<td class="col1">1</td>
<td class="col2">2.91</td>
<td class="col3">Simon</td>
</tr>
<tr>
<td class="col1">5</td>
<td class="col2">9.46</td>
<td class="col3">James</td>
</tr>
</tbody>
</table>
<h3>The Source Code</h3>
<h4>JavaScript</h4>
<pre class="prettyprint lang-js">gloader.load( [ 'glow', '1', 'glow.dom', 'glow.events' ], {
        async: true,
        onLoad: function( glow ) {
                var getPosition = function( heystack, needle )
                {
                        var position = 0;
                        heystack.each( function( i ){
                                if( needle.eq( this ) )
                                        position = i;
                        });
                        return position;
                }
                var sortDir = 0;
                var sortBy_store;
                glow.events.addListener( '#myTable thead tr th' , 'click', function ( event ) {

                        var sortBy      = getPosition( glow.dom.get('#myTable thead tr th'), glow.dom.get( this ) );

                        if( sortBy == sortBy_store )
                                sortDir = ( sortDir ? 0 : 1 );
                        else
                                sortDir = 0;

                        sortBy_store    = sortBy;

                        glow.dom.get( '#myTable tbody tr' ).remove().sort( function( rowA, rowB ) {
                                var sortArr = new Array( 1, -1 );
                                if( sortDir )
                                        sortArr = new Array( -1, 1 );

                                var rowA_obj = glow.dom.get( rowA ).get('td');
                                var sortA = glow.dom.get( rowA_obj[sortBy] ).text();

                                var rowB_obj = glow.dom.get( rowB ).get('td');
                                var sortB = glow.dom.get( rowB_obj[sortBy] ).text();

                                if( !isNaN( sortA ) )
                                        sortA = parseFloat( sortA )
                                if( !isNaN( sortB ) )
                                        sortB = parseFloat( sortB )

                                return sortA > sortB ? sortArr[0] : sortArr[1];

                        }).appendTo( '#myTable tbody' );

                });
        }
});</pre>
<h4>HTML</h4>
<pre class="prettyprint lang-html">&lt;table id='myTable'&gt;
	&lt;thead&gt;
		&lt;tr&gt;
			&lt;th class='col1'&gt;Number&lt;/th&gt;
			&lt;th class='col2'&gt;Male Names&lt;/th&gt;
			&lt;th class='col3'&gt;Female Names&lt;/th&gt;
		&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
		&lt;tr&gt;
			&lt;td class='col1'&gt;3&lt;/td&gt;
			&lt;td class='col2'&gt;James&lt;/td&gt;
			&lt;td class='col3'&gt;Helen&lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr&gt;
			&lt;td class='col1'&gt;2&lt;/td&gt;
			&lt;td class='col2'&gt;Thomas&lt;/td&gt;
			&lt;td class='col3'&gt;Laura&lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr&gt;
			&lt;td class='col1'&gt;4&lt;/td&gt;
			&lt;td class='col2'&gt;Steven&lt;/td&gt;
			&lt;td class='col3'&gt;Catherin&lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr&gt;
			&lt;td class='col1'&gt;1&lt;/td&gt;
			&lt;td class='col2'&gt;Simon&lt;/td&gt;
			&lt;td class='col3'&gt;Samantha&lt;/td&gt;
		&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.blackfade.com/2010/04/01/js-table-sorting/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Ajax Content for MooTools v1.2 (Facebook Style)</title>
		<link>http://www.blackfade.com/2009/10/22/ajax-content-for-mootools-v1-2-facebook-style/</link>
		<comments>http://www.blackfade.com/2009/10/22/ajax-content-for-mootools-v1-2-facebook-style/#comments</comments>
		<pubDate>Thu, 22 Oct 2009 08:48:01 +0000</pubDate>
		<dc:creator>Rob</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[MooTools]]></category>
		<category><![CDATA[Ajax]]></category>
		<category><![CDATA[Content]]></category>
		<category><![CDATA[facebook]]></category>
		<category><![CDATA[LinkedIn]]></category>
		<category><![CDATA[loader]]></category>
		<category><![CDATA[Mootools]]></category>

		<guid isPermaLink="false">http://www.blackfade.com/?p=125</guid>
		<description><![CDATA[Welcome to my second attempt at writing up a mootools class. This one&#8217;s a little more advanced this time. It attaches an Ajax handler to all links on a page which conform to the selector you give it. For example, you can tell it to attach to all standard links (&#60;A HREF=&#8217;/here/&#8217;&#62;Hello&#60;/A&#62;), or links with [...]]]></description>
			<content:encoded><![CDATA[<p>Welcome to my second attempt at writing up a mootools class.  This one&#8217;s a little more advanced this time.</p>
<p>It attaches an Ajax handler to all links on a page which conform to the selector you give it.  For example, you can tell it to attach to all standard links (&lt;A HREF=&#8217;/here/&#8217;&gt;Hello&lt;/A&gt;), or links with a specific class as i&#8217;ve done with the code below (&lt;A HREF=&#8217;/here/&#8217; CLASS=&#8217;ajax&#8217;&gt;Hello&lt;/A&gt;).</p>
<p>I hope someone finds this useful.  As ever this was created after I kept saying that I could write something a hell of a lot better than anything else I was finding.  This might be a bold statement, but I was having trouble finding anything that would do the job, and simply.</p>
<p><span id="more-125"></span><br />
(Demo to come, I&#8217;m just posting the code up right now.)</p>
<pre class='prettyprint lang-js'>/*
 * ContentHandler
 *
 * Content handler that attaches to links and loads content through AJAX
 *
 * @author Rob Taylor
 * @created 28/09/09
 * @modified 29/09/09
 * @version 1.3.5.10
 */

	var ContentHandler = new Class({
		Implements: [Options, Events, Log],

		options : {
			// Array of container elements to load via AJAX
			container		: $('content'),

			// Loading graphic and text to display while working
			loadingImage		: '/images/ajax-loader.gif',
			loadingMessage		: 'Loading Content...',

			// How much Opacity to set on 'Container' while loading new page.
			loadingTransparency	: 0,

			// Type of link to load via AJAX. Defaults to &lt;a&gt; tags
			linkIdentifier		: 'a',

			// TRUE to enable console logging. FALSE by default
			debugMode		: false
		},

		currentURL : '',
		isNavigating : false,

		/*
		 * initialize
		 *
		 * Default constructor. Sets configuration options, attaches load event links and triggers initial load
		 *
		 * @param mixed		options		Array of config options.  Supported elements:
		 *					container		-	Container element to load Ajax into
		 *					loadingImage		-	URL of image to display while working
		 *					loadingMessage		-	Message to display while working
		 *					loadingTransparency	-	Transparency level of 'container' when request is made.  Must be between 0 and 1. Defaults to 0
		 *					linkIdentifier		-	HTML tagname to attach onclick loader to. Defaults to &lt;a&gt;
		 *					debugMode		-	TRUE to enable console logging. FALSE by default
		 */
		initialize : function( options ) {

			// Set configuration options
			this.setOptions(options);

			this.debug('Starting :: ContentHandler');

			// Loop through link elements attaching loader
			$$(this.options.linkIdentifier).each( function( element ){
				this.attachHandler( element );
			}.bind(this));

			// Do initial content load if location is specified
			if( window.location.hash &#038;&#038; window.location.hash.length > 1 )
			{
				// Get initial page
				var url = window.location.hash.substr( 1, window.location.hash.length );

				this.getContent( url, true );
			}

			// Attach check to re-load content if URL changes or previous attempt fails
			this.updateContent.periodical( 200, this );

		},

		/*
		 * createLoader
		 *
		 * Populates and displays
		 */
		createLoader : function(){
			this.debug('Creating :: Loader Image');

			// Container padding
			var padding		= 40;

			// Create image element
			var content		= $( this.options.container );
			var loaderImage		= new Element( 'img', {
				src	: this.options.loadingImage,
				alt	: 'Loading',
				title	: 'Loading'
			});

			// Create test element
			var loaderMessage	= new Element( 'div' ).set('text',this.options.loadingMessage);
			loader			= new Element( 'div' );

			// Style elements
			content.setStyle( 'position', 'relative' );
			loader.setStyles({
				margin		: 'auto',
				textAlign	: 'center',
				position	: 'absolute',
				opacity		: 0
			});

			// Autoresize container onload to fit image
			loaderImage.addEvent('load', function(){
				loader.setStyles({
					height		: ( loaderImage.getSize().y + padding ),
					width		: ( loaderImage.getSize().x + padding ),
					top		: 20 + content.getPosition().y,
					left		: ( ( ( content.getSize().x / 2 ) - ( loaderImage.getSize().x / 2 ) ) - padding ) + content.getPosition().x
				});
			});
			// Add image and message to container
			loader.adopt( loaderImage,loaderMessage );

			// Attach loader to content area and fade in
			$(document.body).adopt( loader );
			loader.fade('in');

		},

		destroyLoader : function(){
			if( loader )
				loader.destroy();
		},

		getContent : function( url, freshStart ){
			this.debug('Collecting :: Page Content');

			var content = $( this.options.container );

			if( this.isNavigating &#038;&#038; request_content )
				request_content.cancel();

			request_content = new Request.HTML({
				url		: url,
				method		: 'get',
				link		: 'cancel',
				update		: content,
				onRequest	: function(){
					this.debug('Collecting :: Page Content -> Request Made');

					// Set active request flag (prevents periodical spawning simultaneous requests)
					this.isNavigating = true;

					// Store current content in case of rollback (e.g. if request fails)
					content.store( 'content', content.get('html') );

					if( freshStart ){
						// Flush content
						content.empty();
					}
					else{
						content.get('tween', {
							property: 'opacity',
							duration: 'normal'
						}).start( this.options.loadingTransparency );
					}

					// Display loaders
					this.createLoader();

				}.bind(this),
				onComplete	: function(){
					this.debug('Collecting :: Page Content -> Complete');

					// Reset active request flag
					this.isNavigating = false;

					this.destroyLoader();

					if( !freshStart ){
						content.get('tween', {
							property: 'opacity',
							duration: 'short'
						}).start(1);
					}

				}.bind(this),
				onSuccess	: function(){
					this.debug('Collecting :: Page Content -> Success');

					// Track new content URL
					this.currentURL = url;

					// Flush stored content
					content.store( 'content', '' );

					if( !freshStart ){
						window.location.hash = url;
					}

					content.getElements( this.options.linkIdentifier ).each( function( inner_element ){
						this.attachHandler( inner_element );
					}.bind(this));

					this.debug('Current URL: '+this.currentURL);

				}.bind(this),
				onFailure	: function(){
					this.debug('Collecting :: Page Content -> Fail');

					// Retrieve stored content
					content.retrieve( 'content' );

				}
			}).send();

			return false;

		},

		attachHandler : function( element ){
			if( $(element) ){
				if( this.checkLink( $(element).get('href') ) )
				{
					url = $(element).get('href');
					//this.debug('Adding Handler : "'+url+'"');
					$(element).addEvent('click', this.getContent.bind(this,url) );
				}
			}
			else{
				this.debug('No Valid Element.');
			}
		},

		updateContent : function(){

			var url = window.location.hash.substr( 1, window.location.hash.length );
			if( this.currentURL != url &#038;&#038; !this.isNavigating &#038;&#038; this.checkLink( url ) ){
				this.debug('Updating :: Page Content: "'+url+'"');
				this.getContent( url );
			}

		},

		checkLink : function( url ){

			if( url.test('^http:|^https:' ) ) // We're assuming here, that external links, do not want to be loaded inside the container.
				return false;

			return true;
		},

		debug : function( message ){

			if( !this.options.debugMode )
				return;

			this.log( '[Content Handler] ' + message );

		}

	});

	document.addEvent('domready', function(){
		content = new ContentHandler({
			linkIdentifier : 'a.ajax' // this will attach to any link with a class of 'ajax'.
			//linkIdentifier : 'a' // This will attach to any link.
		});
	});</pre>
<h3>Available Options</h3>
<ul>
<li><strong>container</strong> : Container element to load Ajax into</li>
<li><strong>loadingImage</strong> : URL of image to display while working</li>
<li><strong>loadingMessage</strong> : Message to display while working</li>
<li><strong>loadingTransparency</strong> : Transparency level of &#8216;container&#8217; when request is made.  Must be between 0 and 1. Defaults to 0</li>
<li><strong>linkIdentifier</strong> : HTML tagname to attach onclick loader to. Defaults to &lt;a&gt;</li>
<li><strong>debugMode</strong> : TRUE to enable console logging. FALSE by default</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.blackfade.com/2009/10/22/ajax-content-for-mootools-v1-2-facebook-style/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Moodal Window for MooTools 1.2.3.1</title>
		<link>http://www.blackfade.com/2009/09/24/moodal-window-for-mootools-1-2-3-1/</link>
		<comments>http://www.blackfade.com/2009/09/24/moodal-window-for-mootools-1-2-3-1/#comments</comments>
		<pubDate>Thu, 24 Sep 2009 11:58:12 +0000</pubDate>
		<dc:creator>Rob</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[MooTools]]></category>
		<category><![CDATA[LinkedIn]]></category>
		<category><![CDATA[Modal]]></category>
		<category><![CDATA[Mootools]]></category>
		<category><![CDATA[Window]]></category>

		<guid isPermaLink="false">http://www.blackfade.com/?p=77</guid>
		<description><![CDATA[This is my first attempt at publishing one of my scripts, and my first real attempt at writing a MooTools class. I hope you enjoy it, and check out the demo: Demo &#8211; I plan on replacing this with an inline demo some time very soon (See below). Launch AJAX Demo &#8211; Not working right [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.blackfade.com/wp-content/uploads/2009/09/MoodalWindow.png" class="highslide-image" onclick="return hs.expand(this);"><img src="http://www.blackfade.com/wp-content/uploads/2009/09/MoodalWindow-150x150.png" alt="MoodalWindow" title="MoodalWindow" width="150" height="150" class="alignleft size-thumbnail wp-image-101" /></a>This is my first attempt at publishing one of my scripts, and my first real attempt at writing a MooTools class.</p>
<p>I hope you enjoy it, and check out the demo:<br />
<span id="more-77"></span><br />
<a href="/demo/MoodalWindow/" target="_blank">Demo</a> &#8211; I plan on replacing this with an inline demo some time very soon (See below).<br />
<a href='/demo/MoodalWindow/ajax-demo.html' title='AJAX Demo' class='ajax'>Launch AJAX Demo</a> &#8211; Not working right now, trying to find the out what&#8217;s not connecting. <img src='http://www.blackfade.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<h3 style='clear: both;'>Here are the image files you will need:</h3>
<p>I suggest you find something better, these were just temp images for me.</p>
<pre>Close:<img class="alignnone size-full wp-image-91" title="close" src="http://www.blackfade.com/wp-content/uploads/2009/09/close.png" alt="close" width="16" height="16" />
Resize: <img class="size-full wp-image-92 alignnone" title="resize" src="http://www.blackfade.com/wp-content/uploads/2009/09/resize.png" alt="resize" width="17" height="17" />
Loading: <a href="http://www.blackfade.com/wp-content/uploads/2009/09/ajax-loader.gif" class="highslide-image" onclick="return hs.expand(this);"><img class="alignnone size-full wp-image-93" title="ajax-loader" src="http://www.blackfade.com/wp-content/uploads/2009/09/ajax-loader.gif" alt="ajax-loader" width="66" height="66" /></a>
</pre>
<h3>First the Javascript</h3>
<p>I&#8217;m assuming you&#8217;ve got MooTools Code and More installed.</p>
<pre class='prettyprint lang-js'>
var MoodalWindow = new Class({

	Implements: [Options, Events],

	options : {
		container		: window,
		height			: 700,
		width			: 600,
		overlayColor		: '#000000',
		overlayTransparency	: 0.7,
		overlayClose		: true,
		move			: true,
		resize			: true,
		url			: '',
		title			: 'Modal Window'
	},

	/*
	Constructor: initialize
		Constructor

		Add event on formular and perform some stuff, you now, like settings, ...
	*/
	initialize : function( element, options ) {
		if( $(element) )
		{
			if( $(element).get('title') )
				this.options.title	= $(element).get('title');
			else if( $(element).get('text') )
				this.options.title	= $(element).get('text');

			if( $(element).get('href') )
				this.options.url	= $(element).get('href');

			this.setOptions(options);

			$(element).addEvent('click', this.createPopup.bind(this) );
			return false;
		}
	},

	createPopup : function(){
		this.killStraglers();

		this.createOverlay();
		this.createWindow();
		if( this.options.title ){
			this.createTitle();
			this.createCloser();
		}
		this.createContent();
		if( this.options.resize )
			this.createResizer();
		return false;
	},

	createOverlay : function(){
		var overlayColor		= this.options.overlayColor;
		var overlayTransparency		= this.options.overlayTransparency;
		modalOverlay = new Element( 'div', { 'id':'modalOverlay' } ).setStyles({
			backgroundColor	: this.options.overlayColor,
			position	: 'absolute',
			left		: 0,
			top		: 0,
			height		: window.getScrollSize().y,
			width		: window.getScrollSize().x,
			zIndex		: 99
		});

		if( this.options.overlayClose )
			modalOverlay.addEvent('click', this.closePopup.bind(this) );

		modalOverlay.fade('hide');

		$(document.body).grab( modalOverlay );
		modalOverlay.fade( this.options.overlayTransparency );

		window.addEvent('resize',function(){
			modalOverlay.setStyles({
				height	: window.getScrollSize().y,
				width	: window.getScrollSize().x
			});

		});

	},

	createWindow : function(){

		var modalWindowTop = ( ( this.options.container.getSize().y / 2 ) - ( this.options.height / 2 ) + window.pageYOffset );
		if( modalWindowTop &amp;amp;lt; 0 )
			var modalWindowTop = 0;

		var modalWindowLeft = ( ( this.options.container.getSize().x / 2 ) - ( this.options.width / 2 ) + window.pageXOffset );
		if( modalWindowLeft &amp;amp;lt; 0 )
			var modalWindowLeft = 0;

		modalWindow = new Element( 'div', { 'id':'modalWindow' } ).setStyles({
			position	: 'absolute',
			top		: modalWindowTop,
			left		: modalWindowLeft,
			height		: this.options.height,
			width		: this.options.width,
			zIndex		: 100
		});

		modalWindow.fade('hide');
		$(document.body).grab( modalWindow );
		modalWindow.fade( 'in' );

		if( !this.options.move )
		{
			var reposition = function(){

				var modalWindowTop = ( ( this.options.container.getSize().y / 2 ) - ( this.options.height / 2 ) + window.pageYOffset );
				if( modalWindowTop &amp;amp;lt; 0 )
					var modalWindowTop = 0;
				if( modalWindowTop &amp;amp;gt; this.options.container.getSize().y )
					var modalWindowTop = this.options.container.getSize().y;

				var modalWindowLeft = ( ( this.options.container.getSize().x / 2 ) - ( this.options.width / 2 ) + window.pageXOffset );
				if( modalWindowLeft &amp;amp;lt; 0 )
					var modalWindowLeft = 0;
				if( modalWindowLeft &amp;amp;gt; this.options.container.getSize().x )
					var modalWindowLeft = this.options.container.getSize().x;

				modalWindow.setStyles({
					top	: modalWindowTop
					//left	: modalWindowLeft
				});

			}

			window.addEvents({
				'resize' : reposition.bind(this),
				'scroll' : reposition.bind(this)
			});
		}

	},

	createTitle : function(){

		modalTitle = new Element( 'div', { 'id':'modalTitle' } ).setStyles({
			position	: 'absolute',
			top		: 0,
			left		: 0,
			width		: '100%'
		});
		modalTitle.set( 'text', this.options.title );
		modalWindow.grab( modalTitle );

		if( this.options.move )
		{
			modalWindow.makeDraggable({
				handle : modalTitle,
				limit: {
					x : [ 0, ( this.options.container.getScrollSize().x ) ],
					y : [ 0, ( this.options.container.getScrollSize().y ) ]
				}
			});
			modalTitle.setStyles({
				cursor	: 'move'
			});
		};

	},

	createContent : function(){

		modalContent = new Element( 'div', { 'id':'modalContent' } ).setStyles({
			position	: 'absolute',
			top		: ( this.options.title ? modalTitle.getStyle('height') : 0 ),
			overflow	: 'auto',
			left		: 0,
			height		: ( this.options.height - ( this.options.title ? modalTitle.getStyle('height').toInt() : 0 ) )+'px',
			width		: '100%'
		});
		modalContent.set( 'html', '&amp;amp;lt;br /&amp;amp;gt;&amp;amp;lt;br /&amp;amp;gt;&amp;amp;lt;center&amp;amp;gt;&amp;amp;lt;img alt=&amp;amp;quot;Loading..&amp;amp;quot; src=&amp;amp;quot;images/ajax-loader.gif&amp;amp;quot;/&amp;amp;gt;&amp;amp;lt;br /&amp;amp;gt;Loading Content...&amp;amp;lt;/center&amp;amp;gt;' );

		modalWindow.grab( modalContent );

		modalContent.load( this.options.url );

	},

	createCloser : function(){

		modalCloser = new Element( 'div', { 'id':'modalClose' } ).setStyles({
			cursor		: 'pointer',
			position	: 'absolute',
			top		: 0,
			right		: 0
		});
		modalTitle.grab( modalCloser );
		modalCloser.addEvent('click', this.closePopup.bind(this) );

	},

	createResizer : function(){

		modalResizer = new Element( 'div', { 'id':'modalResize' } ).setStyles({
			cursor		: 'pointer',
			position	: 'absolute',
			bottom		: 0,
			right		: 0
		});
		modalWindow.grab( modalResizer );

		modalWindow.makeResizable({
			handle : modalResizer,
			onDrag : function(){
				modalContent.setStyles({
					height : ( modalWindow.clientHeight - ( this.options.title ? modalTitle.getStyle('height').toInt() : 0 ) )+'px'
				});
			}.bind(this),
			limit: {
				x : [ 100, this.options.container.getSize().x ],
				y : [ 75, this.options.container.getSize().y ]
			}
		})
		modalResizer.setStyles({
			cursor	: 'se-resize'
		});

	},

	resizePopup : function( newHeight, shift ){

		modalContent.set('tween', {
			duration: 750
		}).tween('height', ( newHeight - ( this.options.title ? modalTitle.getStyle('height').toInt() : 0 ) ) );

		var moveHeight = function(){
			modalWindow.set('tween', {
				duration: 750
			}).tween('height', newHeight );
		}.delay(0);

		if( shift ) {
			var moveTop = function(){
				modalWindow.set('tween', {
					duration: 750
				}).tween('top', ( ( window.getSize().y / 2 ) - ( newHeight / 2 ) + window.pageYOffset ) );
			}.delay(750);
		}

		return false;
	},

	killStraglers : function(){

		if( $('modalOverlay') )
			$('modalOverlay').destroy();
		if( $('modalWindow') )
			$('modalWindow').destroy();

	},

	closePopup : function(){

		modalOverlay.fade('out');
		modalWindow.fade('out');
		var killEm = function(){
			if( $('modalOverlay') )
				$('modalOverlay').destroy();
			if( $('modalWindow') )
				$('modalWindow').destroy();
		}.delay(750);

		return false;

	}

});</pre>
<h3>Second, the CSS.</h3>
<p>I&#8217;m using the CSS3 rounded borders here, but it will roll back to normal borders if the viewer is using IE.</p>
<pre class='prettyprint lang-css'>
#modalWindow{
	background-color		: #FFFFFF;
	border				: 10px solid #222;
	border-radius			: 10px;
	-moz-border-radius		: 10px;
	-webkit-border-radius		: 10px;
}

#modalTitle{
	font-size			: 14px;
	font-weight			: bold;
	color				: #FFF;
	height				: 30px;
	background-color		: #222;
}

#modalContent{
	background-color		: #FFFFFF;
}

#modalClose{
	background-image		: url(images/close.png);
	height				: 16px;
	width				: 16px;
	margin				: 5px;
}

#modalResize{
	background-image		: url(images/resize.png);
	height				: 17px;
	width				: 17px;
}
</pre>
<h3>Lastly, the calling methods.</h3>
<p>I&#8217;ve added both methods here, first attaching to a single element.</p>
<pre class='prettyprint lang-js'>
Moodal = new MoodalWindow( $( 'moobox-link' ) );
</pre>
<p>Second, attaching to any link with a class of &#8220;moobox&#8221;.</p>
<pre class='prettyprint lang-js'>
$$('a.moobox').each(function(element){
	Moodal = new MoodalWindow( element );
});</pre>
<h3>Available options:</h3>
<ul>
<li><strong>height</strong> : Pixel height of the Modal Window. (EG: 250)</li>
<li><strong>width</strong> : Pixel width of the Modal Window. (EG: 350)</li>
<li><strong>overlayColor</strong> : Hex colour of the overlay. (EG: &#8216;#AAAAAA&#8217;/'#AAA&#8217;)</li>
<li><strong>overlayTransparency</strong> : Transparency level of the overlay, from 0 to 1. (EG: 0.4)</li>
<li><strong>overlayClose</strong> : Boolean value, if you want the modal window to close when you click the overlay background. (EG: true/false)</li>
<li><strong>move</strong> : Boolean value, if you want the user to be able to move the Modal window around, using the Title Bar as a handle. (EG: true/false)</li>
<li><strong>resize</strong> : Boolean value, if you want the user to be able to resize the Modal Window, from the bottom right corner.  If this is set to true, the window will not auto position itself when the window scrolls, or resizes. (EG: true/false)</li>
<li><strong>url</strong> : URL to be opened in the modal window.  If this is not set, the class will use the HREF from the link. (EG: &#8216;users/rob/index.php&#8217;)</li>
<li><strong>title</strong> : Title bar text, if this is set to false, the title bar will not appear, disabling the close button, and the move/drag feature.  If this is not set, the code will attempt to get a &#8220;TITLE&#8221; variable from the link, or failing that, the text from inside the link.</li>
</ul>
<h3>Options Example:</h3>
<pre class='prettyprint lang-js'>
Moodal = new MoodalWindow( $('link-id'), {
	height			: 700,
	width			: 600,
	overlayColor		: '#000000',
	overlayTransparency	: 0.7,
	overlayClose		: true,
	move			: true,
	resize			: true,
	url			: '/test/hello-world.html',
	title			: 'Hello World!'
});</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.blackfade.com/2009/09/24/moodal-window-for-mootools-1-2-3-1/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
	</channel>
</rss>

<!-- Dynamic Page Served (once) in 0.881 seconds -->

