<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title type="text">Filmic Blog</title>
  <updated>2016-01-03T03:36:35+01:00</updated>
  <generator uri="http://framework.zend.com" version="1.12.3">Zend_Feed_Writer</generator>
  <link rel="alternate" type="text/html" href="http://filmic.eu/blog"/>
  <link rel="self" type="application/atom+xml" href="http://filmic.eu/blog/feed"/>
  <id>http://filmic.eu/blog</id>
  <author>
    <name>Filip Michałowski</name>
    <email>kanelbula@gmail.com</email>
    <uri>http://filmic.eu</uri>
  </author>
  <entry xmlns:xhtml="http://www.w3.org/1999/xhtml">
    <title type="html"><![CDATA[Build a web project using gulp.js]]></title>
    <summary type="html"><![CDATA[Filmic Blog => The tech blog of Filip Michalowski]]></summary>
    <published>2014-01-17T22:45:00+01:00</published>
    <updated>2014-01-17T22:45:00+01:00</updated>
    <link rel="alternate" type="text/html" href="http://filmic.eu/blog/build-a-web-project-using-gulpjs"/>
    <id>http://filmic.eu/blog/build-a-web-project-using-gulpjs</id>
    <author>
      <name>Filip Michałowski</name>
      <email>kanelbula@gmail.com</email>
      <uri>http://filmic.eu</uri>
    </author>
    <content xmlns:xhtml="http://www.w3.org/1999/xhtml" type="xhtml">
      <xhtml:div xmlns:xhtml="http://www.w3.org/1999/xhtml"><xhtml:p>I have been playing around with <xhtml:a href="http://gulpjs.com/" title="Gulpjs" target="_blank">gulp.js</xhtml:a> streaming build system in the last few days.<xhtml:br/>
Its single configuration file (gulpfile) uses code to define tasks and can be written in any language as long as you install and specify the language module so the gulp CLI can load it.</xhtml:p>

<xhtml:p>
I decided to use CoffeeScript since it's my favorite front-end language. My simple example project contains a single html file that loads CSS and JavaScript files.</xhtml:p>

<xhtml:p>Gulp is configured to:</xhtml:p>

<xhtml:ul class="disc">
	<xhtml:li>run local webserver (using connect)</xhtml:li>
	<xhtml:li>concatenate and compile CoffeeScript files into minified Javascript</xhtml:li>
	<xhtml:li>compile Sass files into CSS</xhtml:li>
	<xhtml:li>run LiveReload server</xhtml:li>
	<xhtml:li>watch files on change and reload the page</xhtml:li>
</xhtml:ul>
<xhtml:p/>
<xhtml:p>To run gulp.js with these tasks you need to have the latest version of Node.js and install some packages into the project folder using npm:</xhtml:p>

<xhtml:ul class="disc">
	<xhtml:li>install gulp and gulp-util
		<xhtml:pre class="brush: shell">npm install gulp gulp-util</xhtml:pre>
	</xhtml:li>

	<xhtml:li>install gulp plugins
		<xhtml:pre class="brush: shell">npm install gulp-coffee gulp-concat gulp-livereload gulp-sass gulp-uglify gulp-util</xhtml:pre>
	</xhtml:li>

	<xhtml:li>install connect webserver
		<xhtml:pre class="brush: shell">npm install connect</xhtml:pre>
	</xhtml:li>

	<xhtml:li>install LiveReload server
		<xhtml:pre class="brush: shell">npm install tiny-lr</xhtml:pre>
	</xhtml:li>
</xhtml:ul>

<xhtml:p>
Additionally you will need <xhtml:a href="https://chrome.google.com/webstore/detail/livereload/jnihajbhpnppcggbcgedagnkighmdlei" title="LiveReload plugin" target="_blank">LiveReload plugin</xhtml:a> for Google Chrome.
</xhtml:p>

