Creating an iOS-like Home Screen with CoffeeScript

Creating an iOS-like Home Screen with CoffeeScript

Today we are going to create an iOS-like home screen using CoffeeScript – a new JavaScript based language, and the jQuery library. CoffeScript has a clean syntax that lies somewhere in between Ruby and Python. If you haven’t used any of them, don’t worry – it is not required. However you will need to be familiar with JavaScript so you can better understand the concepts behind the language.

We are also going to use the Touchable plugin, so we can listen for touch-based events.

First, what is CoffeeScript?

CoffeeScript is a neat programming language meant to enhance the good parts of JavaScript, while working around the not so good. It makes OOP easy and introduces a number of useful additions such as comprehensions, new syntax for functions and scope handling, along with numerous small improvements.

CoffeeScript works in every browser out there, and is compatible with all your existing JavaScript code (including libraries like jQuery and plugins). But how does this work if it is a different language? Simple – CoffeeScript compiles down to JavaScript, so it works in any browser that supports it.

Before you start following this tutorial, I would suggest that you read through the examples on the CoffeeScript website (be sure to check out the “Try CoffeeScript” tab), and The Little Book on CoffeeScript for an introduction to the language.

iOS -like Home Screen with CoffeeScript

iOS -like Home Screen with CoffeeScript

The HTML

Lets start with the HTML markup of our iOS-like home screen. As usual, this is a regular HTML5 document with stylehseets in the head and JS includes before the closing body tag.

index.html

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <title>iOS Home Screen with CoffeeScript | Tutorialzine Demo</title>

        <!-- Our CSS stylesheet file -->
        <link rel="stylesheet" href="assets/css/styles.css" />

        <!--[if lt IE 9]>
          <script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
        <![endif]-->
    </head>

    <body>

		<section id="homeScreen">
			<div id="mask">
				<div id="allScreens">
                                   <!-- The .screen divs will go here -->
                                </div>
			</div>

			<ul id="indicators">
                            <!-- A LI element for every screen -->
                        </ul>

			<div id="dock">
                            <!-- The three dock icons will go here -->
                        </div>
		</section>

        <!-- JavaScript includes -->
		<script src="http://code.jquery.com/jquery-1.6.3.min.js"></script>
		<script src="assets/js/touchable.js"></script>
        <script src="assets/js/coffee-script.js"></script>

		<script type="text/coffeescript">

			# Our Code Goes Here

		</script>

    </body>
</html>

We have the #homeScreen section, which is the main container of our experiment. Inside it is the #mask, which uses overflow:hidden to show only one screen at the time. The #allScreens div inside it, as the name suggests, contains all the dynamically generated .screen divs with icons.

The #mask div shows only one screen at a time with overflow:hidden.

The #mask div shows only one screen at a time with overflow:hidden.

Following is the #indicators UL, which shows the little dots with the currently shown screen, and the #dock div.

As mentioned previously, CoffeeScript requires an extra compilation step, which will convert the source code to JavaScript. You can do this with the coffeescript package for node.js (as explained on their website), or with coffeescript.exe for windows, which is standalone and ready for use executable. For small scripts, you can also include the compiler directly in your page and write your code inline in a <script> tag – which we will be using today.

At the bottom of the page, you can see our script includes. These are the jQuery library, the Touchable plugin, which will help us work with touch events, and the CoffeeScript compilercoffee-script.js. The compiler will look for <script type="text/coffeescript"> tags on the page, which is where we will be writing our code.

The CoffeScript Code

As we are writing the code inline, we do not need to compile it before deploying the web page. This is great for small web pages and during development. However, if you plan on writing larger applications, it would be a better idea to compile your code using one of the tools described above.

Now lets start with writing a simple class – Icon.

# The Icon class. 

class Icon

	# The constructor. The -> arrow signifies
	# a function definition.

	constructor: (@id, @title) ->
		# @ is synonymous for "this". The id and title parameters
		# of the constructor are automatically added as this.id and this.title

		# @markup holds the HTML of the icon. It is
		# transformed to this.markup behind the scenes.

		@markup = "<div class='icon' style='background-image:url(assets/img/icons/#{@id}.png)'
					 title='#{@title}'></div>"

