University of Washington, CSE 190 M, Spring 2008
Lab 7: Scriptaculous and PHP (Thursday, May 15, 2008)

The purpose of this lab is to practice writing server-side PHP code to save and restore the state of a web page. You will also practice using the Scriptaculous library to add animation to the web page.
You probably won't have enough time to finish all of the exercises; finish as much as you can within the allotted time.

Lab 7: Mr. Potato Head

In this lab we'll write code for a web page that lets the user put accessories on a picture of a Mr. Potato Head toy. The page shows a bare image of a potato and has several checkboxes next to it. Checking a box such as "moustache" should cause that accessory to appear on top of the potato toy. A key aspect of this page is that whenever an accessory is added or removed, this information is sent to a server-side PHP script, which saves the state of which options are checked. When the user comes back to the page later, it restores this state (checking the appropriate boxes and showing the appropriate accessories).

In this lab, first you'll write the server-side PHP code to save/load the state of which options are checked. This PHP code will initially interact with an instructor-provided complete version of the web page. Once you get the PHP code working, you'll rewrite the client-side JavaScript code that interacts with it.


Exercise 1: Basic PHP Web Service (roughly 15 minutes)

This exercise is about setting up a skeletal version of the PHP code that always displays a moustache. For this portion of the lab your PHP code will interact with a complete instructor-provided version of the HTML, CSS, and JavaScript code for the page. Download potato.html to your disk (right-click the link and choose Save Link As...), then upload it to your Webster space. You shouldn't modify the HTML file. The suggested destination URL for this file is:

This HTML file already links to an instructor-provided JavaScript file to make the page interactive. When the page initially loads, this JavaScript file tries to make an Ajax GET request to a web service named potato.php to ask it which accessories should be initially shown on the Mr. Potato Head toy. The web service returns this information as a string of text output, where the accessories' names are printed separated by spaces. For example, if the initial state of the Potato Head is to have eyes, glasses, and a moustache, the web service's output should be the text eyes glasses moustache. The following diagram illustrates this interaction:

page Ajax GET request

For this exercise, your PHP file should always respond by saying that the moustache is shown; in other words, your PHP script's output should always be simply "moustache". (The file's contents will be very short.) Create the basic potato.php file and make it produce this output, then upload it to Webster in the same folder as your HTML file. Your page should now be able to find the web service and interact with it, causing the moustache to appear when the page first loads.

The set of steps for completing this exercise are the following:

If you've successfully completed this exercise, the page will always begin with the moustache showing. You'll be able to check and uncheck the boxes and see the accessories appear and disappear. But if you refresh the page, it won't remember which accessories you checked; it will reset to its original state with only the moustache showing.

