University of Washington, CSE 190 M, Spring 2008
Homework Assignment 6: To-Do List
due Wednesday, May 21, 2008, 11:00pm electronically

This assignment tests your understanding of writing a complete Ajax-enabled "Web 2.0" application, specifically including the Scriptaculous JavaScript library and PHP for server-side web programming.

In this assignment you will create a web page for an online to-do list. The user can add an item to the end of the to-do list, delete the first item from the list, or drag the items into a different order. Any of these changes made to the list will be saved to the web server so that if the user leaves the page and returns later, the current state of the list will be remembered.



Unlike in many of the past assignments, we will not be providing you with any starter code whatsoever for this assignment. While this will make a bit more work for you, the goal is that you will gain experience creating an entire web application from scratch. Turn in the following files:

This program uses Ajax to communicate with a PHP web service. In order for Ajax and PHP to work correctly, your files must be uploaded to the Webster server. You will only be able to test your page by directing your browser to its Webster URL; it will not work if you test from your local hard drive, because your computer (probably) does not have the proper web server software installed on it.

Page appearance and behavior:

Unlike in past assignments, the exact appearance of the page is not specified. Certain aspects of the appearance and behavior are specified below. Beyond these, any other aspects of the page are up to you, so long as they do not conflict with what is required. If you want your page to contain additional resources such as image files, place these on your Webster space and link to them using absolute URLs. If you are unsure whether an aspect of your page is acceptable, ask the instructor or TA. The goal here is to encourage you to be creative and personalize your page. You are not expected to match the screenshot in this document exactly; in fact, if you do exactly copy its appearance, you will receive a deduction for lack of creativity.

The page should contain a heading that identifies the course and the fact that this is a to-do list program. The page should also contain images that link to the W3C XHTML/CSS validators and JSLint.

When the page first loads, it should show the current contents of the to-do list as an ordered list. Since these items are retrieved from the server, the page will not show any items until the server has been contacted. (The W3C XHTML validator complains if you have a list with no elements in your HTML, so you may need to add an empty hidden element to get it to validate.) Once the items arrive, they are added to your page using the DOM. Apply some sort of appearing effect to the items using Scriptaculous, such as making the list items "fade in" or "shake" when they arrive. It may help you to recall that you can make items initially invisible by setting their display style property to none. An invisible element can then be shown using Scriptaculous effects such as a new Effect.Grow. To implement an effect on an element that is being deleted, you may want to consult the Scriptaculous lecture slides about the afterFinish effect event.

Once the list appears, the user should be able to change its contents in at least the three following ways:

  1. add an item to the end of the list
  2. delete the item from the front of the list
  3. drag the list items to reorder them

buttons The exact UI the page presents to the user for adding and deleting is up to you. For example, you could put a text field and "Add to Bottom" and "Delete Top Item" buttons near your to-do list; when the user types text into the field and clicks "Add to Bottom", the item is added to the list; when the user clicks "Delete Top Item", the first item is deleted from the list. One constraint is that your page should not use alert or prompt boxes to do the adding/deleting, such as prompting the user for the new item's text. You can accept any text from the user as a valid to-do item, even an empty string; if you like, you can filter out empty or invalid strings that the user tries to add. If the user tries to Delete Top Item when there are no items in the todo list, no error should occur.

Any change to the to-do list should be accompanied by some noticeable visible cue such as a Scriptaculous effect. For example, when the user adds an item, that item could fade into view or grow to its normal size.

The reorderability of the list items should be done using Scriptaculous. Give the list an id of "items" and make it sortable using the Sortable.create method. You must give each item in the list an id that begins with "items_" followed by its 0-based index within the list, such as "items_0" or "items_1". It is important that your ids exactly match this format so that Scriptaculous can properly reorder them. You can tell that the list has been rearranged by listening to its onUpdate event as shown in the lecture slides. If your onUpdate handler is not being called, you may not have correctly set the id on each li.

