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.
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.
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:
https://webster.cs.washington.edu/your_UWNetID/lab7/potato.html
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:
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:
potato.html
to your computer and upload it to a folder on Webster.potato.html
on your Webster space. You should see an HTTP 404 error that the potato.php
service is missing. This is expected.potato.php
that produces a text/plain output of moustache
. Upload this file to Webster in the same folder as potato.html
.eyes glasses moustache
. Re-upload the file and refresh the page to see the change.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!)
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 name | Value |
---|---|
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":
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!)
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"> <legend>Parts</legend> <label><input type="checkbox" id="arms" /> Arms</label> <label><input type="checkbox" id="ears" /> Ears</label> <label><input type="checkbox" id="eyes" /> Eyes</label> ... </fieldset> <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" /> ... </div>
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:
potato.html
to link to your JavaScript file (in the same folder) instead of ours.potato.js
. Write code in window.onload
that uses an Ajax request to fetch the output from potato.php
.potato.php
to check the appropriate checkboxes and make the appropriate accessory images appear on the page.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!)
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>
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 id
s 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!)
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
.