<xhtml:p>
<xhtml:strong>To start the build run:</xhtml:strong>
<xhtml:pre class="brush: shell">gulp --require=gulp-coffee</xhtml:pre>
</xhtml:p>

<xhtml:h3>And here is the gulp.js config file (gulpfile.coffee):</xhtml:h3>
<xhtml:pre class="brush: js">
gulp = require 'gulp'
gutil = require 'gulp-util'

coffee = require 'gulp-coffee'
concat = require 'gulp-concat'
uglify = require 'gulp-uglify'
sass = require 'gulp-sass'
refresh = require 'gulp-livereload'

connect = require 'connect'
http = require 'http'
path = require 'path'
lr = require 'tiny-lr'
server = do lr

# Starts the webserver (http://localhost:3000)
gulp.task 'webserver', -&gt;
	port = 3000
	hostname = null # allow to connect from anywhere
	base = path.resolve '.'
	directory = path.resolve '.'

	app = connect()
		.use(connect.static base)
		.use(connect.directory directory)

	http.createServer(app).listen port, hostname

# Starts the livereload server
gulp.task 'livereload', -&gt;
    server.listen 35729, (err) -&gt;
        console.log err if err?

# Compiles CoffeeScript files into js file
# and reloads the page
gulp.task 'scripts', -&gt;
	gulp.src('scripts/coffee/**/*.coffee')
		.pipe(concat 'scripts.coffee')
		.pipe(do coffee)
		.pipe(do uglify)
		.pipe(gulp.dest 'scripts/js')
		.pipe(refresh server)

# Compiles Sass files into css file
# and reloads the styles
gulp.task 'styles', -&gt;
    gulp.src('styles/scss/init.scss')
        .pipe(sass includePaths: ['styles/scss/includes'])
        .pipe(concat 'styles.css')
        .pipe(gulp.dest 'styles/css')
        .pipe(refresh server)

# Reloads the page
gulp.task 'html', -&gt;
	gulp.src('*.html')
		.pipe(refresh server)

# The default task
gulp.task 'default', -&gt;
	gulp.run 'webserver', 'livereload', 'scripts', 'styles'

	# Watches files for changes
	gulp.watch 'scripts/coffee/**', -&gt;
		gulp.run 'scripts'

	gulp.watch 'styles/scss/**', -&gt;
		gulp.run 'styles'

	gulp.watch '*.html', -&gt;
		gulp.run 'html'
</xhtml:pre>