One subtlety of Sortable.create is that the sortability breaks if you add or remove elements after you've made it sortable. Newly added elements of the list will not be draggable, nor can old items be dragged past new ones. To fix such a case, repeat your Sortable.create call after each modification of the list.

When any of the three preceding actions (add, delete, reorder) has been made on the page, the page should immediately send an Ajax request to a server-side PHP web service to inform the server of the change. The exact behavior of this service is described in the next section. If you've done this properly, at any point the user should be able to refresh the browser and still see the to-do list in its current state.

Another important aspect of your program is that any updates to the to-do list should appear instantly in the page. That is, the instant that the user decides to add, delete, or reorder items in the list, the list on the page should update to reflect this action. In the background, the page may also be contacting the server to inform it of the change, but the page's UI should not be out of date during this time, nor should it lock up and prevent the user from using the page. You do not need to worry about the possibility of multiple rapid updates overloading the server or arriving to the server out-of-order. You also should minimize the amount of heavy changes you make to the page's DOM; in other words, you should not destroy and recreate every list item in the DOM if only one item changes (i.e. on an add or remove).

No CSS code is being provided to you, so the exact styling of your page is up to you. You should, however, set a non-trivial number of CSS styles including, but not limited to, the following:

PHP web service:

Your PHP web service must support the following four types of web queries. Please note that some queries use a request type of GET and others use POST. Your code should respect this distinction and should always send its queries using the proper request type.

  1. getting the current contents of the to-do list: If the browser requests your PHP service, regardless of what parameters (if any) are passed to it, the service's output should always be a text/plain representation of the current to-do list as a string. In particular, if the browser requests your service using a GET request, regardless of the parameters passed to it, you should interpret this as a request to return the current to-do list contents.

    The get query (request type: GET)
    Parameter nameValue
    (none) (none)

    The items in the list are separated by \n line breaks. For example, if the to-do list contains the following three items:

    1. buy meatballs from Ikea
    2. shave head
    3. watch Flight of the Conchords

    then the web service's output would be the following:

    buy meatballs from Ikea
    shave head
    watch Flight of the Conchords
    

    Your PHP code should store the current to-do list as a text file named todolist.txt. Your service should read that file's contents as a string and print them as output. If the service is being used for the first time and no todolist.txt file exists, no output is produced.

  2. adding an element to the end of the to-do list: If the browser sends a POST request to your PHP service and passes the following two parameters, the web service should add an item to the end of the list:

    The add query (request type: POST)
    Parameter nameValue
    action "add"
    item the new to-do item's text as a string, such as "go to the store"

    Do this in your PHP code by reading the to-do list's current contents into your program as a string, concatenating the new item to the end of the string, and then writing this new longer string to the file. As stated previously, the service's output should always be the current state of the to-do list, so your response to this query should be to print the list's contents after the item is added.

  3. deleting the first element from the to-do list: If the browser sends a POST request to your PHP service and passes the following parameter, the web service should delete the first item from the front of the list:

    The delete query (request type: POST)
    Parameter nameValue
    action "delete"

    Do this in your PHP code by reading the to-do list's current contents into your program as a string, splitting the string into an array of lines, removing the first element from this array, combining the array back into a single string, and then writing this new shorter string to the file. If the to-do list is currently empty or the todolist.txt file does not exist, this query has no effect; the list remains empty, no output is produced, and the program should not crash or display an error.

    As stated previously, the service's output should always be the current state of the to-do list, so your response to this query should be to print the list's contents after the item is deleted.

  4. replacing the entire contents of the to-do list: If the browser requests your PHP service as a POST request and passes the following two parameters, then the web service should completely replace the items in the to-do list with a new set of items:

    The set query (request type: POST)
    Parameter nameValue
    action "set"
    items a string representing to-do items separated by \n line breaks, such as:
    "buy meatballs from Ikea\nshave head\nwatch Flight of the Conchords"

    This third query replaces the entire contents of the to-do list with a new list. You can use this query to implement the rearranging of the list when the user drags an element into a new position. In your JavaScript code, use the DOM to gather the text of all elements of the to-do list into a large string, then send this string as a parameter named items in your Ajax request. In your PHP code, write this string's contents into the todolist.txt file on the server, replacing any previous contents of the file.

    Note that the set query is powerful, but it is also inefficient since all items must be sent from the client to the server. It would be possible to implement the add and delete operations by having the page's JavaScript code re-send the entire list of elements to the server using the set action. But this would be inefficient for large lists of items, so you should not implement those operations in that way.

    In this query it is most important for you to understand the difference between GET and POST requests. Since the request you're sending holds a large amount of query data including \n line breaks, it likely will not submit successfully as a GET request (as part of a URL query string). Make sure you are submitting this data as a POST request so that it will reach the server successfully.

    As stated previously, the service's output should always be the current state of the to-do list, so your response to this query should be to print the list's contents after the items have been replaced.