Objects of this class are going to represent the icons in the home screen. Each icon has a markup property which contains the HTML code needed to display it. You can see that functions in CoffeeScript are defined as arrows (->), with the parameters to the function given on the left in braces. Notice that comments here start with the # symbol. You can use three ### to denote multiline comments.

Now lets define a class for the dock icons. It will be pretty similar to the Icon class, so we are going to extend it:

# The DockIcon class inherits from Icon

class DockIcon extends Icon
	constructor: (id, title)->

		# This calls the constructor if Icon

		super(id, title)

		# Changing the class name of the generated HTML
		@markup = @markup.replace("class='icon'","class='dockicon'")

Using super() will call Icon’s constructor and initialize the markup property. We only need to replace the class name.

We will divide the home screen in individual .screen divs, each holding their own set of icons. Here is the class for that:

# The Screen Class

class Screen

	# Function arguments can have default values
	constructor: (icons = [])->
		@icons = icons

	attachIcons: (icons = [])->
		Array.prototype.push.apply(@icons, icons)

	generate: ->
		markup = []

		# Looping through the @icons array
		markup.push(icon.markup) for icon in @icons

		# The last line of every function is implicitly returned
		"<div class='screen'>#{markup.join('')}</div>"

Instead of a markup property, here we are using a generate() method that will return the HTML. Notice how we are looping over the array – this is called a comprehension. The part before the for keyword is executed on every element in the icons array.

The iOS Dock

The iOS Dock

We now need a class that pulls everything together, and controls the transitions between the screens. Here is what it looks like:

class Stage

	# The width of our "device" screen. This is
	# basically the width of the #mask div.

	screenWidth: 332

	constructor: (icons)->

		@currentScreen = 0
		@screens = []

		# Calculating the number of screens
		# necessary to display all the icons

		num = Math.ceil(icons.length / 9)
		i = 0

		while num--
			# we pass a slice of the icons array
			s = new Screen(icons[i...i+9])

			# adding the screen to the local screens array
			@screens.push(s)

			i+=9

	# This method populates the passed element with HTML
	addScreensTo: (element)->

                # We are using the jQuery library from within CS:
		@element = $(element)
		@element.width(@screens.length*@screenWidth)

		for screen in @screens
			@element.append(screen.generate())

	addIndicatorsTo: (elem)->

		# This method creates the small circular
		# indicators. Also using jQuery

		@ul = $(elem)

		for screen in @screens
			@ul.append('<li>')

		@ul.find('li:first').addClass('active');

        # ... More methods go here ...

The Stage takes an array of icons in the constructor. It then calculates how many screens will be needed, and creates an object for each one, passing it a slice of the icons array.

We now have the markup of all these elements on the page, but we are still missing the methods that control the transition between the slides. You can see them below (still part of the Stage class):

	goTo: (screenNum)->

		# This method animates the allScreen div in
		# order to expose the needed screen in #mask

		if @element.is(':animated')
			return false

		# if this is the first or last screen,
		# run the end of scroll animation

		if @currentScreen == screenNum

			# Parallel assignment:
			[from, to] = ['+=15','-=15']

			if @currentScreen != 0
				[from, to] = [to, from]

                        # Tell the user there aren't any more screens:
			@element.animate( { marginLeft : from }, 150 )
					.animate( { marginLeft : to }, 150 )
		else
			# If everything is ok, animate the transition between the screens.
			# The fat arrow => is a function that preserves the context of "this"

			@element.animate( { marginLeft:-screenNum*@screenWidth }, => @currentScreen = screenNum )
			@ul.find('li').removeClass('active').eq(screenNum).addClass('active');

	next: ->
		toShow = @currentScreen+1

		# If there is no next screen, show
		# the last one

		if toShow == @screens.length
			toShow = @screens.length - 1

		@goTo(toShow)

	previous: ->
		toShow = @currentScreen-1

		# If there is no previous screen,
		# show the first one

		if toShow == -1
			toShow = 0

		@goTo(toShow)

Both the next() and previous() methods call goTo() internally, passing a screen number (starting from zero). The goTo() method animates the #allScreen div to show the needed screen.

All we need to do now is bind a function to the document.ready event. For this we will use jQuery .