<xhtml:p>For non-coffeescript devs the same config file <xhtml:a href="http://coffeescript.org/#try:gulp%20%3D%20require%20'gulp'%0Agutil%20%3D%20require%20'gulp-util'%0A%0Acoffee%20%3D%20require%20'gulp-coffee'%0Aconcat%20%3D%20require%20'gulp-concat'%0Auglify%20%3D%20require%20'gulp-uglify'%0Asass%20%3D%20require%20'gulp-sass'%0Arefresh%20%3D%20require%20'gulp-livereload'%0A%0Aconnect%20%3D%20require%20'connect'%0Ahttp%20%3D%20require%20'http'%0Apath%20%3D%20require%20'path'%0Alr%20%3D%20require%20'tiny-lr'%0Aserver%20%3D%20do%20lr%0A%0A%23%20Starts%20the%20webserver%20(http%3A%2F%2Flocalhost%3A3000)%0Agulp.task%20'webserver'%2C%20-%3E%0A%09port%20%3D%203000%0A%09hostname%20%3D%20null%20%23%20allow%20to%20connect%20from%20anywhere%0A%09base%20%3D%20path.resolve%20'.'%0A%09directory%20%3D%20path.resolve%20'.'%0A%0A%09app%20%3D%20connect()%0A%09%09.use(connect.static%20base)%0A%09%09.use(connect.directory%20directory)%0A%0A%09http.createServer(app).listen%20port%2C%20hostname%0A%0A%23%20Starts%20the%20livereload%20server%0Agulp.task%20'livereload'%2C%20-%3E%0A%20%20%20%20server.listen%2035729%2C%20(err)%20-%3E%0A%20%20%20%20%20%20%20%20console.log%20err%20if%20err%3F%0A%0A%23%20Compiles%20CoffeeScript%20files%20into%20js%20file%0A%23%20and%20reloads%20the%20page%0Agulp.task%20'scripts'%2C%20-%3E%0A%09gulp.src('scripts%2Fcoffee%2F**%2F*.coffee')%0A%09%09.pipe(concat%20'scripts.coffee')%0A%09%09.pipe(do%20coffee)%0A%09%09.pipe(do%20uglify)%0A%09%09.pipe(gulp.dest%20'scripts%2Fjs')%0A%09%09.pipe(refresh%20server)%0A%0A%23%20Compiles%20Sass%20files%20into%20css%20file%0A%23%20and%20reloads%20the%20styles%0Agulp.task%20'styles'%2C%20-%3E%0A%20%20%20%20gulp.src('styles%2Fscss%2Finit.scss')%0A%20%20%20%20%20%20%20%20.pipe(sass%20includePaths%3A%20%5B'styles%2Fscss%2Fincludes'%5D)%0A%20%20%20%20%20%20%20%20.pipe(concat%20'styles.css')%0A%20%20%20%20%20%20%20%20.pipe(gulp.dest%20'styles%2Fcss')%0A%20%20%20%20%20%20%20%20.pipe(refresh%20server)%0A%0A%23%20Reloads%20the%20page%0Agulp.task%20'html'%2C%20-%3E%0A%09gulp.src('*.html')%0A%09%09.pipe(refresh%20server)%0A%0A%23%20The%20default%20task%0Agulp.task%20'default'%2C%20-%3E%0A%09gulp.run%20'webserver'%2C%20'livereload'%2C%20'scripts'%2C%20'styles'%0A%0A%09%23%20Watches%20files%20for%20changes%0A%09gulp.watch%20'scripts%2Fcoffee%2F**'%2C%20-%3E%0A%09%09gulp.run%20'scripts'%0A%0A%09gulp.watch%20'styles%2Fscss%2F**'%2C%20-%3E%0A%09%09gulp.run%20'styles'%0A%0A%09gulp.watch%20'*.html'%2C%20-%3E%0A%09%09gulp.run%20'html'%0A%09" target="_blank">translated into JavaScript</xhtml:a></xhtml:p>
<xhtml:p/>
<xhtml:p>You can find this example project with gulp.js setup on <xhtml:a href="https://github.com/filmic/gulpjs-example" title="Gulp.js example" target="_blank">Github</xhtml:a>.</xhtml:p></xhtml:div>
    </content>
  </entry>
  <entry xmlns:xhtml="http://www.w3.org/1999/xhtml">
    <title type="html"><![CDATA[Make your own Twitter timeline using Zend PHP Framework and HTML5]]></title>
    <summary type="html"><![CDATA[Filmic Blog => The tech blog of Filip Michalowski]]></summary>
    <published>2012-02-27T06:48:56+01:00</published>
    <updated>2012-02-27T06:48:56+01:00</updated>
    <link rel="alternate" type="text/html" href="http://filmic.eu/blog/make-your-own-twitter-timeline-using-zend-php-framework-and-html5"/>
    <id>http://filmic.eu/blog/make-your-own-twitter-timeline-using-zend-php-framework-and-html5</id>
    <author>
      <name>Filip Michałowski</name>
      <email>kanelbula@gmail.com</email>
      <uri>http://filmic.eu</uri>
    </author>
    <content xmlns:xhtml="http://www.w3.org/1999/xhtml" type="xhtml">
      <xhtml:div xmlns:xhtml="http://www.w3.org/1999/xhtml">	<xhtml:p>In this tutorial I will show how to make a Twitter user timeline on a website using Zend Framework and HTML5.
</xhtml:p>