While attempting to write to the file todolist.txt, you may see an error of, "failed to open stream: Permission denied". This can occur when the web server's PHP process doesn't have proper permission to write to the file. Try deleting the file on Webster and letting the PHP code recreate it.

We strongly recommend that you debug your queries in Firebug. You can see each Ajax query request in the Console tab. Expand it with the + sign to view the query parameters that were passed and the web service's response.

To help you develop your program incrementally, we have placed a working version of the PHP web service at the following URL. You can initially write your code to talk to this version if you like, but eventually you should re-implement the service yourself and connect your page to your own service.

For CSE Majors:

CSE majors must implement the following three extra features:

You can add any other functionality you like to your page. Such functionality will be ignored for grading as long as it does not interfere with your code's stylistic quality or our ability to test the specified functionality. CSE non-majors may also choose to implement the above features, but they will receive no bonus for doing so. Such features in a non-major's program will be ignored so long as they do not break required functionality.

Development Strategy:

This assignment is challenging in that there is a lot of code to be written, and none of it is being provided to you. It can be challenging to know where to start or how to make the various pieces fit together. We suggest roughly the following development strategy for this assignment:

For reference, our solution has 54 lines of XHTML, 67 lines of CSS, 84 lines of JavaScript, and 37 lines of PHP including blank lines and comments. You do not need to match these totals.

Style guidelines:

Your XHTML and CSS code should be well-styled as in past assignments. For full credit, your page must pass the W3C XHTML and CSS validators. As much as possible, place style information in CSS, not in XHTML or JavaScript DOM code. Express CSS concisely and without unnecessary or redundant styles. Format your code with proper whitespace and indentation. Do not place more than one block element on the same line or begin any block element past the 100th character on a line. Place a comment header in each XHTML and CSS file containing your name, section, and a brief description of the assignment and the file's contents.

Your JavaScript and PHP code should follow reasonable stylistic guidelines similar to those you would follow on a CSE 14x programming assignment. Use the HTML DOM appropriately. Follow proper style in your Ajax requests, including obeying the proper query request type (GET vs. POST). Minimize redundant code, decompose the problem into functions intelligently, minimize the number of global variables, utilize parameters and return values properly, correctly use indentation and spacing, avoid long lines over 100 characters in length, and place a comment header at the top of your code files and atop every function explaining that function's behavior. You should only use material that has been discussed during the first seven weeks of the course, unless given explicit permission from the instructor.

Your JavaScript code should pass the JSLint validator, should correctly utilize Ajax requests and XHTML DOM objects for interacting with the server and manipulating the page contents.

Your PHP code should generate no error or warning messages when run using reasonable sets of parameters.

Part of your grade will come from successfully uploading your files to the Webster web server at the following URL:

Please do not place a solution to this assignment online on a publicly accessible (un-passworded) web site.