<?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/"
	xmlns:series="http://unfoldingneurons.com/"
	>

<channel>
	<title>Ovalpixels Blog about Web-Building &#187; Development</title>
	<atom:link href="http://www.ovalpixels.com/blog/category/development/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.ovalpixels.com/blog</link>
	<description>Tips &#38; Tricks on Web Design and Development</description>
	<lastBuildDate>Fri, 28 Jan 2011 09:17:42 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Adding automatic CSS timestamp to a Thematic child theme</title>
		<link>http://www.ovalpixels.com/blog/2010/08/29/adding-automatic-css-timestamp-to-a-thematic-child-theme/</link>
		<comments>http://www.ovalpixels.com/blog/2010/08/29/adding-automatic-css-timestamp-to-a-thematic-child-theme/#comments</comments>
		<pubDate>Sat, 28 Aug 2010 23:33:55 +0000</pubDate>
		<dc:creator>vladislav</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[CSS]]></category>
		<category><![CDATA[Thematic]]></category>
		<category><![CDATA[Wordpress]]></category>

		<guid isPermaLink="false">http://www.ovalpixels.com/blog/?p=194</guid>
		<description><![CDATA[I recently had a small design job to do on a site based on the Thematic WordPress theme framework. It was all creating graphics and adding them to the CSS file of the blog. While completing this task I stumbled upon several issues, so I woud like to share the solutions I used for them. [...]]]></description>
			<content:encoded><![CDATA[<p><img class="alignright size-full wp-image-250" src="http://www.ovalpixels.com/blog/wp-content/uploads/2010/08/css-screenshot-timestamp1.png" alt="" width="213" height="139" />I recently had a small design job to do on a site based on the <a  href="http://themeshaper.com/thematic/" target="_blank"> Thematic </a> WordPress theme framework. It was all creating graphics and adding them to the CSS file of the blog. While completing this task I stumbled upon several issues, so I woud like to share the solutions I used for them.</p>
<h3><span id="more-194"></span>Issue 1: Browser cache</h3>
<p>As you know, visitors to a site would get served the latest version of a file only if it already doesn&#8217;t exist in the local browser cache (or the local copy is old enough to expire). So only a first-time visitor would surely get the latest CSS version, but what about returning visitors? I needed to make sure they get the new CSS file without having to manually hard-refresh their browser. This is where the CSS timestamp technique comes into place.</p>
<h3>Issue 2: Continuous updates</h3>
<p>In any future updates of the CSS file, I would need to change the timestamp each time, which brings in a bit of inconvenience. This is where generating an <strong><em>automatic timestamp on file change</em></strong> comes in quite handy, if not priceless.</p>
<h3>Issue 3: Updating the Thematic stylesheet call function</h3>
<p>The site used Thematic as a base parent theme, and the <a  href="http://codex.wordpress.org/Child_Themes">child theme</a> of the site contained just a few files &#8211; an index.php file, a css file, a functions.php file, and an /images folder. This is the beauty of child themes introduced recently in WordPress &#8211; you can base your theme on an existing one and add only the files you need to change in your child theme folder. As opposed to directly changing the main theme, this technique protects your changes from any future updates of the main theme, which would overwrite your changes. By using a child theme you effectively preserve your changes in a separate theme folder.</p>
<p>However this also prevents you from directly editing PHP code that includes the stylesheet without adding too much excess code. This is where we will use <a  href="http://themeshaper.com/filters-wordpress-child-themes/">WordPress filters</a> to do the task.</p>
<p>Now let&#8217;s see the solutions to these issues.</p>
<h3>Solution to issue 1 (Browser cache)</h3>
<p>Here is how a normal call to a CSS file looks like in HTML:</p>
<pre>&lt;link href="style.css" type="text/css" rel="stylesheet" /&gt;</pre>
<p>As mentioned before, an elegant solution to the browser cache issue is appending a unique string to the filename call as a parameter passed on to the CSS file:</p>
<pre>&lt;link href="style.css?some_unique_string" type="text/css" rel="stylesheet" /&gt;</pre>
<p>Usually a version number is used, e.g.:</p>
<pre>&lt;link href="style.css?ver=12" type="text/css" rel="stylesheet" /&gt;</pre>
<p>or a date:</p>
<pre>&lt;link href="style.css?20100829" type="text/css" rel="stylesheet" /&gt;</pre>
<p>The idea is generally the same. CSS does not make use of that parameter, but the browser gets tricked that you&#8217;re making a call to a different file (due to the different value of the href attribute), so it downloads it from the server. Voila!</p>
<h3>Solution to issue 2 (Continuous updates)</h3>
<p>Applying the CSS timestamp trick is great, but leaves room for error. Sometimes I might forget to change the version / timestamp, or I may just get tired of constantly changing it. This is why the solution I found <a  href="http://www.prelovac.com/vladimir/adding-version-to-theme-css-file">published here</a> really made my day. What it does is automatically append a unique number based on the actual date / time the CSS file was <em>changed on the server </em>by using a PHP function ( filemtime() ) to check for it<em>.</em></p>
<p>Here is how a line of HTML/PHP code using this method would look:</p>
<pre>&lt;link href="style.css?&lt;?php echo filemtime('/server/path/to/css/file/style.css'); ?&gt;"</pre>
<pre> rel="stylesheet" type="text/css" /&gt;</pre>
<p>This will result in a unique number appended to the CSS call <em>each time the file is changed</em>. No more need to worry you forgot anything.</p>
<h3>Solution to issue 3 (Tinkering with the CSS call function in Thematic)</h3>
<p>I opened the header.php file of the Thematic parent theme to see how the CSS file is being included. I only saw a bunch of PHP functions being called, going like this:</p>
<pre>    // Creating the doctype
    thematic_create_doctype();
    echo " ";
    language_attributes();
    echo "&gt;\n";

    // Creating the head profile
    thematic_head_profile();

    // Creating the doc title
    thematic_doctitle();

    // Creating the content type
    thematic_create_contenttype();
...</pre>
<p>Not a line of HTML. But I noticed one of the functions was this:</p>
<pre>    // Loading the stylesheet
    thematic_create_stylesheet();</pre>
<p>It would obviously take care of inserting the stylesheet. A short run through the Thematic file structure showed this function was defined in /wp_thematic_folder /library /extensions /header-extensions.php:</p>
<pre>// Located in header.php
// creates link to style.css
function thematic_create_stylesheet() {
    $content = "\t";
    $content .= "&lt;link rel=\"stylesheet\" type=\"text/css\" href=\"";
    $content .= get_bloginfo('stylesheet_url');
    $content .= "\" /&gt;";
    $content .= "\n\n";
    echo apply_filters('thematic_create_stylesheet', $content);
}</pre>
<p>It clearly shows how the HTML code for including the CSS file is built and assigned to a $content variable. What I needed is to change the output of this function. I accomplished that by adding a filter that would replace the output of the existing thematic_create_stylesheet() function with what I need. Adding a filter is easy &#8211; just edit the functions.php file of your theme (in this case &#8211; the child theme). This is how it looks:</p>
<pre>function timestampCSS($content) {
    $content = "\t";
    $content .= "&lt;link rel=\"stylesheet\" type=\"text/css\" href=\"";
    $content .= get_bloginfo('stylesheet_url');
    $content .= '?' . filemtime( get_stylesheet_directory() . '/style.css');
    $content .= "\" /&gt;";
    $content .= "\n\n";
    return $content;
}
add_filter ('thematic_create_stylesheet', 'timestampCSS');</pre>
<p>What I did was create a new function ( timestampCSS() ) which would return the output I need, and then hook it as a filter to the old function ( thematic_create_stylesheet() ), so that each time the old function is executed my new function will be, too.<span style="font-size: 13.2px;"> The last line ( add_filter() ) effectively tells WordPress to use the output of timestampCSS() instead of the one of thematic_create_stylesheet().</span></p>
<p>So this is how you can use a combination of handy techniques to make your work on styling Thematic a bit less tedious and make it work independently of the updates of the parent theme.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ovalpixels.com/blog/2010/08/29/adding-automatic-css-timestamp-to-a-thematic-child-theme/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Creating and visualizing customizable products</title>
		<link>http://www.ovalpixels.com/blog/2010/02/27/creating-and-visualizing-customizable-products/</link>
		<comments>http://www.ovalpixels.com/blog/2010/02/27/creating-and-visualizing-customizable-products/#comments</comments>
		<pubDate>Sat, 27 Feb 2010 10:13:07 +0000</pubDate>
		<dc:creator>georgi</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[alpha]]></category>
		<category><![CDATA[caching]]></category>
		<category><![CDATA[day e-commerce]]></category>
		<category><![CDATA[e-commerce]]></category>
		<category><![CDATA[e-shops]]></category>
		<category><![CDATA[online store app]]></category>
		<category><![CDATA[open-source solution]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[server processing part]]></category>
		<category><![CDATA[shirt builder]]></category>
		<category><![CDATA[store app Since]]></category>

		<guid isPermaLink="false">http://www.ovalpixels.com/blog/?p=142</guid>
		<description><![CDATA[Modern day e-commerce needs to be very hi-tech to get advantage over the competition. We have quite a lot of examples of e-shops implementing amazing technology to become more attractive to customers. One of these is the ability to customize a product and view a realistic visualization of how it would look like in real [...]]]></description>
			<content:encoded><![CDATA[<p>Modern day e-commerce needs to be very hi-tech to get advantage over the competition. We have quite a lot of examples of e-shops implementing amazing technology to become more attractive to customers. One of these is the ability to customize a product and view a realistic visualization of how it would look like in real life. We have already done something similar for <a  title="3D virtual configurator" href="http://stonecenter-bg.com/?lang=en#configurators.php" target="_blank">these guys</a> &#8211; it includes some 3D rendering, jQuery and CSS. But this time we have to use other tools and materials.<span id="more-142"></span></p>
<h3>The recipe</h3>
<p>Here are the ingredients we have:</p>
<ol>
<li>client: students startup</li>
<li>application: online store</li>
<li>product: customizable male and female business shirts</li>
<li>no flash</li>
<li>budget: limited</li>
<li>materials: none</li>
<li>deadline: tight</li>
<li>expectations: high</li>
</ol>
<p>So, we have to mix all these and get something delicious in the end.</p>
<h2>The online store app</h2>
<p>Since the whole site has to be clean and straightforward, we decided it would be best to design it from scratch using CakePHP instead of trying to bend any existing open-source solution. We don&#8217;t need all the stuff ZenCart provides but we need that shirt builder which we can hardly implement into any OSS shop.</p>
<h2>Raw materials</h2>
<p>None. The client didn&#8217;t have any materials to provide us with except for some low-resolution, all-messed-up pictures from their shirt-sewing factory. They didn&#8217;t have time or budget for 3D modeling (which could prove to be quite fancy and realistic) and we had to</p>
<h3>Photoshoot</h3>
<p>We hired <a  href="http://mborisov.com/" target="_blank">this fella</a> for the project and I think he did quite well.</p>
<p><a  href="http://www.ovalpixels.com/blog/wp-content/uploads/2010/02/shirt_front.jpeg" class="thickbox no_icon" rel="gallery-142" title=""><img class="alignnone size-medium wp-image-143" src="http://www.ovalpixels.com/blog/wp-content/uploads/2010/02/shirt_front-221x300.jpg" alt="" width="133" height="180" /></a><a  href="http://www.ovalpixels.com/blog/wp-content/uploads/2010/02/shirt_back.jpeg" class="thickbox no_icon" rel="gallery-142" title=""><img class="alignnone size-medium wp-image-144" src="http://www.ovalpixels.com/blog/wp-content/uploads/2010/02/shirt_back-202x300.jpg" alt="" width="121" height="180" /></a><a  href="http://www.ovalpixels.com/blog/wp-content/uploads/2010/02/shirt_side.jpeg" class="thickbox no_icon" rel="gallery-142" title=""><img class="alignnone size-medium wp-image-145" src="http://www.ovalpixels.com/blog/wp-content/uploads/2010/02/shirt_side-129x300.jpg" alt="" width="77" height="180" /></a><a  href="http://www.ovalpixels.com/blog/wp-content/uploads/2010/02/shirt_sleeve.jpeg" class="thickbox no_icon" rel="gallery-142" title=""><img class="alignnone size-medium wp-image-146" src="http://www.ovalpixels.com/blog/wp-content/uploads/2010/02/shirt_sleeve-169x300.jpg" alt="" width="101" height="180" /></a></p>
<p>The pictures don&#8217;t look fancy (to me) but I was amazed what good job they did for us.</p>
<h2>Customizable Product Visualization Technology</h2>
<p>For the shirt builder we needed a solution which would allow us to generate images on the server so that we don&#8217;t have to create all the gazillion possible visualizations. We had to be able to &#8220;apply&#8221; all fabrics to all shirt elements ( fit, sleeves, cuffs, etc ). And the client wanted a fast and smooth experience for the end-user with no Flash!</p>
<p>We came up with the idea to create a mask for all shirt elements like in photoshop, use it to &#8220;cut out&#8221; the fabric in the particular shape and then add another layer which would represent shades and folds.</p>
<p><a  href="http://wideimage.sourceforge.net/" target="_blank">WideImage</a> was chosen for the server processing part. However, it turned out we were jumping in the dark.</p>
<h3>Fabric material</h3>
<p>Well, ok, I lied &#8211; the client gave us some picture of the fabrics they wanted to use. They were good enough and after some processing we got this</p>
<p><a  href="http://www.ovalpixels.com/blog/wp-content/uploads/2010/02/fabric-tile.jpg" class="thickbox no_icon" rel="gallery-142" title=""><img class="alignnone size-medium wp-image-147" src="http://www.ovalpixels.com/blog/wp-content/uploads/2010/02/fabric-tile.jpg" alt="" width="94" height="104" /></a></p>
<p>We had to make a canvas and tile that image in there. That was an easy task for WideImage.</p>
<p>We first load the fabric image and resize it on the fly &#8211; otherwise it would look too big on the final image. We then create the canvas and fill it with repeating instances of the fabric image &#8211; finally, cut out a shirt shape.</p>
<p><a  href="http://www.ovalpixels.com/blog/wp-content/uploads/2010/02/index4php.png" class="thickbox no_icon" rel="gallery-142" title=""><img class="alignnone size-medium wp-image-148" src="http://www.ovalpixels.com/blog/wp-content/uploads/2010/02/index4php-210x300.png" alt="" width="126" height="180" /></a><a  href="http://www.ovalpixels.com/blog/wp-content/uploads/2010/02/male-mask-normal.png" class="thickbox no_icon" rel="gallery-142" title=""><img class="alignnone size-medium wp-image-150" src="http://www.ovalpixels.com/blog/wp-content/uploads/2010/02/male-mask-normal-210x300.png" alt="" width="126" height="180" /></a><a  href="http://www.ovalpixels.com/blog/wp-content/uploads/2010/02/index4php1.png" class="thickbox no_icon" rel="gallery-142" title=""><img class="alignnone size-medium wp-image-151" src="http://www.ovalpixels.com/blog/wp-content/uploads/2010/02/index4php1-210x300.png" alt="" width="126" height="180" /></a></p>
<p>But we have a small problem here &#8211; we need to add the layer for folds and shades now and with this approach it has to reside in a separate file. That&#8217;s not elegant enough&#8230;</p>
<p>We came up with the idea to</p>
<h4>combine the image mask and folds layer into one file</h4>
<p>How to do that? We use the RGB channels of the image to hold the mask and the alpha channel to hold the folds and shades layer. This way we can have just one file to hold all the information we need to generate our image.</p>
<h3>Performance</h3>
<p>Nothing is as easy as it sounds. WideImage has some wonderful methods like getChannels() to get the RGB and alpha channels into different image resources and applyMask() to cut out the shirt element shape from the fabric-tiled canvas but these come with enormous performance hits. Unfortunately, PHP and GD2 do not offer native functions for these tasks and WideImage uses &#8220;for&#8221; loops to go through all pixels of the image to do the necessary processing. So, the algorithm goes like that</p>
<ol>
<li>go through the image pixel by pixel go get its RGB channels and alpha channels and store them in different image resources (mask and folds layer)</li>
<li>once again go through the mask image (which has same size) pixel by pixel to cut out the fabric canvas</li>
<li>apply the folds layer on top of the cut out image</li>
</ol>
<p>This averaged at 8 seconds on our server for a 350&#215;500 image!</p>
<h4>Cache</h4>
<p>We decided we could use some caching which would save us troubles &#8211; we calculate we would need around 1GB of space for that cache which is not a big deal but 8 seconds is still a monster.</p>
<h4>Solution</h4>
<p>We came up with a solution which was similar to what WideImage does but we now do all the processing in a single for loop which saves quite a lot of time. We managed to keep the figure down to 2-3secs for an uncached image which is bearable. In he end the image looks like that</p>
<p><a  href="http://www.ovalpixels.com/blog/wp-content/uploads/2010/02/demo1.png" class="thickbox no_icon" rel="gallery-142" title=""><img class="alignnone size-medium wp-image-152" src="http://www.ovalpixels.com/blog/wp-content/uploads/2010/02/demo1-210x300.png" alt="" width="168" height="240" /></a><a  href="http://www.ovalpixels.com/blog/wp-content/uploads/2010/02/demo3.png" class="thickbox no_icon" rel="gallery-142" title=""><img class="alignnone size-medium wp-image-154" src="http://www.ovalpixels.com/blog/wp-content/uploads/2010/02/demo3-210x300.png" alt="" width="168" height="240" /></a><a  href="http://www.ovalpixels.com/blog/wp-content/uploads/2010/02/demo2.png" class="thickbox no_icon" rel="gallery-142" title=""><img class="alignnone size-medium wp-image-153" src="http://www.ovalpixels.com/blog/wp-content/uploads/2010/02/demo2-210x300.png" alt="" width="168" height="240" /></a></p>
<p>This is still a work in progress and we need a few more things to enhance, so if you have any suggestions, go ahead and shoot!</p>
<p><em><strong>Update:</strong></em> We launched the website some time ago. Here are some final images:</p>
<p><a  href="http://www.ovalpixels.com/blog/wp-content/uploads/2010/02/male-front.jpeg" class="thickbox no_icon" rel="gallery-142" title=""><img class="alignleft size-full wp-image-191" src="http://www.ovalpixels.com/blog/wp-content/uploads/2010/02/male-front.jpeg" alt="" width="170" height="243" /></a><a  href="http://www.ovalpixels.com/blog/wp-content/uploads/2010/02/male-side.jpeg" class="thickbox no_icon" rel="gallery-142" title=""><img class="alignleft size-full wp-image-189" src="http://www.ovalpixels.com/blog/wp-content/uploads/2010/02/male-side.jpeg" alt="" width="170" height="243" /></a><a  href="http://www.ovalpixels.com/blog/wp-content/uploads/2010/02/male-back.jpeg" class="thickbox no_icon" rel="gallery-142" title=""><img class="alignleft size-full wp-image-192" src="http://www.ovalpixels.com/blog/wp-content/uploads/2010/02/male-back.jpeg" alt="" width="170" height="243" /></a></p>
<p><a  href="http://www.ovalpixels.com/blog/wp-content/uploads/2010/02/female-front.jpeg" class="thickbox no_icon" rel="gallery-142" title=""><img class="alignleft size-full wp-image-188" src="http://www.ovalpixels.com/blog/wp-content/uploads/2010/02/female-front.jpeg" alt="" width="170" height="243" /></a><a  href="http://www.ovalpixels.com/blog/wp-content/uploads/2010/02/female-side.jpeg" class="thickbox no_icon" rel="gallery-142" title=""><img class="alignleft size-full wp-image-187" src="http://www.ovalpixels.com/blog/wp-content/uploads/2010/02/female-side.jpeg" alt="" width="170" height="243" /></a><a  href="http://www.ovalpixels.com/blog/wp-content/uploads/2010/02/female-back.jpeg" class="thickbox no_icon" rel="gallery-142" title=""><img class="alignleft size-full wp-image-190" src="http://www.ovalpixels.com/blog/wp-content/uploads/2010/02/female-back.jpeg" alt="" width="170" height="243" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.ovalpixels.com/blog/2010/02/27/creating-and-visualizing-customizable-products/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Making fancy websites without Flash 2: Animating background image</title>
		<link>http://www.ovalpixels.com/blog/2009/02/21/making-fancy-websites-without-flash-animating-background-image/</link>
		<comments>http://www.ovalpixels.com/blog/2009/02/21/making-fancy-websites-without-flash-animating-background-image/#comments</comments>
		<pubDate>Sat, 21 Feb 2009 18:48:43 +0000</pubDate>
		<dc:creator>georgi</dc:creator>
				<category><![CDATA[Design]]></category>
		<category><![CDATA[Development]]></category>
		<category><![CDATA[animation]]></category>
		<category><![CDATA[html]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[jQuery]]></category>

		<guid isPermaLink="false">http://www.ovalpixels.com/blog/?p=87</guid>
		<description><![CDATA[This is a continuation of the Making fancy website without Flash entry from a few days ago. To make the story short &#8211; I will try and show you some jQuery alernatives for popular Flash animation. We will start with a Smooth background image swap &#8211; jQuery Background-Image Transition Plugin I will show you an [...]]]></description>
			<content:encoded><![CDATA[<p>This is a continuation of the <a  href="http://www.ovalpixels.com/blog/2009/02/20/making-fancy-websites-without-flash-introduction/" target="_blank">Making fancy website without Flash</a> entry from a few days ago. To make the story short &#8211; I will try and show you some jQuery alernatives for popular Flash animation. <span id="more-87"></span>We will start with a</p>
<h3>Smooth background image swap &#8211; jQuery Background-Image Transition Plugin</h3>
<p>I will show you an example right now, so you know what I am talking about.</p>
<p><a  title="background-image-transition-example" href="http://www.ovalpixels.com/bgImageTransition/">Here is a working example</a></p>
<p>What we basically do is:</p>
<ol>
<li>Create an additional hidden &lt;div&gt; element on top ( using z-index ) of the element we want to animate</li>
<li>Load the new image in the in the cache in the background, so that the effect is smooth</li>
<li>Set the new src to the new &lt;div&gt; element</li>
<li>fadeIn() the new &lt;div&gt; element so that it creates the illusion that the background image of our initial div is smoothly changing</li>
<li>Optional step &#8211; if we need to change the image once again, go from 2 to 5 but setting the new src to our <em>initial </em>&lt;div&gt; and then using <em>fadeOut()</em> on the new element, so that it disappears and the new image is set as background to the old &lt;div&gt;. This way we won&#8217;t have an infinitive increase of the z-index and won&#8217;t actually change the z-index of the initial &lt;div&gt;</li>
</ol>
<p>OK, let&#8217;s get to work, we will start with the HTML markup:</p>
<p>&lt;div id=&#8221;backImage&#8221;&gt;&lt;/div&gt;</p>
<p>Well, that was pretty easy: we have a simple &lt;div&gt; element with some demo text and just next to it we add that additional &lt;div&gt; which we will need for the animation.</p>
<p>So, here is the CSS:</p>

<div class="wp_syntax"><div class="code"><pre class="css" style="font-family:monospace;"><span style="color: #cc00cc;">#backImage</span> <span style="color: #00AA00;">&#123;</span>
    <span style="color: #000000; font-weight: bold;">z-index</span><span style="color: #00AA00;">:</span> -<span style="color: #cc66cc;">2</span><span style="color: #00AA00;">;</span>
    <span style="color: #000000; font-weight: bold;">height</span><span style="color: #00AA00;">:</span><span style="color: #933;">600px</span><span style="color: #00AA00;">;</span>
    <span style="color: #000000; font-weight: bold;">width</span><span style="color: #00AA00;">:</span><span style="color: #933;">800px</span><span style="color: #00AA00;">;</span>
    <span style="color: #000000; font-weight: bold;">background-image</span><span style="color: #00AA00;">:</span> <span style="color: #993333;">url</span><span style="color: #00AA00;">&#40;</span><span style="color: #ff0000;">'path/to/initial/img'</span><span style="color: #00AA00;">&#41;</span><span style="color: #00AA00;">;</span>
<span style="color: #00AA00;">&#125;</span></pre></div></div>

<p>We just set a height and width of the element so that we are sure the image will actually be shown. It is generally a good idea to have the z-index set to a negative number while other elements have a greater z-index value.</p>
<p>We will use <a  href="http://plugins.jquery.com/project/bgImageTransition/" target="_blank">jQuery&#8217;s Background-Image Transition Plugin</a> for our example.</p>
<p>First, add jQuery and the plugin</p>
<p>&lt;script lang=&#8221;Javascript&#8221; src=&#8221;path/to/jQuery.js&#8221; type=&#8221;text/javascript&#8221;&gt; &lt;/script&gt;<br />
&lt;script lang=&#8221;Javascript&#8221; src=&#8221;path/to/jQuery.bgImageTransition.js&#8221; type=&#8221;text/javascript&#8221;&gt; &lt;/script&gt;</p>
<p>Then, at the end of the document, add the following lines:</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;">jQuery<span style="color: #009900;">&#40;</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
    jQuery<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'#backImage'</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">bgImageTransition</span><span style="color: #009900;">&#40;</span> <span style="color: #3366CC;">'path/to/new/image'</span><span style="color: #339933;">,</span> <span style="color: #009900;">&#123;</span>
        duration<span style="color: #339933;">:</span> <span style="color: #3366CC;">'slow'</span><span style="color: #339933;">,</span>
        easing<span style="color: #339933;">:</span> <span style="color: #3366CC;">'linear'</span><span style="color: #339933;">,</span>
        helperElementId<span style="color: #339933;">:</span> <span style="color: #3366CC;">'backImage2'</span><span style="color: #339933;">,</span>
        zindex<span style="color: #339933;">:</span> <span style="color: #339933;">-</span><span style="color: #CC0000;">1</span>
        callback<span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
           <span style="color: #006600; font-style: italic;">//do sth</span>
        <span style="color: #009900;">&#125;</span>
    <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>The only mandatory argument is the path to the new image. The optional second argument is an object holding some tweaks. You can set the desired duration, easing, helperElementId ( which is generated by the plugin ), z-index of the helperElement ( by default it will take the selected element&#8217;s zindex and increment by 1 ) and a callback function in case you want to execute some functionality when the transition is over.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ovalpixels.com/blog/2009/02/21/making-fancy-websites-without-flash-animating-background-image/feed/</wfw:commentRss>
		<slash:comments>33</slash:comments>
		</item>
		<item>
		<title>Making fancy websites without Flash: Introduction</title>
		<link>http://www.ovalpixels.com/blog/2009/02/20/making-fancy-websites-without-flash-introduction/</link>
		<comments>http://www.ovalpixels.com/blog/2009/02/20/making-fancy-websites-without-flash-introduction/#comments</comments>
		<pubDate>Fri, 20 Feb 2009 11:56:11 +0000</pubDate>
		<dc:creator>georgi</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Adobe]]></category>
		<category><![CDATA[Ajax]]></category>
		<category><![CDATA[favorite tool]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[javascript technology]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[web front-end developers]]></category>

		<guid isPermaLink="false">http://www.ovalpixels.com/blog/?p=88</guid>
		<description><![CDATA[Flash Adobe Flash is no doubt a favorite tool for a lot of web front-end developers and designers. It is widely supported on a variety of platforms and browsers and features a rich and cohesive set of tools and instruments. Some people even say it is the next evolutionary step of the Web. Why not [...]]]></description>
			<content:encoded><![CDATA[<h3>Flash</h3>
<p style="64.125px;">Adobe Flash is no doubt a favorite tool for a lot of web front-end developers and designers. It is widely supported on a variety of platforms and browsers and features a rich and cohesive set of tools and instruments. Some people even say it is the next evolutionary step of the Web.</p>
<h3>Why not then?</h3>
<p style="64.125px;">Even though Flash is great, it has its drawbacks ( of course, I wouldn&#8217;t be writing this blog post otherwise ). <span id="more-88"></span>Here I am talking about a completely Flash made website, not just small fragments of it.</p>
<ul style="64.125px;">
<li>It is extremely <strong>SEO unfriendly</strong>. Although Google <a  href="http://googleblog.blogspot.com/2008/06/google-learns-to-crawl-flash.html" target="_blank">stated</a> back in the middle of 2008 that they have <em>improved</em> readability of Flash sites, this still isn&#8217;t enough compared to a well-made HTML website.</li>
<li><strong>There are no links</strong>. If you want to send a link to a friend &#8211; no dice. If Google actually learns how to crawl such websites, what links is the crawler going to give? There is only one URL in such a site &#8211; the domain name. Best case scenario in Google listings would be a single-page website with a lot of heterogeneous information</li>
<li>The web is all about <strong>content over design</strong> not vice versa. Traditional technologies today are so good that what people usually do with Flash ( and can&#8217;t with other stuff ) is make something which looks more like an art gallery than a website. This is extremely counter-productive for any business &#8211; end-users visit a site not to experience eye-candies but to get some content. Just like a fashion review &#8211; you need to pay attention to the clothes, not to the models. The focus should stay on the content and not on the decoration. Period.</li>
<li><strong>Browsers are not really made for that</strong>. Yes, you know what I am talking about &#8211; when I go to a site and have to wait 7-10 secs just for the Flash to load and then start-up, this makes me a bit nervous. And as I have previously <a  href="http://www.ovalpixels.com/blog/2008/11/15/building-fast-web-sites-with-yahoos-exceptional-performance-team/" target="_blank">stated</a> on this blog, loading time is crucial for web visitors. Each second can be costly.</li>
<li><strong>Background music. </strong>Well, OK, it may be just me but I <em>hate</em> background music. Yes, I can stop it but I didn&#8217;t want it in the first place! I have 10 tabs running right now and I really don&#8217;t want some strange music streaming from somewhere without even notifying me. Yes, this is not just a Flash flaw but it looks like it is easy enough for Flash designers to get tempted by this option.</li>
<li><strong>&#8220;Let&#8217;s reinvent the web!</strong>&#8221; Hmmm&#8230; this sounds a bit like Microsoft but it is actually Adobe trying to do it. Correct me, if I am wrong, but isn&#8217;t &#8220;flashy&#8221; a bad term for a website? You get crazy, incoherent navigation, strange things popping out of nowhere, all kinds of elements moving, resizing and changing shapes all over the place. Long live vector animation! But wait, where did the visitor go&#8230; ?</li>
</ul>
<p style="64.125px;">I am sure you can think of many more reasons not to prefer Flash but these were my top list. These are also not too technical &#8211; we could talk about inter-compatibility with other technologies for too long.</p>
<p style="64.125px;">Enough ranting already &#8211; I will show you some tricks which can make Flash history. Our goal is to create a website which is <strong>both visually compelling and SEO-friendly</strong> &#8211; a simple 5-pager with some help from PHP.</p>
<h3>Back to basics</h3>
<p style="64.125px;">Good &#8216;ol Javascript. It needs some polishing from a well-known library, of course &#8211; otherwise you risk banging your head against the wall for some time. In short, we will use traditional html + css + javascript technology which will help us get some really nice effects. We will then add some nifty AJAX to maintain a good and flowing experience for the user but still making a SEO-friendly site with active links and most importantly &#8211; a graceful degradation. If the visitor is using a stone age computer without JS support ( or is simply using some JS blocking browser extension ), they will <em>still</em> be able to get to the content. They won&#8217;t experience all the sweetness but they will get what they wanted after all &#8211; the content.</p>
<h3>Javascript Libraries</h3>
<p>You can find <a  href="http://edevil.wordpress.com/2005/11/14/javascript-libraries-roundup/" target="_blank">tons</a> of them out there. I have personally used PrototypeJS and jQuery but have had a good look at YUI, MooTools and Rico, too. Good things are told about Dojo, but I haven&#8217;t really looked into it. Some time ago jQuery was much lighter than PrototypeJS and that made many people switch. Today the difference is not so great as jQuery can get down to ~18k and PrototypeJS to ~20k ( gzipped and minified ) but let&#8217;s not forget that PrototypeJS&#8217; effects&#8217; library Scriptaculous ( scriptaculous and effects only &#8211; no builder, slider, sound, controls and drag&amp;drop ) add another 15k. So, jQuery turns out to be twice lighter.</p>
<p>So, I chose</p>
<h4>jQuery</h4>
<p>Go get the most recent version from <a  href="http://code.google.com/p/jqueryjs/" target="_blank">here</a>. The version I am going t use is 1.3.2  as it is the most recent right now. And some additional plugins &#8211; we will talk more about them later but I can recommend <a  href="http://plugins.jquery.com/project/color" target="_blank">Color</a>, <a  href="http://plugins.jquery.com/project/timers" target="_blank">Timers</a> and <a  href="http://plugins.jquery.com/project/fxqueues" target="_blank">fxQueue</a>. The first one gives you the ability to smoothly change colors ( including background and border ) of elements via animate(). I am taking a minimalistic approach and some may argue that the Color plugin is not that much needed, but if we want some candies, we&#8217;ll have to use it. The Timers plugin is not an overkill either &#8211; it is a nice wrapper for setTimeout() and setInterval() and does some good garbage collection so that no memory leaks from the browser. You can, of course, use a variety of great plugins from <a  href="http://plugins.jquery.com/" target="_blank">jQuery&#8217;s plugins&#8217; repository</a>.</p>
<p>And because this post is getting too long, I will begin with the actual stuff in my next blog entry &#8211; stay tuned!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ovalpixels.com/blog/2009/02/20/making-fancy-websites-without-flash-introduction/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>CakePHP Migrations without PEAR</title>
		<link>http://www.ovalpixels.com/blog/2008/11/17/cakephp-migrations-without-pear/</link>
		<comments>http://www.ovalpixels.com/blog/2008/11/17/cakephp-migrations-without-pear/#comments</comments>
		<pubDate>Mon, 17 Nov 2008 21:19:31 +0000</pubDate>
		<dc:creator>georgi</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[API]]></category>
		<category><![CDATA[Bakery Joel Moss]]></category>
		<category><![CDATA[CakePHP]]></category>
		<category><![CDATA[Chris Wanstrath]]></category>
		<category><![CDATA[installed applications]]></category>
		<category><![CDATA[Joel Moss]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Oracle]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.ovalpixels.com/blog/?p=67</guid>
		<description><![CDATA[Rails fans out there? It is no secret that CakePHP was born to implement the ideas of Ruby on Rails to the world of PHP &#8211; wonderful ideas, indeed, and I think we should pay tribute to the guys at 37signals. But what CakePHP still lacks, in my opinion, is pure and complete DB abstraction. [...]]]></description>
			<content:encoded><![CDATA[<h3>Rails fans out there?</h3>
<p>It is no secret that CakePHP was born to implement the ideas of Ruby on Rails to the world of PHP &#8211; wonderful ideas, indeed, and I think we should pay tribute to the guys at 37signals.</p>
<p>But what CakePHP still lacks, in my opinion, is pure and complete DB abstraction. It is true that most recent versions of Cake ( v.2 RC3 as of now ) have done a lot in that area &#8211; the framework is now strongly decoupled from MySQL, although I personally have never heard of study cases that use Oracle, for example.</p>
<p>To the point &#8211; in a multi-developer environment it is critical to have a versioning control system ( you know you should be using <a  href="http://git.or.cz" target="_blank">git</a>, right? ) and a database &#8216;versioning&#8217; system &#8211; that is where Rails is much more powerful than CakePHP &#8211; it has <strong>database migrations</strong>.<span id="more-67"></span></p>
<h3>Some migrations&#8217; background</h3>
<p>If you know what migrations are &#8211; skip that part and go directly to the next one. Otherwise &#8211; here is a simple explanation: they are related to the database like git ( or svn or cvs ) is related to the source. They simple provide a way to go back or forth to a previous or succeeding state ( or version ) of the database schema. The features of migrations are:</p>
<ul>
<li>They are DB agnostic &#8211; this means that they are not affected by the type of the DB server you&#8217;re using and help you in deploying your apps on different environments</li>
<li>They help you with your agile development &#8211; you can put info in and out without affecting the rest of the project</li>
<li>They provide you with a quick way to revert back to a previous state of the DB in case something went wrong</li>
<li>DB migrations can save your life if you work in a team</li>
</ul>
<p>To illustrate the all said, I have a simple example: You create a blog ( of course a blog &#8211; that&#8217;s probably the most often used example in the world ). Let&#8217;s split the development into three simple parts &#8211; development of blog posts CRUD; adding ACL; adding Comments to posts and.. that&#8217;s it &#8211; we want a simple example, after all.</p>
<p>So, first &#8211; blog posts Create, Read, Update, Delete. You begin by creating your DB schema. You need a simple posts&#8217; table with a few fields &#8211; id, title, body, created. Then you write your PHP code, of course ( out of scope here ).</p>
<p>But one beautiful day you decide more than one person should be able to add posts and modify their own posts only &#8211; that&#8217;s when you read about Access Control Lists. Now you need a few more tables &#8211; users, aros, acos, acl and you need to add a field to the posts&#8217; table ( user_id, for example ). Our small blog is getting just a bit more complex.</p>
<p>Finally, you want comments! But you have no time and ask your cousin for a favor ( he is a good dev, after all ). He adds another table for that. And then decides only registered users ( who cannot write new posts ) can add comments. And, of course, writes some more code. And inserts some more data in the db.</p>
<p>You ( and your cousin ) have went through 3 distinctive phases of agile development. You have, of course, used git ( oh, well, maybe svn or cvs ) to keep track of your code and make sure everything is ok and that you can revert back to a previous, stable version, if anything goes wrong. But then, one day &#8211; something really goes wrong. And you need to revert from state 3 to state 2 &#8211; i.e. remove the comments. But &#8230; your cousin is</p>
<ul>
<li> out of town</li>
<li>mad at you because you behaved badly on his last birthday party</li>
<li>has no idea what he did for you so many months ago</li>
</ul>
<p>No problem &#8211; you use your source versioning system and do the reversal. But.. something is still wrong &#8211; your database stays unchanged. What did you add from v2 to v3? Did you remove something? And you know nothing about Database Server X &#8211; can you write the SQLs to revert the schema?</p>
<p>That is where DB migrations come in and save your life. Well, maybe not that important with your blog but imagine 100+ development iterations and 10+ developers working simultaneously on your project and maintaining it on many different platforms &#8211; this can turn into a <em>small</em> nightmare.</p>
<h3>Joel Moss and his migrations</h3>
<p>In his <a  href="http://bakery.cakephp.org/articles/view/cake-db-migrations-v2-1">article</a> at the Bakery Joel Moss describes how to use his CakePHP migrations shell. Although that project was my inspiration and I highly respect his work, his approach has several drawbacks:</p>
<ul>
<li>it uses PEAR &#8211; I don&#8217;t like it &#8211; that&#8217;s why I use CakePHP. I do not find necessary to explain this &#8211; I guess it is highly subjective.</li>
<li>it is non-modular &#8211; you cannot use it to deploy applications &#8211; it is just a shell with no &#8216;core&#8217;</li>
<li>it cannot make a snapshot of your already existing schema &#8211; you haven&#8217;t used migrations yet? That&#8217;s something you will need.</li>
<li>it cannot merge your tables &#8211; that can be crucial when you already have different versions of the schema on different platforms and you just want them all to be standardized</li>
</ul>
<p>So, I proudly present you with</p>
<h3>My CakePHP Yaml Migrations and Fixtures</h3>
<p>The idea was born when <a  href="http://pagebakers.nl" target="_blank">Eelco</a> and I started working on PagebakeryCMS some time ago and was later further developed when we decided we needed a standardized CakePHP App Installer. You can get a <a  href="http://github.com/georgious/cakephp-yaml-migrations-and-fixtures" target="_blank">copy</a> of the project and follow it, too. What I personally find useful in it:</p>
<ul>
<li>no external libraries &#8211; only the SPYC class used to parse YAML files ( that is authored by Chris Wanstrath )</li>
<li>can easily complement your source versioning system &#8211; use it for team collaboration</li>
<li>can be used for DB abstraction installers &#8211; when deploying your applications on different platforms you don&#8217;t want to modify your SQLs &#8211; and the project is DB agnostic. The package also has fixtures ( well, the terms is not used correctly &#8211; this is for adding initial data to your database )</li>
<li>can be used to standardize already installed applications on different platforms</li>
<li>can help you make your apps DB agnostic by generating a YAML structure of your schema from where you can go on with the agnostic aproach</li>
</ul>
<h4>How it works</h4>
<p>Just put all files in your CakePHP vendors folder.</p>
<p>If you want to use the API only, simply include the classes in your code</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">App<span style="color: #339933;">::</span><span style="color: #004000;">Import</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'vendor'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'migrations'</span> <span style="color: #009900;">&#41;</span></pre></div></div>

<p>and/or</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">App<span style="color: #339933;">::</span><span style="color: #004000;">Import</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'vendor'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'fixtures'</span> <span style="color: #009900;">&#41;</span></pre></div></div>

<p>And then, for example</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000088;">$migrations</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> Migrations<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$migrations</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>load<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'comments.yml'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$migrations</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>up<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>For more usages &#8211; dig into the code a bit <img src='http://www.ovalpixels.com/blog/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://www.ovalpixels.com/blog/2008/11/17/cakephp-migrations-without-pear/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Building fast web sites with Yahoo!&#8217;s Exceptional Performance Team</title>
		<link>http://www.ovalpixels.com/blog/2008/11/15/building-fast-web-sites-with-yahoos-exceptional-performance-team/</link>
		<comments>http://www.ovalpixels.com/blog/2008/11/15/building-fast-web-sites-with-yahoos-exceptional-performance-team/#comments</comments>
		<pubDate>Sat, 15 Nov 2008 01:50:59 +0000</pubDate>
		<dc:creator>georgi</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[faulty software]]></category>
		<category><![CDATA[html]]></category>
		<category><![CDATA[http]]></category>
		<category><![CDATA[Performance]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[PHP algorithms]]></category>
		<category><![CDATA[software]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[Steve Souders]]></category>
		<category><![CDATA[web designers]]></category>
		<category><![CDATA[web performance]]></category>
		<category><![CDATA[Yahoo!]]></category>

		<guid isPermaLink="false">http://www.ovalpixels.com/blog/?p=19</guid>
		<description><![CDATA[Yahoo!&#8217;s Developer Theater has always been a priceless resource for web designers and developers. But what I have found the most useful video for me was Steve Souders&#8217; High performance websites presentation. For those of you who don&#8217;t have the time to watch the whole video &#8211; here is a short summary. Like many things [...]]]></description>
			<content:encoded><![CDATA[<p>Yahoo!&#8217;s Developer Theater has always been a priceless resource for web designers and developers. But what I have found the most useful video for me was Steve Souders&#8217; <a  href="http://video.yahoo.com/watch/1040890/3880720" target="_blank">High performance websites</a> presentation. For those of you who don&#8217;t have the time to watch the whole video &#8211; here is a short summary.</p>
<p>Like many things in our Universe, web performance obeys Pareto&#8217;s 80-20 principle &#8211; 20% of the elements of a website cause 80% of the effects on the performance. And if we try to slightly reduce the time spent on loading those 20% of the elements, we can get much more than 20% increase in speed.<span id="more-19"></span></p>
<h3>Are servers the root of all evil?</h3>
<p>And as most of you probably already guessed &#8211; most of the server-side elements are not within those 20%. If you slightly improve ( or think you have ) your PHP algorithms or your SQL queries, you will probably gain benefits which are close to the statistical error. ( Here we are not talking about drastic changes or bug fixes in faulty software which shouldn&#8217;t have been there in the first place ).</p>
<h3>Speed up the browser</h3>
<p>What turns out to have the greatest impact on loading times and user experiences are the elements which load into the browser. And writing speed enhancements for the browser is out of our scope right now &#8211; we can just try to adapt our web pages, so that it is easier for it to parse and display. Here are my top 5 rules which have given me fantastic results.</p>
<h4>Number of HTTP requests</h4>
<p>If we are to believe Yahoo!, 80% of the time spent loading a web page is taken by downloading the entities of that page &#8211; mainly css, javascripts and images. The problem here is that we have too much unimportant (for the users) data sent back and forth, also known as <em>headers</em>. Even the smallest image has its request and response headers traveling with it across the Net. So, my advice is &#8211; combine your javascript and css files and use css sprites&#8217; images. These are image maps which hold all of your images in one file and thus only this single file is sent over with its headers. Read more on css sprites <a  href="http://alistapart.com/articles/sprites" target="_blank">here</a>.</p>
<h4>Expires header</h4>
<p>This technique is very simple, yet very powerful and rarely used. Expires headers tell the browser that the entity it has requested *will not be changed* until some date. In practice, this means that the browser will not download that entity, if it already has it in its cache &#8211; 0 bytes transfered. Be careful, though, if you need to change something on the fly ( especially when still developing a site ), you will have to change the name of that file, so that the browser doesn&#8217;t think it already has it in the cache. This can easily be avoided using a simple versioning technique ( a link to some-file.js can look like some-file.js?version=1.0 and can later be changed to some-file.js?version=1.1 which will instantly make the browser fetch the file again as the url has changed ).</p>
<p>So, here &#8211; simply set a far-future Expires header on static content.</p>
<h4>GZip</h4>
<p>Also very useful, especially on large text files (like css and javascript files). This will effectively compress your content on the server, then send it to the browser which will uncompress it and use it. But be careful &#8211; don&#8217;t use this on images as it can be counter-productive. All A grade browsers support gzipped responses, so no worries about compatibility here.</p>
<h4>Javascript and CSS</h4>
<p>You should already know this but just in case &#8211; compress and minify your javascript and css files; put css at the top and javascript at the bottom. Simple, heh?</p>
<h4>Flush it!</h4>
<p>Well, the only server-side technique in my top 5 &#8211; flush your output buffer early ( just after the &lt;head&gt; tag ). This is very helpful on sites rich in html and text content because it will send the &lt;head&gt; of the html document fast enough so that the browser may start downloading the respective css files ( which you have put in the head, as described in the previous rule ) and underlying css images before the rest of the document has been transfered. Otherwise, you may end up in a situation where the whole HTML document needs to be received before css and the images can start being fetched.</p>
<p>This is just a sneak overview of the techniques &#8211; for a thorough list and technical help, please visit <a  href="http://developer.yahoo.com/performance/rules.html" target="_blank">yahoo&#8217;s site</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.ovalpixels.com/blog/2008/11/15/building-fast-web-sites-with-yahoos-exceptional-performance-team/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Highly responsive ajax applications without excess requests and bandwidth waste?</title>
		<link>http://www.ovalpixels.com/blog/2008/11/15/highly-responsive-ajax-applications-without-excess-bandwidth-waste/</link>
		<comments>http://www.ovalpixels.com/blog/2008/11/15/highly-responsive-ajax-applications-without-excess-bandwidth-waste/#comments</comments>
		<pubDate>Sat, 15 Nov 2008 00:42:17 +0000</pubDate>
		<dc:creator>georgi</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Ajax]]></category>
		<category><![CDATA[CakePHP]]></category>
		<category><![CDATA[controller]]></category>
		<category><![CDATA[http]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[JSON]]></category>
		<category><![CDATA[Pagebaker]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[real time]]></category>
		<category><![CDATA[responsive ajax applications]]></category>

		<guid isPermaLink="false">http://www.ovalpixels.com/blog/?p=3</guid>
		<description><![CDATA[Ajax is not as powerful as one would imagine If you have ever tried to develop a robust ajax application, you have probably reached a point where you want the client to be notified about a change on the server in &#8220;real time&#8221;. The most simple example &#8211; you need to create a chat application [...]]]></description>
			<content:encoded><![CDATA[<h3>Ajax is not as powerful as one would imagine</h3>
<p>If you have ever tried to develop a robust ajax application, you have probably reached a point where you want the client to be notified about a change on the server in &#8220;real time&#8221;. The most simple example &#8211; you need to create a chat application and want the client to instantly receive new messages upon their arrival on the server. And, if you like me, are not a fan of Flash ( which may be one of your major flaws ) and want to achieve this using only ajax techniques, you have found out that is not that simple. <span id="more-3"></span></p>
<h3>There is no real channel between the server and the client</h3>
<p>In that case you have no real permament connection between the server and the client and there is no real way of &#8220;triggering&#8221; events or sending data from the server to the client in any traditional way. Moreover, ajax does not support the client &#8220;listening&#8221; and waiting for a server&#8217;s call ( well, that&#8217;s a client after all ). You googled for some time, asked some fellow developers and almost all you could find was &#8211; &#8220;Just use javascript&#8217;s (notorious) setTimeout() or setInterval() function to repeatedly poll the server and check whether there is new data for the client&#8221;.</p>
<p>Like, for example ( using jQuery ) :</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #003366; font-weight: bold;">function</span> read<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
  jQuery.<span style="color: #660066;">ajax</span><span style="color: #009900;">&#40;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #3366CC;">'url'</span>     <span style="color: #339933;">:</span> <span style="color: #3366CC;">'chat/read/'</span><span style="color: #339933;">,</span>
    <span style="color: #3366CC;">'cache'</span>   <span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">false</span><span style="color: #339933;">,</span>
    <span style="color: #3366CC;">'dataType'</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">'json'</span><span style="color: #339933;">,</span>
    <span style="color: #3366CC;">'success'</span> <span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>messages<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
      <span style="color: #006600; font-style: italic;">//if there are new messages - write them on the wall</span>
      <span style="color: #000066; font-weight: bold;">if</span><span style="color: #009900;">&#40;</span> messages <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
	<span style="color: #006600; font-style: italic;">//write messages to the chat wall</span>
      <span style="color: #009900;">&#125;</span>
    <span style="color: #009900;">&#125;</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
setTimeout<span style="color: #009900;">&#40;</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span> read<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">2000</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>( I will not show any server-side code examples as they are simple enough &#8211; the method being /chat/read/ would just read from the database and return new records. Moreover, what we have here <strong>is not</strong> what we&#8217;re trying to achieve &#8211; the example here is for descriptive purposes only. )</p>
<p>Is that what we call highly-responsive, flexible applications, you&#8217;d ask? No. This technique has several drawbacks:</p>
<ul>
<li>it sends http requests from the client to the server and gets response ( most of the time empty ones ) on every X number of seconds. X usually is a far too small number and that can translate into way too much wasted bandwidth, if we are talking about a high-traffic website and if we need that polling done for multiple actions</li>
<li>it can eventually make the client hang-up as most modern browsers ( except for Chrome &#8211; or at least &#8211; what Chrome pleads ) don&#8217;t have smart javascript garbage collection and all those requests can be quite costly.</li>
<li>it is not really highly-responsive &#8211; it has a lag of 2 seconds which may be enough to make the users nervous</li>
<li>this just doesn&#8217;t feel like the right way of doing things</li>
</ul>
<h3>Comet</h3>
<p>Well, I need to be honest &#8211; the <a  title="Comet" href="http://en.wikipedia.org/wiki/Comet_(programming)" target="_blank">Comet</a> technique ( also known as <strong>long-polling</strong> ) seems like nothing new but I personally was not aware of it&#8217;s power till recently ( <a  href="http://pagebakers.nl">Eelco</a> pointed it to me ). But you will be amazed how many open- and closed-source projects have no idea that it is out there and do not try to use it. And it is simple &#8211; you make a request to the server, it gets it and just&#8230; <em>waits</em>. Waits till there is meaningful data to be returned or returns something less useful ( like null ), if the request is about to timeout. On a standard apache configuration that would mean 5 minutes &#8211; <strong>you can make just one single request on every 5 minutes</strong>, not on every 2 seconds ( which a traditional ajax app would do ). That is 150+ times less requests, less bandwidth, less javascript functions&#8217; calls and the application would feel <strong>much more responsive</strong>.</p>
<p>There is, however, a small side note to mention&#8230;</p>
<h3>PHP Sessions are not keen on long-polling</h3>
<p>And, if you hadn&#8217;t read this post, you&#8217;d have had some hard time finding this out. It is just that in every normal application, you can be 97% sure you will be using sessions. And in most of the time, you will rely on the built-in php sessions&#8217; handler. So far, so good. But the small problem is that you cannot simultaneously be running different scripts ( or more than one instantiation of a script ) which use one and the same user session ( that, again, was a discovery by <a  href="http://pagebakers.nl">Mr. Pagebaker</a> ). PHP will just queue all subsequent requests which try to interact with that session, until the first one has been closed. Well, that is not much of an <em>asynchroneous</em> technique either then. Getting back to our chat application &#8211; if you want to long-poll the server and wait for new messages ( what we will call read() ) and simultaneously send new messages to the server ( write() ), the application will not write() until the read() request has finished ( which we have set to 5 mins, if in the worst case there is no new data to be received ) &#8211; that is absolutely not what we need.</p>
<h3>Frameworks to the rescue</h3>
<p>But, as all self-respectful developers, you have adopted a php framework which provides an alternative to the native php sessions&#8217; handler &#8211; be it file, database or any other geeky approach. I&#8217;d prefer CakePHP where it is simple &#8211; just open your /app/config/core.php and find</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">Configure<span style="color: #339933;">::</span><span style="color: #004000;">write</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Session.save'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'php'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>change that to</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">Configure<span style="color: #339933;">::</span><span style="color: #004000;">write</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Session.save'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'database'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>and uncomment the few lines below that line with respective data.</p>
<p>So, now let&#8217;s see what we have:</p>
<p>Our client-side script ( jQuery again ):</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #003366; font-weight: bold;">function</span> read<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
  jQuery.<span style="color: #660066;">ajax</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#123;</span>
    <span style="color: #3366CC;">'url'</span>     <span style="color: #339933;">:</span> <span style="color: #3366CC;">'/chat/read/'</span><span style="color: #339933;">,</span>
    <span style="color: #3366CC;">'cache'</span>   <span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">false</span><span style="color: #339933;">,</span>
    <span style="color: #3366CC;">'dataType'</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">'json'</span><span style="color: #339933;">,</span>
    <span style="color: #3366CC;">'success'</span> <span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>messages<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
      <span style="color: #000066; font-weight: bold;">if</span><span style="color: #009900;">&#40;</span> messages.<span style="color: #660066;">length</span> <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
	<span style="color: #006600; font-style: italic;">//write to chat wall</span>
      <span style="color: #009900;">&#125;</span>
      read<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
  <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>It is important to notice that even though I have not shown the write() function, you should use <a  href="http://plugins.jquery.com/project/ajaxqueue">jQuery&#8217;s Ajax Queue Plugin</a>, so that our write requests are kept in good order. That is not needed when we read() as no subsequent read() requests will be fired before the first one has ended.</p>
<p>And, our cakephp chat controller method:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> read<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
  <span style="color: #000088;">$lastMessage_id</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>Session<span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>read<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Conversation.lastMessage_id'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span> <span style="color: #000088;">$lastMessage_id</span> <span style="color: #339933;">===</span> <span style="color: #009900; font-weight: bold;">null</span> <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
    <span style="color: #b1b100;">echo</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>Json<span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>encode<span style="color: #009900;">&#40;</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>Session<span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>write<span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">'Conversation.lastMessage_id'</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">0</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #990000;">exit</span><span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
  <span style="color: #000088;">$now</span> <span style="color: #339933;">=</span> <span style="color: #990000;">time</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #000088;">$timeout</span> <span style="color: #339933;">=</span> <span style="color: #cc66cc;">300</span><span style="color: #339933;">;</span>
  <span style="color: #b1b100;">while</span><span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><span style="color: #990000;">connection_aborted</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
    <span style="color: #000088;">$messages</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>Conversation<span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>read<span style="color: #009900;">&#40;</span> <span style="color: #000088;">$lastMessage_id</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span> <span style="color: #339933;">!</span><span style="color: #990000;">empty</span><span style="color: #009900;">&#40;</span> <span style="color: #000088;">$messages</span> <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
      <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>Session<span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>write<span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">'Conversation.lastMessage_id'</span><span style="color: #339933;">,</span> <span style="color: #000088;">$messages</span><span style="color: #009900;">&#91;</span> <span style="color: #990000;">count</span><span style="color: #009900;">&#40;</span> <span style="color: #000088;">$messages</span> <span style="color: #009900;">&#41;</span> <span style="color: #339933;">-</span> <span style="color: #cc66cc;">1</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'Message'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'id'</span><span style="color: #009900;">&#93;</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
      <span style="color: #b1b100;">echo</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>Json<span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>encode<span style="color: #009900;">&#40;</span> <span style="color: #000088;">$messages</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
      <span style="color: #990000;">exit</span><span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
    <span style="color: #b1b100;">elseif</span><span style="color: #009900;">&#40;</span> <span style="color: #990000;">time</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">&amp;</span>gt<span style="color: #339933;">;</span> <span style="color: #000088;">$now</span> <span style="color: #339933;">+</span> <span style="color: #000088;">$timeout</span> <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
      <span style="color: #b1b100;">echo</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>Json<span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>еncode<span style="color: #009900;">&#40;</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
      <span style="color: #990000;">exit</span><span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
    <span style="color: #990000;">sleep</span><span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>In short &#8211; we get the last message id from the user session then use it to fetch newer records from the model. If there are none and the user hasn&#8217;t left our webpage, we start looking for new messages once again and so on. We also keep track on the time we have spent so far in that iteration &#8211; we don&#8217;t want an ugly timeout, that is why we just send an empty response, if we have reached a critical level ( $timeout = 300 in that case ).</p>
<p>For simplicity, I do not use views in that example but it is highly recommended that you avoid using the JSON component and use views instead ( who knows, you might need a different format in the future ).</p>
<p>Notice the sleep(1) line &#8211; we don&#8217;t want our CPU to burn out after a few hours of work, so some time for rest is highly recommended. You may, of course, use smaller intervals but at your own risk.</p>
<p>That is it for now &#8211; feel free to comment and thanks for reading <img src='http://www.ovalpixels.com/blog/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://www.ovalpixels.com/blog/2008/11/15/highly-responsive-ajax-applications-without-excess-bandwidth-waste/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>