# This is equivalent to $(function(){}):

$ ->

        # You can skip the comma if it's on the end of a line:
	allIcons = [
		new Icon('Photos', 'Photo Gallery'), new Icon('Maps', 'Google Maps')
		new Icon('Chuzzle', 'Chuzzle'), new Icon('Safari', 'Safari')
		new Icon('Weather', 'Weather'), new Icon('nes', 'NES Emulator')
		new Icon('Calendar', 'Calendar'), new Icon('Clock', 'Clock')
		new Icon('BossPrefs', 'Boss Prefs'), new Icon('Chess', 'Chess')
		new Icon('Mail', 'Mail'), new Icon('Phone', 'Phone')
		new Icon('SMS', 'SMS Center'), new Icon('Camera', 'Camera')
		new Icon('iPod', 'iPod'), new Icon('Calculator', 'Calculator')
		new Icon('Music', 'Music'), new Icon('Poof', 'Poof')
		new Icon('Settings', 'Settings'), new Icon('YouTube', 'Youtube')
		new Icon('psx4all', 'PSx4All'), new Icon('VideoRecorder', 'Record Video')
		new Icon('Installer', 'Installer'), new Icon('Notes', 'Notes')
		new Icon('RagingThunder', 'RagingThunder'), new Icon('Stocks', 'Stocks')
		new Icon('genesis4iphone', 'Genesis'), new Icon('snes4iphone', 'SNES Emulator')
		new Icon('Calendar', 'Calendar'), new Icon('Clock', 'Clock')
		new Icon('Photos', 'Photo Gallery'), new Icon('Maps', 'Google Maps')
	]

	dockIcons = [
		new DockIcon('Camera', 'Camera')
		new DockIcon('iPod', 'iPod')
		new DockIcon('Calculator', 'Calculator')
	]

	allScreens = $('#allScreens')

	# Using the Touchable plugin to listen for
	# touch based events:

	allScreens.Touchable();

	# Creating a new stage object
	stage = new Stage(allIcons)

	stage.addScreensTo(allScreens)
	stage.addIndicatorsTo('#indicators')

	# Listening for the touchablemove event.
	# Notice the callback function. Braces on
        # function calls are optional
	allScreens.bind 'touchablemove', (e,touch)->
		stage.next() if touch.currentDelta.x < -5
		stage.previous() if touch.currentDelta.x > 5

	# Adding the dock icons:

	dock = $('#dock')

	for icon in dockIcons
		dock.append(icon.markup)

By calling the Touchable method we are extending the element to support several touch based events. Among them is touchablemove, which is executed when the user moves his finger across the screen. It is also called when we drag with the mouse. Further down, when we bind for that event, we get a touch object as the second argument of the callback function. It holds the delta, or difference, from the beginning of the movement.

With this our iOS-like Home Screen is complete!

Conclusion

CoffeeScript is an interesting language that can make developing in the browser easier. You can expect to write up to 50% less code comparing to pure JavaScript.

But don’t fall pray to the hype surrounding it just yet – CoffeeScript isn’t going to replace JavaScript any time soon, as it sacrifices some of the agility that JS provides in attempt to make development easier. The CS way might not be the best fit for your project.

CoffeeScript also introduces an extra compilation step that separates you from deploying your code, but this can be solved by web frameworks that compile the code for you as is the case with Rails, where CS became a default.

Join our newsletter and get our PSDs!18,956 people learn about HTML5, JS and more. Join them!

by Martin Angelov

Martin is a web developer with an eye for design from Bulgaria. He founded Tutorialzine in 2009 and it still is his favorite side project.