You may try our runnable solution to this exercise (so you can see how your page is supposed to look and work. Don't look at the JavaScript source code, please!)

Exercise 2: Complete PHP Web Service (roughly 15 minutes)

In this exercise we'll write the actual complete PHP web service so that the page saves the state on the server of which accessories are enabled. Every time the user checks or unchecks a box, the page's JavaScript code sends an Ajax POST request to the potato.php service, telling it what accessories are selected. It sends this information as a query parameter named accessories, whose value is a string containing the lowercase names of the selected accessories separated by spaces:

Parameter nameValue
accessories the currently selected Potato Head accessories as a string, such as "eyes glasses moustache"

The following diagram illustrates the posting of data to the web service, in response to checking a checkbox such as "mouth":

page Ajax POST request

To make the server save this state correctly, you should change your PHP code so that it looks for this query parameter accessories. If the parameter is set, the web service will read its value and save it into a file named potato.txt. If the parameter is not set, the service instead reads the contents from the file and sends them back as output. The PHP functions file_get_contents(file name) and file_put_contents(file name, text) will be useful.

Make the appropriate changes to your PHP code, re-upload it, and refresh the page to test it. If you've completed this exercise correctly, you should be able to check and uncheck various accessories, then refresh the page, and have that state be remembered. If it doesn't work, we strongly recommend looking at the Console tab in Firebug to see the state of each Ajax request made by the page, the parameters that were passed to it, and the response that was sent back by the PHP service.

If you see an error on the page about "failed to open stream: No such file or directory", it probably means you are trying to call file_get_contents on a file that does not exist. You can avoid this error by only reading the file if file_exists(file name) returns TRUE.

You may try our runnable solution to this exercise (so you can see how your page is supposed to look and work. Don't look at the JavaScript source code, please!)

Exercise 3: JavaScript for Initial Accessories (roughly 15 minutes)

In this phase you'll begin to rewrite the JavaScript code that makes the page interactive on the client (browser) side. The potato.html file you're using links to an instructor-provided potato.js file that you'll now rewrite. You need to modify potato.html so that it'll use your JS file and not the instructor-provided one. Either open the potato.html file and modify the script tag to refer to simply potato.js rather than its current longer URL, or else download this new potato.html which already contains the change. (If you upload this new potato.html to Webster and view the page, you'll see a page with a bare potato and no accessories, due to the lack of JavaScript.)

It will be helpful to understand the HTML code in the page. The page has many checkboxes, each with an id to match its text. Each checkbox corresponds to an image with a similar id that displays the picture of that accessory. For example, the ears checkbox is intended to control the visibility of the ears_image image.

<fieldset id="controls">

    <label><input type="checkbox" id="arms" /> Arms</label>
    <label><input type="checkbox" id="ears" /> Ears</label>
    <label><input type="checkbox" id="eyes" /> Eyes</label>

<div id="potato">
    <img id="arms_image" src="arms.png" alt="arms" />
    <img id="ears_image" src="ears.png" alt="ears" />
    <img id="eyes_image" src="eyes.png" alt="ears" />

Create an empty potato.js file and begin to add your code to it. Write code so that when the page loads (window.onload), you initiate an Ajax request to your potato.php service to get the current list of accessories. Recall that this list of accessories is a string such as "eyes glasses moustache". Each word of this string corresponds to the id of the appropriate checkbox on the page for that accessory. Break apart this string with the split method. For each word in the string, check the checkbox with the appropriate id, and make the appropriate image appear. Recall that you can control whether a checkbox is checked by setting its boolean checked property. Make images appear on the page using a Scriptaculous effect such as a new Effect.Grow.

The set of steps for completing this exercise are the following:

If you've completed this exercise successfully, the page will now appear with the correct state of initially selected accessories. Checking and unchecking the checkboxes will still not do anything; you won't be able to change which accessories are showing.

You may try our runnable solution to this exercise (so you can see how your page is supposed to look and work. Don't look at the JavaScript source code, please!)

Exercise 4: JavaScript for Toggling Accessories and Saving State (roughly 15 minutes)

Now that your page is able to read the initial accessory state from the server, add the code so that the checkboxes work. Attach event handlers to each checkbox so that when a box is clicked, the appropriate image is shown or hidden on the page. Use Scriptaculous to add an effect when the image appears (such as a new Effect.Grow) and disappears (such as a new Effect.Shrink). If you write this code the way we intend, you can use the same event handler for every checkbox. Take advantage of the fact that the id of every image is the same as the id of the corresponding checkbox, but with "_image" appended at the end.

If you've completed this exercise, you should be able to add and remove accessories from Mr. Potato Head. When you refresh the page, it always reverts to the initial state it had the last time you went to the page.

You may try our runnable solution to this exercise (so you can see how your page is supposed to look and work. Don't look at the JavaScript source code, please!)

If you want your page to look more polished, you should also set the page's h2 heading to show the state of what the potato head is wearing. This heading has an id of status.

<h2 id="status">He is wearing: </h2>

Exercise 5: Save State to Server (roughly 10 minutes)

In this final exercise, you should write the JavaScript code so that when the user checks any checkbox, the current state of accessories is saved to the server. Do this by modifying your onclick handler for checkboxes. Use the $$ function to loop over every checkbox on the page (they are input elements found inside a fieldset with id of controls). Examine each checkbox each to see if it is checked. Build a long string representing which boxes are checked; if the checkboxes with ids of eyes, glasses, and moustache are checked, you should build the string "eyes glasses moustache". Use an Ajax POST request to send this string to the server as a query parameter named accessories.

If you've completed this exercise, you should be able to check and uncheck any accessories you like, and if you refresh the page, the state should be remembered. Congratulations! You've created a stateful Ajax/PHP-based web application.

You may try our runnable solution to this exercise (so you can see how your page is supposed to look and work. Don't look at the JavaScript source code, please!)

Exercise 6 (For CSE Majors): More Scriptaculous Effects

If you're a CSE major or finish all the preceding exercises, enhance the page by making it possible to move around all of the accessories. Make them Draggable using Scriptaculous. If you're really l33t, modify the PHP service and JavaScript code so that when an image is moved around, the page remembers its position and saves it to the server. You'd have to modify the format of the data saved by the PHP service so that it retains x/y positions of each accessory. It might look something like this:

eyes 123 98 glasses 74 84 moustache 56 251

It may help you to handle the events on the Draggable object such as onStart, onDrag, and onEnd.

Valid XHTML 1.1 Valid CSS!