Your goal: Build a Trailmaker # Get your toolkit in order ## How it should look in the "back end" trail:history_of_bows step:1 trail:history_of_bows step:2 trail:history_of_bows step:n Sample account: trailmaker_test1 / smallb3ar (but that one is mine, get your own) * Got an editor? (I've used many of the heavier IDEs: Netbeans, Eclipse, Together/J... I'm olllld) * Some way to debug JavaScript? (Firefox/Firebug, or Chrome) ## Build it In our first class, we did an in-class demo showing one possible way to implement trails from Vannevar Bush's Memex using the Delicious API. This tutorial reviews the steps from class. At the end of this tutorial, you will have constructed a small web application that saves a collection of bookmarks to Delicious as a trail. A trail is identified by a set of special tags: trail:[name_of_trail] and step:[step_number]. ## Getting Started 0. Before getting started, you may want to (VERY MUCHLY) create a separate Delicious account for experimenting. The Delicious API has no undo, and you don't want a mistake to erase any existing bookmarks. Also, unless you use a properly configured proxy server, your password will be sent in the clear. You may want to change your password to something that isn't used by another of your other accounts. 1. Start with a basic XHTML page that includes Google-hosted copies of jQuery and jQuery UI. You can download this template at [http://courses.ischool.berkeley.edu/i290-iol/f11/demos/trailmaker/skeleton](http://courses.ischool.berkeley.edu/i290-iol/f11/demos/trailmaker/skeleton) 2. The code samples in this tutorial are broken up by explanations. For the uninterrupted code, you can download the Trailmaker at [http://courses.ischool.berkeley.edu/i290-iol/f11/demos/trailmaker/trailmaker_complete.html](http://courses.ischool.berkeley.edu/i290-iol/f11/demos/trailmaker/trailmaker_complete.html) 3. Create the basic structure that you will need in HTML. This includes a <form> to specify a username, a <div> and <ul> to display loaded bookmarks, and a <div> and a <ul> to create a new trail. The following structure is a good start:

2. Create the basic structure that you will need in HTML. This includes a <form> to specify a username, a <div> and <ul> to display loaded bookmarks, and a <div> and a <ul> to create a new trail. The following structure is a good start:

Enter a Delicious username:

Bookmarks

New Trail

Username:
Password:
Loading Bookmarks 3. When a user enters an account in the #load-bookmarks form, we want to load the Delicious bookmarks for that account. Delicious provides a feed API that lets us get the bookmarks for a user at http://feeds.delicious.com/v2/json/{username}. We want to attach all of the Javascript for this document once the page is “ready,” so we use $(document).ready() inside a In this ready function, we’ll attach a function to the submit event of the #load-bookmarks form. When the form is submitted (by pressing the return key or by clicking on the “Get Bookmarks” button), this function will run. The last thing this function does should be return false;. The browser’s default behavior when submitting a form is to load a new page, and we use return false to prevent this action. $('#load-bookmarks').submit(function(){ // What you want to happen when the load bookmarks form is submitted return false; }); CSS selectors are the basis for nearly all of the jQuery Javascript library. Most programming occurs by selecting some group of elements on the current page and manipulating them. Because the form has the id attribute set to ‘load-bookmarks’, we can select this element using #load-bookmarks—the pound sign (#) is used to indicate an id in CSS. Then we attach a function to the submit() event of the form. jQuery can attach functions (which is called “binding”) to many kinds of events, which are described in the jQuery documentation. The functions that we use on inside .ready() and .submit() do not have a name—they are “anonymous functions,” which are a feature of Javascript and very common. They allow you to define commands that you want to happen inline, without defining a function somewhere else in your code. We’ll discuss anonymous functions more in lecture two; You can also read this guide to anonymous functions in Javascript. 4. When the form is submitted, we want to get the value of the account name entered in the form, which we do with var username = $('#username').val(); Although Javascript does not require var in variable declarations, you should always use it. Then we use the getJSON() method to get the bookmarks from Delicious. You can provide a function to getJSON that is called when the request is complete. In fact, if you want anything to happen when the request is returned, you have to provide a function to getJSON because of the asynchronous nature of AJAX requests. This function receives the response from the server, which you can use to construct an HTML list item and add it to the list of bookmarks. var username = $('#username').val(); // This cross-domain request requires that you use '?callback=?' because it is done using JSONP $.getJSON('http://feeds.delicious.com/v2/json/' + username + '?callback=?', function(json){ // json contains the response provided by the server // You can use console.log(json) to examine the response $(json).each(function(index) { // this.u // url // this.d // description // this.n // extended notes // this.t // array of tags // Create an HTML string for the bookmark // We also use the .data method to store the notes and tags // of the bookmark in the DOM with the object // Finally, we add it to the list of bookmarks with appendTo() $('
  • ').html('' + this.d + '') .data('extended', this.n) .data('tags', this.t) .appendTo('#bookmarks ul'); }); // Later, you'll add dragging functionality here }); return false; Now entering a Delicious user’s account name and clicking “Load Bookmarks” works. Creating a new trail 5.We want to let users drag loaded bookmarks to the New Trail box and rearrange them before saving the trail. Before we do this, we should make the #bookmarks box and the #new-trail box actually appear side-by-side. Add these lines to between the tags in your document head. This makes each box roughly half the width of the screen, and the float: left and float: right make them appear side-by-side: #bookmarks, #new-trail { width: 48%; min-height: 300px; border: 1px solid #666; } #bookmarks { float: left; } #new-trail { float: right; } 6. The jQuery UI library makes it easy to script complex actions like dragging and dropping. First, we want to make each of the loaded bookmarks draggable. We can do this with the .draggable() method when we load each bookmark. Add the following line at the end of your getJSON callback function: $('#bookmarks li').draggable({revert: true}); 7. Now we need a place to drop these draggable elements. We’ll make the entire #new-trail box a droppable area, and define a function that copies the bookmark to the list when the user drags a loaded bookmark to the area. Notice that the droppable method only takes one argument, a Javascript object (indicated by the curly braces {}) that provides various parameters by name. This is common practice in jQuery and jQuery UI. Here we are providing the accept and drop parameters. $('#new-trail').droppable({ accept: 'li', // This droppable area accepts li elements drop: function(event, ui) { // Don't confuse ul, the