34 Comments

  1. vladimire says:

    Great introduction to CofeeScript, i'll definitly be using it.. thx

  2. Rey Thibaut says:

    Hum ... CoffeeScript appear to be a very good web language. I think i will work on it soon. Think you so much for all your tutorial, it's very interesting and well built

  3. Wietse says:

    Awesome, thx!

  4. neat as always, mate :)
    but, for this time i am more interested with the coffee script :p

  5. This is neat and awesome as usual.

  6. Toasterdroid says:

    This is very cool. The masking idea alone gives me a lot of creative ideas in itself!

  7. Bruce says:

    Great job dude!

  8. Alban says:

    This is a really nice and good tutorial! I'm certainly looking to incorporate this in my future projects... Thanks!

  9. Isaac Grant says:

    would it be possible to use magic mouse or laptop trackpad gestures as an option for swiping?

  10. MSANTOS says:

    Thanks for this one! One issue is, the icons are not clickable, what´s the code for enable clicks over them?

  11. Michael says:

    Hi,
    Could you please tell me how would I create a link on the images

    1. Martin Angelov says:

      You can read the suggestion I gave to Mr. Maocan below, who had a similar question.

  12. Kindra says:

    Nice tut, but for some reason Chrome is hanging up on it? Anyone else experiencing this?

  13. Mr. Maocan says:

    Wonderful~ Just curious about how to make the icon link to url? Thanx any way :)

    1. Martin Angelov says:

      You can turn the @markup in the Icon class into a link. Something like this:

      @markup = "<a href='#{@url}' class='icon' style='background-image:
      url(assets/img/icons/#{@id}.png)'  title='#{@title}'></a>"
      

      You will need to change the constructor of the class as well, so it takes a URL:

      constructor: (@id, @title, @url) ->
      

      After this simply pass the URL as the third parameter when creating the icons.

      Just be sure to pass url as a value of the

      1. Mr. Maocan says:

        Great, I'll try~This tutorial is more fantastic with this complement ^^ Thank you Martin

      2. waterg says:

        how to use @url in DockIcon?

      3. JeppeA says:

        Great introduction.

        I have tryid adding the above code and it works fine in a browser on the PC, but on my ipad the href link does not work.
        Nothing happens when I click on it.

        Do I miss something?

      4. joe says:

        hi Martin,This is Very Fantastic Tuttorial ;))

        becasue i love it, so i added it to my website too ;))

        so, can you help me how to change the slider to atomatically slide to right but it keep can dragable with mouse ;)

        your help will very helpfyll Martin,

        Cheers

  14. wheel58m says:

    Haha love it, could make a great feature for my project

  15. Martin Angelov says:

    Thank you for the awesome comments, folks!

  16. Sharun Kumar says:

    SEXY! I was actually looking for this a few days ago!!! :D

  17. Jon Koops says:

    You might wanna add some user-select: none; to the CSS :)

  18. Michael says:

    Ok, got it working thank you so much for your help.

  19. Heiko says:

    Looks really cool - especially with the @markup tip above. Some adoptions in css for screen size on an phone and then you got a nice effect on an Android phone. Thumbs up

  20. Really excellent tutorial. Very crisp and you explained some subtle aspects of jQuery with Coffeescript.

    I would ask only that you:

    1) fix so mouseDowns on the listIndicators does NOT show the text cursor
    2) fix so mouseDowns on the non-active list indicators actually changes the screen.

    Thanks again.

  21. Anais says:

    yeah ! very very nice.. thanks :)
    just one question : can we make de 4 little circles (indicators) linkable to the different parts ?
    so indicator1 = sliding to screen 1...

  22. Marek says:

    in 58 minutes I fall in love with coffeescript! :) well done and thanks

  23. uttam says:

    I have used this on one of my website, its really cool

    1. juliovmd says:

      Great job and very elegant!

      I want you to look like the Apple iPad environment, you can add text dock icons?

      This is mi modified code:

      for icon in dockIcons
      dock.append(icon.markup)
      # This mi comment to add text
      dock.append(icon.id)

      The texts are displayed in wrong position :(

      Can you help?...

      Thanks

  24. karthik says:

    can i use this code ?? there aren't any copyright issue concerning it right ????

  25. Tanner says:

    How would I go about making it 4x4 rather than 3x3? Changing the mask dimensions doesn't seem to be working... What makes it start a new row after every third icon?

  26. Tanner says:

    *I did get it to display 16 icons on a page, but they just push the dock down

  27. Sunny says:

    This is an awesome "bridge" to OOP concepts to javascript. Thanks man,

Add Comment

Add a Reply

HTML is escaped automatically. Surround code blocks with <pre></pre> for readability.
Perks:   **bold**   __italics__   [some text](http://example.com) for links