<xhtml:p>
	If you are not familiar with Zend and want to build a website using it I recommend the Rob Allen's <xhtml:a href="http://akrabat.com/zend-framework-tutorial/">tutorial</xhtml:a> and the framework's <xhtml:a href="http://framework.zend.com/manual/">documentation</xhtml:a>.
</xhtml:p>
  
<xhtml:p>
	Part of the Zend Framework, <xhtml:strong>Zend_Service_Twitter</xhtml:strong> component provides a client for the Twitter REST API. <xhtml:strong>Zend_Service_Twitter</xhtml:strong> requires authentication as a valid user using the OAuth authentication protocol. The OAuth implementation used by <xhtml:strong>Zend_Service_Twitter</xhtml:strong> is <xhtml:strong>Zend_Oauth</xhtml:strong> component. In this tutorial I will request my own Twitter timeline data so I will use <xhtml:strong>Zend_Oauth</xhtml:strong> directly to create access token and pass it into <xhtml:strong>Zend_Service_Twitter</xhtml:strong> (no need to redirect users to Twitter to give their consent to the requested authorization).

</xhtml:p>

<xhtml:p>
	In order to authenticate with Twitter and sign requests with your own Twitter account you need to register a new Twitter application on <xhtml:a href="https://dev.twitter.com/apps">https://dev.twitter.com/apps</xhtml:a> site and obtain "access token" and "access token secret".</xhtml:p>

<xhtml:p>
	Next create <xhtml:strong>Zend_Oauth_Token_Access</xhtml:strong> object in the controller file:
</xhtml:p>

<xhtml:pre class="brush: php">
// Create OAuth token object
$token = new Zend_Oauth_Token_Access();

// Set token and secret
$token-&gt;setToken('twitter_access_token')-&gt;setTokenSecret('twitter_access_token_secret');
</xhtml:pre>

<xhtml:p>Having the token let's create <xhtml:strong>Zend_Service_Twitter</xhtml:strong> object and request data from Twitter API:</xhtml:p>
<xhtml:pre class="brush: php">
// Create options array
$options = array('accessToken' =&gt; $token);
			
// Create Twitter service object
$twitter = new Zend_Service_Twitter($options);

// Request data from Twitter (20 most recent statuses posted from the authenticating user)
$this-&gt;view-&gt;twitter_timeline = $twitter-&gt;status-&gt;userTimeline();
</xhtml:pre>

<xhtml:p>The request returns a <xhtml:strong>Zend_Rest_Client_Response</xhtml:strong> object. This object has many properties that make it easier to access the results. The Twitter statuses are contained in the "status" array:</xhtml:p>

<xhtml:pre class="brush: php">
Zend_Rest_Client_Result Object
(
	[_sxml:protected] =&gt; SimpleXMLElement Object
		(
			[@attributes] =&gt; Array
				(
					[type] =&gt; array
				)

			[status] =&gt; Array
				(
					[0] =&gt; SimpleXMLElement Object
						(
							[created_at] =&gt; Thu Dec 22 11:48:02 +0000 2011
							[id] =&gt; 149818475026714624
							[text] =&gt; Swiss Govt: Downloading Movies and Music Will Stay Legal | TorrentFreak http://t.co/55k6AKjm via @torrentfreak
							[source] =&gt; &lt;a href="http://twitter.com/tweetbutton" rel="nofollow"&gt;Tweet Button&lt;/a&gt;
							...
</xhtml:pre>
	
<xhtml:p>
	The next task is to render the Twitter timeline data in the view file corresponding to the controller file. Since the received data is iterable I can make use of the <xhtml:a href="http://framework.zend.com/manual/1.11/en/zend.view.helpers.html#zend.view.helpers.initial.partial">PartialLoop View Helper</xhtml:a> and render each Twitter post with a template.
	</xhtml:p>
	
	<xhtml:p>First create a folder for the templates in the "library" folder: <xhtml:span class="code">library/MyProject/View/Scripts/templates</xhtml:span></xhtml:p>

	
	<xhtml:p>Next register the custom view scripts location in the Bootstrap file:
	</xhtml:p>
   <xhtml:pre class="brush: php">
 // add custom view scripts 
 $this-&gt;view-&gt;addScriptPath(APPLICATION_PATH.'/../library/MyProject/View/Scripts');
</xhtml:pre>
	<xhtml:p>
		Create template file and call it "twitter_feed.phtml". It will contain HTML markup of a single tweet status update:
	</xhtml:p>
	
	<xhtml:pre class="brush: php">
&lt;article&gt;
	&lt;header&gt;
		&lt;!-- Display create date of the tweet --&gt;
		&lt;time datetime="&lt;?php echo date('Y-m-d\TH:i:s.uP', strtotime($this -&gt; post -&gt; created_at));?&gt;" pubdate&gt;&lt;?php echo date('F jS, Y @ H:i', strtotime($this -&gt; post -&gt; created_at));?&gt;&lt;/time&gt;
	&lt;/header&gt;
	&lt;p&gt;
		&lt;?php
			$tweet = $this -&gt; post -&gt; text;
						
			// Detect links in the tweet text and wrap them in &lt;a&gt; elements
			$regex = '/http([s]?):\/\/([^\ \)$]*)/';
			$link_pattern = '&lt;a href="http$1://$2" rel="nofollow" target="_blank" title="$2"&gt;http$1://$2&lt;/a&gt;';
			$tweet = preg_replace($regex,$link_pattern,$tweet);

			// Detect mentions to other users and wrap them in &lt;a&gt; elements
			$regex = '/@([a-zA-Z0-9_]*)/';
			$link_pattern = '&lt;a href="http://twitter.com/$1" target="_blank" title="$1 profile on Twitter" rel="nofollow"&gt;@$1&lt;/a&gt;';
			$tweet = preg_replace($regex,$link_pattern,$tweet);

			// Detect hash tags and wrap them in &lt;a&gt; elements
			$regex = '/\#([a-zA-Z0-9_]*)/';
			$link_pattern = '&lt;a href="http://search.twitter.com/search?q=%23$1" target="_blank" title="Search for $1 on Twitter" rel="nofollow"&gt;#$1&lt;/a&gt;';
			$tweet = preg_replace($regex,$link_pattern,$tweet);

			// Show tweet text
			echo $tweet;
		?&gt;
	&lt;/p&gt;

&lt;/article&gt;
</xhtml:pre>
	
	<xhtml:p>Now add the following code to the view file:</xhtml:p>
	
	<xhtml:pre class="brush: html">
&lt;section class="twitter"&gt;
	&lt;h2&gt;My Twitter feed&lt;/h2&gt;
	&lt;?php
		// Set key - used in the template file to reference data object
		$this-&gt;partialLoop()-&gt;setObjectKey('post');

		// Run partial loop using the template file and object with data set in the controller file
		echo $this-&gt;partialLoop('templates/twitter_feed.phtml', $this-&gt;twitter_timeline);
	?&gt;
	&lt;!-- Show follow button in the footer --&gt;
	&lt;footer&gt;
		&lt;a href="http://twitter.com/fmmm" class="twitter-follow-button"&gt;Follow @fmmm&lt;/a&gt;
		&lt;script src="http://platform.twitter.com/widgets.js" type="text/javascript"&gt;&lt;/script&gt;
	&lt;/footer&gt;

&lt;/section&gt;
</xhtml:pre>
	
	<xhtml:p>With some CSS styling the Twitter timeline is now ready! See the main page of <xhtml:a href="http://filmic.eu">filmic.eu</xhtml:a> (right column) for an example of the working timeline.</xhtml:p></xhtml:div>
    </content>
  </entry>
  <entry xmlns:xhtml="http://www.w3.org/1999/xhtml">
    <title type="html"><![CDATA[Secure connection to MySQL database through SSH tunnel]]></title>
    <summary type="html"><![CDATA[Filmic Blog => The tech blog of Filip Michalowski]]></summary>
    <published>2011-07-17T02:00:00+02:00</published>
    <updated>2011-07-17T02:00:00+02:00</updated>
    <link rel="alternate" type="text/html" href="http://filmic.eu/blog/secure-connection-to-mysql-database-through-ssh-tunnel"/>
    <id>http://filmic.eu/blog/secure-connection-to-mysql-database-through-ssh-tunnel</id>
    <author>
      <name>Filip Michałowski</name>
      <email>kanelbula@gmail.com</email>
      <uri>http://filmic.eu</uri>
    </author>
    <content xmlns:xhtml="http://www.w3.org/1999/xhtml" type="xhtml">
      <xhtml:div xmlns:xhtml="http://www.w3.org/1999/xhtml"><xhtml:p>In my development I often work with remote database servers which are not exposed to the world outside. This tutorial describes how to connect to a MySQL server which is firewalled and configured only for local access. The secure, encrypted connection can be made via a SSH tunnel.</xhtml:p>
    
<xhtml:p>First make sure that the remote host has a SSH server running and there is an user account that you can connect with SSH to (let's say 'user@example.com').<xhtml:br/>
Secondary there should be a database user with granted access from 127.0.0.1 location (let's say 'dbuser').</xhtml:p>
    
    <xhtml:p>Having that in place the SSH tunnel can be created.
On Mac/Linux run this command and enter password:</xhtml:p>
    
<xhtml:pre class="brush: shell">ssh -L 3306:localhost:3306 user@example.com</xhtml:pre>
<xhtml:p/>
<xhtml:p>The first port 3306 is the local port that you will be listening on. The second port 3306 is the remote port you will connect to. MySQL by default listens on 3306. After you connect leave the window working and minimized.</xhtml:p>
    
<xhtml:p>On Windows use PuTTY and configure the connection details on the "Session" screen - enter the host name.</xhtml:p>

<xhtml:p class="img"><xhtml:img class="shadow" src="http://filmic.eu/assets/img/blog/putty1.png" alt="PuTTY session configuration"/></xhtml:p><xhtml:p/>
    
<xhtml:p>Then go to "Connection" &gt; "SSH" &gt; "Tunnels" screen. In the "Source port" field enter <xhtml:span class="code">3306</xhtml:span> and in the "Destination" field enter <xhtml:span class="code">localhost:3306</xhtml:span>.</xhtml:p>

<xhtml:p class="img"><xhtml:img class="shadow" src="http://filmic.eu/assets/img/blog/putty2.png" alt="PuTTY tunnel configuration"/> </xhtml:p><xhtml:p/>
    
    <xhtml:p>Next click on the "Add" button and in the "Forwarded ports" field you should see<xhtml:br/>
    <xhtml:span class="code">L3306 localhost:3306</xhtml:span>.
    <xhtml:br/>    
Click on the "Open" button and enter password. After you connect leave the window working and minimized.</xhtml:p>
       
    <xhtml:p>Now you have the tunnel established so you can connect to the remote database as it was running on the localhost on port 3306.<xhtml:br/>
        You need to configure your application to connect to 127.0.0.1 (not localhost, if you use localhost mysql will assume you want to connect to a unix socket which will not work over the tunnel). For example with the PHP code:</xhtml:p>

<xhtml:pre class="brush: php">
<?php // we connect to localhost at port 3306
$link = mysql_connect('127.0.0.1:3306', 'dbuser', 'dbpassword');
if (!$link) {
    die('Could not connect: ' . mysql_error());
}
echo 'Connected successfully';
mysql_close($link);
?>
</xhtml:pre>
<xhtml:p/>
        <xhtml:p>Or mysql command line client:</xhtml:p>
        <xhtml:pre class="brush: shell">mysql -u dbuser -h 127.0.0.1 -p</xhtml:pre>
        <xhtml:p/>
        <xhtml:p>There are also tools that create a SSH tunnel internally so you do not need to established the connection manually. One I often use to manage a remote database server is the <xhtml:a href="http://wb.mysql.com/" title="MySQL Workbench">MySQL Workbench</xhtml:a>. Within this program the connection can be set up with SSH tunnel - in the "New Connection" dialog choose the "Standard TCP/IP over SSH" for the "Connection Method" option. Next enter details of your SSH and MySQL servers.</xhtml:p>
        
<xhtml:p class="img"><xhtml:img src="http://filmic.eu/assets/img/blog/tools.png" alt="Setting up a new connection in MySQL Workbench"/> </xhtml:p>

        <xhtml:p>Once connected you can administrate the remote server, design the database and edit the data even if it is behind a firewall.</xhtml:p></xhtml:div>
    </content>
  </entry>
  <entry xmlns:xhtml="http://www.w3.org/1999/xhtml">
    <title type="html"><![CDATA[CSS3 Looped Animations. Multiple animation loop]]></title>
    <summary type="html"><![CDATA[Filmic Blog => The tech blog of Filip Michalowski]]></summary>
    <published>2011-10-07T19:00:00+02:00</published>
    <updated>2011-10-07T19:00:00+02:00</updated>
    <link rel="alternate" type="text/html" href="http://filmic.eu/blog/css3-looped-animations"/>
    <id>http://filmic.eu/blog/css3-looped-animations</id>
    <author>
      <name>Filip Michałowski</name>
      <email>kanelbula@gmail.com</email>
      <uri>http://filmic.eu</uri>
    </author>
    <content xmlns:xhtml="http://www.w3.org/1999/xhtml" type="xhtml">
      <xhtml:div xmlns:xhtml="http://www.w3.org/1999/xhtml"><xhtml:p>Recently I was working on the Filmic.eu teaser site. My idea was to create simple transitions purely based on the CSS3 features so the site worked and looked nice without any single line of JS code. One of the challenges I faced was how to create a CSS animation that loops through multiple text elements using fade in and out transitions.</xhtml:p>

<xhtml:p>Looking at the <xhtml:a href="http://www.w3.org/TR/css3-animations/" target="_blank" title="CSS3 Animations Specs">CSS3 Animations Module specs</xhtml:a> there are properties useful for creating a CSS animation loop:
    <xhtml:ul class="disc">
        <xhtml:li>The <xhtml:span class="code">animation-iteration-count</xhtml:span> property can be set to <xhtml:span class="code">infinite</xhtml:span> so the animation repeats forever.</xhtml:li>
        <xhtml:li>The <xhtml:span class="code">animation-direction</xhtml:span> property when set to <xhtml:span class="code">alternate</xhtml:span> allows to play animation cycle iterations that are even counts in a reverse direction. This can be used to fade in and fade out an element using one and the same animation played in both directions.</xhtml:li>
    </xhtml:ul>
</xhtml:p>
<xhtml:p>In my case I wanted to animate 3 list elements, showing and hiding one after another. To achieve it without event handling in Javascript I had to set a delay for each upcoming animation so the second animation plays after the first one, the third one after the second one and so on.
    <xhtml:br/>
    The CSS <xhtml:span class="code">animation-delay</xhtml:span> property comes to help. It allows an animation to begin execution some time after it is applied. However it applies for the first iteration of the animation only. The next iterations will be executed immediately which breaks the order of the fade in / out animations.</xhtml:p>
<xhtml:p>My solution for this problem was to play around with the animation @keyframes rule to emulate the "delay" behaviour by keeping the property value unchanged over some period of time.
</xhtml:p>
<xhtml:p>Let's look at some code. The example works in the Chrome, Safari, Firefox 5 or better browsers.</xhtml:p>

<xhtml:h3>First create a list with elements that will be animated:</xhtml:h3>
<xhtml:pre class="brush: html">
&lt;div id="animation"&gt;
    &lt;ul&gt;
        &lt;li&gt;This is&lt;/li&gt;
        &lt;li&gt;CSS3 looped&lt;/li&gt;
        &lt;li&gt;animation&lt;/li&gt;
    &lt;/ul&gt;
&lt;/div&gt;
</xhtml:pre>
<xhtml:p/>
<xhtml:h3>Then define the CSS styles:</xhtml:h3>
    The animations are defined using the CSS3 <xhtml:span class="code">animation</xhtml:span> shorthand property that combines six of the animation properties into a single property:
    <xhtml:br/>
    <xhtml:span class="code">[&lt;animation-name&gt; || &lt;animation-duration&gt; ||&lt;animation-timing-function&gt; || &lt;animation-delay&gt; || &lt;animation-iteration-count&gt; || &lt;animation-direction&gt;]</xhtml:span>
<xhtml:pre class="brush: css">
#animation ul { /* The list with elements */
    position: relative;
    text-align: center;
    width: 200px;
}
#animation li { /* Common styles for the list elements */
    position: absolute;
    left:0;
    top:0;
    width: 100%;
    opacity: 0;
    padding: 10px;
}
#animation li:nth-of-type(1) { /* First element of the list */
    background-color: lightgreen;
    
    -webkit-animation: fadein 6s ease-in-out -4s infinite alternate; /* delay = -duration * 66%. Note the negative delay to skip the "keyframes delay" */
    -moz-animation: fadein 6s ease-in-out -4s infinite alternate;
    animation: fadein 6s ease-in-out -4s infinite alternate;
}
#animation li:nth-of-type(2) { /* Second element of the list */
    background-color: yellow;
    
    -webkit-animation: fadein 6s ease-in-out 0s infinite alternate; 
    -moz-animation: fadein 6s ease-in-out 0s infinite alternate;
    animation: fadein 6s ease-in-out 0s infinite alternate;
}
#animation li:nth-of-type(3) { /* Third element of the list */
    background-color: lightblue;
    
    -webkit-animation: fadein 6s ease-in-out 4s infinite alternate; /* delay = duration * 66% */
    -moz-animation: fadein 6s ease-in-out 4s infinite alternate;
    animation: fadein 6s ease-in-out 4s infinite alternate;
}

/* Defines the animation keyframes */
@-webkit-keyframes fadein {
    0% {           /* "Delay" of the animation - 66% of the duration time (100 - 100/number of elements) */ 
        opacity: 0;
    }
    66% {          /* Actual beginning of the fade in animation */
        opacity: 0;
    }
    76% {          /* The fade in animation takes 10% of the duration time */
        opacity: 1;
    }    
    100% {
        opacity: 1;
    }    
}
@-moz-keyframes fadein {
    0% {
        opacity: 0;
    }
    66% {
        opacity: 0;
    }
    76% {
        opacity: 1;
    }    
    100% {
        opacity: 1;
    }    
}
@keyframes fadein {
    0% {
        opacity: 0;
    }
    66% {
        opacity: 0;
    }
    76% {
        opacity: 1;
    }    
    100% {
        opacity: 1;
    }    
}
</xhtml:pre>
<xhtml:p/>
<xhtml:h3>And the result:</xhtml:h3>
<xhtml:div id="animation">
    <xhtml:ul>
        <xhtml:li>This is</xhtml:li>
        <xhtml:li>CSS3 looped</xhtml:li>
        <xhtml:li>animation</xhtml:li>
    </xhtml:ul>
</xhtml:div>

<xhtml:p>The number of animated elements can be different but it requires adjusting the keyframes "delay" range and so the animations initial delays.</xhtml:p>

<xhtml:p>If you want to play around with the code check out this <xhtml:a href="http://jsfiddle.net/kanelbula/PB4BB/" target="_blank" title="CSS3 Looped Animations on the jsFiddle">Fiddle</xhtml:a>.</xhtml:p></xhtml:div>
    </content>
  </entry>
</feed>
